* [PATCH 2/8] btio: Seperate btio.[ch] into btio directory
From: Zhenhua Zhang @ 2010-08-19 14:21 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1282227676-15381-1-git-send-email-zhenhua.zhang@intel.com>
Seperate btio.[ch] from src directory to btio sub-folder.
---
Makefile.am | 19 +-
btio/btio.c | 1299 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
btio/btio.h | 97 +++++
src/btio.c | 1299 -----------------------------------------------------------
src/btio.h | 97 -----
5 files changed, 1406 insertions(+), 1405 deletions(-)
create mode 100644 btio/btio.c
create mode 100644 btio/btio.h
delete mode 100644 src/btio.c
delete mode 100644 src/btio.h
diff --git a/Makefile.am b/Makefile.am
index 73e2f28..a89e62b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,6 +18,8 @@ gwobex_sources = gwobex/gw-obex.h gwobex/gw-obex.c \
gwobex/obex-xfer.h gwobex/obex-xfer.c \
gwobex/utils.h gwobex/utils.c gwobex/log.h
+btio_sources = btio/btio.h btio/btio.c
+
libexec_PROGRAMS =
if SERVER
@@ -62,11 +64,10 @@ builtin_nodist += plugins/phonebook.c
libexec_PROGRAMS += src/obexd
-src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) \
+src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) $(btio_sources) \
src/main.c src/obexd.h src/plugin.h src/plugin.c \
- src/log.h src/log.c src/btio.h src/btio.c \
- src/dbus.h src/manager.c src/obex.h src/obex.c \
- src/obex-priv.h \
+ src/log.h src/log.c src/dbus.h src/manager.c \
+ src/obex.h src/obex.c src/obex-priv.h \
src/mimetype.h src/mimetype.c \
src/service.h src/service.c \
src/transport.h src/transport.c \
@@ -104,13 +105,12 @@ service_in_files += client/obex-client.service.in
libexec_PROGRAMS += client/obex-client
-client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) client/main.c \
- client/session.h client/session.c \
+client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) $(btio_sources) \
+ client/main.c client/session.h client/session.c \
src/log.h src/log.c \
client/pbap.h client/pbap.c \
client/sync.h client/sync.c \
- client/transfer.h client/transfer.c \
- src/btio.c src/btio.h
+ client/transfer.h client/transfer.c
client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @OPENOBEX_LIBS@ @BLUEZ_LIBS@
endif
@@ -123,7 +123,8 @@ AM_CFLAGS = @OPENOBEX_CFLAGS@ @BLUEZ_CFLAGS@ @EBOOK_CFLAGS@ \
-DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
INCLUDES = -I$(builddir)/src -I$(srcdir)/src -I$(srcdir)/plugins \
- -I$(srcdir)/gdbus -I$(srcdir)/gwobex
+ -I$(srcdir)/gdbus -I$(srcdir)/gwobex \
+ -I$(srcdir)/btio
CLEANFILES = $(service_DATA) $(builtin_files)
diff --git a/btio/btio.c b/btio/btio.c
new file mode 100644
index 0000000..42a3bcd
--- /dev/null
+++ b/btio/btio.c
@@ -0,0 +1,1299 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <glib.h>
+
+#include "btio.h"
+
+#define ERROR_FAILED(gerr, str, err) \
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+ str ": %s (%d)", strerror(err), err)
+
+#define DEFAULT_DEFER_TIMEOUT 30
+
+struct set_opts {
+ bdaddr_t src;
+ bdaddr_t dst;
+ int defer;
+ int sec_level;
+ uint8_t channel;
+ uint16_t psm;
+ uint16_t mtu;
+ uint16_t imtu;
+ uint16_t omtu;
+ int master;
+ uint8_t mode;
+};
+
+struct connect {
+ BtIOConnect connect;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+struct accept {
+ BtIOConnect connect;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+struct server {
+ BtIOConnect connect;
+ BtIOConfirm confirm;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+static void server_remove(struct server *server)
+{
+ if (server->destroy)
+ server->destroy(server->user_data);
+ g_free(server);
+}
+
+static void connect_remove(struct connect *conn)
+{
+ if (conn->destroy)
+ conn->destroy(conn->user_data);
+ g_free(conn);
+}
+
+static void accept_remove(struct accept *accept)
+{
+ if (accept->destroy)
+ accept->destroy(accept->user_data);
+ g_free(accept);
+}
+
+static gboolean check_nval(GIOChannel *io)
+{
+ struct pollfd fds;
+
+ memset(&fds, 0, sizeof(fds));
+ fds.fd = g_io_channel_unix_get_fd(io);
+ fds.events = POLLNVAL;
+
+ if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLNVAL))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct accept *accept = user_data;
+ GError *err = NULL;
+
+ /* If the user aborted this accept attempt */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
+ "HUP or ERR on socket");
+
+ accept->connect(io, err, accept->user_data);
+
+ g_clear_error(&err);
+
+ return FALSE;
+}
+
+static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct connect *conn = user_data;
+ GError *gerr = NULL;
+
+ /* If the user aborted this connect attempt */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ if (cond & G_IO_OUT) {
+ int err = 0, sock = g_io_channel_unix_get_fd(io);
+ socklen_t len = sizeof(err);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
+ err = errno;
+
+ if (err)
+ g_set_error(&gerr, BT_IO_ERROR,
+ BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
+ strerror(err), err);
+ } else if (cond & (G_IO_HUP | G_IO_ERR))
+ g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
+ "HUP or ERR on socket");
+
+ conn->connect(io, gerr, conn->user_data);
+
+ if (gerr)
+ g_error_free(gerr);
+
+ return FALSE;
+}
+
+static gboolean server_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct server *server = user_data;
+ int srv_sock, cli_sock;
+ GIOChannel *cli_io;
+
+ /* If the user closed the server */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ srv_sock = g_io_channel_unix_get_fd(io);
+
+ cli_sock = accept(srv_sock, NULL, NULL);
+ if (cli_sock < 0)
+ return TRUE;
+
+ cli_io = g_io_channel_unix_new(cli_sock);
+
+ g_io_channel_set_close_on_unref(cli_io, TRUE);
+ g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
+
+ if (server->confirm)
+ server->confirm(cli_io, server->user_data);
+ else
+ server->connect(cli_io, NULL, server->user_data);
+
+ g_io_channel_unref(cli_io);
+
+ return TRUE;
+}
+
+static void server_add(GIOChannel *io, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy)
+{
+ struct server *server;
+ GIOCondition cond;
+
+ server = g_new0(struct server, 1);
+ server->connect = connect;
+ server->confirm = confirm;
+ server->user_data = user_data;
+ server->destroy = destroy;
+
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
+ (GDestroyNotify) server_remove);
+}
+
+static void connect_add(GIOChannel *io, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy)
+{
+ struct connect *conn;
+ GIOCondition cond;
+
+ conn = g_new0(struct connect, 1);
+ conn->connect = connect;
+ conn->user_data = user_data;
+ conn->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb, conn,
+ (GDestroyNotify) connect_remove);
+}
+
+static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy)
+{
+ struct accept *accept;
+ GIOCondition cond;
+
+ accept = g_new0(struct accept, 1);
+ accept->connect = connect;
+ accept->user_data = user_data;
+ accept->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
+ (GDestroyNotify) accept_remove);
+}
+
+static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
+{
+ struct sockaddr_l2 addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+ addr.l2_psm = htobs(psm);
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "l2cap_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
+{
+ int err;
+ struct sockaddr_l2 addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(psm);
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static int l2cap_set_master(int sock, int master)
+{
+ int flags;
+ socklen_t len;
+
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0)
+ return -errno;
+
+ if (master) {
+ if (flags & L2CAP_LM_MASTER)
+ return 0;
+ flags |= L2CAP_LM_MASTER;
+ } else {
+ if (!(flags & L2CAP_LM_MASTER))
+ return 0;
+ flags &= ~L2CAP_LM_MASTER;
+ }
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, sizeof(flags)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int rfcomm_set_master(int sock, int master)
+{
+ int flags;
+ socklen_t len;
+
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0)
+ return -errno;
+
+ if (master) {
+ if (flags & RFCOMM_LM_MASTER)
+ return 0;
+ flags |= RFCOMM_LM_MASTER;
+ } else {
+ if (!(flags & RFCOMM_LM_MASTER))
+ return 0;
+ flags &= ~RFCOMM_LM_MASTER;
+ }
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, sizeof(flags)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int l2cap_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ L2CAP_LM_AUTH,
+ L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,
+ L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int rfcomm_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ RFCOMM_LM_AUTH,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
+{
+ struct bt_security sec;
+ int ret;
+
+ if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Valid security level range is %d-%d",
+ BT_SECURITY_LOW, BT_SECURITY_HIGH);
+ return FALSE;
+ }
+
+ memset(&sec, 0, sizeof(sec));
+ sec.level = level;
+
+ if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
+ sizeof(sec)) == 0)
+ return TRUE;
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ if (type == BT_IO_L2CAP)
+ ret = l2cap_set_lm(sock, level);
+ else
+ ret = rfcomm_set_lm(sock, level);
+
+ if (ret < 0) {
+ ERROR_FAILED(err, "setsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int l2cap_get_lm(int sock, int *sec_level)
+{
+ int opt;
+ socklen_t len;
+
+ len = sizeof(opt);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, &len) < 0)
+ return -errno;
+
+ *sec_level = 0;
+
+ if (opt & L2CAP_LM_AUTH)
+ *sec_level = BT_SECURITY_LOW;
+ if (opt & L2CAP_LM_ENCRYPT)
+ *sec_level = BT_SECURITY_MEDIUM;
+ if (opt & L2CAP_LM_SECURE)
+ *sec_level = BT_SECURITY_HIGH;
+
+ return 0;
+}
+
+static int rfcomm_get_lm(int sock, int *sec_level)
+{
+ int opt;
+ socklen_t len;
+
+ len = sizeof(opt);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, &len) < 0)
+ return -errno;
+
+ *sec_level = 0;
+
+ if (opt & RFCOMM_LM_AUTH)
+ *sec_level = BT_SECURITY_LOW;
+ if (opt & RFCOMM_LM_ENCRYPT)
+ *sec_level = BT_SECURITY_MEDIUM;
+ if (opt & RFCOMM_LM_SECURE)
+ *sec_level = BT_SECURITY_HIGH;
+
+ return 0;
+}
+
+static gboolean get_sec_level(int sock, BtIOType type, int *level,
+ GError **err)
+{
+ struct bt_security sec;
+ socklen_t len;
+ int ret;
+
+ memset(&sec, 0, sizeof(sec));
+ len = sizeof(sec);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
+ *level = sec.level;
+ return TRUE;
+ }
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ if (type == BT_IO_L2CAP)
+ ret = l2cap_get_lm(sock, level);
+ else
+ ret = rfcomm_get_lm(sock, level);
+
+ if (ret < 0) {
+ ERROR_FAILED(err, "getsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
+ uint8_t mode, int master, GError **err)
+{
+ if (imtu || omtu || mode) {
+ struct l2cap_options l2o;
+ socklen_t len;
+
+ memset(&l2o, 0, sizeof(l2o));
+ len = sizeof(l2o);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (imtu)
+ l2o.imtu = imtu;
+ if (omtu)
+ l2o.omtu = omtu;
+ if (mode)
+ l2o.mode = mode;
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
+ sizeof(l2o)) < 0) {
+ ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+ }
+
+ if (master >= 0 && l2cap_set_master(sock, master) < 0) {
+ ERROR_FAILED(err, "l2cap_set_master", errno);
+ return FALSE;
+ }
+
+ if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
+ return FALSE;
+
+ return TRUE;
+}
+
+static int rfcomm_bind(int sock,
+ const bdaddr_t *src, uint8_t channel, GError **err)
+{
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = channel;
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "rfcomm_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
+{
+ int err;
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, dst);
+ addr.rc_channel = channel;
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
+{
+ if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
+ return FALSE;
+
+ if (master >= 0 && rfcomm_set_master(sock, master) < 0) {
+ ERROR_FAILED(err, "rfcomm_set_master", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int sco_bind(int sock, const bdaddr_t *src, GError **err)
+{
+ struct sockaddr_sco addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, src);
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "sco_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sco_connect(int sock, const bdaddr_t *dst)
+{
+ struct sockaddr_sco addr;
+ int err;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, dst);
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static gboolean sco_set(int sock, uint16_t mtu, GError **err)
+{
+ struct sco_options sco_opt;
+ socklen_t len;
+
+ if (!mtu)
+ return TRUE;
+
+ len = sizeof(sco_opt);
+ memset(&sco_opt, 0, len);
+ if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ sco_opt.mtu = mtu;
+ if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt,
+ sizeof(sco_opt)) < 0) {
+ ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean parse_set_opts(struct set_opts *opts, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+ const char *str;
+
+ memset(opts, 0, sizeof(*opts));
+
+ /* Set defaults */
+ opts->defer = DEFAULT_DEFER_TIMEOUT;
+ opts->master = -1;
+ opts->sec_level = BT_IO_SEC_MEDIUM;
+ opts->mode = L2CAP_MODE_BASIC;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ str = va_arg(args, const char *);
+ if (strncasecmp(str, "hci", 3) == 0)
+ hci_devba(atoi(str + 3), &opts->src);
+ else
+ str2ba(str, &opts->src);
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(&opts->src, va_arg(args, const bdaddr_t *));
+ break;
+ case BT_IO_OPT_DEST:
+ str2ba(va_arg(args, const char *), &opts->dst);
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ opts->defer = va_arg(args, int);
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ opts->sec_level = va_arg(args, int);
+ break;
+ case BT_IO_OPT_CHANNEL:
+ opts->channel = va_arg(args, int);
+ break;
+ case BT_IO_OPT_PSM:
+ opts->psm = va_arg(args, int);
+ break;
+ case BT_IO_OPT_MTU:
+ opts->mtu = va_arg(args, int);
+ opts->imtu = opts->mtu;
+ opts->omtu = opts->mtu;
+ break;
+ case BT_IO_OPT_OMTU:
+ opts->omtu = va_arg(args, int);
+ if (!opts->mtu)
+ opts->mtu = opts->omtu;
+ break;
+ case BT_IO_OPT_IMTU:
+ opts->imtu = va_arg(args, int);
+ if (!opts->mtu)
+ opts->mtu = opts->imtu;
+ break;
+ case BT_IO_OPT_MASTER:
+ opts->master = va_arg(args, gboolean);
+ break;
+ case BT_IO_OPT_MODE:
+ opts->mode = va_arg(args, int);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
+ socklen_t len, GError **err)
+{
+ socklen_t olen;
+
+ memset(src, 0, len);
+ olen = len;
+ if (getsockname(sock, src, &olen) < 0) {
+ ERROR_FAILED(err, "getsockname", errno);
+ return FALSE;
+ }
+
+ memset(dst, 0, len);
+ olen = len;
+ if (getpeername(sock, dst, &olen) < 0) {
+ ERROR_FAILED(err, "getpeername", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int l2cap_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct l2cap_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_l2 src, dst;
+ struct l2cap_options l2o;
+ int flags;
+ uint8_t dev_class[3];
+ uint16_t handle;
+ socklen_t len;
+
+ len = sizeof(l2o);
+ memset(&l2o, 0, len);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.l2_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.l2_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.l2_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ len = sizeof(int);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
+ va_arg(args, int *), &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
+ errno);
+ return FALSE;
+ }
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ if (!get_sec_level(sock, BT_IO_L2CAP,
+ va_arg(args, int *), err))
+ return FALSE;
+ break;
+ case BT_IO_OPT_PSM:
+ *(va_arg(args, uint16_t *)) = src.l2_psm ?
+ src.l2_psm : dst.l2_psm;
+ break;
+ case BT_IO_OPT_OMTU:
+ *(va_arg(args, uint16_t *)) = l2o.omtu;
+ break;
+ case BT_IO_OPT_IMTU:
+ *(va_arg(args, uint16_t *)) = l2o.imtu;
+ break;
+ case BT_IO_OPT_MASTER:
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_LM)",
+ errno);
+ return FALSE;
+ }
+ *(va_arg(args, gboolean *)) =
+ (flags & L2CAP_LM_MASTER) ? TRUE : FALSE;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (l2cap_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (l2cap_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static int rfcomm_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct rfcomm_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_rc src, dst;
+ int flags;
+ socklen_t len;
+ uint8_t dev_class[3];
+ uint16_t handle;
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.rc_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.rc_bdaddr);
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ len = sizeof(int);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
+ va_arg(args, int *), &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
+ errno);
+ return FALSE;
+ }
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ if (!get_sec_level(sock, BT_IO_RFCOMM,
+ va_arg(args, int *), err))
+ return FALSE;
+ break;
+ case BT_IO_OPT_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel ?
+ src.rc_channel : dst.rc_channel;
+ break;
+ case BT_IO_OPT_SOURCE_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel;
+ break;
+ case BT_IO_OPT_DEST_CHANNEL:
+ *(va_arg(args, uint8_t *)) = dst.rc_channel;
+ break;
+ case BT_IO_OPT_MASTER:
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(RFCOMM_LM)",
+ errno);
+ return FALSE;
+ }
+ *(va_arg(args, gboolean *)) =
+ (flags & RFCOMM_LM_MASTER) ? TRUE : FALSE;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static int sco_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct sco_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_SCO, SCO_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_sco src, dst;
+ struct sco_options sco_opt;
+ socklen_t len;
+ uint8_t dev_class[3];
+ uint16_t handle;
+
+ len = sizeof(sco_opt);
+ memset(&sco_opt, 0, len);
+ if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.sco_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.sco_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.sco_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr);
+ break;
+ case BT_IO_OPT_MTU:
+ case BT_IO_OPT_IMTU:
+ case BT_IO_OPT_OMTU:
+ *(va_arg(args, uint16_t *)) = sco_opt.mtu;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (sco_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (sco_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ int sock;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ case BT_IO_L2CAP:
+ return l2cap_get(sock, err, opt1, args);
+ case BT_IO_RFCOMM:
+ return rfcomm_get(sock, err, opt1, args);
+ case BT_IO_SCO:
+ return sco_get(sock, err, opt1, args);
+ }
+
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+}
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy, GError **err)
+{
+ int sock;
+ char c;
+ struct pollfd pfd;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLOUT;
+
+ if (poll(&pfd, 1, 0) < 0) {
+ ERROR_FAILED(err, "poll", errno);
+ return FALSE;
+ }
+
+ if (!(pfd.revents & POLLOUT)) {
+ int ret;
+ ret = read(sock, &c, 1);
+ }
+
+ accept_add(io, connect, user_data, destroy);
+
+ return TRUE;
+}
+
+gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+ struct set_opts opts;
+ int sock;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (!ret)
+ return ret;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ case BT_IO_L2CAP:
+ return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
+ opts.mode, opts.master, err);
+ case BT_IO_RFCOMM:
+ return rfcomm_set(sock, opts.sec_level, opts.master, err);
+ case BT_IO_SCO:
+ return sco_set(sock, opts.mtu, err);
+ }
+
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+}
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = get_valist(io, type, err, opt1, args);
+ va_end(args);
+
+ return ret;
+}
+
+static GIOChannel *create_io(BtIOType type, gboolean server,
+ struct set_opts *opts, GError **err)
+{
+ int sock;
+ GIOChannel *io;
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
+ return NULL;
+ }
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
+ if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
+ goto failed;
+ break;
+ case BT_IO_L2CAP:
+ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
+ return NULL;
+ }
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
+ if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
+ opts->mode, opts->master, err))
+ goto failed;
+ break;
+ case BT_IO_RFCOMM:
+ sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
+ return NULL;
+ }
+ if (rfcomm_bind(sock, &opts->src,
+ server ? opts->channel : 0, err) < 0)
+ goto failed;
+ if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
+ goto failed;
+ break;
+ case BT_IO_SCO:
+ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
+ return NULL;
+ }
+ if (sco_bind(sock, &opts->src, err) < 0)
+ goto failed;
+ if (!sco_set(sock, opts->mtu, err))
+ goto failed;
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return NULL;
+ }
+
+ io = g_io_channel_unix_new(sock);
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+
+ return io;
+
+failed:
+ close(sock);
+
+ return NULL;
+}
+
+GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy,
+ GError **gerr, BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int err, sock;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, gerr, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, FALSE, &opts, gerr);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ err = l2cap_connect(sock, &opts.dst, 0);
+ break;
+ case BT_IO_L2CAP:
+ err = l2cap_connect(sock, &opts.dst, opts.psm);
+ break;
+ case BT_IO_RFCOMM:
+ err = rfcomm_connect(sock, &opts.dst, opts.channel);
+ break;
+ case BT_IO_SCO:
+ err = sco_connect(sock, &opts.dst);
+ break;
+ default:
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return NULL;
+ }
+
+ if (err < 0) {
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
+ "connect: %s (%d)", strerror(-err), -err);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ connect_add(io, connect, user_data, destroy);
+
+ return io;
+}
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int sock;
+ gboolean ret;
+
+ if (type == BT_IO_L2RAW) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Server L2CAP RAW sockets not supported");
+ return NULL;
+ }
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, TRUE, &opts, err);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ if (confirm)
+ setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
+ sizeof(opts.defer));
+
+ if (listen(sock, 5) < 0) {
+ ERROR_FAILED(err, "listen", errno);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ server_add(io, connect, confirm, user_data, destroy);
+
+ return io;
+}
+
+GQuark bt_io_error_quark(void)
+{
+ return g_quark_from_static_string("bt-io-error-quark");
+}
diff --git a/btio/btio.h b/btio/btio.h
new file mode 100644
index 0000000..e9dcc9f
--- /dev/null
+++ b/btio/btio.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifndef BT_IO_H
+#define BT_IO_H
+
+#include <glib.h>
+
+typedef enum {
+ BT_IO_ERROR_DISCONNECTED,
+ BT_IO_ERROR_CONNECT_FAILED,
+ BT_IO_ERROR_FAILED,
+ BT_IO_ERROR_INVALID_ARGS,
+} BtIOError;
+
+#define BT_IO_ERROR bt_io_error_quark()
+
+GQuark bt_io_error_quark(void);
+
+typedef enum {
+ BT_IO_L2RAW,
+ BT_IO_L2CAP,
+ BT_IO_RFCOMM,
+ BT_IO_SCO,
+} BtIOType;
+
+typedef enum {
+ BT_IO_OPT_INVALID = 0,
+ BT_IO_OPT_SOURCE,
+ BT_IO_OPT_SOURCE_BDADDR,
+ BT_IO_OPT_DEST,
+ BT_IO_OPT_DEST_BDADDR,
+ BT_IO_OPT_DEFER_TIMEOUT,
+ BT_IO_OPT_SEC_LEVEL,
+ BT_IO_OPT_CHANNEL,
+ BT_IO_OPT_SOURCE_CHANNEL,
+ BT_IO_OPT_DEST_CHANNEL,
+ BT_IO_OPT_PSM,
+ BT_IO_OPT_MTU,
+ BT_IO_OPT_OMTU,
+ BT_IO_OPT_IMTU,
+ BT_IO_OPT_MASTER,
+ BT_IO_OPT_HANDLE,
+ BT_IO_OPT_CLASS,
+ BT_IO_OPT_MODE,
+} BtIOOption;
+
+typedef enum {
+ BT_IO_SEC_SDP = 0,
+ BT_IO_SEC_LOW,
+ BT_IO_SEC_MEDIUM,
+ BT_IO_SEC_HIGH,
+} BtIOSecLevel;
+
+typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
+
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy, GError **err);
+
+gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy,
+ GError **err, BtIOOption opt1, ...);
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...);
+
+#endif
diff --git a/src/btio.c b/src/btio.c
deleted file mode 100644
index 42a3bcd..0000000
--- a/src/btio.c
+++ /dev/null
@@ -1,1299 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sco.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-
-#include <glib.h>
-
-#include "btio.h"
-
-#define ERROR_FAILED(gerr, str, err) \
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
- str ": %s (%d)", strerror(err), err)
-
-#define DEFAULT_DEFER_TIMEOUT 30
-
-struct set_opts {
- bdaddr_t src;
- bdaddr_t dst;
- int defer;
- int sec_level;
- uint8_t channel;
- uint16_t psm;
- uint16_t mtu;
- uint16_t imtu;
- uint16_t omtu;
- int master;
- uint8_t mode;
-};
-
-struct connect {
- BtIOConnect connect;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-struct accept {
- BtIOConnect connect;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-struct server {
- BtIOConnect connect;
- BtIOConfirm confirm;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-static void server_remove(struct server *server)
-{
- if (server->destroy)
- server->destroy(server->user_data);
- g_free(server);
-}
-
-static void connect_remove(struct connect *conn)
-{
- if (conn->destroy)
- conn->destroy(conn->user_data);
- g_free(conn);
-}
-
-static void accept_remove(struct accept *accept)
-{
- if (accept->destroy)
- accept->destroy(accept->user_data);
- g_free(accept);
-}
-
-static gboolean check_nval(GIOChannel *io)
-{
- struct pollfd fds;
-
- memset(&fds, 0, sizeof(fds));
- fds.fd = g_io_channel_unix_get_fd(io);
- fds.events = POLLNVAL;
-
- if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLNVAL))
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct accept *accept = user_data;
- GError *err = NULL;
-
- /* If the user aborted this accept attempt */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR))
- g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
- "HUP or ERR on socket");
-
- accept->connect(io, err, accept->user_data);
-
- g_clear_error(&err);
-
- return FALSE;
-}
-
-static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct connect *conn = user_data;
- GError *gerr = NULL;
-
- /* If the user aborted this connect attempt */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- if (cond & G_IO_OUT) {
- int err = 0, sock = g_io_channel_unix_get_fd(io);
- socklen_t len = sizeof(err);
-
- if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
- err = errno;
-
- if (err)
- g_set_error(&gerr, BT_IO_ERROR,
- BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
- strerror(err), err);
- } else if (cond & (G_IO_HUP | G_IO_ERR))
- g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
- "HUP or ERR on socket");
-
- conn->connect(io, gerr, conn->user_data);
-
- if (gerr)
- g_error_free(gerr);
-
- return FALSE;
-}
-
-static gboolean server_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct server *server = user_data;
- int srv_sock, cli_sock;
- GIOChannel *cli_io;
-
- /* If the user closed the server */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- srv_sock = g_io_channel_unix_get_fd(io);
-
- cli_sock = accept(srv_sock, NULL, NULL);
- if (cli_sock < 0)
- return TRUE;
-
- cli_io = g_io_channel_unix_new(cli_sock);
-
- g_io_channel_set_close_on_unref(cli_io, TRUE);
- g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
-
- if (server->confirm)
- server->confirm(cli_io, server->user_data);
- else
- server->connect(cli_io, NULL, server->user_data);
-
- g_io_channel_unref(cli_io);
-
- return TRUE;
-}
-
-static void server_add(GIOChannel *io, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy)
-{
- struct server *server;
- GIOCondition cond;
-
- server = g_new0(struct server, 1);
- server->connect = connect;
- server->confirm = confirm;
- server->user_data = user_data;
- server->destroy = destroy;
-
- cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
- (GDestroyNotify) server_remove);
-}
-
-static void connect_add(GIOChannel *io, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy)
-{
- struct connect *conn;
- GIOCondition cond;
-
- conn = g_new0(struct connect, 1);
- conn->connect = connect;
- conn->user_data = user_data;
- conn->destroy = destroy;
-
- cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb, conn,
- (GDestroyNotify) connect_remove);
-}
-
-static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy)
-{
- struct accept *accept;
- GIOCondition cond;
-
- accept = g_new0(struct accept, 1);
- accept->connect = connect;
- accept->user_data = user_data;
- accept->destroy = destroy;
-
- cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
- (GDestroyNotify) accept_remove);
-}
-
-static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
-{
- struct sockaddr_l2 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, src);
- addr.l2_psm = htobs(psm);
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "l2cap_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
-{
- int err;
- struct sockaddr_l2 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, dst);
- addr.l2_psm = htobs(psm);
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static int l2cap_set_master(int sock, int master)
-{
- int flags;
- socklen_t len;
-
- len = sizeof(flags);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0)
- return -errno;
-
- if (master) {
- if (flags & L2CAP_LM_MASTER)
- return 0;
- flags |= L2CAP_LM_MASTER;
- } else {
- if (!(flags & L2CAP_LM_MASTER))
- return 0;
- flags &= ~L2CAP_LM_MASTER;
- }
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, sizeof(flags)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int rfcomm_set_master(int sock, int master)
-{
- int flags;
- socklen_t len;
-
- len = sizeof(flags);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0)
- return -errno;
-
- if (master) {
- if (flags & RFCOMM_LM_MASTER)
- return 0;
- flags |= RFCOMM_LM_MASTER;
- } else {
- if (!(flags & RFCOMM_LM_MASTER))
- return 0;
- flags &= ~RFCOMM_LM_MASTER;
- }
-
- if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, sizeof(flags)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int l2cap_set_lm(int sock, int level)
-{
- int lm_map[] = {
- 0,
- L2CAP_LM_AUTH,
- L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,
- L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE,
- }, opt = lm_map[level];
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int rfcomm_set_lm(int sock, int level)
-{
- int lm_map[] = {
- 0,
- RFCOMM_LM_AUTH,
- RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
- RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
- }, opt = lm_map[level];
-
- if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
- return -errno;
-
- return 0;
-}
-
-static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
-{
- struct bt_security sec;
- int ret;
-
- if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Valid security level range is %d-%d",
- BT_SECURITY_LOW, BT_SECURITY_HIGH);
- return FALSE;
- }
-
- memset(&sec, 0, sizeof(sec));
- sec.level = level;
-
- if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
- sizeof(sec)) == 0)
- return TRUE;
-
- if (errno != ENOPROTOOPT) {
- ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
- return FALSE;
- }
-
- if (type == BT_IO_L2CAP)
- ret = l2cap_set_lm(sock, level);
- else
- ret = rfcomm_set_lm(sock, level);
-
- if (ret < 0) {
- ERROR_FAILED(err, "setsockopt(LM)", -ret);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int l2cap_get_lm(int sock, int *sec_level)
-{
- int opt;
- socklen_t len;
-
- len = sizeof(opt);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, &len) < 0)
- return -errno;
-
- *sec_level = 0;
-
- if (opt & L2CAP_LM_AUTH)
- *sec_level = BT_SECURITY_LOW;
- if (opt & L2CAP_LM_ENCRYPT)
- *sec_level = BT_SECURITY_MEDIUM;
- if (opt & L2CAP_LM_SECURE)
- *sec_level = BT_SECURITY_HIGH;
-
- return 0;
-}
-
-static int rfcomm_get_lm(int sock, int *sec_level)
-{
- int opt;
- socklen_t len;
-
- len = sizeof(opt);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, &len) < 0)
- return -errno;
-
- *sec_level = 0;
-
- if (opt & RFCOMM_LM_AUTH)
- *sec_level = BT_SECURITY_LOW;
- if (opt & RFCOMM_LM_ENCRYPT)
- *sec_level = BT_SECURITY_MEDIUM;
- if (opt & RFCOMM_LM_SECURE)
- *sec_level = BT_SECURITY_HIGH;
-
- return 0;
-}
-
-static gboolean get_sec_level(int sock, BtIOType type, int *level,
- GError **err)
-{
- struct bt_security sec;
- socklen_t len;
- int ret;
-
- memset(&sec, 0, sizeof(sec));
- len = sizeof(sec);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
- *level = sec.level;
- return TRUE;
- }
-
- if (errno != ENOPROTOOPT) {
- ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno);
- return FALSE;
- }
-
- if (type == BT_IO_L2CAP)
- ret = l2cap_get_lm(sock, level);
- else
- ret = rfcomm_get_lm(sock, level);
-
- if (ret < 0) {
- ERROR_FAILED(err, "getsockopt(LM)", -ret);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
- uint8_t mode, int master, GError **err)
-{
- if (imtu || omtu || mode) {
- struct l2cap_options l2o;
- socklen_t len;
-
- memset(&l2o, 0, sizeof(l2o));
- len = sizeof(l2o);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
-
- if (imtu)
- l2o.imtu = imtu;
- if (omtu)
- l2o.omtu = omtu;
- if (mode)
- l2o.mode = mode;
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
- sizeof(l2o)) < 0) {
- ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
- }
-
- if (master >= 0 && l2cap_set_master(sock, master) < 0) {
- ERROR_FAILED(err, "l2cap_set_master", errno);
- return FALSE;
- }
-
- if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
- return FALSE;
-
- return TRUE;
-}
-
-static int rfcomm_bind(int sock,
- const bdaddr_t *src, uint8_t channel, GError **err)
-{
- struct sockaddr_rc addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, src);
- addr.rc_channel = channel;
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "rfcomm_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
-{
- int err;
- struct sockaddr_rc addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, dst);
- addr.rc_channel = channel;
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
-{
- if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
- return FALSE;
-
- if (master >= 0 && rfcomm_set_master(sock, master) < 0) {
- ERROR_FAILED(err, "rfcomm_set_master", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int sco_bind(int sock, const bdaddr_t *src, GError **err)
-{
- struct sockaddr_sco addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, src);
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "sco_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int sco_connect(int sock, const bdaddr_t *dst)
-{
- struct sockaddr_sco addr;
- int err;
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, dst);
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static gboolean sco_set(int sock, uint16_t mtu, GError **err)
-{
- struct sco_options sco_opt;
- socklen_t len;
-
- if (!mtu)
- return TRUE;
-
- len = sizeof(sco_opt);
- memset(&sco_opt, 0, len);
- if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- sco_opt.mtu = mtu;
- if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt,
- sizeof(sco_opt)) < 0) {
- ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean parse_set_opts(struct set_opts *opts, GError **err,
- BtIOOption opt1, va_list args)
-{
- BtIOOption opt = opt1;
- const char *str;
-
- memset(opts, 0, sizeof(*opts));
-
- /* Set defaults */
- opts->defer = DEFAULT_DEFER_TIMEOUT;
- opts->master = -1;
- opts->sec_level = BT_IO_SEC_MEDIUM;
- opts->mode = L2CAP_MODE_BASIC;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- str = va_arg(args, const char *);
- if (strncasecmp(str, "hci", 3) == 0)
- hci_devba(atoi(str + 3), &opts->src);
- else
- str2ba(str, &opts->src);
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(&opts->src, va_arg(args, const bdaddr_t *));
- break;
- case BT_IO_OPT_DEST:
- str2ba(va_arg(args, const char *), &opts->dst);
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- opts->defer = va_arg(args, int);
- break;
- case BT_IO_OPT_SEC_LEVEL:
- opts->sec_level = va_arg(args, int);
- break;
- case BT_IO_OPT_CHANNEL:
- opts->channel = va_arg(args, int);
- break;
- case BT_IO_OPT_PSM:
- opts->psm = va_arg(args, int);
- break;
- case BT_IO_OPT_MTU:
- opts->mtu = va_arg(args, int);
- opts->imtu = opts->mtu;
- opts->omtu = opts->mtu;
- break;
- case BT_IO_OPT_OMTU:
- opts->omtu = va_arg(args, int);
- if (!opts->mtu)
- opts->mtu = opts->omtu;
- break;
- case BT_IO_OPT_IMTU:
- opts->imtu = va_arg(args, int);
- if (!opts->mtu)
- opts->mtu = opts->imtu;
- break;
- case BT_IO_OPT_MASTER:
- opts->master = va_arg(args, gboolean);
- break;
- case BT_IO_OPT_MODE:
- opts->mode = va_arg(args, int);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
- socklen_t len, GError **err)
-{
- socklen_t olen;
-
- memset(src, 0, len);
- olen = len;
- if (getsockname(sock, src, &olen) < 0) {
- ERROR_FAILED(err, "getsockname", errno);
- return FALSE;
- }
-
- memset(dst, 0, len);
- olen = len;
- if (getpeername(sock, dst, &olen) < 0) {
- ERROR_FAILED(err, "getpeername", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int l2cap_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct l2cap_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
- va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_l2 src, dst;
- struct l2cap_options l2o;
- int flags;
- uint8_t dev_class[3];
- uint16_t handle;
- socklen_t len;
-
- len = sizeof(l2o);
- memset(&l2o, 0, len);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.l2_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.l2_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.l2_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- len = sizeof(int);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
- va_arg(args, int *), &len) < 0) {
- ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
- errno);
- return FALSE;
- }
- break;
- case BT_IO_OPT_SEC_LEVEL:
- if (!get_sec_level(sock, BT_IO_L2CAP,
- va_arg(args, int *), err))
- return FALSE;
- break;
- case BT_IO_OPT_PSM:
- *(va_arg(args, uint16_t *)) = src.l2_psm ?
- src.l2_psm : dst.l2_psm;
- break;
- case BT_IO_OPT_OMTU:
- *(va_arg(args, uint16_t *)) = l2o.omtu;
- break;
- case BT_IO_OPT_IMTU:
- *(va_arg(args, uint16_t *)) = l2o.imtu;
- break;
- case BT_IO_OPT_MASTER:
- len = sizeof(flags);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_LM)",
- errno);
- return FALSE;
- }
- *(va_arg(args, gboolean *)) =
- (flags & L2CAP_LM_MASTER) ? TRUE : FALSE;
- break;
- case BT_IO_OPT_HANDLE:
- if (l2cap_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (l2cap_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static int rfcomm_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct rfcomm_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
- va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_rc src, dst;
- int flags;
- socklen_t len;
- uint8_t dev_class[3];
- uint16_t handle;
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.rc_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.rc_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.rc_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.rc_bdaddr);
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- len = sizeof(int);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
- va_arg(args, int *), &len) < 0) {
- ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
- errno);
- return FALSE;
- }
- break;
- case BT_IO_OPT_SEC_LEVEL:
- if (!get_sec_level(sock, BT_IO_RFCOMM,
- va_arg(args, int *), err))
- return FALSE;
- break;
- case BT_IO_OPT_CHANNEL:
- *(va_arg(args, uint8_t *)) = src.rc_channel ?
- src.rc_channel : dst.rc_channel;
- break;
- case BT_IO_OPT_SOURCE_CHANNEL:
- *(va_arg(args, uint8_t *)) = src.rc_channel;
- break;
- case BT_IO_OPT_DEST_CHANNEL:
- *(va_arg(args, uint8_t *)) = dst.rc_channel;
- break;
- case BT_IO_OPT_MASTER:
- len = sizeof(flags);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(RFCOMM_LM)",
- errno);
- return FALSE;
- }
- *(va_arg(args, gboolean *)) =
- (flags & RFCOMM_LM_MASTER) ? TRUE : FALSE;
- break;
- case BT_IO_OPT_HANDLE:
- if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static int sco_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct sco_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_SCO, SCO_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_sco src, dst;
- struct sco_options sco_opt;
- socklen_t len;
- uint8_t dev_class[3];
- uint16_t handle;
-
- len = sizeof(sco_opt);
- memset(&sco_opt, 0, len);
- if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.sco_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.sco_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.sco_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr);
- break;
- case BT_IO_OPT_MTU:
- case BT_IO_OPT_IMTU:
- case BT_IO_OPT_OMTU:
- *(va_arg(args, uint16_t *)) = sco_opt.mtu;
- break;
- case BT_IO_OPT_HANDLE:
- if (sco_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (sco_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, va_list args)
-{
- int sock;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_get(sock, err, opt1, args);
- case BT_IO_RFCOMM:
- return rfcomm_get(sock, err, opt1, args);
- case BT_IO_SCO:
- return sco_get(sock, err, opt1, args);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy, GError **err)
-{
- int sock;
- char c;
- struct pollfd pfd;
-
- sock = g_io_channel_unix_get_fd(io);
-
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = sock;
- pfd.events = POLLOUT;
-
- if (poll(&pfd, 1, 0) < 0) {
- ERROR_FAILED(err, "poll", errno);
- return FALSE;
- }
-
- if (!(pfd.revents & POLLOUT)) {
- int ret;
- ret = read(sock, &c, 1);
- }
-
- accept_add(io, connect, user_data, destroy);
-
- return TRUE;
-}
-
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
- struct set_opts opts;
- int sock;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (!ret)
- return ret;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
- opts.mode, opts.master, err);
- case BT_IO_RFCOMM:
- return rfcomm_set(sock, opts.sec_level, opts.master, err);
- case BT_IO_SCO:
- return sco_set(sock, opts.mtu, err);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
-
- va_start(args, opt1);
- ret = get_valist(io, type, err, opt1, args);
- va_end(args);
-
- return ret;
-}
-
-static GIOChannel *create_io(BtIOType type, gboolean server,
- struct set_opts *opts, GError **err)
-{
- int sock;
- GIOChannel *io;
-
- switch (type) {
- case BT_IO_L2RAW:
- sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
- return NULL;
- }
- if (l2cap_bind(sock, &opts->src,
- server ? opts->psm : 0, err) < 0)
- goto failed;
- if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
- goto failed;
- break;
- case BT_IO_L2CAP:
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
- return NULL;
- }
- if (l2cap_bind(sock, &opts->src,
- server ? opts->psm : 0, err) < 0)
- goto failed;
- if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
- opts->mode, opts->master, err))
- goto failed;
- break;
- case BT_IO_RFCOMM:
- sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
- return NULL;
- }
- if (rfcomm_bind(sock, &opts->src,
- server ? opts->channel : 0, err) < 0)
- goto failed;
- if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
- goto failed;
- break;
- case BT_IO_SCO:
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
- return NULL;
- }
- if (sco_bind(sock, &opts->src, err) < 0)
- goto failed;
- if (!sco_set(sock, opts->mtu, err))
- goto failed;
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return NULL;
- }
-
- io = g_io_channel_unix_new(sock);
-
- g_io_channel_set_close_on_unref(io, TRUE);
- g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
-
- return io;
-
-failed:
- close(sock);
-
- return NULL;
-}
-
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
- GError **gerr, BtIOOption opt1, ...)
-{
- GIOChannel *io;
- va_list args;
- struct set_opts opts;
- int err, sock;
- gboolean ret;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, gerr, opt1, args);
- va_end(args);
-
- if (ret == FALSE)
- return NULL;
-
- io = create_io(type, FALSE, &opts, gerr);
- if (io == NULL)
- return NULL;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- err = l2cap_connect(sock, &opts.dst, 0);
- break;
- case BT_IO_L2CAP:
- err = l2cap_connect(sock, &opts.dst, opts.psm);
- break;
- case BT_IO_RFCOMM:
- err = rfcomm_connect(sock, &opts.dst, opts.channel);
- break;
- case BT_IO_SCO:
- err = sco_connect(sock, &opts.dst);
- break;
- default:
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return NULL;
- }
-
- if (err < 0) {
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
- "connect: %s (%d)", strerror(-err), -err);
- g_io_channel_unref(io);
- return NULL;
- }
-
- connect_add(io, connect, user_data, destroy);
-
- return io;
-}
-
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy, GError **err,
- BtIOOption opt1, ...)
-{
- GIOChannel *io;
- va_list args;
- struct set_opts opts;
- int sock;
- gboolean ret;
-
- if (type == BT_IO_L2RAW) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Server L2CAP RAW sockets not supported");
- return NULL;
- }
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (ret == FALSE)
- return NULL;
-
- io = create_io(type, TRUE, &opts, err);
- if (io == NULL)
- return NULL;
-
- sock = g_io_channel_unix_get_fd(io);
-
- if (confirm)
- setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
- sizeof(opts.defer));
-
- if (listen(sock, 5) < 0) {
- ERROR_FAILED(err, "listen", errno);
- g_io_channel_unref(io);
- return NULL;
- }
-
- server_add(io, connect, confirm, user_data, destroy);
-
- return io;
-}
-
-GQuark bt_io_error_quark(void)
-{
- return g_quark_from_static_string("bt-io-error-quark");
-}
diff --git a/src/btio.h b/src/btio.h
deleted file mode 100644
index e9dcc9f..0000000
--- a/src/btio.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#ifndef BT_IO_H
-#define BT_IO_H
-
-#include <glib.h>
-
-typedef enum {
- BT_IO_ERROR_DISCONNECTED,
- BT_IO_ERROR_CONNECT_FAILED,
- BT_IO_ERROR_FAILED,
- BT_IO_ERROR_INVALID_ARGS,
-} BtIOError;
-
-#define BT_IO_ERROR bt_io_error_quark()
-
-GQuark bt_io_error_quark(void);
-
-typedef enum {
- BT_IO_L2RAW,
- BT_IO_L2CAP,
- BT_IO_RFCOMM,
- BT_IO_SCO,
-} BtIOType;
-
-typedef enum {
- BT_IO_OPT_INVALID = 0,
- BT_IO_OPT_SOURCE,
- BT_IO_OPT_SOURCE_BDADDR,
- BT_IO_OPT_DEST,
- BT_IO_OPT_DEST_BDADDR,
- BT_IO_OPT_DEFER_TIMEOUT,
- BT_IO_OPT_SEC_LEVEL,
- BT_IO_OPT_CHANNEL,
- BT_IO_OPT_SOURCE_CHANNEL,
- BT_IO_OPT_DEST_CHANNEL,
- BT_IO_OPT_PSM,
- BT_IO_OPT_MTU,
- BT_IO_OPT_OMTU,
- BT_IO_OPT_IMTU,
- BT_IO_OPT_MASTER,
- BT_IO_OPT_HANDLE,
- BT_IO_OPT_CLASS,
- BT_IO_OPT_MODE,
-} BtIOOption;
-
-typedef enum {
- BT_IO_SEC_SDP = 0,
- BT_IO_SEC_LOW,
- BT_IO_SEC_MEDIUM,
- BT_IO_SEC_HIGH,
-} BtIOSecLevel;
-
-typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
-
-typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
-
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy, GError **err);
-
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
- GError **err, BtIOOption opt1, ...);
-
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy, GError **err,
- BtIOOption opt1, ...);
-
-#endif
--
1.7.0.4
^ permalink raw reply related
* [PATCH 1/8] btio: Remove blank line at EOF
From: Zhenhua Zhang @ 2010-08-19 14:21 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1282227676-15381-1-git-send-email-zhenhua.zhang@intel.com>
---
src/btio.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/src/btio.c b/src/btio.c
index 485eec6..42a3bcd 100644
--- a/src/btio.c
+++ b/src/btio.c
@@ -1297,4 +1297,3 @@ GQuark bt_io_error_quark(void)
{
return g_quark_from_static_string("bt-io-error-quark");
}
-
--
1.7.0.4
^ permalink raw reply related
* [PATCH 0/8] Clean up Obex btio.[ch] and make it self contained
From: Zhenhua Zhang @ 2010-08-19 14:21 UTC (permalink / raw)
To: linux-bluetooth
Hi,
This series of patches is to seperate btio.[ch] from src to btio directory. To make btio.[ch] self contained for obexd, there're some cleanup work:
1. remove unused bt_io_set(). It is neither used by bluez or obexd.
2. remove unused SCO/L2RAW related code for Obexd. Note: BlueZ code requires SCO/L2RAW related functions. We may consider to add them back later.
3. replace void *userdata with gpointer userdata. To make it consistent with bluez btio.c
4. refactor hci_devba into devid2ba. Remove dependence with hci*.h
5. Remove libbluetooth dependence for obexd.
Regards,
Zhenhua
^ permalink raw reply
* Re: [PATCH 1/2] Add handling of single contact's fields handled in VCARD structure
From: Johan Hedberg @ 2010-08-19 13:36 UTC (permalink / raw)
To: Rafal Michalski; +Cc: linux-bluetooth
In-Reply-To: <1282218500-18458-1-git-send-email-michalski.raf@gmail.com>
Hi Rafal,
On Thu, Aug 19, 2010, Rafal Michalski wrote:
> After pulling contacts these fields weren't present in downloaded
> VCARD structure in spite of that these fields existed (not empty).
>
> This patch adds handling of fields: BDAY, NICKNAME, URL, PHOTO
> To solve this problem extending number of columns and queries of database
> was needed especially. Displaying these fields is done by genaral
> functions: vcard_printf_slash_tag, vcard_printf_slash_slash_tag.
> Of course fields mentioned above were added to phonebook_contact structure
> as char * type to save gained data.
> ---
> plugins/phonebook-tracker.c | 29 +++++++++++++++----
> plugins/vcard.c | 66 +++++++++++++++++++++++++++++++++++++++++++
> plugins/vcard.h | 4 ++
> 3 files changed, 93 insertions(+), 6 deletions(-)
Please always check that your patches compile cleanly with
./bootstrap-configure before submitting upstream. I get this when
compiling your patch:
plugins/vcard.c: In function ‘vcard_printf_tag’:
plugins/vcard.c:268: error: ISO C90 forbids mixed declarations and code
plugins/vcard.c: In function ‘vcard_printf_slash_tag’:
plugins/vcard.c:292: error: ISO C90 forbids mixed declarations and code
plugins/vcard.c:302: error: ISO C90 forbids mixed declarations and code
make[1]: *** [plugins/vcard.o] Error 1
Furthermore, there were the following issues I spotted:
> +static void vcard_printf_tag(GString *vcards, const char *tag,
> + const char* category, const char *fld)
That should be "char *category" and not "char* category"
> + char separator = '\0', *type = "";
> + char buf[LEN_MAX];
> +
> + if (category && strlen(category)) {
> + separator = ';';
> + type = "TYPE=";
> + }
> +
> + snprintf(buf, sizeof(buf), "%s%c%s%s", tag, separator, type, category);
sprintf("...%c...", '\0'); will embed a null-byte into the string which
I'm sure is something that you don't want. Just use a normal string and
%s instead, i.e. "".
> +static void vcard_printf_slash_tag(GString *vcards, const char *tag,
> + const char* category, const char *fld)
Again, char *foo instead of char* foo.
> + char separator = '\0', *type = "";
> + char buf[LEN_MAX];
> +
> + if (category && strlen(category)) {
> + separator = ';';
> + type = "TYPE=";
> + }
> +
> + snprintf(buf, sizeof(buf), "%s%c%s%s", tag, separator, type, category);
And the same problem with the null-byte.
Johan
^ permalink raw reply
* [PATCH 1/2] Add handling of single contact's fields handled in VCARD structure
From: Rafal Michalski @ 2010-08-19 11:56 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Michalski
After pulling contacts these fields weren't present in downloaded
VCARD structure in spite of that these fields existed (not empty).
This patch adds handling of fields: BDAY, NICKNAME, URL, PHOTO
To solve this problem extending number of columns and queries of database
was needed especially. Displaying these fields is done by genaral
functions: vcard_printf_slash_tag, vcard_printf_tag.
---
plugins/phonebook-tracker.c | 29 +++++++++++++++----
plugins/vcard.c | 66 +++++++++++++++++++++++++++++++++++++++++++
plugins/vcard.h | 4 ++
3 files changed, 93 insertions(+), 6 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 1109968..fd92125 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,16 +43,16 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 21
-#define PULL_QUERY_COL_AMOUNT 22
+#define CONTACTS_ID_COL 25
+#define PULL_QUERY_COL_AMOUNT 26
#define COL_HOME_NUMBER 0
#define COL_HOME_EMAIL 7
#define COL_WORK_NUMBER 8
#define COL_FAX_NUMBER 16
#define COL_WORK_EMAIL 17
-#define COL_DATE 18
-#define COL_SENT 19
-#define COL_ANSWERED 20
+#define COL_DATE 22
+#define COL_SENT 23
+#define COL_ANSWERED 24
#define CONTACTS_QUERY_ALL \
"SELECT ?v nco:fullname(?c) " \
@@ -62,6 +62,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"\"NOTACALL\" \"false\" \"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
@@ -106,6 +108,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -151,6 +155,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -196,6 +202,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -239,6 +247,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -306,6 +316,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "nco:birthDate(<%s>) nco:nickname(<%s>) nco:websiteUrl(<%s>) " \
+ "nco:photo(<%s>) " \
"\"NOTACALL\" \"false\" \"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
@@ -774,6 +786,10 @@ add_entry:
contact->region = g_strdup(reply[13]);
contact->postal = g_strdup(reply[14]);
contact->country = g_strdup(reply[15]);
+ contact->birthday = g_strdup(reply[18]);
+ contact->nickname = g_strdup(reply[19]);
+ contact->website = g_strdup(reply[20]);
+ contact->photo = g_strdup(reply[21]);
set_call_type(contact, reply[COL_DATE], reply[COL_SENT],
reply[COL_ANSWERED]);
@@ -978,7 +994,8 @@ int phonebook_get_entry(const char *folder, const char *id,
data->vcardentry = TRUE;
query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id, id,
- id, id, id, id, id, id, id);
+ id, id, id, id, id, id, id,
+ id, id, id, id);
ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 18b5952..c45bfcd 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -256,6 +256,54 @@ static void vcard_printf_number(GString *vcards, uint8_t format,
vcard_printf(vcards, buf, number);
}
+static void vcard_printf_tag(GString *vcards, const char *tag,
+ const char* category, const char *fld)
+{
+ if (tag == NULL || strlen(tag) == 0)
+ return;
+
+ if (fld == NULL || strlen(fld) == 0)
+ return;
+
+ char separator = '\0', *type = "";
+ char buf[LEN_MAX];
+
+ if (category && strlen(category)) {
+ separator = ';';
+ type = "TYPE=";
+ }
+
+ snprintf(buf, sizeof(buf), "%s%c%s%s", tag, separator, type, category);
+
+ vcard_printf(vcards, "%s:%s", buf, fld);
+}
+
+static void vcard_printf_slash_tag(GString *vcards, const char *tag,
+ const char* category, const char *fld)
+{
+ int len;
+
+ if (tag == NULL || strlen(tag) == 0)
+ return;
+
+ if (fld == NULL || (len = strlen(fld)) == 0)
+ return;
+
+ char separator = '\0', *type = "";
+ char buf[LEN_MAX];
+
+ if (category && strlen(category)) {
+ separator = ';';
+ type = "TYPE=";
+ }
+
+ snprintf(buf, sizeof(buf), "%s%c%s%s", tag, separator, type, category);
+
+ char field[LEN_MAX];
+ add_slash(field, fld, LEN_MAX, len);
+ vcard_printf(vcards, "%s:%s", buf, field);
+}
+
static void vcard_printf_email(GString *vcards, const char *email)
{
int len = 0;
@@ -354,6 +402,20 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
if (filter & FILTER_ADR)
vcard_printf_adr(vcards, contact);
+ if (filter & FILTER_BDAY)
+ vcard_printf_tag(vcards, "BDAY", NULL, contact->birthday);
+
+ if (filter & FILTER_NICKNAME)
+ vcard_printf_slash_tag(vcards, "NICKNAME", NULL,
+ contact->nickname);
+
+ if (filter & FILTER_URL)
+ vcard_printf_slash_tag(vcards, "URL", "INTERNET",
+ contact->website);
+
+ if (filter & FILTER_PHOTO)
+ vcard_printf_tag(vcards, "PHOTO", NULL, contact->photo);
+
if (filter & FILTER_X_IRMC_CALL_DATETIME)
vcard_printf_datetime(vcards, contact);
@@ -392,6 +454,10 @@ void phonebook_contact_free(struct phonebook_contact *contact)
g_free(contact->region);
g_free(contact->postal);
g_free(contact->country);
+ g_free(contact->birthday);
+ g_free(contact->nickname);
+ g_free(contact->website);
+ g_free(contact->photo);
g_free(contact->datetime);
g_free(contact);
}
diff --git a/plugins/vcard.h b/plugins/vcard.h
index fa571e4..a9809ea 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -55,6 +55,10 @@ struct phonebook_contact {
char *region;
char *postal;
char *country;
+ char *birthday;
+ char *nickname;
+ char *website;
+ char *photo;
char *datetime;
int calltype;
};
--
1.6.3.3
^ permalink raw reply related
* [PATCH 2/2] Add handling of ORG contact's fields handled in VCARD structure
From: Rafal Michalski @ 2010-08-19 11:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Michalski
After pulling contacts these fields weren't present in downloaded
VCARD structure in spite of that these fields existed (not empty).
This patch adds handling of fields grouped under ORG tag.
To solve this problem extending number of columns and queries of database
was needed especially. Of course fields mentioned above were added to
phonebook_contact structure as char * type to save gained data.
---
plugins/phonebook-tracker.c | 38 +++++++++++++++++++++++++++-----------
plugins/vcard.c | 30 ++++++++++++++++++++++++++++++
plugins/vcard.h | 3 +++
3 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index fd92125..3f63dcb 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,16 +43,16 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 25
-#define PULL_QUERY_COL_AMOUNT 26
+#define CONTACTS_ID_COL 28
+#define PULL_QUERY_COL_AMOUNT 29
#define COL_HOME_NUMBER 0
#define COL_HOME_EMAIL 7
#define COL_WORK_NUMBER 8
#define COL_FAX_NUMBER 16
#define COL_WORK_EMAIL 17
-#define COL_DATE 22
-#define COL_SENT 23
-#define COL_ANSWERED 24
+#define COL_DATE 25
+#define COL_SENT 26
+#define COL_ANSWERED 27
#define CONTACTS_QUERY_ALL \
"SELECT ?v nco:fullname(?c) " \
@@ -63,7 +63,8 @@
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
"nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
- "nco:photo(?c) " \
+ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \
+ "nco:role(?a) " \
"\"NOTACALL\" \"false\" \"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
@@ -83,6 +84,7 @@
"?c nco:hasAffiliation ?a . " \
"OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
"OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"}"
@@ -109,7 +111,8 @@
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
"nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
- "nco:photo(?c) " \
+ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \
+ "nco:role(?a) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -130,6 +133,7 @@
"?c nco:hasAffiliation ?a . " \
"OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
"OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -156,7 +160,8 @@
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
"nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
- "nco:photo(?c) " \
+ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \
+ "nco:role(?a) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -177,6 +182,7 @@
"?c nco:hasAffiliation ?a . " \
"OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
"OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -203,7 +209,8 @@
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
"nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
- "nco:photo(?c) " \
+ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \
+ "nco:role(?a) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -223,6 +230,7 @@
"?c nco:hasAffiliation ?a . " \
"OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
"OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} ORDER BY DESC(nmo:sentDate(?call))"
@@ -248,7 +256,8 @@
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
"nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
- "nco:photo(?c) " \
+ "nco:photo(?c) nco:fullname(?o) nco:department(?a) " \
+ "nco:role(?a) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -268,6 +277,7 @@
"OPTIONAL { ?c nco:hasAffiliation ?a . " \
"OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
"OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} UNION { " \
"?call a nmo:Call ; " \
@@ -285,6 +295,7 @@
"OPTIONAL { ?c nco:hasAffiliation ?a . " \
"OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
"OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} } ORDER BY DESC(nmo:receivedDate(?call))"
@@ -317,7 +328,8 @@
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
"nco:birthDate(<%s>) nco:nickname(<%s>) nco:websiteUrl(<%s>) " \
- "nco:photo(<%s>) " \
+ "nco:photo(<%s>) nco:fullname(?o) nco:department(?a) " \
+ "nco:role(?a) " \
"\"NOTACALL\" \"false\" \"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
@@ -337,6 +349,7 @@
"<%s> nco:hasAffiliation ?a . " \
"OPTIONAL { ?a nco:hasPhoneNumber ?w . }" \
"OPTIONAL { ?a nco:hasEmailAddress ?ew . }" \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"}"
@@ -790,6 +803,9 @@ add_entry:
contact->nickname = g_strdup(reply[19]);
contact->website = g_strdup(reply[20]);
contact->photo = g_strdup(reply[21]);
+ contact->company = g_strdup(reply[22]);
+ contact->department = g_strdup(reply[23]);
+ contact->title = g_strdup(reply[24]);
set_call_type(contact, reply[COL_DATE], reply[COL_SENT],
reply[COL_ANSWERED]);
diff --git a/plugins/vcard.c b/plugins/vcard.c
index c45bfcd..b33c8e3 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -319,6 +319,30 @@ static void vcard_printf_email(GString *vcards, const char *email)
}
}
+static gboolean org_fields_present(struct phonebook_contact *contact)
+{
+ if (contact->company && strlen(contact->company))
+ return TRUE;
+
+ if (contact->department && strlen(contact->department))
+ return TRUE;
+
+ if (contact->title && strlen(contact->title))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void vcard_printf_org(GString *vcards,
+ struct phonebook_contact *contact)
+{
+ if (org_fields_present(contact) == FALSE)
+ return;
+
+ vcard_printf(vcards, "ORG:%s;%s;%s", contact->company,
+ contact->department, contact->title);
+}
+
static void vcard_printf_adr(GString *vcards, struct phonebook_contact *contact)
{
if (address_fields_present(contact) == FALSE) {
@@ -416,6 +440,9 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
if (filter & FILTER_PHOTO)
vcard_printf_tag(vcards, "PHOTO", NULL, contact->photo);
+ if (filter & FILTER_ORG)
+ vcard_printf_org(vcards, contact);
+
if (filter & FILTER_X_IRMC_CALL_DATETIME)
vcard_printf_datetime(vcards, contact);
@@ -458,6 +485,9 @@ void phonebook_contact_free(struct phonebook_contact *contact)
g_free(contact->nickname);
g_free(contact->website);
g_free(contact->photo);
+ g_free(contact->company);
+ g_free(contact->department);
+ g_free(contact->title);
g_free(contact->datetime);
g_free(contact);
}
diff --git a/plugins/vcard.h b/plugins/vcard.h
index a9809ea..0f52425 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -59,6 +59,9 @@ struct phonebook_contact {
char *nickname;
char *website;
char *photo;
+ char *company;
+ char *department;
+ char *title;
char *datetime;
int calltype;
};
--
1.6.3.3
^ permalink raw reply related
* [PATCH 1/2] Add handling of single contact's fields handled in VCARD structure
From: Rafal Michalski @ 2010-08-19 11:48 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Michalski
After pulling contacts these fields weren't present in downloaded
VCARD structure in spite of that these fields existed (not empty).
This patch adds handling of fields: BDAY, NICKNAME, URL, PHOTO
To solve this problem extending number of columns and queries of database
was needed especially. Displaying these fields is done by genaral
functions: vcard_printf_slash_tag, vcard_printf_slash_slash_tag.
Of course fields mentioned above were added to phonebook_contact structure
as char * type to save gained data.
---
plugins/phonebook-tracker.c | 29 +++++++++++++++----
plugins/vcard.c | 66 +++++++++++++++++++++++++++++++++++++++++++
plugins/vcard.h | 4 ++
3 files changed, 93 insertions(+), 6 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 1109968..fd92125 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,16 +43,16 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 21
-#define PULL_QUERY_COL_AMOUNT 22
+#define CONTACTS_ID_COL 25
+#define PULL_QUERY_COL_AMOUNT 26
#define COL_HOME_NUMBER 0
#define COL_HOME_EMAIL 7
#define COL_WORK_NUMBER 8
#define COL_FAX_NUMBER 16
#define COL_WORK_EMAIL 17
-#define COL_DATE 18
-#define COL_SENT 19
-#define COL_ANSWERED 20
+#define COL_DATE 22
+#define COL_SENT 23
+#define COL_ANSWERED 24
#define CONTACTS_QUERY_ALL \
"SELECT ?v nco:fullname(?c) " \
@@ -62,6 +62,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"\"NOTACALL\" \"false\" \"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
@@ -106,6 +108,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -151,6 +155,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -196,6 +202,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -239,6 +247,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nco:birthDate(?c) nco:nickname(?c) nco:websiteUrl(?c) " \
+ "nco:photo(?c) " \
"nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
@@ -306,6 +316,8 @@
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
"nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "nco:birthDate(<%s>) nco:nickname(<%s>) nco:websiteUrl(<%s>) " \
+ "nco:photo(<%s>) " \
"\"NOTACALL\" \"false\" \"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
@@ -774,6 +786,10 @@ add_entry:
contact->region = g_strdup(reply[13]);
contact->postal = g_strdup(reply[14]);
contact->country = g_strdup(reply[15]);
+ contact->birthday = g_strdup(reply[18]);
+ contact->nickname = g_strdup(reply[19]);
+ contact->website = g_strdup(reply[20]);
+ contact->photo = g_strdup(reply[21]);
set_call_type(contact, reply[COL_DATE], reply[COL_SENT],
reply[COL_ANSWERED]);
@@ -978,7 +994,8 @@ int phonebook_get_entry(const char *folder, const char *id,
data->vcardentry = TRUE;
query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id, id,
- id, id, id, id, id, id, id);
+ id, id, id, id, id, id, id,
+ id, id, id, id);
ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 18b5952..c45bfcd 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -256,6 +256,54 @@ static void vcard_printf_number(GString *vcards, uint8_t format,
vcard_printf(vcards, buf, number);
}
+static void vcard_printf_tag(GString *vcards, const char *tag,
+ const char* category, const char *fld)
+{
+ if (tag == NULL || strlen(tag) == 0)
+ return;
+
+ if (fld == NULL || strlen(fld) == 0)
+ return;
+
+ char separator = '\0', *type = "";
+ char buf[LEN_MAX];
+
+ if (category && strlen(category)) {
+ separator = ';';
+ type = "TYPE=";
+ }
+
+ snprintf(buf, sizeof(buf), "%s%c%s%s", tag, separator, type, category);
+
+ vcard_printf(vcards, "%s:%s", buf, fld);
+}
+
+static void vcard_printf_slash_tag(GString *vcards, const char *tag,
+ const char* category, const char *fld)
+{
+ int len;
+
+ if (tag == NULL || strlen(tag) == 0)
+ return;
+
+ if (fld == NULL || (len = strlen(fld)) == 0)
+ return;
+
+ char separator = '\0', *type = "";
+ char buf[LEN_MAX];
+
+ if (category && strlen(category)) {
+ separator = ';';
+ type = "TYPE=";
+ }
+
+ snprintf(buf, sizeof(buf), "%s%c%s%s", tag, separator, type, category);
+
+ char field[LEN_MAX];
+ add_slash(field, fld, LEN_MAX, len);
+ vcard_printf(vcards, "%s:%s", buf, field);
+}
+
static void vcard_printf_email(GString *vcards, const char *email)
{
int len = 0;
@@ -354,6 +402,20 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
if (filter & FILTER_ADR)
vcard_printf_adr(vcards, contact);
+ if (filter & FILTER_BDAY)
+ vcard_printf_tag(vcards, "BDAY", NULL, contact->birthday);
+
+ if (filter & FILTER_NICKNAME)
+ vcard_printf_slash_tag(vcards, "NICKNAME", NULL,
+ contact->nickname);
+
+ if (filter & FILTER_URL)
+ vcard_printf_slash_tag(vcards, "URL", "INTERNET",
+ contact->website);
+
+ if (filter & FILTER_PHOTO)
+ vcard_printf_tag(vcards, "PHOTO", NULL, contact->photo);
+
if (filter & FILTER_X_IRMC_CALL_DATETIME)
vcard_printf_datetime(vcards, contact);
@@ -392,6 +454,10 @@ void phonebook_contact_free(struct phonebook_contact *contact)
g_free(contact->region);
g_free(contact->postal);
g_free(contact->country);
+ g_free(contact->birthday);
+ g_free(contact->nickname);
+ g_free(contact->website);
+ g_free(contact->photo);
g_free(contact->datetime);
g_free(contact);
}
diff --git a/plugins/vcard.h b/plugins/vcard.h
index fa571e4..a9809ea 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -55,6 +55,10 @@ struct phonebook_contact {
char *region;
char *postal;
char *country;
+ char *birthday;
+ char *nickname;
+ char *website;
+ char *photo;
char *datetime;
int calltype;
};
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH] Fix crash when there is no enough space to fragment avdtp packet
From: Johan Hedberg @ 2010-08-19 11:08 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1282215669-24429-1-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Thu, Aug 19, 2010, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
>
> This was catch when running codenomicon tests when the output mtu is not
> big enough to stuff fragmented packets.
> ---
> audio/avdtp.c | 6 ++++++
> 1 files changed, 6 insertions(+), 0 deletions(-)
Thanks. The patch has been pushed upstream.
Johan
^ permalink raw reply
* [PATCH] bluetooth: fix not setting security level when creating a rfcomm session
From: Luiz Augusto von Dentz @ 2010-08-19 11:06 UTC (permalink / raw)
To: linux-bluetooth; +Cc: ville.tervo
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
This cause 'No Bonding' to be used if userspace has not yet been paired
with remote device since the l2cap socket used to create the rfcomm
session does not have any security level set.
Signed-off-by: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
---
net/bluetooth/rfcomm/core.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 7dca91b..08f5757 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -79,7 +79,10 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
static void rfcomm_process_connect(struct rfcomm_session *s);
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
+static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
+ bdaddr_t *dst,
+ u8 sec_level,
+ int *err);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
static void rfcomm_session_del(struct rfcomm_session *s);
@@ -402,7 +405,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
s = rfcomm_session_get(src, dst);
if (!s) {
- s = rfcomm_session_create(src, dst, &err);
+ s = rfcomm_session_create(src, dst, d->sec_level, &err);
if (!s)
return err;
}
@@ -680,7 +683,10 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
rfcomm_session_put(s);
}
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
+static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
+ bdaddr_t *dst,
+ u8 sec_level,
+ int *err)
{
struct rfcomm_session *s = NULL;
struct sockaddr_l2 addr;
@@ -705,6 +711,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
sk = sock->sk;
lock_sock(sk);
l2cap_pi(sk)->imtu = l2cap_mtu;
+ l2cap_pi(sk)->sec_level = sec_level;
if (l2cap_ertm)
l2cap_pi(sk)->mode = L2CAP_MODE_ERTM;
release_sock(sk);
--
1.7.0.4
^ permalink raw reply related
* [PATCH] Fix crash when there is no enough space to fragment avdtp packet
From: Luiz Augusto von Dentz @ 2010-08-19 11:01 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
This was catch when running codenomicon tests when the output mtu is not
big enough to stuff fragmented packets.
---
audio/avdtp.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/audio/avdtp.c b/audio/avdtp.c
index cf07f6c..cc7066f 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -537,6 +537,12 @@ static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
return try_send(sock, session->buf, sizeof(single) + len);
}
+ /* Check if there is enough space to start packet */
+ if (session->omtu < sizeof(start)) {
+ error("No enough space to fragment packet");
+ return FALSE;
+ }
+
/* Count the number of needed fragments */
cont_fragments = (len - (session->omtu - sizeof(start))) /
(session->omtu - sizeof(cont)) + 1;
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH] IrMC sync server support
From: Luiz Augusto von Dentz @ 2010-08-19 10:53 UTC (permalink / raw)
To: Marcel J.E. Mol; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <20100817084850.GA16821@joshua.mesa.nl>
Hi Marcel,
On Tue, Aug 17, 2010 at 11:48 AM, Marcel J.E. Mol <marcel@mesa.nl> wrote:
> Ok, then 17 is just fine for IrMC then. I posted a 3th version at the end=
of
> last week. Are there any new comments I have to take care of? Or can it =
=A0be
> considere for inclusion in the main tree now?
>
>
> On the other hand, if the channel 'varies' it might be better to let the
> plugin manager select a channel number for each service instead of alloca=
ting
> a fixed one in the specific plugin code.
>
> What did you found about channel 11 then? On my nokia 7710 channel 11 is =
used for
> "OBEX File Transfer" (serivce 0x1106).
We decided to use 14, also Johan pushed a complete list of bluez
assigned number to:
http://git.kernel.org/?p=3Dbluetooth/bluez.git;a=3Dcommitdiff;h=3Dfbeff4fd3=
03b43fa7f6c27e95fb6f023e80720a9;hp=3D0627552640140e1d986d36bb4770ccc4b3206b=
03
Could you please update your changes to use 14? Also there seems to be
some white spaces that doesn't follow our code styling, could you
please fix those?
--=20
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* Re: its possible to make a streaming video whith bluez?
From: Johan Hedberg @ 2010-08-19 8:50 UTC (permalink / raw)
To: Alexander Orlenko, Lorenzo Brito Morales, linux-bluetooth
In-Reply-To: <20100819083323.GA7327@jh-x301>
On Thu, Aug 19, 2010, Johan Hedberg wrote:
> On Thu, Aug 19, 2010, Alexander Orlenko wrote:
> > > Do you have plans to implement this for BlueZ?
> > It's a GSoC'10 project. http://hostisdown.org/gsoc/projects/vdp
>
> Ha. Seems I've missed that one completely (though not really a surprise
> since there doesn't seem to have been any communication about it here on
> the mailing list).
I just just took a peek at the projects git tree. There's essentially
nothing there besides some very simple stub files. Also, there doesn't
seem to be anything AVDTP related in the tree but just raw data (video)
sending over an L2CAP connection. So if that's all that there is then
the statement "nothing exists for VDP in BlueZ right now" is actually
quite close to the truth.
Johan
^ permalink raw reply
* Re: BlueZ's A2DP sink role
From: Luiz Augusto von Dentz @ 2010-08-19 8:49 UTC (permalink / raw)
To: Pavan Savoy; +Cc: linux-bluetooth
In-Reply-To: <AANLkTimXDqAej=LAVDvDgspKuH_SAKivp9eL8R9tXPJc@mail.gmail.com>
Hi Pavan,
On Wed, Aug 18, 2010 at 11:22 PM, Pavan Savoy <pavan_savoy@sify.com> wrote:
> As I understand, the A2DP sink role is @ audio/source.c and A2DP
> source role is at sink.c ? (or what is called as the interfaces?..)
> Also How do I test out a2dp sink role in BlueZ, any test audio-server
> I can run ?
You can use PA as explained in Joao Paulo's blog:
http://jprvita.wordpress.com/2009/12/15/1-2-3-4-a2dp-stream/
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* Re: its possible to make a streaming video whith bluez?
From: Johan Hedberg @ 2010-08-19 8:33 UTC (permalink / raw)
To: Alexander Orlenko; +Cc: Lorenzo Brito Morales, linux-bluetooth
In-Reply-To: <AANLkTindRBGJtWuE8OX+fAEAQOSQHzEgLdGdUUHfOKKT@mail.gmail.com>
On Thu, Aug 19, 2010, Alexander Orlenko wrote:
> > Do you have plans to implement this for BlueZ?
> It's a GSoC'10 project. http://hostisdown.org/gsoc/projects/vdp
Ha. Seems I've missed that one completely (though not really a surprise
since there doesn't seem to have been any communication about it here on
the mailing list).
Johan
^ permalink raw reply
* Re: its possible to make a streaming video whith bluez?
From: Alexander Orlenko @ 2010-08-19 8:25 UTC (permalink / raw)
To: Lorenzo Brito Morales, linux-bluetooth
In-Reply-To: <20100819074920.GA5401@jh-x301>
> Do you have plans to implement this for BlueZ?
It's a GSoC'10 project. http://hostisdown.org/gsoc/projects/vdp
On 19 August 2010 18:49, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi,
>
> On Thu, Aug 19, 2010, Lorenzo Brito Morales wrote:
>> its possible to make a streaming video whith bluez?
>
> Not right now.
>
>> if not, are there plans to implementing?
>
> Nothing concrete, but at least the first requirement would be for there
> to exist some devices on the market that support VDP. Do you know any?
> Do you have plans to implement this for BlueZ?
>
> Johan
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 1/2] bluetooth: Add support Bluetooth controller of MacbookPro 6,2
From: Marcel Holtmann @ 2010-08-19 8:11 UTC (permalink / raw)
To: Nobuhiro Iwamatsu; +Cc: linux-bluetooth, stable
In-Reply-To: <1282197259-16609-1-git-send-email-iwamatsu@nigauri.org>
Hi Nobuhiro.
> Bluetooth controller of MacbookPro 6,2 does not work.
> Because Device Class of these controllers was set 255 (Vendor Sepecific Class).
>
> Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
it would be nice if you include the output from /proc/bus/usb/devices or
usb-devices.sh script to proof the different device class.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Fix problem with multiple emails in vcard
From: Johan Hedberg @ 2010-08-19 8:03 UTC (permalink / raw)
To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1282200587-5475-1-git-send-email-ext-jablonski.radoslaw@nokia.com>
Hi Radek,
On Thu, Aug 19, 2010, Radoslaw Jablonski wrote:
> Previously only one email appeared in generated vcard, even if contact
> had defined multiple email addresses in contact data.
> Changed vcard struct and phonebook-tracker pull_contacts func to support
> multiple emails.
> ---
> plugins/phonebook-tracker.c | 99 +++++++++++++++++++++++++++++-------------
> plugins/vcard.c | 12 ++++-
> plugins/vcard.h | 2 +-
> 3 files changed, 78 insertions(+), 35 deletions(-)
Thanks. The patch is now upstream.
Johan
^ permalink raw reply
* Re: its possible to make a streaming video whith bluez?
From: Johan Hedberg @ 2010-08-19 7:49 UTC (permalink / raw)
To: Lorenzo Brito Morales; +Cc: linux-bluetooth
In-Reply-To: <AANLkTikEHVwEXQg=0ahqwDOANa-VPLjd11xC2ri2N8d5@mail.gmail.com>
Hi,
On Thu, Aug 19, 2010, Lorenzo Brito Morales wrote:
> its possible to make a streaming video whith bluez?
Not right now.
> if not, are there plans to implementing?
Nothing concrete, but at least the first requirement would be for there
to exist some devices on the market that support VDP. Do you know any?
Do you have plans to implement this for BlueZ?
Johan
^ permalink raw reply
* its possible to make a streaming video whith bluez?
From: Lorenzo Brito Morales @ 2010-08-19 6:57 UTC (permalink / raw)
To: linux-bluetooth
its possible to make a streaming video whith bluez? if not, are there
plans to implementing?
^ permalink raw reply
* [PATCH] Fix problem with multiple emails in vcard
From: Radoslaw Jablonski @ 2010-08-19 6:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Radoslaw Jablonski
Previously only one email appeared in generated vcard, even if contact
had defined multiple email addresses in contact data.
Changed vcard struct and phonebook-tracker pull_contacts func to support
multiple emails.
---
plugins/phonebook-tracker.c | 99 +++++++++++++++++++++++++++++-------------
plugins/vcard.c | 12 ++++-
plugins/vcard.h | 2 +-
3 files changed, 78 insertions(+), 35 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 618ce8d..1109968 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,14 +43,16 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 20
-#define PULL_QUERY_COL_AMOUNT 21
+#define CONTACTS_ID_COL 21
+#define PULL_QUERY_COL_AMOUNT 22
#define COL_HOME_NUMBER 0
+#define COL_HOME_EMAIL 7
#define COL_WORK_NUMBER 8
#define COL_FAX_NUMBER 16
-#define COL_DATE 17
-#define COL_SENT 18
-#define COL_ANSWERED 19
+#define COL_WORK_EMAIL 17
+#define COL_DATE 18
+#define COL_SENT 19
+#define COL_ANSWERED 20
#define CONTACTS_QUERY_ALL \
"SELECT ?v nco:fullname(?c) " \
@@ -59,8 +61,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
- "\"false\" ?c " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "\"NOTACALL\" \"false\" \"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
"OPTIONAL { ?c nco:hasPhoneNumber ?h . \
@@ -77,7 +79,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"}"
@@ -102,7 +105,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -120,7 +124,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -145,7 +150,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -163,7 +169,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -188,7 +195,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -205,7 +213,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"} ORDER BY DESC(nmo:sentDate(?call))"
@@ -229,7 +238,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"{ " \
@@ -243,12 +253,12 @@
"nco:phoneNumber ?f . " \
"}" \
"} " \
- "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
- "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
- "} " \
+ "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
+ "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "} " \
"} UNION { " \
"?call a nmo:Call ; " \
"nmo:from ?c ; " \
@@ -260,12 +270,12 @@
"nco:phoneNumber ?f . " \
"}" \
"} " \
- "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
- "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
- "} " \
+ "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
+ "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "} " \
"} } ORDER BY DESC(nmo:receivedDate(?call))"
#define COMBINED_CALLS_LIST \
@@ -295,8 +305,8 @@
"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
- "\"false\" <%s> " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "\"NOTACALL\" \"false\" \"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
"OPTIONAL { <%s> nco:hasPhoneNumber ?h . \
@@ -313,7 +323,8 @@
"OPTIONAL { <%s> nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"<%s> nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . }" \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . }" \
"} " \
"}"
@@ -651,6 +662,29 @@ static void add_phone_number(struct phonebook_contact *contact,
contact->numbers = g_slist_append(contact->numbers, number);
}
+static gchar *find_email(GSList *emails, const char *email)
+{
+ GSList *l;
+
+ for (l = emails; l; l = l->next)
+ if (g_strcmp0(l->data, email) == 0)
+ return l->data;
+
+ return NULL;
+}
+
+static void add_email(struct phonebook_contact *contact, const char *email)
+{
+ if (email == NULL || strlen(email) == 0)
+ return;
+
+ /* Not adding email if there is already added with the same value */
+ if (find_email(contact->emails, email))
+ return;
+
+ contact->emails = g_slist_append(contact->emails, g_strdup(email));
+}
+
static GString *gen_vcards(GSList *contacts,
const struct apparam_field *params)
{
@@ -733,7 +767,6 @@ add_entry:
contact->additional = g_strdup(reply[4]);
contact->prefix = g_strdup(reply[5]);
contact->suffix = g_strdup(reply[6]);
- contact->email = g_strdup(reply[7]);
contact->pobox = g_strdup(reply[9]);
contact->extended = g_strdup(reply[10]);
contact->street = g_strdup(reply[11]);
@@ -751,6 +784,10 @@ add_numbers:
add_phone_number(contact, reply[COL_WORK_NUMBER], TEL_TYPE_WORK);
add_phone_number(contact, reply[COL_FAX_NUMBER], TEL_TYPE_FAX);
+ /* Adding emails */
+ add_email(contact, reply[COL_HOME_EMAIL]);
+ add_email(contact, reply[COL_WORK_EMAIL]);
+
DBG("contact %p", contact);
/* Adding contacts data to wrapper struct - this data will be used to
diff --git a/plugins/vcard.c b/plugins/vcard.c
index af00cb5..18b5952 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -344,8 +344,12 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
}
}
- if (filter & FILTER_EMAIL)
- vcard_printf_email(vcards, contact->email);
+ if (filter & FILTER_EMAIL) {
+ GSList *l;
+
+ for (l = contact->emails; l; l = l->next)
+ vcard_printf_email(vcards, l->data);
+ }
if (filter & FILTER_ADR)
vcard_printf_adr(vcards, contact);
@@ -372,11 +376,13 @@ void phonebook_contact_free(struct phonebook_contact *contact)
g_slist_foreach(contact->numbers, number_free, NULL);
g_slist_free(contact->numbers);
+ g_slist_foreach(contact->emails, (GFunc) g_free, NULL);
+ g_slist_free(contact->emails);
+
g_free(contact->fullname);
g_free(contact->given);
g_free(contact->family);
g_free(contact->additional);
- g_free(contact->email);
g_free(contact->prefix);
g_free(contact->suffix);
g_free(contact->pobox);
diff --git a/plugins/vcard.h b/plugins/vcard.h
index 06bcd35..fa571e4 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -45,7 +45,7 @@ struct phonebook_contact {
char *family;
char *additional;
GSList *numbers;
- char *email;
+ GSList *emails;
char *prefix;
char *suffix;
char *pobox;
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH] Fix problem with multiple emails in vcard
From: Radoslaw Jablonski @ 2010-08-19 6:44 UTC (permalink / raw)
To: Hedberg Johan (Nokia-MS/Helsinki); +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <20100819063420.GA3661@jh-x301>
Hi
Sorry this belongs to another set of patches.
I'll resend modified patch without this unnecessary data.
BR,
Radek
On 08/19/2010 09:34 AM, Hedberg Johan (Nokia-MS/Helsinki) wrote:
> Hi Radek,
>
> On Thu, Aug 19, 2010, Radoslaw Jablonski wrote:
>> + char *birthday;
>> + char *nickname;
>> + char *website;
>> + char *photo;
>> + char *company;
>> + char *department;
>> + char *title;
> How is this part related to your patch (about email support in vCards)?
> Seems like it belongs to some other patch. The rest of the patch seems
> fine to me.
>
> Johan
^ permalink raw reply
* Re: [PATCH] Fix problem with multiple emails in vcard
From: Johan Hedberg @ 2010-08-19 6:34 UTC (permalink / raw)
To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1282198407-4025-1-git-send-email-ext-jablonski.radoslaw@nokia.com>
Hi Radek,
On Thu, Aug 19, 2010, Radoslaw Jablonski wrote:
> + char *birthday;
> + char *nickname;
> + char *website;
> + char *photo;
> + char *company;
> + char *department;
> + char *title;
How is this part related to your patch (about email support in vCards)?
Seems like it belongs to some other patch. The rest of the patch seems
fine to me.
Johan
^ permalink raw reply
* [PATCH] Fix problem with multiple emails in vcard
From: Radoslaw Jablonski @ 2010-08-19 6:13 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Radoslaw Jablonski
Previously only one email appeared in generated vcard, even if contact
had defined multiple email addresses in contact data.
Changed vcard struct and phonebook-tracker pull_contacts func to support
multiple emails.
---
plugins/phonebook-tracker.c | 99 +++++++++++++++++++++++++++++-------------
plugins/vcard.c | 12 ++++-
plugins/vcard.h | 9 ++++-
3 files changed, 85 insertions(+), 35 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 618ce8d..1109968 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,14 +43,16 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 20
-#define PULL_QUERY_COL_AMOUNT 21
+#define CONTACTS_ID_COL 21
+#define PULL_QUERY_COL_AMOUNT 22
#define COL_HOME_NUMBER 0
+#define COL_HOME_EMAIL 7
#define COL_WORK_NUMBER 8
#define COL_FAX_NUMBER 16
-#define COL_DATE 17
-#define COL_SENT 18
-#define COL_ANSWERED 19
+#define COL_WORK_EMAIL 17
+#define COL_DATE 18
+#define COL_SENT 19
+#define COL_ANSWERED 20
#define CONTACTS_QUERY_ALL \
"SELECT ?v nco:fullname(?c) " \
@@ -59,8 +61,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
- "\"false\" ?c " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "\"NOTACALL\" \"false\" \"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
"OPTIONAL { ?c nco:hasPhoneNumber ?h . \
@@ -77,7 +79,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"}"
@@ -102,7 +105,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -120,7 +124,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -145,7 +150,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -163,7 +169,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -188,7 +195,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -205,7 +213,8 @@
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
"} " \
"} ORDER BY DESC(nmo:sentDate(?call))"
@@ -229,7 +238,8 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew) " \
+ "nmo:receivedDate(?call) " \
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"{ " \
@@ -243,12 +253,12 @@
"nco:phoneNumber ?f . " \
"}" \
"} " \
- "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
- "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
- "} " \
+ "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
+ "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "} " \
"} UNION { " \
"?call a nmo:Call ; " \
"nmo:from ?c ; " \
@@ -260,12 +270,12 @@
"nco:phoneNumber ?f . " \
"}" \
"} " \
- "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
- "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
- "} " \
+ "OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
+ "OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . } " \
+ "} " \
"} } ORDER BY DESC(nmo:receivedDate(?call))"
#define COMBINED_CALLS_LIST \
@@ -295,8 +305,8 @@
"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
- "\"false\" <%s> " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:emailAddress(?ew)" \
+ "\"NOTACALL\" \"false\" \"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
"OPTIONAL { <%s> nco:hasPhoneNumber ?h . \
@@ -313,7 +323,8 @@
"OPTIONAL { <%s> nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
"<%s> nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . }" \
+ "OPTIONAL { ?a nco:hasEmailAddress ?ew . }" \
"} " \
"}"
@@ -651,6 +662,29 @@ static void add_phone_number(struct phonebook_contact *contact,
contact->numbers = g_slist_append(contact->numbers, number);
}
+static gchar *find_email(GSList *emails, const char *email)
+{
+ GSList *l;
+
+ for (l = emails; l; l = l->next)
+ if (g_strcmp0(l->data, email) == 0)
+ return l->data;
+
+ return NULL;
+}
+
+static void add_email(struct phonebook_contact *contact, const char *email)
+{
+ if (email == NULL || strlen(email) == 0)
+ return;
+
+ /* Not adding email if there is already added with the same value */
+ if (find_email(contact->emails, email))
+ return;
+
+ contact->emails = g_slist_append(contact->emails, g_strdup(email));
+}
+
static GString *gen_vcards(GSList *contacts,
const struct apparam_field *params)
{
@@ -733,7 +767,6 @@ add_entry:
contact->additional = g_strdup(reply[4]);
contact->prefix = g_strdup(reply[5]);
contact->suffix = g_strdup(reply[6]);
- contact->email = g_strdup(reply[7]);
contact->pobox = g_strdup(reply[9]);
contact->extended = g_strdup(reply[10]);
contact->street = g_strdup(reply[11]);
@@ -751,6 +784,10 @@ add_numbers:
add_phone_number(contact, reply[COL_WORK_NUMBER], TEL_TYPE_WORK);
add_phone_number(contact, reply[COL_FAX_NUMBER], TEL_TYPE_FAX);
+ /* Adding emails */
+ add_email(contact, reply[COL_HOME_EMAIL]);
+ add_email(contact, reply[COL_WORK_EMAIL]);
+
DBG("contact %p", contact);
/* Adding contacts data to wrapper struct - this data will be used to
diff --git a/plugins/vcard.c b/plugins/vcard.c
index af00cb5..18b5952 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -344,8 +344,12 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
}
}
- if (filter & FILTER_EMAIL)
- vcard_printf_email(vcards, contact->email);
+ if (filter & FILTER_EMAIL) {
+ GSList *l;
+
+ for (l = contact->emails; l; l = l->next)
+ vcard_printf_email(vcards, l->data);
+ }
if (filter & FILTER_ADR)
vcard_printf_adr(vcards, contact);
@@ -372,11 +376,13 @@ void phonebook_contact_free(struct phonebook_contact *contact)
g_slist_foreach(contact->numbers, number_free, NULL);
g_slist_free(contact->numbers);
+ g_slist_foreach(contact->emails, (GFunc) g_free, NULL);
+ g_slist_free(contact->emails);
+
g_free(contact->fullname);
g_free(contact->given);
g_free(contact->family);
g_free(contact->additional);
- g_free(contact->email);
g_free(contact->prefix);
g_free(contact->suffix);
g_free(contact->pobox);
diff --git a/plugins/vcard.h b/plugins/vcard.h
index 06bcd35..0f52425 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -45,7 +45,7 @@ struct phonebook_contact {
char *family;
char *additional;
GSList *numbers;
- char *email;
+ GSList *emails;
char *prefix;
char *suffix;
char *pobox;
@@ -55,6 +55,13 @@ struct phonebook_contact {
char *region;
char *postal;
char *country;
+ char *birthday;
+ char *nickname;
+ char *website;
+ char *photo;
+ char *company;
+ char *department;
+ char *title;
char *datetime;
int calltype;
};
--
1.7.0.4
^ permalink raw reply related
* [PATCH 2/2] bluetooth: Add support Bluetooth controller of MacbookPro 7,1
From: Nobuhiro Iwamatsu @ 2010-08-19 5:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: stable, Nobuhiro Iwamatsu
In-Reply-To: <1282197259-16609-1-git-send-email-iwamatsu@nigauri.org>
Bluetooth controller of MacbookPro 7,1 does not work.
Because Device Class of these controllers was set 255 (Vendor Sepecific Class).
Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
---
drivers/bluetooth/btusb.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 9fb8635..3da2ba2 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -59,6 +59,9 @@ static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+ /* Apple MacBookPro 7,1 */
+ { USB_DEVICE(0x05ac, 0x8213) },
+
/* Apple iMac11,1 */
{ USB_DEVICE(0x05ac, 0x8215) },
--
1.7.1
^ permalink raw reply related
* [PATCH 1/2] bluetooth: Add support Bluetooth controller of MacbookPro 6,2
From: Nobuhiro Iwamatsu @ 2010-08-19 5:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: stable, Nobuhiro Iwamatsu
Bluetooth controller of MacbookPro 6,2 does not work.
Because Device Class of these controllers was set 255 (Vendor Sepecific Class).
Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
---
drivers/bluetooth/btusb.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index d22ce3c..9fb8635 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -62,6 +62,9 @@ static struct usb_device_id btusb_table[] = {
/* Apple iMac11,1 */
{ USB_DEVICE(0x05ac, 0x8215) },
+ /* Apple MacBookPro6,2 */
+ { USB_DEVICE(0x05ac, 0x8218) },
+
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) },
--
1.7.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox