Diff between 8abc6c728c8fb1d0c9e3177d2dd3bb3925c36918 and f82b81e01502a4b29d5dbe30fb705ab5c740ac00

Changed Files

File Additions Deletions Status
obexd/plugins/filesystem.c +13 -3 modified
obexd/plugins/irmc.c +5 -1 modified
obexd/plugins/nokia-backup.c +5 -1 modified
obexd/plugins/pbap.c +45 -5 modified
obexd/plugins/phonebook-tracker.c +137 -31 modified
obexd/plugins/syncevolution.c +5 -1 modified
obexd/src/mimetype.h +2 -1 modified
obexd/src/obex-priv.h +1 -0 modified
obexd/src/obex.c +10 -5 modified

Full Patch

diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c
index b4ff556..7bfe673 100644
--- a/obexd/plugins/filesystem.c
+++ b/obexd/plugins/filesystem.c
@@ -210,7 +210,7 @@ static int filesystem_close(void *object)
 }
 
 static ssize_t filesystem_read(void *object, void *buf, size_t count,
-								uint8_t *hi)
+					uint8_t *hi, unsigned int *flags)
 {
 	ssize_t ret;
 
@@ -218,6 +218,9 @@ static ssize_t filesystem_read(void *object, void *buf, size_t count,
 	if (ret < 0)
 		return -errno;
 
+	if (flags)
+		*flags = 0;
+
 	*hi = OBEX_HDR_BODY;
 
 	return ret;
@@ -499,17 +502,24 @@ ssize_t string_read(void *object, void *buf, size_t count)
 	return len;
 }
 
-static ssize_t folder_read(void *object, void *buf, size_t count, uint8_t *hi)
+static ssize_t folder_read(void *object, void *buf, size_t count,
+					uint8_t *hi, unsigned int *flags)
 {
+	if (flags)
+		*flags = 0;
+
 	*hi = OBEX_HDR_BODY;
 	return string_read(object, buf, count);
 }
 
 static ssize_t capability_read(void *object, void *buf, size_t count,
-								uint8_t *hi)
+					uint8_t *hi, unsigned int *flags)
 {
 	struct capability_object *obj = object;
 
+	if (flags)
+		*flags = 0;
+
 	*hi = OBEX_HDR_BODY;
 
 	if (obj->buffer)
diff --git a/obexd/plugins/irmc.c b/obexd/plugins/irmc.c
index a281341..0488cae 100644
--- a/obexd/plugins/irmc.c
+++ b/obexd/plugins/irmc.c
@@ -451,7 +451,8 @@ static int irmc_close(void *object)
 	return 0;
 }
 
-static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
+static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi,
+							unsigned int *flags)
 {
 	struct irmc_session *irmc = object;
 	int len;
@@ -460,6 +461,9 @@ static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
 	if (!irmc->buffer)
                 return -EAGAIN;
 
+	if (flags)
+		*flags = 0;
+
 	*hi = OBEX_HDR_BODY;
 	len = string_read(irmc->buffer, buf, count);
 	DBG("returning %d bytes", len);
diff --git a/obexd/plugins/nokia-backup.c b/obexd/plugins/nokia-backup.c
index 6ae4082..4a69d8f 100644
--- a/obexd/plugins/nokia-backup.c
+++ b/obexd/plugins/nokia-backup.c
@@ -222,13 +222,17 @@ static int backup_close(void *object)
 	return 0;
 }
 
-static ssize_t backup_read(void *object, void *buf, size_t count, uint8_t *hi)
+static ssize_t backup_read(void *object, void *buf, size_t count,
+					uint8_t *hi, unsigned int *flags)
 {
 	struct backup_object *obj = object;
 	ssize_t ret = 0;
 
 	*hi = OBEX_HDR_BODY;
 
+	if (flags)
+		*flags = 0;
+
 	if (obj->pending_call) {
 		DBG("cmd = %s, IN WAITING STAGE", obj->cmd);
 		return -EAGAIN;
diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c
index e71a03d..e823d5e 100644
--- a/obexd/plugins/pbap.c
+++ b/obexd/plugins/pbap.c
@@ -147,6 +147,7 @@ struct pbap_session {
 struct pbap_object {
 	GString *buffer;
 	GByteArray *aparams;
+	gboolean firstpacket;
 	struct pbap_session *session;
 	void *request;
 };
@@ -240,6 +241,13 @@ static GByteArray *append_aparam_header(GByteArray *buf, uint8_t tag,
 
 		return g_byte_array_append(buf,	aparam,
 			sizeof(struct aparam_header) + PHONEBOOKSIZE_LEN);
+	case NEWMISSEDCALLS_TAG:
+		hdr->tag = NEWMISSEDCALLS_TAG;
+		hdr->len = NEWMISSEDCALLS_LEN;
+		memcpy(hdr->val, val, NEWMISSEDCALLS_LEN);
+
+		return g_byte_array_append(buf,	aparam,
+			sizeof(struct aparam_header) + NEWMISSEDCALLS_LEN);
 	default:
 		return buf;
 	}
@@ -267,6 +275,13 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 	pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
 					PHONEBOOKSIZE_TAG, &phonebooksize);
 
+	if (missed > 0)	{
+		DBG("missed %d", missed);
+
+		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
+						NEWMISSEDCALLS_TAG, &missed);
+	}
+
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
 }
 
