Diff between c6d258ba8678391872befad186dfa7eb52c571bd and a5ebb33ef1cc26e9d6b973ca1775f071ad4ec637

Changed Files

File Additions Deletions Status
obexd/plugins/ftp.c +4 -1 modified
obexd/plugins/opp.c +4 -1 modified
obexd/plugins/pbap.c +62 -16 modified
obexd/plugins/phonebook-ebook.c +5 -0 modified
obexd/plugins/syncevolution.c +5 -1 modified
obexd/src/obex-priv.h +1 -0 modified
obexd/src/obex.c +189 -164 modified
obexd/src/obex.h +2 -0 modified
obexd/src/service.h +2 -1 modified

Full Patch

diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c
index 0a1c6f8..7404738 100644
--- a/obexd/plugins/ftp.c
+++ b/obexd/plugins/ftp.c
@@ -193,7 +193,7 @@ static gpointer ftp_connect(struct obex_session *os, int *err)
 }
 
 static int ftp_get(struct obex_session *os, obex_object_t *obj,
-		gpointer user_data)
+			gboolean *stream, gpointer user_data)
 {
 	struct ftp_session *ftp = user_data;
 	const char *type = obex_get_type(os);
@@ -206,6 +206,9 @@ static int ftp_get(struct obex_session *os, obex_object_t *obj,
 	if (ret < 0)
 		return ret;
 
+	if (stream)
+		*stream = TRUE;
+
 	return 0;
 }
 
diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c
index 30b7560..c99e686 100644
--- a/obexd/plugins/opp.c
+++ b/obexd/plugins/opp.c
@@ -164,7 +164,7 @@ static int opp_put(struct obex_session *os, gpointer user_data)
 }
 
 static int opp_get(struct obex_session *os, obex_object_t *obj,
-		gpointer user_data)
+			gboolean *stream, gpointer user_data)
 {
 	const char *type;
 
@@ -183,6 +183,9 @@ static int opp_get(struct obex_session *os, obex_object_t *obj,
 	} else
 		return -EPERM;
 
+	if (stream)
+		*stream = TRUE;
+
 	return 0;
 }
 
diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c
index 544aac7..fc0eabe 100644
--- a/obexd/plugins/pbap.c
+++ b/obexd/plugins/pbap.c
@@ -31,6 +31,7 @@
 #include <glib.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -131,7 +132,9 @@ struct pbap_session {
 	struct obex_session *os;
 	struct apparam_field *params;
 	gchar *folder;
-	GString *buffer;
+	GString	*buffer;
+	guint16	phonebooksize;
+	obex_object_t *object;
 };
 
 static const guint8 PBAP_TARGET[TARGET_SIZE] = {
@@ -145,6 +148,29 @@ static void set_folder(struct pbap_session *pbap, const char *new_folder)
 	pbap->folder = new_folder ? g_strdup(new_folder) : NULL;
 }
 
