obexd: Add support to multiple folders to tracker backend
This adds support to ich, och, mch and cch folders to the tracker
backend.
diff --git a/obexd/plugins/phonebook-tracker.c b/obexd/plugins/phonebook-tracker.c
index 9b431d8..c7c4e06 100644
--- a/obexd/plugins/phonebook-tracker.c
+++ b/obexd/plugins/phonebook-tracker.c
@@ -49,29 +49,29 @@
"?contact a nco:PersonContact ; " \
"nco:nameFamily ?family ; " \
"nco:nameGiven ?given ; " \
- "nco:hasPhoneNumber ?phone ." \
+ "nco:hasPhoneNumber ?phone . " \
"OPTIONAL { ?contact nco:hasEmailAddress ?email } " \
"OPTIONAL { ?contact nco:nameAdditional ?additional } " \
"OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
"OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
"}"
-#define CONTACTS_QUERY_ALL_LIST \
+#define CONTACTS_QUERY_ALL_LIST \
"SELECT ?contact ?family ?given ?additional ?prefix " \
"?suffix ?phone " \
"WHERE { " \
"?contact a nco:PersonContact ; " \
"nco:nameFamily ?family ; " \
"nco:nameGiven ?given ; " \
- "nco:hasPhoneNumber ?phone ." \
+ "nco:hasPhoneNumber ?phone . " \
"OPTIONAL { ?contact nco:nameAdditional ?additional } " \
"OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
"OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
"}"
-#define MISSED_CALLS_QUERY \
- "SELECT ?contact ?family ?given ?additional ?prefix " \
- "?suffix ?phone ?email " \
+#define MISSED_CALLS_QUERY \
+ "SELECT ?phone ?family ?given ?additional ?prefix " \
+ "?suffix ?email " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:from ?contact ; " \
@@ -80,16 +80,34 @@
"?contact a nco:PersonContact ; " \
"nco:nameFamily ?family ; " \
"nco:nameGiven ?given ; " \
- "nco:hasPhoneNumber ?phone ." \
+ "nco:hasPhoneNumber ?phone . " \
"OPTIONAL { ?contact nco:hasEmailAddress ?email } " \
"OPTIONAL { ?contact nco:nameAdditional ?additional } " \
"OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
"OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
"}"
-#define INCOMING_CALLS_QUERY \
+#define MISSED_CALLS_LIST \
"SELECT ?contact ?family ?given ?additional ?prefix " \
- "?suffix ?phone ?fullname ?email " \
+ "?suffix ?phone " \
+ "WHERE { " \
+ "?call a nmo:Call ; " \
+ "nmo:from ?contact ; " \
+ "nmo:to " TRACKER_DEFAULT_CONTACT_ME " ; " \
+ "nmo:isRead false ." \
+ "?contact a nco:PersonContact ; " \
+ "nco:nameFamily ?family ; " \
+ "nco:nameGiven ?given ; " \
+ "nco:hasPhoneNumber ?phone . " \
+ "OPTIONAL { ?contact nco:hasEmailAddress ?email } " \
+ "OPTIONAL { ?contact nco:nameAdditional ?additional } " \
+ "OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
+ "OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
+ "}"
+
+#define INCOMING_CALLS_QUERY \
+ "SELECT ?phone ?family ?given ?additional ?prefix " \
+ "?suffix ?email " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:from ?contact ; " \
@@ -97,16 +115,32 @@
"?contact a nco:PersonContact ; " \
"nco:nameFamily ?family ; " \
"nco:nameGiven ?given ; " \
- "nco:hasPhoneNumber ?phone ." \
+ "nco:hasPhoneNumber ?phone . " \
"OPTIONAL { ?contact nco:hasEmailAddress ?email } " \
"OPTIONAL { ?contact nco:nameAdditional ?additional } " \
"OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
"OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
"}"
-#define OUTGOING_CALLS_QUERY \
+#define INCOMING_CALLS_LIST \
"SELECT ?contact ?family ?given ?additional ?prefix " \
- "?suffix ?phone ?fullname ?email " \
+ "?suffix ?phone " \
+ "WHERE { " \
+ "?call a nmo:Call ; " \
+ "nmo:from ?contact ; " \
+ "nmo:to " TRACKER_DEFAULT_CONTACT_ME " . " \
+ "?contact a nco:PersonContact ; " \
+ "nco:nameFamily ?family ; " \
+ "nco:nameGiven ?given ; " \
+ "nco:hasPhoneNumber ?phone . " \
+ "OPTIONAL { ?contact nco:nameAdditional ?additional } " \
+ "OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
+ "OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
+ "}"
+
+#define OUTGOING_CALLS_QUERY \
+ "SELECT ?phone ?family ?given ?additional ?prefix " \
+ "?suffix ?email " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:to ?contact ; " \
@@ -114,20 +148,88 @@
"?contact a nco:PersonContact ; " \
"nco:nameFamily ?family ; " \
"nco:nameGiven ?given ; " \
- "nco:hasPhoneNumber ?phone ." \
+ "nco:hasPhoneNumber ?phone . " \
"OPTIONAL { ?contact nco:hasEmailAddress ?email } " \
"OPTIONAL { ?contact nco:nameAdditional ?additional } " \
"OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
"OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
"}"
-/* FIXME: still not sure about how to implement this */
-#define COMBINED_CALLS_QUERY \
- "SELECT ?contact " \
+#define OUTGOING_CALLS_LIST \
+ "SELECT ?contact ?family ?given ?additional ?prefix " \
+ "?suffix ?phone " \
"WHERE { " \
- "?call a nmo:Call . " \
+ "?call a nmo:Call ; " \
+ "nmo:to ?contact ; " \
+ "nmo:from " TRACKER_DEFAULT_CONTACT_ME " . " \
+ "?contact a nco:PersonContact ; " \
+ "nco:nameFamily ?family ; " \
+ "nco:nameGiven ?given ; " \
+ "nco:hasPhoneNumber ?phone . " \
+ "OPTIONAL { ?contact nco:nameAdditional ?additional } " \
+ "OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } " \
+ "OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } " \
"}"
+#define COMBINED_CALLS_QUERY \
+ "SELECT ?phone ?family ?given ?additional ?prefix " \
+ "?suffix ?email " \
+ "WHERE { " \
+ "{ " \
+ "?call a nmo:Call ; " \
+ "nmo:to ?contact ; " \
+ "nmo:from " TRACKER_DEFAULT_CONTACT_ME " . " \
+ "?contact a nco:PersonContact ; " \
+ "nco:nameFamily ?family ; " \
+ "nco:nameGiven ?given ; " \
+ "nco:hasPhoneNumber ?phone . " \
+ "OPTIONAL { ?contact nco:hasEmailAddress ?email } " \
+ "OPTIONAL { ?contact nco:nameAdditional ?additional } " \
+ "OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } "\
+ "OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } "\
+ "} UNION { " \
+ "?call a nmo:Call ; " \
+ "nmo:from ?contact ; " \
+ "nmo:to " TRACKER_DEFAULT_CONTACT_ME " . " \
+ "?contact a nco:PersonContact ; " \
+ "nco:nameFamily ?family ; " \
+ "nco:nameGiven ?given ; " \
+ "nco:hasPhoneNumber ?phone . " \
+ "OPTIONAL { ?contact nco:hasEmailAddress ?email } " \
+ "OPTIONAL { ?contact nco:nameAdditional ?additional } " \
+ "OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } "\
+ "OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } "\
+ "} } "
+
+#define COMBINED_CALLS_LIST \
+ "SELECT ?contact ?family ?given ?additional ?prefix " \
+ "?suffix ?phone " \
+ "WHERE { " \
+ "{ " \
+ "?call a nmo:Call ; " \
+ "nmo:to ?contact ; " \
+ "nmo:from " TRACKER_DEFAULT_CONTACT_ME " . " \
+ "?contact a nco:PersonContact ; " \
+ "nco:nameFamily ?family ; " \
+ "nco:nameGiven ?given ; " \
+ "nco:hasPhoneNumber ?phone . " \
+ "OPTIONAL { ?contact nco:nameAdditional ?additional } " \
+ "OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } "\
+ "OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } "\
+ "} UNION { " \
+ "?call a nmo:Call ; " \
+ "nmo:from ?contact ; " \
+ "nmo:to " TRACKER_DEFAULT_CONTACT_ME " . " \
+ "?contact a nco:PersonContact ; " \
+ "nco:nameFamily ?family ; " \
+ "nco:nameGiven ?given ; " \
+ "nco:hasPhoneNumber ?phone . " \
+ "OPTIONAL { ?contact nco:nameAdditional ?additional } " \
+ "OPTIONAL { ?contact nco:nameHonorificPrefix ?prefix } "\
+ "OPTIONAL { ?contact nco:nameHonorificSuffix ?suffix } "\
+ "} } "
+
+
#define CONTACTS_QUERY_FROM_URI \
"SELECT ?phone ?family ?given ?additional ?prefix " \
" ?suffix ?email " \
@@ -135,7 +237,7 @@
"<%s> a nco:PersonContact ; " \
"nco:nameFamily ?family ; " \
"nco:nameGiven ?given ; " \
- "nco:hasPhoneNumber ?phone ." \
+ "nco:hasPhoneNumber ?phone . " \
"OPTIONAL { <%s> nco:hasEmailAddress ?email } " \
"OPTIONAL { <%s> nco:nameAdditional ?additional } " \
"OPTIONAL { <%s> nco:nameHonorificPrefix ?prefix } " \
@@ -173,6 +275,58 @@
static DBusConnection *connection = NULL;
+static const char *name2query(const char *name)
+{
+ if (g_str_equal(name, "telecom/pb.vcf"))
+ return CONTACTS_QUERY_ALL;
+ else if (g_str_equal(name, "telecom/ich.vcf"))
+ return INCOMING_CALLS_QUERY;
+ else if (g_str_equal(name, "telecom/och.vcf"))
+ return OUTGOING_CALLS_QUERY;
+ else if (g_str_equal(name, "telecom/mch.vcf"))
+ return MISSED_CALLS_QUERY;
+ else if (g_str_equal(name, "telecom/cch.vcf"))
+ return COMBINED_CALLS_QUERY;
+
+ return NULL;
+}
+
+static gboolean folder_is_valid(const char *folder)
+{
+ if (g_str_equal(folder, "/"))
+ return TRUE;
+ else if (g_str_equal(folder, "/telecom"))
+ return TRUE;
+ else if (g_str_equal(folder, "/telecom/pb"))
+ return TRUE;
+ else if (g_str_equal(folder, "/telecom/ich"))
+ return TRUE;
+ else if (g_str_equal(folder, "/telecom/och"))
+ return TRUE;
+ else if (g_str_equal(folder, "/telecom/mch"))
+ return TRUE;
+ else if (g_str_equal(folder, "/telecom/cch"))
+ return TRUE;
+
+ return FALSE;
+}
+
+static const char *folder2query(const char *folder)
+{
+ if (g_str_equal(folder, "/telecom/pb"))
+ return CONTACTS_QUERY_ALL_LIST;
+ else if (g_str_equal(folder, "/telecom/ich"))
+ return INCOMING_CALLS_LIST;
+ else if (g_str_equal(folder, "/telecom/och"))
+ return OUTGOING_CALLS_LIST;
+ else if (g_str_equal(folder, "/telecom/mch"))
+ return MISSED_CALLS_LIST;
+ else if (g_str_equal(folder, "/telecom/cch"))
+ return COMBINED_CALLS_LIST;
+
+ return NULL;
+}
+
static char **string_array_from_iter(DBusMessageIter iter, int array_len)
{
DBusMessageIter sub;
@@ -364,27 +518,95 @@
char *phonebook_set_folder(const char *current_folder, const char *new_folder,
uint8_t flags, int *err)
{
- char *folder;
+ char *tmp1, *tmp2, *base, *path = NULL;
+ gboolean root, child;
+ int ret, len;
+
+ root = (g_strcmp0("/", current_folder) == 0);
+ child = (new_folder && strlen(new_folder) != 0);
+
+ switch (flags) {
+ case 0x02:
+ /* Go back to root */
+ if (!child) {
+ path = g_strdup("/");
+ goto done;
+ }
+
+ path = g_build_filename(current_folder, new_folder, NULL);
+ break;
+ case 0x03:
+ /* Go up 1 level */
+ if (root) {
+ /* Already root */
+ path = g_strdup("/");
+ goto done;
+ }
+
+ /*
+ * Removing one level of the current folder. Current folder
+ * contains AT LEAST one level since it is not at root folder.
+ * Use glib utility functions to handle invalid chars in the
+ * folder path properly.
+ */
+ tmp1 = g_path_get_basename(current_folder);
+ tmp2 = g_strrstr(current_folder, tmp1);
+ len = tmp2 - (current_folder + 1);
+
+ g_free(tmp1);
+ g_free(tmp2);
+
+ if (len == 0)
+ base = g_strdup("/");
+ else
+ base = g_strndup(current_folder, len);
+
+ /* Return: one level only */
+ if (!child) {
+ path = base;
+ goto done;
+ }
+
+ path = g_build_filename(base, new_folder, NULL);
+ g_free(base);
+
+ break;
+ default:
+ ret = -EBADR;
+ break;
+ }
+
+done:
+
+ if (!folder_is_valid(path)) {
+ g_free(path);
+ path = NULL;
+ ret = -EBADR;
+ } else
+ ret = 0;
if (err)
- *err = 0;
+ *err = ret;
- folder = g_build_path(current_folder, new_folder, NULL);
-
- return folder;
+ return path;
}
int phonebook_pull(const char *name, const struct apparam_field *params,
phonebook_cb cb, void *user_data)
{
struct phonebook_data *data;
+ const char *query;
+
+ query = name2query(name);
+ if (query == NULL)
+ return -1;
data = g_new0(struct phonebook_data, 1);
data->vcards = g_string_new(NULL);
data->user_data = user_data;
data->cb = cb;
- return query_tracker(CONTACTS_QUERY_ALL, 7, pull_contacts, data);
+ return query_tracker(query, 7, pull_contacts, data);
}
int phonebook_get_entry(const char *folder, const char *id,
@@ -413,11 +635,16 @@
phonebook_cache_ready_cb ready_cb, void *user_data)
{
struct cache_data *cache;
+ const char *query;
+
+ query = folder2query(name);
+ if (query == NULL)
+ return -1;
cache = g_new0(struct cache_data, 1);
cache->entry_cb = entry_cb;
cache->ready_cb = ready_cb;
cache->user_data = user_data;
- return query_tracker(CONTACTS_QUERY_ALL_LIST, 7, add_to_cache, cache);
+ return query_tracker(query, 7, add_to_cache, cache);
}