From 62cdab63c167a08869e2cb84cc1291b8bd8ee441 Mon Sep 17 00:00:00 2001 From: Wu zheng Date: Wed, 23 Oct 2013 11:12:41 +0800 Subject: [PATCH] Add phonebook TIZEN driver Change-Id: Ica8125ccf9def4ae26fe322488bdf100e64ba4d8 --- Makefile.obexd | 2 +- obexd/plugins/phonebook-tizen.c | 574 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 575 insertions(+), 1 deletion(-) create mode 100644 obexd/plugins/phonebook-tizen.c diff --git a/Makefile.obexd b/Makefile.obexd index 326562a..62186bd 100644 --- a/Makefile.obexd +++ b/Makefile.obexd @@ -40,7 +40,7 @@ obexd_builtin_modules += pbap obexd_builtin_sources += obexd/plugins/pbap.c \ obexd/plugins/vcard.h obexd/plugins/vcard.c \ obexd/plugins/phonebook.h \ - obexd/plugins/phonebook-dummy.c + obexd/plugins/phonebook-tizen.c endif obexd_builtin_modules += mas diff --git a/obexd/plugins/phonebook-tizen.c b/obexd/plugins/phonebook-tizen.c new file mode 100644 index 0000000..0f725f1 --- /dev/null +++ b/obexd/plugins/phonebook-tizen.c @@ -0,0 +1,574 @@ +/* + * OBEX Server + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hocheol Seo + * Girishashok Joshi + * Chanyeol Park + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "phonebook.h" + +#include +#include + +#define PHONEBOOK_DESTINATION "org.bluez.pb_agent" +#define PHONEBOOK_PATH "/org/bluez/pb_agent" +#define PHONEBOOK_INTERFACE "org.bluez.PbAgent" + +#define QUERY_GET_PHONEBOOK_SIZE "GetPhonebookSize" +#define QUERY_GET_PHONEBOOK "GetPhonebook" +#define QUERY_GET_PHONEBOOK_LIST "GetPhonebookList" +#define QUERY_GET_PHONEBOOK_ENTRY "GetPhonebookEntry" + +struct phonebook_data { + phonebook_cb cb; + DBusPendingCallNotifyFunction reply_cb; + void *user_data; + const struct apparam_field *params; + + phonebook_entry_cb entry_cb; + phonebook_cache_ready_cb ready_cb; + + char *req_name; +}; + +struct phonebook_session { + DBusConnection *connection; + unsigned int clear_id; + + void *user_data; +}; + +static gboolean folder_is_valid(const char *folder) +{ + if (folder == NULL) + return FALSE; + + 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 gboolean phonebook_request(struct phonebook_data *data, + const gchar *method, + DBusPendingCallNotifyFunction function, + int first_arg_type, + ...) +{ + DBusConnection *connection; + DBusPendingCall *call; + DBusMessage *message; + + va_list args; + + if (!method) { + error("Can't get method name"); + return FALSE; + } + + DBG("%s\n", method); + + connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL); + if (!connection) { + error("Can't get on session bus"); + return FALSE; + } + + message = dbus_message_new_method_call(PHONEBOOK_DESTINATION, + PHONEBOOK_PATH, + PHONEBOOK_INTERFACE, + method); + if (!message) { + dbus_connection_unref(connection); + error("Can't Allocate new message"); + return FALSE; + } + + va_start(args, first_arg_type); + dbus_message_append_args_valist(message, first_arg_type, args); + va_end(args); + + if (dbus_connection_send_with_reply(connection, message, &call, -1) == + FALSE) { + dbus_message_unref(message); + dbus_connection_unref(connection); + return FALSE; + } + dbus_pending_call_set_notify(call, function, data, NULL); + + dbus_pending_call_unref(call); + dbus_message_unref(message); + dbus_connection_unref(connection); + + return TRUE; +} + +static void get_phonebook_size_reply(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct phonebook_data *s_data = user_data; + DBusError derr; + uint32_t phonebook_size; + + DBG(""); + + if (!reply) { + DBG("Reply Error\n"); + return; + } + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("Replied with an error: %s, %s", derr.name, derr.message); + dbus_error_free(&derr); + phonebook_size = 0; + } else { + dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, + &phonebook_size, DBUS_TYPE_INVALID); + DBG("phonebooksize:%d\n", phonebook_size); + } + + s_data->cb(NULL, 0, phonebook_size, 0, TRUE, s_data->user_data); + + dbus_message_unref(reply); +} + +static void get_phonebook_reply(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct phonebook_data *s_data = user_data; + DBusError derr; + GString *buffer; + + guint new_missed_call = 0; + + uint32_t count = 0; + + DBG(""); + + if (!reply) { + DBG("Reply Error\n"); + return; + } + + buffer = g_string_new(""); + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("Replied with an error: %s, %s", derr.name, derr.message); + dbus_error_free(&derr); + } else { + DBusMessageIter iter; + + dbus_message_iter_init(reply, &iter); + + if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) { + DBusMessageIter recurse_iter; + + dbus_message_iter_recurse(&iter, &recurse_iter); + while (dbus_message_iter_get_arg_type(&recurse_iter) == + DBUS_TYPE_STRING) { + gchar *str; + + dbus_message_iter_get_basic(&recurse_iter, + &str); + dbus_message_iter_next(&recurse_iter); + + g_string_append(buffer, str); + + DBG("str:\n%s\n", str); + + count++; + } + dbus_message_iter_next(&iter); + } + + if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT16) + dbus_message_iter_get_basic(&iter, &new_missed_call); + + DBG("new_missed_call %d\n", new_missed_call); + } + + s_data->cb(buffer->str, buffer->len, count, new_missed_call, 1, + s_data->user_data); + + g_string_free(buffer, TRUE); + dbus_message_unref(reply); +} + + +static void get_phonebook_list_reply(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter, iter_struct, entry; + struct phonebook_data *data = user_data; + DBusError derr; + uint32_t handle = 0; + const char *name = NULL; + const char *tel = NULL; + char id[10]; + + if (!reply) { + DBG("Reply Error\n"); + return; + } + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("Replied with an error: %s, %s", derr.name, derr.message); + dbus_error_free(&derr); + } else { + + dbus_message_iter_init(reply, &iter); + + dbus_message_iter_recurse(&iter, &iter_struct); + + while (dbus_message_iter_get_arg_type(&iter_struct) == + DBUS_TYPE_STRUCT) { + dbus_message_iter_recurse(&iter_struct, &entry); + + dbus_message_iter_get_basic(&entry, &name); + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tel); + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &handle); + + /* + DBG("[handle:%d name:%s tel:%s]\n", handle, name, tel); + */ + + snprintf(id, sizeof(id), "%d.vcf", handle); + + data->entry_cb(id, handle, name, NULL, tel, + data->user_data); + + dbus_message_iter_next(&iter_struct); + } + } + + data->ready_cb(data->user_data); + + dbus_message_unref(reply); +} + +static void get_phonebook_entry_reply(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct phonebook_data *s_data = user_data; + DBusError derr; + const char *phonebook_entry = NULL; + uint32_t phonebook_entry_size = 0; + int vcards = 1; + + DBG(""); + + if (!reply) { + DBG("Reply Error\n"); + return; + } + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + vcards = -1; + } else { + dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, + &phonebook_entry, DBUS_TYPE_INVALID); + if (phonebook_entry) + phonebook_entry_size = strlen(phonebook_entry); + DBG("phonebook_entry:[%s]\n", phonebook_entry); + } + + s_data->cb(phonebook_entry, phonebook_entry_size, vcards, 0, TRUE, + s_data->user_data); + + dbus_message_unref(reply); +} + +static gboolean get_sim_phonebook_reply(void *user_data) +{ + struct phonebook_data *s_data = user_data; + uint32_t phonebook_size = 0; + int lastpart = 1; + + DBG(""); + + /* We don't support phonebook of SIM + * Send dummy data */ + s_data->cb(NULL, 0, phonebook_size, 0, lastpart, s_data->user_data); + + return FALSE; +} + +static gboolean clear_signal(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + return TRUE; +} + + +int phonebook_init(void) +{ + return 0; +} + +void phonebook_exit(void) +{ +} + +char *phonebook_set_folder(const char *current_folder, + const char *new_folder, uint8_t flags, int *err) +{ + char *tmp1, *tmp2, *base, *path = NULL; + gboolean root, child; + int ret = 0; + int 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); + + 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 (path && !folder_is_valid(path)) + ret = -ENOENT; + + if (ret < 0) { + g_free(path); + path = NULL; + } + + if (err) + *err = ret; + + return path; +} + +void phonebook_req_finalize(void *request) +{ + struct phonebook_data *data = request; + + DBG(""); + + if (!data) + return; + + g_free(data->req_name); + g_free(data); +} + +void *phonebook_pull(const char *name, const struct apparam_field *params, + phonebook_cb cb, void *user_data, int *err) +{ + struct phonebook_data *data; + + DBG("name %s", name); + + if (!g_str_has_suffix(name, ".vcf")) { + DBG("invaild request"); + if (err) + *err = -EBADR; + return NULL; + } + + data = g_new0(struct phonebook_data, 1); + data->params = params; + data->user_data = user_data; + data->cb = cb; + data->req_name = g_strdup(name); + + if (err) + *err = 0; + + return data; +} + +int phonebook_pull_read(void *request) +{ + struct phonebook_data *data = request; + + DBG("name %s", data->req_name); + + if (data->params->maxlistcount == 0) { + phonebook_request(data, + QUERY_GET_PHONEBOOK_SIZE, + get_phonebook_size_reply, + DBUS_TYPE_STRING, &data->req_name, + DBUS_TYPE_INVALID); + return 0; + } + + if (g_strcmp0(data->req_name, "/SIM1/telecom/pb.vcf") == 0) { + g_idle_add(get_sim_phonebook_reply, data); + return 0; + } + + phonebook_request(data, + QUERY_GET_PHONEBOOK, + get_phonebook_reply, + DBUS_TYPE_STRING, &data->req_name, + DBUS_TYPE_UINT64, &data->params->filter, + DBUS_TYPE_BYTE, &data->params->format, + DBUS_TYPE_UINT16, &data->params->maxlistcount, + DBUS_TYPE_UINT16, &data->params->liststartoffset, + DBUS_TYPE_INVALID); + + return 0; +} + +void *phonebook_get_entry(const char *folder, const char *id, + const struct apparam_field *params, phonebook_cb cb, + void *user_data, int *err) +{ + struct phonebook_data *data; + + if (!g_str_has_suffix(id, ".vcf")) { + DBG("invaild request"); + if (err) + *err = -EBADR; + return NULL; + } + DBG("folder %s id %s", folder, id); + + data = g_new0(struct phonebook_data, 1); + data->params = params; + data->user_data = user_data; + data->cb = cb; + + phonebook_request(data, + QUERY_GET_PHONEBOOK_ENTRY, + get_phonebook_entry_reply, + DBUS_TYPE_STRING, &folder, + DBUS_TYPE_STRING, &id, + DBUS_TYPE_UINT64, &data->params->filter, + DBUS_TYPE_BYTE, &data->params->format, + DBUS_TYPE_INVALID); + + return data; +} + +void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb, + phonebook_cache_ready_cb ready_cb, void *user_data, int *err) +{ + struct phonebook_data *data; + gboolean req = FALSE; + + DBG("name %s", name); + + data = g_new0(struct phonebook_data, 1); + data->user_data = user_data; + data->entry_cb = entry_cb; + data->ready_cb = ready_cb; + + req = phonebook_request(data, + QUERY_GET_PHONEBOOK_LIST, + get_phonebook_list_reply, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + + if (*err) { + if (req) + *err = 0; + else + *err = -ENOENT; + } + + return data; +} -- 2.7.4