@@ -293,6 +308,16 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 		pbap->obj->buffer = g_string_append_len(pbap->obj->buffer,
 							buffer,	bufsize);
 
+	if (missed > 0)	{
+		DBG("missed %d", missed);
+
+		pbap->obj->firstpacket = TRUE;
+
+		pbap->obj->aparams = g_byte_array_new();
+		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
+						NEWMISSEDCALLS_TAG, &missed);
+	}
+
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
 }
 
@@ -489,9 +514,7 @@ static void cache_entry_done(void *user_data)
 		return;
 	}
 
-	/* Unref previous request, associated data will be freed. */
 	phonebook_req_finalize(pbap->obj->request);
-	/* Get new pointer to pending call. */
 	pbap->obj->request = phonebook_get_entry(pbap->folder, id,
 				pbap->params, query_result, pbap, &ret);
 	if (ret < 0)
@@ -933,7 +956,7 @@ static ssize_t array_read(GByteArray *array, void *buf, size_t count)
 }
 
 static ssize_t vobject_pull_read(void *object, void *buf, size_t count,
-								uint8_t *hi)
+					uint8_t *hi, unsigned int *flags)
 {
 	struct pbap_object *obj = object;
 	struct pbap_session *pbap = obj->session;
@@ -947,16 +970,27 @@ static ssize_t vobject_pull_read(void *object, void *buf, size_t count,
 	if (pbap->params->maxlistcount == 0) {
 		/* PhoneBookSize */
 		*hi = OBEX_HDR_APPARAM;
+		if (flags)
+			*flags = 0;
+		return array_read(obj->aparams, buf, count);
+	} else if (obj->firstpacket) {
+		/* NewMissedCalls */
+		*hi = OBEX_HDR_APPARAM;
+		obj->firstpacket = FALSE;
+		if (flags)
+			*flags = OBEX_FL_FIT_ONE_PACKET;
 		return array_read(obj->aparams, buf, count);
 	} else {
 		/* Stream data */
 		*hi = OBEX_HDR_BODY;
+		if (flags)
+			*flags = 0;
 		return string_read(obj->buffer, buf, count);
 	}
 }
 
 static ssize_t vobject_list_read(void *object, void *buf, size_t count,
-								uint8_t *hi)
+					uint8_t *hi, unsigned int *flags)
 {
 	struct pbap_object *obj = object;
 	struct pbap_session *pbap = obj->session;
@@ -968,6 +1002,9 @@ static ssize_t vobject_list_read(void *object, void *buf, size_t count,
 	if (!pbap->cache.valid)
 		return -EAGAIN;
 
+	if (flags)
+		*flags = 0;
+
 	if (pbap->params->maxlistcount == 0) {
 		*hi = OBEX_HDR_APPARAM;
 		return array_read(obj->aparams, buf, count);
@@ -978,7 +1015,7 @@ static ssize_t vobject_list_read(void *object, void *buf, size_t count,
 }
 
 static ssize_t vobject_vcard_read(void *object, void *buf, size_t count,
-								uint8_t *hi)
+					uint8_t *hi, unsigned int *flags)
 {
 	struct pbap_object *obj = object;
 
@@ -987,6 +1024,9 @@ static ssize_t vobject_vcard_read(void *object, void *buf, size_t count,
 	if (!obj->buffer)
 		return -EAGAIN;
 
+	if (flags)
+		*flags = 0;
+
 	*hi = OBEX_HDR_BODY;
 	return string_read(obj->buffer, buf, count);
 }
diff --git a/obexd/plugins/phonebook-tracker.c b/obexd/plugins/phonebook-tracker.c
index cc4b49f..a6a2e47 100644
--- a/obexd/plugins/phonebook-tracker.c
+++ b/obexd/plugins/phonebook-tracker.c
@@ -919,6 +919,41 @@
 	"}"								\
 	"}"
 
+#define NEW_MISSED_CALLS_LIST						\
+	"SELECT ?c "							\
+	"nco:phoneNumber(?h) "						\
+	"nmo:isRead(?call) "						\
+	"WHERE { "							\
+	"{"								\
+		"?c a nco:Contact . "					\
+		"?c nco:hasPhoneNumber ?h . "				\
+		"?call a nmo:Call ; "					\
+		"nmo:from ?c ; "					\
+		"nmo:isSent false ; "					\
+		"nmo:isAnswered false ."				\
+	"}UNION{"							\
+		"?x a nco:Contact . "					\
+		"?x nco:hasPhoneNumber ?h . "				\
+		"?call a nmo:Call ; "					\
+		"nmo:from ?x ; "					\
+		"nmo:isSent false ; "					\
+		"nmo:isAnswered false ."				\
+		"?c a nco:PersonContact . "				\
+		"?c nco:hasPhoneNumber ?h . "				\
+	"} UNION { "							\
+		"?x a nco:Contact . "					\
+		"?x nco:hasPhoneNumber ?h . "				\
+		"?call a nmo:Call ; "					\
+		"nmo:from ?x ; "					\
+		"nmo:isSent false ; "					\
+		"nmo:isAnswered false ."				\
+		"?c a nco:PersonContact . "				\
+		"?c nco:hasAffiliation ?a . "				\
+		"?a nco:hasPhoneNumber ?h . "				\
+	"} "								\
+	"} GROUP BY ?call ORDER BY DESC(nmo:receivedDate(?call)) "	\
+	"LIMIT 40"
+
 typedef void (*reply_list_foreach_t) (char **reply, int num_fields,
 							void *user_data);
 
@@ -943,6 +978,8 @@ struct phonebook_data {
 	GSList *contacts;
 	phonebook_cache_ready_cb ready_cb;
 	phonebook_entry_cb entry_cb;
+	int newmissedcalls;
+	DBusPendingCall *call;
 };
 
 struct phonebook_index {
@@ -1111,11 +1148,7 @@ done:
 
 	dbus_message_unref(reply);
 
-	/*
-	 * pending data is freed in query_free_data after call is unreffed.
-	 * Same holds for pending->user_data which is not freed in callback
-	 * but in query_free_data.
-	 */
+	/* pending data is freed in query_free_data after call is unreffed. */
 }
 
 static void query_free_data(void *user_data)
@@ -1155,8 +1188,6 @@ static DBusPendingCall *query_tracker(const char *query, int num_fields,
 		dbus_message_unref(msg);
 		if (err)
 			*err = -EPERM;
-		/* user_data is freed otherwise only if call was sent */
-		g_free(user_data);
 		return NULL;
 	}
 
@@ -1394,12 +1425,11 @@ static void pull_contacts_size(char **reply, int num_fields, void *user_data)
 		return;
 	}
 
-	data->cb(NULL, 0, data->index, 0, data->user_data);
+	data->cb(NULL, 0, data->index, data->newmissedcalls, data->user_data);
 
 	/*
-	 * phonebook_data is freed in query_free_data after call is unreffed.
-	 * It is accessible by pointer from data (pending) associated to call.
-	 * Useful in cases when call was terminated.
+	 * phonebook_data is freed in phonebook_req_finalize. Useful in
+	 * cases when call is terminated.
 	 */
 }
 
@@ -1682,19 +1712,17 @@ done:
 
 	if (num_fields == 0)
 		data->cb(vcards->str, vcards->len,
-					g_slist_length(data->contacts), 0,
-					data->user_data);
+					g_slist_length(data->contacts),
+					data->newmissedcalls, data->user_data);
 
 	g_string_free(vcards, TRUE);
 fail:
-	g_slist_free(data->contacts);
 	g_free(temp_id);
 	temp_id = NULL;
 
 	/*
-	 * phonebook_data is freed in query_free_data after call is unreffed.
-	 * It is accessible by pointer from data (pending) associated to call.
-	 * Useful in cases when call was terminated.
+	 * phonebook_data is freed in phonebook_req_finalize. Useful in
+	 * cases when call is terminated.
 	 */
 }
 
@@ -1741,9 +1769,8 @@ done:
 		data->ready_cb(data->user_data);
 
 	/*
-	 * data is freed in query_free_data after call is unreffed.
-	 * It is accessible by pointer from data (pending) associated to call.
-	 * Useful in cases when call was terminated.
+	 * phonebook_data is freed in phonebook_req_finalize. Useful in
+	 * cases when call is terminated.
 	 */
 }
 
@@ -1834,14 +1861,87 @@ done:
 
 void phonebook_req_finalize(void *request)
 {
-	struct DBusPendingCall *call = request;
+	struct phonebook_data *data = request;
 
 	DBG("");
 
-	if (!dbus_pending_call_get_completed(call))
-		dbus_pending_call_cancel(call);
+	if (!data)
+		return;
+
+	if (!dbus_pending_call_get_completed(data->call))
+		dbus_pending_call_cancel(data->call);
 
-	dbus_pending_call_unref(call);
+	dbus_pending_call_unref(data->call);
+
+	g_slist_free(data->contacts);
+	g_free(data);
+}
+
+static gboolean find_checked_number(GSList *numbers, const char *number)
+{
+	GSList *l;
+
+	for (l = numbers; l; l = l->next) {
+		GString *ph_num = l->data;
+		if (g_strcmp0(ph_num->str, number) == 0)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void gstring_free_helper(gpointer data, gpointer user_data)
+{
+	g_string_free(data, TRUE);
+}
+
+static void pull_newmissedcalls(char **reply, int num_fields, void *user_data)
+{
+	struct phonebook_data *data = user_data;
+	reply_list_foreach_t pull_cb;
+	int col_amount, err;
+	const char *query;
+
+	if (num_fields < 0 || reply == NULL)
+		goto done;
+
+	if (!find_checked_number(data->contacts, reply[1])) {
+		if (g_strcmp0(reply[2], "false") == 0)
+			data->newmissedcalls++;
+		else {
+			GString *number = g_string_new(reply[1]);
+			data->contacts = g_slist_append(data->contacts,
+								number);
+		}
+	}
+	return;
+
+done:
+	DBG("newmissedcalls %d", data->newmissedcalls);
+	g_slist_foreach(data->contacts, gstring_free_helper, NULL);
+	g_slist_free(data->contacts);
+	data->contacts = NULL;
+
+	if (num_fields < 0) {
+		data->cb(NULL, 0, num_fields, 0, data->user_data);
+		return;
+	}
+
+	if (data->params->maxlistcount == 0) {
+		query = name2count_query("telecom/mch.vcf");
+		col_amount = COUNT_QUERY_COL_AMOUNT;
+		pull_cb = pull_contacts_size;
+	} else {
+		query = name2query("telecom/mch.vcf");
+		col_amount = PULL_QUERY_COL_AMOUNT;
+		pull_cb = pull_contacts;
+	}
+
+	dbus_pending_call_unref(data->call);
+	data->call = query_tracker(query, col_amount, pull_cb, data, NULL,
+								&err);
+	if (err < 0)
+		data->cb(NULL, 0, err, 0, data->user_data);
 }
 
 void *phonebook_pull(const char *name, const struct apparam_field *params,
@@ -1854,7 +1954,11 @@ void *phonebook_pull(const char *name, const struct apparam_field *params,
 
 	DBG("name %s", name);
 
-	if (params->maxlistcount == 0) {
+	if (g_strcmp0(name, "telecom/mch.vcf") == 0) {
+		query = NEW_MISSED_CALLS_LIST;
+		col_amount = PULL_QUERY_COL_AMOUNT;
+		pull_cb = pull_newmissedcalls;
+	} else if (params->maxlistcount == 0) {
 		query = name2count_query(name);
 		col_amount = COUNT_QUERY_COL_AMOUNT;
 		pull_cb = pull_contacts_size;
@@ -1874,8 +1978,10 @@ void *phonebook_pull(const char *name, const struct apparam_field *params,
 	data->params = params;
 	data->user_data = user_data;
 	data->cb = cb;
+	data->call = query_tracker(query, col_amount, pull_cb, data, NULL,
+									err);
 
-	return query_tracker(query, col_amount, pull_cb, data, g_free, err);
+	return data;
 }
 
 void *phonebook_get_entry(const char *folder, const char *id,
@@ -1884,7 +1990,6 @@ void *phonebook_get_entry(const char *folder, const char *id,
 {
 	struct phonebook_data *data;
 	char *query;
-	DBusPendingCall *call;
 
 	DBG("folder %s id %s", folder, id);
 
@@ -1902,12 +2007,12 @@ void *phonebook_get_entry(const char *folder, const char *id,
 		query = g_strdup_printf(CONTACTS_OTHER_QUERY_FROM_URI,
 								id, id, id);
 
-	call = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts,
-							data, g_free, err);
+	data->call = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts,
+							data, NULL, err);
 
 	g_free(query);
 
-	return call;
+	return data;
 }
 
 void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
@@ -1929,6 +2034,7 @@ void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
 	data->entry_cb = entry_cb;
 	data->ready_cb = ready_cb;
 	data->user_data = user_data;
+	data->call = query_tracker(query, 7, add_to_cache, data, NULL, err);
 
-	return query_tracker(query, 7, add_to_cache, data, g_free, err);
+	return data;
 }
diff --git a/obexd/plugins/syncevolution.c b/obexd/plugins/syncevolution.c
index 8041df6..a000b36 100644
--- a/obexd/plugins/syncevolution.c
+++ b/obexd/plugins/syncevolution.c
@@ -331,7 +331,8 @@ done:
 	return 0;
 }
 
-static ssize_t synce_read(void *object, void *buf, size_t count, uint8_t *hi)
+static ssize_t synce_read(void *object, void *buf, size_t count,
+					uint8_t *hi, unsigned int *flags)
 {
 	struct synce_context *context = object;
 	DBusConnection *conn;
@@ -342,6 +343,9 @@ static ssize_t synce_read(void *object, void *buf, size_t count, uint8_t *hi)
 	gboolean authenticate;
 	DBusPendingCall *call;
 
+	if (flags)
+		*flags = 0;
+
 	if (context->buffer) {
 		*hi = OBEX_HDR_BODY;
 		return string_read(context->buffer, buf, count);
diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h
index 200b950..ff16a8c 100644
--- a/obexd/src/mimetype.h
+++ b/obexd/src/mimetype.h
@@ -33,7 +33,8 @@ struct obex_mime_type_driver {
 	void *(*open) (const char *name, int oflag, mode_t mode,
 			void *driver_data, size_t *size, int *err);
 	int (*close) (void *object);
-	ssize_t (*read) (void *object, void *buf, size_t count, uint8_t *hi);
+	ssize_t (*read) (void *object, void *buf, size_t count, uint8_t *hi,
+							unsigned int *flags);
 	ssize_t (*write) (void *object, const void *buf, size_t count);
 	int (*remove) (const char *name);
 	int (*set_io_watch) (void *object, obex_object_io_func func,
diff --git a/obexd/src/obex-priv.h b/obexd/src/obex-priv.h
index 0806a56..2a22f38 100644
--- a/obexd/src/obex-priv.h
+++ b/obexd/src/obex-priv.h
@@ -46,6 +46,7 @@ struct obex_session {
 	obex_object_t *obj;
 	struct obex_mime_type_driver *driver;
 	gboolean finished;
+	uint16_t write_offset;
 };
 
 int obex_session_start(GIOChannel *io, uint16_t tx_mtu, uint16_t rx_mtu,
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
index e7d40dd..65f17fc 100644
--- a/obexd/src/obex.c
+++ b/obexd/src/obex.c
@@ -640,10 +640,13 @@ static int obex_write_stream(struct obex_session *os,
 
 		len = MIN(os->size - os->offset, os->tx_mtu);
 		ptr = os->buf + os->offset;
+		flags = 0;
 		goto add_header;
 	}
 
-	len = os->driver->read(os->object, os->buf, os->tx_mtu, &hi);
+	ptr = os->buf + os->write_offset;
+	len = os->driver->read(os->object, ptr, os->tx_mtu - os->write_offset,
+								&hi, &flags);
 	if (len < 0) {
 		error("read(): %s (%zd)", strerror(-len), -len);
 		if (len == -EAGAIN)
@@ -656,18 +659,15 @@ static int obex_write_stream(struct obex_session *os,
 		return len;
 	}
 
-	ptr = os->buf;
-
 add_header:
 
 	hd.bs = ptr;
 
 	switch (hi) {
 	case OBEX_HDR_BODY:
-		flags = len ? OBEX_FL_STREAM_DATA : OBEX_FL_STREAM_DATAEND;
+		flags |= len ? OBEX_FL_STREAM_DATA : OBEX_FL_STREAM_DATAEND;
 		break;
 	case OBEX_HDR_APPARAM:
-		flags =  0;
 		break;
 	default:
 		error("read(): unkown header type %u", hi);
@@ -681,6 +681,11 @@ add_header:
 		os->buf = NULL;
 	}
 
+	if (flags & OBEX_FL_FIT_ONE_PACKET)
+		os->write_offset += len;
+	else
+		os->write_offset = 0;
+
 	os->offset += len;
 
 	return 0;