+static void phonebook_size_result(const gchar *buffer, size_t bufsize,
+			gint vcards, gint missed, gpointer user_data)
+{
+	struct pbap_session *pbap = user_data;
+
+	pbap->phonebooksize = vcards;
+
+	obex_object_set_io_flags(pbap, G_IO_IN, 0);
+}
+
+static void query_result(const gchar *buffer, size_t bufsize,
+		gint vcards, gint missed, gpointer user_data)
+{
+	struct pbap_session *pbap = user_data;
+
+	if (!pbap->buffer)
+		pbap->buffer = g_string_new_len(buffer, bufsize);
+	else
+		pbap->buffer = g_string_append_len(pbap->buffer, buffer, bufsize);
+
+	obex_object_set_io_flags(pbap, G_IO_IN, 0);
+}
+
 static struct apparam_field *parse_aparam(const guint8 *buffer, guint32 hlen)
 {
 	struct apparam_field *param;
@@ -237,7 +263,7 @@ static gpointer pbap_connect(struct obex_session *os, int *err)
 }
 
 static int pbap_get(struct obex_session *os, obex_object_t *obj,
-		gpointer user_data)
+			gboolean *stream, gpointer user_data)
 {
 	struct pbap_session *pbap = user_data;
 	const gchar *type = obex_get_type(os);
@@ -286,7 +312,13 @@ static int pbap_get(struct obex_session *os, obex_object_t *obj,
 		g_free(pbap->params);
 	}
 
+	if (params->maxlistcount == 0)
+		*stream = FALSE;
+	else
+		*stream = TRUE;
+
 	pbap->params = params;
+	pbap->object = obj;
 
 	ret = obex_get_stream_start(os, path, pbap);
 failed:
@@ -365,19 +397,6 @@ static 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 pbap_session *pbap = user_data;
-
-	if (!pbap->buffer)
-		pbap->buffer = g_string_new_len(buffer, bufsize);
-	else
-		pbap->buffer = g_string_append_len(pbap->buffer, buffer, bufsize);
-
-	obex_object_set_io_flags(pbap, G_IO_IN, 0);
-}
-
 static gpointer vobject_open(const char *name, int oflag, mode_t mode,
 		gpointer context, size_t *size, int *err)
 {
@@ -389,7 +408,17 @@ static gpointer vobject_open(const char *name, int oflag, mode_t mode,
 		goto fail;
 	}
 
-	ret = phonebook_pull(name, pbap->params, query_result, pbap);
+	/*
+	 * Zero means that the PCE wants to know the number of used indexes in
+	 * the phone book of interest. PSE shall ignore all other application
+	 * parameter that may be present in the request.
+	 */
+	if (pbap->params->maxlistcount == 0)
+		ret = phonebook_pull(name, pbap->params,
+				phonebook_size_result, pbap);
+	else
+		ret = phonebook_pull(name, pbap->params, query_result, pbap);
+
 	if (ret < 0)
 		goto fail;
 
@@ -409,6 +438,23 @@ static ssize_t vobject_read(gpointer object, void *buf, size_t count)
 {
 	struct pbap_session *pbap = object;
 
+	/* PhoneBookSize */
+	if (pbap->params->maxlistcount == 0) {
+		guint8 data[4];
+		guint16 phonebooksize;
+		struct aparam_header *hdr = (struct aparam_header *) data;
+
+		phonebooksize = htons(pbap->phonebooksize);
+		hdr->tag = PHONEBOOKSIZE_TAG;
+		hdr->len = PHONEBOOKSIZE_LEN;
+		memcpy(hdr->val, &phonebooksize, sizeof(phonebooksize));
+
+		obex_aparam_write(pbap->os, pbap->object, data, sizeof(data));
+
+		return 0;
+	}
+
+	/* Stream data */
 	if (pbap->buffer)
 		return string_read(pbap->buffer, buf, count);
 
diff --git a/obexd/plugins/phonebook-ebook.c b/obexd/plugins/phonebook-ebook.c
index 528adf3..997e1b2 100644
--- a/obexd/plugins/phonebook-ebook.c
+++ b/obexd/plugins/phonebook-ebook.c
@@ -70,6 +70,10 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *contacts,
 
 	/* FIXME: Missing 0.vcf */
 
+	/* PCE wants only the number of indexes in the phonebook */
+	if (maxcount == 0)
+		goto done;
+
 	for (; l && count < maxcount; l = g_list_next(l), count++) {
 		EContact *contact;
 		EVCard *evcard;
@@ -82,6 +86,7 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *contacts,
 		g_free(vcard);
 	}
 
+done:
 	data->cb(string->str, string->len,
 			g_list_length(contacts), 0, data->user_data);
 
diff --git a/obexd/plugins/syncevolution.c b/obexd/plugins/syncevolution.c
index 2354991..12cf78b 100644
--- a/obexd/plugins/syncevolution.c
+++ b/obexd/plugins/syncevolution.c
@@ -228,8 +228,12 @@ static int synce_put(struct obex_session *os, gpointer user_data)
 	return 0;
 }
 
-static int synce_get(struct obex_session *os, obex_object_t *obj, gpointer user_data)
+static int synce_get(struct obex_session *os, obex_object_t *obj,
+			gboolean *stream, gpointer user_data)
 {
+	if (stream)
+		*stream = TRUE;
+
 	return obex_get_stream_start(os, NULL, os);
 }
 
diff --git a/obexd/src/obex-priv.h b/obexd/src/obex-priv.h
index 932f275..8406bc0 100644
--- a/obexd/src/obex-priv.h
+++ b/obexd/src/obex-priv.h
@@ -60,6 +60,7 @@ struct obex_session {
 	obex_object_t	*obj;
 	struct obex_mime_type_driver *driver;
 	gboolean	finished;
+	gboolean	stream;
 };
 
 gint obex_session_start(GIOChannel *io, struct server *server);
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
index a2c7346..aa0dfb1 100644
--- a/obexd/src/obex.c
+++ b/obexd/src/obex.c
@@ -316,6 +316,159 @@ static gboolean chk_cid(obex_t *obex, obex_object_t *obj, guint32 cid)
 	return ret;
 }
 
