Diff between 32f70b67709f6c6e1d0f4211ce8a93d43c038106 and 2e2c48dfc234088c664d663233beb31521819e0a

Changed Files

File Additions Deletions Status
obexd/plugins/filesystem.c +4 -3 modified
obexd/plugins/filesystem.h +25 -0 added
obexd/plugins/ftp.c +1 -1 modified
obexd/plugins/opp.c +1 -1 modified
obexd/plugins/pbap.c +158 -287 modified
obexd/plugins/phonebook-dummy.c +36 -7 modified
obexd/plugins/phonebook-ebook.c +40 -343 modified
obexd/plugins/phonebook.h +9 -6 modified
obexd/plugins/syncevolution.c +1 -1 modified
obexd/src/obex.c +1 -1 modified
obexd/src/service.h +1 -1 modified

Full Patch

diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c
index dcc03ff..9775bcb 100644
--- a/obexd/plugins/filesystem.c
+++ b/obexd/plugins/filesystem.c
@@ -49,6 +49,7 @@
 #include "obex.h"
 #include "mimetype.h"
 #include "service.h"
+#include "filesystem.h"
 
 #define EOL_CHARS "\n"
 
@@ -409,7 +410,7 @@ failed:
 	return NULL;
 }
 
-static int string_free(gpointer object)
+int string_free(gpointer object)
 {
 	GString *string = object;
 
@@ -418,7 +419,7 @@ static int string_free(gpointer object)
 	return 0;
 }
 
-static ssize_t string_read(gpointer object, void *buf, size_t count)
+ssize_t string_read(gpointer object, void *buf, size_t count)
 {
 	GString *string = object;
 	ssize_t len;
@@ -426,7 +427,7 @@ static ssize_t string_read(gpointer object, void *buf, size_t count)
 	if (string->len == 0)
 		return 0;
 
-	len = count > string->len ? string->len : count;
+	len = MIN(string->len, count);
 	memcpy(buf, string->str, len);
 	string = g_string_erase(string, 0, len);
 
diff --git a/obexd/plugins/filesystem.h b/obexd/plugins/filesystem.h
new file mode 100644
index 0000000..636ddb2
--- /dev/null
+++ b/obexd/plugins/filesystem.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+int string_free(gpointer object);
+ssize_t string_read(gpointer object, void *buf, size_t count);
diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c
index fe775f4..0bd5a5e 100644
--- a/obexd/plugins/ftp.c
+++ b/obexd/plugins/ftp.c
@@ -193,7 +193,7 @@ static obex_rsp_t ftp_connect(struct OBEX_session *os)
 	return OBEX_RSP_SUCCESS;
 }
 
-static obex_rsp_t ftp_get(struct OBEX_session *os)
+static obex_rsp_t ftp_get(struct OBEX_session *os, obex_object_t *obj)
 {
 	const char *folder = obex_get_folder(os);
 	const char *type = obex_get_type(os);
diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c
index d003f21..3325d08 100644
--- a/obexd/plugins/opp.c
+++ b/obexd/plugins/opp.c
@@ -151,7 +151,7 @@ static obex_rsp_t opp_put(struct OBEX_session *os)
 	return OBEX_RSP_SUCCESS;
 }
 
