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_SIZE "GetPhonebookSize"
53 #define QUERY_GET_PHONEBOOK "GetPhonebook"
54 #define QUERY_GET_PHONEBOOK_LIST "GetPhonebookList"
55 #define QUERY_GET_PHONEBOOK_ENTRY "GetPhonebookEntry"
57 struct phonebook_data {
59 DBusPendingCallNotifyFunction reply_cb;
61 const struct apparam_field *params;
63 phonebook_entry_cb entry_cb;
64 phonebook_cache_ready_cb ready_cb;
69 struct phonebook_session {
70 DBusConnection *connection;
71 phonebook_cache_clear_cb clear_cb;
72 unsigned int clear_id;
77 static gboolean folder_is_valid(const char *folder)
82 if (g_str_equal(folder, "/"))
84 else if (g_str_equal(folder, "/telecom"))
86 else if (g_str_equal(folder, "/telecom/pb"))
88 else if (g_str_equal(folder, "/telecom/ich"))
90 else if (g_str_equal(folder, "/telecom/och"))
92 else if (g_str_equal(folder, "/telecom/mch"))
94 else if (g_str_equal(folder, "/telecom/cch"))
100 static gboolean phonebook_request(struct phonebook_data *data,
102 DBusPendingCallNotifyFunction function,
106 DBusConnection *connection;
107 DBusPendingCall *call;
108 DBusMessage *message;
115 error("Can't get method name");
119 connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
121 error("Can't get on session bus");
125 message = dbus_message_new_method_call(PHONEBOOK_DESTINATION,
130 dbus_connection_unref(connection);
131 error("Can't Allocate new message");
135 va_start(args, first_arg_type);
136 dbus_message_append_args_valist(message, first_arg_type, args);
139 if (dbus_connection_send_with_reply(connection, message, &call, -1) == FALSE) {
140 dbus_message_unref(message);
141 dbus_connection_unref(connection);
144 dbus_pending_call_set_notify(call, function, data, NULL);
146 dbus_pending_call_unref(call);
147 dbus_message_unref(message);
148 dbus_connection_unref(connection);
153 static void get_phonebook_size_reply(DBusPendingCall *call, void *user_data)
155 DBusMessage *reply = dbus_pending_call_steal_reply(call);
156 struct phonebook_data *s_data = user_data;
158 uint32_t phonebook_size;
163 DBG("Reply Error\n");
167 dbus_error_init(&derr);
168 if (dbus_set_error_from_message(&derr, reply)) {
169 error("Replied with an error: %s, %s", derr.name, derr.message);
170 dbus_error_free(&derr);
173 dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32,
174 &phonebook_size, DBUS_TYPE_INVALID);
175 DBG("phonebooksize:%d\n", phonebook_size);
178 s_data->cb(NULL, 0, phonebook_size, 0, TRUE, s_data->user_data);
180 dbus_message_unref(reply);
183 static void get_phonebook_reply(DBusPendingCall *call, void *user_data)
185 DBusMessage *reply = dbus_pending_call_steal_reply(call);
186 struct phonebook_data *s_data = user_data;
190 guint new_missed_call = 0;
197 DBG("Reply Error\n");
201 buffer = g_string_new("");
203 dbus_error_init(&derr);
204 if (dbus_set_error_from_message(&derr, reply)) {
205 error("Replied with an error: %s, %s", derr.name, derr.message);
206 dbus_error_free(&derr);
208 DBusMessageIter iter;
210 dbus_message_iter_init(reply, &iter);
212 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
213 DBusMessageIter recurse_iter;
215 dbus_message_iter_recurse(&iter, &recurse_iter);
216 while (dbus_message_iter_get_arg_type(&recurse_iter) == DBUS_TYPE_STRING) {
219 dbus_message_iter_get_basic(&recurse_iter, &str);
220 dbus_message_iter_next(&recurse_iter);
222 g_string_append(buffer, str);
224 DBG("str:\n%s\n", str);
228 dbus_message_iter_next(&iter);
231 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT16)
232 dbus_message_iter_get_basic(&iter, &new_missed_call);
234 DBG("new_missed_call %d\n", new_missed_call);
237 s_data->cb(buffer->str, buffer->len, count, new_missed_call, 1, s_data->user_data);
239 g_string_free(buffer, TRUE);
240 dbus_message_unref(reply);
244 static void get_phonebook_list_reply(DBusPendingCall *call, void *user_data)
246 DBusMessage *reply = dbus_pending_call_steal_reply(call);
247 DBusMessageIter iter, iter_struct, entry;
248 struct phonebook_data *data = user_data;
251 const char *name = NULL;
252 const char *tel = NULL;
256 DBG("Reply Error\n");
260 dbus_error_init(&derr);
261 if (dbus_set_error_from_message(&derr, reply)) {
262 error("Replied with an error: %s, %s", derr.name, derr.message);
263 dbus_error_free(&derr);
266 dbus_message_iter_init(reply, &iter);
268 dbus_message_iter_recurse(&iter, &iter_struct);
270 while (dbus_message_iter_get_arg_type(&iter_struct) ==
272 dbus_message_iter_recurse(&iter_struct, &entry);
274 dbus_message_iter_get_basic(&entry, &name);
275 dbus_message_iter_next(&entry);
276 dbus_message_iter_get_basic(&entry, &tel);
277 dbus_message_iter_next(&entry);
278 dbus_message_iter_get_basic(&entry, &handle);
281 DBG("[handle:%d name:%s tel:%s]\n", handle, name, tel);
284 snprintf(id, sizeof(id), "%d.vcf", handle);
286 data->entry_cb(id, handle, name, NULL, tel,
289 dbus_message_iter_next(&iter_struct);
293 data->ready_cb(data->user_data);
295 dbus_message_unref(reply);
298 static void get_phonebook_entry_reply(DBusPendingCall *call, void *user_data)
300 DBusMessage *reply = dbus_pending_call_steal_reply(call);
301 struct phonebook_data *s_data = user_data;
303 const char *phonebook_entry;
308 DBG("Reply Error\n");
312 dbus_error_init(&derr);
313 if (dbus_set_error_from_message(&derr, reply)) {
314 error("Replied with an error: %s, %s", derr.name, derr.message);
315 dbus_error_free(&derr);
317 dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING,
318 &phonebook_entry, DBUS_TYPE_INVALID);
319 DBG("phonebook_entry:[%s]\n", phonebook_entry);
322 s_data->cb(phonebook_entry, strlen(phonebook_entry), 1, 0, TRUE,
325 dbus_message_unref(reply);
328 static gboolean get_sim_phonebook_reply(void *user_data)
330 struct phonebook_data *s_data = user_data;
331 uint32_t phonebook_size = 0;
336 /* We don't support phonebook of SIM
338 s_data->cb(NULL, 0, phonebook_size, 0, lastpart, s_data->user_data);
343 static gboolean clear_signal(DBusConnection *conn, DBusMessage *msg,
346 struct phonebook_session *session;
348 if (user_data == NULL)
354 session->clear_cb(session->user_data);
356 g_dbus_remove_watch(session->connection, session->clear_id);
357 session->clear_id = 0;
363 int phonebook_init(void)
368 void phonebook_exit(void)
372 int phonebook_connect(void **user_data)
374 struct phonebook_session *session;
378 session = g_new0(struct phonebook_session, 1);
380 *user_data = session;
385 void phonebook_disconnect(void *user_data)
387 struct phonebook_session *session;
392 g_dbus_remove_watch(session->connection, session->clear_id);
393 dbus_connection_unref(session->connection);
398 char *phonebook_set_folder(const char *current_folder,
399 const char *new_folder, uint8_t flags, int *err)
401 char *tmp1, *tmp2, *base, *path = NULL;
402 gboolean root, child;
406 root = (g_strcmp0("/", current_folder) == 0);
407 child = (new_folder && strlen(new_folder) != 0);
411 /* Go back to root */
413 path = g_strdup("/");
417 path = g_build_filename(current_folder, new_folder, NULL);
423 path = g_strdup("/");
428 * Removing one level of the current folder. Current folder
429 * contains AT LEAST one level since it is not at root folder.
430 * Use glib utility functions to handle invalid chars in the
431 * folder path properly.
433 tmp1 = g_path_get_basename(current_folder);
434 tmp2 = g_strrstr(current_folder, tmp1);
435 len = tmp2 - (current_folder + 1);
440 base = g_strdup("/");
442 base = g_strndup(current_folder, len);
444 /* Return: one level only */
450 path = g_build_filename(base, new_folder, NULL);
460 if (path && !folder_is_valid(path))
474 void phonebook_req_finalize(void *request)
476 struct phonebook_data *data = request;
483 g_free(data->req_name);
487 void *phonebook_pull(const char *name, const struct apparam_field *params,
488 phonebook_cb cb, void *user_data, int *err)
490 struct phonebook_data *data;
492 DBG("name %s", name);
494 if (!g_str_has_suffix(name, ".vcf")) {
495 DBG("invaild request");
501 data = g_new0(struct phonebook_data, 1);
502 data->params = params;
503 data->user_data = user_data;
505 data->req_name = g_strdup(name);
513 int phonebook_pull_read(void *request)
515 struct phonebook_data *data = request;
517 DBG("name %s", data->req_name);
519 if (data->params->maxlistcount == 0) {
520 phonebook_request(data,
521 QUERY_GET_PHONEBOOK_SIZE,
522 get_phonebook_size_reply,
523 DBUS_TYPE_STRING, &data->req_name,
528 if (g_strcmp0(data->req_name, "/SIM1/telecom/pb.vcf") == 0) {
529 g_idle_add(get_sim_phonebook_reply, data);
533 phonebook_request(data,
536 DBUS_TYPE_STRING, &data->req_name,
537 DBUS_TYPE_UINT64, &data->params->filter,
538 DBUS_TYPE_BYTE, &data->params->format,
539 DBUS_TYPE_UINT16, &data->params->maxlistcount,
540 DBUS_TYPE_UINT16, &data->params->liststartoffset,
546 void *phonebook_get_entry(const char *folder, const char *id,
547 const struct apparam_field *params, phonebook_cb cb,
548 void *user_data, int *err)
550 struct phonebook_data *data;
552 if (!g_str_has_suffix(id, ".vcf")) {
553 DBG("invaild request");
558 DBG("folder %s id %s", folder, id);
560 data = g_new0(struct phonebook_data, 1);
561 data->params = params;
562 data->user_data = user_data;
565 phonebook_request(data,
566 QUERY_GET_PHONEBOOK_ENTRY,
567 get_phonebook_entry_reply,
568 DBUS_TYPE_STRING, &folder,
569 DBUS_TYPE_STRING, &id,
570 DBUS_TYPE_UINT64, &data->params->filter,
571 DBUS_TYPE_BYTE, &data->params->format,
577 void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
578 phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
580 struct phonebook_data *data;
581 gboolean req = FALSE;
583 DBG("name %s", name);
585 data = g_new0(struct phonebook_data, 1);
586 data->user_data = user_data;
587 data->entry_cb = entry_cb;
588 data->ready_cb = ready_cb;
590 req = phonebook_request(data,
591 QUERY_GET_PHONEBOOK_LIST,
592 get_phonebook_list_reply,
593 DBUS_TYPE_STRING, &name,
606 void phonebook_set_cache_notification(void *session,
607 phonebook_cache_clear_cb clear_cb,
610 struct phonebook_session *s = session;
613 s->clear_cb = clear_cb;
615 if (s->connection == NULL) {
616 s->connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM,
619 if (s->connection == NULL) {
620 error("Can't get on s bus");
625 s->user_data = user_data;
628 g_dbus_remove_watch(s->connection, s->clear_id);
632 s->clear_id = g_dbus_add_signal_watch(s->connection,
633 NULL, PHONEBOOK_PATH, PHONEBOOK_INTERFACE,
634 "clear", clear_signal,