+static gint obex_read_stream(struct obex_session *os, obex_t *obex,
+						obex_object_t *obj)
+{
+	gint size;
+	gint32 len = 0;
+	const guint8 *buffer;
+
+	if (os->aborted)
+		return -EPERM;
+
+	/* workaround: client didn't send the object lenght */
+	if (os->size == OBJECT_SIZE_DELETE)
+		os->size = OBJECT_SIZE_UNKNOWN;
+
+	size = OBEX_ObjectReadStream(obex, obj, &buffer);
+	if (size < 0) {
+		error("Error on OBEX stream");
+		return -EIO;
+	}
+
+	if (size > os->rx_mtu) {
+		error("Received more data than RX_MAX");
+		return -EIO;
+	}
+
+	if (os->object == NULL && size > 0) {
+		os->buf = g_realloc(os->buf, os->offset + size);
+		memcpy(os->buf + os->offset, buffer, size);
+		os->offset += size;
+
+		debug("Stored %u bytes into temporary buffer", size);
+
+		return 0;
+	}
+
+	while (len < size) {
+		gint w;
+
+		w = os->driver->write(os->object, buffer + len, size - len);
+		if (w < 0) {
+			if (w == -EINTR)
+				continue;
+			else
+				return w;
+		}
+
+		len += w;
+	}
+
+	os->offset += len;
+
+	return 0;
+}
+
+static gint obex_write_stream(struct obex_session *os,
+			obex_t *obex, obex_object_t *obj)
+{
+	obex_headerdata_t hd;
+	gint32 len;
+	guint8 *ptr;
+
+	debug("obex_write_stream: name=%s type=%s tx_mtu=%d file=%p",
+		os->name ? os->name : "", os->type ? os->type : "",
+		os->tx_mtu, os->object);
+
+	if (os->aborted)
+		return -EPERM;
+
+	if (os->object == NULL) {
+		if (os->buf == NULL && os->finished == FALSE)
+			return -EIO;
+
+		len = MIN(os->size - os->offset, os->tx_mtu);
+		ptr = os->buf + os->offset;
+		goto add_header;
+	}
+
+	len = os->driver->read(os->object, os->buf, os->tx_mtu);
+	if (len < 0) {
+		error("read(): %s (%d)", strerror(-len), -len);
+		if (len == -EAGAIN)
+			return len;
+		else if (len == -ENOSTR)
+			return 0;
+
+		g_free(os->buf);
+		os->buf = NULL;
+		return len;
+	}
+
+	if (!os->stream)
+		return 0;
+
+	ptr = os->buf;
+
+add_header:
+
+	hd.bs = ptr;
+
+	if (len == 0) {
+		OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, 0,
+					OBEX_FL_STREAM_DATAEND);
+		g_free(os->buf);
+		os->buf = NULL;
+		return len;
+	}
+
+	os->offset += len;
+
+	OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, len,
+				OBEX_FL_STREAM_DATA);
+
+	return len;
+}
+
+static gboolean handle_async_io(gpointer object, int flags, int err,
+						gpointer user_data)
+{
+	struct obex_session *os = user_data;
+	int ret = 0;
+
+	if (err < 0) {
+		ret = err;
+		goto proceed;
+	}
+
+	if (flags & (G_IO_IN | G_IO_PRI))
+		ret = obex_write_stream(os, os->obex, os->obj);
+	else if (flags & G_IO_OUT)
+		ret = obex_read_stream(os, os->obex, os->obj);
+
+proceed:
+	switch (ret) {
+	case -EINVAL:
+		OBEX_ObjectSetRsp(os->obj, OBEX_RSP_BAD_REQUEST,
+				OBEX_RSP_BAD_REQUEST);
+	case -EPERM:
+		OBEX_ObjectSetRsp(os->obj, OBEX_RSP_FORBIDDEN,
+					OBEX_RSP_FORBIDDEN);
+		break;
+	default:
+		if (ret < 0)
+			OBEX_ObjectSetRsp(os->obj,
+					OBEX_RSP_INTERNAL_SERVER_ERROR,
+					OBEX_RSP_INTERNAL_SERVER_ERROR);
+		break;
+	}
+
+	OBEX_ResumeRequest(os->obex);
+
+	return FALSE;
+}
+
 static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj)
 {
 	obex_headerdata_t hd;
@@ -397,24 +550,34 @@ static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj)
 		}
 	}
 