-static obex_rsp_t opp_get(struct OBEX_session *os)
+static obex_rsp_t opp_get(struct OBEX_session *os, obex_object_t *obj)
 {
 	const char *type;
 
diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c
index 53d4a9c..2a7d6d1 100644
--- a/obexd/plugins/pbap.c
+++ b/obexd/plugins/pbap.c
@@ -29,6 +29,11 @@
 #include <string.h>
 #include <errno.h>
 #include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <bluetooth/bluetooth.h>
 
 #include <openobex/obex.h>
@@ -40,6 +45,8 @@
 #include "service.h"
 #include "phonebook.h"
 #include "telephony.h"
+#include "mimetype.h"
+#include "filesystem.h"
 #include "dbus.h"
 
 #define PHONEBOOK_TYPE		"x-bt/phonebook"
@@ -127,257 +134,16 @@ struct apparam_hdr {
 	uint8_t		val[0];
 } __attribute__ ((packed));
 
+struct phonebook_query {
+	const char *type;
+	GString *buffer;
+	struct OBEX_session *os;
+};
+
 static const guint8 PBAP_TARGET[TARGET_SIZE] = {
 			0x79, 0x61, 0x35, 0xF0,  0xF0, 0xC5, 0x11, 0xD8,
 			0x09, 0x66, 0x08, 0x00,  0x20, 0x0C, 0x9A, 0x66  };
 
-static int pbap_parse_apparam_header(obex_t *obex, obex_object_t *obj,
-						struct apparam_field *apparam)
-{
-	obex_headerdata_t hd;
-	guint8 hi;
-	guint32 hlen;
-
-	while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
-		void *ptr = (void *) hd.bs;
-		uint32_t len = hlen;
-
-		if (hi != OBEX_HDR_APPARAM)
-			continue;
-
-		if (hlen < APPARAM_HDR_SIZE) {
-			g_free(apparam->searchval);
-			error("PBAP pullphonebook app parameters header"
-						" is too short: %d", hlen);
-			return -1;
-		}
-
-		while (len > APPARAM_HDR_SIZE) {
-			struct apparam_hdr *hdr = ptr;
-
-			if (hdr->len > len - APPARAM_HDR_SIZE) {
-				g_free(apparam->searchval);
-				error("Unexpected PBAP pullphonebook app"
-						" length, tag %d, len %d",
-							hdr->tag, hdr->len);
-				return -1;
-			}
-
-			switch (hdr->tag) {
-			case ORDER_TAG:
-				if (hdr->len == ORDER_LEN)
-					apparam->order = hdr->val[0];
-				break;
-			case SEARCHATTRIB_TAG:
-				if (hdr->len == SEARCHATTRIB_LEN)
-					apparam->searchattrib = hdr->val[0];
-				break;
-			case SEARCHVALUE_TAG:
-				apparam->searchval = g_try_malloc(hdr->len + 1);
-				if (apparam->searchval != NULL) {
-					memcpy(apparam->searchval, hdr->val,
-								hdr->len);
-					apparam->searchval[hdr->len] = '\0';
-				}
-				break;
-			case FILTER_TAG:
-				if (hdr->len == FILTER_LEN) {
-					guint64 val;
-					memcpy(&val, hdr->val, sizeof(val));
-					apparam->filter = get_be64(&val);
-				}
-				break;
-			case FORMAT_TAG:
-				if (hdr->len == FORMAT_LEN)
-					apparam->format = hdr->val[0];
-				break;
-			case MAXLISTCOUNT_TAG:
-				if (hdr->len == MAXLISTCOUNT_LEN) {
-					guint16 val;
-					memcpy(&val, hdr->val, sizeof(val));
-					apparam->maxlistcount = get_be16(&val);
-				}
-				break;
-			case LISTSTARTOFFSET_TAG:
-				if (hdr->len == LISTSTARTOFFSET_LEN) {
-					guint16 val;
-					memcpy(&val, hdr->val, sizeof(val));
-					apparam->liststartoffset = get_be16(&val);
-				}
-				break;
-			default:
-				g_free(apparam->searchval);
-				error("Unexpected PBAP pullphonebook app"
-						" parameter, tag %d, len %d",
-							hdr->tag, hdr->len);
-				return -1;
-			}
-
-			ptr += APPARAM_HDR_SIZE + hdr->len;
-			len -= APPARAM_HDR_SIZE + hdr->len;
-		}
-
-		/* Ignore multiple app param headers */
-		break;
-	}
-
-	return 0;
-}
-
-/* Add app parameter header, that is sent back to PBAP client */
-static int pbap_add_result_apparam_header(obex_t *obex, obex_object_t *obj,
-				guint16 maxlistcount, gchar *path_name,
-				guint16 phonebooksize,
-				guint8 newmissedcalls, gboolean *addbody)
-{
-	guint8 rspsize = 0;
-	gboolean addmissedcalls = FALSE;
-	obex_headerdata_t hd;
-
-	if (maxlistcount == 0) {
-		rspsize += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN;
-		*addbody = FALSE;
-	}
-
-	if (g_str_equal(path_name, SIM1_MCH) == TRUE ||
-				g_str_equal(path_name, MCH) == TRUE) {
-		rspsize += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN;
-		addmissedcalls = TRUE;
-	}
-
-	if (rspsize > 0) {
-		void *buf, *ptr;
-
-		buf = g_try_malloc0(rspsize);
-		if (buf == NULL)
-			return -ENOMEM;
-
-		ptr = buf;
-
-		if (maxlistcount == 0) {
-			struct apparam_hdr *hdr = ptr;
-			guint16 val = GUINT16_TO_BE(phonebooksize);
-
-			hdr->tag = PHONEBOOKSIZE_TAG;
-			hdr->len = PHONEBOOKSIZE_LEN;
-			memcpy(hdr->val, &val, sizeof(val));
-
-			ptr += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN;
-		}
-
-		if (addmissedcalls == TRUE) {
-			struct apparam_hdr *hdr = ptr;
-
-			hdr->tag = NEWMISSEDCALLS_TAG;
-			hdr->len = NEWMISSEDCALLS_LEN;
-			hdr->val[0] = newmissedcalls;
-
-			ptr += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN;
-		}
-
-		hd.bs = buf;
-		OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_APPARAM,
-							hd, rspsize, 0);
-		g_free(buf);
-	}
-
-	return 0;
-}
-
-static int pbap_pullphonebook(obex_t *obex, obex_object_t *obj,
-							gboolean *addbody)
-{
-	struct obex_session *session = OBEX_GetUserData(obex);
-	struct apparam_field params;
-	guint8 newmissedcalls = 0;
-	guint16 phonebooksize = 0;
-	int err;
-
-	memset(&params, 0, sizeof(struct apparam_field));
-
-	err = pbap_parse_apparam_header(obex, obj, &params);
-	if (err < 0)
-		return err;
-
-	if (params.maxlistcount == 0) {
-		phonebooksize = DEFAULT_COUNT;
-		goto done;
-	}
-
-	err = phonebook_pullphonebook(obex, obj, params);
-	if (err < 0)
-		return err;
-
-done:
-	return pbap_add_result_apparam_header(obex, obj, params.maxlistcount,
-						session->name, phonebooksize,
-						newmissedcalls, addbody);
-}
-
-static int pbap_pullvcardlisting(obex_t *obex, obex_object_t *obj,
-							gboolean *addbody)
-{
-	struct obex_session *session = OBEX_GetUserData(obex);
-	gchar *fullname;
-	struct apparam_field params;
-	guint8 newmissedcalls = 0;
-	guint16 phonebooksize = 0;
-	int err;
-
-	memset(&params, 0, sizeof(struct apparam_field));
-
-	err = pbap_parse_apparam_header(obex, obj, &params);
-	if (err < 0)
-		return err;
-
-	if (params.maxlistcount == 0) {
-		phonebooksize = DEFAULT_COUNT;
-		goto proceed;
-	}
-
-	/* libebook does not support sound attribute */
-	if (params.searchattrib >= 2) {
-		DBG("libebook does not support sound attribute");
-		goto done;
-	}
-
-	err = phonebook_pullvcardlisting(obex, obj, params);
-	if (err < 0)
-		goto done;
-
-proceed:
-
-	fullname = g_build_filename(session->current_folder, session->name,
-								NULL);
-	if (fullname != NULL)
-		fullname = g_strconcat(fullname, ".vcf", NULL);
-
-	err = pbap_add_result_apparam_header(obex, obj, params.maxlistcount,
-						fullname, phonebooksize,
-						newmissedcalls, addbody);
-	g_free(fullname);
-
-done:
-	g_free(params.searchval);
-	return err;
-}
-
-static int pbap_pullvcardentry(obex_t *obex, obex_object_t *obj)
-{
-	struct apparam_field params;
-	int err;
-
-	memset(&params, 0, sizeof(struct apparam_field));
-	err = pbap_parse_apparam_header(obex, obj, &params);
-	if (err < 0)
-		return err;
-
-	err = phonebook_pullvcardentry(obex, obj, params);
-
-	g_free(params.searchval);
-	return err;
-}
-
 static obex_rsp_t pbap_connect(struct OBEX_session *os)
 {
 	manager_register_session(os);
@@ -385,56 +151,47 @@ static obex_rsp_t pbap_connect(struct OBEX_session *os)
 	return OBEX_RSP_SUCCESS;
 }
 
