From: Jinkun Jang Date: Tue, 12 Mar 2013 16:47:07 +0000 (+0900) Subject: Tizen 2.1 base X-Git-Tag: 2.1b_release~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8a5ef20b9cdfbd223f917bed8dadfccadd272125;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-agent.git Tizen 2.1 base --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..46d1687 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Jinmin Jung +DoHyun Pyun diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5836600 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +ADD_SUBDIRECTORY(map-agent) + +ADD_SUBDIRECTORY(pb-agent) + +ADD_SUBDIRECTORY(hfp-agent) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..43e91eb --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/bluetooth-agent.manifest b/bluetooth-agent.manifest new file mode 100644 index 0000000..839dfd4 --- /dev/null +++ b/bluetooth-agent.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/hfp-agent/CMakeLists.txt b/hfp-agent/CMakeLists.txt new file mode 100644 index 0000000..4c47c31 --- /dev/null +++ b/hfp-agent/CMakeLists.txt @@ -0,0 +1,31 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(bluetooth-hfp-agent C) + +SET(SRCS bluetooth-hfp-agent.c) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs_hfp_agent + REQUIRED + dbus-glib-1 vconf appsvc contacts-service2 tapi) + +FOREACH(flag ${pkgs_hfp_agent_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +FIND_PROGRAM(DBUS_BINDING_TOOL NAMES dbus-binding-tool) +EXEC_PROGRAM("${DBUS_BINDING_TOOL}" + ARGS "--prefix=bt_hfp_agent \\ + ${CMAKE_CURRENT_SOURCE_DIR}/hfp_agent.xml \\ + --mode=glib-server \\ + --output=${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_hfp_agent_glue.h") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_hfp_agent_LDFLAGS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.bluez.hfp_agent.service + DESTINATION share/dbus-1/services) diff --git a/hfp-agent/bluetooth-hfp-agent.c b/hfp-agent/bluetooth-hfp-agent.c new file mode 100644 index 0000000..388eb89 --- /dev/null +++ b/hfp-agent/bluetooth-hfp-agent.c @@ -0,0 +1,1859 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "vconf.h" +#include "vconf-keys.h" +#include "contacts.h" +#include "appsvc.h" + +#include "bluetooth-hfp-agent.h" + +static GMainLoop *gmain_loop = NULL; +static DBusGConnection *g_connection = NULL; +static DBusConnection *gconn = NULL; +static gboolean nrec_status = FALSE; + +#define BT_ERROR_INTERNAL "InternalError" +#define BT_ERROR_NOT_AVAILABLE "NotAvailable" +#define BT_ERROR_NOT_CONNECTED "NotConnected" +#define BT_ERROR_BUSY "InProgress" +#define BT_ERROR_INVALID_PARAM "InvalidArguments" +#define BT_ERROR_ALREADY_EXSIST "AlreadyExists" +#define BT_ERROR_ALREADY_CONNECTED "Already Connected" +#define BT_ERROR_NO_MEMORY "No memory" +#define BT_ERROR_I_O_ERROR "I/O error" +#define BT_ERROR_OPERATION_NOT_AVAILABLE "Operation currently not available" +#define BT_ERROR_BATTERY "Battery error " +#define BT_ERROR_SIGNAL "Signal error" +#define BT_ERROR_NO_CALL_LOG "No Call log" +#define BT_ERROR_INVLAID_DTMF "Invalid dtmf" + +#define BLUEZ_SERVICE_NAME "org.bluez" +#define TELEPHONY_CSD_INTERFACE "org.tizen.telephony.csd" +#define TELEPHONY_CSD_OBJECT_PATH "/org/tizen/csd" +#define TELEPHONY_APP_INTERFACE "org.tizen.csd.Call.Instance" + +#define BT_HFP_AGENT_SET_PROPERTY "SetProperty" + +#define BT_HFP_AGENT_OBJECT "/org/bluez/agent/hfp_agent" +#define BT_HFP_AGENT_INTERFACE "org.bluez.hfp_agent" + +#define BT_SIGNAL_ARRAY_MAX 2 + +/* AT+CSQ : Returns received signal strength indication. + Command response: +CSQ: , + is not supported and has a constant value of 99, included for compatibility reasons. +*/ +#define BT_SIGNAL_QUALITY_BER 99 + +/*Length of the string used to send telephone number to app-svc + format: tel: +*/ +#define BT_MAX_TEL_NUM_STRING 20 + +typedef struct { + GObject parent; +} BtHfpAgent; + +typedef struct { + GObjectClass parent; +} BtHfpAgentClass; + +GType bt_hfp_agent_get_type(void); + +#define BT_HFP_TYPE_AGENT (bt_hfp_agent_get_type()) + +#define BT_HFP_AGENT(object)(G_TYPE_CHECK_INSTANCE_CAST((object), \ + BT_HFP_TYPE_AGENT , BtHfpAgent)) + +#define BT_HFP_AGENT_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST((klass), \ + BT_HFP_TYPE_AGENT , BtHfpAgentClass)) + +#define BT_IS_HFP_AGENT(object)(G_TYPE_CHECK_INSTANCE_TYPE((object), \ + BT_HFP_TYPE_AGENT)) + +#define BT_IS_HFP_AGENT_CLASS(klass)(G_TYPE_CHECK_CLASS_TYPE((klass), \ + BT_HFP_TYPE_AGENT)) + +#define BT_HFP_AGENT_GET_CLASS(obj)(G_TYPE_INSTANCE_GET_CLASS((obj), \ + BT_HFP_TYPE_AGENT , BtHfpAgentClass)) + +G_DEFINE_TYPE(BtHfpAgent, bt_hfp_agent, G_TYPE_OBJECT) + +static gboolean bt_hfp_agent_register_application(BtHfpAgent *agent, + const gchar *path, DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_unregister_application(BtHfpAgent *agent, + const gchar *path, DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_incoming_call(BtHfpAgent *agent, const gchar *path, + const gchar *number, gint call_id, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_outgoing_call(BtHfpAgent *agent, const gchar *path, + const gchar *number, gint call_id, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_change_call_status(BtHfpAgent *agent, + const gchar *path, gint status, gint call_id, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_answer_call(BtHfpAgent *agent, unsigned int call_id, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_release_call(BtHfpAgent *agent, unsigned int call_id, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_reject_call(BtHfpAgent *agent, unsigned int call_id, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_threeway_call(BtHfpAgent *agent, gint call_id, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_dial_last_num(BtHfpAgent *agent, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_dial_num(BtHfpAgent *agent, + const gchar *number, guint flags, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_dial_memory(BtHfpAgent *agent, gint location, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_send_dtmf(BtHfpAgent *agent, const gchar *dtmf, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_voice_dial(BtHfpAgent *agent, gboolean activate, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_get_battery_status(BtHfpAgent *object, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_get_signal_quality(BtHfpAgent *object, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_get_properties(BtHfpAgent *agent, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_get_operator_name(BtHfpAgent *object, + DBusGMethodInvocation *context); + +static gboolean bt_hfp_agent_nrec_status(BtHfpAgent *agent, gboolean status, + DBusGMethodInvocation *context); + +#include "bluetooth_hfp_agent_glue.h" + +static void bt_hfp_agent_init(BtHfpAgent *obj) +{ + DBG("+\n"); + + g_assert(obj != NULL); +} + +static void bt_hfp_agent_finalize(GObject *obj) +{ + DBG("+\n"); + + G_OBJECT_CLASS(bt_hfp_agent_parent_class)->finalize(obj); +} + +static void bt_hfp_agent_class_init(BtHfpAgentClass *klass) +{ + DBG("+\n"); + + GObjectClass *object_class = (GObjectClass *)klass; + + g_assert(klass != NULL); + + object_class->finalize = bt_hfp_agent_finalize; + + dbus_g_object_type_install_info(BT_HFP_TYPE_AGENT, + &dbus_glib_bt_hfp_agent_object_info); +} + +static GQuark __bt_hfp_agent_error_quark(void) +{ + DBG("+\n"); + + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string("agent"); + + return quark; +} + +static GError *__bt_hfp_agent_set_error(bt_hfp_agent_error_t error) +{ + DBG("+\n"); + + switch (error) { + case BT_HFP_AGENT_ERROR_NOT_AVAILABLE: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_NOT_AVAILABLE); + case BT_HFP_AGENT_ERROR_NOT_CONNECTED: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_NOT_CONNECTED); + case BT_HFP_AGENT_ERROR_BUSY: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_BUSY); + case BT_HFP_AGENT_ERROR_INVALID_PARAM: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_INVALID_PARAM); + case BT_HFP_AGENT_ERROR_ALREADY_EXSIST: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_ALREADY_EXSIST); + case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_ALREADY_CONNECTED); + case BT_HFP_AGENT_ERROR_NO_MEMORY: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_NO_MEMORY); + case BT_HFP_AGENT_ERROR_I_O_ERROR: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_I_O_ERROR); + case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_OPERATION_NOT_AVAILABLE); + case BT_HFP_AGENT_ERROR_BATTERY_STATUS: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_BATTERY); + case BT_HFP_AGENT_ERROR_SIGNAL_STATUS: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_SIGNAL); + case BT_HFP_AGENT_ERROR_NO_CALL_LOGS: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_NO_CALL_LOG); + case BT_HFP_AGENT_ERROR_INTERNAL: + default: + return g_error_new(BT_HFP_AGENT_ERROR, error, + BT_ERROR_INTERNAL); + } +} + +static int __bt_hfp_agent_get_error(const char *error_message) +{ + if (error_message == NULL) { + DBG("Error message NULL\n"); + return BT_HFP_AGENT_ERROR_INTERNAL; + } + + DBG("Error message = %s \n", error_message); + + if (g_strcmp0(error_message, BT_ERROR_NOT_AVAILABLE) == 0) + return BT_HFP_AGENT_ERROR_NOT_AVAILABLE; + else if (g_strcmp0(error_message, BT_ERROR_NOT_CONNECTED) == 0) + return BT_HFP_AGENT_ERROR_NOT_CONNECTED; + else if (g_strcmp0(error_message, BT_ERROR_BUSY) == 0) + return BT_HFP_AGENT_ERROR_BUSY; + else if (g_strcmp0(error_message, BT_ERROR_INVALID_PARAM) == 0) + return BT_HFP_AGENT_ERROR_INVALID_PARAM; + else if (g_strcmp0(error_message, BT_ERROR_ALREADY_EXSIST) == 0) + return BT_HFP_AGENT_ERROR_ALREADY_EXSIST; + else if (g_strcmp0(error_message, BT_ERROR_ALREADY_CONNECTED) == 0) + return BT_HFP_AGENT_ERROR_ALREADY_CONNECTED; + else if (g_strcmp0(error_message, BT_ERROR_NO_MEMORY) == 0) + return BT_HFP_AGENT_ERROR_NO_MEMORY; + else if (g_strcmp0(error_message, BT_ERROR_I_O_ERROR) == 0) + return BT_HFP_AGENT_ERROR_I_O_ERROR; + else if (g_strcmp0(error_message, + BT_ERROR_OPERATION_NOT_AVAILABLE) == 0) + return BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE; + else if (g_strcmp0(error_message, BT_ERROR_INVLAID_DTMF) == 0) + return BT_HFP_AGENT_ERROR_INVALID_DTMF; + else + return BT_HFP_AGENT_ERROR_INTERNAL; +} + +static int __bt_hfp_agent_dbus_method_send(const char *service, + const char *path, const char *interface, + const char *method, gboolean response, + int type, ...) +{ + DBusMessage *msg; + DBusMessage *reply; + DBusError err; + va_list args; + int error; + + DBG("__bt_hfp_agent_dbus_method_send +\n"); + + msg = dbus_message_new_method_call(service, path, interface, + method); + if (!msg) { + DBG("Unable to allocate new D-Bus %s message \n", method); + return BT_HFP_AGENT_ERROR_INTERNAL; + } + + va_start(args, type); + + if (!dbus_message_append_args_valist(msg, type, args)) { + dbus_message_unref(msg); + va_end(args); + return BT_HFP_AGENT_ERROR_INTERNAL; + } + + va_end(args); + + dbus_error_init(&err); + + if (response) { + reply = dbus_connection_send_with_reply_and_block(gconn, + msg, -1, &err); + dbus_message_unref(msg); + + if (!reply) { + DBG("Error returned in method call\n"); + if (dbus_error_is_set(&err)) { + error = __bt_hfp_agent_get_error(err.message); + dbus_error_free(&err); + return error; + } else { + DBG("Error is not set\n"); + return BT_HFP_AGENT_ERROR_INTERNAL; + } + } + dbus_message_unref(reply); + } else { + dbus_connection_send(gconn, msg, NULL); + dbus_message_unref(msg); + } + + DBG("__bt_hfp_agent_dbus_method_send -\n"); + + return BT_HFP_AGENT_ERROR_NONE; +} + +static gboolean bt_hfp_agent_register_application(BtHfpAgent *agent, + const gchar *path, DBusGMethodInvocation *context) +{ + gboolean flag = TRUE; + char *sender; + GError *error; + int ret; + + DBG("bt_hfp_agent_register_application + \n"); + + if (path == NULL) { + DBG("Invalid Argument path\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s\n", path); + + sender = dbus_g_method_get_sender(context); + + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(BLUEZ_SERVICE_NAME, + TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + "RegisterTelephonyAgent", TRUE, + DBUS_TYPE_BOOLEAN, &flag, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &sender, DBUS_TYPE_INVALID); + g_free(sender); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + + DBG("bt_hfp_agent_register_application - \n"); + return TRUE; +} + +static gboolean bt_hfp_agent_unregister_application(BtHfpAgent *agent, + const gchar *path, DBusGMethodInvocation *context) +{ + gboolean flag = FALSE; + char *sender; + GError *error; + int ret; + + DBG("bt_hfp_agent_unregister_application + \n"); + + if (path == NULL) { + DBG("Invalid Argument path\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s \n", path); + + sender = dbus_g_method_get_sender(context); + + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(BLUEZ_SERVICE_NAME, + TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + "RegisterTelephonyAgent", TRUE, + DBUS_TYPE_BOOLEAN, &flag, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &sender, DBUS_TYPE_INVALID); + g_free(sender); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + + DBG("bt_hfp_agent_unregister_application - \n"); + return TRUE; +} + +static gboolean bt_hfp_agent_incoming_call(BtHfpAgent *agent, const gchar *path, + const gchar *number, gint call_id, + DBusGMethodInvocation *context) +{ + GError *error; + char *sender; + int ret; + + DBG("bt_hfp_agent_incoming_call + \n"); + + if (path == NULL || number == NULL) { + DBG("Invalid Arguments\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s\n", path); + DBG("Phone number = %s\n", number); + DBG("Call id = %d\n", call_id); + + sender = dbus_g_method_get_sender(context); + + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(BLUEZ_SERVICE_NAME, + TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + "Incoming", TRUE, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &number, + DBUS_TYPE_UINT32, &call_id, + DBUS_TYPE_STRING, &sender, + DBUS_TYPE_INVALID); + g_free(sender); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + + DBG("bt_hfp_agent_incoming_call - \n"); + return TRUE; +} + +static gboolean bt_hfp_agent_outgoing_call(BtHfpAgent *agent, const gchar *path, + const gchar *number, gint call_id, + DBusGMethodInvocation *context) +{ + GError *error; + char *sender; + int ret; + + DBG("bt_hfp_agent_outgoing_call + \n"); + + if (path == NULL || number == NULL) { + DBG("Invalid Arguments\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s\n", path); + DBG("Phone number = %s\n", number); + DBG("Call id = %d\n", call_id); + + sender = dbus_g_method_get_sender(context); + + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(BLUEZ_SERVICE_NAME, + TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + "Outgoing", TRUE, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &number, + DBUS_TYPE_UINT32, &call_id, + DBUS_TYPE_STRING, &sender, + DBUS_TYPE_INVALID); + g_free(sender); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + + DBG("bt_hfp_agent_outgoing_call - \n"); + return TRUE; +} + +static gboolean bt_hfp_agent_change_call_status(BtHfpAgent *agent, + const gchar *path, gint status, gint call_id, + DBusGMethodInvocation *context) +{ + GError *error; + char *sender; + int ret; + + DBG("bt_hfp_agent_change_call_status + \n"); + + if (path == NULL) { + DBG("Invalid Argument path\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s\n", path); + DBG("Status = %d\n", status); + DBG("Call id = %d\n", call_id); + + sender = dbus_g_method_get_sender(context); + + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(BLUEZ_SERVICE_NAME, + TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + "SetCallStatus", TRUE, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_UINT32, &status, + DBUS_TYPE_UINT32, &call_id, + DBUS_TYPE_STRING, &sender, + DBUS_TYPE_INVALID); + g_free(sender); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + + DBG("bt_hfp_agent_change_call_status - \n"); + return TRUE; +} + +static gboolean bt_hfp_agent_answer_call(BtHfpAgent *agent, unsigned int call_id, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context) +{ + int ret; + GError *error; + DBG("+\n"); + + if (path == NULL || sender == NULL) { + DBG("Invalid Arguments\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s \n", path); + DBG("Call Id = %d", call_id); + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(sender, + path, TELEPHONY_APP_INTERFACE, + "Answer", FALSE, + DBUS_TYPE_UINT32, &call_id, + DBUS_TYPE_INVALID); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + + DBG("-\n"); + return TRUE; +} + +static gboolean bt_hfp_agent_release_call(BtHfpAgent *agent, unsigned int call_id, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context) +{ + int ret; + GError *error; + DBG("+\n"); + + if (path == NULL || sender == NULL) { + DBG("Invalid Arguments\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s \n", path); + DBG("Call Id = %d", call_id); + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(sender, + path, TELEPHONY_APP_INTERFACE, + "Release", FALSE, + DBUS_TYPE_UINT32, &call_id, + DBUS_TYPE_INVALID); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + DBG("-\n"); + return TRUE; +} + +static gboolean bt_hfp_agent_reject_call(BtHfpAgent *agent, unsigned int call_id, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context) +{ + int ret; + GError *error; + DBG("+\n"); + + if (path == NULL || sender == NULL) { + DBG("Invalid Arguments\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s \n", path); + DBG("Call Id = %d", call_id); + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(sender, + path, TELEPHONY_APP_INTERFACE, + "Reject", FALSE, + DBUS_TYPE_UINT32, &call_id, + DBUS_TYPE_INVALID); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + DBG("-\n"); + return TRUE; +} + +static gboolean bt_hfp_agent_threeway_call(BtHfpAgent *agent, gint value, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context) +{ + int ret; + GError *error; + DBG("+\n"); + + if (path == NULL || sender == NULL) { + DBG("Invalid Arguments\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Application path = %s \n", path); + DBG("Value = %d", value); + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(sender, + path, TELEPHONY_APP_INTERFACE, + "Threeway", TRUE, + DBUS_TYPE_UINT32, &value, + DBUS_TYPE_INVALID); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_g_method_return(context); + DBG("-\n"); + return TRUE; +} + +void __bt_append_entry(DBusMessageIter *iter, + const char *key, int type, void *val) +{ + DBusMessageIter entry; + DBusMessageIter value; + const char *str; + char signal[BT_SIGNAL_ARRAY_MAX] = { type, '\0' }; + + if (type == DBUS_TYPE_STRING) { + str = *((const char **) val); + if (str == NULL) { + return; + } + } + + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + signal, &value); + + dbus_message_iter_append_basic(&value, type, val); + + dbus_message_iter_close_container(&entry, &value); + + dbus_message_iter_close_container(iter, &entry); +} + +static gboolean bt_hfp_agent_get_properties(BtHfpAgent *agent, + DBusGMethodInvocation *context) +{ + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter dict; + GError *error; + + DBG("bt_hfp_agent_get_properties + \n"); + + reply = dbus_g_method_get_reply(context); + if (!reply) { + error = __bt_hfp_agent_set_error(BT_HFP_AGENT_ERROR_INTERNAL); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + dbus_message_iter_init_append(reply, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); + + __bt_append_entry(&dict, "nrec", DBUS_TYPE_BOOLEAN, &nrec_status); + dbus_message_iter_close_container(&iter, &dict); + dbus_g_method_send_reply(context, reply); + DBG("bt_hfp_agent_get_properties - \n"); + return TRUE; +} + +static gboolean __bt_hfp_agent_make_call(const char *number) +{ + bundle *b; + char telnum[BT_MAX_TEL_NUM_STRING]; + + b = bundle_create(); + if (NULL == b) + return FALSE; + + appsvc_set_operation(b, APPSVC_OPERATION_CALL); + snprintf(telnum, sizeof(telnum), "tel:%s", number); + appsvc_set_uri(b, telnum); + appsvc_add_data(b, "ctindex", "-1"); + appsvc_run_service(b, 0, NULL, NULL); + bundle_free(b); + + return TRUE; +} + +static gboolean bt_hfp_agent_dial_last_num(BtHfpAgent *agent, + DBusGMethodInvocation *context) +{ + GError *error; + int error_code = BT_HFP_AGENT_ERROR_NONE; + char *last_number = NULL; + contacts_list_h list = NULL; + contacts_query_h query = NULL; + contacts_filter_h filter = NULL; + contacts_record_h record = NULL; + unsigned int projections[] = { + _contacts_phone_log.address, + }; + + DBG("+ \n"); + + if (contacts_connect2() != CONTACTS_ERROR_NONE) { + ERR(" contacts_connect2 failed \n"); + error = __bt_hfp_agent_set_error(BT_HFP_AGENT_ERROR_INTERNAL); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + contacts_filter_create(_contacts_phone_log._uri, &filter); + + if (filter == NULL) + goto done; + + if (contacts_filter_add_int(filter, _contacts_phone_log.log_type, + CONTACTS_MATCH_EQUAL, + CONTACTS_PLOG_TYPE_VOICE_OUTGOING) != + CONTACTS_ERROR_NONE) { + ERR(" contacts_filter_add_int failed \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR) != + CONTACTS_ERROR_NONE) { + ERR(" contacts_filter_add_operator failed \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_filter_add_int(filter, _contacts_phone_log.log_type, + CONTACTS_MATCH_EQUAL, + CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) != + CONTACTS_ERROR_NONE) { + ERR(" contacts_filter_add_int failed \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + contacts_query_create(_contacts_phone_log._uri, &query); + + if (query == NULL) + goto done; + + contacts_query_set_filter(query, filter); + + if (contacts_query_set_projection(query, projections, + sizeof(projections)/sizeof(unsigned int)) != + CONTACTS_ERROR_NONE) { + ERR(" contacts_query_set_projection failed \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_query_set_sort(query, _contacts_phone_log.log_time, false) != + CONTACTS_ERROR_NONE) { + ERR(" contacts_query_set_sort failed \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_db_get_records_with_query(query, 0, 1, &list) != + CONTACTS_ERROR_NONE) { + ERR(" contacts_db_get_records_with_query failed \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_list_first(list) != CONTACTS_ERROR_NONE) { + ERR(" contacts_list_first failed \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_list_get_current_record_p(list, &record) != + CONTACTS_ERROR_NONE) { + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (record == NULL) + goto done; + + contacts_record_get_str(record, _contacts_phone_log.address, + &last_number); + + if (last_number == NULL) { + ERR("No last number \n"); + error_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS; + goto done; + } + + /*Make Voice call*/ + if (!__bt_hfp_agent_make_call(last_number)) { + ERR("Problem launching application \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + } + + g_free(last_number); + +done: + if (list != NULL) + contacts_list_destroy(list, TRUE); + + if (filter != NULL) + contacts_filter_destroy(filter); + + if (query != NULL) + contacts_query_destroy(query); + + contacts_disconnect2(); + + DBG("-\n"); + + if (error_code == BT_HFP_AGENT_ERROR_NONE) { + dbus_g_method_return(context); + return TRUE; + } else { + error = __bt_hfp_agent_set_error(error_code); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } +} + +static gboolean bt_hfp_agent_dial_num(BtHfpAgent *agent, + const gchar *number, guint flags, + DBusGMethodInvocation *context) +{ + GError *error; + int error_code; + + DBG("+\n"); + + if (number == NULL) { + ERR("Invalid Argument\n"); + error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM; + goto fail; + } + + DBG("Number = %s \n", number); + DBG("flags = %d", flags); + + /*TODO: Make use of flags*/ + + /*Make Voice call*/ + if (!__bt_hfp_agent_make_call(number)) { + ERR("Problem launching application \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto fail; + } + + dbus_g_method_return(context); + + DBG("-\n"); + return TRUE; +fail: + error = __bt_hfp_agent_set_error(error_code); + dbus_g_method_return_error(context, error); + g_error_free(error); + DBG("-\n"); + return FALSE; +} + +static gboolean bt_hfp_agent_dial_memory(BtHfpAgent *agent, gint location, + DBusGMethodInvocation *context) +{ + GError *error; + int error_code = BT_HFP_AGENT_ERROR_NONE; + char *number = NULL; + contacts_filter_h filter = NULL; + contacts_query_h query = NULL; + contacts_list_h list = NULL; + contacts_record_h record = NULL; + unsigned int projections[] = { + _contacts_speeddial.number, + }; + + DBG("+\n"); + + DBG("location = %d \n", location); + + /*Get number from contacts location*/ + if (contacts_connect2() != CONTACTS_ERROR_NONE) { + ERR(" contacts_connect2 failed \n"); + error = __bt_hfp_agent_set_error(BT_HFP_AGENT_ERROR_INTERNAL); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + contacts_filter_create(_contacts_speeddial._uri, &filter); + + if (filter == NULL) + goto done; + + if (contacts_filter_add_int(filter, _contacts_speeddial.speeddial_number, + CONTACTS_MATCH_EQUAL, location) != + CONTACTS_ERROR_NONE) { + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + contacts_query_create(_contacts_speeddial._uri, &query); + + if (query == NULL) + goto done; + + contacts_query_set_filter(query, filter); + + if (contacts_query_set_projection(query, projections, + sizeof(projections)/sizeof(unsigned int)) != + CONTACTS_ERROR_NONE) { + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_db_get_records_with_query(query, 0, 1, &list) != + CONTACTS_ERROR_NONE) { + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_list_first(list) != CONTACTS_ERROR_NONE) { + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (contacts_list_get_current_record_p(list, &record) != + CONTACTS_ERROR_NONE) { + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + goto done; + } + + if (record == NULL) + goto done; + + contacts_record_get_str(record, _contacts_speeddial.number, + &number); + + if (number == NULL) { + ERR("No number at the location \n"); + error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX; + goto done; + } + + DBG("number %s\n", number); + + /*Make Voice call*/ + if (!__bt_hfp_agent_make_call(number)) { + ERR("Problem launching application \n"); + error_code = BT_HFP_AGENT_ERROR_INTERNAL; + } + + g_free(number); +done: + if (list != NULL) + contacts_list_destroy(list, TRUE); + + if (filter != NULL) + contacts_filter_destroy(filter); + + if (query != NULL) + contacts_query_destroy(query); + + contacts_disconnect2(); + + DBG("-\n"); + + if (error_code == BT_HFP_AGENT_ERROR_NONE) { + dbus_g_method_return(context); + return TRUE; + } else { + error = __bt_hfp_agent_set_error(error_code); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } +} + +static gboolean bt_hfp_agent_send_dtmf(BtHfpAgent *agent, const gchar *dtmf, + const gchar *path, const gchar *sender, + DBusGMethodInvocation *context) +{ + GError *error; + int ret; + + DBG("+\n"); + + if (dtmf == NULL || path == NULL || sender == NULL) { + ERR("Invalid Argument\n"); + error = __bt_hfp_agent_set_error( + BT_HFP_AGENT_ERROR_INVALID_PARAM); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("Dtmf = %s \n", dtmf); + DBG("Application path = %s \n", path); + DBG("Sender = %s\n", sender); + + ret = __bt_hfp_agent_dbus_method_send(sender, + path, TELEPHONY_APP_INTERFACE, + "SendDtmf", FALSE, + DBUS_TYPE_STRING, &dtmf, + DBUS_TYPE_INVALID); + + if (ret != BT_HFP_AGENT_ERROR_NONE) { + error = __bt_hfp_agent_set_error(ret); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + /*App Selector code here needed*/ + dbus_g_method_return(context); + + DBG("-\n"); + return TRUE; +} + +static gboolean bt_hfp_agent_voice_dial(BtHfpAgent *agent, gboolean activate, + DBusGMethodInvocation *context) +{ + DBG("+\n"); + + DBG("Activate = %d \n", activate); + + /*App Selector code here needed*/ + dbus_g_method_return(context); + + DBG("-\n"); + return TRUE; +} + +static gboolean bt_hfp_agent_get_battery_status(BtHfpAgent *object, + DBusGMethodInvocation *context) +{ + gint battery_chrg_status; + gint battery_capacity; + GError *error; + + DBG("+\n"); + + if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, + &battery_chrg_status)) { + DBG("VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW failed\n"); + goto fail; + } + + DBG("Status : %d\n", battery_chrg_status); + + if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, + &battery_capacity)) { + DBG("VCONFKEY_SYSMAN_BATTERY_CAPACITY failed\n"); + goto fail; + } + + DBG("Capacity : %d\n", battery_capacity); + + dbus_g_method_return(context, battery_chrg_status, battery_capacity); + DBG("-\n"); + return TRUE; + +fail: + error = __bt_hfp_agent_set_error(BT_HFP_AGENT_ERROR_BATTERY_STATUS); + dbus_g_method_return_error(context, error); + g_error_free(error); + DBG("-\n"); + return FALSE; +} + +static gboolean bt_hfp_agent_get_signal_quality(BtHfpAgent *object, + DBusGMethodInvocation *context) +{ + gint rssi; + GError *error; + + DBG("+\n"); + + if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) { + DBG("VCONFKEY_TELEPHONY_RSSI failed\n"); + goto fail; + } + + DBG("RSSI : %d \n", rssi); + + dbus_g_method_return(context, rssi, BT_SIGNAL_QUALITY_BER); + DBG("-\n"); + return TRUE; +fail: + error = __bt_hfp_agent_set_error(BT_HFP_AGENT_ERROR_SIGNAL_STATUS); + dbus_g_method_return_error(context, error); + g_error_free(error); + DBG("-\n"); + return FALSE; +} + +static gboolean bt_hfp_agent_get_operator_name(BtHfpAgent *object, + DBusGMethodInvocation *context) +{ + char *operator_name; + GError *error; + + DBG(" +\n"); + + operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME); + if (NULL == operator_name) { + DBG("vconf_get_str failed \n"); + error = __bt_hfp_agent_set_error(BT_HFP_AGENT_ERROR_INTERNAL); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } + + DBG("operator_name = [%s] \n", operator_name); + + dbus_g_method_return(context, operator_name); + free(operator_name); + + DBG(" -\n"); + return TRUE; +} + +static gboolean bt_hfp_agent_nrec_status(BtHfpAgent *agent, gboolean status, + DBusGMethodInvocation *context) +{ + DBusMessage *signal; + + DBG("+\n"); + + DBG("NREC status = %d \n", status); + nrec_status = status; + dbus_g_method_return(context); + + /*Emit NREC Status change signal with value*/ + signal = dbus_message_new_signal(BT_HFP_AGENT_OBJECT, + BT_HFP_AGENT_INTERFACE, + "NrecStatusChanged"); + if (!signal) + return FALSE; + + if (!dbus_message_append_args(signal, + DBUS_TYPE_BOOLEAN, &status, + DBUS_TYPE_INVALID)) { + DBG("Signal appending failed\n"); + dbus_message_unref(signal); + return FALSE; + } + + dbus_connection_send(gconn, signal, NULL); + dbus_message_unref(signal); + DBG("-\n"); + return TRUE; +} + +static void __bt_hfp_agent_append_variant(DBusMessageIter *iter, + int type, void *val) +{ + DBusMessageIter value_iter; + const char *variant; + + switch (type) { + case DBUS_TYPE_BOOLEAN: + variant = DBUS_TYPE_BOOLEAN_AS_STRING; + break; + case DBUS_TYPE_STRING: + variant = DBUS_TYPE_STRING_AS_STRING; + break; + case DBUS_TYPE_BYTE: + variant = DBUS_TYPE_BYTE_AS_STRING; + break; + case DBUS_TYPE_UINT16: + variant = DBUS_TYPE_UINT16_AS_STRING; + break; + case DBUS_TYPE_UINT32: + variant = DBUS_TYPE_UINT32_AS_STRING; + break; + case DBUS_TYPE_INT16: + variant = DBUS_TYPE_INT16_AS_STRING; + break; + case DBUS_TYPE_INT32: + variant = DBUS_TYPE_INT32_AS_STRING; + break; + case DBUS_TYPE_OBJECT_PATH: + variant = DBUS_TYPE_OBJECT_PATH_AS_STRING; + break; + default: + variant = DBUS_TYPE_VARIANT_AS_STRING; + break; + } + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, variant, + &value_iter); + dbus_message_iter_append_basic(&value_iter, type, val); + dbus_message_iter_close_container(iter, &value_iter); +} + +static gboolean __bt_hfp_agent_dbus_method_variant_send(const char *path, + const char *interface, const char *method, const char *name, + int type, void *value) +{ + DBusMessage *msg; + DBusMessage *reply; + DBusError err; + DBusMessageIter iter; + + DBG(" +\n"); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE_NAME, + path, interface, method); + + if (!msg) { + DBG("Unable to allocate new D-Bus %s message", method); + return FALSE; + } + + dbus_message_iter_init_append(msg, &iter); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); + + __bt_hfp_agent_append_variant(&iter, type, value); + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(gconn, + msg, -1, &err); + + dbus_message_unref(msg); + + if (!reply) { + DBG("Error returned in method call\n"); + if (dbus_error_is_set(&err)) { + if (err.message != NULL) { + DBG("Error message = %s\n", err.message); + } + dbus_error_free(&err); + } + return FALSE; + } + + dbus_message_unref(reply); + + DBG(" -\n"); + return TRUE; +} + +static gboolean __bt_hfp_agent_send_registration_status_changed( + bt_hfp_agent_network_registration_status_t status) +{ + const char *property = g_strdup("RegistrationChanged"); + + DBG(" +\n"); + + if (!__bt_hfp_agent_dbus_method_variant_send(TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + BT_HFP_AGENT_SET_PROPERTY, + property, DBUS_TYPE_BYTE, &status)) { + DBG("__bt_hfp_agent_dbus_method_variant_send - ERROR\n"); + g_free((void *)property); + return FALSE; + } + DBG(" -\n"); + + g_free((void *)property); + return TRUE; +} + +static gboolean __bt_hfp_agent_send_subscriber_number_changed( + const char *number) +{ + const char *property = g_strdup("SubscriberNumberChanged"); + + DBG(" +\n"); + + if (!__bt_hfp_agent_dbus_method_variant_send(TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + BT_HFP_AGENT_SET_PROPERTY, + property, + DBUS_TYPE_STRING, &number)) { + DBG("__bt_hfp_agent_dbus_method_variant_send - ERROR\n"); + g_free((void *)property); + return FALSE; + } + + DBG(" -\n"); + g_free((void *)property); + return TRUE; +} + +static gboolean __bt_hfp_agent_send_signal_bar_changed(int signal_bar) +{ + const char *property = g_strdup("SignalBarsChanged"); + + DBG(" +\n"); + + if (!__bt_hfp_agent_dbus_method_variant_send(TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + BT_HFP_AGENT_SET_PROPERTY, + property, DBUS_TYPE_INT32, &signal_bar)) { + DBG("__bt_hfp_agent_dbus_method_variant_send - ERROR\n"); + g_free((void *)property); + return FALSE; + } + + g_free((void *)property); + DBG(" -\n"); + return TRUE; +} + +static gboolean __bt_hfp_agent_send_battery_level_changed(int battery_level) +{ + const char *property = g_strdup("BatteryBarsChanged"); + int battery_status; + + DBG(" +\n"); + + /* We need to send battery status ranging from 0-5 */ + if (battery_level < 5) + battery_status = 0; + else if (battery_level >= 100) + battery_status = 5; + else + battery_status = battery_level / 20 + 1; + + if (!__bt_hfp_agent_dbus_method_variant_send(TELEPHONY_CSD_OBJECT_PATH, + TELEPHONY_CSD_INTERFACE, + BT_HFP_AGENT_SET_PROPERTY, + property, + DBUS_TYPE_INT32, &battery_status)) { + DBG("__bt_hfp_agent_dbus_method_variant_send - ERROR\n"); + g_free((void *)property); + return FALSE; + } + + DBG(" -\n"); + g_free((void *)property); + return TRUE; +} + +static void __bt_hfp_agent_send_battery_level(void) +{ + int ret; + int batt; + + DBG(" +\n"); + + ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, &batt); + if (ret != 0) { + DBG("vconf_get_int failed err = %d \n", ret); + return; + } + + DBG("Current battery Level = [%d] \n", batt); + + __bt_hfp_agent_send_battery_level_changed(batt); + + DBG(" -\n"); +} + +static void __bt_hfp_agent_send_signal_status(void) +{ + int ret; + int signal_level; + + DBG(" +\n"); + + ret = vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &signal_level); + if (ret != 0) { + DBG("vconf_get_int failed err = %d \n", ret); + return; + } + + DBG("Current Signal Level = [%d] \n", signal_level); + + __bt_hfp_agent_send_signal_bar_changed(signal_level); + + DBG(" -\n"); +} + +static void __bt_hfp_agent_network_send( int service, int roam_status) +{ + int ret; + bt_hfp_agent_network_registration_status_t network_service; + + DBG(" +\n"); + + switch (service) { + case VCONFKEY_TELEPHONY_SVCTYPE_NONE: + case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC: + case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH: + service = 0; + break; + default: + service = 1; + break; + } + + ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status); + if (ret != 0) { + DBG("Get roaming status failed err = %d\n", ret); + return; + } + + if (roam_status == 0 && service == 1) + network_service = BT_HFP_AGENT_NETWORK_REG_STATUS_HOME; + else if (roam_status == 1 && service == 1) + network_service = BT_HFP_AGENT_NETWORK_REG_STATUS_ROAMING; + else + network_service = BT_HFP_AGENT_NETWORK_REG_STATUS_UNKOWN; + + DBG("Network service = %d\n", network_service); + + __bt_hfp_agent_send_registration_status_changed(network_service); + + DBG(" -\n"); +} + +static void __bt_hfp_agent_send_network_status(void) +{ + int ret; + int roam_status; + int service; + + + DBG(" +\n"); + + ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status); + if (ret != 0) { + DBG("vconf_get_int failed for \n"); + return; + } + + DBG("roam_status = [%d] \n", roam_status); + + ret = vconf_get_int(VCONFKEY_TELEPHONY_SVCTYPE, &service); + if (ret != 0) { + DBG("vconf_get_int failed\n"); + return; + } + + DBG("service = [%d] \n", service); + + __bt_hfp_agent_network_send(service, roam_status); + + DBG(" -\n"); +} + +static void __bt_hfp_agent_send_vconf_values(void) +{ + __bt_hfp_agent_send_battery_level(); + __bt_hfp_agent_send_signal_status(); + __bt_hfp_agent_send_network_status(); +} + +static void __bt_hfp_agent_battery_status_cb(keynode_t *node) +{ + int batt = vconf_keynode_get_int(node); + + DBG(" +\n"); + + DBG("Current Battery Level = [%d] \n", batt); + + __bt_hfp_agent_send_battery_level_changed(batt); + + DBG(" -\n"); +} + +static void __bt_hfp_agent_network_signal_status_cb(keynode_t *node) +{ + int signal_bar = vconf_keynode_get_int(node); + + DBG(" +\n"); + + DBG("Current Signal Level = [%d] \n", signal_bar); + + __bt_hfp_agent_send_signal_bar_changed(signal_bar); + + DBG(" -\n"); +} + +static void __bt_hfp_agent_network_register_status_cb(keynode_t *node) +{ + int service = vconf_keynode_get_int(node); + int roam_status; + int ret; + + DBG(" +\n"); + + DBG("Current Signal Level = [%d] \n", service); + + ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status); + if (ret != 0) { + DBG("Get roaming status failed err = %d\n", ret); + return; + } + + __bt_hfp_agent_network_send(service, roam_status); + + DBG(" -\n"); +} + +static void __bt_hfp_agent_subscribe_vconf_updates(void) +{ + int ret; + + DBG(" +\n"); + + ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY, + (void *)__bt_hfp_agent_battery_status_cb, NULL); + if (0 != ret) { + DBG("Subsrciption to battery status failed err = [%d]\n", ret); + } + + ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI, + (void *)__bt_hfp_agent_network_signal_status_cb, NULL); + if (0 != ret) { + DBG("Subsrciption to netowrk signal failed err = [%d]\n", ret); + } + + ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE, + (void *)__bt_hfp_agent_network_register_status_cb, NULL); + if (0 != ret) { + DBG("Subsrciption to network failed err = [%d]\n", ret); + } + + DBG(" -\n"); +} + +static void __bt_hfp_agent_release_vconf_updates(void) +{ + int ret; + + DBG(" +\n"); + + ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY, + (vconf_callback_fn)__bt_hfp_agent_battery_status_cb); + if (0 != ret) { + DBG("vconf_ignore_key_changed failed\n"); + } + + ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI, + (vconf_callback_fn)__bt_hfp_agent_network_signal_status_cb); + if (0 != ret) { + DBG("vconf_ignore_key_changed failed\n"); + } + + ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE, + (vconf_callback_fn)__bt_hfp_agent_network_register_status_cb); + if (0 != ret) { + DBG("vconf_ignore_key_changed failed\n"); + } + + DBG(" -\n"); +} + +static void __bt_hfp_agent_dbus_init(BtHfpAgent *agent) +{ + GError *error = NULL; + DBusGProxy *bus_proxy = NULL; + guint result; + + g_connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); + if (error != NULL) { + ERR("Failed connection to system bus[%s] \n", error->message); + g_error_free(error); + return; + } + + bus_proxy = dbus_g_proxy_new_for_name(g_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); + if (bus_proxy == NULL) { + ERR("Failed to get a proxy for D-Bus\n"); + return; + } + + if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error, G_TYPE_STRING, + BT_HFP_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, + G_TYPE_UINT, &result, G_TYPE_INVALID)) { + if (error != NULL) { + ERR("RequestName RPC failed[%s]\n", error->message); + g_error_free(error); + } + + g_object_unref(bus_proxy); + return; + } + + DBG("result : %d %d\n", result, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + ERR("Failed to get the primary well-known name.\n"); + g_object_unref(bus_proxy); + return; + } + + g_object_unref(bus_proxy); + + dbus_g_connection_register_g_object(g_connection, + BT_HFP_SERVICE_OBJECT_PATH, G_OBJECT(agent)); + + gconn = dbus_g_connection_get_connection(g_connection); + if (gconn == NULL) { + ERR("Failed to get connection \n"); + return; + } + + __bt_hfp_agent_send_vconf_values(); + __bt_hfp_agent_subscribe_vconf_updates(); +} + +static void __bt_hfp_agent_tel_cb(TapiHandle *handle, + int result, + void *data, + void *user_data) +{ + TelSimMsisdnList_t *number; + gchar *subscriber_number; + + if (data == NULL) + return; + + number = (TelSimMsisdnList_t *)data; + subscriber_number = g_strdup(number->list[0].num); + __bt_hfp_agent_send_subscriber_number_changed(subscriber_number); + g_free(subscriber_number); +} + +static void __bt_hfp_agent_sigterm_handler(int signo) +{ + DBG("+\n"); + + if (gmain_loop) + g_main_loop_quit(gmain_loop); + else + exit(0); + + DBG("-\n"); +} + +int main(void) +{ + TapiHandle *handle; + BtHfpAgent *bt_hfp_obj = NULL; + struct sigaction sa; + int tapi_result; + + g_type_init(); + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = __bt_hfp_agent_sigterm_handler; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + gmain_loop = g_main_loop_new(NULL, FALSE); + + if (gmain_loop == NULL) { + ERR("GMainLoop create failed \n"); + return EXIT_FAILURE; + } + + bt_hfp_obj = g_object_new(BT_HFP_TYPE_AGENT, NULL); + if (bt_hfp_obj == NULL) { + ERR("Failed to create BtHfpAgent instance \n"); + if (gmain_loop) + g_main_loop_unref(gmain_loop); + + return EXIT_FAILURE; + } + + handle = tel_init(NULL); + tapi_result = tel_get_sim_msisdn(handle, __bt_hfp_agent_tel_cb, + bt_hfp_obj); + + if(tapi_result != TAPI_API_SUCCESS) + ERR("Fail to get sim info: %d", tapi_result); + + __bt_hfp_agent_dbus_init(bt_hfp_obj); + + g_main_loop_run(gmain_loop); + + tel_deinit(handle); + + __bt_hfp_agent_release_vconf_updates(); + + if (bt_hfp_obj) { + dbus_g_connection_unregister_g_object(g_connection, + G_OBJECT(bt_hfp_obj)); + g_object_unref(bt_hfp_obj); + } + + if (g_connection) + dbus_g_connection_unref(g_connection); + + if (gmain_loop) + g_main_loop_unref(gmain_loop); + + return 0; +} diff --git a/hfp-agent/bluetooth-hfp-agent.h b/hfp-agent/bluetooth-hfp-agent.h new file mode 100644 index 0000000..ddf8a61 --- /dev/null +++ b/hfp-agent/bluetooth-hfp-agent.h @@ -0,0 +1,73 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#ifndef __DEF_BT_HFP_AGENT_H_ +#define __DEF_BT_HFP_AGENT_H_ + +#include +#include +#include + +#define BT_HFP_AGENT_ERROR (__bt_hfp_agent_error_quark()) + +typedef enum { + BT_HFP_AGENT_NETWORK_REG_STATUS_HOME, + BT_HFP_AGENT_NETWORK_REG_STATUS_ROAMING, + BT_HFP_AGENT_NETWORK_REG_STATUS_OFFLINE, + BT_HFP_AGENT_NETWORK_REG_STATUS_SEARCHING, + BT_HFP_AGENT_NETWORK_REG_STATUS_NO_SIM, + BT_HFP_AGENT_NETWORK_REG_STATUS_POWEROFF, + BT_HFP_AGENT_NETWORK_REG_STATUS_POWERSAFE, + BT_HFP_AGENT_NETWORK_REG_STATUS_NO_COVERAGE, + BT_HFP_AGENT_NETWORK_REG_STATUS_REJECTED, + BT_HFP_AGENT_NETWORK_REG_STATUS_UNKOWN, +} bt_hfp_agent_network_registration_status_t; + +typedef enum { + BT_HFP_AGENT_ERROR_INTERNAL, + BT_HFP_AGENT_ERROR_NOT_AVAILABLE, + BT_HFP_AGENT_ERROR_NOT_CONNECTED, + BT_HFP_AGENT_ERROR_BUSY, + BT_HFP_AGENT_ERROR_INVALID_PARAM, + BT_HFP_AGENT_ERROR_ALREADY_EXSIST, + BT_HFP_AGENT_ERROR_ALREADY_CONNECTED, + BT_HFP_AGENT_ERROR_NO_MEMORY, + BT_HFP_AGENT_ERROR_I_O_ERROR, + BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE, + BT_HFP_AGENT_ERROR_NO_CALL_LOGS, + BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX, + BT_HFP_AGENT_ERROR_INVALID_CHLD_INDEX, + BT_HFP_AGENT_ERROR_BATTERY_STATUS, + BT_HFP_AGENT_ERROR_SIGNAL_STATUS, + BT_HFP_AGENT_ERROR_NOT_SUPPORTED, + BT_HFP_AGENT_ERROR_INVALID_NUMBER, + BT_HFP_AGENT_ERROR_APPLICATION, + BT_HFP_AGENT_ERROR_INVALID_DTMF, + BT_HFP_AGENT_ERROR_NONE, +} bt_hfp_agent_error_t; + +#define BT_HFP_SERVICE_OBJECT_PATH "/org/bluez/hfp_agent" +#define BT_HFP_SERVICE "org.bluez.hfp_agent" + +#undef LOG_TAG +#define LOG_TAG "BLUETOOTH_AGENT_HFP" + +#define DBG(fmt, args...) SLOGD(fmt, ##args) +#define ERR(fmt, args...) SLOGE(fmt, ##args) +#endif /* __DEF_BT_HFP_AGENT_H_ */ diff --git a/hfp-agent/hfp_agent.xml b/hfp-agent/hfp_agent.xml new file mode 100644 index 0000000..a9942dd --- /dev/null +++ b/hfp-agent/hfp_agent.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hfp-agent/org.bluez.hfp_agent.service b/hfp-agent/org.bluez.hfp_agent.service new file mode 100644 index 0000000..ec36aa3 --- /dev/null +++ b/hfp-agent/org.bluez.hfp_agent.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.bluez.hfp_agent +Exec=/usr/bin/bluetooth-hfp-agent diff --git a/map-agent/CMakeLists.txt b/map-agent/CMakeLists.txt new file mode 100644 index 0000000..932bee4 --- /dev/null +++ b/map-agent/CMakeLists.txt @@ -0,0 +1,31 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(bluetooth-map-agent C) + +SET(SRCS bluetooth_map_agent.c map_bmessage.c) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs_map_agent + REQUIRED + dbus-glib-1 dlog msg-service email-service vconf) + +FOREACH(flag ${pkgs_map_agent_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +FIND_PROGRAM(DBUS_BINDING_TOOL NAMES dbus-binding-tool) +EXEC_PROGRAM("${DBUS_BINDING_TOOL}" + ARGS "--prefix=bluetooth_map \\ + ${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_map_agent.xml \\ + --mode=glib-server \\ + --output=${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_map_agent_glue.h") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_map_agent_LDFLAGS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.bluez.map_agent.service + DESTINATION share/dbus-1/services) diff --git a/map-agent/bluetooth_map_agent.c b/map-agent/bluetooth_map_agent.c new file mode 100644 index 0000000..ab1af4d --- /dev/null +++ b/map-agent/bluetooth_map_agent.c @@ -0,0 +1,2172 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "vconf.h" +#include "vconf-keys.h" + +#include +#include + +/*Messaging Header Files*/ +#include "msg.h" +#include "msg_storage.h" +#include "msg_storage_types.h" +#include "msg_transport.h" +#include "msg_transport_types.h" +#include "msg_types.h" + +#ifdef SUPPORT_EMAIL +/*Email Header Files*/ +#include "email-types.h" +#include "email-api-init.h" +#include "email-api-account.h" +#include "email-api-mailbox.h" +#include "email-api-mail.h" +#include "email-api-network.h" +#endif + +#include + +#include + +#define OBEX_CLIENT_SERVICE "org.openobex.client" +#define OBEX_CLIENT_INTERFACE "org.openobex.Client" +#define OBEX_CLIENT_PATH "/" +#define MNS_CLIENT_INTERFACE "org.openobex.MessageNotification" + +#define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct("GValueArray", \ + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID)) + +#define DBUS_STRUCT_MESSAGE_LIST (dbus_g_type_get_struct("GValueArray", \ + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, \ + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, \ + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING, \ + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, \ + G_TYPE_BOOLEAN, G_TYPE_STRING, \ + G_TYPE_INVALID)) + +static msg_handle_t g_msg_handle = NULL; + +#define BT_MAP_NEW_MESSAGE "NewMessage" +#define BT_MAP_STATUS_CB "sent status callback" +#define BT_MAP_MSG_CB "sms message callback" +#define BT_MAP_EMAIL_DEFAULTACCOUNT "db/email/defaultaccount" +#define BT_MNS_OBJECT_PATH "/org/bluez/mns" +#define BT_MNS_INTERFACE "org.bluez.mns" +#define BT_MAIL_TEMP_BODY "/tmp/bt_mail.txt" +#define BT_MAP_SENT_FOLDER_NAME "SENT" +#define BT_MAP_MSG_INFO_MAX 256 +#define BT_MAP_MSG_HANDLE_MAX 21 +#define BT_MAP_TIMESTAMP_MAX_LEN 16 +#define BT_MAP_SUBJECT_MAX_LEN 20 +#define BT_MAP_MSG_BODY_MAX 1024 +#define BT_MSG_UPDATE 0 +#define BT_MSG_DELETE 1 +#define BT_SMS 0 +#define BT_EMAIL 1 +#define BT_EMAIL_HANDLE_BASE (G_MAXUINT64 / 2) +#define BT_MAIL_ID_MAX_LENGTH 50 + +#define BEGIN_BMSEG "BEGIN:BMSG\r\n" +#define END_BMSEG "END:BMSG\r\n" +#define BMSEG_VERSION "VERSION:1.0\r\n" +#define MSEG_STATUS "STATUS:%s\r\n" +#define MSEG_TYPE "TYPE:%s\r\n" +#define FOLDER_PATH "FOLDER:%s\r\n" +#define VCARD "BEGIN:VCARD\r\nVERSION:2.1\r\nN:%s\r\nTEL:%s\r\nEND:VCARD\r\n" +#define BEGIN_BENV "BEGIN:BENV\r\n" +#define END_BENV "END:BENV\r\n" +#define BEGIN_BBODY "BEGIN:BBODY\r\n" +#define END_BBODY "END:BBODY\r\n" +#define ENCODING "ENCODING:%s\r\n" +#define CHARSET "CHARSET:%s\r\n" +#define LANGUAGE "LANGUAGE:%s\r\n" +#define LENGTH "LENGTH:%d\r\n" +#define MSG_BODY "BEGIN:MSG\r\n%s\r\nEND:MSG\r\n" + +/* This has been added for testing purpose, will be removed when SMS APIs + are available. */ +#define TEST_PDU "06810000000000040681567777000021017101750261A05"\ + "376BA0D8297E5F3B73BCC4ED3F3A030FB1ECECF41613A"\ + "5D1E1ED3E7A0B2BD2CCF8362AEA4195407C941ECF77C9"\ + "E769F41753968FC769BD3E4B27B5C0691EB6510FD0D7AD"\ + "BCBF27B397D46D343A163990E42BFDB6590BCDC4E93D3"\ + "E539889E86CF41F437485E26D7C765D0DB5E96DFCBE933"\ + "9A1E9A36A72063900AA2BF41B5DBED760385E920E9DC357B35A9" + +GSList* id_list = NULL; +guint64 current_push_map_id; + +struct id_info { + guint64 map_id; + int uid; +}; + +struct msg_send_option { + bool save_copy; + bool retry_send; + bool native; +}; + +struct message_info { + char *handle; + char *subject; + char *datetime; + char *sender_name; + char *sender_addressing; + char *recipient_name; + char *recipient_addressing; + char *type; + char *size; + char *reception_status; + char *attachment_size; + char *replyto_addressing; + gboolean text; + gboolean priority; + gboolean read; + gboolean sent; + gboolean protect; +}; + +typedef struct { + GObject parent; +} BluetoothMapAgent; + +typedef struct { + GObjectClass parent; +} BluetoothMapAgentClass; + +GType bluetooth_map_agent_get_type(void); + +#define BLUETOOTH_MAP_TYPE_AGENT (bluetooth_map_agent_get_type()) + +#define BLUETOOTH_MAP_AGENT(object) \ + (G_TYPE_CHECK_INSTANCE_CAST((object), \ + BLUETOOTH_MAP_TYPE_AGENT , BluetoothMapAgent)) +#define BLUETOOTH_MAP_AGENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + BLUETOOTH_MAP_TYPE_AGENT , BluetoothMapAgentClass)) +#define BLUETOOTH_MAP_IS_AGENT(object) \ + (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + BLUETOOTH_MAP_TYPE_AGENT)) +#define BLUETOOTH_MAP_IS_AGENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), \ + BLUETOOTH_MAP_TYPE_AGENT)) +#define BLUETOOTH_MAP_AGENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + BLUETOOTH_MAP_TYPE_AGENT , BluetoothMapAgentClass)) + +G_DEFINE_TYPE(BluetoothMapAgent, bluetooth_map_agent, G_TYPE_OBJECT) + +GMainLoop *g_mainloop = NULL; +static DBusGConnection *g_connection = NULL; +static char *g_mns_path = NULL; +static struct msg_send_option opt; + +static gboolean bluetooth_map_get_folder_tree(BluetoothMapAgent *agent, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_get_message_list(BluetoothMapAgent *agent, + gchar *folder_name, guint16 max, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_get_message(BluetoothMapAgent *agent, + gchar *message_name, + gboolean attach, gboolean transcode, + gboolean first_request, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_push_message(BluetoothMapAgent *agent, + gboolean save_copy, + gboolean retry_send, + gboolean native, + gchar *folder_name, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_push_message_data(BluetoothMapAgent *agent, + gchar *bmsg, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_update_message(BluetoothMapAgent *agent, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_set_read_status(BluetoothMapAgent *agent, + gchar *handle, gboolean read_status, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_set_delete_status(BluetoothMapAgent *agent, + gchar *handle, gboolean delete_status, + DBusGMethodInvocation *context); +static gboolean bluetooth_map_noti_registration(BluetoothMapAgent *agent, + gchar *remote_addr, + gboolean status, + DBusGMethodInvocation *context); + + +#include "bluetooth_map_agent_glue.h" + +static void bluetooth_map_agent_init(BluetoothMapAgent *obj) +{ + DBG("+\n"); + + g_assert(obj != NULL); +} + +static void bluetooth_map_agent_finalize(GObject *obj) +{ + DBG("+\n"); + + G_OBJECT_CLASS(bluetooth_map_agent_parent_class)->finalize(obj); +} + +static void bluetooth_map_agent_class_init(BluetoothMapAgentClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + g_assert(klass != NULL); + + object_class->finalize = bluetooth_map_agent_finalize; + + dbus_g_object_type_install_info(BLUETOOTH_MAP_TYPE_AGENT, + &dbus_glib_bluetooth_map_object_info); +} + +static GQuark __bt_map_agent_error_quark(void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string("agent"); + + return quark; +} + +static GError *__bt_map_agent_error(bt_map_agent_error_t error, + const char *err_msg) +{ + return g_error_new(BT_MAP_AGENT_ERROR, error, err_msg, NULL); +} + +static guint64 _bt_validate_uid(int uid) +{ + DBG("Validate uid"); + struct id_info *info; + int count; + int i; + + count = g_slist_length(id_list); + for (i = 0; i < count; i++) { + info = (struct id_info *)g_slist_nth_data(id_list, i); + if (!info) + break; + + if (info->uid == uid) { + printf("uid = %d\n", uid); + return info->map_id; + } + } + + return 0; +} + +static guint64 __bt_add_id(int uid) +{ + DBG("Add id: %d\n", uid); + static guint64 map_id; + struct id_info *info; + guint64 test; + + test = _bt_validate_uid(uid); + DBG("test: %llx\n", test); + if (test) + return test; + + info = g_new0(struct id_info, 1); + + map_id++; + + info->map_id = map_id; + info->uid = uid; + DBG("map_id = %llx, uid = %d \n", info->map_id, info->uid); + + id_list = g_slist_append(id_list, info); + + return map_id; +} + +static int __bt_get_id(guint64 map_id) +{ + DBG("get id\n"); + struct id_info *info; + int count; + int i; + + count = g_slist_length(id_list); + + for (i = 0; i < count; i++) { + info = (struct id_info *)g_slist_nth_data(id_list, i); + + if (info->map_id == map_id) + return info->uid; + } + + return -1; +} + +static int __bt_get_uid(gchar *handle) +{ + guint64 map_id; + int uid; + + if (NULL == handle) + return -1; + + map_id = g_ascii_strtoull(handle, NULL, 16); + if (!map_id) + return -1; + + uid = __bt_get_id(map_id); + + return uid; +} + +static int __bt_update_id(guint64 map_id, int new_uid) +{ + DBG("update id\n"); + struct id_info *info; + int i; + int count; + + count = g_slist_length(id_list); + + for (i = 0; i < count; i++) { + info = g_slist_nth_data(id_list, i); + + if (info->map_id == map_id) { + info->uid = new_uid; + return map_id; + } + } + + return -1; +} + +static void __bt_remove_list(GSList *id_list) +{ + if (!id_list) + return; + + DBG("Removing id list\n"); + g_slist_free_full(id_list, g_free); +} + + +static gchar *__bt_get_folder_name(int id) +{ + int ret; + char folder_name[BT_MAP_MSG_INFO_MAX] = {0,}; + + msg_struct_list_s g_folderList; + msg_struct_t p_folder; + + ret = msg_get_folder_list(g_msg_handle, &g_folderList); + if (ret != MSG_SUCCESS) + goto done; + + p_folder = g_folderList.msg_struct_info[id]; + + ret = msg_get_str_value(p_folder, MSG_FOLDER_INFO_NAME_STR, + folder_name, BT_MAP_MSG_INFO_MAX); + if (ret != MSG_SUCCESS) + goto done; + + return g_strdup_printf("TELECOM/MSG/%s", folder_name); + +done: + return g_strdup("TELECOM/MSG"); +} + +static void __get_msg_timestamp(time_t *ltime, char *timestamp) +{ + struct tm local_time; + int year; + int month; + + if (!localtime_r(ltime, &local_time)) + return; + + year = local_time.tm_year + 1900; /* years since 1900 */ + month = local_time.tm_mon + 1; /* months since January */ + snprintf(timestamp, 16, "%04d%02d%02dT%02d%02d%02d", year, month, + local_time.tm_mday, local_time.tm_hour, + local_time.tm_min, local_time.tm_sec); + + return; +} + +static char *__bt_prepare_msg_bmseg(msg_struct_t msg_info, gboolean attach, + gboolean transcode) +{ + int ret; + int m_type = MSG_TYPE_SMS; + int folder_id; + int count; + bool read_status = false; + char msg_body[BT_MAP_MSG_BODY_MAX] = {0,}; + char addr_value[MAX_ADDRESS_VAL_LEN] = {0,}; + char name_value[MAX_ADDRESS_VAL_LEN] = {0,}; + gchar *folder_path; + + msg_struct_list_s *addr_list = NULL; + GString *msg; + + msg = g_string_new(BEGIN_BMSEG); + g_string_append(msg, BMSEG_VERSION); + + ret = msg_get_bool_value(msg_info, MSG_MESSAGE_READ_BOOL, &read_status); + if (ret == MSG_SUCCESS) { + DBG("read_status %d\n", read_status); + } + + if (read_status) + g_string_append_printf(msg, MSEG_STATUS, "READ"); + else + g_string_append_printf(msg, MSEG_STATUS, "UNREAD"); + + ret = msg_get_int_value(msg_info, MSG_MESSAGE_TYPE_INT, &m_type); + if (ret == MSG_SUCCESS) { + DBG("m_type %d\n", m_type); + } + + switch (m_type) { + case MSG_TYPE_MMS: + case MSG_TYPE_MMS_JAVA: + case MSG_TYPE_MMS_NOTI: + g_string_append_printf(msg, MSEG_TYPE, "MMS"); + break; + + default: + g_string_append_printf(msg, MSEG_TYPE, "SMS_GSM"); + break; + } + + ret = msg_get_int_value(msg_info, MSG_MESSAGE_FOLDER_ID_INT, + &folder_id); + if (ret == MSG_SUCCESS) { + DBG("folder_id %d\n", folder_id); + } + + folder_path = __bt_get_folder_name(folder_id); + g_string_append_printf(msg, FOLDER_PATH, folder_path); + + + ret = msg_get_list_handle(msg_info, MSG_MESSAGE_ADDR_LIST_STRUCT, + (void **)&addr_list); + if (ret == MSG_SUCCESS) { + count = addr_list->nCount; + DBG("count %d \n", count); + while (count > 0) { + msg_struct_t addr_info = NULL; + addr_info = addr_list->msg_struct_info[count - 1]; + + msg_get_str_value(addr_info, + MSG_ADDRESS_INFO_ADDRESS_VALUE_STR, + addr_value, MAX_ADDRESS_VAL_LEN); + DBG("addr_value %s\n", addr_value); + msg_get_str_value(addr_info, + MSG_ADDRESS_INFO_DISPLAYNAME_STR, + name_value, MAX_ADDRESS_VAL_LEN); + if (!strlen(name_value)) + g_stpcpy(name_value, addr_value); + + DBG("name_value %s\n", name_value); + + g_string_append_printf(msg, VCARD, name_value, + addr_value); + count--; + } + } + + g_string_append(msg, BEGIN_BENV); + g_string_append(msg, BEGIN_BBODY); + + if (transcode) { + g_string_append_printf(msg, CHARSET, "UTF-8"); + + if (m_type == MSG_TYPE_MMS) + ret = msg_get_str_value(msg_info, + MSG_MESSAGE_MMS_TEXT_STR, + msg_body, BT_MAP_SUBJECT_MAX_LEN); + else + ret = msg_get_str_value(msg_info, + MSG_MESSAGE_SMS_DATA_STR, + msg_body, BT_MAP_MSG_BODY_MAX); + + if (ret == MSG_SUCCESS) { + g_string_append_printf(msg, LENGTH, strlen(msg_body)); + g_string_append_printf(msg, MSG_BODY, msg_body); + } + } else { + gchar *msg_pdu; + g_string_append_printf(msg, ENCODING, "G-7BIT"); + g_string_append_printf(msg, CHARSET, "native"); + /* The below line has been added for testing purpose, + will be removed when SMS APIs are available. */ + msg_pdu = g_strdup(TEST_PDU); + g_string_append_printf(msg, LENGTH, strlen(msg_pdu)); + g_string_append_printf(msg, MSG_BODY, msg_pdu); + g_free(msg_pdu); + } + + g_string_append(msg, END_BBODY); + g_string_append(msg, END_BENV); + g_string_append(msg, END_BMSEG); + + return g_string_free(msg, FALSE); +} + +static void __bt_message_info_free(struct message_info msg_info) +{ + g_free(msg_info.handle); + g_free(msg_info.subject); + g_free(msg_info.datetime); + g_free(msg_info.sender_name); + g_free(msg_info.sender_addressing); + g_free(msg_info.replyto_addressing); + g_free(msg_info.recipient_name); + g_free(msg_info.recipient_addressing); + g_free(msg_info.type); + g_free(msg_info.reception_status); + g_free(msg_info.size); + g_free(msg_info.attachment_size); +} + +static struct message_info __bt_message_info_get(msg_struct_t msg_struct_handle) +{ + struct message_info msg_info = {0,}; + int ret; + int msg_id; + guint64 uid; + int dptime; + int m_type = 0; + int data_size; + int priority; + int direction_type; + bool protect_status = 0; + bool read_status = 0; + + char msg_handle[BT_MAP_MSG_HANDLE_MAX] = {0,}; + char msg_subject[BT_MAP_SUBJECT_MAX_LEN] = {0,}; + char msg_datetime[BT_MAP_TIMESTAMP_MAX_LEN] = {0,}; + char msg_size[5] = {0,}; + char msg_body[BT_MAP_MSG_BODY_MAX] = {0,}; + char addr_value[MAX_ADDRESS_VAL_LEN] = {0,}; + char name_value[MAX_ADDRESS_VAL_LEN] = {0,}; + + msg_info.text = FALSE; + msg_info.protect = FALSE; + msg_info.read = FALSE; + msg_info.priority = FALSE; + + msg_struct_t msg = NULL; + msg_struct_t send_opt = NULL; + msg_struct_list_s *addr_list = NULL; + msg_struct_t addr_info = NULL; + + ret = msg_get_int_value(msg_struct_handle, MSG_MESSAGE_ID_INT, &msg_id); + if (ret == MSG_SUCCESS) { + uid = __bt_add_id(msg_id); + snprintf(msg_handle, sizeof(msg_handle), "%llx", uid); + } + msg_info.handle = g_strdup(msg_handle); + + msg = msg_create_struct(MSG_STRUCT_MESSAGE_INFO); + send_opt = msg_create_struct(MSG_STRUCT_SENDOPT); + + ret = msg_get_message(g_msg_handle, + (msg_message_id_t)msg_id, + msg, send_opt); + if (ret != MSG_SUCCESS) { + DBG("ret = %d\n", ret); + goto next; + } + + ret = msg_get_list_handle(msg, MSG_MESSAGE_ADDR_LIST_STRUCT, + (void **)&addr_list); + if (ret != MSG_SUCCESS) { + DBG("ret = %d\n", ret); + goto next; + } + + addr_info = addr_list->msg_struct_info[0]; + + ret = msg_get_str_value(addr_info, MSG_ADDRESS_INFO_ADDRESS_VALUE_STR, + addr_value, MAX_ADDRESS_VAL_LEN); + if (ret == MSG_SUCCESS) + DBG("addr_value %s\n", addr_value); + + ret = msg_get_str_value(addr_info, MSG_ADDRESS_INFO_DISPLAYNAME_STR, + name_value, MAX_ADDRESS_VAL_LEN); + if (ret == MSG_SUCCESS) + DBG("name_value %s\n", name_value); + + if (!strlen(name_value)) + g_stpcpy(name_value, addr_value); + + DBG("name_value %s\n", name_value); + + ret = msg_get_int_value(msg, MSG_MESSAGE_DIRECTION_INT, &direction_type); + if (ret != MSG_SUCCESS) + goto next; + + if (direction_type == MSG_DIRECTION_TYPE_MT) { + msg_info.sender_name = g_strdup(name_value); + msg_info.sender_addressing = g_strdup(addr_value); + msg_info.recipient_name = g_strdup("Unknown"); + msg_info.recipient_addressing = g_strdup("0000"); + } else { + msg_info.sender_name = g_strdup("Unknown"); + msg_info.sender_addressing = g_strdup("0000"); + msg_info.recipient_name = g_strdup(name_value); + msg_info.recipient_addressing = g_strdup(addr_value); + } + +next: + msg_release_struct(&msg); + msg_release_struct(&send_opt); + + ret = msg_get_int_value(msg_struct_handle, MSG_MESSAGE_DISPLAY_TIME_INT, &dptime); + if (ret == MSG_SUCCESS) { + __get_msg_timestamp((time_t *)&dptime, msg_datetime); + } + msg_info.datetime = g_strdup(msg_datetime); + + ret = msg_get_int_value(msg_struct_handle, MSG_MESSAGE_TYPE_INT, + &m_type); + if (ret == MSG_SUCCESS) { + DBG("m_type %d\n", m_type); + } + + switch (m_type) { + case MSG_TYPE_MMS: + case MSG_TYPE_MMS_JAVA: + case MSG_TYPE_MMS_NOTI: + msg_info.type = g_strdup("MMS"); + break; + + default: + msg_info.type = g_strdup("SMS_GSM"); + break; + } + + if (m_type == MSG_TYPE_MMS) { + ret = msg_get_str_value(msg_struct_handle, + MSG_MESSAGE_SUBJECT_STR, msg_subject, + BT_MAP_SUBJECT_MAX_LEN); + if (ret == MSG_SUCCESS) { + DBG("MMS subject %s", msg_subject); + } + + msg_info.subject = g_strdup(msg_subject); + + ret = msg_get_str_value(msg_struct_handle, + MSG_MESSAGE_MMS_TEXT_STR, msg_body, + BT_MAP_MSG_BODY_MAX); + if (ret == MSG_SUCCESS) { + DBG("msg_body %s", msg_body); + if (strlen(msg_body)) + msg_info.text = TRUE ; + } + + } else if (m_type == MSG_TYPE_SMS) { + ret = msg_get_str_value(msg_struct_handle, + MSG_MESSAGE_SMS_DATA_STR, msg_body, + BT_MAP_MSG_BODY_MAX); + if (ret == MSG_SUCCESS) { + DBG("SMS subject %s", msg_body); + if (strlen(msg_body)) { + msg_info.text = TRUE ; + msg_info.subject = g_strndup(msg_body, + BT_MAP_SUBJECT_MAX_LEN); + } + } + } + + ret = msg_get_int_value(msg_struct_handle, MSG_MESSAGE_DATA_SIZE_INT, + &data_size); + if (ret == MSG_SUCCESS) + snprintf(msg_size, sizeof(msg_size), "%d", data_size); + + msg_info.size = g_strdup(msg_size); + + msg_info.reception_status = g_strdup("complete"); + msg_info.attachment_size = g_strdup("0"); + + ret = msg_get_bool_value(msg_struct_handle, MSG_MESSAGE_PROTECTED_BOOL, + &protect_status); + if (ret == MSG_SUCCESS) { + if (protect_status) + msg_info.protect = TRUE; + } + + ret = msg_get_bool_value(msg_struct_handle, MSG_MESSAGE_READ_BOOL, + &read_status); + if (ret == MSG_SUCCESS) { + if (read_status) + msg_info.read = TRUE; + } + + ret = msg_get_int_value(msg_struct_handle, MSG_MESSAGE_PRIORITY_INT, + &priority); + if (ret == MSG_SUCCESS) { + if (priority == MSG_MESSAGE_PRIORITY_HIGH) + msg_info.priority = TRUE; + } + + return msg_info; +} + +static void __bluetooth_map_msg_incoming_status_cb(msg_handle_t handle, + msg_struct_t msg, + void *user_param) +{ + DBusGProxy *mns_proxy; + GError *error = NULL; + + int msg_id = 0; + int msg_type = 0; + int ret = MSG_SUCCESS; + + char *message_type = NULL; + + guint64 uid; + + DBG("+\n"); + + ret = msg_get_int_value(msg, MSG_MESSAGE_ID_INT, &msg_id); + if (ret != MSG_SUCCESS) + return;; + + uid = __bt_add_id(msg_id); + + ret = msg_get_int_value(msg, MSG_MESSAGE_TYPE_INT, &msg_type); + if (ret != MSG_SUCCESS) + return; + + switch (msg_type) { + case MSG_TYPE_SMS: + message_type = g_strdup("SMS_GSM"); + break; + case MSG_TYPE_MMS: + message_type = g_strdup("MMS"); + break; + default: + return; + } + + mns_proxy = dbus_g_proxy_new_for_name(g_connection, OBEX_CLIENT_SERVICE, + g_mns_path, + MNS_CLIENT_INTERFACE); + if (mns_proxy == NULL) { + ERR("Failed to get a proxy for D-Bus\n"); + g_free(message_type); + return; + } + + dbus_g_proxy_call(mns_proxy, "SendEvent", &error, + G_TYPE_STRING, "NewMessage", + G_TYPE_UINT64, uid, + G_TYPE_STRING, "TELECOM/MSG/INBOX", + G_TYPE_STRING, "", + G_TYPE_STRING, message_type, + G_TYPE_INVALID, G_TYPE_INVALID); + if (error) { + DBG("Error [%s]", error->message); + g_error_free(error); + } + + DBG("-\n"); + g_free(message_type); + g_object_unref(mns_proxy); + return; +} + +static gboolean __bluetooth_map_start_service() +{ + msg_error_t err = MSG_SUCCESS; + gboolean msg_ret = TRUE; +#ifdef SUPPORT_EMAIL + int email_err = EMAIL_ERROR_NONE; + gboolean email_ret = TRUE; +#endif + + err = msg_open_msg_handle(&g_msg_handle); + if (err != MSG_SUCCESS) { + ERR("msg_open_msg_handle error = %d\n", err); + msg_ret = FALSE; + goto done; + } + + err = msg_reg_sms_message_callback(g_msg_handle, + __bluetooth_map_msg_incoming_status_cb, + 0, (void *)BT_MAP_MSG_CB); + if (err != MSG_SUCCESS) { + ERR("msg_reg_sms_message_callback error = %d\n", err); + msg_ret = FALSE; + } + +done: + +#ifdef SUPPORT_EMAIL + + email_err = email_service_begin(); + if (email_err != EMAIL_ERROR_NONE) { + ERR("email_service_begin fail error = %d\n", email_err); + email_ret = FALSE; + } + + if (msg_ret || email_ret) + return TRUE; + else + return FALSE; + +#else + + return msg_ret; + +#endif +} + +static void __bluetooth_map_stop_service() +{ + if (NULL != g_msg_handle) + msg_close_msg_handle(&g_msg_handle); + + g_msg_handle = NULL; + +#ifdef SUPPORT_EMAIL + if (EMAIL_ERROR_NONE != email_service_end()) + ERR("email_service_end fail \n"); +#endif + return; +} + +#ifdef SUPPORT_EMAIL +static int __bt_store_mail(email_mailbox_type_e type, char *subject, + char *body, char *recepients) +{ + int account_id; + int mail_id; + int err; + char from_address[BT_MAIL_ID_MAX_LENGTH] = { 0, }; + FILE *body_file; + struct stat st_buf; + + email_account_t *account_data = NULL; + email_mailbox_t *mailbox_data = NULL; + email_mail_data_t *mail_data = NULL; + + err = email_load_default_account_id(&account_id); + if (EMAIL_ERROR_NONE != err) + goto fail; + + err = email_get_account(account_id, GET_FULL_DATA_WITHOUT_PASSWORD, + &account_data); + if (EMAIL_ERROR_NONE != err) + goto fail; + + err = email_get_mailbox_by_mailbox_type(account_id, type, + &mailbox_data); + if (EMAIL_ERROR_NONE != err) + goto fail; + + snprintf(from_address, BT_MAIL_ID_MAX_LENGTH, "<%s>", + account_data->user_email_address); + email_free_account(&account_data, 1); + + mail_data = calloc(1, sizeof(email_mail_data_t)); + if (NULL == mail_data) { + email_free_mailbox(&mailbox_data, 1); + goto fail; + } + + DBG("\n account_id %d\n", account_id); + mail_data->account_id = account_id; + mail_data->save_status = 1; + mail_data->body_download_status = 1; + /* mail_data->flags_draft_field = 1; */ + mail_data->flags_seen_field = 1; + mail_data->file_path_plain = g_strdup(BT_MAIL_TEMP_BODY); + + mail_data->mailbox_id = mailbox_data->mailbox_id; + mail_data->mailbox_type = mailbox_data->mailbox_type; + email_free_mailbox(&mailbox_data, 1); + + mail_data->full_address_from = g_strdup(from_address); + mail_data->full_address_to = g_strdup(recepients); + mail_data->subject = g_strdup(subject); + mail_data->report_status = EMAIL_MAIL_REQUEST_DSN | + EMAIL_MAIL_REQUEST_MDN; + + body_file = fopen(BT_MAIL_TEMP_BODY, "w"); + if (body_file == NULL) { + DBG("\n fopen [%s]failed\n", BT_MAIL_TEMP_BODY); + email_free_mail_data(&mail_data, 1); + goto fail; + } + + fprintf(body_file, body); + fflush(body_file); + fclose(body_file); + + err = email_add_mail(mail_data, NULL, 0, NULL, 0); + if (err != EMAIL_ERROR_NONE) { + DBG("email_add_mail failed. [%d]\n", err); + if (!stat(mail_data->file_path_plain, &st_buf)) + remove(mail_data->file_path_plain); + + email_free_mail_data(&mail_data, 1); + goto fail; + } + + DBG("saved mail id = [%d]\n", mail_data->mail_id); + + mail_id = mail_data->mail_id; + + email_free_mail_data(&mail_data, 1); + + return mail_id; + +fail: + return 0; +} + +static int __bt_email_send(char *subject, char *body, char* recepients) +{ + int err; + int mail_id; + int handle; + + mail_id = __bt_store_mail(EMAIL_MAILBOX_TYPE_OUTBOX, subject, + body, recepients); + if (mail_id) { + DBG("mail_id = %d\n", mail_id); + err = email_send_mail(mail_id, &handle); + if (err != EMAIL_ERROR_NONE) + DBG("Sending failed[%d]\n", err); + } + + return mail_id; +} +#endif + +static int __bt_get_folder_id(char *folder_path) +{ + int folder_id = -1; + int i; + char *folder; + msg_struct_list_s folder_list; + msg_error_t err; + msg_struct_t p_folder; + DBG("__bt_get_folder_id\n"); + + folder = strrchr(folder_path, '/'); + if (NULL == folder) + return -1; + + folder++; + + DBG("folderName %s\n", folder); + + err = msg_get_folder_list(g_msg_handle, &folder_list); + if (err != MSG_SUCCESS) + return -1; + + for (i = 0; i < folder_list.nCount; i++) { + p_folder = folder_list.msg_struct_info[i]; + char folder_name[BT_MAP_MSG_INFO_MAX] = {0, }; + + err = msg_get_str_value(p_folder, MSG_FOLDER_INFO_NAME_STR, + folder_name, BT_MAP_MSG_INFO_MAX); + if (err != MSG_SUCCESS) + continue; + + DBG("folderName %s\n", folder_name); + if (!g_ascii_strncasecmp(folder_name, folder, strlen(folder))) { + err = msg_get_int_value(p_folder, MSG_FOLDER_INFO_ID_INT, + &folder_id); + if (err != MSG_SUCCESS) + return -1; + + break; + } + } + + return folder_id; + +} + +msg_error_t __bt_send_sms(int msg_id, msg_struct_t pMsg, msg_struct_t pSendOpt) +{ + msg_error_t err; + msg_struct_t pReq; + + pReq = msg_create_struct(MSG_STRUCT_REQUEST_INFO); + + msg_set_int_value(pMsg, MSG_MESSAGE_ID_INT, msg_id); + msg_set_struct_handle(pReq, MSG_REQUEST_MESSAGE_HND, pMsg); + msg_set_struct_handle(pReq, MSG_REQUEST_SENDOPT_HND, pSendOpt); + + err = msg_sms_send_message(g_msg_handle, pReq); + if (err == MSG_SUCCESS) + DBG("Sending Message is successful!!!"); + else + DBG("Sending Message is failed!!! %d", err); + + msg_release_struct(&pReq); + return err; +} + +static int __bt_push_sms(gboolean send, int folder_id, char *body, + GSList *recepients) +{ + DBG("+ \n"); + msg_struct_t msg_info = NULL; + msg_struct_t send_opt = NULL; + msg_struct_list_s *addr_list; + msg_error_t err; + + int count = 0; + int i = 0; + int msg_id; + guint64 uid = -1; + + msg_info = msg_create_struct(MSG_STRUCT_MESSAGE_INFO); + if (msg_info == NULL) + goto fail; + + err = msg_set_int_value(msg_info, MSG_MESSAGE_TYPE_INT, MSG_TYPE_SMS); + if (err != MSG_SUCCESS) + goto fail; + + if (body) { + err = msg_set_str_value(msg_info, MSG_MESSAGE_SMS_DATA_STR, body, + strlen(body)); + if (err != MSG_SUCCESS) + goto fail; + } else { + err = msg_set_str_value(msg_info, MSG_MESSAGE_SMS_DATA_STR, + NULL, 0); + if (err != MSG_SUCCESS) + goto fail; + } + + DBG("folder_id %d\n", folder_id); + err = msg_set_int_value(msg_info, MSG_MESSAGE_FOLDER_ID_INT, + folder_id); + if (err != MSG_SUCCESS) + goto fail; + + if (recepients) { + count = g_slist_length(recepients); + DBG("Count = %d\n", count); + msg_get_list_handle(msg_info, MSG_MESSAGE_ADDR_LIST_STRUCT, + (void**)&addr_list); + + addr_list->nCount = count; + for (i = 0; i < count; i++) { + char *address = (char *)g_slist_nth_data(recepients, i); + if (address == NULL) { + DBG("[ERROR] address is value NULL, skip"); + continue; + } + msg_set_int_value(addr_list->msg_struct_info[i], + MSG_ADDRESS_INFO_ADDRESS_TYPE_INT, + MSG_ADDRESS_TYPE_PLMN); + + msg_set_int_value(addr_list->msg_struct_info[i], + MSG_ADDRESS_INFO_RECIPIENT_TYPE_INT, + MSG_RECIPIENTS_TYPE_TO); + + msg_set_str_value(addr_list->msg_struct_info[i], + MSG_ADDRESS_INFO_ADDRESS_VALUE_STR, + address, strlen(address)); + } + } + + send_opt = msg_create_struct(MSG_STRUCT_SENDOPT); + + err = msg_set_bool_value(send_opt, MSG_SEND_OPT_SETTING_BOOL, true); + if (err != MSG_SUCCESS) + goto fail; + + /* Do not keep a copy */ + err = msg_set_bool_value(send_opt, MSG_SEND_OPT_KEEPCOPY_BOOL, + opt.save_copy); + if (err != MSG_SUCCESS) + goto fail; + + msg_id = msg_add_message(g_msg_handle, msg_info, send_opt); + DBG("msg_id = %d\n", msg_id); + uid = __bt_add_id(msg_id); + + if (send == TRUE) { + err = __bt_send_sms(msg_id, msg_info, send_opt); + if (err != MSG_SUCCESS) { + uid = -1; + goto fail; + } + } + +fail: + msg_release_struct(&msg_info); + msg_release_struct(&send_opt); + DBG("-\n"); + return uid; +} + +static gboolean __bt_msg_is_mms(int msg_type) +{ + gboolean result = FALSE; + + switch (msg_type) { + case MSG_TYPE_MMS_NOTI: + case MSG_TYPE_MMS_JAVA: + case MSG_TYPE_MMS: + result = TRUE; + break; + default: + break; + } + + return result; +} + +static void __bt_mns_client_connect(char *address) +{ + DBusGProxy *mns_proxy; + GHashTable *hash; + GValue *addr_value; + GValue *tgt_value; + GError *error = NULL; + const char *session_path = NULL; + + DBG("+ address %s\n", address); + + mns_proxy = dbus_g_proxy_new_for_name(g_connection, OBEX_CLIENT_SERVICE, + OBEX_CLIENT_PATH, + OBEX_CLIENT_INTERFACE); + if (mns_proxy == NULL) { + ERR("Failed to get a proxy for D-Bus\n"); + return; + } + + hash = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, (GDestroyNotify)g_free); + + addr_value = g_new0(GValue, 1); + g_value_init(addr_value, G_TYPE_STRING); + g_value_set_string(addr_value, address); + g_hash_table_insert(hash, "Destination", addr_value); + + tgt_value = g_new0(GValue, 1); + g_value_init(tgt_value, G_TYPE_STRING); + g_value_set_string(tgt_value, "MNS"); + g_hash_table_insert(hash, "Target", tgt_value); + + dbus_g_proxy_call(mns_proxy, "CreateSession", &error, + dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + hash, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &session_path, + G_TYPE_INVALID); + if (error) { + DBG("Error [%s]", error->message); + g_error_free(error); + g_hash_table_destroy(hash); + g_object_unref(mns_proxy); + return; + } + + g_mns_path = g_strdup(session_path); + DBG("g_mns_path = %s\n", g_mns_path); + + g_hash_table_destroy(hash); + g_object_unref(mns_proxy); + + DBG("-\n"); + return; +} + +static void __bt_mns_client_disconnect() +{ + DBusGProxy *mns_proxy; + GError *error = NULL; + + if (!g_mns_path) + return; + + mns_proxy = dbus_g_proxy_new_for_name(g_connection, OBEX_CLIENT_SERVICE, + OBEX_CLIENT_PATH, + OBEX_CLIENT_INTERFACE); + if (mns_proxy == NULL) { + DBG("Failed to get a proxy for D-Bus\n"); + return; + } + + dbus_g_proxy_call(mns_proxy, "RemoveSession", &error, + DBUS_TYPE_G_OBJECT_PATH, g_mns_path, + G_TYPE_INVALID, G_TYPE_INVALID); + if (error) { + DBG("Error [%s]", error->message); + g_error_free(error); + g_object_unref(mns_proxy); + return; + } + + g_free(g_mns_path); + g_mns_path = NULL; + + g_object_unref(mns_proxy); + + DBG("-\n"); + return; +} + +static gboolean bluetooth_map_get_folder_tree(BluetoothMapAgent *agent, + DBusGMethodInvocation *context) +{ + GPtrArray *array = g_ptr_array_new(); + GValue value; + GError *error = NULL; + + char name[BT_MAP_MSG_INFO_MAX] = {0,}; + char folder_name[BT_MAP_MSG_INFO_MAX] = {0,}; + int i; + int ret; + gboolean msg_ret = TRUE; + + msg_struct_list_s g_folderList; + msg_struct_t p_folder; + +#ifdef SUPPORT_EMAIL + int j; + int account_id = 0; + int mailbox_count = 0; + gboolean flag = FALSE; + email_mailbox_t *mailbox_list = NULL; +#endif + + if (g_msg_handle == NULL) { + msg_ret = FALSE; + goto done; + } + + if (msg_get_folder_list(g_msg_handle, &g_folderList) != MSG_SUCCESS) { + msg_ret = FALSE; + goto done; + } + + for (i = 0; i < g_folderList.nCount; i++) { + p_folder = g_folderList.msg_struct_info[i]; + memset(folder_name, 0x00, BT_MAP_MSG_INFO_MAX); + + ret = msg_get_str_value(p_folder, MSG_FOLDER_INFO_NAME_STR, + folder_name, BT_MAP_MSG_INFO_MAX); + if (ret != MSG_SUCCESS) + continue; + + if (!g_ascii_strncasecmp(folder_name, BT_MAP_SENT_FOLDER_NAME, + strlen(BT_MAP_SENT_FOLDER_NAME))) { + memset(folder_name, 0, sizeof(folder_name)); + g_strlcpy(folder_name, BT_MAP_SENT_FOLDER_NAME, + sizeof(folder_name)); + } + + g_strlcpy(name, folder_name, sizeof(name)); + memset(&value, 0, sizeof(GValue)); + g_value_init(&value, DBUS_STRUCT_STRING_STRING_UINT); + g_value_take_boxed(&value, dbus_g_type_specialized_construct( + DBUS_STRUCT_STRING_STRING_UINT)); + dbus_g_type_struct_set(&value, 0, name, G_MAXUINT); + g_ptr_array_add(array, g_value_get_boxed(&value)); + } + +#ifdef SUPPORT_EMAIL +email: + if (EMAIL_ERROR_NONE != email_load_default_account_id(&account_id)) + goto done; + + if (EMAIL_ERROR_NONE != email_get_mailbox_list(account_id, + EMAIL_MAILBOX_ALL, + &mailbox_list, + &mailbox_count)) { + goto done; + } + + msg_ret = TRUE; + + for (i = 0; i < mailbox_count; i++) { + flag = FALSE; + for (j = 0; j < g_folderList.nCount; j++) { + + p_folder = g_folderList.msg_struct_info[j]; + memset(folder_name, 0x00, BT_MAP_MSG_INFO_MAX); + + ret = msg_get_str_value(p_folder, + MSG_FOLDER_INFO_NAME_STR, + folder_name, + BT_MAP_MSG_INFO_MAX); + if (ret != MSG_SUCCESS) + continue; + + if (!g_ascii_strncasecmp(mailbox_list[i].alias, + folder_name, strlen(mailbox_list[i].alias))) { + flag = TRUE; + break; + } + } + + if (!flag) { + g_strlcpy(name, mailbox_list[i].alias, sizeof(name)); + + if (!g_ascii_strncasecmp(name, BT_MAP_SENT_FOLDER_NAME, + strlen(BT_MAP_SENT_FOLDER_NAME))) + continue; + + memset(&value, 0, sizeof(GValue)); + g_value_init(&value, DBUS_STRUCT_STRING_STRING_UINT); + g_value_take_boxed(&value, + dbus_g_type_specialized_construct( + DBUS_STRUCT_STRING_STRING_UINT)); + dbus_g_type_struct_set(&value, 0, name, G_MAXUINT); + g_ptr_array_add(array, g_value_get_boxed(&value)); + } + } + + if (mailbox_list != NULL) + email_free_mailbox(&mailbox_list, mailbox_count); +#endif + +done: + + if (msg_ret == FALSE) { + g_ptr_array_free(array, TRUE); + + error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL, + "InternalError"); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; + } else { + dbus_g_method_return(context, array); + g_ptr_array_free(array, TRUE); + return TRUE; + } +} + +static gboolean bluetooth_map_get_message_list(BluetoothMapAgent *agent, + gchar *folder_name, guint16 max, + DBusGMethodInvocation *context) +{ + GPtrArray *array = g_ptr_array_new(); + GValue value; + GError *error = NULL; + + char *folder = NULL; + int i = 0; + int ret = 0; + int folder_id = 0; + int unread_cnt; + guint64 count; + gboolean newmsg; + + msg_struct_list_s g_folderList; + msg_struct_list_s msg_list; + msg_struct_t count_info; + +#ifdef SUPPORT_EMAIL + int total = 0; + int account_id = 0; + int mailbox_count = 0; + int mail_count = 0; + char *type = NULL; + char msg_datetime[BT_MAP_TIMESTAMP_MAX_LEN] = {0,}; + email_mailbox_t *mailbox_list = NULL; + email_mail_list_item_t *mail_list = NULL; + email_list_filter_t *filter_list = NULL; + email_list_sorting_rule_t *sorting_rule_list = NULL; +#endif + + if (g_msg_handle == NULL) + goto fail; + + folder = strrchr(folder_name, '/'); + if (NULL == folder) + folder = folder_name; + else + folder++; + + ret = msg_get_folder_list(g_msg_handle, &g_folderList); + if (ret != MSG_SUCCESS) + goto fail; + + for (i = 0; i < g_folderList.nCount; i++) { + msg_struct_t pFolder = g_folderList.msg_struct_info[i]; + char folderName[BT_MAP_MSG_INFO_MAX] = {0, }; + + ret = msg_get_str_value(pFolder, MSG_FOLDER_INFO_NAME_STR, + folderName, BT_MAP_MSG_INFO_MAX); + if (ret != MSG_SUCCESS) + continue; + + if (!g_ascii_strncasecmp(folderName, folder, strlen(folder))) { + ret = msg_get_int_value(pFolder, MSG_FOLDER_INFO_ID_INT, + &folder_id); + if (ret != MSG_SUCCESS) + goto fail; + else + DBG("folder_id %d \n", folder_id); + + break; + } + } + + ret = msg_get_folder_view_list(g_msg_handle, folder_id, + NULL, &msg_list); + if (ret != MSG_SUCCESS) + goto fail; + + count = msg_list.nCount; + + count_info = msg_create_struct(MSG_STRUCT_COUNT_INFO); + ret = msg_count_message(g_msg_handle, folder_id, count_info); + if (ret != MSG_SUCCESS) { + msg_release_struct(&count_info); + goto fail; + } + + ret = msg_get_int_value(count_info, MSG_COUNT_INFO_UNREAD_INT, + &unread_cnt); + if (ret != MSG_SUCCESS) { + msg_release_struct(&count_info); + goto fail; + } + + if (unread_cnt != 0) + newmsg = TRUE; + else + newmsg = FALSE; + + msg_release_struct(&count_info); + + DBG("MaxlistCount %d \n", max); + if (max == 0) + goto done; + + for (i = 0; i < msg_list.nCount; i++) { + + struct message_info msg_info; + + memset(&value, 0, sizeof(GValue)); + g_value_init(&value, DBUS_STRUCT_MESSAGE_LIST); + g_value_take_boxed(&value, dbus_g_type_specialized_construct( + DBUS_STRUCT_MESSAGE_LIST)); + + msg_info = __bt_message_info_get(msg_list.msg_struct_info[i]); + +/* Keeping the bleow debug till stabilization is done. */ + +/* + DBG("msg_info.handle = %s\n", msg_info.handle); + DBG("msg_info.subject = %s\n", msg_info.subject); + DBG("msg_info.datetime = %s\n", msg_info.datetime); + DBG("msg_info.sender_name = %s\n", msg_info.sender_name); + DBG("msg_info.sender_addressing = %s\n", msg_info.sender_addressing); + DBG("msg_info.replyto_addressing = %s\n", msg_info.replyto_addressing); + DBG("msg_info.recipient_name = %s\n", msg_info.recipient_name); + DBG("msg_info.recipient_addressing = %s\n", + msg_info.recipient_addressing); + DBG("msg_info.type = %s\n", msg_info.type); + DBG("msg_info.reception_status = %s\n", msg_info.reception_status); + DBG("msg_info.size = %s\n", msg_info.size); + DBG("msg_info.attachment_size = %s\n", msg_info.attachment_size); + DBG("msg_info.text = %d\n", msg_info.text); + DBG("msg_info.read = %d\n", msg_info.read); + DBG("msg_info.sent = %d\n", msg_info.sent); + DBG("msg_info.protect = %d\n", msg_info.protect); + DBG("msg_info.priority = %d\n", msg_info.priority); +*/ + + dbus_g_type_struct_set(&value, 0, msg_info.handle, + 1, msg_info.subject, + 2, msg_info.datetime, + 3, msg_info.sender_name, + 4, msg_info.sender_addressing, + 5, msg_info.recipient_name, + 6, msg_info.recipient_addressing, + 7, msg_info.type, + 8, msg_info.size, + 9, msg_info.reception_status, + 10, msg_info.text, + 11, msg_info.attachment_size, + 12, msg_info.priority, + 13, msg_info.read, + 14, msg_info.sent, + 15, msg_info.protect, + 16, msg_info.replyto_addressing, G_MAXUINT); + g_ptr_array_add(array, g_value_get_boxed(&value)); + + __bt_message_info_free(msg_info); + } + +#ifdef SUPPORT_EMAIL +email: + if (EMAIL_ERROR_NONE != email_load_default_account_id(&account_id)) { + if (!msg_ret) + goto fail; + } + + if (EMAIL_ERROR_NONE != email_get_mailbox_list(account_id, + EMAIL_MAILBOX_ALL, + &mailbox_list, + &mailbox_count)) { + if (!msg_ret) + goto fail; + } + + if (mailbox_list == NULL) + goto fail; + + for (i = 0; i < mailbox_count; i++) { + DBG("mailbox alias = %s \n", mailbox_list[i].alias); + if (!g_ascii_strncasecmp(mailbox_list[i].alias, folder, + strlen(folder))) { + total = mailbox_list[i].total_mail_count_on_server; + DBG("Total mail on sever:%d\n", total); + DBG("mailbox name:%s\n", mailbox_list[i].mailbox_name); + + break; + } + + if (!msg_ret) + goto fail; + else + goto done; + } + + /* Need to modify the filter code, have to make it dynamic + based on remote device request Also to check whether it needs + to be done in agent or in obexd */ + + filter_list = g_new0(email_list_filter_t, 3); + filter_list[0].list_filter_item_type = EMAIL_LIST_FILTER_ITEM_RULE; + filter_list[0].list_filter_item.rule.target_attribute = + EMAIL_MAIL_ATTRIBUTE_ACCOUNT_ID; + filter_list[0].list_filter_item.rule.rule_type = + EMAIL_LIST_FILTER_RULE_EQUAL; + filter_list[0].list_filter_item.rule.key_value.integer_type_value = + account_id; + + filter_list[1].list_filter_item_type = EMAIL_LIST_FILTER_ITEM_OPERATOR; + filter_list[1].list_filter_item.operator_type = + EMAIL_LIST_FILTER_OPERATOR_AND; + + filter_list[2].list_filter_item_type = EMAIL_LIST_FILTER_ITEM_RULE; + filter_list[2].list_filter_item.rule.target_attribute = + EMAIL_MAIL_ATTRIBUTE_MAILBOX_NAME; + filter_list[2].list_filter_item.rule.rule_type = + EMAIL_LIST_FILTER_RULE_EQUAL; + type = g_strdup(mailbox_list[i].mailbox_name); + filter_list[2].list_filter_item.rule.key_value.string_type_value = type; + filter_list[2].list_filter_item.rule.case_sensitivity = true; + + sorting_rule_list = g_new0(email_list_sorting_rule_t, 1); + sorting_rule_list->target_attribute = EMAIL_MAIL_ATTRIBUTE_DATE_TIME; + sorting_rule_list->sort_order = EMAIL_SORT_ORDER_ASCEND; + + ret = email_get_mail_list_ex(filter_list, 3, + sorting_rule_list, 1, 0, total - 1, + &mail_list, &mail_count); + + DBG("email API ret %d \n", ret); + if (ret != EMAIL_ERROR_NONE) { + if (!msg_ret) { + g_free(type); + g_free(filter_list); + g_free(sorting_rule_list); + goto fail; + } else + goto done; + } + + for (i = 0; i < mail_count; ++i) { + time_t time = {0,}; + memset(&value, 0, sizeof(GValue)); + g_value_init(&value, DBUS_STRUCT_MESSAGE_LIST); + g_value_take_boxed(&value, dbus_g_type_specialized_construct( + DBUS_STRUCT_MESSAGE_LIST)); + + uid = __bt_add_id(mail_list[i].mail_id); + snprintf(msg_handle, sizeof(msg_handle), "%llx", uid); + + g_strlcpy(msg_type, "EMAIL", sizeof(msg_type)); + + time = mail_list[i].date_time; + __get_msg_timestamp(&time, msg_datetime); + + dbus_g_type_struct_set(&value, 0, msg_handle, 1, msg_type, + 2, msg_datetime, G_MAXUINT); + g_ptr_array_add(array, g_value_get_boxed(&value)); + } + + if (mailbox_list != NULL) + email_free_mailbox(&mailbox_list, mailbox_count); + if (mail_list != NULL) + g_free(mail_list); + + g_free(filter_list); + g_free(sorting_rule_list); + g_free(type); +#endif + +done: + DBG("Request completed \n"); + dbus_g_method_return(context, newmsg, count, array); + g_ptr_array_free(array, TRUE); + DBG("Request completed successfully \n"); + return TRUE; + +fail: + g_ptr_array_free(array, TRUE); + error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL, + "InternalError"); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; +} + +static gboolean bluetooth_map_get_message(BluetoothMapAgent *agent, + gchar *message_name, + gboolean attach, + gboolean transcode, + gboolean first_request, + DBusGMethodInvocation *context) +{ + DBG("+ \n"); + char *buf = NULL; + int message_id = 0; + int msg_type = BT_SMS; + + GError *error = NULL; + + msg_struct_t msg = NULL; + msg_struct_t send_opt = NULL; +#ifdef SUPPORT_EMAIL + email_mail_data_t *mail_data = NULL; +#endif + message_id = __bt_get_uid(message_name); + if (message_id == -1) + goto fail; + + DBG("message_id %d \n", message_id); + DBG("msg_type %d \n", msg_type); + DBG("attach %d \n", attach); + DBG("transcode %d \n", transcode); + DBG("first_request %d \n", first_request); + + if (msg_type == BT_SMS) { + if (g_msg_handle == NULL) + goto fail; + + msg_error_t msg_err; + + msg = msg_create_struct(MSG_STRUCT_MESSAGE_INFO); + send_opt = msg_create_struct(MSG_STRUCT_SENDOPT); + + msg_err = msg_get_message(g_msg_handle, + (msg_message_id_t)message_id, + msg, send_opt); + if (msg_err != MSG_SUCCESS) + goto fail; + + buf = __bt_prepare_msg_bmseg(msg, attach, transcode); + + msg_release_struct(&msg); + msg_release_struct(&send_opt); +#ifdef SUPPORT_EMAIL + } else if (msg_type == BT_EMAIL) { + + FILE *body_file; + int account_id; + long read_size; + long email_size; + + if (EMAIL_ERROR_NONE != + email_load_default_account_id(&account_id)) + goto fail; + + if (EMAIL_ERROR_NONE != + email_get_mail_data(message_id, &mail_data)) + goto fail; + + body_file = fopen(mail_data->file_path_plain, "r"); + if (body_file == NULL) + body_file = fopen(mail_data->file_path_html, "rb"); + + if (body_file != NULL) { + fseek(body_file , 0, SEEK_END); + email_size = ftell(body_file); + rewind(body_file); + + buf = (char *)g_malloc0(sizeof(char) * email_size); + + read_size = fread(buf, 1, email_size, body_file); + + fclose(body_file); + + if (read_size != email_size) + goto fail; + } else + buf = (char *)g_strdup(""); + + email_free_mail_data(&mail_data, 1); +#endif + } else { + DBG("msg_type not supported %d \n", msg_type); + goto fail; + } + + dbus_g_method_return(context, FALSE, buf); + g_free(buf); + + DBG("- \n"); + return TRUE; + +fail: + g_free(buf); + + if (msg) + msg_release_struct(&msg); + + if (send_opt) + msg_release_struct(&send_opt); + +#ifdef SUPPORT_EMAIL + if (mail_data) + email_free_mail_data(&mail_data, 1); +#endif + + error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL, + "InternalError"); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; +} + +static gboolean bluetooth_map_push_message(BluetoothMapAgent *agent, + gboolean save_copy, + gboolean retry_send, + gboolean native, + gchar *folder_name, + DBusGMethodInvocation *context) +{ + DBG("+\n"); + GError *error = NULL; + guint64 handle = 0; + int folder_id; + + DBG("folder_name = %s\n", folder_name); + + folder_id = __bt_get_folder_id(folder_name); + if (folder_id == -1) + goto fail; + + handle = __bt_add_id(-1); + current_push_map_id = handle; + + /* FALSE : Keep messages in Sent folder */ + /* TRUE : don't keep messages in sent folder */ + opt.save_copy = save_copy; + DBG("opt.save_copy = %d\n", opt.save_copy); + + /* FALSE : don't retry */ + /* TRUE : retry */ + opt.retry_send = retry_send; + DBG("opt.retry_send = %d\n", opt.retry_send); + + /* FALSE : native */ + /* TRUE : UTF-8 */ + opt.native = native; + DBG("opt.native = %d\n", opt.native); + + dbus_g_method_return(context, handle); + DBG("-\n"); + return TRUE; +fail: + error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL, + "InternalError"); + dbus_g_method_return_error(context, error); + g_error_free(error); + + return FALSE; +} + +static gboolean bluetooth_map_push_message_data(BluetoothMapAgent *agent, + gchar *bmsg, + DBusGMethodInvocation *context) +{ + DBG("+\n"); + int id = -1; + int folder_id; + char *folder = NULL; + char *body = NULL; + GSList *recepients = NULL; + gboolean send = FALSE; + + GError *error = NULL; + + DBG("BMSG is \n %s", bmsg); + + struct bmsg_data *bmsg_info = NULL; + + bmsg_info = bmsg_parse(bmsg); + if (!bmsg_info) + goto done; + + folder = bmsg_get_msg_folder(bmsg_info); + if (folder == NULL) + goto done; + + folder_id = __bt_get_folder_id(bmsg_info->folder); + if (folder_id == -1) + goto done; + + if (MSG_OUTBOX_ID == folder_id) + send = TRUE; + + body = bmsg_get_msg_body(bmsg_info); + if (body == NULL) + goto done; + + recepients = bmsg_get_msg_recepients(bmsg_info); + + id = __bt_push_sms(send, folder_id, body, recepients); + if (id == -1) + goto done; + + __bt_update_id(current_push_map_id, id); + +done: + g_free(folder); + g_free(body); + g_slist_free(recepients); + g_free(bmsg_info); + + if (id == -1) { + error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL, + "InternalError"); + dbus_g_method_return_error(context, error); + g_error_free(error); + DBG("-\n"); + return FALSE; + } + + dbus_g_method_return(context); + DBG("-\n"); + return TRUE; +} + +static gboolean bluetooth_map_update_message(BluetoothMapAgent *agent, + DBusGMethodInvocation *context) +{ + int err = TRUE; +#ifdef SUPPORT_EMAIL + int handle; + err = email_sync_header_for_all_account(&handle); + + if (err == EMAIL_ERROR_NONE) { + DBG("Handle to stop download = %d \n", handle); + } else { + ERR("Message Update failed \n"); + } + + dbus_g_method_return(context, err); + return (err == EMAIL_ERROR_NONE) ? TRUE : FALSE; +#else + dbus_g_method_return(context, err); + return TRUE; +#endif +} + +static gboolean bluetooth_map_set_read_status(BluetoothMapAgent *agent, + gchar *handle, + gboolean read_status, + DBusGMethodInvocation *context) +{ + int message_id = 0; + int msg_type = BT_SMS; +#ifdef SUPPORT_EMAIL + email_mail_data_t *mail_data = NULL; +#endif + GError *error = NULL; + + DBG("+\n"); + + message_id = __bt_get_uid(handle); + if (message_id == -1) + goto fail; + + DBG("message_id = %d, read_status = %d\n", message_id, read_status); + + if (msg_type == BT_SMS) { + msg_error_t msg_err; + msg_struct_t msg = msg_create_struct(MSG_STRUCT_MESSAGE_INFO); + msg_struct_t send_opt = msg_create_struct(MSG_STRUCT_SENDOPT); + int msg_type = 0; + + msg_err = msg_get_message(g_msg_handle, + (msg_message_id_t)message_id, + msg, send_opt); + if (msg_err != MSG_SUCCESS) { + msg_release_struct(&msg); + msg_release_struct(&send_opt); + goto fail; + } + + msg_err = msg_get_int_value(msg, MSG_MESSAGE_TYPE_INT, + &msg_type); + if (msg_err != MSG_SUCCESS) { + msg_release_struct(&msg); + msg_release_struct(&send_opt); + goto fail; + } + + msg_err = msg_update_read_status(g_msg_handle, message_id, + read_status); + if (msg_err != MSG_SUCCESS) { + msg_release_struct(&msg); + msg_release_struct(&send_opt); + goto fail; + } + + if (__bt_msg_is_mms(msg_type)) { + if (read_status == TRUE) + msg_err = msg_mms_send_read_report(g_msg_handle, + message_id, + MSG_READ_REPORT_IS_READ); + else + msg_err = msg_mms_send_read_report(g_msg_handle, + message_id, + MSG_READ_REPORT_NONE); + } + + msg_release_struct(&msg); + msg_release_struct(&send_opt); + + if (msg_err != MSG_SUCCESS) + goto fail; +#ifdef SUPPORT_EMAIL + } else if (msg_type == BT_EMAIL) { + + if (email_get_mail_data(message_id, &mail_data) != + EMAIL_ERROR_NONE) { + ERR("email_get_mail_data failed\n"); + goto fail; + } + + if (email_set_flags_field(mail_data->account_id, &message_id, 1, + EMAIL_FLAGS_SEEN_FIELD, read_status, 0) != + EMAIL_ERROR_NONE) { + email_free_mail_data(&mail_data, 1); + goto fail; + } + + email_free_mail_data(&mail_data, 1); +#endif + } else + goto fail; + + dbus_g_method_return(context); + DBG("-\n"); + return TRUE; + +fail: + error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL, + "InternalError"); + dbus_g_method_return_error(context, error); + g_error_free(error); + + return FALSE; +} + +static gboolean bluetooth_map_set_delete_status(BluetoothMapAgent *agent, + gchar *handle, + gboolean delete_status, + DBusGMethodInvocation *context) +{ + int message_id = 0; + int msg_type = BT_SMS; +#ifdef SUPPORT_EMAIL + email_mail_data_t *mail_data = NULL; +#endif + GError *error = NULL; + + DBG("+\n"); + + message_id = __bt_get_uid(handle); + if (message_id == -1) + goto fail; + + DBG("message_id = %d, delete_status = %d\n", message_id, delete_status); + + if (msg_type == BT_SMS) { + if (msg_delete_message(g_msg_handle, message_id) != + MSG_SUCCESS) { + goto fail; + } +#ifdef SUPPORT_EMAIL + } else if (msg_type == BT_EMAIL) { + + if (email_get_mail_data(message_id, &mail_data) != + EMAIL_ERROR_NONE) + goto fail; + + if (email_delete_mail(mail_data->mailbox_id, &message_id, + 1, 1) != EMAIL_ERROR_NONE) { + email_free_mail_data(&mail_data, 1); + goto fail; + } + + email_free_mail_data(&mail_data, 1); +#endif + } else + goto fail; + + dbus_g_method_return(context); + DBG("-\n"); + return TRUE; + +fail: + error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL, + "InternalError"); + dbus_g_method_return_error(context, error); + g_error_free(error); + return FALSE; +} + +static gboolean bluetooth_map_noti_registration(BluetoothMapAgent *agent, + gchar *remote_addr, + gboolean status, + DBusGMethodInvocation *context) +{ + DBG("remote_addr = %s \n", remote_addr); + + if (status == TRUE) + __bt_mns_client_connect(remote_addr); + else + __bt_mns_client_disconnect(); + + return TRUE; +} + +int main(int argc, char **argv) +{ + BluetoothMapAgent *bluetooth_map_obj = NULL; + DBusGProxy *bus_proxy = NULL; + guint result = 0; + GError *error = NULL; + + g_type_init(); + + g_mainloop = g_main_loop_new(NULL, FALSE); + + if (g_mainloop == NULL) { + ERR("Couldn't create GMainLoop\n"); + return EXIT_FAILURE; + } + + g_connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); + + if (error != NULL) { + ERR("Couldn't connect to system bus[%s]\n", error->message); + g_error_free(error); + return EXIT_FAILURE; + } + + bus_proxy = dbus_g_proxy_new_for_name(g_connection, DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + if (bus_proxy == NULL) { + ERR("Failed to get a proxy for D-Bus\n"); + goto failure; + } + + if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error, G_TYPE_STRING, + BT_MAP_SERVICE_NAME, G_TYPE_UINT, 0, + G_TYPE_INVALID, G_TYPE_UINT, &result, + G_TYPE_INVALID)) { + if (error != NULL) { + ERR("RequestName RPC failed[%s]\n", error->message); + g_error_free(error); + } + goto failure; + } + DBG("result : %d %d\n", result, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + ERR("Failed to get the primary well-known name.\n"); + goto failure; + } + + g_object_unref(bus_proxy); + bus_proxy = NULL; + + bluetooth_map_obj = g_object_new(BLUETOOTH_MAP_TYPE_AGENT, NULL); + if (bluetooth_map_obj == NULL) { + ERR("Failed to create one BluetoothMapAgent instance.\n"); + goto failure; + } + + /* Registering it on the D-Bus */ + dbus_g_connection_register_g_object(g_connection, + BT_MAP_SERVICE_OBJECT_PATH, + G_OBJECT(bluetooth_map_obj)); + + if (__bluetooth_map_start_service() == FALSE) + goto failure; + + g_main_loop_run(g_mainloop); + + failure: + DBG("Terminate the bluetooth-map-agent\n"); + + __bt_remove_list(id_list); + + if (g_mns_path) + __bt_mns_client_disconnect(); + if (bus_proxy) + g_object_unref(bus_proxy); + if (bluetooth_map_obj) + g_object_unref(bluetooth_map_obj); + if (g_connection) + dbus_g_connection_unref(g_connection); + + + __bluetooth_map_stop_service(); + return EXIT_FAILURE; +} diff --git a/map-agent/bluetooth_map_agent.h b/map-agent/bluetooth_map_agent.h new file mode 100644 index 0000000..5989903 --- /dev/null +++ b/map-agent/bluetooth_map_agent.h @@ -0,0 +1,47 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#ifndef __DEF_BT_PB_AGENT_H_ +#define __DEF_BT_PB_AGENT_H_ + +#include +#include + +#include + +#include + +#define BT_MAP_AGENT_ERROR (__bt_map_agent_error_quark()) + +typedef enum { + BT_MAP_AGENT_ERROR_INTERNAL, + BT_MAP_AGENT_ERROR_CANCEL, +} bt_map_agent_error_t; + +#define BT_MAP_SERVICE_OBJECT_PATH "/org/bluez/map_agent" +#define BT_MAP_SERVICE_NAME "org.bluez.map_agent" +#define BT_MAP_SERVICE_INTERFACE "org.bluez.MapAgent" + +#undef LOG_TAG +#define LOG_TAG "BLUETOOTH_AGENT_MESSAGE" + +#define DBG(fmt, args...) SLOGD(fmt, ##args) +#define ERR(fmt, args...) SLOGE(fmt, ##args) + +#endif /* __DEF_BT_AGENT_H_ */ diff --git a/map-agent/bluetooth_map_agent.xml b/map-agent/bluetooth_map_agent.xml new file mode 100644 index 0000000..fea0177 --- /dev/null +++ b/map-agent/bluetooth_map_agent.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/map-agent/map_bmessage.c b/map-agent/map_bmessage.c new file mode 100644 index 0000000..febfe03 --- /dev/null +++ b/map-agent/map_bmessage.c @@ -0,0 +1,520 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#include +#include +#include + +#include + +#include + +#define CRLF_LEN 2 + +#define BMSG_TAG "BEGIN:BMSG\r\n" +#define VER_TAG "VERSION:" +#define STATUS_TAG "STATUS:" +#define TYPE_TAG "TYPE:" +#define FOLDER_TAG "FOLDER:" +#define VCARD_BEGIN_TAG "BEGIN:VCARD\r\n" +#define VCARD_END_TAG "END:VCARD\r\n" +#define VCARD_N_TAG "N:" +#define VCARD_FN_TAG "FN:" +#define VCARD_TEL_TAG "TEL:" +#define VCARD_EMAIL_TAG "EMAIL:" +#define BENV_TAG "BEGIN:BENV\r\n" +#define BBODY_TAG "BEGIN:BBODY\r\n" +#define MSG_TAG "BEGIN:MSG\r\n" +#define PARTID_TAG "PARTID:" +#define ENCODING_TAG "ENCODING:" +#define CHARSET_TAG "CHARSET:" +#define LANGUAGE_TAG "LANGUAGE:" +#define LENGTH_TAG "LENGTH:" + + +void print_bmsg(struct bmsg_data *bmsg) +{ + if (bmsg == NULL) + return; + + struct benv_data *env_data = NULL; + + DBG("bmsg->version = %s", bmsg->version); + DBG("bmsg->status = %s", bmsg->status); + DBG("bmsg->type = %s", bmsg->type); + DBG("bmsg->folder = %s", bmsg->folder); + DBG("bmsg->originator_vcard_data->version = %s", + bmsg->originator_vcard_data->version); + DBG("bmsg->originator_vcard_data->n = %s", + bmsg->originator_vcard_data->n); + + int i = 0; + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + while (env_data != NULL) { + + DBG("env_data = %d", env_data->encapsulation_level); + int k = 0; + struct bmsg_vcard *rvcard; + + rvcard = g_slist_nth_data(env_data->recipient_vcard, k); + + while (rvcard != NULL) { + k++; + + if (rvcard->version != NULL) + DBG("vcard->version = %s\n", rvcard->version); + if (rvcard->n != NULL) + DBG("vcard->n = %s\n", rvcard->n); + if (rvcard->fn != NULL) + DBG("vcard->fn = %s\n", rvcard->fn); + if (rvcard->tel != NULL) + DBG("vcard->tel = %s\n", rvcard->tel); + if (rvcard->email != NULL) + DBG("vcard->email = %s\n", rvcard->email); + + rvcard = g_slist_nth_data(env_data->recipient_vcard, k); + } + + if (env_data->body_content != NULL) { + DBG("env_data->body_content->length = %" + G_GUINT64_FORMAT "\n", + env_data->body_content->length); + DBG("env_data->body_content->msg = %s\n", + env_data->body_content->msg); + } + + i++; + + if (i > 2) + break; + + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + } +} + +char *bmsg_get_msg_folder(struct bmsg_data *bmsg) +{ + return g_strdup(bmsg->folder); +} + +char *bmsg_get_msg_body(struct bmsg_data *bmsg) +{ + struct benv_data *env_data; + int i = 0; + + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + + while (env_data != NULL) { + if (env_data->body_content != NULL) { + DBG("env_data->body_content->msg = %s\n", + env_data->body_content->msg); + DBG("env_data->body_content->length = %" + G_GUINT64_FORMAT "\n", + env_data->body_content->length); + return g_strndup(env_data->body_content->msg, + env_data->body_content->length); + } + + i++; + if (i > 2) + break; + + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + } + + return NULL; +} + +GSList *bmsg_get_msg_recepients(struct bmsg_data *bmsg) +{ + struct benv_data *env_data; + GSList *receiver = NULL; + int i = 0; + + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + + while (env_data != NULL) { + + DBG("env_data = %d", env_data->encapsulation_level); + int k = 0; + struct bmsg_vcard *rvcard; + + rvcard = g_slist_nth_data(env_data->recipient_vcard, k); + while (rvcard != NULL) { + k++; + + if (rvcard->tel != NULL) { + DBG("vcard->tel = %s\n", rvcard->tel); + receiver = g_slist_append(receiver, rvcard->tel); + } + + rvcard = g_slist_nth_data(env_data->recipient_vcard, k); + } + + i++; + if (i > 2) + break; + + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + } + + return receiver; +} + +void bmsg_free_vcard_data(struct bmsg_vcard *vcard_data) +{ + if (vcard_data == NULL) + return; + + g_free(vcard_data->version); + g_free(vcard_data->n); + g_free(vcard_data->fn); + g_free(vcard_data->tel); + g_free(vcard_data->email); + g_free(vcard_data); + + return; +} + +void bmsg_free_bmsg(struct bmsg_data *bmsg) +{ + struct benv_data *env_data; + int i = 0; + + if (bmsg == NULL) + return; + + g_free(bmsg->version); + g_free(bmsg->status); + g_free(bmsg->type); + g_free(bmsg->folder); + bmsg_free_vcard_data(bmsg->originator_vcard_data); + + if (bmsg->envelope_data == NULL) + goto done; + + if (bmsg->envelope_data->env_data == NULL) + goto done; + + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + while (env_data != NULL) { + + DBG("env_data = %d", env_data->encapsulation_level); + int k = 0; + struct bmsg_vcard *rvcard; + + rvcard = g_slist_nth_data(env_data->recipient_vcard, k); + + while (rvcard != NULL) { + k++; + bmsg_free_vcard_data(rvcard); + rvcard = g_slist_nth_data(env_data->recipient_vcard, k); + } + + if (env_data->body_content != NULL) { + g_free(env_data->body_content->encoding); + g_free(env_data->body_content->charset); + g_free(env_data->body_content->language); + g_free(env_data->body_content->msg); + g_free(env_data->body_content); + } + + g_free(env_data); + i++; + + env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i); + } + +done: + g_free(bmsg); +} + +gchar *bmsg_get_parse_sub_block(char **sub_block_data, char *element) +{ + gchar *start; + gchar *end; + gchar *block_start; + gchar *block_end; + gchar *sub_block = NULL; + size_t offset; + size_t len; + + DBG(""); + + start = g_strdup_printf("BEGIN:%s\r\n", element); + end = g_strdup_printf("END:%s\r\n", element); + offset = strlen(start); + + block_start = g_strstr_len(*sub_block_data, offset, start); + if (block_start == NULL) + goto done; + + if (!g_strcmp0(start, VCARD_BEGIN_TAG)) + block_end = g_strstr_len(*sub_block_data, -1, end); + else + block_end = g_strrstr(*sub_block_data, end); + + if (block_end == NULL) + goto done; + + len = block_end - block_start - offset; + sub_block = g_strndup(block_start + offset, len); + *sub_block_data = *sub_block_data + strlen(sub_block) + strlen(start) + + strlen(end); +done: + g_free(start); + g_free(end); + return sub_block; +} + +gchar *bmsg_get_tag_data(char **block_data, char *element) +{ + gchar *end = "\r\n"; + gchar *block_start; + gchar *block_end; + gchar *sub_block; + size_t offset; + size_t len; + + DBG(""); + + if (*block_data == NULL || element == NULL) + return NULL; + + block_start = g_strstr_len(*block_data, -1, element); + if (block_start == NULL) + return NULL; + + offset = strlen(element); + + block_end = g_strstr_len(block_start+offset, -1, end); + if (block_end == NULL) + return NULL; + + len = block_end - block_start - offset; + sub_block = g_strndup(block_start + offset, len); + *block_data = *block_data + offset + len + CRLF_LEN; + + return sub_block; +} + +struct bmsg_bbody *bmsg_get_bbody_data(gchar *block_data) +{ + gchar *bbody_block_data_start; + gchar *temp; + struct bmsg_bbody *bbody; + DBG(""); + + bbody_block_data_start = block_data; + + bbody = g_new0(struct bmsg_bbody, 1); + + temp = bmsg_get_tag_data(&block_data, PARTID_TAG); + if (temp != NULL) { + bbody->part_id = (guint16)g_ascii_strtoull(temp, NULL, 10); + g_free(temp); + } + + bbody->encoding = bmsg_get_tag_data(&block_data, ENCODING_TAG); + bbody->charset = bmsg_get_tag_data(&block_data, CHARSET_TAG); + bbody->language = bmsg_get_tag_data(&block_data, LANGUAGE_TAG); + + temp = bmsg_get_tag_data(&block_data, LENGTH_TAG); + + if (temp != NULL) { + bbody->length = g_ascii_strtoull(temp, NULL, 10); + g_free(temp); + } + + bbody->msg = bmsg_get_parse_sub_block(&block_data, "MSG"); + + g_free(bbody_block_data_start); + + return bbody; +} + +struct bmsg_vcard *bmsg_get_vcard_data(gchar *sub_block_data) +{ + gchar *vcard_block_data_start; + struct bmsg_vcard *vcard; + DBG(""); + + vcard_block_data_start = sub_block_data; + + vcard = g_new0(struct bmsg_vcard, 1); + + vcard->version = bmsg_get_tag_data(&sub_block_data, VER_TAG); + vcard->n = bmsg_get_tag_data(&sub_block_data, VCARD_N_TAG); + vcard->fn = bmsg_get_tag_data(&sub_block_data, VCARD_FN_TAG); + vcard->tel = bmsg_get_tag_data(&sub_block_data, VCARD_TEL_TAG); + vcard->email = bmsg_get_tag_data(&sub_block_data, VCARD_EMAIL_TAG); + + g_free(vcard_block_data_start); + + return vcard; +} + +struct benv_data *bmsg_get_env_encapsulation_data(gchar **sub_block_data) +{ + gchar *is_valid; + gchar *bbody_data = NULL; + static guint8 lvl = 1; + + is_valid = g_strstr_len(*sub_block_data, strlen(VCARD_BEGIN_TAG), + VCARD_BEGIN_TAG); + if (is_valid == NULL) + return NULL; + + if (lvl > 3) + return NULL; + + struct benv_data *rec_data = g_new0(struct benv_data, 1); + + rec_data->encapsulation_level = lvl; + lvl++; + + while (is_valid != NULL) { + gchar *vcard_data = NULL; + struct bmsg_vcard *vcard; + + vcard_data = bmsg_get_parse_sub_block(sub_block_data, "VCARD"); + if (vcard_data == NULL) { + DBG("parse error\n"); + g_free(rec_data); + return NULL; + } + vcard = bmsg_get_vcard_data(vcard_data); + + rec_data->recipient_vcard = g_slist_append( + rec_data->recipient_vcard, + vcard); + + is_valid = g_strstr_len(*sub_block_data, + strlen(VCARD_BEGIN_TAG), + VCARD_BEGIN_TAG); + } + + is_valid = g_strstr_len(*sub_block_data, strlen(BBODY_TAG), BBODY_TAG); + + if (!is_valid) + return rec_data; + + bbody_data = bmsg_get_parse_sub_block(sub_block_data, "BBODY"); + if (bbody_data == NULL) { + DBG("parse error\n"); + return rec_data; + } + + rec_data->body_content = bmsg_get_bbody_data(bbody_data); + + return rec_data; +} + +struct bmsg_envelope *bmsg_get_envelope_data(gchar **block_data) +{ + gchar *env_block_data_start; + gchar *sub_block_data; + struct bmsg_envelope *envelope_data; + struct benv_data *rec_data; + + env_block_data_start = *block_data; + + envelope_data = g_new0(struct bmsg_envelope, 1); + + sub_block_data = bmsg_get_parse_sub_block(block_data, "BENV"); + + while (sub_block_data) { + + rec_data = bmsg_get_env_encapsulation_data(&sub_block_data); + + while (rec_data) { + envelope_data->env_data = g_slist_append( + envelope_data->env_data, + rec_data); + + rec_data = bmsg_get_env_encapsulation_data( + &sub_block_data); + } + sub_block_data = bmsg_get_parse_sub_block(&sub_block_data, + "BENV"); + } + g_free(sub_block_data); + + return envelope_data; +} + +struct bmsg_data * bmsg_parse(gchar *buf) +{ + gchar *block_data; + gchar *sub_block_data; + gchar *block_data_start; + struct bmsg_data *bmsg; + + DBG(""); + + block_data = bmsg_get_parse_sub_block(&buf, "BMSG"); + if (block_data == NULL) + return NULL; + + block_data_start = block_data; + + bmsg = g_new0(struct bmsg_data, 1); + + bmsg->version = bmsg_get_tag_data(&block_data, VER_TAG); + if (bmsg->version == NULL) + goto parse_fail; + + bmsg->status = bmsg_get_tag_data(&block_data, STATUS_TAG); + if (bmsg->status == NULL) + goto parse_fail; + + bmsg->type = bmsg_get_tag_data(&block_data, TYPE_TAG); + if (bmsg->type == NULL) + goto parse_fail; + + bmsg->folder = bmsg_get_tag_data(&block_data, FOLDER_TAG); + if (bmsg->folder == NULL) + goto parse_fail; + + sub_block_data = bmsg_get_parse_sub_block(&block_data, "VCARD"); + if (sub_block_data == NULL) + goto parse_fail; + + bmsg->originator_vcard_data = bmsg_get_vcard_data(sub_block_data); + if (bmsg->originator_vcard_data == NULL) + goto parse_fail; + + bmsg->envelope_data = bmsg_get_envelope_data(&block_data); + if (bmsg->envelope_data == NULL) + goto parse_fail; + + g_free(block_data_start); + + DBG("Parse done"); + print_bmsg(bmsg); + + return bmsg; + +parse_fail: + DBG("Parse fail"); + bmsg_free_bmsg(bmsg); + + return NULL; +} + diff --git a/map-agent/map_bmessage.h b/map-agent/map_bmessage.h new file mode 100644 index 0000000..4cdadf7 --- /dev/null +++ b/map-agent/map_bmessage.h @@ -0,0 +1,72 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + + #ifndef __BMSG_H +#define __BMSG_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct bmsg_vcard { + gchar *version; + gchar *n; + gchar *fn; + gchar *tel; + gchar *email; +}; + +struct bmsg_bbody { + guint16 part_id; + gchar *encoding; + gchar *charset; + gchar *language; + guint64 length; + gchar *msg; +}; + +struct benv_data { + guint8 encapsulation_level; + GSList *recipient_vcard; + struct bmsg_bbody *body_content; +}; + +struct bmsg_envelope { + GSList *env_data; /* Add benv_data here*/ +}; + +struct bmsg_data { + gchar *version; + gchar *status; + gchar *type; + gchar *folder; + struct bmsg_vcard *originator_vcard_data; + struct bmsg_envelope *envelope_data; +}; + +struct bmsg_data * bmsg_parse(gchar *buf); +char *bmsg_get_msg_folder(struct bmsg_data *bmsg); +char *bmsg_get_msg_body(struct bmsg_data *bmsg); +GSList *bmsg_get_msg_recepients(struct bmsg_data *bmsg); + +#ifdef __cplusplus +} +#endif + +#endif /* __BMSG_H */ diff --git a/map-agent/org.bluez.map_agent.service b/map-agent/org.bluez.map_agent.service new file mode 100644 index 0000000..3a5a867 --- /dev/null +++ b/map-agent/org.bluez.map_agent.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.bluez.map_agent +Exec=/usr/bin/bluetooth-map-agent diff --git a/packaging/bluetooth-agent.spec b/packaging/bluetooth-agent.spec new file mode 100644 index 0000000..8cc6ce8 --- /dev/null +++ b/packaging/bluetooth-agent.spec @@ -0,0 +1,42 @@ +Name: bluetooth-agent +Summary: Bluetooth agent packages that support various external profiles +Version: 0.0.7 +Release: 2 +Group: TO_BE/FILLED_IN +License: TO BE FILLED IN +Source0: %{name}-%{version}.tar.gz + +BuildRequires: pkgconfig(contacts-service2) +BuildRequires: pkgconfig(dbus-glib-1) +BuildRequires: pkgconfig(msg-service) +BuildRequires: pkgconfig(email-service) +BuildRequires: pkgconfig(tapi) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(appsvc) +BuildRequires: cmake + +%description +Bluetooth agent packages that support various external profiles + +%prep +%setup -q + +%build +cmake . -DCMAKE_INSTALL_PREFIX=/usr + +make VERBOSE=1 + +%install +rm -rf %{buildroot} +%make_install + +%files +%manifest bluetooth-agent.manifest +%defattr(-, root, root) +%{_bindir}/bluetooth-map-agent +%{_bindir}/bluetooth-pb-agent +%{_bindir}/bluetooth-hfp-agent +%{_datadir}/dbus-1/services/org.bluez.pb_agent.service +%{_datadir}/dbus-1/services/org.bluez.map_agent.service +%{_datadir}/dbus-1/services/org.bluez.hfp_agent.service diff --git a/pb-agent/CMakeLists.txt b/pb-agent/CMakeLists.txt new file mode 100644 index 0000000..2f0b495 --- /dev/null +++ b/pb-agent/CMakeLists.txt @@ -0,0 +1,30 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(bluetooth-pb-agent C) + +SET(SRCS bluetooth_pb_agent.c bluetooth_pb_vcard.c) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs_pb_agent + REQUIRED + dbus-glib-1 dlog contacts-service2 tapi vconf) + +FOREACH(flag ${pkgs_pb_agent_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +FIND_PROGRAM(DBUS_BINDING_TOOL NAMES dbus-binding-tool) +EXEC_PROGRAM("${DBUS_BINDING_TOOL}" + ARGS "--prefix=bluetooth_pb \\ + ${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_pb_agent.xml \\ + --mode=glib-server \\ + --output=${CMAKE_CURRENT_SOURCE_DIR}/bluetooth_pb_agent_glue.h") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_pb_agent_LDFLAGS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.bluez.pb_agent.service + DESTINATION share/dbus-1/services) diff --git a/pb-agent/bluetooth_pb_agent.c b/pb-agent/bluetooth_pb_agent.c new file mode 100644 index 0000000..93ad026 --- /dev/null +++ b/pb-agent/bluetooth_pb_agent.c @@ -0,0 +1,2161 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + +#include + +#include +#include + +#include "bluetooth_pb_agent.h" +#include "bluetooth_pb_vcard.h" + +#define BLUETOOTH_PB_AGENT_TIMEOUT 600 + +static gchar *bluetooth_pb_agent_folder_list[] = { + "/telecom/pb", + "/telecom/ich", + "/telecom/och", + "/telecom/mch", + "/telecom/cch", + NULL +}; + +typedef enum { + TELECOM_PB = 0, + TELECOM_ICH, + TELECOM_OCH, + TELECOM_MCH, + TELECOM_CCH, + TELECOM_NONE +} PhoneBookType; + +typedef struct { + GObject parent; + + DBusGConnection *bus; + DBusGProxy *proxy; + + TapiHandle *tapi_handle; + gchar *tel_number; + + GHashTable *contact_list; + + guint timeout_id; + + PhoneBookType pb_type; +} BluetoothPbAgent; + +typedef struct { + GObjectClass parent; + + void (*clear) (BluetoothPbAgent *agent); +} BluetoothPbAgentClass; + +enum { + CLEAR, + LAST_SIGNAL +}; + +GType bluetooth_pb_agent_get_type(void); + +#define BLUETOOTH_PB_TYPE_AGENT (bluetooth_pb_agent_get_type()) + +#define BLUETOOTH_PB_AGENT(object) \ + (G_TYPE_CHECK_INSTANCE_CAST((object), \ + BLUETOOTH_PB_TYPE_AGENT , BluetoothPbAgent)) +#define BLUETOOTH_PB_AGENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + BLUETOOTH_PB_TYPE_AGENT , BluetoothPbAgentClass)) +#define BLUETOOTH_IS_PB_AGENT(object) \ + (G_TYPE_CHECK_INSTANCE_TYPE((object), \ + BLUETOOTH_PB_TYPE_AGENT)) +#define BLUETOOTH_IS_PB_AGENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), \ + BLUETOOTH_PB_TYPE_AGENT)) +#define BLUETOOTH_PB_AGENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + BLUETOOTH_PB_TYPE_AGENT , BluetoothPbAgentClass)) + +G_DEFINE_TYPE(BluetoothPbAgent, bluetooth_pb_agent, G_TYPE_OBJECT) + +#define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct("GValueArray", G_TYPE_STRING, \ + G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID)) + +static guint signals[LAST_SIGNAL] = { 0 }; + +static GMainLoop *mainloop = NULL; + +static void bluetooth_pb_agent_finalize(GObject *obj); + +static void bluetooth_pb_agent_clear(BluetoothPbAgent *agent); + +/* Dbus messages */ +static gboolean bluetooth_pb_get_phonebook_folder_list(BluetoothPbAgent *agent, + const gchar ***folder_list, + GError **error); + +static gboolean bluetooth_pb_get_phonebook(BluetoothPbAgent *agent, + const char *name, + guint64 filter, + guint8 format, + guint16 max_list_count, + guint16 list_start_offset, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_get_phonebook_size(BluetoothPbAgent *agent, + const char *name, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_get_phonebook_list(BluetoothPbAgent *agent, + const char *name, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_get_phonebook_entry(BluetoothPbAgent *agent, + const gchar *folder, + const gchar *id, + guint64 filter, + guint8 format, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_get_phonebook_size_at(BluetoothPbAgent *agent, + const gchar *command, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_get_phonebook_entries_at(BluetoothPbAgent *agent, + const gchar *command, + gint32 start_index, + gint32 end_index, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_get_phonebook_entries_find_at(BluetoothPbAgent *agent, + const gchar *command, + const gchar *find_text, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_get_total_object_count(BluetoothPbAgent *agent, + gchar *path, + DBusGMethodInvocation *context); + +static gboolean bluetooth_pb_add_contact (BluetoothPbAgent *agent, + const char *filename, + GError **error); + +static void __bluetooth_pb_dbus_return_error(DBusGMethodInvocation *context, + gint code, + const gchar *message); + +static PhoneBookType __bluetooth_pb_get_pb_type(const char *name); + +static PhoneBookType __bluetooth_pb_get_storage_pb_type(const char *name); + +static gint __bluetooth_pb_phone_log_filter_append(contacts_filter_h filter, + gint *match, + gint size); + +static contacts_query_h __bluetooth_pb_query_phone_log(gint *match, + gint size); + +static contacts_query_h __bluetooth_pb_query_person(void); + +static contacts_query_h __bluetooth_pb_query_person_number(void); + +static contacts_query_h __bluetooth_pb_query_phone_log_incoming(void); + +static contacts_query_h __bluetooth_pb_query_phone_log_outgoing(void); + +static contacts_query_h __bluetooth_pb_query_phone_log_missed(void); + +static contacts_query_h __bluetooth_pb_query_phone_log_combined(void); + +static gboolean __bluetooth_pb_get_count(PhoneBookType pb_type, + guint *count); + +static gboolean __bluetooth_pb_get_count_new_missed_call(guint *count); + +static const char *__bluetooth_pb_phone_log_get_log_type(contacts_record_h record); + +static void __bluetooth_pb_get_vcards(BluetoothPbAgent *agent, + PhoneBookType pb_type, + guint64 filter, + guint8 format, + guint16 max_list_count, + guint16 list_start_offset, + GPtrArray *vcards); + +static void __bluetooth_pb_get_contact_list(BluetoothPbAgent *agent, + contacts_query_h query, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_phone_log_list(BluetoothPbAgent *agent, + contacts_query_h query, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_list(BluetoothPbAgent *agent, + PhoneBookType pb_type, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_contact_list_number(BluetoothPbAgent *agent, + contacts_query_h query, + gint start_index, + gint end_index, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_phone_log_list_number(BluetoothPbAgent *agent, + contacts_query_h query, + gint start_index, + gint end_index, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_list_number(BluetoothPbAgent *agent, + PhoneBookType pb_type, + gint start_index, + gint end_index, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_contact_list_name(BluetoothPbAgent *agent, + contacts_query_h query, + const gchar *find_text, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_phone_log_list_name(BluetoothPbAgent *agent, + contacts_query_h query, + const gchar *find_text, + GPtrArray *ptr_array); + +static void __bluetooth_pb_get_list_name(BluetoothPbAgent *agent, + PhoneBookType pb_type, + const gchar *find_text, + GPtrArray *ptr_array); + +static void __bluetooth_pb_list_hash_reset(BluetoothPbAgent *agent); + +static gboolean __bluetooth_pb_list_hash_insert(BluetoothPbAgent *agent, + gint handle, + gint id); + +static gint __bluetooth_pb_list_hash_lookup_id(BluetoothPbAgent *agent, + gint handle); + +static void __bluetooth_pb_list_ptr_array_add(GPtrArray *ptr_array, + const gchar *name, + const gchar *number, + gint handle); + +static void __bluetooth_pb_list_ptr_array_free(gpointer data); + +static void __bluetooth_pb_agent_signal_handler(int signum); + +static void __bluetooth_pb_contact_changed(const gchar *view_uri, + void *user_data); + +static void __bluetooth_pb_agent_timeout_add_seconds(BluetoothPbAgent *agent); + +static gboolean __bluetooth_pb_agent_timeout_calback(gpointer user_data); + +static void __bluetooth_pb_tel_callback(TapiHandle *handle, + int result, + void *data, + void *user_data); + +static void __bluetooth_pb_agent_dbus_init(BluetoothPbAgent *agent); + +#include "bluetooth_pb_agent_glue.h" + +static void bluetooth_pb_agent_init(BluetoothPbAgent *agent) +{ + agent->bus = NULL; + agent->proxy = NULL; + + agent->tapi_handle = NULL; + agent->tel_number = NULL; + + agent->contact_list = NULL; + agent->timeout_id = 0; + + agent->pb_type = TELECOM_NONE; +} + +static void bluetooth_pb_agent_class_init(BluetoothPbAgentClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + klass->clear = bluetooth_pb_agent_clear; + + object_class->finalize = bluetooth_pb_agent_finalize; + + signals[CLEAR] = g_signal_new("clear", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(BluetoothPbAgentClass, clear), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + dbus_g_object_type_install_info(BLUETOOTH_PB_TYPE_AGENT, + &dbus_glib_bluetooth_pb_object_info); +} + +static void bluetooth_pb_agent_finalize(GObject *obj) +{ + BluetoothPbAgent *agent = BLUETOOTH_PB_AGENT(obj); + + DBG("+\n"); + + if (agent->tapi_handle) { + tel_deinit(agent->tapi_handle); + agent->tapi_handle = NULL; + } + + if (agent->tel_number) { + g_free(agent->tel_number); + agent->tel_number = NULL; + } + + if(agent->timeout_id) { + g_source_remove(agent->timeout_id); + agent->timeout_id = 0; + } + + if (agent->contact_list) { + g_hash_table_destroy(agent->contact_list); + agent->contact_list = NULL; + } + + if (agent->proxy) { + g_object_unref(agent->proxy); + agent->proxy = NULL; + } + + if (agent->bus) { + dbus_g_connection_unref(agent->bus); + agent->bus = NULL; + } + + + G_OBJECT_CLASS(bluetooth_pb_agent_parent_class)->finalize(obj); +} + +static void bluetooth_pb_agent_clear(BluetoothPbAgent *agent) +{ + DBG("+\n"); + + if (agent->contact_list) { + g_hash_table_destroy(agent->contact_list); + agent->contact_list = NULL; + } + + agent->pb_type = TELECOM_NONE; +} + +static gboolean bluetooth_pb_get_phonebook_folder_list(BluetoothPbAgent *agent, + const gchar ***folder_list, + GError **error) +{ + gint size; + gint i; + gchar **folder; + + size = G_N_ELEMENTS(bluetooth_pb_agent_folder_list); + folder = g_new0(gchar *, size); + + for (i = 0; i < size; i++) + folder[i] = g_strdup(bluetooth_pb_agent_folder_list[i]); + + *folder_list = (const gchar **)folder; + + return TRUE; +} + +static gboolean bluetooth_pb_get_phonebook(BluetoothPbAgent *agent, + const char *name, + guint64 filter, + guint8 format, + guint16 max_list_count, + guint16 list_start_offset, + DBusGMethodInvocation *context) +{ + PhoneBookType pb_type = TELECOM_NONE; + GPtrArray *vcards = NULL; + gchar **vcards_str = NULL; + + guint new_missed_call = 0; + + DBG("name: %s filter: %lld format: %d max_list_count: %d list_start_offset: %d\n", + name, filter, format, max_list_count, list_start_offset); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + pb_type = __bluetooth_pb_get_pb_type(name); + + if (pb_type == TELECOM_NONE) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + vcards = g_ptr_array_new(); + + if (max_list_count > 0) { + __bluetooth_pb_get_vcards(agent, pb_type, + filter, format, + max_list_count, list_start_offset, + vcards); + + } + + g_ptr_array_add(vcards, NULL); + + vcards_str = (gchar **) g_ptr_array_free(vcards, FALSE); + + dbus_g_method_return(context, vcards_str, new_missed_call); + + g_strfreev(vcards_str); + + return TRUE; +} + +static gboolean bluetooth_pb_get_phonebook_size(BluetoothPbAgent *agent, + const char *name, + DBusGMethodInvocation *context) +{ + PhoneBookType pb_type = TELECOM_NONE; + + guint new_missed_call = 0; + guint count = 0; + + DBG("name: %s\n", name); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + pb_type = __bluetooth_pb_get_pb_type(name); + + if (__bluetooth_pb_get_count(pb_type, &count) == FALSE) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + /* for owner */ + if (pb_type == TELECOM_PB) + count++; + + __bluetooth_pb_get_count_new_missed_call(&new_missed_call); + + dbus_g_method_return(context, count, new_missed_call); + + return TRUE; +} + + +static gboolean bluetooth_pb_get_phonebook_list(BluetoothPbAgent *agent, + const char *name, + DBusGMethodInvocation *context) +{ + PhoneBookType pb_type = TELECOM_NONE; + + GPtrArray *ptr_array; + + DBG("name: %s\n", name); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + pb_type = __bluetooth_pb_get_pb_type(name); + + if (pb_type == TELECOM_NONE) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + ptr_array = g_ptr_array_new_with_free_func(__bluetooth_pb_list_ptr_array_free); + + __bluetooth_pb_get_list(agent, pb_type, ptr_array); + + dbus_g_method_return(context, ptr_array); + + if (ptr_array) + g_ptr_array_free(ptr_array, TRUE); + + return TRUE; +} + + +static gboolean bluetooth_pb_get_phonebook_entry(BluetoothPbAgent *agent, + const gchar *folder, + const gchar *id, + guint64 filter, + guint8 format, + DBusGMethodInvocation *context) +{ + PhoneBookType pb_type = TELECOM_NONE; + + gint handle = 0; + gint cid = -1; + gchar *str = NULL; + + const gchar *attr = NULL; + + DBG("folder: %s id: %s filter: %ld format: %d\n", + folder, id, filter, format); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + if (!g_str_has_suffix(id, ".vcf")) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "invalid vcf file"); + return FALSE; + } + + handle = (gint)g_ascii_strtoll(id, NULL, 10); + + pb_type = __bluetooth_pb_get_pb_type(folder); + + if (pb_type == TELECOM_NONE) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + /* create index cache */ + __bluetooth_pb_get_list(agent, pb_type, NULL); + + cid = __bluetooth_pb_list_hash_lookup_id(agent, handle); + + switch(pb_type) { + case TELECOM_PB: + if (handle == 0) { + str = _bluetooth_pb_vcard_contact_owner(agent->tel_number, + filter, format); + } else { + str = _bluetooth_pb_vcard_contact(cid, filter, format); + } + break; + case TELECOM_ICH: + str = _bluetooth_pb_vcard_call(cid, filter, format, "RECEIVED"); + break; + case TELECOM_OCH: + str = _bluetooth_pb_vcard_call(cid, filter, format, "DIALED"); + break; + case TELECOM_MCH: + str = _bluetooth_pb_vcard_call(cid, filter, format, "MISSED"); + break; + case TELECOM_CCH: { + contacts_record_h record = NULL; + + gint status; + + status = contacts_db_get_record(_contacts_phone_log._uri, + cid, &record); + + if (status != CONTACTS_ERROR_NONE) + break; + + attr = __bluetooth_pb_phone_log_get_log_type(record); + str = _bluetooth_pb_vcard_call(cid, filter, format, attr); + + contacts_record_destroy(record, TRUE); + break; + } + default: + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + dbus_g_method_return(context, str); + g_free(str); + + return TRUE; +} + +static gboolean bluetooth_pb_get_phonebook_size_at(BluetoothPbAgent *agent, + const gchar *command, + DBusGMethodInvocation *context) +{ + PhoneBookType pb_type = TELECOM_NONE; + guint count = 0; + + DBG("command: %s\n", command); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + pb_type = __bluetooth_pb_get_storage_pb_type(command); + + if (__bluetooth_pb_get_count(pb_type, &count) == FALSE) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + dbus_g_method_return(context, count); + + return TRUE; +} + +static gboolean bluetooth_pb_get_phonebook_entries_at(BluetoothPbAgent *agent, + const gchar *command, + gint start_index, + gint end_index, + DBusGMethodInvocation *context) +{ + PhoneBookType pb_type = TELECOM_NONE; + + GPtrArray *ptr_array = NULL; + + DBG("command: %s, start_index: %d, end_index: %d\n", + command, start_index, end_index); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + pb_type = __bluetooth_pb_get_storage_pb_type(command); + + if (pb_type == TELECOM_NONE || pb_type == TELECOM_CCH) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + ptr_array = g_ptr_array_new_with_free_func(__bluetooth_pb_list_ptr_array_free); + + __bluetooth_pb_get_list_number(agent, pb_type, + start_index, end_index, + ptr_array); + + dbus_g_method_return(context, ptr_array); + + if (ptr_array) + g_ptr_array_free(ptr_array, TRUE); + + return TRUE; +} + +static gboolean bluetooth_pb_get_phonebook_entries_find_at(BluetoothPbAgent *agent, + const gchar *command, + const gchar *find_text, + DBusGMethodInvocation *context) +{ + PhoneBookType pb_type = TELECOM_NONE; + + GPtrArray *ptr_array = NULL; + + DBG("command: %s, find text: %s\n", command, find_text); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + pb_type = __bluetooth_pb_get_storage_pb_type(command); + + if (pb_type == TELECOM_NONE || pb_type == TELECOM_CCH) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + ptr_array = g_ptr_array_new_with_free_func(__bluetooth_pb_list_ptr_array_free); + + __bluetooth_pb_get_list_name(agent, pb_type, + find_text, ptr_array); + + dbus_g_method_return(context, ptr_array); + + if (ptr_array) + g_ptr_array_free(ptr_array, TRUE); + + return TRUE; +} + +static gboolean bluetooth_pb_get_total_object_count(BluetoothPbAgent *agent, + gchar *path, DBusGMethodInvocation *context) +{ + guint count = 0; + PhoneBookType pb_type = TELECOM_NONE; + + DBG("%s() %d\n", __FUNCTION__, __LINE__); + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + pb_type = __bluetooth_pb_get_storage_pb_type(path); + + if (__bluetooth_pb_get_count(pb_type, &count) == FALSE) { + __bluetooth_pb_dbus_return_error(context, + G_FILE_ERROR_INVAL, + "unsupported name defined"); + return FALSE; + } + + dbus_g_method_return(context, count); + + DBG("%s() %d\n", __FUNCTION__, __LINE__); + + return TRUE; +} + + +#if 0 +static int __bluetooth_pb_agent_read_file(const char *file_path, char **stream) +{ + FILE *fp = NULL; + int read_len = -1; + int received_file_size = 0; + struct stat file_attr; + + if (file_path == NULL || stream == NULL) { + DBG("Invalid data \n"); + return -1; + } + + DBG("file_path = %s\n", file_path); + + if ((fp = fopen(file_path, "r+")) == NULL) { + DBG("Cannot open %s\n", file_path); + return -1; + } + + if (fstat(fileno(fp), &file_attr) == 0) { + received_file_size = file_attr.st_size; + DBG("file_attr.st_size = %d, size = %d\n", file_attr.st_size, received_file_size); + + if (received_file_size <= 0) { + DBG("Some problem in the file size [%s] \n", file_path); + fclose(fp); + fp = NULL; + return -1; + } + + *stream = (char *)malloc(sizeof(char) * received_file_size); + if (NULL == *stream) { + fclose(fp); + fp = NULL; + return -1; + } + } else { + DBG("Some problem in the file [%s] \n", file_path); + fclose(fp); + fp = NULL; + return -1; + } + + read_len = fread(*stream, 1, received_file_size, fp); + + if (read_len == 0) { + if (fp != NULL) { + fclose(fp); + fp = NULL; + } + DBG("Cannot open %s\n", file_path); + return -1; + } + + if (fp != NULL) { + fclose(fp); + fp = NULL; + } + return 0; +} +#endif + +static gboolean bluetooth_pb_add_contact(BluetoothPbAgent *agent, const char *filename, + GError **error) +{ + /* Contact API is changed, Temporary blocked */ +#if 0 + CTSstruct *contact_record = NULL; + GSList *numbers_list = NULL, *cursor; + int is_success = 0; + int is_duplicated = 0; + int err = 0; + char *stream = NULL; + + DBG("file_path = %s\n", filename); + + err = contacts_svc_connect(); + DBG("contact_db_service_connect fucntion call [error] = %d \n", err); + + err = __bluetooth_pb_agent_read_file(filename, &stream); + + if (err != 0) { + contacts_svc_disconnect(); + DBG("contacts_svc_disconnect fucntion call [error] = %d \n", err); + + if (NULL != stream) { + free(stream); + stream = NULL; + } + return FALSE; + } + + is_success = contacts_svc_get_contact_from_vcard((const void *)stream, &contact_record); + + DBG("contacts_svc_get_contact_from_vcard fucntion call [is_success] = %d \n", is_success); + + if (0 == is_success) { + contacts_svc_struct_get_list(contact_record, CTS_CF_NUMBER_LIST, &numbers_list); + cursor = numbers_list; + + for (; cursor; cursor = g_slist_next(cursor)) { + if (contacts_svc_find_contact_by(CTS_FIND_BY_NUMBER, + contacts_svc_value_get_str(cursor->data, + CTS_NUM_VAL_NUMBER_STR)) > 0) { + DBG("is_duplicated\n"); + is_duplicated = TRUE; + } + } + + if (is_duplicated == FALSE) { + contacts_svc_insert_contact(0, contact_record); + } + } else { + DBG("Fail \n"); + } + + err = contacts_svc_disconnect(); + DBG("contacts_svc_disconnect fucntion call [error] = %d \n", err); + + if (NULL != stream) { + free(stream); + stream = NULL; + } +#endif + + return TRUE; +} + +static void __bluetooth_pb_dbus_return_error(DBusGMethodInvocation *context, + gint code, + const gchar *message) +{ + GQuark quark; + GError *error = NULL; + + quark = g_type_qname(bluetooth_pb_agent_get_type()); + error = g_error_new_literal(quark, code, message); + + DBG("%s\n", message); + + dbus_g_method_return_error(context, error); + g_error_free(error); +} + +static PhoneBookType __bluetooth_pb_get_pb_type(const char *name) +{ + gchar *suffix = ".vcf"; + gint len; + gint size; + gint i; + + if (name == NULL) + return TELECOM_NONE; + + len = strlen(name); + + if (g_str_has_suffix(name, suffix)) + len -= strlen(suffix); + + size = G_N_ELEMENTS(bluetooth_pb_agent_folder_list) - 1; + for (i = 0; i < size; i++) { + if (strncmp(name, bluetooth_pb_agent_folder_list[i], len) == 0) + return i; + } + + return TELECOM_NONE; +} + +static PhoneBookType __bluetooth_pb_get_storage_pb_type(const char *name) +{ + if (name == NULL) + return TELECOM_NONE; + + if (g_strcmp0(name, "\"ME\"") == 0 ) + return TELECOM_PB; + + if (g_strcmp0(name, "\"RC\"") == 0) + return TELECOM_ICH; + + if (g_strcmp0(name, "\"DC\"") == 0) + return TELECOM_OCH; + + if (g_strcmp0(name, "\"MC\"") == 0) + return TELECOM_MCH; + + return TELECOM_NONE; +} + +static gint __bluetooth_pb_phone_log_filter_append(contacts_filter_h filter, + gint *match, + gint size) +{ + gint i; + gint status; + + for (i = 0; i < size; i++) { + + if ( i > 0) { + status = contacts_filter_add_operator(filter, + CONTACTS_FILTER_OPERATOR_OR); + + if (status != CONTACTS_ERROR_NONE) + return status; + } + + status = contacts_filter_add_int(filter, + _contacts_phone_log.log_type, + CONTACTS_MATCH_EQUAL, + match[i]); + + if (status != CONTACTS_ERROR_NONE) + return status; + } + + return CONTACTS_ERROR_NONE; +} + +static contacts_query_h __bluetooth_pb_query_phone_log(gint *match, + gint size) +{ + contacts_query_h query = NULL; + contacts_filter_h filter = NULL; + + gint status; + + status = contacts_query_create(_contacts_phone_log._uri, + &query); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_filter_create(_contacts_phone_log._uri, &filter); + + if (status != CONTACTS_ERROR_NONE) { + contacts_query_destroy(query); + return NULL; + } + + status = __bluetooth_pb_phone_log_filter_append(filter, match, size); + + if (status != CONTACTS_ERROR_NONE) { + contacts_filter_destroy(filter); + contacts_query_destroy(query); + return NULL; + } + + status = contacts_query_set_filter(query, filter); + + if (status != CONTACTS_ERROR_NONE) { + contacts_filter_destroy(filter); + contacts_query_destroy(query); + return NULL; + } + + status = contacts_query_set_sort(query, + _contacts_phone_log.log_time, + false); + + if (status != CONTACTS_ERROR_NONE) { + contacts_filter_destroy(filter); + contacts_query_destroy(query); + return NULL; + } + + contacts_filter_destroy(filter); + + return query; +} + +static contacts_query_h __bluetooth_pb_query_person(void) +{ + contacts_query_h query = NULL; + + gint status; + + status = contacts_query_create(_contacts_person._uri, + &query); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + return query; +} + +static contacts_query_h __bluetooth_pb_query_person_number(void) +{ + contacts_query_h query = NULL; + + gint status; + + status = contacts_query_create(_contacts_person_number._uri, + &query); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + return query; +} + +static contacts_query_h __bluetooth_pb_query_phone_log_incoming(void) +{ + gint size = 2; + gint match[] = { + CONTACTS_PLOG_TYPE_VOICE_INCOMMING, + CONTACTS_PLOG_TYPE_VIDEO_INCOMMING + }; + + return __bluetooth_pb_query_phone_log(match, size); +} + +static contacts_query_h __bluetooth_pb_query_phone_log_outgoing(void) +{ + gint size = 2; + gint match[] = { + CONTACTS_PLOG_TYPE_VOICE_OUTGOING, + CONTACTS_PLOG_TYPE_VIDEO_OUTGOING + }; + + return __bluetooth_pb_query_phone_log(match, size); + +} + +static contacts_query_h __bluetooth_pb_query_phone_log_missed(void) +{ + gint size = 4; + gint match[] = { + CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN, + CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN, + CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN, + CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN + }; + + return __bluetooth_pb_query_phone_log(match, size); +} + +static contacts_query_h __bluetooth_pb_query_phone_log_combined(void) +{ + gint size = 8; + gint match[] = { + CONTACTS_PLOG_TYPE_VOICE_INCOMMING, + CONTACTS_PLOG_TYPE_VIDEO_INCOMMING, + CONTACTS_PLOG_TYPE_VOICE_OUTGOING, + CONTACTS_PLOG_TYPE_VIDEO_OUTGOING, + CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN, + CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN, + CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN, + CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN + }; + + return __bluetooth_pb_query_phone_log(match, size); +} + +static gboolean __bluetooth_pb_get_count(PhoneBookType pb_type, + guint *count) +{ + contacts_query_h query = NULL; + + gint status; + gint signed_count; + + switch (pb_type) { + case TELECOM_PB: + query = __bluetooth_pb_query_person(); + break; + case TELECOM_ICH: + query = __bluetooth_pb_query_phone_log_incoming(); + break; + case TELECOM_OCH: + query = __bluetooth_pb_query_phone_log_outgoing(); + break; + case TELECOM_MCH: + query = __bluetooth_pb_query_phone_log_missed(); + break; + case TELECOM_CCH: + query = __bluetooth_pb_query_phone_log_combined(); + break; + default: + return FALSE; + } + + if (query == NULL) + return FALSE; + + status = contacts_db_get_count_with_query(query, &signed_count); + + if (status != CONTACTS_ERROR_NONE) { + contacts_query_destroy(query); + return FALSE; + } + + contacts_query_destroy(query); + + if (signed_count < 0) + signed_count = 0; + + *count = (gint) signed_count; + + return TRUE; +} + +static gboolean __bluetooth_pb_get_count_new_missed_call(guint *count) +{ + contacts_query_h query = NULL; + + gint status; + gint signed_count; + + gint size = 2; + gint match[] = { + CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN, + CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN + }; + + query = __bluetooth_pb_query_phone_log(match, size); + + if (query == NULL) + return FALSE; + + status = contacts_db_get_count_with_query(query, &signed_count); + + if (status != CONTACTS_ERROR_NONE) { + contacts_query_destroy(query); + return FALSE; + } + + contacts_query_destroy(query); + + if (signed_count < 0) + signed_count = 0; + + *count = (guint)signed_count; + + return TRUE; +} + +static const char *__bluetooth_pb_phone_log_get_log_type(contacts_record_h record) +{ + gint status; + gint log_type; + + status = contacts_record_get_int(record, + _contacts_phone_log.log_type, + &log_type); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + switch (log_type) { + case CONTACTS_PLOG_TYPE_VOICE_INCOMMING: + case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING: + return "RECEIVED"; + case CONTACTS_PLOG_TYPE_VOICE_OUTGOING: + case CONTACTS_PLOG_TYPE_VIDEO_OUTGOING: + return "DIALED"; + case CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN: + case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN: + case CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN: + case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN: + return "MISSED"; + default: + return NULL; + } +} + +static void __bluetooth_pb_get_vcards(BluetoothPbAgent *agent, + PhoneBookType pb_type, + guint64 filter, + guint8 format, + guint16 max_list_count, + guint16 list_start_offset, + GPtrArray *vcards) +{ + contacts_list_h record_list = NULL; + contacts_query_h query = NULL; + + gint status; + + gint limit; + gint offset; + + guint property_id = 0; + + const char *attr = NULL; + + gboolean get_log = FALSE; + + /* contact offset is n - 1 of PBAP */ + offset = (gint)list_start_offset - 1; + + if ( max_list_count >= 65535) + limit = -1; /* contact limit -1 means unrestricted */ + else + limit = (gint)max_list_count; + + switch (pb_type) { + case TELECOM_PB: + /* for owner */ + if (list_start_offset == 0) { + char *vcard; + + vcard = _bluetooth_pb_vcard_contact_owner(agent->tel_number, + filter, format); + if (vcard) + g_ptr_array_add(vcards, vcard); + + offset = 0; + + if (limit > 0) + limit--; + } + + query = __bluetooth_pb_query_person(); + property_id = _contacts_person.id; + break; + case TELECOM_ICH: + query = __bluetooth_pb_query_phone_log_incoming(); + property_id = _contacts_phone_log.id; + attr = "RECEIVED"; + break; + case TELECOM_OCH: + query = __bluetooth_pb_query_phone_log_outgoing(); + property_id = _contacts_phone_log.id; + attr = "DIALED"; + break; + case TELECOM_MCH: + query = __bluetooth_pb_query_phone_log_missed(); + property_id = _contacts_phone_log.id; + attr = "MISSED"; + break; + case TELECOM_CCH: + query = __bluetooth_pb_query_phone_log_combined(); + property_id = _contacts_phone_log.id; + get_log = TRUE; + break; + default: + return; + } + + status = contacts_db_get_records_with_query(query, offset, limit, &record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_query_destroy(query); + return; + } + + status = contacts_list_first(record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + contacts_query_destroy(query); + return; + } + + do { + contacts_record_h record; + + gint id; + + gchar *vcard = NULL; + + record = NULL; + status = contacts_list_get_current_record_p(record_list, &record); + + if (status != CONTACTS_ERROR_NONE) + continue; + id = 0; + status = contacts_record_get_int(record, property_id, &id); + + if (status != CONTACTS_ERROR_NONE) + continue; + + if (property_id == _contacts_person.id) + vcard = _bluetooth_pb_vcard_contact(id, filter, format); + else { + if (get_log) + attr = __bluetooth_pb_phone_log_get_log_type(record); + + vcard = _bluetooth_pb_vcard_call(id, filter, format, attr); + } + + if (vcard) + g_ptr_array_add(vcards, vcard); + + } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE); + + contacts_list_destroy(record_list, TRUE); + contacts_query_destroy(query); +} + +static void __bluetooth_pb_get_contact_list(BluetoothPbAgent *agent, + contacts_query_h query, + GPtrArray *ptr_array) +{ + contacts_list_h record_list = NULL; + + gint status; + int i = 1; + + /* Add owner */ + if (ptr_array) { + gchar *tmp; + gchar *name; + + tmp = _bluetooth_pb_owner_name(); + name = g_strdup_printf("%s;;;;", tmp); + g_free(tmp); + + __bluetooth_pb_list_ptr_array_add(ptr_array, + name, agent->tel_number, 0); + + g_free(name); + } + + status = contacts_db_get_records_with_query(query, + -1, -1, &record_list); + + if (status != CONTACTS_ERROR_NONE) + return; + + status = contacts_list_first(record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + contacts_query_destroy(query); + return; + } + + __bluetooth_pb_list_hash_reset(agent); + + do { + contacts_record_h record; + + gint id; + + record = NULL; + status = contacts_list_get_current_record_p(record_list, + &record); + + if (status != CONTACTS_ERROR_NONE) + continue; + + id = 0; + status = contacts_record_get_int(record, + _contacts_person.id, + &id); + + if (status != CONTACTS_ERROR_NONE) + continue; + + __bluetooth_pb_list_hash_insert(agent, i, id); + + /* create list */ + if (ptr_array) { + gchar *name; + gchar *number; + + name = _bluetooth_pb_name_from_person_id(id); + number = _bluetooth_pb_number_from_person_id(id); + + __bluetooth_pb_list_ptr_array_add(ptr_array, + name, number, i); + + g_free(name); + g_free(number); + } + + i++; + + } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE); + + contacts_list_destroy(record_list, TRUE); +} + +static void __bluetooth_pb_get_phone_log_list(BluetoothPbAgent *agent, + contacts_query_h query, + GPtrArray *ptr_array) +{ + contacts_list_h record_list = NULL; + + gint status; + int i = 1; + + status = contacts_db_get_records_with_query(query, + -1, -1, &record_list); + + if (status != CONTACTS_ERROR_NONE) + return; + + status = contacts_list_first(record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + contacts_query_destroy(query); + return; + } + + __bluetooth_pb_list_hash_reset(agent); + + do { + contacts_record_h record; + + gint id; + + record = NULL; + status = contacts_list_get_current_record_p(record_list, + &record); + + if (status != CONTACTS_ERROR_NONE) + continue; + + id = 0; + status = contacts_record_get_int(record, + _contacts_phone_log.id, + &id); + + if (status != CONTACTS_ERROR_NONE) + continue; + + __bluetooth_pb_list_hash_insert(agent, i, id); + + /* create list */ + if (ptr_array) { + gchar *name; + gchar *number; + + name = _bluetooth_pb_name_from_phonelog_id(id); + + number = NULL; + contacts_record_get_str_p(record, + _contacts_phone_log.address, + &number); + + __bluetooth_pb_list_ptr_array_add(ptr_array, + name, number, i); + + g_free(name); + } + + i++; + + } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE); + + contacts_list_destroy(record_list, TRUE); +} + + +static void __bluetooth_pb_get_list(BluetoothPbAgent *agent, + PhoneBookType pb_type, + GPtrArray *ptr_array) +{ + contacts_query_h query; + + /* no requires refresh cache */ + if (ptr_array == NULL && agent->pb_type == pb_type) + return; + + switch (pb_type) { + case TELECOM_PB: + query = __bluetooth_pb_query_person(); + __bluetooth_pb_get_contact_list(agent, query, ptr_array); + break; + case TELECOM_ICH: + query = __bluetooth_pb_query_phone_log_incoming(); + __bluetooth_pb_get_phone_log_list(agent, query, ptr_array); + break; + case TELECOM_OCH: + query = __bluetooth_pb_query_phone_log_outgoing(); + __bluetooth_pb_get_phone_log_list(agent, query, ptr_array); + break; + case TELECOM_MCH: + query = __bluetooth_pb_query_phone_log_missed(); + __bluetooth_pb_get_phone_log_list(agent, query, ptr_array); + break; + case TELECOM_CCH: + query = __bluetooth_pb_query_phone_log_combined(); + __bluetooth_pb_get_phone_log_list(agent, query, ptr_array); + break; + default: + return; + } + + agent->pb_type = pb_type; + + if (query) + contacts_query_destroy(query); +} + +static void __bluetooth_pb_get_contact_list_number(BluetoothPbAgent *agent, + contacts_query_h query, + gint start_index, + gint end_index, + GPtrArray *ptr_array) +{ + contacts_list_h record_list = NULL; + + gint status; + + gint i; + + gint from; + gint to; + gint offset; + + from = start_index; + to = end_index; + + if (from < 1) + from = 1; + + if (to < 1) + to = 1; + + offset = to - from + 1; + if (offset <= 0) + return; + + i = from; + + status = contacts_db_get_records_with_query(query, + from - 1 , offset, + &record_list); + + if (status != CONTACTS_ERROR_NONE) + return; + + status = contacts_list_first(record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + return; + } + + do { + contacts_record_h record; + + gchar *display_name; + gchar *number; + + record = NULL; + status = contacts_list_get_current_record_p(record_list, + &record); + + if (status != CONTACTS_ERROR_NONE) + continue; + + display_name = NULL; + number = NULL; + + contacts_record_get_str_p(record, + _contacts_person_number.display_name, + &display_name); + contacts_record_get_str_p(record, + _contacts_person_number.number, + &number); + + __bluetooth_pb_list_ptr_array_add(ptr_array, + display_name, number, i); + + i++; + } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE); + + contacts_list_destroy(record_list, TRUE); +} + +static void __bluetooth_pb_get_phone_log_list_number(BluetoothPbAgent *agent, + contacts_query_h query, + gint start_index, + gint end_index, + GPtrArray *ptr_array) +{ + contacts_list_h record_list = NULL; + + gint status; + + gint i; + + gint from; + gint to; + gint offset; + + from = start_index; + to = end_index; + + if (from < 1) + from = 1; + + if (to < 1) + to = 1; + + offset = to - from + 1; + if (offset <= 0) + return; + + i = from; + + status = contacts_db_get_records_with_query(query, + from - 1 , offset, + &record_list); + + if (status != CONTACTS_ERROR_NONE) + return; + + status = contacts_list_first(record_list); + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + return; + } + + do { + contacts_record_h record = NULL; + + gint id; + + gchar *display_name; + gchar *number; + + record = NULL; + status = contacts_list_get_current_record_p(record_list, + &record); + + if (status != CONTACTS_ERROR_NONE) + continue; + + id = 0; + status = contacts_record_get_int(record, + _contacts_phone_log.id, + &id); + + display_name = _bluetooth_pb_fn_from_phonelog_id(id); + + number = NULL; + contacts_record_get_str_p(record, + _contacts_phone_log.address, + &number); + + + __bluetooth_pb_list_ptr_array_add(ptr_array, + display_name, number, i); + + i++; + + g_free(display_name); + + } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE); + + contacts_list_destroy(record_list, TRUE); +} + +static void __bluetooth_pb_get_list_number(BluetoothPbAgent *agent, + PhoneBookType pb_type, + gint start_index, + gint end_index, + GPtrArray *ptr_array) +{ + contacts_query_h query; + + switch (pb_type) { + case TELECOM_PB: + query = __bluetooth_pb_query_person_number(); + __bluetooth_pb_get_contact_list_number(agent, query, + start_index, end_index, ptr_array); + break; + case TELECOM_ICH: + query = __bluetooth_pb_query_phone_log_incoming(); + __bluetooth_pb_get_phone_log_list_number(agent, query, + start_index, end_index, ptr_array); + break; + case TELECOM_OCH: + query = __bluetooth_pb_query_phone_log_outgoing(); + __bluetooth_pb_get_phone_log_list_number(agent, query, + start_index, end_index, ptr_array); + break; + case TELECOM_MCH: + query = __bluetooth_pb_query_phone_log_missed(); + __bluetooth_pb_get_phone_log_list_number(agent, query, + start_index, end_index, ptr_array); + break; + case TELECOM_CCH: + query = __bluetooth_pb_query_phone_log_combined(); + __bluetooth_pb_get_phone_log_list_number(agent, query, + start_index, end_index, ptr_array); + break; + default: + return; + } + + if (query) + contacts_query_destroy(query); +} + +static void __bluetooth_pb_get_contact_list_name(BluetoothPbAgent *agent, + contacts_query_h query, + const gchar *find_text, + GPtrArray *ptr_array) +{ + contacts_list_h record_list = NULL; + + gint status; + gint i = 1; + + status = contacts_db_get_records_with_query(query, + -1, -1, &record_list); + + if (status != CONTACTS_ERROR_NONE) + return; + + status = contacts_list_first(record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + return; + } + + do { + contacts_record_h record; + + gchar *display_name; + + record = NULL; + status = contacts_list_get_current_record_p(record_list, + &record); + + if (status != CONTACTS_ERROR_NONE) + continue; + + display_name = NULL; + contacts_record_get_str_p(record, + _contacts_person_number.display_name, + &display_name); + + if (g_str_has_prefix(display_name, find_text)) { + gchar *number; + + number = NULL; + contacts_record_get_str_p(record, + _contacts_person_number.number, + &number); + + __bluetooth_pb_list_ptr_array_add(ptr_array, + display_name, number, i); + } + + i++; + } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE); +} + +static void __bluetooth_pb_get_phone_log_list_name(BluetoothPbAgent *agent, + contacts_query_h query, + const gchar *find_text, + GPtrArray *ptr_array) +{ + contacts_list_h record_list = NULL; + + gint status; + + gint i = 1; + + status = contacts_db_get_records_with_query(query, + -1, -1, + &record_list); + + if (status != CONTACTS_ERROR_NONE) + return; + + status = contacts_list_first(record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + return; + } + + do { + contacts_record_h record = NULL; + + gint id; + + gchar *display_name; + + record = NULL; + status = contacts_list_get_current_record_p(record_list, + &record); + + if (status != CONTACTS_ERROR_NONE) + continue; + + id = 0; + status = contacts_record_get_int(record, + _contacts_phone_log.id, + &id); + + display_name = _bluetooth_pb_fn_from_phonelog_id(id); + + if (g_str_has_prefix(display_name, find_text)) { + gchar *number = NULL; + + number = NULL; + contacts_record_get_str_p(record, + _contacts_phone_log.address, + &number); + + __bluetooth_pb_list_ptr_array_add(ptr_array, + display_name, number, i); + } + + i++; + + g_free(display_name); + + } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE); + + contacts_list_destroy(record_list, TRUE); +} + +static void __bluetooth_pb_get_list_name(BluetoothPbAgent *agent, + PhoneBookType pb_type, + const gchar *find_text, + GPtrArray *ptr_array) +{ + contacts_query_h query; + + switch (pb_type) { + case TELECOM_PB: + query = __bluetooth_pb_query_person_number(); + __bluetooth_pb_get_contact_list_name(agent, query, + find_text, ptr_array); + break; + case TELECOM_ICH: + query = __bluetooth_pb_query_phone_log_incoming(); + __bluetooth_pb_get_phone_log_list_name(agent, query, + find_text, ptr_array); + break; + case TELECOM_OCH: + query = __bluetooth_pb_query_phone_log_outgoing(); + __bluetooth_pb_get_phone_log_list_name(agent, query, + find_text, ptr_array); + break; + case TELECOM_MCH: + query = __bluetooth_pb_query_phone_log_missed(); + __bluetooth_pb_get_phone_log_list_name(agent, query, + find_text, ptr_array); + break; + case TELECOM_CCH: + query = __bluetooth_pb_query_phone_log_combined(); + __bluetooth_pb_get_phone_log_list_name(agent, query, + find_text, ptr_array); + break; + default: + return; + } + + if (query) + contacts_query_destroy(query); +} + +static void __bluetooth_pb_list_hash_reset(BluetoothPbAgent *agent) +{ + if(agent->contact_list) + g_hash_table_destroy(agent->contact_list); + + agent->contact_list = g_hash_table_new(g_direct_hash, g_direct_equal); +} + +static gboolean __bluetooth_pb_list_hash_insert(BluetoothPbAgent *agent, + gint handle, + gint id) +{ + if (agent->contact_list == NULL) + return FALSE; + + g_hash_table_insert(agent->contact_list, + GINT_TO_POINTER(handle), GINT_TO_POINTER(id)); + + return TRUE; +} + +static gint __bluetooth_pb_list_hash_lookup_id(BluetoothPbAgent *agent, + gint handle) +{ + gint id; + + if (agent->contact_list == NULL) + return 0; + + id = GPOINTER_TO_INT(g_hash_table_lookup(agent->contact_list, + GINT_TO_POINTER(handle))); + + return id; +} + +static void __bluetooth_pb_list_ptr_array_add(GPtrArray *ptr_array, + const gchar *name, + const gchar *number, + gint handle) +{ + GValue value = { 0, }; + + g_value_init(&value, DBUS_STRUCT_STRING_STRING_UINT); + g_value_take_boxed(&value, + dbus_g_type_specialized_construct(DBUS_STRUCT_STRING_STRING_UINT)); + + dbus_g_type_struct_set(&value, + 0, g_strdup(name), + 1, g_strdup(number), + 2, handle, + G_MAXUINT); + + g_ptr_array_add(ptr_array, g_value_get_boxed(&value)); +} + +static void __bluetooth_pb_list_ptr_array_free(gpointer data) +{ + GValue value = { 0, }; + + gchar *name = NULL; + gchar *number = NULL; + + if(data == NULL) + return; + + g_value_init(&value, DBUS_STRUCT_STRING_STRING_UINT); + g_value_set_boxed(&value, data); + + dbus_g_type_struct_get(&value, + 0, &name, + 1, &number, + G_MAXUINT); + + g_free(name); + g_free(number); +} + +static void __bluetooth_pb_agent_signal_handler(int signum) +{ + if (mainloop) + g_main_loop_quit(mainloop); + else + exit(0); +} + + +static void __bluetooth_pb_contact_changed(const gchar *view_uri, + void *user_data) +{ + BluetoothPbAgent *agent; + + g_return_if_fail(BLUETOOTH_IS_PB_AGENT(user_data)); + agent = BLUETOOTH_PB_AGENT(user_data); + + g_signal_emit(agent, signals[CLEAR], 0); + g_object_unref(agent); +} + +static void __bluetooth_pb_agent_timeout_add_seconds(BluetoothPbAgent *agent) +{ + g_return_if_fail(BLUETOOTH_IS_PB_AGENT(agent)); + + if(agent->timeout_id) + g_source_remove(agent->timeout_id); + + agent->timeout_id = g_timeout_add_seconds(BLUETOOTH_PB_AGENT_TIMEOUT, + __bluetooth_pb_agent_timeout_calback, + agent); +} + +static gboolean __bluetooth_pb_agent_timeout_calback(gpointer user_data) +{ + BluetoothPbAgent *agent; + + g_return_val_if_fail(BLUETOOTH_IS_PB_AGENT(user_data), FALSE); + + agent = BLUETOOTH_PB_AGENT(user_data); + agent->timeout_id = 0; + + if (mainloop) + g_main_loop_quit(mainloop); + + return FALSE; +} + +static void __bluetooth_pb_tel_callback(TapiHandle *handle, + int result, + void *data, + void *user_data) +{ + BluetoothPbAgent *agent; + TelSimMsisdnList_t *number; + + g_return_if_fail(BLUETOOTH_IS_PB_AGENT(user_data)); + + agent = BLUETOOTH_PB_AGENT(user_data); + + __bluetooth_pb_agent_dbus_init(agent); + + number = (TelSimMsisdnList_t *)data; + agent->tel_number = g_strdup(number->list[0].num); + + tel_deinit(agent->tapi_handle); + agent->tapi_handle = NULL; +} + +static void __bluetooth_pb_agent_dbus_init(BluetoothPbAgent *agent) +{ + guint result = 0; + GError *error = NULL; + + agent->bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); + + if (error != NULL) { + DBG("Couldn't connect to system bus[%s]\n", error->message); + g_error_free(error); + return; + } + + agent->proxy = dbus_g_proxy_new_for_name(agent->bus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + if (agent->proxy == NULL) { + DBG("Failed to get a proxy for D-Bus\n"); + return; + } + + if (!dbus_g_proxy_call(agent->proxy, + "RequestName", &error, + G_TYPE_STRING, BT_PB_SERVICE_NAME, + G_TYPE_UINT, 0, + G_TYPE_INVALID, + G_TYPE_UINT, &result, + G_TYPE_INVALID)) { + if (error != NULL) { + DBG("RequestName RPC failed[%s]\n", error->message); + g_error_free(error); + } + + g_object_unref(agent->proxy); + agent->proxy = NULL; + + return; + } + DBG("result : %d %d\n", result, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + DBG("Failed to get the primary well-known name.\n"); + + g_object_unref(agent->proxy); + agent->proxy = NULL; + + return; + } + + g_object_unref(agent->proxy); + agent->proxy = NULL; + + dbus_g_connection_register_g_object(agent->bus, + BT_PB_SERVICE_OBJECT_PATH, + G_OBJECT(agent)); +} + +int main(int argc, char **argv) +{ + BluetoothPbAgent *agent; + + gint ret = EXIT_SUCCESS; + gint tapi_result; + + struct sigaction sa; + + g_type_init(); + + mainloop = g_main_loop_new(NULL, FALSE); + if (mainloop == NULL) { + DBG("Couldn't create GMainLoop\n"); + return EXIT_FAILURE; + } + + agent = g_object_new(BLUETOOTH_PB_TYPE_AGENT, NULL); + + /* connect contact */ + if (contacts_connect2() != CONTACTS_ERROR_NONE) { + DBG("Can not connect contacts server\n"); + g_object_unref(agent); + return EXIT_FAILURE; + } + + if (contacts_db_add_changed_cb(_contacts_event._uri, + __bluetooth_pb_contact_changed, + g_object_ref(agent)) != CONTACTS_ERROR_NONE) { + DBG("Can not add changed callback"); + } + + /* set signal */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = __bluetooth_pb_agent_signal_handler; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + /* init tapi */ + agent->tapi_handle = tel_init(NULL); + tapi_result = tel_get_sim_msisdn(agent->tapi_handle, + __bluetooth_pb_tel_callback, agent); + + if (tapi_result != TAPI_API_SUCCESS) { + __bluetooth_pb_agent_dbus_init(agent); + } + + + __bluetooth_pb_agent_timeout_add_seconds(agent); + + g_main_loop_run(mainloop); + + DBG("Terminate the bluetooth-pb-agent\n"); + + if (agent) { + contacts_db_remove_changed_cb(_contacts_event._uri, + __bluetooth_pb_contact_changed, + g_object_ref(agent)); + + g_object_unref(agent); + } + + + contacts_disconnect2(); + + g_signal_emit(agent, signals[CLEAR], 0); + + if (agent) + g_object_unref(agent); + + return ret; +} diff --git a/pb-agent/bluetooth_pb_agent.h b/pb-agent/bluetooth_pb_agent.h new file mode 100644 index 0000000..515170b --- /dev/null +++ b/pb-agent/bluetooth_pb_agent.h @@ -0,0 +1,40 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#ifndef __DEF_BT_PB_AGENT_H_ +#define __DEF_BT_PB_AGENT_H_ + +#include +#include + +#include + +#include + +#define BT_PB_SERVICE_OBJECT_PATH "/org/bluez/pb_agent" +#define BT_PB_SERVICE_NAME "org.bluez.pb_agent" +#define BT_PB_SERVICE_INTERFACE "org.bluez.PbAgent" + +#undef LOG_TAG +#define LOG_TAG "BLUETOOTH_AGENT_PHONEBOOK" + +#define DBG(fmt, args...) SLOGD(fmt, ##args) +#define ERR(fmt, args...) SLOGE(fmt, ##args) + +#endif /* __DEF_BT_AGENT_H_ */ diff --git a/pb-agent/bluetooth_pb_agent.xml b/pb-agent/bluetooth_pb_agent.xml new file mode 100644 index 0000000..f41836c --- /dev/null +++ b/pb-agent/bluetooth_pb_agent.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pb-agent/bluetooth_pb_vcard.c b/pb-agent/bluetooth_pb_vcard.c new file mode 100644 index 0000000..c17dc44 --- /dev/null +++ b/pb-agent/bluetooth_pb_vcard.c @@ -0,0 +1,2430 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#include +#include +#include + + +#include +#include + +#include +#include +#include + +#include "bluetooth_pb_vcard.h" + +#define BT_PB_AGENT "BT_PB_AGENT" +#define DBG(fmt, args...) SLOG(LOG_DEBUG, BT_PB_AGENT, "%s():%d "fmt, __func__, __LINE__, ##args) +#define ERR(fmt, args...) SLOG(LOG_ERROR, BT_PB_AGENT, "%s():%d "fmt, __func__, __LINE__, ##args) + +#define VCARD_FORMAT_2_1 0x0 +#define VCARD_FORMAT_3_0 0x1 + +#define VCARD_VERSION (0x1) +#define VCARD_FN (0x1 << 1) +#define VCARD_N (0x1 << 2) +#define VCARD_PHOTO (0x1 << 3) +#define VCARD_BDAY (0x1 << 4) +#define VCARD_ADR (0x1 << 5) +#define VCARD_LABEL (0x1 << 6) /* not supported */ +#define VCARD_TEL (0x1 << 7) +#define VCARD_EMAIL (0x1 << 8) +#define VCARD_MAILER (0x1 << 9) /* not supported */ +#define VCARD_TZ (0x1 << 10) /* not supported */ +#define VCARD_GEO (0x1 << 11) /* not supported */ +#define VCARD_TITLE (0x1 << 12) +#define VCARD_ROLE (0x1 << 13) +#define VCARD_LOGO (0x1 << 14) /* not supported */ +#define VCARD_AGENT (0x1 << 15) /* not supported */ +#define VCARD_ORG (0x1 << 16) +#define VCARD_NOTE (0x1 << 17) +#define VCARD_REV (0x1 << 18) +#define VCARD_SOUND (0x1 << 19) /* not supported */ +#define VCARD_URL (0x1 << 20) +#define VCARD_UID (0x1 << 21) +#define VCARD_KEY (0x1 << 22) /* not supported */ +#define VCARD_NICKNAME (0x1 << 23) +#define VCARD_CATEGORIES (0x1 << 24) /* not supported */ +#define VCARD_PROID (0x1 << 25) /* not supported */ +#define VCARD_CLASS (0x1 << 26) /* not supported */ +#define VCARD_SORT_STRING (0x1 << 27) /* not supported */ + +#define VCARD_X_IRMC_CALL_DATETIME (0x1 << 28) + +#define QP_ENC_LEN 3 +#define LINEBREAK_LEN 75 + +static gchar *__bluetooth_pb_vcard_escape(const gchar *str); + +static gchar *__bluetooth_pb_vcard_strv_concat(gchar **strv, + const gchar *delimeter); + +static gboolean __bluetooth_pb_vcard_qp_encode_check(const gchar *str); + +static gint __bluetooth_pb_vcard_qp_encode_strlen(const gchar *str, + gint len); + +static void __bluetooth_pb_vcard_qp_encode_append_to_hex(GString *string, + const gchar *str, + gint len, + gint *line_pos); + +static void __bluetooth_pb_vcard_qp_encode_append_printable_c(GString *string, + gchar ch, + gint *line_pos); + +static void __bluetooth_pb_vcard_qp_encode_append(GString *string, + const gchar *str, + gint len, + gint *line_pos); + +static gchar *__bluetooth_pb_vcard_qp_encode(const gchar *str); + +static void __bluetooth_pb_vcard_append_param_v21(GString *string, + const gchar *param); + +static void __bluetooth_pb_vcard_append_qp_encode_v21(GString *string, + const gchar *name, + const gchar *param, + const gchar *value); + +static void __bluetooth_pb_vcard_append_base64_encode_v21(GString *string, + const gchar *name, + const gchar *param, + const gchar *value, + gsize len, + gboolean folding); + +static void __bluetooth_pb_vcard_append_n_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_tel_v21(GString *string, + contacts_record_h conatct); + +static void __bluetooth_pb_vcard_append_fn_v21(GString *string, + contacts_record_h person); + +static void __bluetooth_pb_vcard_append_photo_v21(GString *string, + contacts_record_h person); + +static void __bluetooth_pb_vcard_append_bday_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_adr_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_email_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_title_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_role_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_org_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_note_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_rev_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_url_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_uid_v21(GString *string, + contacts_record_h contact); + +static void __bluetooth_pb_vcard_append_v30(GString *string, + const gchar *name, + const gchar *param, + const gchar *value); + +static void __bluetooth_pb_vcard_remove_v30(GString *string, + const gchar *property_name); + +static gchar *__bluetooth_pb_vcard_filter_v30(const gchar *vcard, + guint64 filter); + +static gchar *__bluetooth_pb_vcard_real_contact_valist_v21(gint person_id, + gint phonelog_id, + guint64 filter, + const gchar *first_name, + va_list args); + +static gchar *__bluetooth_pb_vcard_real_contact_valist_v30(gint person_id, + gint phonelog_id, + guint64 filter, + const gchar *first_name, + va_list args); + +static gchar *__bluetooth_pb_vcard_real_contact_with_properties(gint person_id, + gint phonelog_id, + guint64 filter, + guint8 format, + const gchar *first_name, + ...); + +static gchar *__bluetooth_pb_vcard_real_call_v21(gint phonelog_id, + guint filter, + const gchar *attr); + +static gchar *__bluetooth_pb_vcard_real_call_v30(gint phonelog_id, + guint filter, + const gchar *attr); + +static gchar *__bluetooth_pb_vcard_real_call(gint phonelog_id, + guint filter, + guint8 format, + const gchar *attr); + +static gchar **__bluetooth_pb_contact_add_field_str(contacts_record_h record, + int *field, + gint field_size); + +static gchar **__bluetooth_pb_contact_tel_param(contacts_record_h number); + +static gchar *__bluetooth_pb_contact_photo_type(const gchar *filename); + +static gchar **__bluetooth_pb_contact_addr(contacts_record_h address); + +static gchar **__bluetooth_pb_contact_addr_param(contacts_record_h address); + +static gchar *__bluetooth_pb_phonelog_datetime(gint phonelog_id); + +static gchar *__bluetooth_pb_name_from_contact(contacts_record_h contact); + +static gchar *__bluetooth_pb_number_from_contact(contacts_record_h contact); + +static gint __bluetooth_pb_person_id_from_phonelog_id(gint phonelog_id); + + +static gchar *__bluetooth_pb_vcard_escape(const gchar *str) +{ + GString *escaped; + + gchar *st = NULL; + gchar *pos = NULL; + + if (str == NULL) + return NULL; + + escaped = g_string_new(NULL); + + st = (gchar *)str; + pos = st; + + while (*pos != '\0') { + if (*pos == ';') { + g_string_append_len(escaped, st, (pos - st)); + g_string_append(escaped, "\\;"); + + pos++; + st = pos; + } + else { + pos++; + } + } + + g_string_append_len(escaped, st, (pos - st)); + return g_string_free(escaped, FALSE); +} + +static gchar *__bluetooth_pb_vcard_strv_concat(gchar **strv, + const gchar *separator) +{ + GString *string = g_string_new(NULL); + gint i; + + for (i = 0; strv[i] != NULL; i++) { + if (i > 0) + g_string_append(string, ";"); + + g_string_append(string, strv[i]); + } + + return g_string_free(string, FALSE); +} + +static gboolean __bluetooth_pb_vcard_qp_encode_check(const gchar *str) +{ + gchar *pos = NULL; + + if (str == NULL) + return FALSE; + + pos = (gchar *)str; + while (*pos != '\0') { + /* ascii code ' ' : 32, '~' : 126 */ + if ((guchar)*pos < ' ' || (guchar)*pos > '~') + return TRUE; + + pos++; + } + return FALSE; +} + +/* get string length, which convert to quoted-printable encoding */ +static gint __bluetooth_pb_vcard_qp_encode_strlen(const gchar *str, + gint len) +{ + gchar *pos; + + gint count = 0; + gint length = len; + + if (str == NULL) + return 0; + + if (strlen(str) < len ) + length = -1; + + pos = (gchar *)str; + + while (*pos != '\0' && (((pos - str) < length) || length < 0)) { + if ((guchar)*pos == '\t') { + count++; + pos++; + continue; + } + + if ((guchar)*pos < ' ' || (guchar)*pos == '=') { + count += QP_ENC_LEN; + pos++; + continue; + } + + /* check no-ascii utf-8 character */ + if ((guchar)*pos > '~') { + + gchar *next; + + next = g_utf8_next_char(pos); + + count += QP_ENC_LEN * (next - pos); + pos = next; + continue; + } + + pos++; + count++; + } + + return count; +} + +/* convert to quoted printable code */ +static void __bluetooth_pb_vcard_qp_encode_append_to_hex(GString *string, + const gchar *str, + gint len, + gint *line_pos) +{ + int i; + + if (str == NULL || len == 0) + return; + + /* add soft linebreak when it exceed */ + if ((*line_pos + (QP_ENC_LEN * len) > LINEBREAK_LEN)) { + g_string_append(string, "=\r\n"); + *line_pos = 0; + } + + for (i = 0; i < len; i++) { + g_string_append_printf(string, "=%02X", (guchar)*(str+i)); + *line_pos += QP_ENC_LEN; + } +} + +/* append plain visiable ascii character */ +static void __bluetooth_pb_vcard_qp_encode_append_printable_c(GString *string, + gchar ch, + gint *line_pos) +{ + /* add soft linebreak when it exceed */ + if (*line_pos + 1 > LINEBREAK_LEN) { + g_string_append(string, "=\r\n"); + *line_pos = 0; + } + g_string_append_c(string, ch); + (*line_pos)++; +} + +static void __bluetooth_pb_vcard_qp_encode_append(GString *string, + const gchar *str, + gint len, + gint *line_pos) +{ + gint length; + gint encode_len; + + gint i = 0; + + if (string == NULL) + return; + + encode_len = __bluetooth_pb_vcard_qp_encode_strlen(str, len); + + /* add soft linebreak when it exceed */ + if (((*line_pos + encode_len) > LINEBREAK_LEN) && (*line_pos > 1)) { + g_string_append(string, "=\r\n"); + *line_pos = 0; + } + + length = strlen(str); + if (length > len) + length = len; + + while (i < len) { + gchar *pos; + + pos = ((gchar *)str) + i; + + /* converts invisiable character and escape character '=' to quoted-printable */ + if ((guchar)*pos != '\t' && + ((guchar)*pos < ' ' || (guchar)*pos == '=')) { + __bluetooth_pb_vcard_qp_encode_append_to_hex(string, pos, + 1, line_pos); + i++; + + continue; + } + + /* converts non-ascii utf-8 character to quoted-printable */ + if ((guchar)*pos > '~') { + gchar *next; + int ch_len; + + next = g_utf8_next_char(pos); + + ch_len = next - pos; + __bluetooth_pb_vcard_qp_encode_append_to_hex(string, pos, + ch_len, line_pos); + i += ch_len; + + continue; + } + + __bluetooth_pb_vcard_qp_encode_append_printable_c(string, *pos, line_pos); + i++; + } +} + +static gchar* __bluetooth_pb_vcard_qp_encode(const gchar *str) +{ + GString *enc; + + gchar *st_pos; + gchar *pos; + + gint line_pos = 0; + + if (str == NULL) + return NULL; + + enc = g_string_new(NULL); + + st_pos = (gchar *)str; + pos = (gchar *)str; + + while (*pos != '\0') { + /* split string with given delimeter ' ' or '\t' */ + if (*pos == ' ' || *pos == '\t') { + __bluetooth_pb_vcard_qp_encode_append(enc, st_pos, + (pos - st_pos), &line_pos); + + st_pos = pos; + pos++; + + continue; + } + + /* split string with given delimeter '\r', '\n' or '\r\n' - newline */ + if (*pos == '\r' || *pos == '\n' ) { + __bluetooth_pb_vcard_qp_encode_append(enc, st_pos, + (pos - st_pos), &line_pos); + + /* converts newline to qp_encode with soft linebreak + for example, converts \r\n to =0D=0A=\r\n */ + __bluetooth_pb_vcard_qp_encode_append_to_hex(enc, "\r\n", + 2, &line_pos); + g_string_append(enc, "=\r\n "); + + line_pos = 1; + + if (*pos == '\r' && *(pos + 1) == '\n') + pos += 2; + else + pos++; + + st_pos = pos; + + continue; + } + + pos++; + } + + __bluetooth_pb_vcard_qp_encode_append(enc, st_pos, + (pos - st_pos), &line_pos); + + return g_string_free(enc, FALSE); +} + +static void __bluetooth_pb_vcard_append_param_v21(GString *string, + const gchar *param) +{ + gchar *pos = NULL; + + if (param == NULL) + return; + + pos = (gchar *)param; + + /* trim ';' on first */ + while (*pos != '\0') { + if (*pos != ';') + break; + + pos++; + } + + if (*pos != '\0') + g_string_append_printf(string, ";%s", pos); +} + +static void __bluetooth_pb_vcard_append_qp_encode_v21(GString *string, + const gchar *name, + const gchar *param, + const gchar *value) +{ + GString *property = NULL; + + if (name == NULL) + return; + + property = g_string_new(name); + __bluetooth_pb_vcard_append_param_v21(property, param); + + if (__bluetooth_pb_vcard_qp_encode_check(value)) { + gchar *enc = NULL; + + __bluetooth_pb_vcard_append_param_v21(property, + "CHARSET=UTF-8"); + __bluetooth_pb_vcard_append_param_v21(property, + "ENCODING=QUOTED-PRINTABLE"); + g_string_append(property, ":"); + + enc = __bluetooth_pb_vcard_qp_encode(value); + + if (enc) { + g_string_append(property, enc); + g_free(enc); + } + } else { + g_string_append(property, ":"); + if (value) + g_string_append(property , value); + } + + g_string_append_printf(string, "%s\r\n", property->str); + + g_string_free(property, TRUE); +} + + +static void __bluetooth_pb_vcard_append_base64_encode_v21(GString *string, + const gchar *name, + const gchar *param, + const gchar *value, + gsize len, + gboolean folding) +{ + gchar *enc = NULL; + + if (name == NULL) + return; + + g_string_append(string, name); + + __bluetooth_pb_vcard_append_param_v21(string, param); + __bluetooth_pb_vcard_append_param_v21(string, "ENCODING=BASE64"); + + g_string_append(string, ":"); + + if (value == NULL) + return; + + enc = g_base64_encode((const guchar *)value, len); + + + if (folding == FALSE) { + g_string_append(string, enc); + } else { + gint enc_len = strlen(enc); + gint i = 0; + + /* count ' ' size for folding */ + gint fline_len = LINEBREAK_LEN -1; + + for (i = 0; (i * fline_len) < enc_len; i++) { + g_string_append(string, "\r\n "); + if ((i * fline_len) + fline_len > enc_len) + g_string_append(string, enc + (i * fline_len)); + else + g_string_append_len(string, enc + (i * fline_len), fline_len); + } + + /* some application requires more \r\n */ + g_string_append(string, "\r\n"); + } + g_string_append(string, "\r\n"); + + g_free(enc); +} + +static void __bluetooth_pb_vcard_append_n_v21(GString *string, + contacts_record_h contact) +{ + gchar *str; + + str = __bluetooth_pb_name_from_contact(contact); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "N", NULL, str); + + g_free(str); +} + +static void __bluetooth_pb_vcard_append_tel_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint i; + gint status; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.number, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h number = NULL; + + gchar **paramv = NULL; + gchar *param = NULL; + + gchar *tel = NULL; + gchar *escaped = NULL; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.number, i, &number); + + if (status != CONTACTS_ERROR_NONE) + continue; + + status = contacts_record_get_str_p(number, + _contacts_number.number, + &tel); + + if (status != CONTACTS_ERROR_NONE) + continue; + + escaped = __bluetooth_pb_vcard_escape(tel); + + paramv = __bluetooth_pb_contact_tel_param(number); + param = __bluetooth_pb_vcard_strv_concat(paramv, ";"); + + g_strfreev(paramv); + + __bluetooth_pb_vcard_append_qp_encode_v21(string, "TEL", param, escaped); + + g_free(escaped); + g_free(param); + } +} + +static void __bluetooth_pb_vcard_append_fn_v21(GString *string, + contacts_record_h person) +{ + gint status; + + gchar *fn = NULL; + gchar *tmp = NULL; + + status = contacts_record_get_str_p(person, + _contacts_person.display_name, + &tmp); + + if (status != CONTACTS_ERROR_NONE) + return; + + fn = __bluetooth_pb_vcard_escape(tmp); + + __bluetooth_pb_vcard_append_qp_encode_v21(string, "FN", NULL, fn); + + g_free(fn); +} + +static void __bluetooth_pb_vcard_append_photo_v21(GString *string, + contacts_record_h person) +{ + gint status; + + gsize len = 0; + + gchar *filename = NULL; + + gchar *type = NULL; + gchar *param = NULL; + gchar *contents = NULL; + + + status = contacts_record_get_str_p(person, + _contacts_person.image_thumbnail_path, + &filename); + + if (status != CONTACTS_ERROR_NONE) + return; + + type = __bluetooth_pb_contact_photo_type(filename); + + if (type) { + param = g_strdup_printf("TYPE=%s", type); + g_free(type); + } + + if (g_file_get_contents(filename, &contents, &len, NULL) == FALSE) { + ERR("can not read file contents:%s\n", filename); + return; + } + + __bluetooth_pb_vcard_append_base64_encode_v21(string, + "PHOTO", param, contents, len, TRUE); + + g_free(param); + g_free(contents); +} + +static void __bluetooth_pb_vcard_append_bday_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.event, &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h event = NULL; + + gint date; + + gchar *bday; + + contacts_event_type_e type; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.event, i, &event); + + if (status != CONTACTS_ERROR_NONE) + continue; + + status = contacts_record_get_int(event, + _contacts_event.type, + (gint *) &type); + + if (status != CONTACTS_ERROR_NONE) + continue; + + if (type != CONTACTS_EVENT_TYPE_BIRTH) + continue; + + status = contacts_record_get_int(event, + _contacts_event.date, + &date); + + if (status != CONTACTS_ERROR_NONE) + continue; + + if (date <= 0) + continue; + + bday = g_strdup_printf("%04d-%02d-%02d", + (date/10000), (date/100)%100, date%100); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "BDAY", + NULL, bday); + g_free(bday); + } +} + +static void __bluetooth_pb_vcard_append_adr_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.address, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h address = NULL; + + gchar **addrv; + gchar **paramv; + + gchar *addr; + gchar *param; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.address, i, &address); + + if (status != CONTACTS_ERROR_NONE) + continue; + + addrv = __bluetooth_pb_contact_addr(address); + + if (addrv == NULL) + continue; + + addr = __bluetooth_pb_vcard_strv_concat(addrv, ";"); + g_strfreev(addrv); + + paramv = __bluetooth_pb_contact_addr_param(address); + param = __bluetooth_pb_vcard_strv_concat(paramv, ";"); + g_strfreev(paramv); + + __bluetooth_pb_vcard_append_qp_encode_v21(string, "ADR", + param, addr); + + g_free(param); + g_free(addr); + } +} + +static void __bluetooth_pb_vcard_append_email_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.email, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h email = NULL; + + gchar *tmp = NULL; + gchar *escaped; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.email, i, &email); + + if (status != CONTACTS_ERROR_NONE) + continue; + + status = contacts_record_get_str_p(email, + _contacts_email.email, + &tmp); + + if (status != CONTACTS_ERROR_NONE) + continue; + + escaped = __bluetooth_pb_vcard_escape(tmp); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "EMAIL", NULL, escaped); + + g_free(escaped); + } +} + +static void __bluetooth_pb_vcard_append_title_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.company, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h company = NULL; + + char *title = NULL; + gchar *escaped; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.company,i, &company); + + if (status != CONTACTS_ERROR_NONE) + continue; + + status = contacts_record_get_str_p(company, + _contacts_company.job_title, + &title); + + if (status != CONTACTS_ERROR_NONE) + continue; + + escaped = __bluetooth_pb_vcard_escape(title); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "TITLE", NULL, escaped); + + g_free(escaped); + } +} + +static void __bluetooth_pb_vcard_append_role_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.company, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h company = NULL; + + char *role = NULL; + gchar *escaped; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.company, i, &company); + + if (status != CONTACTS_ERROR_NONE) + continue; + + status = contacts_record_get_str_p(company, + _contacts_company.role, + &role); + + if (status != CONTACTS_ERROR_NONE) + continue; + + escaped = __bluetooth_pb_vcard_escape(role); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "ROLE", NULL, escaped); + + g_free(escaped); + } +} + +static void __bluetooth_pb_vcard_append_org_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.company, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h company = NULL; + + GString *str; + + gchar *name = NULL; + gchar *department = NULL; + + gint name_status; + gint department_status; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.company, i, &company); + + if (status != CONTACTS_ERROR_NONE) + continue; + + + name_status = contacts_record_get_str_p(company, + _contacts_company.name, + &name); + + department_status = contacts_record_get_str_p(company, + _contacts_company.department, + &department); + + if ((name_status != CONTACTS_ERROR_NONE) && + (department_status != CONTACTS_ERROR_NONE)) + continue; + + str = g_string_new(NULL); + + if (name) { + gchar *escaped; + + escaped = __bluetooth_pb_vcard_escape(name); + g_string_append(str, escaped); + g_free(escaped); + } + + g_string_append(str, ";"); + + if (department) { + gchar *escaped; + + escaped = __bluetooth_pb_vcard_escape(department); + g_string_append(str, escaped); + g_free(escaped); + } + + __bluetooth_pb_vcard_append_qp_encode_v21(string, "ORG", NULL, str->str); + + g_string_free(str, TRUE); + + } +} + +static void __bluetooth_pb_vcard_append_note_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.note, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h note = NULL; + + char *tmp = NULL; + gchar *escaped; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.note, i, ¬e); + + if (status != CONTACTS_ERROR_NONE) + continue; + + status = contacts_record_get_str_p(note, + _contacts_note.note, + &tmp); + + if (status != CONTACTS_ERROR_NONE) + continue; + + escaped = __bluetooth_pb_vcard_escape(tmp); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "NOTE", NULL, escaped); + + g_free(escaped); + } +} + +static void __bluetooth_pb_vcard_append_rev_v21(GString *string, + contacts_record_h contact) +{ + gint time = 0; + gint status; + + gchar *rev; + struct tm result; + + status = contacts_record_get_int(contact, + _contacts_contact.changed_time, + &time); + + if (status != CONTACTS_ERROR_NONE) + return; + + if (time <= 0) + return; + + gmtime_r((const time_t*)(&time), &result); + + rev = g_strdup_printf("%04d-%02d-%02dT%02d:%02d:%02dZ", + (1900 + result.tm_year), (1 + result.tm_mon), result.tm_mday, + result.tm_hour, result.tm_min, result.tm_sec); + + __bluetooth_pb_vcard_append_qp_encode_v21(string, "REV", NULL, rev); + + g_free(rev); +} + +static void __bluetooth_pb_vcard_append_url_v21(GString *string, + contacts_record_h contact) +{ + guint count = 0; + + gint i; + gint status; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.url, + &count); + + if (status != CONTACTS_ERROR_NONE) + return; + + for (i = 0; i < count; i++) { + contacts_record_h url = NULL; + + gchar *tmp = NULL; + gchar *escaped; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.url, i, &url); + + if (status != CONTACTS_ERROR_NONE) + return; + + if (url == NULL) + continue; + + status = contacts_record_get_str_p(url, + _contacts_url.url, + &tmp); + + if (status != CONTACTS_ERROR_NONE) + continue; + + escaped = __bluetooth_pb_vcard_escape(tmp); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "URL", NULL, escaped); + + g_free(escaped); + } +} + +static void __bluetooth_pb_vcard_append_uid_v21(GString *string, + contacts_record_h contact) +{ + int status; + + gchar *uid = NULL; + gchar *escaped; + + status = contacts_record_get_str_p(contact, + _contacts_contact.uid, + &uid); + + if (status != CONTACTS_ERROR_NONE) + return; + + escaped = __bluetooth_pb_vcard_escape(uid); + __bluetooth_pb_vcard_append_qp_encode_v21(string, "UID", NULL, escaped); + + g_free(escaped); +} + +static void __bluetooth_pb_vcard_append_v30(GString *string, + const gchar *name, + const gchar *param, + const gchar *value) +{ + if (string == NULL) + return; + if (name == NULL) + return; + + g_string_append(string, name); + + if (param) + g_string_append_printf(string, ";%s", param); + + g_string_append(string, ":"); + + if (value) + g_string_append(string, value); + + g_string_append(string, "\r\n"); +} + +static void __bluetooth_pb_vcard_remove_v30(GString *string, + const gchar *property_name) +{ + gchar *pos = NULL; + gchar *st_pos = NULL; + + gboolean matched = FALSE; + + if(string == NULL || property_name == NULL) + return; + + pos = string->str; + + while(*pos != '\0') { + if (matched == FALSE) { + if (g_ascii_strncasecmp(pos, "\r\n", 2) == 0) { + gint attrlen = 0; + + st_pos = pos; + pos += 2; + + attrlen = strlen(property_name); + if (g_ascii_strncasecmp(pos, property_name, attrlen) == 0) { + pos += attrlen; + + if (*pos == ':' || *pos == ';') { + matched = TRUE; + pos++; + } + } + continue; + } + } + else { + if (g_ascii_strncasecmp(pos, "\r\n", 2) == 0) { + pos += 2; + + if (*pos != ' ' && *pos != '\t') { + /* +2 means move over \r\n */ + g_string_erase(string, (st_pos+2)-(string->str), pos-(st_pos +2)); + pos = st_pos; + matched = FALSE; + } + continue; + } + } + + pos++; + } +} + +static gchar *__bluetooth_pb_vcard_filter_v30(const gchar *vcard, + guint64 filter) +{ + GString *string = NULL; + + if (vcard == NULL) + return NULL; + + string = g_string_new(vcard); + + if ((filter & VCARD_PHOTO) == 0) + __bluetooth_pb_vcard_remove_v30(string, "PHOTO"); + + if ((filter & VCARD_BDAY) == 0) + __bluetooth_pb_vcard_remove_v30(string, "BDAY"); + + if ((filter & VCARD_ADR) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "ADR"); + + if ((filter & VCARD_EMAIL) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "EMAIL"); + + if ((filter & VCARD_TITLE) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "TITLE"); + + if ((filter & VCARD_ROLE) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "ROLE"); + + if ((filter & VCARD_ORG) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "ORG"); + + if ((filter & VCARD_NOTE) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "NOTE"); + + if ((filter & VCARD_REV) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "REV"); + + if ((filter & VCARD_URL) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "URL"); + + if ((filter & VCARD_UID) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "UID"); + + if ((filter & VCARD_NICKNAME) == 0 ) + __bluetooth_pb_vcard_remove_v30(string, "NICKNAME"); + + return g_string_free(string, FALSE); +} + +static gchar *__bluetooth_pb_vcard_real_contact_valist_v21(gint person_id, + gint phonelog_id, + guint64 filter, + const gchar *first_name, + va_list args) +{ + contacts_record_h person = NULL; + contacts_record_h contact = NULL; + + GString *str = NULL; + + gint contact_id = 0; + gint status; + + guint64 f = filter; + + const gchar *name = first_name; + + status = contacts_db_get_record(_contacts_person._uri, + person_id, + &person); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_record_get_int(person, + _contacts_person.display_contact_id, + &contact_id); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_db_get_record(_contacts_contact._uri, + contact_id, + &contact); + + if (status != CONTACTS_ERROR_NONE) { + contacts_record_destroy(person, TRUE); + return NULL;; + } + + if (f == 0) + f = ~f; + + str = g_string_new("BEGIN:VCARD\r\nVERSION:2.1\r\n"); + + /* N, TEL is default */ + __bluetooth_pb_vcard_append_n_v21(str, contact); + + if (phonelog_id > 0) { + gchar *number; + + number = _bluetooth_pb_number_from_phonelog_id(phonelog_id); + __bluetooth_pb_vcard_append_qp_encode_v21(str, "TEL", "X-0", number); + g_free(number); + + + } else { + __bluetooth_pb_vcard_append_tel_v21(str, contact); + } + + if (f & VCARD_FN) + __bluetooth_pb_vcard_append_fn_v21(str, person); + if (f & VCARD_PHOTO) + __bluetooth_pb_vcard_append_photo_v21(str, person); + if (f & VCARD_BDAY) + __bluetooth_pb_vcard_append_bday_v21(str, contact); + if (f & VCARD_ADR) + __bluetooth_pb_vcard_append_adr_v21(str, contact); + if (f & VCARD_EMAIL) + __bluetooth_pb_vcard_append_email_v21(str, contact); + if (f & VCARD_TITLE) + __bluetooth_pb_vcard_append_title_v21(str, contact); + if (f & VCARD_ROLE) + __bluetooth_pb_vcard_append_role_v21(str, contact); + if (f & VCARD_ORG) + __bluetooth_pb_vcard_append_org_v21(str, contact); + if (f & VCARD_NOTE) + __bluetooth_pb_vcard_append_note_v21(str, contact); + if (f & VCARD_REV) + __bluetooth_pb_vcard_append_rev_v21(str, contact); + if (f & VCARD_URL) + __bluetooth_pb_vcard_append_url_v21(str, contact); + if (f & VCARD_UID) + __bluetooth_pb_vcard_append_uid_v21(str, contact); + + while (name) { + const gchar *param = va_arg(args, const gchar *); + const gchar *value = va_arg(args, const gchar *); + + if (value) { + gchar *escaped = NULL; + + escaped = __bluetooth_pb_vcard_escape(value); + __bluetooth_pb_vcard_append_qp_encode_v21(str, name, param, escaped); + + g_free(escaped); + } + + name = va_arg(args, const gchar *); + } + + g_string_append(str, "END:VCARD\r\n"); + + contacts_record_destroy(contact, TRUE); + contacts_record_destroy(person, TRUE); + + return g_string_free(str, FALSE); +} + + +static gchar *__bluetooth_pb_vcard_real_contact_valist_v30(gint person_id, + gint phonelog_id, + guint64 filter, + const gchar *first_name, + va_list args) +{ + contacts_record_h person = NULL; + + GString *str = NULL; + + gint status; + + const gchar *name = first_name; + gchar *vcard = NULL; + + status = contacts_db_get_record(_contacts_person._uri, + person_id, + &person); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_vcard_make_from_person(person, &vcard); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_record_destroy(person, TRUE); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + str = g_string_new(vcard); + g_free(vcard); + + /* append contents on vcard */ + while (name) { + const gchar *param = va_arg(args, const gchar *); + const gchar *value = va_arg(args, const gchar *); + + __bluetooth_pb_vcard_append_v30(str, name, param, value); + + name = va_arg(args, const gchar *); + } + + /* if phonelog_id exist, + we shall show only the phone number, which was used for that phone log */ + if (phonelog_id > 0) { + gchar *number; + + __bluetooth_pb_vcard_remove_v30(str, "TEL"); + + number = _bluetooth_pb_number_from_phonelog_id(phonelog_id); + __bluetooth_pb_vcard_append_v30(str, "TEL", NULL, number); + g_free(number); + } + + vcard = g_string_free(str, FALSE); + + /* temporary fixed for some application crash */ + if (filter == 0) + filter = ~VCARD_NOTE; + + if (filter) { + gchar *new_vcard = NULL; + + new_vcard = __bluetooth_pb_vcard_filter_v30(vcard, filter); + + if (new_vcard) { + g_free(vcard); + vcard = new_vcard; + } + } + + return vcard; +} + + +static gchar *__bluetooth_pb_vcard_real_contact_with_properties(gint person_id, + gint phonelog_id, + guint64 filter, + guint8 format, + const gchar *first_name, + ...) +{ + DBG("\n"); + gchar *vcard = NULL; + va_list args; + + va_start(args, first_name); + + switch(format) { + case VCARD_FORMAT_3_0: + vcard = __bluetooth_pb_vcard_real_contact_valist_v30(person_id, + phonelog_id, filter, + first_name, args); + break; + case VCARD_FORMAT_2_1: + default: + vcard = __bluetooth_pb_vcard_real_contact_valist_v21(person_id, + phonelog_id, filter, + first_name, args); + break; + } + + va_end(args); + + return vcard; +} + +static gchar *__bluetooth_pb_vcard_real_call_v21(gint phonelog_id, + guint filter, + const char *attr) +{ + GString *str; + gchar *number; + + str = g_string_new("BEGIN:VCARD\r\nVERSION:2.1\r\n"); + + __bluetooth_pb_vcard_append_qp_encode_v21(str, "N", NULL, NULL); + + number = _bluetooth_pb_number_from_phonelog_id(phonelog_id); + __bluetooth_pb_vcard_append_qp_encode_v21(str, "TEL", "X-0", number); + g_free(number); + + if (((filter == 0) || (filter & VCARD_X_IRMC_CALL_DATETIME)) + && attr) { + gchar *datetime = NULL; + + datetime = __bluetooth_pb_phonelog_datetime(phonelog_id); + __bluetooth_pb_vcard_append_qp_encode_v21(str, "X-IRMC-CALL-DATETIME", + attr, datetime); + g_free(datetime); + } + + g_string_append(str, "END:VCARD\r\n"); + + return g_string_free(str, FALSE); +} + +static gchar *__bluetooth_pb_vcard_real_call_v30(gint phonelog_id, + guint filter, + const gchar *attr) +{ + GString *str; + gchar *number; + + str = g_string_new("BEGIN:VCARD\r\nVERSION:3.0\r\n"); + + __bluetooth_pb_vcard_append_v30(str, "N", NULL, NULL); + __bluetooth_pb_vcard_append_v30(str, "FN", NULL, NULL); + + number = _bluetooth_pb_number_from_phonelog_id(phonelog_id); + __bluetooth_pb_vcard_append_v30(str, "TEL", NULL, number); + g_free(number); + + if (((filter == 0) || (filter & VCARD_X_IRMC_CALL_DATETIME)) + && attr) { + gchar *datetime = NULL; + + datetime = __bluetooth_pb_phonelog_datetime(phonelog_id); + __bluetooth_pb_vcard_append_v30(str, + "X-IRMC-CALL-DATETIME", attr, datetime); + g_free(datetime); + } + + g_string_append(str, "END:VCARD\r\n"); + + return g_string_free(str, FALSE); +} + +static gchar *__bluetooth_pb_vcard_real_call(gint phonelog_id, + guint filter, + guint8 format, + const gchar *attr) +{ + DBG("\n"); + gchar *vcard = NULL; + + switch(format) { + case VCARD_FORMAT_3_0: + vcard = __bluetooth_pb_vcard_real_call_v30(phonelog_id, + filter, attr); + break; + case VCARD_FORMAT_2_1: + default: + vcard = __bluetooth_pb_vcard_real_call_v21(phonelog_id, + filter, attr); + break; + } + + return vcard; +} + +static gchar **__bluetooth_pb_contact_add_field_str(contacts_record_h record, + int *field, + gint field_size) +{ + gchar **strv; + + gint status; + gint i; + + gboolean valid = FALSE; + + /* check empty field */ + for (i = 0; i < field_size; i++) { + gchar *tmp = NULL; + + status = contacts_record_get_str_p(record, field[i], &tmp); + + if (status != CONTACTS_ERROR_NONE) + continue; + + if (tmp) { + valid = TRUE; + break; + } + } + + if (valid == FALSE) + return NULL; + + strv = g_new0(gchar *, field_size + 1); + + for (i = 0; i < field_size; i++) { + gchar *tmp; + + status = contacts_record_get_str_p(record, field[i], &tmp); + + if (status != CONTACTS_ERROR_NONE) + continue; + + if (tmp == NULL) + strv[i] = g_strdup(""); + else + strv[i] = __bluetooth_pb_vcard_escape(tmp); + } + + return strv; +} + +static gchar **__bluetooth_pb_contact_tel_param(contacts_record_h number) +{ + gchar **strv = NULL; + + const gint TEL_PARAM_LEN = 13; + + gint status; + gint i = 0; + + contacts_number_type_e type; + + bool is_default = false; + + strv = g_new0(char *, TEL_PARAM_LEN + 1); /* tel param max size is 13 */ + + status = contacts_record_get_bool(number, _contacts_number.is_default, + &is_default); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + if (is_default) { + strv[i] = g_strdup("PREF"); + i++; + } + + status = contacts_record_get_int(number, + _contacts_number.type, + (gint *)&type); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + if (type & CONTACTS_NUMBER_TYPE_HOME) { + strv[i] = g_strdup("HOME"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_WORK) { + strv[i] = g_strdup("WORK"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_VOICE) { + strv[i] = g_strdup("VOICE"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_FAX) { + strv[i] = g_strdup("FAX"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_MSG) { + strv[i] = g_strdup("MSG"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_CELL) { + strv[i] = g_strdup("CELL"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_PAGER) { + strv[i] = g_strdup("PAGER"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_BBS) { + strv[i] = g_strdup("BBS"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_MODEM) { + strv[i] = g_strdup("MODEM"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_CAR) { + strv[i] = g_strdup("CAR"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_ISDN) { + strv[i] = g_strdup("ISDN"); + i++; + } + + if (type & CONTACTS_NUMBER_TYPE_VIDEO) { + strv[i] = g_strdup("VIDEO"); + i++; + } + + /* CTS_NUM_TYPE_PCS is not part of vcard2.1 */ + return strv; +} + + +static gchar *__bluetooth_pb_contact_photo_type(const gchar *filename) +{ + gchar *filetype = NULL; + gchar *ext = NULL; + + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR) == FALSE) { + ERR("file does not regular:%s\n", filename); + return NULL; + } + + ext = strrchr(filename, '.'); + if (ext == NULL) { + ERR("file doesn't have extension\n"); + return NULL; + } + + ext++; + + if (g_ascii_strcasecmp(ext, "gif") == 0) + filetype = "GIF"; + else if (g_ascii_strcasecmp(ext, "cgm") == 0) + filetype = "CGM"; + else if (g_ascii_strcasecmp(ext, "wmf") == 0) + filetype = "WMF"; + else if (g_ascii_strcasecmp(ext, "bmp") == 0) + filetype = "BMP"; + else if (g_ascii_strcasecmp(ext, "met") == 0) + filetype = "MET"; + else if (g_ascii_strcasecmp(ext, "dib") == 0) + filetype = "DIB"; + else if (g_ascii_strcasecmp(ext, "pict") == 0 || g_ascii_strcasecmp(ext, "pct") == 0 || + g_ascii_strcasecmp(ext, "pic") == 0) + filetype = "PICT"; + else if (g_ascii_strcasecmp(ext, "tiff") == 0 || g_ascii_strcasecmp(ext, "tif") == 0) + filetype = "TIFF"; + else if (g_ascii_strcasecmp(ext, "ps") == 0) + filetype = "PS"; + else if (g_ascii_strcasecmp(ext, "pdf") == 0) + filetype = "PDF"; + else if (g_ascii_strcasecmp(ext, "jpeg") == 0 || g_ascii_strcasecmp(ext, "jpg") == 0 || + g_ascii_strcasecmp(ext, "jpe") == 0) + filetype = "JPEG"; + else if (g_ascii_strcasecmp(ext, "mpeg") == 0 || g_ascii_strcasecmp(ext, "mpg") == 0) + filetype = "MPEG"; + else if (g_ascii_strcasecmp(ext, "m2v") == 0) + filetype = "MPEG2"; + else if (g_ascii_strcasecmp(ext, "avi") == 0) + filetype = "AVI"; + else if (g_ascii_strcasecmp(ext, "mov") == 0) + filetype = "QTIME"; + else if (g_ascii_strcasecmp(ext, "png") == 0) + filetype = "PNG"; + + return g_strdup(filetype); +} + +static gchar **__bluetooth_pb_contact_addr(contacts_record_h address) +{ + const gint ADDR_LEN = 7; + + gchar **strv = NULL; + + gint addr[] = { _contacts_address.postbox, + _contacts_address.extended, + _contacts_address.street, + _contacts_address.locality, + _contacts_address.region, + _contacts_address.postal_code, + _contacts_address.country }; + + strv = __bluetooth_pb_contact_add_field_str(address, + addr, ADDR_LEN); + return strv; +} + +static gchar **__bluetooth_pb_contact_addr_param(contacts_record_h address) +{ + + contacts_address_type_e type; + + gint status; + gint i = 0; + + gchar **strv = NULL; + + strv = g_new0(gchar *, 7); /* ADDR param max size is 6 */ + + status = contacts_record_get_int(address, + _contacts_address.type, + (gint *)&type); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + if (type & CONTACTS_ADDRESS_TYPE_HOME) { + strv[i] = g_strdup("HOME"); + i++; + } + if (type & CONTACTS_ADDRESS_TYPE_WORK) { + strv[i] = g_strdup("WORK"); + i++; + } + if (type & CONTACTS_ADDRESS_TYPE_DOM) { + strv[i] = g_strdup("DOM"); + i++; + } + if (type & CONTACTS_ADDRESS_TYPE_INTL) { + strv[i] = g_strdup("INTL"); + i++; + } + if (type & CONTACTS_ADDRESS_TYPE_POSTAL) { + strv[i] = g_strdup("POSTAL"); + i++; + } + if (type & CONTACTS_ADDRESS_TYPE_PARCEL) { + strv[i] = g_strdup("PARCEL"); + i++; + } + return strv; +} + +static gchar *__bluetooth_pb_phonelog_datetime(gint phonelog_id) +{ + contacts_record_h phone_log; + + char time_str[32] = {0,}; + + gint status; + gint time = 0; + + struct tm time_info; + + status = contacts_db_get_record(_contacts_phone_log._uri, + phonelog_id, + &phone_log); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_record_get_int(phone_log, + _contacts_phone_log.log_time, + &time); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + if (time <= 0) + return NULL; + + localtime_r((time_t *)&time, &time_info); + + strftime(time_str, sizeof(time_str), + "%Y%m%dT%H%M%S", &time_info); + + contacts_record_destroy(phone_log, TRUE); + + return g_strdup(time_str); +} + +static gchar *__bluetooth_pb_name_from_contact(contacts_record_h contact) +{ + contacts_record_h name = NULL; + + GString *str = g_string_new(NULL); + + gint status; + gint i; + + gint name_size = 5; + gint name_val[] = { _contacts_name.last, + _contacts_name.first, + _contacts_name.addition, + _contacts_name.prefix, + _contacts_name.suffix }; + + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.name, 0, &name); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + for (i = 0; i < name_size; i++) { + gchar *tmp = NULL; + gchar *escape = NULL; + + if (i > 0) + g_string_append_c(str, ';'); + + status = contacts_record_get_str_p(name, name_val[i], &tmp); + + if (status != CONTACTS_ERROR_NONE) + continue; + + escape = __bluetooth_pb_vcard_escape(tmp); + g_string_append(str, escape); + + g_free(escape); + } + + return g_string_free(str, FALSE); +} + +static gchar *__bluetooth_pb_number_from_contact(contacts_record_h contact) +{ + guint count = 0; + + gint status; + gint i; + + gchar *str = NULL; + + status = contacts_record_get_child_record_count(contact, + _contacts_contact.number, + &count); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + for (i = 0; i < count; i++) { + contacts_record_h number = NULL; + + gchar *tmp = NULL; + + bool is_default = false; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.number, i, &number); + + if (status != CONTACTS_ERROR_NONE) + continue; + + status = contacts_record_get_bool(number, + _contacts_number.is_default, + &is_default); + + if (status != CONTACTS_ERROR_NONE) + continue; + + if (is_default == FALSE) + continue; + + status = contacts_record_get_str_p(number, + _contacts_number.number, + &tmp); + + if (status != CONTACTS_ERROR_NONE) + continue; + + if (tmp) { + str = g_strdup(tmp); + break; + } + } + + /* get first number */ + if (str == NULL) { + gchar *tmp = NULL; + + contacts_record_h number = NULL; + + status = contacts_record_get_child_record_at_p(contact, + _contacts_contact.number, 0, &number); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_record_get_str_p(number, + _contacts_number.number, + &tmp); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + str = g_strdup(tmp); + } + + return str; +} + +static gint __bluetooth_pb_person_id_from_phonelog_id(gint phonelog_id) +{ + contacts_query_h query = NULL; + contacts_filter_h filter = NULL; + contacts_list_h record_list = NULL; + + contacts_record_h phone_log = NULL; + contacts_record_h record = NULL; + + gint status; + gint person_id = 0; + + status = contacts_db_get_record(_contacts_phone_log._uri, + phonelog_id, + &phone_log); + + if (status != CONTACTS_ERROR_NONE) + return 0; + + status = contacts_record_get_int(phone_log, + _contacts_phone_log.person_id, + &person_id); + + if (status != CONTACTS_ERROR_NONE) { + contacts_record_destroy(phone_log, TRUE); + return 0; + } + + contacts_record_destroy(phone_log, TRUE); + + if (person_id) + return person_id; + + status = contacts_filter_create(_contacts_person_phone_log._uri, + &filter); + + if (status != CONTACTS_ERROR_NONE) + return 0; + + + status = contacts_filter_add_int(filter, + _contacts_person_phone_log.log_id, + CONTACTS_MATCH_EQUAL, + phonelog_id); + + if (status != CONTACTS_ERROR_NONE) { + contacts_filter_destroy(filter); + return 0; + } + + status = contacts_query_create(_contacts_person_phone_log._uri, &query); + + if (status != CONTACTS_ERROR_NONE) { + contacts_filter_destroy(filter); + return 0; + } + + status = contacts_query_set_filter(query, filter); + + if (status != CONTACTS_ERROR_NONE) { + contacts_filter_destroy(filter); + contacts_query_destroy(query); + return 0; + } + + status = contacts_db_get_records_with_query(query, -1, -1, &record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_filter_destroy(filter); + contacts_query_destroy(query); + + return 0; + } + + status = contacts_list_first(record_list); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + contacts_filter_destroy(filter); + contacts_query_destroy(query); + + return 0; + } + + status = contacts_list_get_current_record_p(record_list, &record); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + contacts_filter_destroy(filter); + contacts_query_destroy(query); + + return 0; + } + + status = contacts_record_get_int(record, + _contacts_person_phone_log.person_id, + &person_id); + + if (status != CONTACTS_ERROR_NONE) { + contacts_list_destroy(record_list, TRUE); + contacts_filter_destroy(filter); + contacts_query_destroy(query); + + return 0; + } + + contacts_list_destroy(record_list, TRUE); + contacts_filter_destroy(filter); + contacts_query_destroy(query); + + return person_id; +} + +/* API for vcard */ +gchar *_bluetooth_pb_vcard_contact(gint person_id, + guint64 filter, + guint8 format) +{ + gchar *str = NULL; + + if (person_id <= 0) + return NULL; + + str = __bluetooth_pb_vcard_real_contact_with_properties(person_id, 0, + filter, format, + NULL); + return str; +} + +gchar *_bluetooth_pb_vcard_contact_owner(const gchar *number, + guint64 filter, + guint8 format) +{ + GString *str = g_string_new("BEGIN:VCARD\r\n"); + gchar *fn; + gchar *name; + + fn = _bluetooth_pb_owner_name(); + name = g_strdup_printf("%s;;;;", fn); + + switch (format) { + case VCARD_FORMAT_3_0: + g_string_append(str, "VERSION:3.0\r\n"); + + __bluetooth_pb_vcard_append_v30(str, "N", NULL, name); + __bluetooth_pb_vcard_append_v30(str, "FN", NULL, fn); + __bluetooth_pb_vcard_append_v30(str, "TEL", "TYPE=CELL", number); + break; + case VCARD_FORMAT_2_1: + default : + g_string_append(str, "VERSION:2.1\r\n"); + + __bluetooth_pb_vcard_append_qp_encode_v21(str, "N", NULL, name); + + if (filter == 0 || (filter & VCARD_FN)) + __bluetooth_pb_vcard_append_qp_encode_v21(str, "FN", NULL, fn); + + __bluetooth_pb_vcard_append_qp_encode_v21(str, "TEL", "CELL", number); + break; + + } + + g_string_append(str, "END:VCARD\r\n"); + + g_free(fn); + g_free(name); + + return g_string_free(str, FALSE); +} + +gchar *_bluetooth_pb_vcard_call(gint phonelog_id, + guint64 filter, + guint8 format, + const gchar *attr) +{ + gint person_id = 0; + + gchar *str = NULL; + + if (attr == NULL) { + DBG("Unknown attribute type ignored\n"); + return NULL; + } + + person_id = __bluetooth_pb_person_id_from_phonelog_id(phonelog_id); + + DBG("person_id %d\n", person_id); + + if (person_id) { + if (filter == 0 || (filter & VCARD_X_IRMC_CALL_DATETIME)) { + gchar *datetime = NULL; + + datetime = __bluetooth_pb_phonelog_datetime(phonelog_id); + + str = __bluetooth_pb_vcard_real_contact_with_properties(person_id, + phonelog_id, + filter, format, + "X-IRMC-CALL-DATETIME", attr, datetime, + NULL); + + if(datetime) + g_free(datetime); + } + else { + str = __bluetooth_pb_vcard_real_contact_with_properties(person_id, + phonelog_id, + filter, format, + NULL); + } + } + else + str = __bluetooth_pb_vcard_real_call(phonelog_id, filter, format, attr); + + return str; +} + +gchar *_bluetooth_pb_fn_from_person_id(gint person_id) +{ + contacts_record_h person = NULL; + + gint status; + + gchar *str = NULL; + + status = contacts_db_get_record(_contacts_person._uri, + person_id, + &person); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_record_get_str(person, + _contacts_person.display_name, + &str); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + contacts_record_destroy(person, TRUE); + + return str; +} + +gchar *_bluetooth_pb_name_from_person_id(gint person_id) +{ + contacts_record_h person = NULL; + contacts_record_h contact = NULL; + + gint status; + gint contact_id = 0; + + gchar *str; + + status = contacts_db_get_record(_contacts_person._uri, + person_id, + &person); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + status = contacts_record_get_int(person, + _contacts_person.display_contact_id, + &contact_id); + + if (status != CONTACTS_ERROR_NONE) { + contacts_record_destroy(person, TRUE); + return NULL; + } + + contacts_db_get_record(_contacts_contact._uri, + contact_id, + &contact); + + if (status != CONTACTS_ERROR_NONE) { + contacts_record_destroy(person, TRUE); + return NULL; + } + + str = __bluetooth_pb_name_from_contact(contact); + + contacts_record_destroy(contact, TRUE); + contacts_record_destroy(person, TRUE); + + return str; +} + +gchar *_bluetooth_pb_number_from_person_id(gint person_id) +{ + contacts_record_h person = NULL; + contacts_record_h contact = NULL; + + gint status; + gint contact_id = 0; + + gchar *str; + + status = contacts_db_get_record(_contacts_person._uri, + person_id, + &person); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + + status = contacts_record_get_int(person, + _contacts_person.display_contact_id, + &contact_id); + + if (status != CONTACTS_ERROR_NONE) { + contacts_record_destroy(person, TRUE); + return NULL; + } + + status = contacts_db_get_record(_contacts_contact._uri, + contact_id, + &contact); + + if (status != CONTACTS_ERROR_NONE) { + contacts_record_destroy(person, TRUE); + return NULL; + } + + str = __bluetooth_pb_number_from_contact(contact); + + contacts_record_destroy(contact, TRUE); + contacts_record_destroy(person, TRUE); + + return str; +} + +gchar *_bluetooth_pb_fn_from_phonelog_id(gint phonelog_id) +{ + gint person_id = 0; + gchar *str = NULL; + + person_id = __bluetooth_pb_person_id_from_phonelog_id(phonelog_id); + + if (person_id > 0) + str = _bluetooth_pb_fn_from_person_id(person_id); + else + str = _bluetooth_pb_number_from_phonelog_id(phonelog_id); + + return str; +} + +gchar *_bluetooth_pb_name_from_phonelog_id(gint phonelog_id) +{ + gint person_id = 0; + gchar *str = NULL; + + person_id = __bluetooth_pb_person_id_from_phonelog_id(phonelog_id); + + if (person_id > 0) + str = _bluetooth_pb_name_from_person_id(person_id); + else { + gchar *tmp; + + tmp = _bluetooth_pb_number_from_phonelog_id(phonelog_id); + str = g_strdup_printf("%s;;;;", tmp); + + g_free(tmp); + } + + return str; +} + +gchar *_bluetooth_pb_number_from_phonelog_id(gint phonelog_id) +{ + contacts_record_h phone_log; + + gint status; + + gchar *str; + gchar *tmp = NULL; + + status = contacts_db_get_record(_contacts_phone_log._uri, + phonelog_id, &phone_log); + + if (status != CONTACTS_ERROR_NONE) + return NULL; + + contacts_record_get_str_p(phone_log, + _contacts_phone_log.address, + &tmp); + + if (status != CONTACTS_ERROR_NONE) { + contacts_record_destroy(phone_log, TRUE); + return NULL; + } + + str = g_strdup(tmp); + + contacts_record_destroy(phone_log, TRUE); + + return str; +} + +gchar *_bluetooth_pb_owner_name(void) +{ + gchar *name; + + name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR); + + if (name == NULL) + name = g_strdup("My Name"); + + return name; +} diff --git a/pb-agent/bluetooth_pb_vcard.h b/pb-agent/bluetooth_pb_vcard.h new file mode 100644 index 0000000..24d9675 --- /dev/null +++ b/pb-agent/bluetooth_pb_vcard.h @@ -0,0 +1,53 @@ +/* + * bluetooth-agent + * + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * 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. + * + */ + +#ifndef __DEF_BT_PB_VCARD_H_ +#define __DEF_BT_PB_VCARD_H_ + +#include + +/* vcard */ +gchar *_bluetooth_pb_vcard_contact(gint person_id, + guint64 filter, + guint8 format); + +gchar *_bluetooth_pb_vcard_contact_owner(const gchar *number, + guint64 filter, + guint8 format); + +gchar *_bluetooth_pb_vcard_call(gint phonelog_id, + guint64 filter, + guint8 format, + const gchar *attr); + +gchar *_bluetooth_pb_fn_from_person_id(gint person_id); + +gchar *_bluetooth_pb_name_from_person_id(gint person_id); + +gchar *_bluetooth_pb_number_from_person_id(gint person_id); + +gchar *_bluetooth_pb_fn_from_phonelog_id(gint phonelog_id); + +gchar *_bluetooth_pb_name_from_phonelog_id(gint phonelog_id); + +gchar *_bluetooth_pb_number_from_phonelog_id(gint phonelog_id); + +gchar *_bluetooth_pb_owner_name(void); + +#endif diff --git a/pb-agent/org.bluez.pb_agent.service b/pb-agent/org.bluez.pb_agent.service new file mode 100644 index 0000000..e890341 --- /dev/null +++ b/pb-agent/org.bluez.pb_agent.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.bluez.pb_agent +Exec=/usr/bin/bluetooth-pb-agent