-	err = os->service->get(os, obj, os->service_data);
-	if (err == 0) {
-		if (os->size != OBJECT_SIZE_UNKNOWN) {
-			hd.bq4 = os->size;
-			OBEX_ObjectAddHeader(obex, obj,
-					OBEX_HDR_LENGTH, hd, 4, 0);
-		}
+	err = os->service->get(os, obj, &os->stream, os->service_data);
 
-		/* Add body header */
-		hd.bs = NULL;
-		if (os->size == 0)
-			OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
-					hd, 0, OBEX_FL_FIT_ONE_PACKET);
-		else
-			OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
-					hd, 0, OBEX_FL_STREAM_START);
+	if (err < 0)
+		goto done;
+
+	if (os->size != OBJECT_SIZE_UNKNOWN) {
+		hd.bq4 = os->size;
+		OBEX_ObjectAddHeader(obex, obj,
+				OBEX_HDR_LENGTH, hd, 4, 0);
 	}
 
+	/* Add body header */
+	hd.bs = NULL;
+	if (os->size == 0)
+		OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
+				hd, 0, OBEX_FL_FIT_ONE_PACKET);
+	else if (!os->stream) {
+		/* Asynchronous operation that doesn't use stream */
+		OBEX_SuspendRequest(obex, obj);
+		os->obj = obj;
+		os->driver->set_io_watch(os->object, handle_async_io, os);
+		return;
+	} else
+		/* Standard data stream */
+		OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
+				hd, 0, OBEX_FL_STREAM_START);
+
+done:
 	os_set_response(obj, err);
 }
 
@@ -500,62 +663,6 @@ fail:
 	return err;
 }
 