-static obex_rsp_t pbap_get(struct OBEX_session *os)
+static obex_rsp_t pbap_get(struct OBEX_session *os, obex_object_t *obj)
 {
-	int addbody = TRUE;
-	const char *type = obex_get_type(os);
-	const char *name = obex_get_name(os);
-	int err;
+	const gchar *type = obex_get_type(os);
+	const gchar *folder = obex_get_folder(os);
+	const gchar *name = obex_get_name(os);
+	gchar *path;
+	gint ret;
 
 	if (type == NULL)
-		goto fail;
+		return OBEX_RSP_BAD_REQUEST;
 
-	if (g_str_equal(type, VCARDLISTING_TYPE) == FALSE
-						&& name == NULL)
-		goto fail;
+	if (strcmp(type, PHONEBOOK_TYPE) == 0)
+		/* Always contains the absolute path */
+		path = g_strdup(name);
+	else if (strcmp(type, VCARDLISTING_TYPE) == 0)
+		/* Always relative */
+		if (!name || strlen(name) == 0)
+			/* Current folder */
+			path = g_strdup(folder);
+		else
+			/* Current folder + relative path */
+			path = g_build_filename(folder, name, NULL);
 
-	/* FIXME: broken */
-#if 0
-	OBEX_ObjectReParseHeaders(, obj);
-#endif
-	if (g_str_equal(type, PHONEBOOK_TYPE) == TRUE)
-		err = pbap_pullphonebook(NULL, NULL, NULL);
-	else if (g_str_equal(type, VCARDLISTING_TYPE) == TRUE)
-		err = pbap_pullvcardlisting(NULL, NULL, NULL);
-	else if (g_str_equal(type, VCARDENTRY_TYPE) == TRUE)
-		err = pbap_pullvcardentry(NULL, NULL);
+	else if (strcmp(type, VCARDENTRY_TYPE) == 0)
+		/* Always relative */
+		path = g_build_filename(folder, name, NULL);
 	else
-		goto fail;
+		return OBEX_RSP_BAD_REQUEST;
 
-	if (err < 0)
-		goto fail;
+	ret = obex_stream_start(os, path);
+	g_free(path);
 
-	if (addbody == TRUE) {
-#if 0
-		OBEX_SuspendRequest(obex, obj);
-		session->size = 0;
+	switch (ret) {
+	case 0:
+		return OBEX_RSP_SUCCESS;
+	case -ENOENT:
+		return OBEX_RSP_NOT_FOUND;
+	default:
+		return OBEX_RSP_FORBIDDEN;
 
-		/* Add body header */
-		hd.bs = NULL;
-		OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY,
-				hd, 0, OBEX_FL_STREAM_START);
-#endif
 	}
-
-#if 0
-	OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
-#endif
-
-	return OBEX_RSP_SUCCESS;
-
-fail:
-	return OBEX_RSP_FORBIDDEN;
 }
 
 static gboolean pbap_is_valid_folder(struct obex_session *session)
