4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Girishashok Joshi <girish.joshi@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
37 #include <sys/types.h>
43 #include "phonebook.h"
45 #include <dbus/dbus.h>
48 #define PHONEBOOK_DESTINATION "org.bluez.pb_agent"
49 #define PHONEBOOK_PATH "/org/bluez/pb_agent"
50 #define PHONEBOOK_INTERFACE "org.bluez.PbAgent"
52 #define QUERY_GET_PHONEBOOK_FOLDER_LIST "GetPhonebookFolderList"
53 #define QUERY_GET_PHONEBOOK_SIZE "GetPhonebookSize"
54 #define QUERY_GET_PHONEBOOK "GetPhonebook"
55 #define QUERY_GET_PHONEBOOK_LIST "GetPhonebookList"
56 #define QUERY_GET_PHONEBOOK_ENTRY "GetPhonebookEntry"
57 #define QUERY_DESTROY_AGENT "DestroyAgent"
59 static GPtrArray *folder_list = NULL;
61 struct phonebook_data {
63 DBusPendingCallNotifyFunction reply_cb;
64 DBusPendingCall *call;
66 const struct apparam_field *params;
68 phonebook_entry_cb entry_cb;
69 phonebook_cache_ready_cb ready_cb;
74 struct phonebook_session {
75 DBusConnection *connection;
76 phonebook_cache_clear_cb clear_cb;
77 unsigned int clear_id;
82 static gboolean folder_is_valid(const gchar *folder,
88 if (folder_list == NULL || folder == NULL)
91 folder_len = strlen(folder);
93 for (i = 0 ; i < folder_list->len; i++) {
94 char *str = (char *)g_ptr_array_index(folder_list, i);
96 if (folder_len > strlen(str))
99 if (g_strcmp0(str, folder) == 0)
102 if (leaf_only == TRUE)
105 if (strncmp(str, folder, folder_len) == 0) {
107 if (*(folder + folder_len - 1) == '/')
108 return TRUE; /* folder is ended with '/' */
110 if (*(str + folder_len) == '/')
111 return TRUE; /* folder is matched */
118 static DBusPendingCall* phonebook_request(struct phonebook_data *data,
120 DBusPendingCallNotifyFunction function,
124 DBusConnection *connection;
125 DBusPendingCall *call;
126 DBusMessage *message;
133 error("Can't get method name");
137 connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
139 error("Can't get on session bus");
143 message = dbus_message_new_method_call(PHONEBOOK_DESTINATION,
148 dbus_connection_unref(connection);
149 error("Can't Allocate new message");
153 va_start(args, first_arg_type);
154 dbus_message_append_args_valist(message, first_arg_type, args);
157 if (dbus_connection_send_with_reply(connection, message, &call, -1) == FALSE) {
158 dbus_message_unref(message);
159 dbus_connection_unref(connection);
163 dbus_pending_call_set_notify(call, function, data, NULL);
165 dbus_message_unref(message);
166 dbus_connection_unref(connection);
172 static void get_phonebook_size_reply(DBusPendingCall *call, void *user_data)
174 DBusMessage *reply = dbus_pending_call_steal_reply(call);
175 struct phonebook_data *s_data = user_data;
177 uint32_t phonebook_size;
179 unsigned int new_missed_call = 0;
182 dbus_pending_call_unref(s_data->call);
186 DBG("Reply Error\n");
190 dbus_error_init(&derr);
191 if (dbus_set_error_from_message(&derr, reply)) {
192 error("Replied with an error: %s, %s", derr.name, derr.message);
193 dbus_error_free(&derr);
196 dbus_message_get_args(reply, NULL,
197 DBUS_TYPE_UINT32, &phonebook_size,
198 DBUS_TYPE_UINT32, &new_missed_call,
200 DBG("phonebooksize:%d\n", phonebook_size);
203 s_data->cb(NULL, 0, phonebook_size, new_missed_call, TRUE, s_data->user_data);
205 dbus_message_unref(reply);
208 static void get_phonebook_reply(DBusPendingCall *call, void *user_data)
210 DBusMessage *reply = dbus_pending_call_steal_reply(call);
211 struct phonebook_data *s_data = user_data;
215 unsigned int new_missed_call = 0;
220 dbus_pending_call_unref(s_data->call);
224 DBG("Reply Error\n");
228 buffer = g_string_new("");
230 dbus_error_init(&derr);
231 if (dbus_set_error_from_message(&derr, reply)) {
232 error("Replied with an error: %s, %s", derr.name, derr.message);
233 dbus_error_free(&derr);
235 DBusMessageIter iter;
237 dbus_message_iter_init(reply, &iter);
239 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
240 DBusMessageIter recurse_iter;
242 dbus_message_iter_recurse(&iter, &recurse_iter);
243 while (dbus_message_iter_get_arg_type(&recurse_iter) == DBUS_TYPE_STRING) {
246 dbus_message_iter_get_basic(&recurse_iter, &str);
247 dbus_message_iter_next(&recurse_iter);
249 g_string_append(buffer, str);
251 DBG("str:\n%s\n", str);
255 dbus_message_iter_next(&iter);
258 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
259 dbus_message_iter_get_basic(&iter, &new_missed_call);
261 DBG("new_missed_call %d\n", new_missed_call);
264 s_data->cb(buffer->str, buffer->len, count, new_missed_call, 1, s_data->user_data);
266 g_string_free(buffer, TRUE);
267 dbus_message_unref(reply);
271 static void get_phonebook_list_reply(DBusPendingCall *call, void *user_data)
273 DBusMessage *reply = dbus_pending_call_steal_reply(call);
274 DBusMessageIter iter, iter_struct, entry;
275 struct phonebook_data *data = user_data;
278 const char *name = NULL;
279 const char *tel = NULL;
281 unsigned int new_missed_call = 0;
283 dbus_pending_call_unref(data->call);
286 DBG("Reply Error\n");
290 dbus_error_init(&derr);
291 if (dbus_set_error_from_message(&derr, reply)) {
292 error("Replied with an error: %s, %s", derr.name, derr.message);
293 dbus_error_free(&derr);
296 dbus_message_iter_init(reply, &iter);
298 dbus_message_iter_recurse(&iter, &iter_struct);
300 while (dbus_message_iter_get_arg_type(&iter_struct) ==
302 dbus_message_iter_recurse(&iter_struct, &entry);
304 dbus_message_iter_get_basic(&entry, &name);
305 dbus_message_iter_next(&entry);
306 dbus_message_iter_get_basic(&entry, &tel);
307 dbus_message_iter_next(&entry);
308 dbus_message_iter_get_basic(&entry, &handle);
311 DBG("[handle:%d name:%s tel:%s]\n", handle, name, tel);
314 snprintf(id, sizeof(id), "%d.vcf", handle);
316 data->entry_cb(id, handle, name, NULL, tel,
319 dbus_message_iter_next(&iter_struct);
322 dbus_message_iter_next(&iter);
323 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32) {
324 dbus_message_iter_get_basic(&iter, &new_missed_call);
327 DBG("new_missed_call %d\n", new_missed_call);
329 #ifdef __TIZEN_PATCH__
330 data->ready_cb(data->user_data, new_missed_call);
332 data->ready_cb(data->user_data);
333 #endif /* __TIZEN_PATCH__ */
335 dbus_message_unref(reply);
338 static void get_phonebook_entry_reply(DBusPendingCall *call, void *user_data)
340 DBusMessage *reply = dbus_pending_call_steal_reply(call);
341 struct phonebook_data *s_data = user_data;
343 const char *phonebook_entry;
346 dbus_pending_call_unref(s_data->call);
350 DBG("Reply Error\n");
354 dbus_error_init(&derr);
355 if (dbus_set_error_from_message(&derr, reply)) {
356 error("Replied with an error: %s, %s", derr.name, derr.message);
357 dbus_error_free(&derr);
359 dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING,
360 &phonebook_entry, DBUS_TYPE_INVALID);
361 DBG("phonebook_entry:[%s]\n", phonebook_entry);
364 s_data->cb(phonebook_entry, strlen(phonebook_entry), 1, 0, TRUE,
367 dbus_message_unref(reply);
370 static gboolean clear_signal(DBusConnection *conn, DBusMessage *msg,
373 struct phonebook_session *session;
375 if (user_data == NULL)
381 session->clear_cb(session->user_data);
383 g_dbus_remove_watch(session->connection, session->clear_id);
384 session->clear_id = 0;
389 static gboolean phonebook_folder_list_init(struct phonebook_session *session)
391 DBusMessage *message;
394 DBusMessageIter iter;
395 DBusMessageIter recurse_iter;
399 if (session->connection == NULL) {
400 session->connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM,
404 if (session->connection == NULL) {
405 DBG("Can't get on s bus");
409 message = dbus_message_new_method_call(PHONEBOOK_DESTINATION,
412 QUERY_GET_PHONEBOOK_FOLDER_LIST);
414 if (message == NULL) {
415 DBG("Can't allocate dbus message");
419 dbus_error_init(&error);
421 reply = dbus_connection_send_with_reply_and_block(session->connection,
422 message, -1, &error);
425 if (dbus_error_is_set(&error) == TRUE) {
426 DBG("%s", error.message);
427 dbus_error_free(&error);
429 DBG("Failed to get contacts");
431 dbus_message_unref(message);
435 dbus_message_iter_init(reply, &iter);
437 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
438 dbus_message_unref(message);
439 dbus_message_unref(reply);
444 g_ptr_array_free(folder_list, TRUE);
448 folder_list = g_ptr_array_new();
450 dbus_message_iter_recurse(&iter, &recurse_iter);
452 while (dbus_message_iter_get_arg_type(&recurse_iter)
453 == DBUS_TYPE_STRING) {
456 dbus_message_iter_get_basic(&recurse_iter, &str);
457 DBG("folder list %s\n", str);
458 g_ptr_array_add(folder_list, g_strdup(str));
460 dbus_message_iter_next(&recurse_iter);
463 dbus_message_unref(message);
464 dbus_message_unref(reply);
468 int phonebook_init(void)
473 void phonebook_exit(void)
477 int phonebook_connect(void **user_data)
479 struct phonebook_session *session;
484 session = g_new0(struct phonebook_session, 1);
486 *user_data = session;
488 ret = phonebook_folder_list_init(session);
496 void phonebook_disconnect(void *user_data)
498 struct phonebook_session *session;
499 DBusMessage *message;
504 g_ptr_array_free(folder_list, TRUE);
508 if (!session->connection) {
514 if (session->clear_id)
515 g_dbus_remove_watch(session->connection, session->clear_id);
517 message = dbus_message_new_method_call(PHONEBOOK_DESTINATION,
520 QUERY_DESTROY_AGENT);
523 if (dbus_connection_send(session->connection, message,
525 error("Could not send dbus message");
527 dbus_message_unref(message);
530 dbus_connection_unref(session->connection);
534 char *phonebook_set_folder(const char *current_folder,
535 const char *new_folder, uint8_t flags, int *err)
537 char *tmp1, *tmp2, *base, *path = NULL;
538 gboolean root, child;
542 root = (g_strcmp0("/", current_folder) == 0);
543 child = (new_folder && strlen(new_folder) != 0);
547 /* Go back to root */
549 path = g_strdup("/");
553 path = g_build_filename(current_folder, new_folder, NULL);
559 path = g_strdup("/");
564 * Removing one level of the current folder. Current folder
565 * contains AT LEAST one level since it is not at root folder.
566 * Use glib utility functions to handle invalid chars in the
567 * folder path properly.
569 tmp1 = g_path_get_basename(current_folder);
570 tmp2 = g_strrstr(current_folder, tmp1);
571 len = tmp2 - (current_folder + 1);
576 base = g_strdup("/");
578 base = g_strndup(current_folder, len);
580 /* Return: one level only */
586 path = g_build_filename(base, new_folder, NULL);
596 if (path && !folder_is_valid(path, FALSE))
607 DBG("path : %s\n", path);
612 void phonebook_req_finalize(void *request)
614 struct phonebook_data *data = request;
622 dbus_pending_call_cancel(data->call);
623 dbus_pending_call_unref(data->call);
625 g_free(data->req_name);
629 void *phonebook_pull(const char *name, const struct apparam_field *params,
630 phonebook_cb cb, void *user_data, int *err)
632 struct phonebook_data *data;
635 DBG("name %s", name);
637 if (!g_str_has_suffix(name, ".vcf")) {
644 folder = g_strndup(name, strlen(name) - 4);
646 if (!folder_is_valid(folder, TRUE)) {
656 data = g_new0(struct phonebook_data, 1);
657 data->params = params;
658 data->user_data = user_data;
660 data->req_name = g_strdup(name);
668 int phonebook_pull_read(void *request)
670 struct phonebook_data *data = request;
672 DBG("name %s", data->req_name);
674 if (data->params->maxlistcount == 0) {
675 data->call = phonebook_request(data,
676 QUERY_GET_PHONEBOOK_SIZE,
677 get_phonebook_size_reply,
678 DBUS_TYPE_STRING, &data->req_name,
683 data->call = phonebook_request(data,
686 DBUS_TYPE_STRING, &data->req_name,
687 DBUS_TYPE_UINT64, &data->params->filter,
688 DBUS_TYPE_BYTE, &data->params->format,
689 DBUS_TYPE_UINT16, &data->params->maxlistcount,
690 DBUS_TYPE_UINT16, &data->params->liststartoffset,
696 void *phonebook_get_entry(const char *folder, const char *id,
697 const struct apparam_field *params, phonebook_cb cb,
698 void *user_data, int *err)
700 struct phonebook_data *data;
703 if (!g_str_has_suffix(id, ".vcf")) {
710 if (!folder_is_valid(folder, TRUE)) {
717 DBG("folder %s id %s", folder, id);
719 data = g_new0(struct phonebook_data, 1);
720 data->params = params;
721 data->user_data = user_data;
724 data->call = phonebook_request(data,
725 QUERY_GET_PHONEBOOK_ENTRY,
726 get_phonebook_entry_reply,
727 DBUS_TYPE_STRING, &folder,
728 DBUS_TYPE_STRING, &id,
729 DBUS_TYPE_UINT64, &data->params->filter,
730 DBUS_TYPE_BYTE, &data->params->format,
746 void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
747 phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
749 struct phonebook_data *data;
751 if (!folder_is_valid(name, TRUE)) {
758 DBG("name %s", name);
760 data = g_new0(struct phonebook_data, 1);
761 data->user_data = user_data;
762 data->entry_cb = entry_cb;
763 data->ready_cb = ready_cb;
765 data->call = phonebook_request(data,
766 QUERY_GET_PHONEBOOK_LIST,
767 get_phonebook_list_reply,
768 DBUS_TYPE_STRING, &name,
784 void phonebook_set_cache_notification(void *session,
785 phonebook_cache_clear_cb clear_cb,
788 struct phonebook_session *s = session;
791 s->clear_cb = clear_cb;
793 if (s->connection == NULL) {
794 s->connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM,
797 if (s->connection == NULL) {
798 error("Can't get on s bus");
803 s->user_data = user_data;
806 g_dbus_remove_watch(s->connection, s->clear_id);
810 s->clear_id = g_dbus_add_signal_watch(s->connection,
811 NULL, PHONEBOOK_PATH, PHONEBOOK_INTERFACE,
812 "clear", clear_signal,