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
}
static ssize_t filesystem_read(void *object, void *buf, size_t count,
- uint8_t *hi)
+ uint8_t *hi, unsigned int *flags)
{
ssize_t ret;
if (ret < 0)
return -errno;
+ if (flags)
+ *flags = 0;
+
*hi = OBEX_HDR_BODY;
return ret;
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
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;
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
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
struct pbap_object {
GString *buffer;
GByteArray *aparams;
+ gboolean firstpacket;
struct pbap_session *session;
void *request;
};
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;
}
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);
}
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);
}
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)
}
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;
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;
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);
}
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;
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
"}" \
"}"
+#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);
GSList *contacts;
phonebook_cache_ready_cb ready_cb;
phonebook_entry_cb entry_cb;
+ int newmissedcalls;
+ DBusPendingCall *call;
};
struct phonebook_index {
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)
dbus_message_unref(msg);
if (err)
*err = -EPERM;
- /* user_data is freed otherwise only if call was sent */
- g_free(user_data);
return NULL;
}
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.
*/
}
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.
*/
}
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.
*/
}
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,
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;
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,
{
struct phonebook_data *data;
char *query;
- DBusPendingCall *call;
DBG("folder %s id %s", folder, 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,
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
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;
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
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
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
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)
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);
os->buf = NULL;
}
+ if (flags & OBEX_FL_FIT_ONE_PACKET)
+ os->write_offset += len;
+ else
+ os->write_offset = 0;
+
os->offset += len;
return 0;