@@ -555,14 +312,128 @@ struct obex_service_driver pbap = {
 	.chkput = pbap_chkput
 };
 
+static void query_result(const gchar *buffer, size_t bufsize,
+		gint vcards, gint missed, gpointer user_data)
+{
+	struct phonebook_query *query = user_data;
+
+	if (!query->buffer)
+		query->buffer = g_string_new_len(buffer, bufsize);
+	else
+		query->buffer = g_string_append_len(query->buffer, buffer, bufsize);
+
+	obex_object_set_io_flags(query, G_IO_IN, 0);
+}
+
+static gpointer vobject_open(const char *name, int oflag, mode_t mode,
+		size_t *size, struct OBEX_session *os, int *err)
+{
+	const gchar *type = obex_get_type(os);
+	struct phonebook_query *query;
+
+	if (oflag != O_RDONLY)
+		goto fail;
+
+	/* TODO: mch? */
+
+	/* TODO: get application parameter */
+	query = g_new0(struct phonebook_query, 1);
+	query->type = type;
+	query->os = os;
+
+	if (phonebook_query(name, query_result, query) < 0) {
+		g_free(query);
+		goto fail;
+	}
+
+	if (size)
+		*size = 1;
+
+	return query;
+
+fail:
+	if (err)
+		*err = -EPERM;
+
+	return NULL;
+}
+
+static ssize_t vobject_read(gpointer object, void *buf, size_t count)
+{
+	struct phonebook_query *query = object;
+
+	if (query->buffer)
+		return string_read(query->buffer, buf, count);
+
+	return -EAGAIN;
+}
+
+static int vobject_close(gpointer object)
+{
+	struct phonebook_query *query = object;
+
+	if (query->buffer)
+		string_free(query->buffer);
+
+	g_free(query);
+
+	return 0;
+}
+
+struct obex_mime_type_driver mime_pull = {
+	.target		= PBAP_TARGET,
+	.mimetype	= "x-bt/phonebook",
+	.open		= vobject_open,
+	.close		= vobject_close,
+	.read		= vobject_read,
+};
+
+struct obex_mime_type_driver mime_list = {
+	.target		= PBAP_TARGET,
+	.mimetype	= "x-bt/vcard-listing",
+	.open		= vobject_open,
+	.close		= vobject_close,
+	.read		= vobject_read,
+};
+
+struct obex_mime_type_driver mime_vcard = {
+	.target		= PBAP_TARGET,
+	.mimetype	= "x-bt/vcard",
+	.open		= vobject_open,
+	.close		= vobject_close,
+	.read		= vobject_read,
+};
+
 static int pbap_init(void)
 {
+	int err;
+
+	err = phonebook_init();
+	if (err < 0)
+		return err;
+
+	err = obex_mime_type_driver_register(&mime_pull);
+	if (err < 0)
+		return err;
+
+	err = obex_mime_type_driver_register(&mime_list);
+	if (err < 0)
+		return err;
+
+	err = obex_mime_type_driver_register(&mime_vcard);
+	if (err < 0)
+		return err;
+
 	return obex_service_driver_register(&pbap);
 }
 
 static void pbap_exit(void)
 {
 	obex_service_driver_unregister(&pbap);
+	obex_mime_type_driver_unregister(&mime_pull);
+	obex_mime_type_driver_unregister(&mime_list);
+	obex_mime_type_driver_unregister(&mime_vcard);
+	phonebook_exit();
 }
 
 OBEX_PLUGIN_DEFINE(pbap, pbap_init, pbap_exit)