-static gint obex_write_stream(struct obex_session *os,
-			obex_t *obex, obex_object_t *obj)
-{
-	obex_headerdata_t hd;
-	gint32 len;
-	guint8 *ptr;
-
-	debug("obex_write_stream: name=%s type=%s tx_mtu=%d file=%p",
-		os->name ? os->name : "", os->type ? os->type : "",
-		os->tx_mtu, os->object);
-
-	if (os->aborted)
-		return -EPERM;
-
-	if (os->object == NULL) {
-		if (os->buf == NULL && os->finished == FALSE)
-			return -EIO;
-
-		len = MIN(os->size - os->offset, os->tx_mtu);
-		ptr = os->buf + os->offset;
-		goto add_header;
-	}
-
-	len = os->driver->read(os->object, os->buf, os->tx_mtu);
-	if (len < 0) {
-		error("read(): %s (%d)", strerror(-len), -len);
-		if (len == -EAGAIN)
-			return len;
-
-		g_free(os->buf);
-		os->buf = NULL;
-		return len;
-	}
-
-	ptr = os->buf;
-
-add_header:
-
-	hd.bs = ptr;
-
-	if (len == 0) {
-		OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, 0,
-					OBEX_FL_STREAM_DATAEND);
-		g_free(os->buf);
-		os->buf = NULL;
-		return len;
-	}
-
-	os->offset += len;
-
-	OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, len,
-				OBEX_FL_STREAM_DATA);
-
-	return len;
-}
-
 int obex_put_stream_start(struct obex_session *os,
 		const gchar *filename, gpointer driver_data)
 {
@@ -599,99 +706,6 @@ int obex_put_stream_start(struct obex_session *os,
 	return 0;
 }
 
-static gint obex_read_stream(struct obex_session *os, obex_t *obex,
-				obex_object_t *obj)
-{
-	gint size;
-	gint32 len = 0;
-	const guint8 *buffer;
-
-	if (os->aborted)
-		return -EPERM;
-
-	/* workaround: client didn't send the object lenght */
-	if (os->size == OBJECT_SIZE_DELETE)
-		os->size = OBJECT_SIZE_UNKNOWN;
-
-	size = OBEX_ObjectReadStream(obex, obj, &buffer);
-	if (size < 0) {
-		error("Error on OBEX stream");
-		return -EIO;
-	}
-
-	if (size > os->rx_mtu) {
-		error("Received more data than RX_MAX");
-		return -EIO;
-	}
-
-	if (os->object == NULL && size > 0) {
-		os->buf = g_realloc(os->buf, os->offset + size);
-		memcpy(os->buf + os->offset, buffer, size);
-		os->offset += size;
-
-		debug("Stored %u bytes into temporary buffer", size);
-
-		return 0;
-	}
-
-	while (len < size) {
-		gint w;
-
-		w = os->driver->write(os->object, buffer + len, size - len);
-		if (w < 0) {
-			if (w == -EINTR)
-				continue;
-			else
-				return w;
-		}
-
-		len += w;
-	}
-
-	os->offset += len;
-
-	return 0;
-}
-
-static gboolean handle_async_io(gpointer object, int flags, int err,
-				gpointer user_data)
-{
-	struct obex_session *os = user_data;
-	int ret = 0;
-
-	if (err < 0) {
-		ret = err;
-		goto proceed;
-	}
-
-	if (flags & (G_IO_IN | G_IO_PRI))
-		ret = obex_write_stream(os, os->obex, os->obj);
-	else if (flags & G_IO_OUT)
-		ret = obex_read_stream(os, os->obex, os->obj);
-
-proceed:
-	switch (ret) {
-	case -EINVAL:
-		OBEX_ObjectSetRsp(os->obj, OBEX_RSP_BAD_REQUEST,
-				OBEX_RSP_BAD_REQUEST);
-		break;
-	case -EPERM:
-		OBEX_ObjectSetRsp(os->obj, OBEX_RSP_FORBIDDEN,
-					OBEX_RSP_FORBIDDEN);
-		break;
-	default:
-		if (ret < 0)
-			OBEX_ObjectSetRsp(os->obj,
-					OBEX_RSP_INTERNAL_SERVER_ERROR,
-					OBEX_RSP_INTERNAL_SERVER_ERROR);
-		break;
-	}
-
-	OBEX_ResumeRequest(os->obex);
-
-	return FALSE;
-}
-
 static gboolean check_put(obex_t *obex, obex_object_t *obj)
 {
 	struct obex_session *os;
@@ -1229,6 +1243,17 @@ ssize_t obex_aparam_read(struct obex_session *os,
 	return -EBADR;
 }
 
+int obex_aparam_write(struct obex_session *os,
+		obex_object_t *obj, const guint8 *data, guint size)
+{
+	obex_headerdata_t hd;
+
+	hd.bs = data;
+
+	return OBEX_ObjectAddHeader(os->obex, obj,
+			OBEX_HDR_APPARAM, hd, size, 0);
+}
+
 int memcmp0(const void *a, const void *b, size_t n)
 {
 	if (a == NULL)
diff --git a/obexd/src/obex.h b/obexd/src/obex.h
index 64591f6..00336c7 100644
--- a/obexd/src/obex.h
+++ b/obexd/src/obex.h
@@ -58,6 +58,8 @@ int obex_remove(struct obex_session *os, const char *path);
 char *obex_get_id(struct obex_session *os);
 ssize_t obex_aparam_read(struct obex_session *os,
 		obex_object_t *obj, const guint8 **buffer);
+int obex_aparam_write(struct obex_session *os,
+		obex_object_t *obj, const guint8 *buffer, guint size);
 
 const gchar *obex_option_root_folder(void);
 gboolean obex_option_symlinks(void);
diff --git a/obexd/src/service.h b/obexd/src/service.h
index 1ff9603..81185d9 100644
--- a/obexd/src/service.h
+++ b/obexd/src/service.h
@@ -32,7 +32,8 @@ struct obex_service_driver {
 	const gchar *record;
 	gpointer (*connect) (struct obex_session *os, int *err);
 	void (*progress) (struct obex_session *os, gpointer user_data);
-	int (*get) (struct obex_session *os, obex_object_t *obj, gpointer user_data);
+	int (*get) (struct obex_session *os, obex_object_t *obj,
+			gboolean *stream, gpointer user_data);
 	int (*put) (struct obex_session *os, gpointer user_data);
 	gint (*chkput) (struct obex_session *os, gpointer user_data);
 	int (*setpath) (struct obex_session *os, obex_object_t *obj, gpointer user_data);