diff --git a/obexd/plugins/phonebook-dummy.c b/obexd/plugins/phonebook-dummy.c
index df3760c..38b2803 100644
--- a/obexd/plugins/phonebook-dummy.c
+++ b/obexd/plugins/phonebook-dummy.c
@@ -26,27 +26,56 @@
 #include <config.h>
 #endif
 
+#include <string.h>
 #include <glib.h>
 
 #include <openobex/obex.h>
 #include <openobex/obex_const.h>
 
+#include "logging.h"
 #include "phonebook.h"
 
-int phonebook_pullphonebook(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params)
+#define VCARD0				\
+        "BEGIN:VCARD\n"			\
+        "VERSION:3.0\n"			\
+        "N:Klaus;Santa\n"		\
+        "FN:\n"				\
+        "TEL:+001122334455\n"		\
+        "END:VCARD\n"
+
+
+struct dummy_data {
+	phonebook_cb	cb;
+	gpointer	user_data;
+};
+
+int phonebook_init(void)
 {
 	return 0;
 }
 
-int phonebook_pullvcardlisting(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params)
+void phonebook_exit(void)
 {
-	return 0;
 }
 
-int phonebook_pullvcardentry(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params)
+static gboolean dummy_result(gpointer data)
 {
+	struct dummy_data *dummy = data;
+
+	dummy->cb(VCARD0, strlen(VCARD0), 1, 0, dummy->user_data);
+
+	return FALSE;
+}
+
+int phonebook_query(const gchar *name, phonebook_cb cb, gpointer user_data)
+{
+	struct dummy_data *dummy;
+
+	dummy = g_new0(struct dummy_data, 1);
+	dummy->cb = cb;
+	dummy->user_data = user_data;
+
+	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+			dummy_result, dummy, g_free);
 	return 0;
 }
diff --git a/obexd/plugins/phonebook-ebook.c b/obexd/plugins/phonebook-ebook.c
index b25ce25..e1a7996 100644
--- a/obexd/plugins/phonebook-ebook.c
+++ b/obexd/plugins/phonebook-ebook.c
@@ -52,380 +52,77 @@
 #define QUERY_GIVEN_NAME "(contains \"given_name\" \"%s\")"
 #define QUERY_PHONE "(contains \"phone\" \"%s\")"
 
-struct phonebook_data {
-	obex_t *obex;
-	obex_object_t *obj;
-	struct apparam_field params;
+struct query_data {
+	phonebook_cb cb;
+	gpointer user_data;
 };
 
-static char *vcard_attribs[29] = { EVC_VERSION, EVC_FN, EVC_N, EVC_PHOTO,
-				EVC_BDAY, EVC_ADR, EVC_LABEL, EVC_TEL,
-				EVC_EMAIL, EVC_MAILER, NULL, EVC_GEO,
-				EVC_TITLE, EVC_ROLE, EVC_LOGO, NULL,
-				EVC_ORG, EVC_NOTE, EVC_REV, NULL, EVC_URL,
-				EVC_UID, EVC_KEY, EVC_NICKNAME, EVC_CATEGORIES,
-				EVC_PRODID, NULL, NULL, NULL };
+static EBook *ebook = NULL;
 
-static void ebookpull_cb(EBook *book, EBookStatus status, GList *list,
+static void ebookpull_cb(EBook *book, EBookStatus status, GList *contacts,
 				gpointer user_data)
 {
-	struct phonebook_data *pb_data = user_data;
-	struct apparam_field *params = &pb_data->params;
-	struct obex_session *session = OBEX_GetUserData(pb_data->obex);
-	guint16 offset = 0, count = 0;
-	GList *contacts = list;
-	GString *pb;
-	gchar *result;
-	gint32 size;
+	struct query_data *data = user_data;
+	GString *string = g_string_new("");
+	GList *l;
 
-	pb = g_string_new(NULL);
-
-	/* Mandatory attributes for vCard 3.0 are VERSION, N, FN and TEL */
-	if (params->filter != 0 && params->format == EVC_FORMAT_VCARD_30)
-		params->filter |= 0x87;
-
-	for (; contacts != NULL; contacts = g_list_next(contacts)) {
-		EContact *contact = NULL;
-		EVCard *evcard = NULL, *evcard_filtered = NULL;
-		GList *attrib_list = NULL, *l;
-		char *vcard;
-
-		if (offset < params->liststartoffset) {
-			offset++;
-			continue;
-		}
-
-		if (count < params->maxlistcount)
-			count++;
-		else
-			break;
+	for (l = contacts; l; l = g_list_next(l)) {
+		EContact *contact;
+		EVCard *evcard;
+		gchar *vcard;
 
 		contact = E_CONTACT(contacts->data);
 		evcard = E_VCARD(contact);
-		attrib_list = e_vcard_get_attributes(evcard);
-
-		if (!params->filter) {
-			vcard = e_vcard_to_string(evcard, params->format);
-			goto done;
-		}
-
-		evcard_filtered = e_vcard_new();
-		for (l = attrib_list; l; l = l->next) {
-			int i;
-			const char *attrib_name = e_vcard_attribute_get_name(
-						(EVCardAttribute *) l->data);
-
-			for (i = 0; i <= 28; i++) {
-				int mask;
-
-				mask = 1 << i;
-				if (!(params->filter & mask))
-					continue;
-				if (g_strcmp0(vcard_attribs[i], attrib_name))
-					continue;
-				e_vcard_add_attribute(evcard_filtered,
-						e_vcard_attribute_copy(
-						(EVCardAttribute *) l->data));
-				break;
-			}
-		}
-		vcard = e_vcard_to_string(evcard_filtered, params->format);
-		g_object_unref(evcard_filtered);
-
-done:		g_string_append_printf(pb, "%s\n", vcard);
+		vcard = e_vcard_to_string(evcard, EVC_FORMAT_VCARD_30);
+		string = g_string_append(string, vcard);
 		g_free(vcard);
 	}
 
-	result = g_string_free(pb, FALSE);
-	size = strlen(result);
-
-	if (size != 0) {
-		session->buf = g_realloc(session->buf, session->size + size);
-		memcpy(session->buf + session->size, result, size);
-		session->size += size;
-	}
-
-	session->finished = 1;
-	OBEX_ResumeRequest(session->obex);
-
-	g_free(result);
-	g_free(pb_data);
-	g_object_unref(book);
+	data->cb(string->str, string->len,
+			g_list_length(contacts), 0, data->user_data);
 }
 
-int phonebook_pullphonebook(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params)
+int phonebook_init(void)
 {
-	struct phonebook_data *pb_data;
-	EBook *book;
-	EBookQuery *query;
-
-	if (params.format != EVC_FORMAT_VCARD_30) {
-		DBG("libebook does not support e_vcard_to_string_vcard_21()");
-		return -1;
+	GError *gerr = NULL;
+
+	ebook = e_book_new_default_addressbook(&gerr);
+	if (!ebook) {
+		error("Can't create user's default address book: %s",
+				gerr->message);
+		g_error_free(gerr);
+		return -EIO;
 	}
 
-	pb_data = g_new0(struct phonebook_data, 1);
-	pb_data->obex = obex;
-	pb_data->obj = obj;
-	pb_data->params = params;
-
-	book = e_book_new_default_addressbook(NULL);
-
-	e_book_open(book, FALSE, NULL);
-
-	query = e_book_query_any_field_contains("");
-
-	e_book_async_get_contacts(book, query, ebookpull_cb, pb_data);
-
-	e_book_query_unref(query);
-
-	OBEX_SuspendRequest(obex, obj);
-
-	return 0;
-}
-
-static void ebooklist_cb(EBook *book, EBookStatus status, GList *list,
-				gpointer user_data)
-{
-	struct phonebook_data *pb_data = user_data;
-	struct apparam_field *params = &pb_data->params;
-	struct obex_session *session = OBEX_GetUserData(pb_data->obex);
-	guint16 offset = 0, count = 0;
-	GString *listing;
-	GList *contacts = list;
-	gchar *result;
-	gint32 size;
-
-	listing = g_string_new(VL_VERSION);
-	listing = g_string_append(listing, VL_TYPE);
-	listing = g_string_append(listing, VL_BODY_BEGIN);
-
-	for (; contacts != NULL; contacts = g_list_next(contacts)) {
-		EContact *contact = NULL;
-		EVCard *evcard = NULL;
-		EVCardAttribute *name_attrib = NULL;
-		GList *name_values = NULL;
-		gchar *name = NULL, *name_part = NULL, *element = NULL;
-
-		if (offset < params->liststartoffset) {
-			offset++;
-			continue;
-		}
-
-		if (count < params->maxlistcount)
-			count++;
-		else
-			break;
-
-		contact = E_CONTACT(contacts->data);
-		evcard = E_VCARD(contact);
-		name_attrib = e_vcard_get_attribute(evcard, EVC_N);
-
-		if (name_attrib) {
-			name_values = e_vcard_attribute_get_values(name_attrib);
-			for (; name_values; name_values = name_values->next) {
-				if (!name_part) {
-					name_part = g_strdup(name_values->data);
-					continue;
-				}
-				name = g_strjoin(";", name_part,
-						name_values->data, NULL);
-				g_free(name_part);
-				name_part = name;
-			}
-
-			element = g_strdup_printf(VL_ELEMENT, offset, name);
-			listing = g_string_append(listing, element);
-
-			g_free(name);
-			g_free(element);
-		}
-
-		offset++;
+	if (!e_book_open(ebook, FALSE, &gerr)) {
+		error("Can't open e-book address book: %s", gerr->message);
+		g_error_free(gerr);
+		return -EIO;
 	}
 
-	listing = g_string_append(listing, VL_BODY_END);
-	result = g_string_free(listing, FALSE);
-	size = strlen(result);
-
-	if (size != 0) {
-		session->buf = g_realloc(session->buf, session->size + size);
-		memcpy(session->buf + session->size, result, size);
-		session->size += size;
-	}
-
-	session->finished = 1;
-	OBEX_ResumeRequest(session->obex);
-
-	g_free(result);
-	g_free(pb_data);
-	g_object_unref(book);
-}
-
-int phonebook_pullvcardlisting(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params)
-{
-	struct phonebook_data *pb_data;
-	EBook *book;
-	EBookQuery *query = NULL, *query1 = NULL, *query2 = NULL;
-	gchar *str1 = NULL, *str2 = NULL;
-	gchar **value_list = NULL;
-
-	pb_data = g_new0(struct phonebook_data, 1);
-	pb_data->obex = obex;
-	pb_data->obj = obj;
-	pb_data->params = params;
-
-	book = e_book_new_default_addressbook(NULL);
-
-	e_book_open(book, FALSE, NULL);
-
-	/* All the vCards shall be returned if SearchValue header is
-	 * not specified */
-	if (!params.searchval || !strlen((char *) params.searchval)) {
-		query = e_book_query_any_field_contains("");
-		goto done;
-	}
-
-	if (params.searchattrib == 0) {
-		value_list = g_strsplit((gchar *) params.searchval, ";", 5);
-
-		if (value_list[0])
-			str1 = g_strdup_printf(QUERY_FAMILY_NAME,
-						value_list[0]);
-		if (value_list[1])
-			str2 = g_strdup_printf(QUERY_GIVEN_NAME, value_list[1]);
-
-		if (str1)
-			query1 = e_book_query_from_string(str1);
-		if (str2)
-			query2 = e_book_query_from_string(str2);
-		if (query1 && query2)
-			query = e_book_query_andv(query1, query2, NULL);
-		else
-			query = query1;
-	} else {
-		str1 = g_strdup_printf(QUERY_PHONE, params.searchval);
-		query = e_book_query_from_string((char *) params.searchval);
-	}
-
-done:
-	e_book_async_get_contacts(book, query, ebooklist_cb, pb_data);
-
-	g_free(str1);
-	g_free(str2);
-	if (query1 && query1 != query)
-		e_book_query_unref(query1);
-	if (query2)
-		e_book_query_unref(query2);
-	e_book_query_unref(query);
-	g_strfreev(value_list);
-
-	OBEX_SuspendRequest(obex, obj);
-
 	return 0;
 }
 
-static void ebookpullentry_cb(EBook *book, EBookStatus status, GList *list,
-                                gpointer user_data)
+void phonebook_exit(void)
 {
-	struct phonebook_data *pb_data = user_data;
-	struct apparam_field *params = &pb_data->params;
-	struct obex_session *session = OBEX_GetUserData(pb_data->obex);
-	guint16 i = 0, index;
-	GList *contacts = list, *attrib_list = NULL, *l;
-	EContact *contact = NULL;
-	EVCard *evcard = NULL, *evcard_filtered = NULL;
-	gint32 size = 0;
-	char *vcard = NULL;
-
-	if (params->filter != 0 && params->format == EVC_FORMAT_VCARD_30)
-		params->filter |= 0x87;
-
-	sscanf(session->name, "%hu.vcf", &index);
-
-	for (; contacts != NULL; contacts = g_list_next(contacts)) {
-		if (i < index) {
-			i++;
-			continue;
-		}
-
-		contact = E_CONTACT(contacts->data);
-		evcard = E_VCARD(contact);
-
-		if (!params->filter) {
-			vcard = e_vcard_to_string(evcard, params->format);
-			break;
-		}
-
-		attrib_list = e_vcard_get_attributes(evcard);
-		evcard_filtered = e_vcard_new();
-		for (l = attrib_list; l; l = l->next) {
-			int i;
-			const char *attrib_name = e_vcard_attribute_get_name(
-						(EVCardAttribute *) l->data);
-			for (i = 0; i <= 28; i++) {
-				int mask;
-
-				mask = 1 << i;
-				if (!(params->filter & mask))
-					continue;
-				if (g_strcmp0(vcard_attribs[i], attrib_name))
-					continue;
-
-				e_vcard_add_attribute(evcard_filtered,
-						e_vcard_attribute_copy(
-						(EVCardAttribute *) l->data));
-				break;
-			}
-		}
-		vcard = e_vcard_to_string(evcard_filtered, params->format);
-		g_object_unref(evcard_filtered);
-		break;
-	}
-
-	if (vcard) {
-		size = strlen(vcard);
-		session->buf = g_realloc(session->buf, session->size + size);
-		memcpy(session->buf + session->size, vcard, size);
-		session->size += size;
-	}
-
-	session->finished = 1;
-	OBEX_ResumeRequest(session->obex);
-
-	g_free(vcard);
-	g_free(pb_data);
-	g_object_unref(book);
+	if (ebook)
+		g_object_unref(ebook);
 }
 
-int phonebook_pullvcardentry(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params)
+int phonebook_query(const gchar *name, phonebook_cb cb, gpointer user_data)
 {
-	struct phonebook_data *pb_data;
-	EBook *book;
+	struct query_data *data;
 	EBookQuery *query;
 
-	if (params.format != EVC_FORMAT_VCARD_30) {
-		DBG("libebook does not support e_vcard_to_string_vcard_21()");
-		return -1;
-	}
-
-	pb_data = g_new0(struct phonebook_data, 1);
-	pb_data->obex = obex;
-	pb_data->obj = obj;
-	pb_data->params = params;
-
-	book = e_book_new_default_addressbook(NULL);
-
-	e_book_open(book, FALSE, NULL);
-
 	query = e_book_query_any_field_contains("");
 
-	e_book_async_get_contacts(book, query, ebookpullentry_cb, pb_data);
+	data = g_new0(struct query_data, 1);
+	data->cb = cb;
+	data->user_data = user_data;
 
-	OBEX_SuspendRequest(obex, obj);
+	e_book_async_get_contacts(ebook, query, ebookpull_cb, data);
+
+	e_book_query_unref(query);
 
 	return 0;
 }
diff --git a/obexd/plugins/phonebook.h b/obexd/plugins/phonebook.h
index cc5743e..dc8e5e0 100644
--- a/obexd/plugins/phonebook.h
+++ b/obexd/plugins/phonebook.h
@@ -31,9 +31,12 @@ struct apparam_field {
 	guint8		*searchval;
 };
 
-int phonebook_pullphonebook(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params);
-int phonebook_pullvcardlisting(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params);
-int phonebook_pullvcardentry(obex_t *obex, obex_object_t *obj,
-				struct apparam_field params);
+typedef void (*phonebook_cb) (const gchar *buffer, size_t bufsize,
+		gint vcards, gint missed, gpointer user_data);
+
+int phonebook_init(void);
+void phonebook_exit(void);
+
+int phonebook_setfolder(const gchar *name);
+
+int phonebook_query(const gchar *name, phonebook_cb cb, gpointer user_data);
diff --git a/obexd/plugins/syncevolution.c b/obexd/plugins/syncevolution.c
index 5f78952..60cd15d 100644
--- a/obexd/plugins/syncevolution.c
+++ b/obexd/plugins/syncevolution.c
@@ -392,7 +392,7 @@ static obex_rsp_t synce_put(struct OBEX_session *os)
 	return OBEX_RSP_SUCCESS;
 }
 
-static obex_rsp_t synce_get(struct OBEX_session *os)
+static obex_rsp_t synce_get(struct OBEX_session *os, obex_object_t *obj)
 {
 	struct synce_context *context;
 
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
index 0484523..0b0c0f2 100644
--- a/obexd/src/obex.c
+++ b/obexd/src/obex.c
@@ -364,7 +364,7 @@ static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj)
 		}
 	}
 
-	rsp = os->service->get(os);
+	rsp = os->service->get(os, obj);
 	if (rsp == OBEX_RSP_SUCCESS) {
 		hd.bq4 = os->size;
 		OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_LENGTH, hd, 4, 0);
diff --git a/obexd/src/service.h b/obexd/src/service.h
index 4bd78fe..b6fc289 100644
--- a/obexd/src/service.h
+++ b/obexd/src/service.h
@@ -34,7 +34,7 @@ struct obex_service_driver {
 	const gchar *record;
 	obex_rsp_t (*connect) (struct OBEX_session *os);
 	void (*progress) (struct OBEX_session *os);
-	obex_rsp_t (*get) (struct OBEX_session *os);
+	obex_rsp_t (*get) (struct OBEX_session *os, obex_object_t *obj);
 	obex_rsp_t (*put) (struct OBEX_session *os);
 	gint (*chkput) (struct OBEX_session *os);
 	obex_rsp_t (*setpath) (struct OBEX_session *os, obex_object_t *obj);