CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+IF (TIZEN_WEARABLE)
+ADD_SUBDIRECTORY(hf-agent)
+ELSE (TIZEN_WEARABLE)
ADD_SUBDIRECTORY(map-agent)
-
-#ADD_SUBDIRECTORY(pb-agent)
-
-#ADD_SUBDIRECTORY(hfp-agent)
+ADD_SUBDIRECTORY(pb-agent)
+IF (TIZEN_BT_HFP_AG_ENABLE)
+ADD_SUBDIRECTORY(ag-agent)
+ENDIF (TIZEN_BT_HFP_AG_ENABLE)
+ENDIF (TIZEN_WEARABLE)
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(bluetooth-ag-agent C)
+
+SET(SRCS bluetooth-ag-agent.c
+ bluetooth-ag-handler.c
+ bluetooth-ag-manager.c)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+SET(PKG_MODULES
+ dlog
+ dbus-glib-1
+ vconf
+ appsvc
+ contacts-service2
+ tapi
+ capi-appfw-application
+ aul
+ capi-system-info
+ glib-2.0
+ gio-2.0
+ gio-unix-2.0
+)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs_ag_agent REQUIRED ${PKG_MODULES})
+
+FOREACH(flag ${pkgs_ag_agent_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+SET(APP_SYSCONFDIR /opt/var/lib/bluetooth)
+
+ADD_DEFINITIONS("-DAPP_SYSCONFDIR=\"${APP_SYSCONFDIR}\"")
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_ag_agent_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.bluez.ag_agent.service
+ DESTINATION share/dbus-1/system-services)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/voice-recognition-blacklist
+ DESTINATION /opt/var/lib/bluetooth/)
--- /dev/null
+/*
+ * Bluetooth-ag-agent
+ *
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Chethan T N <chethan.tn@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ * Rakesh MK <rakesh.mk@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/poll.h>
+#include <gio/gunixfdlist.h>
+#include <bundle_internal.h>
+#include "bluetooth-ag-agent.h"
+#include "bluetooth-ag-handler.h"
+
+#include <TapiUtility.h>
+#include <ITapiSim.h>
+#include <ITapiModem.h>
+#include <TelNetwork.h>
+#include <app.h>
+#include <aul.h>
+#include <system_info.h>
+
+#include "contacts.h"
+#include "appsvc.h"
+
+static GMainLoop *gmain_loop = NULL;
+static GDBusProxy *service_gproxy;
+static int owner_sig_id = -1;
+static int name_owner_sig_id = -1;
+GDBusConnection *ag_dbus_conn = NULL;
+gchar *remote_dev_path = NULL;
+gboolean wbs_en;
+uint16_t hfp_ver;
+uint16_t hsp_ver;
+static TapiHandle *tapi_handle;
+extern wbs_options wbs_opts;
+GSList *active_devices = NULL;
+static gchar *local_addr = NULL;
+static GDBusProxy *app_gproxy;
+static gboolean call_launch_requested = FALSE;
+static gchar* sco_owner = NULL;
+static guint sco_open_timer_id = 0;
+static gboolean sco_open_request = FALSE;
+static guint hf_bluez_id;
+static guint hs_bluez_id;
+static guint app_id;
+#ifdef TIZEN_MEDIA_ENHANCE
+static int media_sig_id = -1;
+static int media_state_sig_id = -1;
+static bt_ag_media_transport_state_t transport_state;
+#endif
+
+#define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
+#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
+#ifdef TIZEN_MEDIA_ENHANCE
+#define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
+#endif
+#define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
+
+#ifdef TIZEN_SUPPORT_LUNAR_DEVICE
+#define VCONF_KEY_BT_LUNAR_ENABLED "db/wms/bt_loop_device_hfp_connected"
+#endif
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_BT_HFP_AG_ENABLE)
+#define CALL_APP_ID "org.tizen.call-ui"
+#endif
+
+#if defined(TIZEN_SUPPORT_DUAL_HF)
+#define VCONF_KEY_BT_HOST_BT_MAC_ADDR "db/wms/host_bt_mac"
+#define MAX_CONNECTED_DEVICES 2
+#else
+#define MAX_CONNECTED_DEVICES 1
+#endif
+
+#define BT_AG_SIG_NUM 3
+static struct sigaction bt_ag_sigoldact[BT_AG_SIG_NUM];
+static int bt_ag_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
+
+/*Below Inrospection data is exposed to bluez from agent*/
+static const gchar ag_agent_bluez_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.bluez.Profile1'>"
+" <method name='NewConnection'>"
+" <arg type='o' name='device' direction='in'/>"
+" <arg type='h' name='fd' direction='in'/>"
+" <arg type='a{sv}' name='options' direction='in'/>"
+" </method>"
+" <method name='RequestDisconnection'>"
+" <arg type='o' name='device' direction='in'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+/*Below Introspection data is exposed to application from agent*/
+static const gchar ag_agent_app_introspection_xml[] =
+"<node name='/'>"
+" <interface name='Org.Hfp.App.Interface'>"
+" <method name='RegisterApplication'>"
+" <arg type='s' name='path' direction='in'/>"
+" <arg type='s' name='address' direction='in'/>"
+" </method>"
+" <method name='UnregisterApplication'>"
+" <arg type='s' name='path' direction='in'/>"
+" </method>"
+" <method name='IncomingCall'>"
+" <arg type='s' name='path' direction='in'/>"
+" <arg type='s' name='number' direction='in'/>"
+" <arg type='i' name='id' direction='in'/>"
+" </method>"
+" <method name='OutgoingCall'>"
+" <arg type='s' name='path' direction='in'/>"
+" <arg type='s' name='number' direction='in'/>"
+" <arg type='i' name='id' direction='in'/>"
+" </method>"
+" <method name='ChangeCallStatus'>"
+" <arg type='s' name='path' direction='in'/>"
+" <arg type='s' name='number' direction='in'/>"
+" <arg type='i' name='status' direction='in'/>"
+" <arg type='i' name='id' direction='in'/>"
+" </method>"
+" <method name='GetProperties'>"
+" <arg type='a{sv}' name='properties' direction='out'/>"
+" </method>"
+" <method name='Disconnect'>"
+" </method>"
+" <method name='IsConnected'>"
+" <arg type='b' name='connected' direction='out'/>"
+" </method>"
+" <method name='IndicateCall'>"
+" </method>"
+" <method name='CancelCall'>"
+" </method>"
+" <method name='Play'>"
+" </method>"
+" <method name='Stop'>"
+" </method>"
+" <method name='IsPlaying'>"
+" <arg type='b' name='playing' direction='out'/>"
+" </method>"
+" <method name='GetSpeakerGain'>"
+" <arg type='q' name='gain' direction='out'/>"
+" </method>"
+" <method name='GetMicrophoneGain'>"
+" <arg type='q' name='gain' direction='out'/>"
+" </method>"
+" <method name='SetSpeakerGain'>"
+" <arg type='q' name='gain' direction='in'/>"
+" </method>"
+" <method name='SetMicrophoneGain'>"
+" <arg type='q' name='gain' direction='in'/>"
+" </method>"
+" <method name='SetVoiceDial'>"
+" <arg type='b' name='enable' direction='in'/>"
+" </method>"
+" <method name='CheckPrivilege'>"
+" </method>"
+" </interface>"
+"</node>";
+
+struct event {
+ const char *cmd;
+ int (*callback)(bt_ag_info_t *hs, const char *buf);
+};
+
+struct sco_socket_addr {
+ sa_family_t sco_family;
+ bt_addr sco_bdaddr;
+};
+
+typedef struct {
+ uint16_t setting;
+} bt_voice;
+
+struct ag_codec {
+ bt_ag_info_t *bt_ag_info;
+ char *codec_status;
+};
+
+bt_ag_status_t ag = {
+ .telephony_ready = FALSE,
+ .features = 0,
+ .er_mode = 3,
+ .er_ind = 0,
+ .rh = BT_RSP_HOLD_NOT_SUPPORTED,
+ .number = NULL,
+ .number_type = 0,
+ .ring_timer = 0,
+ .sdp_features = 0,
+};
+static void __bt_ag_agent_sigterm_handler(int signo);
+static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
+ const gchar *object_path);
+static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs);
+static gboolean __bt_ag_event_handler(GIOChannel *channel, GIOCondition cond,
+ void *user_data);
+static int __bt_ag_sco_connect(bt_ag_info_t *hs);
+void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state);
+static void __bt_ag_agent_reg_sim_event(TapiHandle *handle, void *user_data);
+static void __bt_ag_agent_dereg_sim_event(TapiHandle *handle);
+static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data);
+
+static void __bt_convert_addr_type_to_rev_string(char *address,
+ unsigned char *addr)
+{
+ ret_if(address == NULL);
+ ret_if(addr == NULL);
+
+ g_snprintf(address, BT_ADDRESS_STRING_SIZE,
+ "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
+}
+
+static GDBusProxy *__bt_ag_gdbus_init_service_proxy(const gchar *service,
+ const gchar *path, const gchar *interface)
+{
+ FN_START;
+
+ GDBusProxy *proxy;
+ GError *err = NULL;
+
+ if (ag_dbus_conn == NULL)
+ ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+
+ if (!ag_dbus_conn) {
+ if (err) {
+ ERR("Unable to connect to gdbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+
+ proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ service, path,
+ interface, NULL, &err);
+
+ if (!proxy) {
+ if (err) {
+ ERR("Unable to create proxy: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+
+ FN_END;
+ return proxy;
+}
+
+static GDBusProxy *__bt_ag_gdbus_get_app_proxy(const gchar *service,
+ const gchar *path, const gchar *interface)
+{
+ return (app_gproxy) ? app_gproxy :
+ __bt_ag_gdbus_init_service_proxy(service,
+ path, interface);
+}
+
+static int __bt_ag_agent_gdbus_method_send(const char *service,
+ const gchar *path, const char *interface,
+ const char *method, gboolean response,
+ GVariant *parameters)
+{
+ FN_START;
+
+ GVariant *ret;
+ GDBusProxy *proxy;
+ GError *error = NULL;
+
+ proxy = __bt_ag_gdbus_get_app_proxy(service, path, interface);
+ if (!proxy)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+
+ if (response) {
+ ret = g_dbus_proxy_call_sync(proxy,
+ method, parameters,
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ if (ret == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("dBUS-RPC is failed");
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+
+ g_clear_error(&error);
+ }
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ g_variant_unref(ret);
+ } else {
+ g_dbus_proxy_call(proxy,
+ method, parameters,
+ G_DBUS_CALL_FLAGS_NONE, 2000,
+ NULL, NULL, NULL);
+ }
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+gboolean _bt_ag_agent_emit_signal(
+ GDBusConnection *connection,
+ const char *path,
+ const char *interface,
+ const char *name,
+ GVariant *property)
+{
+ FN_START;
+
+ GError *error = NULL;
+ gboolean ret;
+ ret = g_dbus_connection_emit_signal(connection,
+ NULL, path, interface,
+ name, property,
+ &error);
+ if (!ret) {
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ }
+ INFO_C("Emit Signal done = [%s]", name);
+
+ FN_END;
+ return ret;
+}
+
+gboolean _bt_ag_agent_emit_property_changed(
+ GDBusConnection *connection,
+ const char *path,
+ const char *interface,
+ const char *name,
+ GVariant *property)
+{
+ FN_START;
+
+ gboolean ret;
+ GVariant *var_data;
+
+ var_data = g_variant_new("(sv)", name, property);
+
+ ret = _bt_ag_agent_emit_signal(connection,
+ path, interface,
+ "PropertyChanged", var_data);
+ FN_END;
+ return ret;
+}
+
+static void __bt_ag_agent_start_watch(bt_ag_info_t *bt_ag_info)
+{
+ bt_ag_info->watch_id = g_io_add_watch(bt_ag_info->io_chan,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) __bt_ag_event_handler, bt_ag_info);
+}
+
+static void __bt_ag_agent_remove_watch(guint *watch_id)
+{
+ DBG("Remove IO watch ID %d", *watch_id);
+ if (*watch_id > 0) {
+ g_source_remove(*watch_id);
+ *watch_id = 0;
+ }
+}
+
+#if defined(TIZEN_SUPPORT_DUAL_HF)
+gboolean __bt_ag_agent_is_companion_device(const char *addr)
+{
+#if defined(TIZEN_WEARABLE)
+ char *host_device_address = NULL;
+ host_device_address = vconf_get_str(VCONF_KEY_BT_HOST_BT_MAC_ADDR);
+
+ if (!host_device_address) {
+ INFO("Failed to get a companion device address");
+ return FALSE;
+ }
+
+ if (g_strcmp0(host_device_address, addr) == 0) {
+ INFO("addr[%s] is companion device", addr);
+ return TRUE;
+ }
+
+ return FALSE;
+#else
+ /* TODO : Need to add companion device check condition for Phone models */
+ return FALSE;
+#endif
+}
+
+void __bt_convert_device_path_to_address(const gchar *device_path,
+ char *device_address)
+{
+ char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+ char *dev_addr;
+
+ ret_if(device_path == NULL);
+ ret_if(device_address == NULL);
+
+ dev_addr = strstr(device_path, "dev_");
+ if (dev_addr != NULL) {
+ char *pos = NULL;
+ dev_addr += 4;
+ g_strlcpy(address, dev_addr, sizeof(address));
+
+ while ((pos = strchr(address, '_')) != NULL) {
+ *pos = ':';
+ }
+
+ g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
+ }
+}
+
+static gboolean __bt_ag_agent_is_companion_device_connected(void)
+{
+ GSList *l;
+
+ for (l = active_devices ; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ if (data->is_companion_device) {
+ DBG("Companion device found");
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean __bt_ag_agent_check_dual_hf_condition(const gchar *device_path)
+{
+ char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
+ gboolean is_companion_device;
+
+ __bt_convert_device_path_to_address(device_path, device_address);
+ is_companion_device = __bt_ag_agent_is_companion_device(device_address);
+
+ DBG(" device_address[%s]", device_address);
+ DBG(" is_companion_device[%d]", is_companion_device);
+
+ if (__bt_ag_agent_is_companion_device_connected()) {
+ if (is_companion_device)
+ return FALSE;
+ } else {
+ if (!is_companion_device)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif /* TIZEN_SUPPORT_DUAL_HF */
+
+static gboolean __bt_is_phone_locked(int *phone_lock_state)
+{
+ FN_START;
+ int ret;
+
+ if (NULL == phone_lock_state)
+ return FALSE;
+
+ ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, phone_lock_state);
+ if (ret != 0) {
+ ERR("Failed to read [%s]\n", VCONFKEY_IDLE_LOCK_STATE);
+ return FALSE;
+ }
+
+ FN_END;
+ return TRUE;
+}
+
+static gboolean __bt_get_outgoing_callapp_type(int *callapp_type)
+{
+ FN_START;
+
+ if (NULL == callapp_type)
+ return FALSE;
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_BT_HFP_AG_ENABLE)
+ *callapp_type = BT_VOICE_CALL;
+ FN_END;
+ return TRUE;
+#else
+#if 0
+ int ret;
+ ret = vconf_get_int(
+ VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT,
+ callapp_type);
+ if (ret != 0) {
+ ERR("Failed to read [%s]\n",
+ VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT);
+ return FALSE;
+ }
+
+ INFO(" [%s] = [%d]\n",
+ VCONFKEY_CISSAPPL_OUTGOING_CALL_TYPE_INT, *callapp_type);
+#endif
+ /* The vconf value does not include in platform. */
+ *callapp_type = BT_VOICE_CALL;
+ FN_END;
+ return TRUE;
+#endif
+}
+
+static gboolean __bt_get_outgoing_call_condition(int *condition)
+{
+ FN_START;
+
+ if (NULL == condition)
+ return FALSE;
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_BT_HFP_AG_ENABLE)
+ *condition = BT_MO_ONLY_UNLOCKED;
+ FN_END;
+ return TRUE;
+#else
+#if 0
+ int ret;
+ ret = vconf_get_int(
+ VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT,
+ condition);
+ if (ret != 0) {
+ ERR("Failed to read [%s]\n",
+ VCONFKEY_CISSAPPL_OUTGOING_CALL_CONDITIONS_INT);
+ return FALSE;
+ }
+#endif
+ /* The vconf value does not include in platform. */
+ *condition = BT_MO_ONLY_UNLOCKED;
+ FN_END;
+ return TRUE;
+#endif
+}
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_TELEPHONY_ENABLED)
+static gboolean __bt_ag_agent_launch_call_app(const char *number)
+{
+ FN_START;
+ bundle *b;
+
+ DBG_SECURE("number(%s)", number);
+
+ b = bundle_create();
+ if (NULL == b) {
+ ERR("bundle_create() Failed");
+ return FALSE;
+ }
+
+ bundle_add(b, "launch-type", "MO");
+ bundle_add(b, "dial-type", "HEADSET");
+
+ if (strlen(number) != 0)
+ bundle_add(b, "number", number);
+
+ aul_launch_app_async(CALL_APP_ID, b);
+ bundle_free(b);
+
+ FN_END;
+ return TRUE;
+}
+#endif
+
+static void *__bt_ag_agent_launch_call_req(void *arg)
+{
+ FN_START;
+ bundle *b = (bundle *)arg;
+ if (appsvc_run_service(b, 0, NULL, NULL) < 0)
+ ERR("Unable to run app svc");
+ bundle_free(b);
+ call_launch_requested = FALSE;
+ FN_END;
+ return NULL;
+}
+
+static gboolean __bt_ag_agent_make_call(const char *number)
+{
+ FN_START;
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_BT_HFP_AG_ENABLE)
+ FN_END;
+ return __bt_ag_agent_launch_call_app(number);
+#else
+ char telnum[BT_MAX_TEL_NUM_STRING];
+ bundle *b;
+ pthread_t thread_id;
+
+ if (call_launch_requested == TRUE) {
+ DBG("Launch request is in progress");
+ return TRUE;
+ }
+
+ 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");
+
+ call_launch_requested = TRUE;
+ if (pthread_create(&thread_id, NULL,
+ (void *)&__bt_ag_agent_launch_call_req,
+ (void *)b) < 0) {
+ ERR("pthread_create() is failed");
+ call_launch_requested = FALSE;
+ return FALSE;
+ }
+ if (pthread_detach(thread_id) < 0)
+ ERR("pthread_detach() is failed");
+
+ FN_END;
+ return TRUE;
+#endif
+}
+
+static gboolean __bt_ag_agent_make_video_call(const char *mo_number)
+{
+ FN_START;
+ bundle *kb;
+
+ kb = bundle_create();
+ if (NULL == kb)
+ return FALSE;
+
+ bundle_add(kb, "KEY_CALL_TYPE", "MO");
+ bundle_add(kb, "number", mo_number);
+ aul_launch_app("org.tizen.vtmain", kb);
+ bundle_free(kb);
+
+ FN_END;
+ return TRUE;
+}
+
+gboolean _bt_ag_agent_answer_call(unsigned int call_id,
+ const gchar *path, const gchar *sender)
+{
+ FN_START;
+
+ if (path == NULL || sender == NULL) {
+ DBG("Invalid Arguments");
+ return FALSE;
+ }
+
+ DBG("Application path = %s", path);
+ DBG("Call Id = %d", call_id);
+ DBG("Sender = %s", sender);
+
+ _bt_ag_agent_emit_signal(ag_dbus_conn, path,
+ BT_AG_SERVICE_NAME, "Answer",
+ g_variant_new("(u)", call_id));
+ FN_END;
+ return TRUE;
+}
+
+gboolean _bt_ag_agent_reject_call(unsigned int call_id,
+ const gchar *path, const gchar *sender)
+{
+ FN_START;
+
+ if (path == NULL || sender == NULL) {
+ DBG("Invalid Arguments");
+ return FALSE;
+ }
+
+ DBG("Application path = %s", path);
+ DBG("Call Id = %d", call_id);
+ DBG("Sender = %s", sender);
+
+ _bt_ag_agent_emit_signal(ag_dbus_conn, path,
+ BT_AG_SERVICE_NAME, "Reject",
+ g_variant_new("(u)", call_id));
+ FN_END;
+ return TRUE;
+}
+
+gboolean _bt_ag_agent_release_call(unsigned int call_id,
+ const gchar *path, const gchar *sender)
+{
+ FN_START;
+
+ if (path == NULL || sender == NULL) {
+ DBG("Invalid Arguments");
+ return FALSE;
+ }
+
+ DBG("Application path = %s", path);
+ DBG("Call Id = %d", call_id);
+ DBG("Sender = %s", sender);
+
+ _bt_ag_agent_emit_signal(ag_dbus_conn, path,
+ BT_AG_SERVICE_NAME, "Release",
+ g_variant_new("(u)", call_id));
+
+ FN_END;
+ return TRUE;
+}
+
+bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags)
+{
+ bt_hfp_agent_error_t error_code = BT_HFP_AGENT_ERROR_NONE;
+ int callapp_type;
+ int phone_lock_state;
+ int condition;
+
+ FN_START;
+
+ if (number == NULL) {
+ ERR("Invalid Argument");
+ error_code = BT_HFP_AGENT_ERROR_INVALID_PARAM;
+ goto fail;
+ }
+
+ DBG("Number = %s", number);
+ DBG("flags = %d", flags);
+
+ if (!__bt_is_phone_locked(&phone_lock_state)) {
+ error_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
+ error_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ if (!__bt_get_outgoing_call_condition(&condition)) {
+ error_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ if (condition == BT_MO_ONLY_UNLOCKED && phone_lock_state ==
+ VCONFKEY_IDLE_LOCK) {
+ error_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ if (callapp_type == BT_VIDEO_CALL) {
+ if (!__bt_ag_agent_make_video_call(number)) {
+ ERR("Problem launching application");
+ error_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+ } else {
+ if (!__bt_ag_agent_make_call(number)) {
+ ERR("Problem launching application");
+ error_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+ }
+
+fail:
+ FN_END;
+ return error_code;
+}
+
+bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location)
+{
+ bt_hfp_agent_error_t 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,
+ };
+
+ FN_START;
+
+ DBG("location = %d", location);
+
+ /*Get number from contacts location*/
+ if (contacts_connect() != CONTACTS_ERROR_NONE) {
+ ERR(" contacts_connect failed");
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ 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;
+
+ if (contacts_record_get_str(record, _contacts_speeddial.number, &number)
+ != CONTACTS_ERROR_NONE) {
+ error_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (number == NULL) {
+ ERR("No number at the location");
+ error_code = BT_HFP_AGENT_ERROR_INVALID_MEMORY_INDEX;
+ goto done;
+ }
+
+ DBG("number %s", number);
+
+ /*Make Voice call*/
+ if (!__bt_ag_agent_make_call(number)) {
+ ERR("Problem launching application");
+ 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_disconnect();
+
+ FN_END;
+
+ return error_code;
+}
+
+bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
+ const gchar *path, const gchar *sender)
+{
+ bt_hfp_agent_error_t ret;
+
+ FN_START;
+
+ if (dtmf == NULL || path == NULL || sender == NULL) {
+ ERR("Invalid Argument");
+ return FALSE;
+ }
+
+ DBG("Dtmf = %s", dtmf);
+ DBG("Application path = %s", path);
+ DBG("Sender = %s", sender);
+
+ ret = __bt_ag_agent_gdbus_method_send(sender,
+ path, TELEPHONY_APP_INTERFACE,
+ "SendDtmf", FALSE,
+ g_variant_new("(s)", dtmf));
+
+ return ret;
+}
+
+gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
+ const gchar *path, const gchar *sender)
+{
+ FN_START;
+
+ if (path == NULL || sender == NULL) {
+ DBG("Invalid Arguments");
+ return FALSE;
+ }
+
+ DBG("Application path = %s", path);
+ DBG("Value = %d", chld_value);
+ DBG("Sender = %s", sender);
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_BT_HFP_AG_ENABLE)
+ /* Check if AG supports (i.e. ag_chld_str = "0,1,2") the requested CHLD;
+ if not return FALSE */
+ if (chld_value != 0 && chld_value != 1 && chld_value != 2)
+ return FALSE;
+#else
+ if (chld_value != 0 && chld_value != 1 && chld_value != 2 &&
+ chld_value != 3)
+ return FALSE;
+#endif
+ _bt_ag_agent_emit_signal(ag_dbus_conn, path,
+ BT_AG_SERVICE_NAME, "Threeway",
+ g_variant_new("(u)", chld_value));
+ FN_END;
+ return TRUE;
+}
+
+bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device)
+{
+ bt_hfp_agent_error_t err_code = BT_HFP_AGENT_ERROR_NONE;
+ char *last_num = NULL;
+ int type;
+ int callapp_type;
+ int phone_lock_state;
+ int condition;
+ 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,
+ _contacts_phone_log.log_type,
+ };
+
+ FN_START;
+
+ if (contacts_connect() != CONTACTS_ERROR_NONE) {
+ ERR(" contacts_connect failed");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ return err_code;
+ }
+
+ 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");
+ err_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");
+ err_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");
+ err_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");
+ err_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");
+ err_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");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (contacts_list_first(list) != CONTACTS_ERROR_NONE) {
+ ERR(" contacts_list_first failed");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (contacts_list_get_current_record_p(list, &record) !=
+ CONTACTS_ERROR_NONE) {
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (record == NULL)
+ goto done;
+
+ if (contacts_record_get_str(record, _contacts_phone_log.address,
+ &last_num) != CONTACTS_ERROR_NONE) {
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (last_num == NULL) {
+ ERR("No last number");
+ err_code = BT_HFP_AGENT_ERROR_NO_CALL_LOGS;
+ goto done;
+ }
+
+ if (!__bt_is_phone_locked(&phone_lock_state)) {
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (!__bt_get_outgoing_callapp_type(&callapp_type)) {
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (!__bt_get_outgoing_call_condition(&condition)) {
+ ERR(" Failed to get the call condition");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ if (condition == BT_MO_ONLY_UNLOCKED &&
+ phone_lock_state == VCONFKEY_IDLE_LOCK) {
+ ERR(" call condition and phone lock state check fail");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto done;
+ }
+
+ switch (callapp_type) {
+ case BT_VOICE_CALL:
+ if (!__bt_ag_agent_make_call(last_num)) {
+ ERR("Problem launching application");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ break;
+ case BT_VIDEO_CALL:
+ if (!__bt_ag_agent_make_video_call(last_num)) {
+ ERR("Problem launching application");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ break;
+ case BT_FOLLOW_CALL_LOG:
+ if (contacts_record_get_int(record,
+ _contacts_phone_log.log_type,
+ &type) != CONTACTS_ERROR_NONE) {
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ break;
+ }
+ if (type == CONTACTS_PLOG_TYPE_VOICE_OUTGOING) {
+ if (!__bt_ag_agent_make_call(last_num)) {
+ ERR("Problem launching application");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ } else if (type == CONTACTS_PLOG_TYPE_VIDEO_OUTGOING) {
+ if (!__bt_ag_agent_make_video_call(last_num)) {
+ ERR("Problem launching application");
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ } else {
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ break;
+ default:
+ err_code = BT_HFP_AGENT_ERROR_INTERNAL;
+ break;
+ }
+
+done:
+
+ if (list != NULL)
+ contacts_list_destroy(list, TRUE);
+
+ if (filter != NULL)
+ contacts_filter_destroy(filter);
+
+ if (query != NULL)
+ contacts_query_destroy(query);
+
+ contacts_disconnect();
+
+ if (last_num != NULL)
+ g_free(last_num);
+
+ FN_END;
+
+ return err_code;
+}
+
+bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
+ const gchar *path, const gchar *sender)
+{
+ bt_hfp_agent_error_t ret;
+
+ FN_START;
+
+ if (cmd == NULL || path == NULL || sender == NULL) {
+ ERR("Invalid Argument");
+ return BT_HFP_AGENT_ERROR_INVALID_PARAM;
+ }
+
+ DBG("cmd = %s", cmd);
+ DBG("Application path = %s", path);
+ DBG("Sender = %s", sender);
+
+ ret = __bt_ag_agent_gdbus_method_send(sender,
+ path, TELEPHONY_APP_INTERFACE,
+ "VendorCmd", FALSE,
+ g_variant_new("(s)", cmd));
+ FN_END;
+ return ret;
+}
+
+gboolean _bt_ag_agent_get_signal_quality(void *device)
+{
+ gint rssi;
+
+ FN_START;
+
+ if (vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &rssi)) {
+ DBG("VCONFKEY_TELEPHONY_RSSI failed\n");
+ goto fail;
+ }
+
+ DBG("RSSI : %d", rssi);
+
+ _bt_hfp_signal_quality_reply(rssi, BT_SIGNAL_QUALITY_BER,
+ device);
+
+ FN_END;
+ return TRUE;
+fail:
+ FN_END;
+ _bt_hfp_signal_quality_reply(-1, -1, device);
+ return FALSE;
+}
+
+gboolean _bt_ag_agent_get_battery_status(void *device)
+{
+ gint battery_chrg_status;
+ gint battery_capacity;
+
+ FN_START;
+
+ 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);
+
+ _bt_hfp_battery_property_reply(device,
+ battery_chrg_status, battery_capacity);
+ FN_END;
+ return TRUE;
+
+fail:
+ _bt_hfp_battery_property_reply(device, -1, -1);
+ FN_END;
+ return FALSE;
+}
+
+gboolean _bt_ag_agent_get_operator_name(void *device)
+{
+ char *operator_name;
+ FN_START;
+
+ operator_name = vconf_get_str(VCONFKEY_TELEPHONY_NWNAME);
+ if (NULL == operator_name) {
+ DBG("vconf_get_str failed");
+ _bt_hfp_operator_reply(NULL, device);
+ return FALSE;
+ }
+
+ DBG("operator_name = [%s]", operator_name);
+
+ _bt_hfp_operator_reply(operator_name, device);
+
+ free(operator_name);
+
+ FN_END;
+ return TRUE;
+}
+
+gboolean _bt_hfp_agent_nrec_status(gboolean status,
+ void *t_device)
+{
+ FN_START;
+ bt_ag_info_t *hs = (bt_ag_info_t *)t_device;
+
+ DBG("NREC status = %d", status);
+ if (status)
+ hs->nrec_status = FALSE;
+ else
+ hs->nrec_status = TRUE;
+
+ _bt_ag_agent_emit_signal(ag_dbus_conn, hs->path,
+ BT_AG_SERVICE_NAME, "NrecStatusChanged",
+ g_variant_new("(b)", status));
+ FN_END;
+ return TRUE;
+}
+
+gboolean _bt_ag_agent_get_imei_number(void *device)
+{
+ FN_START;
+ char *imei_number;
+
+ imei_number = tel_get_misc_me_imei_sync(tapi_handle);
+ if (NULL == imei_number) {
+ ERR("tel_get_misc_me_imei_sync for imei_number failed");
+ goto fail;
+ }
+
+ if (!g_utf8_validate(imei_number, -1, NULL)) {
+ free(imei_number);
+ ERR("get_imei_number : invalid UTF8");
+ goto fail;
+ }
+
+ DBG_SECURE("imei_number = [%s]", imei_number);
+ _bt_hfp_get_imei_number_reply(imei_number, device);
+ free(imei_number);
+ FN_END;
+ return TRUE;
+
+fail:
+ _bt_hfp_get_imei_number_reply(NULL, device);
+ FN_END;
+ return FALSE;
+}
+
+void _bt_ag_agent_get_manufacturer_name(void *device)
+{
+ FN_START;
+ char *manufacturer_name;
+ int ret;
+
+ ret = system_info_get_platform_string("http://tizen.org/system/manufacturer",
+ &manufacturer_name);
+ if (SYSTEM_INFO_ERROR_NONE != ret) {
+ ERR("Get manufacturer_name failed : %d", ret);
+ if (NULL != manufacturer_name)
+ free(manufacturer_name);
+
+ manufacturer_name = g_strdup("Unknown");
+ } else if (!g_utf8_validate(manufacturer_name, -1, NULL)) {
+ free(manufacturer_name);
+ manufacturer_name = g_strdup("Unknown");
+ ERR("get_manufacturer_name : invalid UTF8");
+ }
+
+ DBG_SECURE("manufacturer_name = [%s]", manufacturer_name);
+ _bt_hfp_get_device_manufacturer_reply(manufacturer_name, device);
+ free(manufacturer_name);
+ FN_END;
+}
+
+void _bt_ag_agent_get_imsi(void *device)
+{
+ FN_START;
+ TelSimImsiInfo_t imsi;
+ memset (&imsi, 0, sizeof(TelSimImsiInfo_t));
+ if (tel_get_sim_imsi(tapi_handle, &imsi) != TAPI_API_SUCCESS) {
+ ERR("tel_get_sim_imsi failed");
+ goto fail;
+ }
+ DBG_SECURE("tapi values %s %s %s", imsi.szMcc, imsi.szMnc, imsi.szMsin);
+
+ _bt_hfp_get_imsi_reply(imsi.szMcc, imsi.szMnc, imsi.szMsin, device);
+ FN_END;
+ return;
+fail:
+ _bt_hfp_get_imsi_reply(NULL, NULL, NULL, device);
+ FN_END;
+}
+
+int _bt_ag_agent_registration_status_convert(int result)
+{
+ switch (result) {
+ case TAPI_NETWORK_SERVICE_LEVEL_NO:
+ return BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER;
+ case TAPI_NETWORK_SERVICE_LEVEL_EMERGENCY:
+ return BT_AGENT_NETWORK_REG_STATUS_EMERGENCY;
+ case TAPI_NETWORK_SERVICE_LEVEL_FULL:
+ return BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK;
+ case TAPI_NETWORK_SERVICE_LEVEL_SEARCH:
+ return BT_AGENT_NETWORK_REG_STATUS_SEARCH;
+ default:
+ return BT_AGENT_NETWORK_REG_STATUS_UNKNOWN;
+ }
+ return result;
+}
+
+void _bt_ag_agent_get_creg_status(void *device)
+{
+ FN_START;
+ int result = 0;
+ int ret = 0;
+ int n = 1;
+ int registration_status = 0;
+ int roam_status = 0;
+
+ ret = tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_CIRCUIT_STATUS,
+ &result);
+ if (ret != TAPI_API_SUCCESS) {
+ ERR("tel_get_property_int failed");
+ return;
+ }
+ registration_status =
+ _bt_ag_agent_registration_status_convert(result);
+
+ DBG_SECURE("Registration status %d", result);
+ DBG_SECURE("Mapped Status %d", registration_status);
+ if (registration_status ==
+ BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK) {
+ ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &roam_status);
+ if (ret != 0) {
+ ERR("Get roaming status failed err = %d\n", ret);
+ return;
+ }
+ DBG_SECURE("Roam status %d", roam_status);
+ if (roam_status == 1) {
+ registration_status =
+ BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING;
+ }
+ }
+
+ _bt_hfp_get_creg_status_reply(n, registration_status, device);
+
+ FN_END;
+ return;
+}
+
+void _bt_ag_agent_get_model_name(void *device)
+{
+ FN_START;
+ char *model_name;
+ int ret;
+
+ ret = system_info_get_platform_string("http://tizen.org/system/model_name", &model_name);
+ if (SYSTEM_INFO_ERROR_NONE != ret) {
+ ERR("Get model_name failed: %d", ret);
+ if (NULL != model_name)
+ free(model_name);
+
+ model_name = g_strdup("Unknown");
+ } else if (!g_utf8_validate(model_name, -1, NULL)) {
+ free(model_name);
+ model_name = g_strdup("Unknown");
+ ERR("get_model_name : invalid UTF8");
+ }
+
+ DBG_SECURE("model_name = [%s]", model_name);
+ _bt_hfp_get_model_info_reply(model_name, device);
+ free(model_name);
+ FN_END;
+}
+
+void _bt_ag_agent_get_revision_information(void *device)
+{
+ FN_START;
+ char *revision_info;
+ int ret;
+
+ ret = system_info_get_platform_string("http://tizen.org/system/build.string",
+ &revision_info);
+ if (SYSTEM_INFO_ERROR_NONE != ret) {
+ ERR("Get revision_info failed: %d", ret);
+ if (NULL != revision_info)
+ free(revision_info);
+
+ revision_info = g_strdup("Unknown");
+ } else if (!g_utf8_validate(revision_info, -1, NULL)) {
+ free(revision_info);
+ revision_info = g_strdup("Unknown");
+ ERR("get_revision_info: invalid UTF8");
+ }
+
+ DBG_SECURE("revision_info = [%s]", revision_info);
+ _bt_hfp_get_revision_info_reply(revision_info, device);
+ free(revision_info);
+ FN_END;
+}
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_BT_HFP_AG_ENABLE)
+static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
+{
+ FN_START;
+ bundle *b;
+
+ b = bundle_create();
+ if (NULL == b) {
+ ERR("bundle_create() Failed");
+ return FALSE;
+ }
+
+ bundle_add(b, "domain", "bt_headset");
+ if (!activate)
+ bundle_add(b, "action_type", "deactivate");
+
+ aul_launch_app_async("org.tizen.svoice", b);
+ bundle_free(b);
+ FN_END;
+ return TRUE;
+}
+#else
+static gboolean __bt_ag_agent_launch_voice_dial(gboolean activate)
+{
+ FN_START;
+ app_control_h service = NULL;
+
+ app_control_create(&service);
+
+ if (service == NULL) {
+ ERR("Service create failed");
+ return FALSE;
+ }
+
+ app_control_set_app_id(service, "org.tizen.svoice");
+ app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
+ if (app_control_add_extra_data(service, "domain", "bt_headset")
+ != APP_CONTROL_ERROR_NONE) {
+ ERR("app_control_add_extra_data failed");
+ app_control_destroy(service);
+ return FALSE;
+ }
+
+ if (!activate)
+ if (app_control_add_extra_data(service, "action_type", "deactivate")
+ != APP_CONTROL_ERROR_NONE) {
+ ERR("app_control_add_extra_data failed");
+ app_control_destroy(service);
+ return FALSE;
+ }
+
+ if (app_control_send_launch_request(service, NULL, NULL) !=
+ APP_CONTROL_ERROR_NONE) {
+ ERR("launch failed");
+ app_control_destroy(service);
+ return FALSE;
+ }
+
+ app_control_destroy(service);
+ FN_END;
+ return TRUE;
+}
+#endif
+
+gboolean _bt_ag_agent_voice_dial(gboolean activate)
+{
+ DBG("Activate = %d", activate);
+
+ return __bt_ag_agent_launch_voice_dial(activate);
+}
+
+static void __bt_ag_codec_negotiation_info_reset(bt_ag_info_t *hs,
+ gboolean reset)
+{
+ hs->codec_info.is_negotiating = FALSE;
+ hs->codec_info.requested_by_hf = FALSE;
+ hs->codec_info.sending_codec = 0;
+ if (reset) {
+ hs->codec_info.remote_codecs = 0;
+ hs->codec_info.final_codec = 0;
+ hs->nrec_status = FALSE;
+ }
+
+ if (hs->codec_info.nego_timer) {
+ g_source_remove(hs->codec_info.nego_timer);
+ hs->codec_info.nego_timer = 0;
+ }
+ wbs_opts.wbs_enable = wbs_en;
+}
+
+static gboolean __bt_ag_codec_negotiation_finished(gpointer user_data)
+{
+ struct ag_codec *data = (struct ag_codec *)user_data;
+
+ if (g_strcmp0(data->codec_status, "finish") == 0) {
+ DBG("Codec negotiation finished");
+ __bt_ag_sco_connect(data->bt_ag_info);
+ __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
+ g_free (data->codec_status);
+ g_free (data);
+ return TRUE;
+ } else if (g_strcmp0(data->codec_status, "timeout") == 0) {
+ DBG("Timeout is occured in codec negotiation");
+ }
+
+ if (data->bt_ag_info->codec_info.requested_by_hf) {
+ __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
+ } else {
+ __bt_ag_sco_connect(data->bt_ag_info);
+ __bt_ag_codec_negotiation_info_reset(data->bt_ag_info, FALSE);
+ }
+ g_free (data->codec_status);
+ g_free (data);
+
+ return FALSE;
+}
+
+static bt_hfp_agent_error_t __bt_ag_set_codec(void *device, char *method)
+{
+ GDBusProxy *proxy;
+ GVariant *ret;
+ GError *err = NULL;
+ bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)device;
+
+ proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ BLUEZ_SERVICE_NAME, DEFAULT_ADAPTER_OBJECT_PATH,
+ BT_ADAPTER_INTERFACE, NULL, &err);
+
+ if (!proxy) {
+ if (err) {
+ ERR("Unable to create proxy: %s", err->message);
+ g_clear_error(&err);
+ }
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ ret = g_dbus_proxy_call_sync(proxy, method,
+ g_variant_new("(ss)", "Gateway", bt_ag_info->remote_addr),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &err);
+ if (ret == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("dBUS-RPC is failed");
+ if (err != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ err->code, err->message);
+
+ g_clear_error(&err);
+ }
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ g_variant_unref(ret);
+
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+static bt_hfp_agent_error_t __bt_ag_codec_selection_setup(bt_ag_info_t *hs,
+ uint32_t codec)
+{
+ bt_hfp_agent_error_t err = BT_HFP_AGENT_ERROR_NONE;
+
+ DBG("Codec setup [%x]", codec);
+
+ /* 1. Compare sending codec & recieved code */
+ if (hs->codec_info.sending_codec != codec)
+ err = BT_HFP_AGENT_ERROR_INTERNAL;
+
+ /* 2. Send WB or NB command */
+ switch (codec) {
+ case BT_CVSD_CODEC_ID:
+ err = __bt_ag_set_codec(hs, "SetNbParameters");
+ break;
+ case BT_MSBC_CODEC_ID:
+ err = __bt_ag_set_codec(hs, "SetWbsParameters");
+ break;
+ default:
+ err = BT_HFP_AGENT_ERROR_INTERNAL;
+ break;
+ }
+
+ /* If the vendor specific calling returns error or codec is not correct,
+ * we send CVSD Codec parameter to MM module. and also returns
+ * normal value to HF
+ */
+ if (err != BT_HFP_AGENT_ERROR_NONE)
+ codec = BT_CVSD_CODEC_ID;
+
+ hs->codec_info.final_codec = codec;
+
+ return err;
+}
+
+static bt_hfp_agent_error_t __bt_hfp_send_bcs_command(bt_ag_info_t *hs,
+ gboolean init_by_hf)
+{
+ uint32_t codec;
+ struct ag_codec *data = g_new0(struct ag_codec, 1);
+
+#ifdef TIZEN_KIRAN
+ codec = BT_CVSD_CODEC_ID;
+#else
+ if (hs->codec_info.remote_codecs & BT_MSBC_CODEC_MASK)
+ codec = BT_MSBC_CODEC_ID;
+ else
+ codec = BT_CVSD_CODEC_ID;
+#endif
+
+ if (wbs_opts.wbs_enable == FALSE)
+ codec = BT_CVSD_CODEC_ID;
+
+ hs->codec = codec;
+
+ if (_bt_ag_send_at(hs, "\r\n+BCS: %d\r\n", codec) < 0)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ else
+ DBG("Send +BCS:%d\n", codec);
+
+ /* Send +BCS command to HF, and wait some times */
+ hs->codec_info.is_negotiating = TRUE;
+ hs->codec_info.sending_codec = codec;
+ hs->codec_info.requested_by_hf = init_by_hf;
+ hs->codec_info.final_codec = codec;
+
+ data->bt_ag_info = hs;
+ data->codec_status = g_strdup ("timeout");
+
+ hs->codec_info.nego_timer = g_timeout_add_seconds(
+ HFP_CODEC_NEGOTIATION_TIMEOUT,
+ (GSourceFunc)__bt_ag_codec_negotiation_finished,
+ data);
+
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+
+static bt_hfp_agent_error_t __bt_hfp_codec_connection_setup(
+ bt_ag_info_t *hs, gboolean init_by_hf)
+{
+ DBG("Request to codec connection by %s", init_by_hf ? "HF" : "AG");
+
+ if (hs->state < HEADSET_STATE_CONNECTED)
+ return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+
+ if (hs->codec_info.is_negotiating == TRUE) {
+ /* In codec negotiation, return and wait */
+ ERR("Codec nogotiation is in progress");
+ return BT_HFP_AGENT_ERROR_BUSY;
+ }
+
+ /* Not support Codec Negotiation or Not recieved BAC command */
+ if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) ||
+ hs->codec_info.remote_codecs == 0) {
+ ERR("No support for Codec Negotiation or receive BAC command");
+ if (init_by_hf) {
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ } else {
+ __bt_ag_sco_connect(hs);
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ }
+
+ /* If HF initiated codec connection setup, it should send OK command
+ * before +BCS command transmission.
+ */
+ if (init_by_hf)
+ return HFP_STATE_MNGR_ERR_NONE;
+ else
+ return __bt_hfp_send_bcs_command(hs, init_by_hf);
+}
+
+
+static int __hfp_parse_available_codecs(const char *cmd, uint32_t *codecs)
+{
+ char *str = NULL;
+ *codecs = 0x00000000;
+
+ str = strchr(cmd, '=');
+ if (str == NULL)
+ return -EINVAL;
+
+ while (str != NULL) {
+ str++;
+
+ if (atoi(str) == BT_CVSD_CODEC_ID)
+ *codecs |= BT_CVSD_CODEC_MASK;
+ else if (atoi(str) == BT_MSBC_CODEC_ID)
+ *codecs |= BT_MSBC_CODEC_MASK;
+
+ str = strchr(str, ',');
+ }
+
+ if (*codecs == 0x00000000)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* AT+BAC (Bluetooth Available Codecs) */
+static int __bt_hfp_available_codecs(bt_ag_info_t *hs, const char *buf)
+{
+ uint32_t codecs = 0x00000000;
+ hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
+
+ if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION)) {
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+ } else if (__hfp_parse_available_codecs(buf, &codecs) < 0) {
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+ } else {
+ DBG("Update remote available codecs [%x]", codecs);
+ hs->codec_info.remote_codecs = codecs;
+ }
+
+ _bt_ag_send_response(hs, err);
+
+ /* Reset codec information and
+ * restart codec connection setup by AG
+ */
+ hs->codec_info.final_codec = 0;
+ if (hs->codec_info.nego_timer) {
+ hs->codec_info.is_negotiating = FALSE;
+ hs->codec_info.requested_by_hf = FALSE;
+ hs->codec_info.sending_codec = 0;
+ g_source_remove(hs->codec_info.nego_timer);
+ __bt_hfp_codec_connection_setup(hs, FALSE);
+ }
+
+ return 0;
+}
+
+/* AT+BCC (Bluetooth Codec Connection) */
+static int __bt_hfp_codec_connection(bt_ag_info_t *hs, const char *buf)
+{
+ hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
+
+ err = __bt_hfp_codec_connection_setup(hs, TRUE);
+
+ _bt_ag_send_response(hs, err);
+
+ if (err == HFP_STATE_MNGR_ERR_NONE)
+ err = __bt_hfp_send_bcs_command(hs, TRUE);
+
+ if (err != HFP_STATE_MNGR_ERR_NONE)
+ ERR("Fail to request codec connection setup");
+
+ return 0;
+}
+
+/* AT+BCS (Bluetooth Codec Selection) */
+static int __bt_hfp_codec_selection(bt_ag_info_t *hs, const char *buf)
+{
+ uint32_t codec = 0x00000000;
+ hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
+ struct ag_codec *data = g_new0(struct ag_codec, 1);
+
+ /* Timer reset */
+ if (hs->codec_info.nego_timer) {
+ g_source_remove(hs->codec_info.nego_timer);
+ hs->codec_info.nego_timer = 0;
+ }
+
+ if (!(ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION))
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+ else if (__hfp_parse_available_codecs(buf, &codec) < 0)
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+ else if (__bt_ag_codec_selection_setup(hs, codec) !=
+ BT_HFP_AGENT_ERROR_NONE)
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+
+ data->bt_ag_info = hs;
+ data->codec_status = g_strdup ("finish");
+ _bt_ag_send_response(hs, err);
+ __bt_ag_codec_negotiation_finished(data);
+
+ return 0;
+}
+
+static void __bt_ag_str2ba(const char *str, bt_addr *ba)
+{
+ int i;
+ for (i = 5; i >= 0; i--, str += 3)
+ ba->b[i] = strtol(str, NULL, 16);
+}
+
+static const char *__bt_ag_state2str(hs_state_t state)
+{
+ switch (state) {
+ case HEADSET_STATE_DISCONNECTED:
+ return "disconnected";
+ case HEADSET_STATE_CONNECTING:
+ return "connecting";
+ case HEADSET_STATE_CONNECTED:
+ return "connected";
+ case HEADSET_STATE_PLAY_IN_PROGRESS:
+ return "Play In Progress";
+ case HEADSET_STATE_ON_CALL:
+ return "On Call";
+ }
+
+ return NULL;
+}
+
+void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
+ const char *address)
+{
+ int i;
+ char *ptr = NULL;
+
+ ret_if(address == NULL);
+ ret_if(addr == NULL);
+
+ for (i = 0; i < 6; i++) {
+ addr[5 - i] = strtol(address, &ptr, 16);
+ if (ptr[0] != '\0') {
+ if (ptr[0] != ':')
+ return;
+
+ address = ptr + 1;
+ }
+ }
+}
+
+static gboolean __bt_ag_check_nval(GIOChannel *chan)
+{
+ struct pollfd file_desc;
+
+ memset(&file_desc, 0, sizeof(file_desc));
+ file_desc.fd = g_io_channel_unix_get_fd(chan);
+ file_desc.events = POLLNVAL;
+
+ if (poll(&file_desc, 1, 0) > 0 && (POLLNVAL & file_desc.revents))
+ return TRUE;
+
+ return FALSE;
+}
+
+static int __bt_ag_sco_connect(bt_ag_info_t *hs)
+{
+ struct sco_socket_addr sco_addr;
+ int err;
+ GIOChannel *io;
+ int sco_skt;
+ bt_voice bt_vo;
+ bt_ag_slconn_t *slconn = hs->slc;
+ /*guint watch_id;*/
+
+ if (hs->state != HEADSET_STATE_CONNECTED)
+ return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+#ifdef TIZEN_MEDIA_ENHANCE
+ _bt_ag_agent_check_transport_state();
+#endif
+
+ /* Create Sco socket */
+ sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
+ if (sco_skt < 0) {
+ ERR("ERROR: Create socket failed.\n");
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ /* Bind Sco Socket to Local BD addr */
+ memset(&sco_addr, 0, sizeof(sco_addr));
+ sco_addr.sco_family = AF_BLUETOOTH;
+
+ __bt_ag_str2ba(local_addr, &sco_addr.sco_bdaddr);
+ DBG("Local BD address: %s", local_addr);
+
+ err = bind(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
+ if (err < 0) {
+ ERR("ERROR: sco socket binding failed");
+ ERR("Close SCO skt");
+ close(sco_skt);
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ DBG("Socket FD : %d", sco_skt);
+
+ io = g_io_channel_unix_new(sco_skt);
+ g_io_channel_set_close_on_unref(io, TRUE);
+ /*g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_buffered(io, FALSE);
+ g_io_channel_set_encoding(io, NULL, NULL);*/
+
+ if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
+ (slconn && (slconn->hs_features &
+ BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
+ wbs_opts.wbs_enable == TRUE) {
+ bt_vo.setting = (hs->codec == BT_MSBC_CODEC_ID) ?
+ BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
+
+ DBG("set Bluetooth voice: %d", bt_vo.setting);
+ err = setsockopt(sco_skt, BT_SOCKET_LEVEL,
+ BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
+ if (err < 0) {
+ ERR("ERROR: sco socket set socket option failed");
+ ERR("Close SCO skt");
+ close(sco_skt);
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ } else {
+ DBG("Set NB codec parameter");
+ __bt_ag_set_codec(hs, "SetNbParameters");
+ }
+
+ memset(&sco_addr, 0, sizeof(sco_addr));
+ sco_addr.sco_family = AF_BLUETOOTH;
+ __bt_ag_str2ba(hs->remote_addr, &sco_addr.sco_bdaddr);
+ DBG("remotel BD address: %s", hs->remote_addr);
+
+ err = connect(sco_skt, (struct sockaddr *) &sco_addr, sizeof(sco_addr));
+ if (err < 0 && !(errno == EINPROGRESS || errno == EAGAIN)) {
+ ERR("ERROR: sco socket connect failed : %d", err);
+ ERR("Close SCO skt");
+ close(sco_skt);
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ /* Disabling the watch since SCO is connected */
+ /*watch_id = __bt_ag_set_watch(io,
+ (GIOFunc) __bt_ag_sco_connect_cb, hs);
+ if (watch_id)
+ DBG("SCO watch set Success");*/
+
+ hs->sco = io;
+
+ _bt_ag_set_headset_state(hs, HEADSET_STATE_ON_CALL);
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+static void __bt_ag_close_sco(bt_ag_info_t *hs)
+{
+ DBG("");
+ if (hs->sco) {
+ int sock = g_io_channel_unix_get_fd(hs->sco);
+ shutdown(sock, SHUT_RDWR);
+ g_io_channel_unref(hs->sco);
+ hs->sco = NULL;
+ }
+
+ if (hs->sco_id)
+ __bt_ag_agent_remove_watch(&hs->sco_id);
+}
+
+static gboolean __bt_ag_sco_server_conn_cb(GIOChannel *chan,
+ GIOCondition cond, gpointer user_data)
+{
+ bt_ag_info_t *ag_info = user_data;
+
+ DBG("");
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ ag_info->sco = NULL;
+ if (ag_info->sco_id)
+ __bt_ag_agent_remove_watch(&ag_info->sco_id);
+
+ if (ag_info->watch_id)
+ _bt_ag_set_headset_state(ag_info, HEADSET_STATE_CONNECTED);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean __bt_ag_sco_server_cb(GIOChannel *chan,
+ GIOCondition cond, gpointer user_data)
+{
+ bt_ag_info_t *ag_info = user_data;
+ int sco_skt;
+ int cli_sco_sock;
+ GIOChannel *sco_io;
+ bt_ag_slconn_t *slconn = ag_info->slc;
+ bt_voice bt_vo;
+ int err;
+
+ if ((cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) ||
+ __bt_ag_check_nval(chan)) {
+ ERR("cond or chan is not valid");
+ return FALSE;
+ }
+
+ INFO_C("Incoming SCO....");
+
+ if (ag_info->state < HEADSET_STATE_CONNECTED)
+ return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+
+ sco_skt = g_io_channel_unix_get_fd(chan);
+
+ cli_sco_sock = accept(sco_skt, NULL, NULL);
+ if (cli_sco_sock < 0) {
+ ERR("accept is failed");
+ return TRUE;
+ }
+
+ sco_io = g_io_channel_unix_new(cli_sco_sock);
+ g_io_channel_set_close_on_unref(sco_io, TRUE);
+ g_io_channel_set_encoding(sco_io, NULL, NULL);
+ g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_buffered(sco_io, FALSE);
+
+ if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
+ (slconn && (slconn->hs_features &
+ BT_HF_FEATURE_CODEC_NEGOTIATION)) &&
+ wbs_opts.wbs_enable == TRUE) {
+ bt_vo.setting = (ag_info->codec == BT_MSBC_CODEC_ID) ?
+ BT_HFP_MSBC_VOICE : BT_HFP_CVSD_VOICE;
+
+ DBG("set Bluetooth voice: %d", bt_vo.setting);
+ err = setsockopt(cli_sco_sock, BT_SOCKET_LEVEL,
+ BT_VOICE_NUM, &bt_vo, sizeof(bt_vo));
+ if (err < 0) {
+ ERR("Sco socket set socket option failed");
+ close(cli_sco_sock);
+ return FALSE;
+ }
+ }
+
+ ag_info->sco = sco_io;
+ ag_info->sco_id = g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ __bt_ag_sco_server_conn_cb, ag_info);
+
+ if (remote_dev_path)
+ g_free(remote_dev_path);
+
+ remote_dev_path = g_strdup(ag_info->path);
+
+ _bt_ag_set_headset_state(ag_info, HEADSET_STATE_ON_CALL);
+
+ return TRUE;
+}
+
+static int __bt_ag_start_sco_server(bt_ag_info_t *hs)
+{
+ DBG("Start SCO server");
+ struct sco_socket_addr addr;
+ GIOChannel *sco_io;
+ int sco_skt;
+ bdaddr_t bd_addr = {{0},};
+
+ if (hs->sco_server_started) {
+ DBG("Already exsist");
+ return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
+ }
+
+ /* Create socket */
+ sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BT_SCO_PRTCL);
+ if (sco_skt < 0) {
+ ERR("Can't create socket:\n");
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+
+ _bt_convert_addr_string_to_type_rev(bd_addr.b, hs->remote_addr);
+ DBG("Bind to address %s", hs->remote_addr);
+ memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
+
+ if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERR("Can't bind socket:\n");
+ goto error;
+ }
+
+ if (listen(sco_skt, 1)) {
+ ERR("Can not listen on the socket:\n");
+ goto error;
+ }
+
+ sco_io = g_io_channel_unix_new(sco_skt);
+ g_io_channel_set_close_on_unref(sco_io, TRUE);
+ g_io_channel_set_encoding(sco_io, NULL, NULL);
+ g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_buffered(sco_io, FALSE);
+
+ hs->sco_server = sco_io;
+ hs->sco_watch_id = g_io_add_watch(sco_io,
+ G_IO_IN | G_IO_HUP | G_IO_ERR |
+ G_IO_NVAL, __bt_ag_sco_server_cb, hs);
+
+ hs->sco_server_started = TRUE;
+ return BT_HFP_AGENT_ERROR_NONE;
+
+error:
+ close(sco_skt);
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+}
+
+void __bt_ag_stop_sco_server(bt_ag_info_t *hs)
+{
+ DBG("Stop SCO server");
+ if (hs->sco_server) {
+ g_io_channel_shutdown(hs->sco_server, TRUE, NULL);
+ g_io_channel_unref(hs->sco_server);
+ hs->sco_server = NULL;
+ }
+ hs->sco_server_started = FALSE;
+}
+
+static int __bt_ag_headset_close_rfcomm(bt_ag_info_t *hs)
+{
+ GIOChannel *rfcomm = hs->rfcomm;
+
+ if (rfcomm) {
+ g_io_channel_shutdown(rfcomm, TRUE, NULL);
+ g_io_channel_unref(rfcomm);
+ hs->rfcomm = NULL;
+ }
+
+ g_free(hs->slc);
+ hs->slc = NULL;
+
+ return 0;
+}
+
+static gboolean __bt_ag_sco_cb(GIOChannel *chan, GIOCondition cond,
+ bt_ag_info_t *hs)
+{
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (name_owner_sig_id != -1)
+ g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
+ name_owner_sig_id);
+ name_owner_sig_id = -1;
+ g_free(sco_owner);
+ sco_owner = NULL;
+
+ DBG("Audio connection disconnected");
+ _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
+
+ return FALSE;
+}
+
+void _bt_ag_set_headset_state(bt_ag_info_t *hs, hs_state_t state)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+ const char *hs_state;
+ hs_state_t org_state = hs->state;
+ gboolean val = FALSE;
+
+ if (org_state == state)
+ return;
+
+ hs_state = __bt_ag_state2str(state);
+
+ switch (state) {
+ case HEADSET_STATE_CONNECTING:
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn,
+ hs->path,
+ BT_HEADSET_INTERFACE, "State",
+ g_variant_new("s", hs_state));
+ hs->state = state;
+ break;
+
+ case HEADSET_STATE_CONNECTED:
+ if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn,
+ hs->path,
+ BT_HEADSET_INTERFACE, "State",
+ g_variant_new("s", hs_state));
+
+ if (hs->state < state) {
+ val = TRUE;
+ active_devices = g_slist_append(active_devices, hs);
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn,
+ hs->path,
+ BT_HEADSET_INTERFACE,
+ "Connected",
+ g_variant_new("b", val));
+
+ DBG("Device %s connected\n", hs->remote_addr);
+#if defined(TIZEN_SUPPORT_DUAL_HF)
+ if (!hs->is_companion_device)
+ __bt_ag_start_sco_server(hs);
+#else
+ __bt_ag_start_sco_server(hs);
+#endif
+
+ /* Set default code as Gateway NB */
+ __bt_ag_set_codec(hs, "SetNbParameters");
+ } else if (hs->state == HEADSET_STATE_ON_CALL) {
+ val = FALSE;
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn,
+ hs->path,
+ BT_HEADSET_INTERFACE,
+ "Playing",
+ g_variant_new("b", val));
+ }
+ hs->state = state;
+ break;
+
+ case HEADSET_STATE_DISCONNECTED:
+ __bt_ag_close_sco(hs);
+ __bt_ag_headset_close_rfcomm(hs);
+
+ if (hs->state == HEADSET_STATE_ON_CALL) {
+ val = FALSE;
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn,
+ hs->path,
+ BT_HEADSET_INTERFACE,
+ "Playing",
+ g_variant_new("b", val));
+ }
+
+ val = FALSE;
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn,
+ hs->path,
+ BT_HEADSET_INTERFACE,
+ "Connected",
+ g_variant_new("b", val));
+ if (hs->state > HEADSET_STATE_CONNECTING)
+ _bt_hfp_device_disconnected(hs);
+
+ active_devices = g_slist_remove(active_devices, hs);
+
+ __bt_ag_codec_negotiation_info_reset(hs, TRUE);
+#if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
+ __bt_ag_set_codec(hs, "SetNbParameters");
+#endif
+ hs->codec = 0;
+
+ /* Since SCO server is binded on remote address */
+ /* Need to stop SCO server once heasdet disconencted*/
+ if(hs->sco_server_started)
+ __bt_ag_stop_sco_server(hs);
+
+ g_free(hs->remote_addr);
+ g_free(hs->slc);
+ g_free(hs);
+ break;
+
+ case HEADSET_STATE_PLAY_IN_PROGRESS:
+ case HEADSET_STATE_ON_CALL:
+ val = TRUE;
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn,
+ hs->path,
+ BT_HEADSET_INTERFACE, "State",
+ g_variant_new("s", hs_state));
+
+ /*add watch for sco data */
+ hs->sco_id = g_io_add_watch(hs->sco,
+ G_IO_ERR | G_IO_NVAL,
+ (GIOFunc) __bt_ag_sco_cb, hs);
+
+ _bt_ag_agent_emit_property_changed(
+ ag_dbus_conn, hs->path,
+ BT_HEADSET_INTERFACE, "Playing",
+ g_variant_new("b", val));
+
+ if (slconn->microphone_gain >= 0)
+ _bt_ag_send_at(hs, "\r\n+VGM=%u\r\n",
+ slconn->microphone_gain);
+
+ if (slconn->speaker_gain >= 0)
+ _bt_ag_send_at(hs, "\r\n+VGS=%u\r\n",
+ slconn->speaker_gain);
+
+ hs->state = state;
+ break;
+
+ default:
+ hs->state = state;
+ break;
+ }
+
+ INFO("STATE CHANGED from [%s(%d)] to [%s(%d)]",
+ __bt_ag_state2str(org_state), org_state, __bt_ag_state2str(state), state);
+}
+
+static struct event at_event_callbacks[] = {
+ { "AT+BRSF", _bt_hfp_supported_features },
+ { "AT+CIND", _bt_hfp_report_indicators },
+ { "AT+CMER", _bt_hfp_enable_indicators },
+ { "AT+CHLD", _bt_hfp_call_hold },
+ { "ATA", _bt_hfp_answer_call },
+ { "ATD", _bt_hfp_dial_number },
+ { "AT+VG", _bt_hfp_signal_gain_setting },
+ { "AT+CHUP", _bt_hfp_terminate_call },
+ { "AT+CKPD", _bt_hfp_key_press },
+ { "AT+CLIP", _bt_hfp_cli_notification },
+ { "AT+BTRH", _bt_hfp_response_and_hold },
+ { "AT+BLDN", _bt_hfp_last_dialed_number },
+ { "AT+VTS", _bt_hfp_dtmf_tone },
+ { "AT+CNUM", _bt_hfp_subscriber_number },
+ { "AT+CLCC", _bt_hfp_list_current_calls },
+ { "AT+CMEE", _bt_hfp_extended_errors },
+ { "AT+CCWA", _bt_hfp_call_waiting_notify },
+ { "AT+COPS", _bt_hfp_operator_selection },
+ { "AT+NREC", _bt_hfp_nr_and_ec },
+ { "AT+BVRA", _bt_hfp_voice_dial },
+ { "AT+XAPL", _bt_hfp_apl_command },
+ { "AT+IPHONEACCEV", _bt_hfp_apl_command },
+ { "AT+BIA", _bt_hfp_indicators_activation },
+ { "AT+CPBS", _bt_hfp_select_pb_memory },
+ { "AT+CPBR", _bt_hfp_read_pb_entries},
+ { "AT+CPBF", _bt_hfp_find_pb_entires },
+ { "AT+CSCS", _bt_hfp_select_character_set },
+ { "AT+CSQ", _bt_hfp_get_signal_quality },
+ { "AT+CBC", _bt_hfp_get_battery_charge_status },
+ { "AT+CPAS", _bt_hfp_get_activity_status },
+ { "AT+CGSN", _bt_hfp_get_equipment_identity },
+ { "AT+CGMM", _bt_hfp_get_model_information },
+ { "AT+CGMI", _bt_hfp_get_device_manufacturer },
+ { "AT+CGMR", _bt_hfp_get_revision_information },
+ { "AT+BAC", __bt_hfp_available_codecs },
+ { "AT+BCC", __bt_hfp_codec_connection },
+ { "AT+BCS", __bt_hfp_codec_selection },
+ { "AT+XSAT", _bt_hfp_vendor_cmd },
+ { "AT+CIMI", _bt_hfp_get_imsi },
+ { "AT+CREG", _bt_hfp_get_creg_status },
+ { 0 }
+};
+
+int num_of_secure_command = 4;
+static const char* secure_command[] = {"CLCC", "CLIP", "CPBR", "CCWA"};
+
+void __bt_ag_agent_print_at_buffer(char *message, const char *buf)
+{
+
+ int i = 0;
+ char s[MAX_BUFFER_SIZE] = {0, };
+ gboolean hide = FALSE;
+
+ gboolean is_security_command = FALSE;
+ char *xsat_ptr;
+
+ strncpy(s, buf, MAX_BUFFER_SIZE - 1);
+
+ for (i=0; i<num_of_secure_command; i++) {
+ if (strstr(buf, secure_command[i])) {
+ is_security_command = TRUE;
+ break;
+ }
+ }
+
+done:
+ /* +XSAT: 11,DISC */
+ xsat_ptr = strstr(s, "11,DISC,");
+ if (xsat_ptr) {
+ xsat_ptr = xsat_ptr + 8;
+ int x = 0;
+ while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
+ xsat_ptr[x] = 'X';
+ x++;
+ }
+ }
+
+ /* AT+XSAT=11,Q_CT,X,XXXX */
+ xsat_ptr = strstr(s, "11,Q_CT,");
+ if (xsat_ptr) {
+ xsat_ptr = xsat_ptr + 8;
+ int x = 0;
+ while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
+ if (x > 1) /* ignore 0 and 1 position */
+ xsat_ptr[x] = 'X';
+ x++;
+ }
+ }
+
+ i = 0;
+ while (s[i] != '\0') {
+ if (s[i] == '\r' || s[i] == '\n') {
+ s[i] = '.';
+ } else {
+ if (s[i] == '\"')
+ hide = hide ? FALSE : TRUE;
+ else if (is_security_command && hide) {
+ if (i % 2)
+ s[i] = 'X';
+ }
+ }
+ i++;
+ }
+ if (message)
+ INFO("%s Buffer = [%s], Len(%d)", message, s, strlen(s));
+ else
+ INFO("[%s]", s);
+}
+
+static int __bt_ag_at_handler(bt_ag_info_t *hs, const char *buf)
+{
+ struct event *ev;
+
+ __bt_ag_agent_print_at_buffer("[AG AT CMD][RCVD] :", buf);
+
+ for (ev = at_event_callbacks; ev->cmd; ev++) {
+ if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
+ return ev->callback(hs, buf);
+ }
+
+ return -EINVAL;
+}
+
+static int __bt_ag_send_at_valist(bt_ag_info_t *hdset, va_list list,
+ char *list_format)
+{
+ ssize_t final_written, count;
+ char rsp_buffer[MAX_BUFFER_SIZE];
+ int fd;
+ int err;
+
+ count = vsnprintf(rsp_buffer, sizeof(rsp_buffer), list_format, list);
+ if (count < 0) {
+ ERR("count is %d", count);
+ return -EINVAL;
+ }
+
+ if (!hdset->io_chan) {
+ ERR("__bt_ag_send_at_valist: headset not connected");
+ return -EIO;
+ }
+
+ final_written = 0;
+
+ fd = g_io_channel_unix_get_fd(hdset->io_chan);
+
+ if (fd != 0) {
+ while (final_written < count) {
+ ssize_t written;
+
+ do {
+ written = write(fd, rsp_buffer + final_written,
+ count - final_written);
+ } while (written < 0 && errno == EINTR);
+
+ if (written < 0) {
+ err = -errno;
+ ERR("write failed : %s (%d)", strerror(-err), -err);
+ return -errno;
+ }
+
+ final_written += written;
+ }
+
+ /* Synchronize the sending buffer */
+ sync();
+ fsync(fd);
+ } else {
+ ERR("FD is 0. remote_addr : %s", hdset->remote_addr);
+ return -1;
+ }
+
+ __bt_ag_agent_print_at_buffer("[AG AT CMD][SENT]", rsp_buffer);
+
+ return 0;
+}
+
+int __attribute__((format(printf, 2, 3)))
+ _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = __bt_ag_send_at_valist(hs, ap, format);
+ va_end(ap);
+
+ return ret;
+}
+
+void __attribute__((format(printf, 3, 4)))
+ _bt_ag_send_foreach_headset(GSList *devices,
+ int (*cmp) (bt_ag_info_t *hs),
+ char *format, ...)
+{
+ GSList *l;
+ va_list ap;
+
+ for (l = devices; l != NULL; l = l->next) {
+ bt_ag_info_t *hs = l->data;
+ int ret;
+
+ if (cmp && cmp(hs) != 0)
+ continue;
+
+ va_start(ap, format);
+ ret = __bt_ag_send_at_valist(hs, ap, format);
+ if (ret < 0)
+ ERR("Failed to send to headset: %s (%d)",
+ strerror(-ret), -ret);
+ va_end(ap);
+ }
+}
+
+int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err)
+{
+ if ((err != HFP_STATE_MNGR_ERR_NONE) && hs->slc->is_cme_enabled)
+ return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n", err);
+
+ switch (err) {
+ case HFP_STATE_MNGR_ERR_NONE:
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+ case HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE:
+ return _bt_ag_send_at(hs, "\r\nNO CARRIER\r\n");
+ default:
+ return _bt_ag_send_at(hs, "\r\nERROR\r\n");
+ }
+}
+
+static gboolean __bt_ag_event_handler(GIOChannel *channel,
+ GIOCondition cond, void *user_data)
+{
+ bt_ag_slconn_t *slconn;
+ unsigned char event_buf[MAX_BUFFER_SIZE];
+ ssize_t len;
+ size_t available_buffer;
+ int fd;
+ bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
+
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ slconn = bt_ag_info->slc;
+ if (cond & (G_IO_ERR | G_IO_HUP)) {
+ if (bt_ag_info->watch_id)
+ __bt_ag_agent_remove_watch(&bt_ag_info->watch_id);
+
+ ERR("ERR or HUP on RFCOMM socket");
+ INFO_C("Disconnected [AG role] [Terminated by remote dev]");
+ goto failed;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+ len = read(fd, event_buf, sizeof(event_buf) - 1);
+
+ if (len < 0)
+ return FALSE;
+ available_buffer = sizeof(slconn->buffer) - (slconn->start) -
+ (slconn->length) - 1;
+ if (available_buffer < (size_t) len) {
+ ERR("Buffer over flow");
+ goto failed;
+ }
+
+ memcpy(&slconn->buffer[slconn->start], event_buf, len);
+ slconn->length += len;
+
+ slconn->buffer[slconn->start + slconn->length] = '\0';
+
+ while (slconn->length > 0) {
+ char *get_cr;
+ int err;
+ off_t cmd_len;
+
+ get_cr = strchr(&slconn->buffer[slconn->start], '\r');
+ if (!get_cr)
+ break;
+
+ cmd_len = 1 + (off_t) get_cr -
+ (off_t) &slconn->buffer[slconn->start];
+ *get_cr = '\0';
+
+ if (cmd_len > 1) {
+ DBG("Call AT handler");
+ err = __bt_ag_at_handler(bt_ag_info,
+ &slconn->buffer[slconn->start]);
+ } else {
+ ERR("Failed to call AT handler");
+ err = 0;
+ }
+
+ if (err == -EINVAL) {
+ ERR("Unrecognized command: %s",
+ &slconn->buffer[slconn->start]);
+ err = _bt_ag_send_response(bt_ag_info,
+ HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
+ if (err < 0)
+ goto failed;
+ } else if (err < 0)
+ ERR("Error handling command %s: %s (%d)",
+ &slconn->buffer[slconn->start],
+ strerror(-err), -err);
+
+ slconn->start += cmd_len;
+ slconn->length -= cmd_len;
+
+ if (!slconn->length)
+ slconn->start = 0;
+ }
+ return TRUE;
+failed:
+ ERR("Failed in event handler - SLC Disconnect");
+ _bt_ag_set_headset_state(bt_ag_info,
+ HEADSET_STATE_DISCONNECTED);
+ return FALSE;
+}
+
+static gboolean __bt_ag_agent_connection(gint32 fd, const gchar *device_path,
+ const gchar *object_path)
+{
+ GIOFlags flags;
+
+ bt_ag_info_t *bt_ag_info = g_new0(bt_ag_info_t, 1);
+ struct sockaddr_remote address;
+ socklen_t address_len;
+
+ INFO_C("Connected [AG role]");
+ bt_ag_info->rfcomm = NULL;
+ bt_ag_info->slc = NULL;
+ bt_ag_info->hfp_active = TRUE;
+ bt_ag_info->vr_blacklisted = FALSE;
+ bt_ag_info->state = HEADSET_STATE_DISCONNECTED;
+ bt_ag_info->sco_server_started = FALSE;
+ __bt_ag_codec_negotiation_info_reset(bt_ag_info, TRUE);
+
+ bt_ag_info->path = device_path;
+ DBG("device_path = [%s]", device_path);
+
+ address_len = sizeof(address);
+ if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
+ ERR("BD_ADDR is NULL");
+
+ DBG("RFCOMM connection for HFP/HSP is completed. Fd = [%d]", fd);
+ bt_ag_info->fd = fd;
+ bt_ag_info->io_chan = g_io_channel_unix_new(bt_ag_info->fd);
+ flags = g_io_channel_get_flags(bt_ag_info->io_chan);
+
+ flags &= ~G_IO_FLAG_NONBLOCK;
+ flags &= G_IO_FLAG_MASK;
+ g_io_channel_set_flags(bt_ag_info->io_chan, flags, NULL);
+ g_io_channel_set_encoding(bt_ag_info->io_chan, NULL, NULL);
+ g_io_channel_set_buffered(bt_ag_info->io_chan, FALSE);
+
+ bt_ag_info->rfcomm = g_io_channel_ref(bt_ag_info->io_chan);
+
+ bt_ag_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
+ __bt_convert_addr_type_to_rev_string(bt_ag_info->remote_addr,
+ address.remote_bdaddr.b);
+
+#if defined(TIZEN_SUPPORT_DUAL_HF)
+ bt_ag_info->is_companion_device =
+ __bt_ag_agent_is_companion_device(bt_ag_info->remote_addr);
+#endif
+
+ DBG("remote Device Address = [%s]", bt_ag_info->remote_addr);
+
+ if (g_strcmp0(object_path, BT_HS_AG_AGENT_OBJECT_PATH) == 0) {
+ DBG("HSP connection completed");
+ _bt_ag_set_headset_state(bt_ag_info,
+ HEADSET_STATE_CONNECTED);
+ }
+ else {
+ DBG("HFP connection connecting");
+ _bt_ag_set_headset_state(bt_ag_info,
+ HEADSET_STATE_CONNECTING);
+ }
+
+ __bt_ag_agent_start_watch(bt_ag_info);
+
+ bt_ag_info->slc = g_new0(bt_ag_slconn_t, 1);
+ bt_ag_info->slc->speaker_gain = 15;
+ bt_ag_info->slc->microphone_gain = 15;
+ bt_ag_info->slc->is_nrec = TRUE;
+
+ return TRUE;
+}
+
+static gboolean __bt_ag_agent_is_device_vr_blacklisted(const char *lap_addr)
+{
+ char *buffer;
+ FILE *fp;
+ long size;
+ size_t result;
+ char *token;
+ char *saveptr;
+
+ fp = fopen(AGENT_VR_BLACKLIST_FILE, "r");
+
+ if (fp == NULL) {
+ ERR("Unable to open VR blacklist file");
+ return FALSE;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ if (size <= 0) {
+ ERR("size is not a positive number");
+ fclose(fp);
+ return FALSE;
+ }
+
+ rewind(fp);
+
+ buffer = g_malloc0(sizeof(char) * size);
+ if (buffer == NULL) {
+ ERR("g_malloc0 is failed");
+ fclose(fp);
+ return FALSE;
+ }
+ result = fread((char *)buffer, 1, size, fp);
+ fclose(fp);
+ if (result != size) {
+ ERR("Read Error");
+ g_free(buffer);
+ return FALSE;
+ }
+
+ token= strtok_r(buffer, "=", &saveptr);
+ if (token == NULL) {
+ g_free(buffer);
+ return FALSE;
+ }
+
+ while ((token = strtok_r(NULL, ",", &saveptr))) {
+ if (strlen(token) > 8)
+ token[8] = '\0';
+ if (0 == g_strcmp0(token, lap_addr)) {
+ INFO("Voice Recognition blacklisted");
+ g_free(buffer);
+ return TRUE;
+ }
+ }
+ g_free(buffer);
+ return FALSE;
+}
+
+static gboolean __bt_sco_open_delay_timeout_cb(gpointer user_data)
+{
+ bt_ag_info_t *bt_ag_info = (bt_ag_info_t *)user_data;
+ sco_open_timer_id = 0;
+ DBG("sco_open_request (%d)", sco_open_request);
+
+ if (sco_open_request && bt_ag_info->state == HEADSET_STATE_CONNECTED) {
+ bt_ag_slconn_t *slconn = bt_ag_info->slc;
+
+ INFO("try to open SCO");
+ sco_open_request = FALSE;
+
+ if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
+ (slconn && (slconn->hs_features &
+ BT_HF_FEATURE_CODEC_NEGOTIATION))) {
+ switch (bt_ag_info->codec_info.final_codec) {
+ case BT_CVSD_CODEC_ID:
+ __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
+ __bt_ag_sco_connect(bt_ag_info);
+ break;
+ case BT_MSBC_CODEC_ID:
+ __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
+ __bt_ag_sco_connect(bt_ag_info);
+ break;
+ default:
+ __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
+ break;
+ }
+ } else
+ __bt_ag_sco_connect(bt_ag_info);
+ }
+
+ return FALSE;
+}
+
+/*
+* Service level connection complete
+* indication and state management
+*/
+void _bt_ag_slconn_complete(bt_ag_info_t *hs)
+{
+ char lap_address[BT_LOWER_ADDRESS_LENGTH];
+
+ DBG("HFP Service Level Connection established\n");
+
+ /* Check device Voice Recognition blacklist status */
+ g_strlcpy(lap_address, hs->remote_addr, sizeof(lap_address));
+ hs->vr_blacklisted =
+ __bt_ag_agent_is_device_vr_blacklisted(lap_address);
+
+ if (sco_open_timer_id > 0) {
+ g_source_remove(sco_open_timer_id);
+ sco_open_timer_id = 0;
+ }
+
+ sco_open_request = FALSE;
+ sco_open_timer_id = g_timeout_add(BT_SCO_OPEN_DELAY_TIMER,
+ __bt_sco_open_delay_timeout_cb, hs);
+
+ _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
+}
+
+static gboolean __bt_ag_agent_connection_release(bt_ag_info_t *hs)
+{
+
+ g_io_channel_shutdown(hs->io_chan, TRUE, NULL);
+ g_io_channel_unref(hs->io_chan);
+ hs->io_chan = NULL;
+
+ if (hs->sco) {
+ __bt_ag_close_sco(hs);
+ _bt_ag_set_headset_state(hs, HEADSET_STATE_CONNECTED);
+ hs->sco = NULL;
+ }
+ __bt_ag_agent_remove_watch(&hs->watch_id);
+
+ _bt_ag_set_headset_state(hs, HEADSET_STATE_DISCONNECTED);
+ return TRUE;
+}
+
+static GQuark __bt_ag_agent_error_quark(void)
+{
+ FN_START;
+
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string("ag-agent");
+
+ FN_END;
+ return quark;
+}
+
+static GError *__bt_ag_agent_set_error(bt_hfp_agent_error_t error)
+{
+ FN_START;
+ ERR("error[%d]\n", error);
+
+ switch (error) {
+ case BT_HFP_AGENT_ERROR_NOT_AVAILABLE:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_NOT_AVAILABLE);
+ case BT_HFP_AGENT_ERROR_NOT_CONNECTED:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_NOT_CONNECTED);
+ case BT_HFP_AGENT_ERROR_BUSY:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_BUSY);
+ case BT_HFP_AGENT_ERROR_INVALID_PARAM:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_INVALID_PARAM);
+ case BT_HFP_AGENT_ERROR_ALREADY_EXSIST:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_ALREADY_EXSIST);
+ case BT_HFP_AGENT_ERROR_ALREADY_CONNECTED:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_ALREADY_CONNECTED);
+ case BT_HFP_AGENT_ERROR_NO_MEMORY:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_NO_MEMORY);
+ case BT_HFP_AGENT_ERROR_I_O_ERROR:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_I_O_ERROR);
+ case BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_OPERATION_NOT_AVAILABLE);
+ case BT_HFP_AGENT_ERROR_BATTERY_STATUS:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_BATTERY);
+ case BT_HFP_AGENT_ERROR_SIGNAL_STATUS:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_SIGNAL);
+ case BT_HFP_AGENT_ERROR_NO_CALL_LOGS:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_NO_CALL_LOG);
+ case BT_HFP_AGENT_ERROR_INTERNAL:
+ default:
+ return g_error_new(BT_AG_AGENT_ERROR, error,
+ BT_ERROR_INTERNAL);
+ }
+ FN_END;
+}
+
+static bt_ag_info_t *__bt_get_active_headset(const gchar *device_path)
+{
+ GSList *l;
+
+ for (l = active_devices ; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+ if (device_path == NULL) /*just to avoid crash incase of "play" when dailed from device[NEEDS TO BE CHANGED]*/
+ return data;
+ if (g_strcmp0(data->path, device_path) == 0) {
+ INFO("Active device found");
+ return data;
+ }
+ }
+
+ INFO("Active device not found");
+ return NULL;
+}
+
+static void __bt_ag_agent_method(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ FN_START;
+
+ INFO("method %s", method_name);
+ INFO("object_path %s", object_path);
+ int ret = BT_HFP_AGENT_ERROR_NONE;
+ GError *err = NULL;
+ const gchar *device_path = NULL;
+
+ if (g_strcmp0(method_name, "NewConnection") == 0) {
+ gint32 fd;
+ int index;
+ GDBusMessage *msg;
+ GUnixFDList *fd_list;
+ GVariant *options;
+ int device_count = 0;
+ GSList *l;
+
+ device_count = g_slist_length(active_devices);
+
+ INFO("device_count %d", device_count);
+
+ if (device_count >= MAX_CONNECTED_DEVICES) {
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ g_variant_get(parameters, "(oha{sv})",
+ &device_path, &index, &options);
+#if defined(TIZEN_SUPPORT_DUAL_HF)
+ if (device_count &&
+ __bt_ag_agent_check_dual_hf_condition(device_path) == FALSE) {
+ INFO("not allow to connect 2nd HF connection");
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+#endif
+ msg = g_dbus_method_invocation_get_message(invocation);
+ fd_list = g_dbus_message_get_unix_fd_list(msg);
+ if (fd_list == NULL) {
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ fd = g_unix_fd_list_get(fd_list, index, NULL);
+ if (fd == -1) {
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ DBG("FD is = [%d], device_path = [%s]\n", fd, device_path);
+
+ if (!__bt_ag_agent_connection(fd, device_path, object_path)) {
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
+ GSList *l;
+
+ g_variant_get(parameters, "(o)", &device_path);
+ INFO("device_path %s", device_path);
+
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ INFO("data->path %s", data->path);
+ if (g_strcmp0(data->path, device_path) == 0) {
+ if (!__bt_ag_agent_connection_release(data)) {
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+ INFO_C("Disconnected [AG role] [Terminated by local host]");
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ }
+ }
+ } else if (g_strcmp0(method_name, "RegisterApplication") == 0) {
+ gchar *path = NULL;
+ gchar *address = NULL;
+ g_variant_get(parameters, "(&s&s)", &path, &address);
+ /*local_addr = malloc(strlen(address));
+ memcpy(local_addr, address, strlen(address));*/
+
+ DBG("Sender = %s, Application path = %s\n", sender, path);
+ ret = _bt_hfp_register_telephony_agent(TRUE, path, sender);
+ if (ret)
+ goto fail;
+
+ if (local_addr)
+ g_free(local_addr);
+
+ local_addr = g_strdup(address);
+ DBG("Address = %s\n", local_addr);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
+ gchar *path = NULL;
+ g_variant_get(parameters, "(&s)", &path);
+
+ DBG("Application path = %s\n", path);
+ DBG("Sender = %s\n", sender);
+
+ ret = _bt_hfp_register_telephony_agent(FALSE, path, sender);
+ if (ret)
+ goto fail;
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "IncomingCall") == 0) {
+ gchar *path;
+ gchar *number;
+ gint call_id;
+
+ g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
+
+ DBG("Application path = %s", path);
+ DBG_SECURE("Phone number = %s", number);
+ DBG("Call id = %d", call_id);
+
+ DBG("Sender = %s", sender);
+
+ ret = _bt_hfp_incoming_call(path, number, call_id, sender);
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "OutgoingCall") == 0) {
+ gchar *path;
+ gchar *number;
+ gint call_id;
+
+ g_variant_get(parameters, "(&s&si)", &path, &number, &call_id);
+
+ DBG("Application path = %s", path);
+ DBG_SECURE("Phone number = %s", number);
+ DBG("Call id = %d", call_id);
+
+ DBG("Sender = %s", sender);
+
+ ret = _bt_hfp_outgoing_call(path, number, call_id, sender);
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "ChangeCallStatus") == 0) {
+ gchar *path;
+ gchar *number;
+ gint status;
+ gint call_id;
+ GSList *l;
+
+ g_variant_get(parameters, "(&s&sii)",
+ &path, &number, &status, &call_id);
+ DBG("Application path = %s\n", path);
+ DBG_SECURE("Number = %s\n", number);
+ DBG("Status = %d\n", status);
+ DBG("Call id = %d\n", call_id);
+ DBG("Sender = %s\n", sender);
+
+ ret = _bt_hfp_change_call_status(path,
+ number, status, call_id, sender);
+
+ if (_bt_hfp_is_call_exist() == FALSE) {
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ if(data->state == HEADSET_STATE_ON_CALL) {
+ __bt_ag_close_sco(data);
+ _bt_ag_set_headset_state(data,
+ HEADSET_STATE_CONNECTED);
+ }
+ }
+ }
+
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "GetProperties") == 0) {
+ GVariantBuilder *builder;
+ GVariant *var_data;
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+
+ if (bt_ag_info) {
+ gchar *codec = g_strdup("codec");
+ gchar *nrec = g_strdup("nrec");
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(builder, "{sv}",
+ codec, g_variant_new("u", bt_ag_info->codec_info.final_codec));
+ g_variant_builder_add(builder, "{sv}",
+ nrec, g_variant_new("b", bt_ag_info->nrec_status));
+
+ var_data = g_variant_new("(a{sv})", builder);
+ g_variant_builder_unref(builder);
+ g_dbus_method_invocation_return_value(invocation, var_data);
+
+ g_free(codec);
+ g_free(nrec);
+ }
+ } else if (g_strcmp0(method_name, "Disconnect") == 0) {
+ char hdset_address[18] = { 0, };
+ GSList *l;
+
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ __bt_convert_addr_type_to_rev_string(hdset_address,
+ (unsigned char *)data->remote_addr);
+
+ DBG("Disconnect Headset %s, %s\n",
+ hdset_address, data->path);
+ _bt_ag_set_headset_state(data,
+ HEADSET_STATE_DISCONNECTED);
+ }
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "IsConnected") == 0) {
+ gboolean is_connected = FALSE;
+ GSList *l;
+
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ if(data->state == HEADSET_STATE_CONNECTED)
+ is_connected = TRUE;
+ }
+ DBG("is_connected : %s",
+ is_connected ? "Connected":"Disconnected");
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(b)", is_connected));
+ } else if (g_strcmp0(method_name, "IndicateCall") == 0) {
+ GSList *l;
+
+ if (0 == g_slist_length(active_devices)) {
+ ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+ goto fail;
+ }
+
+ if (ag.ring_timer) {
+ DBG("IndicateCall received when already indicating");
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ }
+
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ if(data->state >= HEADSET_STATE_CONNECTED)
+ _bt_ag_send_at(data, "\r\nRING\r\n");
+ }
+
+ __bt_ring_timer_cb(NULL);
+ ag.ring_timer = g_timeout_add(AG_RING_INTERVAL,
+ __bt_ring_timer_cb, NULL);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "CancelCall") == 0) {
+ if (0 == g_slist_length(active_devices)) {
+ ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+ goto fail;
+ }
+
+ if (ag.ring_timer) {
+ g_source_remove(ag.ring_timer);
+ ag.ring_timer = 0;
+ } else
+ DBG("Got CancelCall method call but no call is active");
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "Play") == 0) {
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+ bt_ag_slconn_t *slconn = NULL;
+
+ if (bt_ag_info) {
+ slconn = bt_ag_info->slc;
+ } else {
+ ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+ goto fail;
+ }
+
+#ifndef __TIZEN_OPEN__
+#ifdef MDM_PHASE_2
+ int mode;
+ if ( slconn && FALSE == slconn->is_voice_recognition_running &&
+ mdm_get_service() == MDM_RESULT_SUCCESS) {
+ mode = mdm_get_allow_bluetooth_outgoing_call();
+ mdm_release_service();
+
+ if (mode == MDM_RESTRICTED) {
+ ERR("[MDM] Not allow the outgoing call");
+ ret = BT_HFP_AGENT_ERROR_OPERATION_NOT_AVAILABLE;
+ goto fail;
+ }
+ }
+#endif
+#endif
+
+ switch (bt_ag_info->state) {
+ case HEADSET_STATE_CONNECTING:
+ case HEADSET_STATE_DISCONNECTED:
+ ERR("HEADSET_STATE ERROR");
+ ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+ break;
+ case HEADSET_STATE_CONNECTED:
+ break;
+ case HEADSET_STATE_PLAY_IN_PROGRESS:
+ ERR("Play In Progress");
+ ret = BT_HFP_AGENT_ERROR_BUSY;
+ break;
+ default:
+ break;
+ }
+ if (ret)
+ goto fail;
+
+ if (sco_open_timer_id > 0) {
+ INFO("SCO open delay");
+ sco_open_request = TRUE;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
+ if ((ag.features & BT_AG_FEATURE_CODEC_NEGOTIATION) &&
+ (slconn && (slconn->hs_features &
+ BT_HF_FEATURE_CODEC_NEGOTIATION))) {
+ switch (bt_ag_info->codec_info.final_codec) {
+ case BT_CVSD_CODEC_ID:
+ __bt_ag_set_codec(bt_ag_info, "SetNbParameters");
+ ret = __bt_ag_sco_connect(bt_ag_info);
+ break;
+ case BT_MSBC_CODEC_ID:
+ __bt_ag_set_codec(bt_ag_info, "SetWbsParameters");
+ ret = __bt_ag_sco_connect(bt_ag_info);
+ break;
+ default:
+ ret = __bt_hfp_codec_connection_setup(bt_ag_info, FALSE);
+ break;
+ }
+ } else
+ ret = __bt_ag_sco_connect(bt_ag_info);
+
+ if (ret)
+ goto fail;
+
+ g_free(sco_owner);
+ sco_owner = g_strdup(sender);
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+
+ name_owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
+ NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
+ __bt_ag_name_owner_changed_cb, NULL, NULL);
+ } else if (g_strcmp0(method_name, "Stop") == 0) {
+ GSList *l;
+
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ if(data->state > HEADSET_STATE_CONNECTED) {
+ __bt_ag_close_sco(data);
+ _bt_ag_set_headset_state(data,
+ HEADSET_STATE_CONNECTED);
+ }
+ }
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "IsPlaying") == 0) {
+ gboolean is_playing = FALSE;
+ GSList *l;
+
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ if(data->state == HEADSET_STATE_ON_CALL)
+ is_playing = TRUE;
+ }
+ DBG("is_playing : %s", is_playing ? "Playing":"Not Playing");
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(b)", is_playing));
+ } else if (g_strcmp0(method_name, "GetSpeakerGain") == 0) {
+ bt_ag_slconn_t *slconn = NULL;
+ guint16 gain_value = 0;
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+
+ if (bt_ag_info == NULL) {
+ ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ goto fail;
+ }
+
+ if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
+ ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+ goto fail;
+ }
+
+ slconn = bt_ag_info->slc;
+ if (slconn)
+ gain_value = (guint16) slconn->speaker_gain;
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(q)", gain_value));
+ } else if (g_strcmp0(method_name, "SetSpeakerGain") == 0) {
+ guint16 gain;
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+
+ g_variant_get(parameters, "(q)", &gain);
+ DBG("Speaker gain = %d\n", gain);
+
+ if (bt_ag_info == NULL) {
+ ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ goto fail;
+ }
+
+ ret = _bt_hfp_set_speaker_gain(bt_ag_info, gain);
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "GetMicrophoneGain") == 0) {
+ bt_ag_slconn_t *slconn = NULL;
+ guint16 gain_value;
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+
+ if (bt_ag_info == NULL) {
+ ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ goto fail;
+ }
+
+ if (bt_ag_info->state < HEADSET_STATE_CONNECTED) {
+ ret = BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+ goto fail;
+ }
+
+ slconn = bt_ag_info->slc;
+ if (slconn)
+ gain_value = (guint16) slconn->microphone_gain;
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(q)", gain_value));
+ } else if (g_strcmp0(method_name, "SetMicrophoneGain") == 0) {
+ guint16 gain;
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+
+ g_variant_get(parameters, "(q)", &gain);
+ DBG("Microphone gain = %d\n", gain);
+
+ if (bt_ag_info == NULL) {
+ ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ goto fail;
+ }
+
+ ret = _bt_hfp_set_microphone_gain(bt_ag_info, gain);
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "SetVoiceDial") == 0) {
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+ if (bt_ag_info == NULL) {
+ ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ goto fail;
+ }
+
+ bt_ag_slconn_t *slconn = bt_ag_info->slc;
+ gboolean enable;
+
+ g_variant_get(parameters, "(b)", &enable);
+ DBG("VoiceDail enable = %d\n", enable);
+
+ if ((slconn && !(slconn->hs_features &
+ BT_HF_FEATURE_VOICE_RECOGNITION)))
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ else if (bt_ag_info->vr_blacklisted)
+ ret = BT_HFP_AGENT_ERROR_INTERNAL;
+ else
+ ret = _bt_hfp_set_voice_dial(bt_ag_info, enable);
+
+ if (slconn)
+ slconn->is_voice_recognition_running = enable;
+
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "SendVendorAtCmd") == 0) {
+ gchar *cmd;
+ bt_ag_info_t *bt_ag_info = __bt_get_active_headset(remote_dev_path);
+ if (bt_ag_info == NULL) {
+ ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ goto fail;
+ }
+
+ g_variant_get(parameters, "(&s)", &cmd);
+ if (cmd == NULL){
+ ret = BT_HFP_AGENT_ERROR_INVALID_PARAM;
+ goto fail;
+ }
+
+ DBG("vendor cmd = %s", cmd);
+
+ ret = _bt_hfp_send_vendor_cmd(bt_ag_info, cmd);
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (g_strcmp0(method_name, "CheckPrivilege") == 0) {
+ DBG("Already pass dbus SMACK for bt-service::platform");
+ /* Return success */
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ }
+
+ INFO("-");
+ return;
+
+fail:
+ err = __bt_ag_agent_set_error(ret);
+ g_dbus_method_invocation_return_gerror(invocation, err);
+ g_error_free(err);
+ INFO("-");
+}
+
+static const GDBusInterfaceVTable method_table = {
+ __bt_ag_agent_method,
+ NULL,
+ NULL,
+};
+
+static GDBusNodeInfo *__bt_ag_create_method_node_info
+ (const gchar *introspection_data)
+{
+ GError *err = NULL;
+ GDBusNodeInfo *node_info = NULL;
+
+ if (introspection_data == NULL)
+ return NULL;
+
+ node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
+
+ if (err) {
+ ERR("Unable to create node: %s", err->message);
+ g_clear_error(&err);
+ }
+ return node_info;
+}
+
+static GDBusConnection *__bt_ag_get_gdbus_connection(void)
+{
+ FN_START;
+
+ GError *err = NULL;
+
+ if (ag_dbus_conn == NULL)
+ ag_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+
+ if (!ag_dbus_conn) {
+ if (err) {
+ ERR("Unable to connect to dbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+ FN_END;
+
+ return ag_dbus_conn;
+}
+
+static gboolean __bt_ag_register_profile_methods(void)
+{
+ FN_START;
+ GError *error = NULL;
+ guint owner_id;
+ GDBusNodeInfo *node_info;
+ gchar *path;
+
+ owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
+ BT_AG_SERVICE_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL, NULL, NULL,
+ NULL, NULL);
+
+ DBG("owner_id is [%d]", owner_id);
+
+ node_info = __bt_ag_create_method_node_info(
+ ag_agent_bluez_introspection_xml);
+ if (node_info == NULL)
+ return FALSE;
+
+ path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
+ DBG("path is [%s]", path);
+
+ hf_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
+ node_info->interfaces[0],
+ &method_table,
+ NULL, NULL, &error);
+ if (hf_bluez_id == 0) {
+ ERR("Failed to register: %s", error->message);
+ g_error_free(error);
+ g_free(path);
+ return FALSE;
+ }
+ g_free(path);
+
+ /* Ag register profile methods for HSP*/
+
+ path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
+ DBG("path is [%s]", path);
+
+ hs_bluez_id = g_dbus_connection_register_object(ag_dbus_conn, path,
+ node_info->interfaces[0],
+ &method_table,
+ NULL, NULL, &error);
+ if (hs_bluez_id == 0) {
+ ERR("Failed to register: %s", error->message);
+ g_error_free(error);
+ g_free(path);
+ return FALSE;
+ }
+ g_free(path);
+
+ node_info = __bt_ag_create_method_node_info
+ (ag_agent_app_introspection_xml);
+ if (node_info == NULL)
+ return FALSE;
+
+ path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
+ DBG("path is [%s]", path);
+
+ app_id = g_dbus_connection_register_object(ag_dbus_conn, path,
+ node_info->interfaces[0],
+ &method_table,
+ NULL, NULL, &error);
+ if (app_id == 0) {
+ ERR("Failed to register: %s", error->message);
+ g_error_free(error);
+ g_free(path);
+ return FALSE;
+ }
+ g_free(path);
+
+ FN_END;
+ return TRUE;
+}
+
+static void __bt_ag_unregister_profile_methods(void)
+{
+ DBG("");
+
+ if (hf_bluez_id > 0) {
+ g_dbus_connection_unregister_object(ag_dbus_conn,
+ hf_bluez_id);
+ hf_bluez_id = 0;
+ }
+
+ if (hs_bluez_id > 0) {
+ g_dbus_connection_unregister_object(ag_dbus_conn,
+ hs_bluez_id);
+ hs_bluez_id = 0;
+ }
+
+ if (app_id > 0) {
+ g_dbus_connection_unregister_object(ag_dbus_conn,
+ app_id);
+ app_id = 0;
+ }
+}
+
+static GDBusProxy *__bt_ag_gdbus_get_service_proxy(const gchar *service,
+ const gchar *path, const gchar *interface)
+{
+ return (service_gproxy) ? service_gproxy :
+ __bt_ag_gdbus_init_service_proxy(service,
+ path, interface);
+}
+
+static void __bt_ag_agent_register(gchar *path, uint16_t profile_version,
+ char *profile_uuid, const char* profile_name)
+{
+ FN_START;
+ GDBusProxy *proxy;
+ GVariant *ret;
+ GError *error = NULL;
+ GVariantBuilder *builder;
+
+ proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
+ "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
+ if (proxy == NULL)
+ return;
+
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(builder, "{sv}",
+ "Name", g_variant_new("s",
+ profile_name));
+ g_variant_builder_add(builder, "{sv}",
+ "Version", g_variant_new("q", profile_version));
+ /*g_variant_builder_add(builder, "{sv}",
+ "Role", g_variant_new("s","client"));*/
+ if (g_strcmp0(path, BT_AG_AGENT_OBJECT_PATH) == 0) {
+ g_variant_builder_add(builder, "{sv}",
+ "features", g_variant_new("q", ag.sdp_features));
+ }
+
+ ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
+ g_variant_new("(osa{sv})", path,
+ profile_uuid, builder),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ g_variant_builder_unref(builder);
+ /* set the name and role for the profile*/
+ if (ret == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("dBUS-RPC is failed");
+
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+
+ g_clear_error(&error);
+ }
+ g_free(path);
+ return;
+ }
+ g_variant_unref(ret);
+ g_free(path);
+
+ FN_END;
+ return;
+}
+
+static void __bt_ag_agent_unregister(gchar *path)
+{
+ FN_START;
+ GDBusProxy *proxy;
+ GVariant *ret;
+ GError *error = NULL;
+
+ proxy = __bt_ag_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
+ "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
+ if (proxy == NULL)
+ return;
+
+
+ ret = g_dbus_proxy_call_sync(proxy, "UnregisterProfile",
+ g_variant_new("(o)", path),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ g_free(path);
+ /* set the name and role for the profile*/
+ if (ret == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("dBUS-RPC is failed");
+
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+
+ g_clear_error(&error);
+ }
+ return;
+ }
+ g_variant_unref(ret);
+
+ if (local_addr) {
+ g_free(local_addr);
+ local_addr = NULL;
+ }
+ FN_END;
+ return;
+}
+
+static void __bt_ag_agent_battery_status_cb(keynode_t *node)
+{
+ int batt = vconf_keynode_get_int(node);
+
+ _bt_hfp_set_property_value("BatteryBarsChanged", batt);
+}
+
+static void __bt_ag_agent_network_signal_status_cb(keynode_t *node)
+{
+ int signal_bar = vconf_keynode_get_int(node);
+
+ BT_CHECK_SIGNAL_STRENGTH(signal_bar);
+ _bt_hfp_set_property_value("SignalBarsChanged", signal_bar);
+}
+
+#ifdef TIZEN_SUPPORT_LUNAR_DEVICE
+static void __bt_ag_agent_lunar_connection_status_cb(keynode_t *node)
+{
+ gboolean status = vconf_keynode_get_bool(node);
+ GSList *l;
+ DBG("status = %d", status);
+
+ if (status == TRUE) {
+ for (l = active_devices; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+ _bt_ag_send_at(data, "\r\n+BSIR:1\r\n");
+ }
+ }
+}
+#endif
+
+static void __bt_ag_agent_network_register_status_cb(keynode_t *node)
+{
+ int service = vconf_keynode_get_int(node);
+ bt_hfp_agent_network_registration_status_t network_service;
+ int roam_status;
+ int ret;
+
+ DBG("Current Signal Level = [%d] \n", service);
+
+ 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) {
+ ERR("Get roaming status failed err = %d\n", ret);
+ return;
+ }
+
+ if (roam_status == 0 && service == 1)
+ network_service = BT_AGENT_NETWORK_REG_STATUS_HOME;
+ else if (roam_status == 1 && service == 1)
+ network_service = BT_AGENT_NETWORK_REG_STATUS_ROAMING;
+ else
+ network_service = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
+
+ _bt_hfp_set_property_value("RegistrationChanged", network_service);
+}
+
+static void __bt_ag_agent_subscribe_vconf_updates(void)
+{
+ int ret;
+
+ DBG("\n");
+
+ ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
+ (void *)__bt_ag_agent_battery_status_cb, NULL);
+ if (0 != ret) {
+ ERR("Subsrciption to battery status failed err = [%d]\n", ret);
+ }
+
+ ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_RSSI,
+ (void *)__bt_ag_agent_network_signal_status_cb, NULL);
+ if (0 != ret) {
+ ERR("Subsrciption to netowrk signal failed err = [%d]\n", ret);
+ }
+
+ ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
+ (void *)__bt_ag_agent_network_register_status_cb, NULL);
+ if (0 != ret) {
+ ERR("Subsrciption to network failed err = [%d]\n", ret);
+ }
+#ifdef TIZEN_SUPPORT_LUNAR_DEVICE
+ ret = vconf_notify_key_changed(VCONF_KEY_BT_LUNAR_ENABLED,
+ (void *)__bt_ag_agent_lunar_connection_status_cb, NULL);
+ if (0 != ret) {
+ ERR("Subsrciption to lunar connection failed err = [%d]\n", ret);
+ }
+#endif
+}
+
+static void __bt_ag_agent_release_vconf_updates(void)
+{
+ int ret;
+
+ DBG("\n");
+
+ ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
+ (vconf_callback_fn)__bt_ag_agent_battery_status_cb);
+ if (0 != ret) {
+ ERR("vconf_ignore_key_changed failed\n");
+ }
+
+ ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_RSSI,
+ (vconf_callback_fn)__bt_ag_agent_network_signal_status_cb);
+ if (0 != ret) {
+ ERR("vconf_ignore_key_changed failed\n");
+ }
+
+ ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
+ (vconf_callback_fn)__bt_ag_agent_network_register_status_cb);
+ if (0 != ret) {
+ ERR("vconf_ignore_key_changed failed\n");
+ }
+}
+
+static gboolean __bt_ag_agent_send_subscriber_number_changed(
+ const char *number)
+{
+ const char *property = g_strdup("SubscriberNumberChanged");
+
+ FN_START;
+
+ DBG("Number is %s", number);
+
+ if (!_bt_hfp_set_property_name(property, number)) {
+ DBG("Error- set property for subscriber no change - ERROR\n");
+ g_free((void *)property);
+ return FALSE;
+ }
+ g_free((void *)property);
+ FN_END;
+ return TRUE;
+}
+static void __bt_ag_agent_sigterm_handler(int signo)
+{
+ int i;
+ GSList *l;
+
+ ERR_C("***** Signal handler came with signal %d *****", signo);
+
+ for (l = active_devices ; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+ if (!__bt_ag_agent_connection_release(data))
+ ERR("__bt_ag_agent_connection_release failed");
+ }
+ if (ag_dbus_conn)
+ g_dbus_connection_flush(ag_dbus_conn, NULL, NULL, NULL);
+
+ if (gmain_loop) {
+ g_main_loop_quit(gmain_loop);
+ DBG("Exiting");
+ gmain_loop = NULL;
+ } else {
+ INFO("Terminating AG agent");
+ exit(0);
+ }
+
+ if (signo == SIGTERM)
+ return;
+
+ for (i = 0; i < BT_AG_SIG_NUM; i++)
+ sigaction(bt_ag_sig_to_handle[i], &(bt_ag_sigoldact[i]), NULL);
+
+ raise(signo);
+}
+
+static void __bt_ag_agent_tel_cb(TapiHandle *handle,
+ int result,
+ void *data,
+ void *user_data)
+{
+ TelSimMsisdnList_t *number;
+ gchar *subscriber_number;
+
+ ERR("*********** result = %d", result);
+
+ if (result == TAPI_API_SIM_LOCKED ||
+ result == TAPI_API_SIM_NOT_INITIALIZED ||
+ result == TAPI_API_SERVICE_NOT_READY) {
+ DBG("initializing the tapi event for SIM status");
+ __bt_ag_agent_reg_sim_event(handle, user_data);
+ return;
+ }
+
+ if (data == NULL)
+ return;
+
+ number = (TelSimMsisdnList_t *)data;
+ subscriber_number = g_strdup(number->list[0].num);
+ __bt_ag_agent_send_subscriber_number_changed(subscriber_number);
+ g_free(subscriber_number);
+}
+
+static void __bt_ag_agent_on_noti_sim_status (TapiHandle *handle,
+ const char *noti_id, void *data, void *user_data)
+{
+ TelSimCardStatus_t *status = data;
+ int tapi_result;
+
+ DBG("event TAPI_NOTI_SIM_STATUS received!! status[%d]", *status);
+
+ if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
+ __bt_ag_agent_dereg_sim_event(handle);
+ tapi_result = tel_get_sim_msisdn(handle, __bt_ag_agent_tel_cb,
+ user_data);
+ if (tapi_result != TAPI_API_SUCCESS)
+ ERR("Fail to get sim info: %d", tapi_result);
+ }
+}
+
+static void __bt_ag_agent_reg_sim_event (TapiHandle *handle, void *user_data)
+{
+ int ret;
+ ret = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS,
+ __bt_ag_agent_on_noti_sim_status, user_data);
+
+ if (ret != TAPI_API_SUCCESS)
+ ERR("event register failed(%d)", ret);
+}
+
+static void __bt_ag_agent_dereg_sim_event (TapiHandle *handle)
+{
+ int ret;
+ ret = tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
+
+ if (ret != TAPI_API_SUCCESS)
+ ERR("event deregister failed(%d)", ret);
+}
+
+static void __bt_ag_name_owner_changed_cb(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ FN_START;
+ char *name_owner = NULL;
+ char *old_owner = NULL;
+ char *new_owner = NULL;
+
+ if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
+ GSList *l;
+
+ g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
+
+ _bt_hfp_release_all_calls_by_sender(name_owner);
+
+ if (sco_owner == NULL)
+ return;
+
+ if (strcasecmp(name_owner, sco_owner) == 0) {
+ if (name_owner_sig_id != -1)
+ g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
+ name_owner_sig_id);
+ name_owner_sig_id = -1;
+ g_free(sco_owner);
+ sco_owner = NULL;
+
+ for (l = active_devices ; l; l = l->next) {
+ bt_ag_info_t *data = l->data;
+
+ if (data->sco) {
+ __bt_ag_close_sco(data);
+ _bt_ag_set_headset_state(data,
+ HEADSET_STATE_CONNECTED);
+ }
+ }
+ }
+ }
+}
+
+static void __bt_ag_agent_filter_cb(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ FN_START;
+ char *path = NULL;
+ GVariant *optional_param;
+
+ if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
+
+ g_variant_get(parameters, "(&o@a{sa{sv}})",
+ &path, &optional_param);
+ if (!path) {
+ ERR("Invalid adapter path");
+ return;
+ }
+
+ INFO("Adapter Path = [%s]", path);
+ if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
+ gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
+ __bt_ag_agent_register(path, hfp_ver,
+ HFP_AG_UUID, "Hands-Free Audio Gateway");
+
+ path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
+ __bt_ag_agent_register(path, hsp_ver,
+ HSP_AG_UUID, "Headset Audio Gateway");
+ }
+ } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
+ g_variant_get(parameters, "(&o@as)", &path, &optional_param);
+ if (!path) {
+ ERR("Invalid adapter path");
+ return;
+ }
+
+ INFO("Adapter Path = [%s]", path);
+ if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
+ gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
+ __bt_ag_agent_unregister(path);
+
+ path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
+ __bt_ag_agent_unregister(path);
+ }
+ }
+
+ FN_END;
+}
+
+static void __bt_ag_agent_dbus_deinit(void)
+{
+
+ if (service_gproxy) {
+ g_object_unref(service_gproxy);
+ service_gproxy = NULL;
+ }
+
+ if (app_gproxy) {
+ g_object_unref(app_gproxy);
+ app_gproxy = NULL;
+ }
+
+ if (ag_dbus_conn) {
+ __bt_ag_unregister_profile_methods();
+
+ if (owner_sig_id != -1)
+ g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
+ owner_sig_id);
+
+ if (name_owner_sig_id != -1)
+ g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
+ name_owner_sig_id);
+#ifdef TIZEN_MEDIA_ENHANCE
+ if (media_sig_id != -1)
+ g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
+ media_sig_id);
+
+ if (media_state_sig_id != -1)
+ g_dbus_connection_signal_unsubscribe(ag_dbus_conn,
+ media_state_sig_id);
+#endif
+ name_owner_sig_id = -1;
+ g_free(sco_owner);
+ sco_owner = NULL;
+
+ g_object_unref(ag_dbus_conn);
+ ag_dbus_conn= NULL;
+ }
+ return;
+}
+
+static int __bt_ag_agent_get_adapter_path(GDBusConnection *conn, char *path)
+{
+ GError *err = NULL;
+ GDBusProxy *manager_proxy = NULL;
+ GVariant *result = NULL;
+ char *adapter_path = NULL;
+
+ if (conn == NULL)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+
+ manager_proxy = g_dbus_proxy_new_sync(conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ BLUEZ_SERVICE_NAME,
+ "/",
+ BT_MANAGER_INTERFACE,
+ NULL, &err);
+
+ if (!manager_proxy) {
+ ERR("Unable to create proxy: %s", err->message);
+ goto fail;
+ }
+
+ result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ if (!result) {
+ if (err != NULL)
+ ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
+ else
+ ERR("Fail to get DefaultAdapter");
+
+ goto fail;
+ }
+
+ if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
+ ERR("Incorrect result\n");
+ goto fail;
+ }
+
+ g_variant_get(result, "(&o)", &adapter_path);
+
+ if (adapter_path == NULL ||
+ strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
+ ERR("Adapter path is inproper\n");
+ goto fail;
+ }
+
+ if (path)
+ g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
+
+ g_variant_unref(result);
+ g_object_unref(manager_proxy);
+
+ return 0;
+
+fail:
+ g_clear_error(&err);
+
+ if (result)
+ g_variant_unref(result);
+
+ if (manager_proxy)
+ g_object_unref(manager_proxy);
+
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+
+}
+
+#ifdef TIZEN_MEDIA_ENHANCE
+void _bt_ag_agent_check_transport_state(void)
+{
+ FN_START;
+
+ if (transport_state == MEDIA_TRANSPORT_STATE_PLAYING) {
+ GDBusProxy *proxy;
+ GVariant *ret;
+ GError *err = NULL;
+
+ proxy = g_dbus_proxy_new_sync(ag_dbus_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ "org.PulseAudio2", A2DP_SOURCE_ENDPOINT,
+ BLUEZ_MEDIA_ENDPOINT_INTERFACE, NULL, &err);
+
+ if (!proxy) {
+ if (err) {
+ ERR("Unable to create proxy: %s", err->message);
+ g_clear_error(&err);
+ }
+ return;
+ }
+ INFO_C("SuspendMedia initiated");
+
+ g_dbus_proxy_call(proxy,
+ "SuspendMedia", NULL,
+ G_DBUS_CALL_FLAGS_NONE, 2000,
+ NULL, NULL, NULL);
+ transport_state = MEDIA_TRANSPORT_STATE_IDLE;
+ }
+
+ FN_END;
+}
+
+static void __bt_ag_agent_transport_state_update(const char *value)
+{
+
+ if (!g_strcmp0(value, "idle"))
+ transport_state = MEDIA_TRANSPORT_STATE_IDLE;
+ else if (!g_strcmp0(value, "pending") || !g_strcmp0(value, "active"))
+ transport_state = MEDIA_TRANSPORT_STATE_PLAYING;
+ else
+ transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
+
+ INFO_C("transport_state %d", transport_state);
+}
+
+static void __bt_ag_agent_media_filter_cb(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ FN_START;
+ char *inter = NULL;
+ GVariant *dict_param = NULL;
+ GVariant *optional_param = NULL;
+
+ if (strcasecmp(signal_name, "PropertiesChanged") == 0) {
+ if (g_strcmp0(g_variant_get_type_string(parameters),
+ "(sa{sv}as)")) {
+ ERR("Incorrect parameters\n");
+ return;
+ }
+
+ g_variant_get(parameters, "(&s@a{sv}@as)",
+ &inter, &dict_param, &optional_param);
+ if (dict_param && (!g_strcmp0(inter,
+ BLUEZ_MEDIA_TRANSPORT_INTERFACE))){
+ GVariantIter *iter = NULL;
+ const gchar *key = NULL;
+ GVariant *value_var = NULL;
+ gchar *value = NULL;
+ g_variant_get(dict_param, "a{sv}", &iter);
+ while (g_variant_iter_loop(
+ iter, "{sv}", &key, &value_var)) {
+ DBG("key %s", key);
+ if (g_strcmp0(key, "State") == 0) {
+ value = g_variant_get_string(
+ value_var,
+ NULL);
+ DBG("value %s", value);
+ __bt_ag_agent_transport_state_update(value);
+ break;
+ }
+ }
+ g_variant_iter_free(iter);
+ g_variant_unref(dict_param);
+ }
+ } else if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
+ char *profile_uuid = NULL;
+ int state = 0;
+
+ g_variant_get(parameters, "(&si)", &profile_uuid, &state);
+ if ((g_strcmp0(profile_uuid, A2DP_SINK_UUID) == 0) &&
+ (state == BT_PROFILE_STATE_DISCONNECTED)) {
+ DBG("Updating the transport state");
+ __bt_ag_agent_transport_state_update("Disconnect");
+ }
+ }
+
+ FN_END;
+}
+#endif
+static void __bt_ag_agent_dbus_init(void)
+{
+ FN_START;
+
+ if (__bt_ag_get_gdbus_connection() == NULL) {
+ ERR("Error in creating the gdbus connection\n");
+ return;
+ }
+ if (!__bt_ag_register_profile_methods()) {
+ ERR("Error in HFP / HSP register_profile_methods\n");
+ return;
+ }
+
+ if(!__bt_ag_agent_get_adapter_path(ag_dbus_conn , NULL)) {
+
+ gchar *path = g_strdup(BT_AG_AGENT_OBJECT_PATH);
+ __bt_ag_agent_register(path, hfp_ver,
+ HFP_AG_UUID, "Hands-Free Audio Gateway");
+
+ path = g_strdup(BT_HS_AG_AGENT_OBJECT_PATH);
+ __bt_ag_agent_register(path, hsp_ver,
+ HSP_AG_UUID, "Headset Audio Gateway");
+ }
+
+ owner_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
+ NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
+ __bt_ag_agent_filter_cb, NULL, NULL);
+#ifdef TIZEN_MEDIA_ENHANCE
+ media_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
+ NULL, BT_PROPERTIES_INTERFACE, NULL, NULL,
+ NULL, 0, __bt_ag_agent_media_filter_cb,
+ NULL, NULL);
+
+ media_state_sig_id = g_dbus_connection_signal_subscribe(ag_dbus_conn,
+ NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
+ NULL, 0, __bt_ag_agent_media_filter_cb,
+ NULL, NULL);
+
+ transport_state = MEDIA_TRANSPORT_STATE_DISCONNECTED;
+#endif
+ FN_END;
+ return;
+}
+
+static uint32_t __bt_ag_agent_get_ag_features(void)
+{
+
+ uint32_t ag_features = BT_AG_FEATURE_EC_AND_NR |
+ BT_AG_FEATURE_REJECT_CALL |
+ BT_AG_FEATURE_ENHANCED_CALL_STATUS |
+ BT_AG_FEATURE_THREE_WAY_CALL |
+#ifndef TIZEN_KIRAN
+ BT_AG_FEATURE_VOICE_RECOGNITION |
+#endif
+ BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
+
+ wbs_en = TRUE;
+#if defined(TIZEN_BT_HFP_AG_ENABLE)
+ hfp_ver = HFP_VERSION_1_6;
+#else
+ hfp_ver = HFP_VERSION_1_5;
+#endif
+ hsp_ver = HSP_VERSION_1_2;
+
+ if (hfp_ver == HFP_VERSION_1_6)
+ ag_features |= BT_AG_FEATURE_CODEC_NEGOTIATION;
+ return ag_features;
+}
+
+void *__bt_ag_agent_telephony_init(void *arg) {
+
+ int tapi_result;
+ uint32_t ag_features = *((uint32_t *)arg);
+
+ INFO_C("Initializing the telephony info");
+
+ _bt_hfp_initialize_telephony_manager(ag_features);
+ __bt_ag_agent_subscribe_vconf_updates();
+
+ tapi_handle = tel_init(NULL);
+ tapi_result = tel_get_sim_msisdn(tapi_handle, __bt_ag_agent_tel_cb,
+ NULL);
+ if (tapi_result != TAPI_API_SUCCESS)
+ ERR("Fail to get sim info: %d", tapi_result);
+ return NULL;
+}
+
+int main(void)
+{
+ int i;
+ uint32_t ag_features;
+ struct sigaction sa;
+ pthread_t thread_id;
+
+ INFO_C("Starting Bluetooth AG agent");
+
+ g_type_init();
+
+ ag_features = __bt_ag_agent_get_ag_features();
+
+ ag.sdp_features = (uint16_t) ag_features & 0x1F;
+
+ if (hfp_ver == HFP_VERSION_1_6 && wbs_en == TRUE)
+ ag.sdp_features |= BT_AG_FEATURE_SDP_WIDEBAND_SPEECH;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = __bt_ag_agent_sigterm_handler;
+
+ for (i = 0; i < BT_AG_SIG_NUM; i++)
+ sigaction(bt_ag_sig_to_handle[i], &sa, &(bt_ag_sigoldact[i]));
+
+ gmain_loop = g_main_loop_new(NULL, FALSE);
+
+ if (gmain_loop == NULL) {
+ ERR("GMainLoop create failed");
+ return EXIT_FAILURE;
+ }
+
+ __bt_ag_agent_dbus_init();
+ if (pthread_create(&thread_id, NULL,
+ (void *)&__bt_ag_agent_telephony_init,
+ &ag_features) < 0) {
+ ERR("pthread_create() is failed");
+ return EXIT_FAILURE;
+ }
+
+ if (pthread_detach(thread_id) < 0) {
+ ERR("pthread_detach() is failed");
+ }
+
+ g_main_loop_run(gmain_loop);
+
+ DBG("Cleaning up");
+
+ tel_deinit(tapi_handle);
+
+ __bt_ag_agent_dbus_deinit();
+ _bt_hfp_deinitialize_telephony_manager();
+ __bt_ag_agent_release_vconf_updates();
+
+ if (remote_dev_path)
+ g_free(remote_dev_path);
+
+ if (gmain_loop)
+ g_main_loop_unref(gmain_loop);
+
+ INFO_C("Terminating Bluetooth AG agent");
+ return 0;
+}
--- /dev/null
+/*
+ * Bluetooth-ag-agent.h
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Chethan TN <chethan.tn@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ * Rakesh MK <rakesh.mk@samsung.com>
+ *
+ * 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_AG_AGENT_H_
+#define __DEF_BT_AG_AGENT_H_
+
+#undef LOG_TAG
+#define LOG_TAG "BLUETOOTH_AG_AGENT"
+
+#define LOG_COLOR_RESET "\033[0m"
+#define LOG_COLOR_RED "\033[31m"
+#define LOG_COLOR_YELLOW "\033[33m"
+#define LOG_COLOR_GREEN "\033[32m"
+#define LOG_COLOR_BLUE "\033[36m"
+#define LOG_COLOR_PURPLE "\033[35m"
+
+#define DBG(fmt, args...) SLOGD(fmt, ##args)
+#define INFO(fmt, args...) SLOGI(fmt, ##args)
+#define ERR(fmt, args...) SLOGE(fmt, ##args)
+#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args)
+#define INFO_SECURE(fmt, args...) SECURE_SLOGI(fmt, ##args)
+#define ERR_SECURE(fmt, args...) SECURE_SLOGE(fmt, ##args)
+#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args)
+#define ERR_SECURE(fmt, args...) SECURE_SLOGE(fmt, ##args)
+#define INFO_C(fmt, arg...) \
+ SLOGI_IF(TRUE, LOG_COLOR_BLUE" "fmt" "LOG_COLOR_RESET, ##arg)
+#define ERR_C(fmt, arg...) \
+ SLOGI_IF(TRUE, LOG_COLOR_RED" "fmt" "LOG_COLOR_RESET, ##arg)
+
+#include <unistd.h>
+#include <dlog.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <errno.h>
+
+#include "vconf.h"
+#include "vconf-keys.h"
+
+#define BT_AG_SERVICE_NAME "org.bluez.ag_agent"
+#define BT_AG_AGENT_OBJECT_PATH "/org/bluez/hfp_agent"
+#define BT_HS_AG_AGENT_OBJECT_PATH "/org/bluez/hsp_agent"
+#define BLUEZ_AG_INTERFACE_NAME "Hands-Free Audio Gateway"
+#define BLUEZ_SERVICE_NAME "org.bluez"
+#define BLUEZ_PROFILE_MGMT_INTERFACE "org.bluez.ProfileManager1"
+#define BT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
+#define HFP_APP_INTERFACE "Org.Hfp.App.Interface"
+#define TELEPHONY_APP_INTERFACE "org.tizen.csd.Call.Instance"
+#define BT_HEADSET_INTERFACE "org.bluez.Headset"
+#define BT_ADAPTER_INTERFACE "org.bluez.Adapter1"
+#ifdef TIZEN_MEDIA_ENHANCE
+#define BT_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
+#define BLUEZ_MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
+#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1"
+#define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource"
+#endif
+
+#define BT_ADAPTER_OBJECT_PATH_MAX 50
+
+#define BT_ADDRESS_STRING_SIZE 18
+#define MAX_BUFFER_SIZE 1024
+
+/* Response and hold values */
+#define BT_RSP_HOLD_NOT_SUPPORTED -2
+#define HANDSFREE_FEATURE_CALL_WAITING_AND_3WAY 0x0002
+
+/* HFP Agent Indicator event values */
+#define INDICATOR_EVENT_SERVICE_NONE 0
+#define INDICATOR_EVENT_SERVICE_PRESENT 1
+
+#define INDICATOR_EVENT_CALL_INACTIVE 0
+#define INDICATOR_EVENT_CALL_ACTIVE 1
+
+#define INDICATOR_EVENT_CALLSETUP_INACTIVE 0
+#define INDICATOR_EVENT_CALLSETUP_INCOMING 1
+#define INDICATOR_EVENT_CALLSETUP_OUTGOING 2
+#define INDICATOR_EVENT_CALLSETUP_ALERTING 3
+
+#define INDICATOR_EVENT_CALLHELD_NONE 0
+#define INDICATOR_EVENT_CALLHELD_MULTIPLE 1
+#define INDICATOR_EVENT_CALLHELD_ON_HOLD 2
+
+#define INDICATOR_EVENT_ROAM_INACTIVE 0
+#define INDICATOR_EVENT_ROAM_ACTIVE 1
+
+/* Telephony number types */
+#define AGENT_NUMBER_TYPE_TELEPHONY 129
+#define AGENT_NUMBER_TYPE_INTERNATIONAL 145
+
+/* Call direction parameters */
+#define AGENT_CALL_DIRECTION_OUTGOING 0
+#define AGENT_CALL_DIRECTION_INCOMING 1
+
+#define AGENT_CALL_STATUS_ACTIVE 0
+#define AGENT_CALL_STATUS_HELD 1
+#define AGENT_CALL_STATUS_DIALING 2
+#define AGENT_CALL_STATUS_ALERTING 3
+#define AGENT_CALL_STATUS_INCOMING 4
+#define AGENT_CALL_STATUS_WAITING 5
+
+#define AGENT_CALL_MODE_VOICE 0
+#define AGENT_CALL_MODE_DATA 1
+#define AGENT_CALL_MODE_FAX 2
+
+#define AGENT_CALL_MULTIPARTY_NO 0
+#define AGENT_CALL_MULTIPARTY_YES 1
+
+/* Subscriber number parameters*/
+#define AGENT_SUBSCRIBER_SERVICE_VOICE 4
+
+/* Operator selection mode values */
+#define AGENT_OPERATOR_MODE_AUTO 0
+#define HSP_VERSION_1_2 0x0102
+
+/* Voice recognition blacklist file */
+#define AGENT_VR_BLACKLIST_FILE (APP_SYSCONFDIR"/voice-recognition-blacklist")
+
+#define BT_LOWER_ADDRESS_LENGTH 9
+
+enum hfp_version {
+ HFP_VERSION_1_5 = 0x0105,
+ HFP_VERSION_1_6 = 0x0106,
+ HFP_VERSION_LATEST = HFP_VERSION_1_6,
+};
+
+/* BD Address */
+typedef struct {
+ uint8_t b[6];
+} __attribute__((packed)) bt_addrs;
+
+/**
+ * @brief Outgoing call type status
+ *
+ * 0 : Follow last call log \n
+ * 1 : Voice call \n
+ * 2 : Video call \n
+ */
+#define BT_FOLLOW_CALL_LOG 0
+#define BT_VOICE_CALL 1
+#define BT_VIDEO_CALL 2
+
+/**
+ * @brief The status of making outgoing calls with BT headsets
+ *
+ * 0 : Even when device locked \n
+ * 1 : Only when device unlocked \n
+ */
+#define BT_MO_EVEN_LOCKED 0
+#define BT_MO_ONLY_UNLOCKED 1
+
+#define BT_CVSD_CODEC_ID 1
+#define BT_MSBC_CODEC_ID 2
+
+#define BT_CVSD_CODEC_MASK 0x0001
+#define BT_MSBC_CODEC_MASK 0x0002
+
+#define BT_HFP_MSBC_VOICE 0x0063
+#define BT_HFP_CVSD_VOICE 0x0060
+
+#define BT_SOCKET_LEVEL 274
+#define BT_VOICE_NUM 11
+
+#define BT_SCO_PRTCL 2
+
+#define HFP_CODEC_NEGOTIATION_TIMEOUT 3 /* 3 seconds */
+
+#define BT_SCO_OPEN_DELAY_TIMER 1000 /*1000 milliseconds*/
+
+/* AT+CSQ : Returns received signal strength indication.
+ Command response: +CSQ: <rssi>,<ber>
+ <ber> 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*/
+#define BT_MAX_TEL_NUM_STRING 30
+
+#define FUCNTION_CALLS
+#ifdef FUCNTION_CALLS
+#define FN_START DBG("ENTER==>")
+#define FN_END DBG("EXIT===>")
+#else
+#define FN_START
+#define FN_END
+#endif
+
+/* HS states */
+typedef enum {
+ HEADSET_STATE_DISCONNECTED,
+ HEADSET_STATE_CONNECTING,
+ HEADSET_STATE_CONNECTED,
+ HEADSET_STATE_PLAY_IN_PROGRESS,
+ HEADSET_STATE_ON_CALL
+} hs_state_t;
+
+typedef enum {
+ HFP_STATE_MNGR_ERR_AG_FAILURE = 0,
+ HFP_STATE_MNGR_NO_PHONE_CONNECTION = 1,
+ HFP_STATE_MNGR_ERR_NOT_ALLOWED = 3,
+ HFP_STATE_MNGR_ERR_NOT_SUPPORTED = 4,
+ HFP_STATE_MNGR_ERR_SIM_BUSY = 14,
+ HFP_STATE_MNGR_ERR_INVALID_INDEX = 21,
+ HFP_STATE_MNGR_ERR_INVALID_CHAR_IN_STRING = 25,
+ HFP_STATE_MNGR_ERR_NO_NETWORK_SERVICE = 30,
+ HFP_STATE_MNGR_ERR_NONE = 0x8000
+} hfp_state_manager_err_t;
+
+typedef enum {
+ BT_AG_FEATURE_THREE_WAY_CALL = 0x0001,
+ BT_AG_FEATURE_EC_AND_NR = 0x0002,
+ BT_AG_FEATURE_VOICE_RECOGNITION = 0x0004,
+ BT_AG_FEATURE_INBAND_RINGTONE = 0x0008,
+ BT_AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG = 0x0010,
+ BT_AG_FEATURE_REJECT_CALL = 0x0020,
+ BT_AG_FEATURE_ENHANCED_CALL_STATUS = 0x0040,
+ BT_AG_FEATURE_ENHANCED_CALL_CONTROL = 0x0080,
+ BT_AG_FEATURE_EXTENDED_ERROR_RESULT_CODES = 0x0100,
+ BT_AG_FEATURE_CODEC_NEGOTIATION = 0x0200,
+} bt_ag_agent_feature_t;
+
+typedef enum {
+ BT_HF_FEATURE_EC_ANDOR_NR = 0x0001,
+ BT_HF_FEATURE_CALL_WAITING_AND_3WAY = 0x0002,
+ BT_HF_FEATURE_CLI_PRESENTATION = 0x0004,
+ BT_HF_FEATURE_VOICE_RECOGNITION = 0x0008,
+ BT_HF_FEATURE_REMOTE_VOLUME_CONTROL = 0x0010,
+ BT_HF_FEATURE_ENHANCED_CALL_STATUS = 0x0020,
+ BT_HF_FEATURE_ENHANCED_CALL_CONTROL = 0x0040,
+ BT_HF_FEATURE_CODEC_NEGOTIATION = 0x0080,
+} bt_hf_agent_feature_t;
+
+/* HFP AG service record bitmap. Bluetooth HFP 1.6 spec page 95 */
+#define BT_AG_FEATURE_SDP_3WAY 0x1
+#define BT_AG_FEATURE_SDP_ECNR 0x2
+#define BT_AG_FEATURE_SDP_VOICE_RECOG 0x4
+#define BT_AG_FEATURE_SDP_IN_BAND_RING_TONE 0x8
+#define BT_AG_FEATURE_SDP_ATTACH_VOICE_TAG 0x10
+#define BT_AG_FEATURE_SDP_WIDEBAND_SPEECH 0x20
+
+#define BT_AG_AGENT_ERROR (__bt_ag_agent_error_quark())
+
+#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 BT_CHECK_SIGNAL_STRENGTH(rssi) \
+ if (rssi >= VCONFKEY_TELEPHONY_RSSI_4) \
+ rssi = VCONFKEY_TELEPHONY_RSSI_5
+
+typedef enum {
+ BT_HFP_AGENT_ERROR_NONE,
+ 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_t;
+
+typedef enum {
+ BT_AGENT_NETWORK_REG_STATUS_HOME,
+ BT_AGENT_NETWORK_REG_STATUS_ROAMING,
+ BT_AGENT_NETWORK_REG_STATUS_OFFLINE,
+ BT_AGENT_NETWORK_REG_STATUS_SEARCHING,
+ BT_AGENT_NETWORK_REG_STATUS_NO_SIM,
+ BT_AGENT_NETWORK_REG_STATUS_POWEROFF,
+ BT_AGENT_NETWORK_REG_STATUS_POWERSAFE,
+ BT_AGENT_NETWORK_REG_STATUS_NO_COVERAGE,
+ BT_AGENT_NETWORK_REG_STATUS_REJECTED,
+ BT_AGENT_NETWORK_REG_STATUS_UNKOWN,
+} bt_hfp_agent_network_registration_status_t;
+
+typedef enum {
+ BT_AGENT_NETWORK_REG_STATUS_NOT_REGISTER,
+ BT_AGENT_NETWORK_REG_STATUS_REGISTER_HOME_NETWORK,
+ BT_AGENT_NETWORK_REG_STATUS_SEARCH,
+ BT_AGENT_NETWORK_REG_STATUS_REGISTRATION_DENIED,
+ BT_AGENT_NETWORK_REG_STATUS_UNKNOWN,
+ BT_AGENT_NETWORK_REG_STATUS_REGISTERED_ROAMING,
+ BT_AGENT_NETWORK_REG_STATUS_REGISTERED_SMS_HOME,
+ BT_AGENT_NETWORK_REG_STATUS_REGISTERED_SMS_ROAMING,
+ BT_AGENT_NETWORK_REG_STATUS_EMERGENCY,
+ BT_AGENT_NETWORK_REG_STATUS_REGISTERED_CSFB_HOME,
+ BT_AGENT_NETWORK_REG_STATUS_REGISTERED_CSFB_ROAMING,
+} bt_hfp_agent_reg_status_t;
+
+#ifdef TIZEN_MEDIA_ENHANCE
+typedef enum media_transport_state {
+ MEDIA_TRANSPORT_STATE_DISCONNECTED,
+ MEDIA_TRANSPORT_STATE_IDLE,
+ MEDIA_TRANSPORT_STATE_PLAYING
+} bt_ag_media_transport_state_t;
+
+/* Profile states matched to btd_service_state_t of bluez service.h */
+typedef enum {
+ BT_PROFILE_STATE_UNAVAILABLE,
+ BT_PROFILE_STATE_DISCONNECTED,
+ BT_PROFILE_STATE_CONNECTING,
+ BT_PROFILE_STATE_CONNECTED,
+ BT_PROFILE_STATE_DISCONNECTING,
+} bt_profile_state_t;
+#endif
+
+#define retv_if(expr, val) \
+ do { \
+ if (expr) { \
+ ERR("(%s) return", #expr); \
+ return (val); \
+ } \
+ } while (0)
+
+#define ret_if(expr) \
+ do { \
+ if (expr) { \
+ ERR("(%s) return", #expr); \
+ return; \
+ } \
+ } while (0)
+
+typedef struct {
+ unsigned char b[6];
+} __attribute__((packed)) bdaddr_t;
+
+/* Remote socket address */
+struct sockaddr_remote {
+ sa_family_t family;
+ bdaddr_t remote_bdaddr;
+ uint8_t channel;
+};
+
+typedef struct {
+ const char *indicator_desc;
+ const char *indicator_range;
+ int hfp_value;
+ gboolean ignore;
+ gboolean is_activated;
+} bt_ag_indicators_t;
+
+typedef struct {
+ gboolean telephony_ready; /* plugin initialized */
+ uint32_t features; /* AG features */
+ const bt_ag_indicators_t *indicators; /* Supported indicators */
+ int er_mode; /* Event reporting mode */
+ int er_ind; /* Event reporting for indicators */
+ int rh; /* Response and Hold state */
+ char *number; /* Incoming phone number */
+ int number_type; /* Incoming number type */
+ guint ring_timer; /* For incoming call indication */
+ const char *chld; /* Response to AT+CHLD=? */
+ uint32_t sdp_features; /* SDP features */
+} bt_ag_status_t;
+
+typedef struct {
+ char buffer[MAX_BUFFER_SIZE];
+
+ int start;
+ int length;
+
+ gboolean is_nrec;
+ gboolean is_nrec_req;
+ gboolean is_pending_ring;
+ gboolean is_inband_ring;
+ gboolean is_cme_enabled;
+ gboolean is_cwa_enabled;
+ gboolean is_client_active;
+ gboolean is_voice_recognition_running;
+
+ int speaker_gain;
+ int microphone_gain;
+
+ unsigned int hs_features;
+} bt_ag_slconn_t;
+
+typedef struct {
+/* DBusMessage *msg;
+ DBusPendingCall *call;*/
+ GIOChannel *io;
+ int err;
+ hs_state_t target_state;
+ GSList *callbacks;
+ uint16_t svclass;
+} hs_connecting_t;
+
+typedef struct {
+ char *object_path;
+ gboolean is_negotiating;
+ gboolean requested_by_hf;
+ guint nego_timer;
+ unsigned int remote_codecs;
+ unsigned int sending_codec;
+ unsigned int final_codec;
+} bt_negotiation_info_t;
+
+typedef struct {
+ const char *path;
+ guint32 fd;
+
+ gboolean auto_connect;
+ GIOChannel *io_chan;
+ char *remote_addr;
+ guint watch_id;
+ GIOChannel *sco_server;
+ guint sco_watch_id;
+
+ GIOChannel *rfcomm;
+ GIOChannel *sco;
+ guint sco_id;
+ guint codec;
+
+ gboolean auto_dc;
+
+ guint dc_timer;
+
+ gboolean hfp_active;
+ gboolean search_hfp;
+ gboolean rfcomm_initiator;
+ gboolean vr_blacklisted;
+
+ hs_state_t state;
+ bt_ag_slconn_t *slc;
+ hs_connecting_t *pending;
+ GSList *nrec_cbs;
+ gboolean sco_server_started;
+ gboolean nrec_status;
+ bt_negotiation_info_t codec_info;
+#if defined(TIZEN_SUPPORT_DUAL_HF)
+ gboolean is_companion_device;
+#endif
+} bt_ag_info_t;
+
+typedef void (*headset_nrec_cb) (bt_ag_info_t *hs,
+ gboolean nrec,
+ void *user_data);
+
+struct hs_nrec_callback {
+ unsigned int id;
+ headset_nrec_cb cb;
+ void *user_data;
+};
+
+typedef void (*hs_state_cb) (bt_ag_info_t *hs,
+ hs_state_t old_state,
+ hs_state_t new_state,
+ void *user_data);
+
+struct hs_state_callback {
+ hs_state_cb cb;
+ void *user_data;
+ unsigned int id;
+};
+
+int __attribute__((format(printf, 2, 3)))
+ _bt_ag_send_at(bt_ag_info_t *hs, char *format, ...);
+void __attribute__((format(printf, 3, 4)))
+ _bt_ag_send_foreach_headset(GSList *devices,
+ int (*cmp) (bt_ag_info_t *hs),
+ char *format, ...);
+void _bt_ag_slconn_complete(bt_ag_info_t *hs);
+int _bt_ag_send_response(bt_ag_info_t *hs, hfp_state_manager_err_t err);
+void _bt_hfp_call_hold_request(const char *t_cmd, void *t_device);
+void _bt_hfp_key_press_request(const char *t_key_press, void *t_device);
+void _bt_hfp_terminate_call_request(void *t_device);
+void _bt_hfp_answer_call_request(void *t_device);
+void _bt_hfp_update_event_request(int indicator, void *t_device);
+void _bt_hfp_response_and_hold_request(void *t_device);
+void _bt_hfp_last_dialed_number_request(void *t_device);
+void _bt_hfp_dial_number_request(const char *dial_number, void *t_device);
+void _bt_hfp_channel_dtmf_request(char t_tone, void *t_device);
+void _bt_hfp_subscriber_number_request(void *t_device);
+void _bt_hfp_get_operator_selection_request(void *t_device);
+void _bt_hfp_noise_red_and_echo_cancel_request(gboolean t_enable,
+ void *t_device);
+void _bt_hfp_voice_dial_request(gboolean t_enable, void *t_device);
+void _bt_hfp_set_indicators(const char *t_command, void *t_device);
+void _bt_hfp_select_phonebook_memory_status(void *t_device);
+void _bt_hfp_select_phonebook_memory_list(void *t_device);
+void _bt_hfp_select_phonebook_memory(void *t_device, const gchar *pb_path);
+void _bt_hfp_read_phonebook_entries_list(void *t_device);
+void _bt_hfp_read_phonebook_entries(void *t_device, const char *cmd);
+void _bt_hfp_find_phonebook_entries_status(void *t_device);
+void _bt_hfp_find_phonebook_entries(void *t_device, const char *cmd);
+void _bt_hfp_get_character_set(void *t_device);
+void _bt_hfp_list_supported_character(void *t_device);
+void _bt_hfp_set_character_set(void *t_device, const char *cmd);
+void _bt_hfp_get_battery_property(void *t_device);
+void _bt_hfp_signal_quality_reply(int32_t rssi, int32_t ber,
+ void *t_device);
+void _bt_hfp_battery_property_reply(void *data, int32_t bcs,
+ int32_t bcl);
+void _bt_hfp_operator_reply(char *operator_name, void *t_device);
+bt_hfp_agent_error_t _bt_ag_agent_dial_num(const gchar *number, guint flags);
+bt_hfp_agent_error_t _bt_ag_agent_dial_last_num(void *device);
+bt_hfp_agent_error_t _bt_ag_agent_send_dtmf(const gchar *dtmf,
+ const gchar *path, const gchar *sender);
+bt_hfp_agent_error_t _bt_ag_agent_dial_memory(unsigned int location);
+gboolean _bt_ag_agent_get_signal_quality(void *device);
+gboolean _bt_ag_agent_get_battery_status(void *device);
+gboolean _bt_ag_agent_get_operator_name(void *device);
+gboolean _bt_hfp_agent_nrec_status(gboolean status,
+ void *t_device);
+gboolean _bt_ag_agent_voice_dial(gboolean activate);
+gboolean _bt_ag_agent_answer_call(unsigned int call_id,
+ const gchar *path, const gchar *sender);
+gboolean _bt_ag_agent_reject_call(unsigned int call_id,
+ const gchar *path, const gchar *sender);
+gboolean _bt_ag_agent_release_call(unsigned int call_id,
+ const gchar *path, const gchar *sender);
+gboolean _bt_ag_agent_threeway_call(unsigned int chld_value,
+ const gchar *path, const gchar *sender);
+void _bt_list_current_calls(void *t_device);
+void _bt_get_activity_status(void *t_device);
+int _bt_hfp_set_property_name(const char *property, const char *operator_name);
+void _bt_hfp_get_imei_number_reply(char *imei_number, void *t_device);
+void _bt_hfp_get_model_info_reply(char *model, void *t_device);
+void _bt_hfp_get_device_manufacturer_reply(char *manufacturer, void *t_device);
+void _bt_hfp_get_revision_info_reply(char *revision, void *t_device);
+void _bt_hfp_device_disconnected(void *t_device);
+int _bt_hfp_get_equipment_identity(bt_ag_info_t *device, const char *buf);
+int _bt_hfp_get_model_information(bt_ag_info_t *device, const char *buf);
+int _bt_hfp_get_device_manufacturer(bt_ag_info_t *device, const char *buf);
+int _bt_hfp_get_imsi(bt_ag_info_t *device, const char *buf);
+int _bt_hfp_get_creg_status(bt_ag_info_t *device, const char *buf);
+int _bt_hfp_get_revision_information(bt_ag_info_t *device, const char *buf);
+void _bt_hfp_get_equipment_identity_req(void *t_device);
+bt_hfp_agent_error_t _bt_hfp_register_telephony_agent(gboolean register_flag,
+ const char *path_to_register,
+ const char *sender);
+bt_hfp_agent_error_t _bt_hfp_incoming_call(const char *call_path,
+ const char *incoming_number,
+ uint32_t incoming_call_id,
+ const char *sender);
+bt_hfp_agent_error_t _bt_hfp_outgoing_call(const char *call_path,
+ const char *number,
+ uint32_t call_id, const char *sender);
+bt_hfp_agent_error_t _bt_hfp_change_call_status(const char *call_path,
+ const char *number,
+ uint32_t call_status,
+ uint32_t call_id,
+ const char *sender);
+void _bt_hfp_initialize_telephony_manager(uint32_t ag_features);
+void _bt_hfp_deinitialize_telephony_manager(void);
+gboolean _bt_ag_agent_emit_property_changed(
+ GDBusConnection *connection,
+ const char *path,
+ const char *interface,
+ const char *name,
+ GVariant *property);
+void _bt_hfp_get_model_info_req(void *t_device);
+void _bt_hfp_get_device_manufacturer_req(void *t_device);
+void _bt_hfp_get_imsi_req(void *t_device);
+void _bt_hfp_get_creg_status_req(void *t_device);
+void _bt_hfp_get_revision_info_req(void *t_device);
+gboolean _bt_hfp_is_call_exist(void);
+void _bt_hfp_release_all_calls_by_sender(const char *sender);
+void _bt_hfp_get_imsi_reply(char *mcc, char *mnc, char *msin, void *t_device);
+void _bt_hfp_get_creg_status_reply(int n, int status, void *t_device);
+int _bt_hfp_set_property_value(const char *property, int value);
+void _bt_hfp_vendor_cmd_request(const char *cmd,
+ void *t_device);
+
+gboolean _bt_ag_agent_get_imei_number(void *device);
+void _bt_ag_agent_get_model_name(void *device);
+void _bt_ag_agent_get_manufacturer_name(void *device);
+void _bt_ag_agent_get_imsi(void *device);
+void _bt_ag_agent_get_creg_status(void *device);
+void _bt_ag_agent_get_revision_information(void *device);
+bt_hfp_agent_error_t _bt_ag_agent_vendor_cmd(const gchar *cmd,
+ const gchar *path, const gchar *sender);
+#ifdef TIZEN_MEDIA_ENHANCE
+void _bt_ag_agent_check_transport_state(void);
+#endif
+
+#endif /* __DEF_BT_AG_AGENT_H_ */
--- /dev/null
+/*
+ * bluetooth-ag-handler.c
+ *
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Chethan TN <chethan.tn@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ * Rakesh MK <rakesh.mk@samsung.com>
+ *
+ * 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 "bluetooth-ag-agent.h"
+#include "bluetooth-ag-handler.h"
+#include "vconf.h"
+#include "vconf-keys.h"
+
+extern bt_ag_status_t ag;
+extern GSList *active_devices;
+extern GDBusConnection *ag_dbus_conn;
+extern gchar *remote_dev_path;
+
+ /* AT+CSQ : Returns received signal strength indication.
+ Command response: +CSQ: <rssi>,<ber>
+ <ber> is not supported and has a constant value of 99, included for compatibility reasons.
+*/
+#define BT_SIGNAL_QUALITY_BER 99
+
+wbs_options wbs_opts = {
+ .wbs_enable = FALSE,
+ .i2s_enable = 0x00,
+ .is_master = 0x00,
+ .clock_rate = 0x02,
+ .pcm_interface_rate = 0x00,
+};
+
+/* AT+BRSF response */
+int _bt_hfp_supported_features(bt_ag_info_t *hs, const char *buf)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+ int err;
+// bt_hfp_agent_error_t ret = BT_HFP_AGENT_ERROR_NONE;
+
+ DBG("AT + BRSF");
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ slconn->hs_features = strtoul(&buf[8], NULL, 10);
+#if 0 /* SCO is crashed if below is called when SCO is opened by hf-agent */
+ if (slconn->hs_features & BT_HF_FEATURE_CODEC_NEGOTIATION) {
+ ret = _bt_ag_set_codec(hs, "SetWbsParameters");
+ if (ret != BT_HFP_AGENT_ERROR_NONE)
+ ERR("Unable to set the default WBC codec");
+ } else {
+ /* Default codec is NB */
+ ret = _bt_ag_set_codec(hs, "SetNbParameters");
+ if (ret != BT_HFP_AGENT_ERROR_NONE)
+ ERR("Unable to set the default NBC codec");
+ }
+#endif
+ err = _bt_ag_send_at(hs, "\r\n+BRSF: %u\r\n", ag.features);
+ if (err < 0)
+ return err;
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+static char *__bt_get_indicator_ranges(const bt_ag_indicators_t *indicators)
+{
+ int i;
+ GString *gstr;
+
+ DBG("__bt_get_indicator_ranges");
+ gstr = g_string_new("\r\n+CIND: ");
+
+ for (i = 0; indicators[i].indicator_desc != NULL; i++) {
+ if (i == 0)
+ g_string_append_printf(gstr, "(\"%s\",(%s))",
+ indicators[i].indicator_desc,
+ indicators[i].indicator_range);
+ else
+ g_string_append_printf(gstr, ",(\"%s\",(%s))",
+ indicators[i].indicator_desc,
+ indicators[i].indicator_range);
+ }
+ g_string_append(gstr, "\r\n");
+ return g_string_free(gstr, FALSE);
+}
+
+static char *__bt_get_indicator_values(const bt_ag_indicators_t *indicators)
+{
+ int i;
+ GString *gstr;
+
+ gstr = g_string_new("\r\n+CIND: ");
+ DBG("__bt_get_indicator_values");
+ for (i = 0; indicators[i].indicator_range != NULL; i++) {
+ if (i == 0)
+ g_string_append_printf(gstr, "%d",
+ indicators[i].hfp_value);
+ else
+ g_string_append_printf(gstr, ",%d",
+ indicators[i].hfp_value);
+ }
+ g_string_append(gstr, "\r\n");
+
+ return g_string_free(gstr, FALSE);
+}
+
+static int __bt_check_hdset(bt_ag_info_t *hdset)
+{
+ bt_ag_slconn_t *slconn = hdset->slc;
+
+ if (!hdset->hfp_active)
+ return -1;
+
+ if (slconn->is_client_active)
+ return 0;
+ else
+ return -1;
+}
+
+static int __bt_hfp_cmp(bt_ag_info_t *hs)
+{
+ if (hs->hfp_active)
+ return 0;
+ else
+ return -1;
+}
+
+static int __bt_cwa_cmp(bt_ag_info_t *hs)
+{
+ if (!hs->hfp_active)
+ return -1;
+
+ if (hs->slc->is_cwa_enabled)
+ return 0;
+ else
+ return -1;
+}
+
+gboolean __bt_ring_timer_cb(gpointer data)
+{
+ _bt_ag_send_foreach_headset(active_devices, NULL, "\r\nRING\r\n");
+
+ if (ag.number)
+ _bt_ag_send_foreach_headset(active_devices, __bt_check_hdset,
+ "\r\n+CLIP: \"%s\",%d\r\n",
+ ag.number, ag.number_type);
+
+ return TRUE;
+}
+
+int _bt_incoming_call_indicator(const char *number, int type)
+{
+ bt_ag_info_t *hs;
+ bt_ag_slconn_t *slconn;
+
+ if (!active_devices)
+ return -ENODEV;
+
+ /* Get the updated list of connected devices */
+ hs = active_devices->data;
+ slconn = hs->slc;
+
+ if (ag.ring_timer) {
+ DBG("incoming_call_indicator: already calling....");
+ return -EBUSY;
+ }
+
+ /*If inband ring supported then no need to send RING alert to HF */
+ if (!hs->hfp_active && slconn->is_inband_ring) {
+ DBG("Inband ring tone supported");
+ return 0;
+ }
+
+ DBG("Inband ring tone not supported.. so send a RING to HF");
+ g_free(ag.number);
+ ag.number = g_strdup(number);
+ ag.number_type = type;
+
+ if (slconn->is_inband_ring &&
+ hs->state != HEADSET_STATE_ON_CALL) {
+ slconn->is_pending_ring = TRUE;
+ return 0;
+ }
+
+ __bt_ring_timer_cb(NULL);
+ ag.ring_timer = g_timeout_add(AG_RING_INTERVAL, __bt_ring_timer_cb, NULL);
+
+ return 0;
+}
+
+int _bt_calling_stopped_indicator(void)
+{
+ bt_ag_info_t *dev;
+
+ if (ag.ring_timer) {
+ g_source_remove(ag.ring_timer);
+ ag.ring_timer = 0;
+ }
+
+ if (!active_devices)
+ return 0;
+
+ /* In case SCO is in intermediate state to connect */
+ dev = active_devices->data;
+
+ if (!dev->slc->is_pending_ring && !ag.ring_timer)
+ return -EINVAL;
+
+ dev->slc->is_pending_ring = FALSE;
+
+ return 0;
+}
+
+void _bt_hfp_set_ag_indicator(uint32_t ag_features,
+ const bt_ag_indicators_t *ag_indicators, int rh,
+ const char *chld)
+{
+ DBG("Set Ag Features");
+ ag.telephony_ready = TRUE;
+ ag.features = ag_features;
+ ag.indicators = ag_indicators;
+ ag.rh = rh;
+ ag.chld = chld;
+}
+
+void _bt_hfp_deinitialize(void)
+{
+ g_free(ag.number);
+ memset(&ag, 0, sizeof(ag));
+ ag.rh = BT_RSP_HOLD_NOT_SUPPORTED;
+ ag.er_mode = 3;
+}
+
+/* Send event indication call from Statemanager module */
+bt_hfp_agent_error_t _bt_hfp_event_indicator(int index)
+{
+ if (!active_devices) {
+ DBG("No Active devices present");
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ }
+
+ if (!ag.er_ind) {
+ DBG("Indicate event called but event reporting is disabled");
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+
+ DBG("Sending event notification to hf....");
+
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CIEV: %d,%d\r\n", index + 1,
+ ag.indicators[index].hfp_value);
+
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+/* AT+CIND response */
+int _bt_hfp_report_indicators(bt_ag_info_t *hs, const char *buf)
+{
+ int err;
+ char *str;
+
+ if (strlen(buf) < 8)
+ return -EINVAL;
+
+ if (buf[7] == '=')
+ str = __bt_get_indicator_ranges(ag.indicators);
+ else
+ str = __bt_get_indicator_values(ag.indicators);
+
+ err = _bt_ag_send_at(hs, "%s", str);
+
+ g_free(str);
+
+ if (err < 0)
+ return err;
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+/* AT+CMER response */
+int _bt_event_reporting_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hdset = t_device;
+ bt_ag_slconn_t *slconn = hdset->slc;
+ int ret_val;
+
+ if (err != (bt_hfp_agent_error_t) HFP_STATE_MNGR_ERR_NONE)
+ return _bt_ag_send_response(t_device, err);
+
+ ret_val = _bt_ag_send_at(hdset, "\r\nOK\r\n");
+ if (ret_val < 0)
+ return ret_val;
+
+ if (hdset->state != HEADSET_STATE_CONNECTING)
+ return 0;
+
+ if (slconn->hs_features & HANDSFREE_FEATURE_CALL_WAITING_AND_3WAY &&
+ ag.features & BT_AG_FEATURE_THREE_WAY_CALL)
+ return 0;
+
+ _bt_ag_slconn_complete(hdset);
+
+ return 0;
+}
+
+int _bt_hfp_enable_indicators(bt_ag_info_t *hdset, const char *buffer)
+{
+ if (strlen(buffer) < 13)
+ return -EINVAL;
+
+ /* tokenks can be <mode>,<keyp>,<disp>,<ind>,<bfr>*/
+ char **ind_tokens = g_strsplit(&buffer[8], ",", 5);
+
+ if (g_strv_length(ind_tokens) < 4) {
+ g_strfreev(ind_tokens);
+ return -EINVAL;
+ }
+
+ ag.er_mode = atoi(ind_tokens[0]);
+ ag.er_ind = atoi(ind_tokens[3]);
+
+ DBG("hfp_enable_indicators (CMER): indicator=%d, mode=%d",
+ ag.er_ind, ag.er_mode);
+
+ g_strfreev(ind_tokens);
+ ind_tokens = NULL;
+
+ switch (ag.er_ind) {
+ case 0:
+ case 1:
+ _bt_hfp_update_event_request(ag.er_ind, hdset);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+ /* AT+CHLD response */
+int _bt_hfp_call_hold(bt_ag_info_t *hs, const char *buf)
+{
+ int err;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ if (buf[8] != '?') {
+ _bt_hfp_call_hold_request(&buf[8], hs);
+ return 0;
+ }
+
+ err = _bt_ag_send_at(hs, "\r\n+CHLD: (%s)\r\n", ag.chld);
+ if (err < 0)
+ return err;
+
+ err = _bt_ag_send_at(hs, "\r\nOK\r\n");
+ if (err < 0)
+ return err;
+
+ _bt_ag_slconn_complete(hs);
+
+ return 0;
+}
+
+int _bt_key_press_response(void *t_device, bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_key_press(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ if (ag.ring_timer) {
+ g_source_remove(ag.ring_timer);
+ ag.ring_timer = 0;
+ }
+
+ _bt_hfp_key_press_request(&buf[8], hs);
+
+ return 0;
+}
+
+int _bt_answer_call_response(void *hs, bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(hs, err);
+}
+
+int _bt_hfp_answer_call(bt_ag_info_t *hs, const char *buf)
+{
+ if (ag.ring_timer) {
+ g_source_remove(ag.ring_timer);
+ ag.ring_timer = 0;
+ }
+
+ if (ag.number) {
+ g_free(ag.number);
+ ag.number = NULL;
+ }
+
+ if (remote_dev_path)
+ g_free(remote_dev_path);
+
+ remote_dev_path = g_strdup(hs->path);
+
+ _bt_hfp_answer_call_request(hs);
+
+ return 0;
+}
+int _bt_terminate_call_response(void *t_device,
+ hfp_state_manager_err_t err)
+{
+ bt_ag_info_t *hs = t_device;
+
+ if (err != HFP_STATE_MNGR_ERR_NONE)
+ return _bt_ag_send_response(hs, err);
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_hfp_terminate_call(bt_ag_info_t *hs, const char *buf)
+{
+ if (ag.number) {
+ g_free(ag.number);
+ ag.number = NULL;
+ }
+
+ if (ag.ring_timer) {
+ g_source_remove(ag.ring_timer);
+ ag.ring_timer = 0;
+ }
+
+ _bt_hfp_terminate_call_request(hs);
+
+ return 0;
+}
+
+int _bt_hfp_cli_notification(bt_ag_info_t *hs, const char *buf)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ slconn->is_client_active = buf[8] == '1' ? TRUE : FALSE;
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_response_and_hold_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_response_and_hold(bt_ag_info_t *hs, const char *buf)
+{
+
+ if (strlen(buf) < 8)
+ return -EINVAL;
+
+ if (ag.rh == BT_RSP_HOLD_NOT_SUPPORTED)
+ return _bt_ag_send_response(hs,
+ HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
+
+ if (buf[7] == '=') {
+ _bt_hfp_response_and_hold_request(hs);
+ return 0;
+ }
+
+ if (ag.rh >= 0)
+ _bt_ag_send_at(hs, "\r\n+BTRH: %d\r\n", ag.rh);
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_hfp_last_dialed_number(bt_ag_info_t *hs, const char *buf)
+{
+ if (remote_dev_path)
+ g_free(remote_dev_path);
+
+ remote_dev_path = g_strdup(hs->path);
+ _bt_hfp_last_dialed_number_request(hs);
+
+ return 0;
+}
+
+int _bt_dial_number_response(void *t_device, bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_dial_number(bt_ag_info_t *hs, const char *buf)
+{
+ char number[MAX_BUFFER_SIZE];
+ size_t buf_len;
+
+ buf_len = strlen(buf);
+
+ if (buf[buf_len - 1] != ';') {
+ DBG("Reject the non-voice call dial number request");
+ return -EINVAL;
+ }
+
+ memset(number, 0, sizeof(number));
+ strncpy(number, &buf[3], buf_len - 4);
+
+ if (remote_dev_path)
+ g_free(remote_dev_path);
+
+ remote_dev_path = g_strdup(hs->path);
+
+ _bt_hfp_dial_number_request(number, hs);
+
+ return 0;
+}
+
+static int __bt_headset_set_gain(bt_ag_info_t *hs, uint16_t gain, char type)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+ const char *property;
+
+ if (gain > 15) {
+ DBG("Invalid gain value: %u", gain);
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case BT_HFP_SPEAKER_GAIN:
+ if (slconn->speaker_gain == gain) {
+ DBG("Ignoring no-change in speaker gain");
+ return -EALREADY;
+ }
+ property = "SpeakerGain";
+ slconn->speaker_gain = gain;
+ break;
+ case BT_HFP_MICROPHONE_GAIN:
+ if (slconn->microphone_gain == gain) {
+ DBG("Ignoring no-change in microphone gain");
+ return -EALREADY;
+ }
+ property = "MicrophoneGain";
+ slconn->microphone_gain = gain;
+ break;
+ default:
+ DBG("Unknown gain setting\n");
+ return -EINVAL;
+ }
+
+ _bt_ag_agent_emit_property_changed(ag_dbus_conn, hs->path,
+ BT_HEADSET_INTERFACE, property,
+ g_variant_new("q", gain));
+ return 0;
+}
+
+int _bt_hfp_signal_gain_setting(bt_ag_info_t *hs, const char *buf)
+{
+ uint16_t gain;
+ int err;
+
+ if (strlen(buf) < 8) {
+ DBG("very short string to use for Gain setting\n");
+ return -EINVAL;
+ }
+
+ gain = (uint16_t) strtol(&buf[7], NULL, 10);
+
+ err = __bt_headset_set_gain(hs, gain, buf[5]);
+ if (err < 0 && err != -EALREADY)
+ return err;
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_transmit_dtmf_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_dtmf_tone(bt_ag_info_t *hs, const char *buf)
+{
+ char tone;
+
+ if (strlen(buf) < 8) {
+ printf("Too short string for DTMF tone");
+ return -EINVAL;
+ }
+
+ tone = buf[7];
+ if (tone >= '#' && tone <= 'D')
+ _bt_hfp_channel_dtmf_request(tone, hs);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+int _bt_hfp_set_speaker_gain(bt_ag_info_t *hs,
+ uint16_t gain_value)
+{
+ int err;
+ char type = BT_HFP_SPEAKER_GAIN;
+
+ err = __bt_headset_set_gain(hs, gain_value, type);
+ if (err < 0)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+
+ if (hs->state == HEADSET_STATE_ON_CALL) {
+ err = _bt_ag_send_at(hs, "\r\n+VG%c=%u\r\n", type,
+ gain_value);
+ if (err < 0)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+int _bt_hfp_set_microphone_gain(bt_ag_info_t *hs,
+ uint16_t gain_value)
+{
+ int err;
+ char type = BT_HFP_MICROPHONE_GAIN;
+
+ if (hs == NULL) {
+ DBG("hs is NULL");
+ return BT_HFP_AGENT_ERROR_INVALID_PARAM;
+ }
+
+ err = __bt_headset_set_gain(hs, gain_value, type);
+ if (err < 0)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+
+ if (hs->state == HEADSET_STATE_ON_CALL) {
+ err = _bt_ag_send_at(hs, "\r\n+VG%c=%u\r\n", type,
+ gain_value);
+ if (err < 0)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+ }
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+
+int _bt_hfp_set_voice_dial(bt_ag_info_t *hs,
+ gboolean enable)
+{
+ DBG("_bt_hfp_set_voice_dial = %d", enable);
+
+ if (_bt_ag_send_at(hs, "\r\n+BVRA: %d\r\n", enable) < 0)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+int _bt_hfp_send_vendor_cmd(bt_ag_info_t *hs,
+ const char *cmd)
+{
+ DBG("_bt_hfp_send_vendor_cmd = %d", cmd);
+
+ if (_bt_ag_send_at(hs, "\r\n%s\r\n", cmd) < 0)
+ return BT_HFP_AGENT_ERROR_INTERNAL;
+
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+int _bt_vendor_cmd_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_vendor_cmd(bt_ag_info_t *hs, const char *buf)
+{
+ DBG("XSAT vendor command");
+
+ _bt_hfp_vendor_cmd_request(buf, hs);
+
+ return 0;
+}
+
+int _bt_list_current_call_indicator(bt_ag_info_t *hs, int index, int direction,
+ int mode, int status, const char *call_num, int conference, int t_num)
+{
+ if (call_num && strlen(call_num) > 0) {
+ _bt_ag_send_at(hs,
+ "\r\n+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n",
+ index, direction, status, mode, conference,
+ call_num, t_num);
+ } else {
+ _bt_ag_send_at(hs,
+ "\r\n+CLCC: %d,%d,%d,%d,%d\r\n",
+ index, direction, status, mode, conference);
+ }
+
+ return 0;
+}
+int _bt_subscriber_number_indicator(const char *call_num, int type, int service)
+{
+ if (!active_devices)
+ return -ENODEV;
+
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CNUM: ,%s,%d,,%d\r\n",
+ call_num, type, service);
+ return 0;
+}
+
+int _bt_subscriber_number_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_subscriber_number(bt_ag_info_t *hs, const char *buf)
+{
+ _bt_hfp_subscriber_number_request(hs);
+
+ return 0;
+}
+
+int _bt_call_waiting_indicator(const char *number, int type)
+{
+ if (!active_devices)
+ return -ENODEV;
+
+ DBG("Call waiting indicator to hf");
+ _bt_ag_send_foreach_headset(active_devices, __bt_cwa_cmp,
+ "\r\n+CCWA: \"%s\",%d\r\n",
+ number, type);
+ return 0;
+}
+
+int _bt_list_current_calls_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_list_current_calls(bt_ag_info_t *hs, const char *buf)
+{
+ _bt_list_current_calls(hs);
+
+ return 0;
+}
+
+int _bt_hfp_extended_errors(bt_ag_info_t *hs, const char *buf)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ if (buf[8] == '1') {
+ slconn->is_cme_enabled = TRUE;
+ DBG("CME errors enabled for headset %p", hs);
+ } else {
+ slconn->is_cme_enabled = FALSE;
+ DBG("CME errors disabled for headset %p", hs);
+ }
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_hfp_call_waiting_notify(bt_ag_info_t *hs, const char *buf)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ if (buf[8] == '1') {
+ slconn->is_cwa_enabled = TRUE;
+ DBG("Call waiting notification enabled for headset %p", hs);
+ } else {
+ slconn->is_cwa_enabled = FALSE;
+ DBG("Call waiting notification disabled for headset %p", hs);
+ }
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_operator_selection_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_call_hold_response(void *t_device, bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_nr_and_ec_response(void *t_device, bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hs = t_device;
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if (err == (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ GSList *l;
+
+ for (l = hs->nrec_cbs; l; l = l->next) {
+ struct hs_nrec_callback *nrec_cb = l->data;
+
+ nrec_cb->cb(hs, slconn->is_nrec_req,
+ nrec_cb->user_data);
+ }
+
+ slconn->is_nrec = hs->slc->is_nrec_req;
+ }
+
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_voice_dial_response(void *t_device, bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_operator_selection_indicator(int mode, const char *oper)
+{
+ if (!active_devices)
+ return -ENODEV;
+
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+COPS: %d,0,\"%s\"\r\n",
+ mode, oper);
+ return 0;
+}
+
+int _bt_hfp_operator_selection(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 8)
+ return -EINVAL;
+
+ switch (buf[7]) {
+ case '?':
+ _bt_hfp_get_operator_selection_request(hs);
+ break;
+ case '=': {
+ if (buf[8] == '?')
+ return _bt_ag_send_at(hs, "\r\n+CME ERROR: %d\r\n",
+ HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
+ else
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int _bt_hfp_nr_and_ec(bt_ag_info_t *hs, const char *buf)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ if (buf[8] == '0')
+ slconn->is_nrec_req = FALSE;
+ else
+ slconn->is_nrec_req = TRUE;
+
+ _bt_hfp_noise_red_and_echo_cancel_request(slconn->is_nrec_req, hs);
+
+ return 0;
+}
+
+int _bt_hfp_voice_dial(bt_ag_info_t *hs, const char *buf)
+{
+ bt_ag_slconn_t *slconn = hs->slc;
+ gboolean enable;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ if (buf[8] == '0')
+ enable = FALSE;
+ else
+ enable = TRUE;
+
+ _bt_hfp_voice_dial_request(enable, hs);
+
+ slconn->is_voice_recognition_running = enable;
+
+ return 0;
+}
+
+int _bt_hfp_indicators_activation(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 7) {
+ printf("Invalid indicator activation request\n");
+ return -EINVAL;
+ }
+
+ _bt_hfp_set_indicators(&buf[6], hs);
+ return 0;
+}
+
+int _bt_indicators_activation_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_select_phonebook_memory_status_response(void *t_device,
+ const char *path,
+ uint32_t total, uint32_t used,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hs = t_device;
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if (err != (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ if (slconn->is_cme_enabled)
+ return _bt_ag_send_at(hs,
+ "\r\n+CME ERROR: %d\r\n", err);
+ else
+ return _bt_ag_send_at(hs, "\r\nERROR\r\n");
+ }
+
+ if (!active_devices)
+ return -ENODEV;
+
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CPBS: %s,%d,%d\r\n",
+ path, used, total);
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_select_phonebook_memory_list_response(void *t_device,
+ const char *buf,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hs = t_device;
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if ((err != (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) ||
+ (NULL == buf)) {
+ if (slconn->is_cme_enabled)
+ return _bt_ag_send_at(hs,
+ "\r\n+CME ERROR: %d\r\n", err);
+ else
+ return _bt_ag_send_at(hs, "\r\nERROR\r\n");
+ }
+
+ if (NULL != buf) {
+ if (!active_devices)
+ return -ENODEV;
+
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CPBS: %s\r\n", buf);
+
+ }
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_select_phonebook_memory_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_select_pb_memory(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 8)
+ return -EINVAL;
+
+ if (buf[7] == '?') {
+ _bt_hfp_select_phonebook_memory_status(hs);
+ return 0;
+ }
+
+ if (buf[7] == '=') {
+ if (buf[8] == '?') {
+ _bt_hfp_select_phonebook_memory_list(hs);
+ return 0;
+ }
+ _bt_hfp_select_phonebook_memory(hs, &buf[8]);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int _bt_read_phonebook_entries_list_response(void *t_device,
+ uint32_t used,
+ uint32_t number_length,
+ uint32_t name_length,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hs = t_device;
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ int send_err = 0;
+ int index = 1;
+
+ if (err != (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ if (slconn->is_cme_enabled)
+ return _bt_ag_send_at(hs,
+ "\r\n+CME ERROR: %d\r\n", err);
+ else
+ return _bt_ag_send_at(hs, "\r\nERROR\r\n");
+ }
+
+ if (used < 1)
+ index = 0;
+
+ send_err = _bt_ag_send_at(hs, "\r\n+CPBR: (%d-%d),%d,%d\r\n",
+ index, used, number_length, name_length);
+ if (send_err < 0)
+ return send_err;
+
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_read_phonebook_entries_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_read_phonebook_entries_indicator(const char *name, const char *number,
+ uint32_t handle)
+{
+ int type = 129;
+ const char *pos = NULL;
+
+ pos = number;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ /* 145 means international access code, otherwise 129 is used */
+ if (*pos == '+')
+ type = 145;
+
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CPBR: %d,\"%s\",%d,\"%s\"\r\n",
+ handle, number, type, name);
+ return 0;
+}
+
+int _bt_hfp_read_pb_entries(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 8)
+ return -EINVAL;
+
+ if (buf[7] != '=')
+ return -EINVAL;
+
+ if (buf[8] == '?')
+ _bt_hfp_read_phonebook_entries_list(hs);
+ else
+ _bt_hfp_read_phonebook_entries(hs, &buf[8]);
+
+ return 0;
+}
+
+int _bt_find_phonebook_entries_status_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_find_phonebook_entries_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_find_phonebook_entries_status_indicator(uint32_t number_length,
+ uint32_t name_length)
+{
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CPBF: %d,%d\r\n",
+ number_length, name_length);
+
+ return 0;
+}
+
+int _bt_hfp_find_pb_entires(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 8)
+ return -EINVAL;
+
+ if (buf[7] != '=')
+ return -EINVAL;
+
+ if (buf[8] == '?')
+ _bt_hfp_find_phonebook_entries_status(hs);
+ else
+ _bt_hfp_find_phonebook_entries(hs, &buf[8]);
+
+ return 0;
+}
+
+int _bt_supported_character_generic_response(void *t_device,
+ char *character_set_list,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hs = t_device;
+ bt_ag_slconn_t *slconn = hs->slc;
+
+ if (err != (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ if (slconn->is_cme_enabled)
+ return _bt_ag_send_at(hs,
+ "\r\n+CME ERROR: %d\r\n", err);
+ else
+ return _bt_ag_send_at(hs, "\r\nERROR\r\n");
+ }
+
+ if (NULL != character_set_list) {
+ if (!active_devices)
+ return -ENODEV;
+
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CSCS: %s\r\n", character_set_list);
+ }
+ return _bt_ag_send_at(hs, "\r\nOK\r\n");
+}
+
+int _bt_set_characterset_generic_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_select_character_set(bt_ag_info_t *hs, const char *buf)
+{
+ if (NULL != buf) {
+ if (strlen(buf) < 7)
+ return -EINVAL;
+
+ if (buf[7] == '?') {
+ _bt_hfp_get_character_set(hs);
+ return 0;
+ }
+
+ if (buf[7] == '=') {
+ if (buf[8] == '?')
+ _bt_hfp_list_supported_character(hs);
+ else
+ _bt_hfp_set_character_set(hs, &buf[8]);
+ }
+ }
+ return 0;
+
+}
+
+int _bt_battery_charge_status_response(void *t_device,
+ int32_t bcs,
+ int32_t bcl,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hs = t_device;
+
+ if (err == (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CBC: %d,%d\r\n", bcs, bcl);
+ }
+
+ return _bt_ag_send_response(hs, err);
+}
+
+int _bt_hfp_get_battery_charge_status(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 6)
+ return -EINVAL;
+
+ if (buf[6] == '=')
+ return _bt_ag_send_response(hs, HFP_STATE_MNGR_ERR_NONE);
+
+ _bt_hfp_get_battery_property(hs);
+ return 0;
+}
+
+int _bt_hfp_apl_command(bt_ag_info_t *hs, const char *buf)
+{
+ DBG("Got Apple command: %s", buf);
+
+ return _bt_ag_send_response(hs, HFP_STATE_MNGR_ERR_NONE);
+}
+
+/* convert signal strength to a RSSI level */
+static int __bt_telephony_convert_signal_to_rssi(int signal)
+{
+ /* input : BT signal strength (0~5) */
+ /* output : RSSI strength (0~31) */
+ switch (signal) {
+ case 0: return 0;
+ case 1: return 4;
+ case 2: return 8;
+ case 3: return 13;
+ case 4: return 19;
+ case 5: return 31;
+ }
+
+ if (signal > 5)
+ return 31;
+
+ return 0;
+}
+
+int _bt_signal_quality_response(void *t_device,
+ int32_t rssi,
+ int32_t ber,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *hs = t_device;
+
+ if (err == (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CSQ: %d,%d\r\n",
+ __bt_telephony_convert_signal_to_rssi(rssi), ber);
+ }
+ return _bt_ag_send_response(hs, err);
+}
+
+int _bt_telephony_signal_quality_list_supported_response(void *t_device,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *device = t_device;
+
+ if (err == (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CSQ: (0-31,99),(99)\r\n");
+ }
+ return _bt_ag_send_response(device, err);
+}
+
+int _bt_hfp_get_signal_quality(bt_ag_info_t *hs, const char *buf)
+{
+ if (strlen(buf) < 6)
+ return -EINVAL;
+
+ if (buf[6] == '=')
+ _bt_telephony_signal_quality_list_supported_response(hs,
+ HFP_STATE_MNGR_ERR_NONE);
+ else
+ _bt_ag_agent_get_signal_quality(hs);
+
+ return 0;
+}
+
+int _bt_hfp_get_activity_status_rsp(void *t_device,
+ int status,
+ bt_hfp_agent_error_t err)
+{
+ bt_ag_info_t *device = t_device;
+
+ if (err == (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE) {
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CPAS: %d\r\n", status);
+ }
+
+ return _bt_ag_send_response(device, err);
+}
+
+int _bt_hfp_get_activity_status(bt_ag_info_t *device, const char *buf)
+{
+ if (strlen(buf) < 7)
+ return -EINVAL;
+
+ if (buf[7] == '?') {
+ return _bt_ag_send_response(device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ } else if (buf[7] == '=') {
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CPAS: (0-4)\r\n");
+ return _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_NONE);
+ }
+
+ _bt_get_activity_status(device);
+ return 0;
+}
+
+int _bt_hfp_get_equipment_identity_rsp(void *t_device,
+ char *identity, bt_hfp_agent_error_t err)
+{
+ if (identity)
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CGSN: %s\r\n", identity);
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_get_imsi_rsp(void *t_device,
+ char *mcc, char *mnc, char *msin, bt_hfp_agent_error_t err)
+{
+ if (err == (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE)
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n%s%s%s\r\n", mcc,mnc,msin);
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_get_creg_status_rsp(void *t_device,
+ int n, int status, bt_hfp_agent_error_t err)
+{
+ if (err == (bt_hfp_agent_error_t)HFP_STATE_MNGR_ERR_NONE)
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CREG: %d,%d\r\n", n, status);
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_get_equipment_identity(bt_ag_info_t *device, const char *buf)
+{
+ int len = strlen(buf);
+
+ if (len == 9 && buf[7] == '=' && buf[8] == '?') /* AT+CGSN=? */
+ return _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_NONE);
+
+ else if (len > 7)
+ return -EINVAL;
+
+ _bt_hfp_get_equipment_identity_req(device); /* AT+CGSN */
+ return 0;
+}
+
+int _bt_hfp_get_model_info_rsp(void *t_device, char *model,
+ bt_hfp_agent_error_t err)
+{
+ if (model)
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CGMM: %s\r\n", model);
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_get_model_information(bt_ag_info_t *device, const char *buf)
+{
+ int len = strlen(buf);
+
+ if (len == 9 && buf[7] == '=' && buf[8] == '?') /* AT+CGMM=? */
+ return _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_NONE);
+
+ else if (len > 7)
+ return -EINVAL;
+
+ _bt_hfp_get_model_info_req(device);/* AT+CGMM */
+ return 0;
+}
+
+int _bt_hfp_get_device_manufacturer_rsp(void *t_device,
+ char *manufacturer, bt_hfp_agent_error_t err)
+{
+ if (manufacturer)
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CGMI: %s\r\n", manufacturer);
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_get_device_manufacturer(bt_ag_info_t *device, const char *buf)
+{
+ int len = strlen(buf);
+
+ if (len == 9 && buf[7] == '=' && buf[8] == '?') /* AT+CGMI=? */
+ return _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_NONE);
+
+ else if (len > 7)
+ return -EINVAL;
+
+ _bt_hfp_get_device_manufacturer_req(device);
+ return 0;
+}
+
+int _bt_hfp_get_imsi(bt_ag_info_t *device, const char *buf)
+{
+ int len = strlen(buf);
+ DBG_SECURE("Buf %s", buf);
+
+ if (len == 7) {
+ _bt_hfp_get_imsi_req(device);
+ } else {
+ _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_INVALID_INDEX);
+ }
+
+ return 0;
+}
+
+int _bt_hfp_get_creg_status(bt_ag_info_t *device, const char *buf)
+{
+ int len = strlen(buf);
+ DBG_SECURE("buf %s", buf);
+ if (len < 7 || len > 9)
+ return -EINVAL;
+ else if (len == 7) {
+ _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_INVALID_INDEX);
+ } else if (buf[7] == '=') {
+ _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_INVALID_INDEX);
+ } else if (buf[7] == '?') {
+ _bt_hfp_get_creg_status_req(device);
+ }
+ return 0;
+}
+int _bt_hfp_get_revision_info_rsp(void *t_device, char *revision,
+ bt_hfp_agent_error_t err)
+{
+ if (revision)
+ _bt_ag_send_foreach_headset(active_devices, __bt_hfp_cmp,
+ "\r\n+CGMR: %s\r\n", revision);
+ return _bt_ag_send_response(t_device, err);
+}
+
+int _bt_hfp_get_revision_information(bt_ag_info_t *device, const char *buf)
+{
+ int len = strlen(buf);
+
+ if (len == 9 && buf[7] == '=' && buf[8] == '?') /* AT+CGMR=? */
+ return _bt_ag_send_response(device, HFP_STATE_MNGR_ERR_NONE);
+
+ else if (len > 7)
+ return -EINVAL;
+
+ _bt_hfp_get_revision_info_req(device);
+ return 0;
+}
--- /dev/null
+/*
+ * bluetoth-ag-handler.h
+ *
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Chethan TN <chethan.tn@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ * Rakesh MK <rakesh.mk@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <glib.h>
+#include "bluetooth-ag-agent.h"
+
+#define BT_HFP_SPEAKER_GAIN 'S'
+#define BT_HFP_MICROPHONE_GAIN 'M'
+
+#define AG_RING_INTERVAL 1500
+
+typedef struct {
+ gboolean wbs_enable;
+ uint8_t i2s_enable;
+ uint8_t is_master;
+ uint8_t clock_rate;
+ uint8_t pcm_interface_rate;
+} wbs_options;
+
+/* BD Address */
+typedef struct {
+ uint8_t b[6];
+} __attribute__((packed)) bt_addr;
+
+int _bt_hfp_supported_features(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_report_indicators(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_enable_indicators(bt_ag_info_t *hdset, const char *buffer);
+int _bt_hfp_call_hold(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_answer_call(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_dial_number(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_signal_gain_setting(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_terminate_call(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_key_press(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_last_dialed_number(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_response_and_hold(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_cli_notification(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_dtmf_tone(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_subscriber_number(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_list_current_calls(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_extended_errors(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_call_waiting_notify(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_operator_selection(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_nr_and_ec(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_voice_dial(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_apl_command(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_apl_command(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_indicators_activation(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_select_pb_memory(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_read_pb_entries(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_select_character_set(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_find_pb_entires(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_get_signal_quality(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_get_battery_charge_status(bt_ag_info_t *hs, const char *buf);
+int _bt_calling_stopped_indicator(void);
+int _bt_incoming_call_indicator(const char *number, int type);
+int _bt_call_waiting_indicator(const char *number, int type);
+void _bt_hfp_deinitialize(void);
+gboolean __bt_ring_timer_cb(gpointer data);
+bt_hfp_agent_error_t _bt_hfp_event_indicator(int index);
+void _bt_hfp_set_ag_indicator(uint32_t ag_features,
+ const bt_ag_indicators_t *ag_indicators,
+ int rh, const char *chld);
+int _bt_calling_stopped_indicator(void);
+int _bt_incoming_call_indicator(const char *number, int type);
+int _bt_dial_number_response(void *t_device, bt_hfp_agent_error_t err);
+int _bt_event_reporting_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_terminate_call_response(void *t_device,
+ hfp_state_manager_err_t err);
+int _bt_call_hold_response(void *t_device, bt_hfp_agent_error_t err);
+int _bt_key_press_response(void *t_device, bt_hfp_agent_error_t err);
+int _bt_subscriber_number_indicator(const char *call_num,
+ int type, int service);
+int _bt_subscriber_number_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_list_current_call_indicator(bt_ag_info_t *hs, int index, int direction,
+ int mode, int status, const char *call_num, int conference, int t_num);
+int _bt_list_current_calls_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_nr_and_ec_response(void *t_device, bt_hfp_agent_error_t err);
+int _bt_voice_dial_response(void *t_device, bt_hfp_agent_error_t err);
+int _bt_indicators_activation_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_select_phonebook_memory_status_response(void *t_device,
+ const char *path,
+ uint32_t total, uint32_t used,
+ bt_hfp_agent_error_t err);
+int _bt_select_phonebook_memory_list_response(void *t_device,
+ const char *buf,
+ bt_hfp_agent_error_t err);
+int _bt_select_phonebook_memory_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_read_phonebook_entries_list_response(void *t_device,
+ uint32_t used,
+ uint32_t number_length,
+ uint32_t name_length,
+ bt_hfp_agent_error_t err);
+int _bt_read_phonebook_entries_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_find_phonebook_entries_status_indicator(uint32_t number_length,
+ uint32_t name_length);
+int _bt_find_phonebook_entries_status_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_supported_character_generic_response(void *t_device,
+ char *character_set_list,
+ bt_hfp_agent_error_t err);
+int _bt_set_characterset_generic_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_signal_quality_response(void *t_device,
+ int32_t rssi,
+ int32_t ber,
+ bt_hfp_agent_error_t err);
+int _bt_battery_charge_status_response(void *t_device,
+ int32_t bcs,
+ int32_t bcl,
+ bt_hfp_agent_error_t err);
+int _bt_operator_selection_indicator(int mode, const char *oper);
+int _bt_operator_selection_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_transmit_dtmf_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_find_phonebook_entries_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_response_and_hold_response(void *t_device,
+ bt_hfp_agent_error_t err);
+int _bt_answer_call_response(void *hs, bt_hfp_agent_error_t err);
+int _bt_hfp_get_activity_status_rsp(void *t_device,
+ int status,
+ bt_hfp_agent_error_t err);
+int _bt_hfp_get_activity_status(bt_ag_info_t *device, const char *buf);
+int _bt_hfp_set_speaker_gain(bt_ag_info_t *hs,
+ uint16_t gain_value);
+int _bt_hfp_set_microphone_gain(bt_ag_info_t *hs,
+ uint16_t gain_value);
+int _bt_hfp_set_voice_dial(bt_ag_info_t *hs,
+ gboolean enable);
+int _bt_hfp_get_equipment_identity_rsp(void *t_device,
+ char *identity, bt_hfp_agent_error_t err);
+int _bt_hfp_get_imsi_rsp(void *t_device,
+ char *mcc, char *mnc, char *msin, bt_hfp_agent_error_t err);
+int _bt_hfp_get_creg_status_rsp(void *t_device,
+ int n, int status, bt_hfp_agent_error_t err);
+int _bt_hfp_get_model_info_rsp(void *t_device,
+ char *model, bt_hfp_agent_error_t err);
+int _bt_hfp_get_device_manufacturer_rsp(void *t_device,
+ char *manufacturer, bt_hfp_agent_error_t err);
+int _bt_hfp_get_revision_info_rsp(void *t_device,
+ char *revision, bt_hfp_agent_error_t err);
+int _bt_hfp_vendor_cmd(bt_ag_info_t *hs, const char *buf);
+int _bt_hfp_send_vendor_cmd(bt_ag_info_t *hs,
+ const char *cmd);
+int _bt_vendor_cmd_response(void *t_device,
+ bt_hfp_agent_error_t err);
--- /dev/null
+/*
+ * bluetooth-ag-manager.c
+ *
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Chethan TN <chethan.tn@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ * Rakesh MK <rakesh.mk@samsung.com>
+ *
+ * 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 <string.h>
+#include "bluetooth-ag-agent.h"
+#include "bluetooth-ag-handler.h"
+#include <dbus/dbus.h>
+
+#define PHONEBOOK_AGENT_BUS_NAME "org.bluez.pb_agent"
+#define PHONEBOOK_AGENT_PATH "/org/bluez/pb_agent"
+#define PHONEBOOK_AGENT_INTERFACE "org.bluez.PbAgent.At"
+
+struct telephony_call {
+ char *call_path;
+ int call_status;
+ gboolean call_originating;
+ gboolean call_emergency;
+ gboolean call_on_hold;
+ gboolean call_conference;
+ char *call_number;
+ gboolean call_setup;
+ uint32_t call_id;
+ char *call_sender;
+};
+
+#define HFP_AGENT_ACTIVITY_STATUS_READY 0
+#define HFP_AGENT_ACTIVITY_STATUS_UNAVAILABLE 1
+#define HFP_AGENT_ACTIVITY_STATUS_UNKNOWN 2
+#define HFP_AGENT_ACTIVITY_STATUS_RINGING 3
+#define HFP_AGENT_ACTIVITY_STATUS_CALL_IN_PROGRESS 4
+
+#define HFP_AGENT_BATTERY_INDICATOR "battchg"
+#define HFP_AGENT_CALL_INDICATOR "call"
+#define HFP_AGENT_CALLHELD_INDICATOR "callheld"
+#define HFP_AGENT_CALLSETUP_INDICATOR "callsetup"
+#define HFP_AGENT_ROAMING_INDICATOR "roam"
+#define HFP_AGENT_SERVICE_INDICATOR "service"
+#define HFP_AGENT_SIGNAL_INDICATOR "signal"
+
+#define HFP_AGENT_CALL_IDLE 0
+#define HFP_AGENT_CALL_ACTIVE 1
+
+#define HFP_INCOMING_CALLSETUP 1
+#define HFP_OUTGOING_CALLSETUP 2
+#define RESTRAIN_CALL_FLAG 0x01
+#define ALLOW_CALL_FLAG 0x02
+
+#define HFP_CALL_STATUS_IDLE 0
+#define HFP_CALL_STATUS_CREATE 1
+#define HFP_CALL_STATUS_COMING 2
+#define HFP_CALL_STATUS_PROCEEDING 3
+#define HFP_CALL_STATUS_MO_ALERTING 4
+#define HFP_CALL_STATUS_MT_ALERTING 5
+#define HFP_CALL_STATUS_WAITING 6
+#define HFP_CALL_STATUS_ANSWERED 7
+#define HFP_CALL_STATUS_ACTIVE 8
+#define HFP_CALL_STATUS_MO_RELEASE 9
+#define HFP_CALL_STATUS_MT_RELEASE 10
+#define HFP_CALL_STATUS_HOLD_INITIATED 11
+#define HFP_CALL_STATUS_HOLD 12
+#define HFP_CALL_STATUS_RETRIEVE_INITIATED 13
+#define HFP_CALL_STATUS_RECONNECT_PENDING 14
+#define HFP_CALL_STATUS_TERMINATED 15
+#define HFP_CALL_STATUS_SWAP_INITIATED 16
+
+#define AGENT_MAX_PB_COUNT 1000
+#define AGENT_PB_NAME_MAX_LENGTH 20
+#define AGENT_PB_NUMBER_MAX_LENGTH 20
+#define AGENT_MAX_CALLLOG_COUNT 30
+#define ERR_NOT_FOUND -1
+#define AG_MAX_LENGTH 16
+
+static gboolean update_events = FALSE;
+static int caller_id = 0;
+
+static GSList *call_senders_paths = NULL;
+static GSList *existing_call_list = NULL;
+static GSList *agent_active_call_list = NULL;
+static char *ag_subscriber_num = NULL;
+
+static guint call_on_hold_timer = 0;
+
+typedef struct {
+ gchar *sender_path;
+ gchar *sender_name;
+} sender_info_t;
+
+static struct {
+ char *network_operator_name;
+ uint8_t network_status;
+ int32_t signal_strength;
+} network_info = {
+ .network_operator_name = NULL,
+ .network_status = BT_AGENT_NETWORK_REG_STATUS_UNKOWN,
+ .signal_strength = 0,
+};
+
+static const char *agent_pb_store_list[] = {
+ "\"ME\"", "\"DC\"", "\"MC\"", "\"RC\""
+};
+
+static const char *agent_supported_character_set[] = {
+ "\"UTF-8\"", "\"IRA\""
+};
+
+#if defined(TIZEN_WEARABLE) && defined(TIZEN_BT_HFP_AG_ENABLE)
+static const char *ag_chld_str = "0,1,2";
+#else
+static const char *ag_chld_str = "0,1,2,3";
+#endif
+
+#define AGENT_PB_STORE_LIST_SIZE (sizeof(agent_pb_store_list) \
+ /sizeof(const char *))
+#define AGENT_SUPPORTED_CHARACTER_SET_SIZE ( \
+ sizeof(agent_supported_character_set)/sizeof(const char *))
+
+static bt_ag_indicators_t hfp_ag_ind[] = {
+ { "call", "0,1", 0, TRUE, TRUE },
+ { "callsetup", "0-3", 0 , TRUE, TRUE },
+ { "battchg", "0-5", 5 , TRUE, TRUE },
+ { "callheld", "0-2", 0 , FALSE, TRUE },
+ { "roam", "0,1", 0 , TRUE, TRUE },
+ { "signal", "0-5", 0 , TRUE, TRUE },
+ { "service", "0,1", 0, TRUE, TRUE },
+ { NULL }
+};
+
+static struct {
+ int32_t path_id;
+ int32_t charset_id;
+} ag_pb_info = {
+ .path_id = 0,
+ .charset_id = 0
+};
+
+static gboolean __bt_hfp_check_for_callpath(const char *call_path,
+ const char *call_sender)
+{
+ GSList *sender_list = call_senders_paths;
+ sender_info_t *sender;
+
+ DBG("call path is = %s\n", call_path);
+ DBG("sender is = %s\n", call_sender);
+
+ if (call_path == NULL || call_sender == NULL) {
+
+ ERR("Invalid Parameters");
+ return FALSE;
+ }
+
+ /*check if the call is already registered*/
+ DBG("Checking if the call is already registered");
+ while (sender_list != NULL) {
+ sender = sender_list->data;
+
+ if (sender == NULL)
+ break;
+
+ if (g_strcmp0(sender->sender_path, call_path) == 0) {
+ DBG("sender path and call path match... so return true");
+ return TRUE;
+ }
+
+ sender_list = sender_list->next;
+ }
+
+ ERR("Call path is not already registered");
+ return FALSE;
+}
+
+static void __bt_hfp_clear_sender_path(sender_info_t *s_path)
+{
+ if (s_path == NULL)
+ return;
+
+ g_free(s_path->sender_name);
+ g_free(s_path->sender_path);
+ g_free(s_path);
+
+ if (g_slist_length(call_senders_paths) == 0) {
+ g_slist_free(call_senders_paths);
+ call_senders_paths = NULL;
+ }
+}
+
+static void __bt_hfp_free_call(struct telephony_call *t_call)
+{
+ if (t_call == NULL)
+ return;
+
+ g_free(t_call->call_number);
+ g_free(t_call->call_path);
+ g_free(t_call->call_sender);
+ g_free(t_call);
+}
+
+static void __bt_hfp_reset_indicators(void)
+{
+ int i;
+
+ for (i = 0; hfp_ag_ind[i].indicator_desc != NULL; i++)
+ hfp_ag_ind[i].is_activated = TRUE;
+}
+
+void _bt_hfp_device_disconnected(void *t_device)
+{
+ DBG("hfp_agent: device %p disconnected", t_device);
+ update_events = FALSE;
+ __bt_hfp_reset_indicators();
+}
+
+void _bt_hfp_initialize_telephony_manager(uint32_t ag_features)
+{
+ int index;
+ int value;
+ int ret;
+
+ /* Reset the indicator values */
+ for (index = 0; hfp_ag_ind[index].indicator_desc != NULL; index++) {
+ if (g_str_equal(hfp_ag_ind[index].indicator_desc, "battchg")) {
+ ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
+ &value);
+ if (ret != 0) {
+ ERR("Get battery status failed : %d\n", ret);
+ } else {
+ /* Send battery status ranging from 0-5 */
+ if (value < 5)
+ hfp_ag_ind[index].hfp_value = 0;
+ else if (value >= 100)
+ hfp_ag_ind[index].hfp_value = 5;
+ else
+ hfp_ag_ind[index].hfp_value = value / 20 + 1;
+ }
+ } else if (g_str_equal(hfp_ag_ind[index].indicator_desc, "signal")) {
+ ret = vconf_get_int(VCONFKEY_TELEPHONY_RSSI, &value);
+ if (ret != 0) {
+ ERR("Get signal status failed err = %d\n", ret);
+ } else {
+ BT_CHECK_SIGNAL_STRENGTH(value);
+ hfp_ag_ind[index].hfp_value = value;
+ }
+ } else if (g_str_equal(hfp_ag_ind[index].indicator_desc, "roam")) {
+ ret = vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &value);
+ if (ret != 0)
+ ERR("Get roaming status failed err = %d\n", ret);
+ else
+ hfp_ag_ind[index].hfp_value = value;
+ } else if (g_str_equal(hfp_ag_ind[index].indicator_desc, "service")) {
+ ret = vconf_get_int(VCONFKEY_TELEPHONY_SVCTYPE, &value);
+ if (ret != 0) {
+ ERR("Get Service status failed : %d\n", ret);
+ } else {
+ switch (value) {
+ case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
+ case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
+ case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
+ hfp_ag_ind[index].hfp_value =
+ INDICATOR_EVENT_SERVICE_NONE;
+ break;
+ default:
+ hfp_ag_ind[index].hfp_value =
+ INDICATOR_EVENT_SERVICE_PRESENT;
+ break;
+ }
+ }
+ } else {
+ hfp_ag_ind[index].hfp_value = 0;
+ }
+ }
+
+ /*Initializatoin of the indicators*/
+ _bt_hfp_set_ag_indicator(ag_features, hfp_ag_ind,
+ BT_RSP_HOLD_NOT_SUPPORTED,
+ ag_chld_str);
+}
+
+void _bt_hfp_deinitialize_telephony_manager(void)
+{
+ GSList *list = call_senders_paths;
+
+ g_free(ag_subscriber_num);
+ ag_subscriber_num = NULL;
+
+ g_free(network_info.network_operator_name);
+ network_info.network_operator_name = NULL;
+
+ network_info.network_status = BT_AGENT_NETWORK_REG_STATUS_UNKOWN;
+ network_info.signal_strength = 0;
+
+ g_slist_free(agent_active_call_list);
+ agent_active_call_list = NULL;
+
+ g_slist_foreach(existing_call_list, (GFunc) __bt_hfp_free_call, NULL);
+ g_slist_free(existing_call_list);
+ existing_call_list = NULL;
+
+ while (list != NULL) {
+ __bt_hfp_clear_sender_path(list->data);
+ list = list->next;
+ }
+
+ g_slist_free(call_senders_paths);
+ call_senders_paths = NULL;
+
+ _bt_hfp_deinitialize();
+}
+
+bt_hfp_agent_error_t _bt_hfp_register_telephony_agent(gboolean register_flag,
+ const char *path_to_register,
+ const char *sender)
+{
+ sender_info_t *sender_info;
+
+ if (sender == NULL || path_to_register == NULL)
+ return BT_HFP_AGENT_ERROR_INVALID_PARAM;
+
+ DBG(" register_flag = %d", register_flag);
+ DBG(" path_to_register = %s", path_to_register);
+ DBG(" sender = %s", sender);
+
+ if (register_flag) {
+ if (__bt_hfp_check_for_callpath(path_to_register, sender))
+ return BT_HFP_AGENT_ERROR_ALREADY_EXSIST;
+
+ /* add call path to the senders list*/
+ DBG("Call path doesn't exist. Add path %s to global path",
+ path_to_register);
+ sender_info = g_new0(sender_info_t, 1);
+ sender_info->sender_path = g_strdup(path_to_register);
+ sender_info->sender_name = g_strdup(sender);
+ call_senders_paths = g_slist_append(call_senders_paths,
+ sender_info);
+
+ return BT_HFP_AGENT_ERROR_NONE;
+ } else {
+ /*remove the call from senders list */
+ GSList *s_list = call_senders_paths;
+
+ while (s_list != NULL) {
+ sender_info = s_list->data;
+
+ if (sender_info == NULL)
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ if (g_strcmp0(sender_info->sender_path,
+ path_to_register) == 0) {
+ call_senders_paths = g_slist_remove(
+ call_senders_paths,
+ sender_info);
+ __bt_hfp_clear_sender_path(sender_info);
+ return BT_HFP_AGENT_ERROR_NONE;
+ }
+ s_list = s_list->next;
+ }
+
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ }
+}
+
+static gboolean __bt_hfp_is_call_allowed(const char *call_path)
+{
+ GSList *call_list = existing_call_list;
+
+ /*if prior call list doesn't exisit, allow the call as it can be a new-call*/
+ if (!existing_call_list) {
+ DBG(" This must be a new call... Allow it!");
+ return TRUE;
+ }
+
+ while (call_list != NULL) {
+
+ struct telephony_call *t_call = call_list->data;
+
+ if (g_strcmp0(t_call->call_path, call_path) == 0)
+ return TRUE;
+
+ call_list = call_list->next;
+ }
+
+ ERR("call is not allowed");
+ return FALSE;
+}
+
+static struct telephony_call *__bt_hfp_create_new_call(
+ const char *incoming_path,
+ uint32_t incoming_call_id,
+ const char *incoming_number,
+ const char *sender)
+{
+ struct telephony_call *t_call = NULL;
+ GSList *call_list = existing_call_list;
+
+ while (call_list != NULL) {
+ t_call = call_list->data;
+
+ if (t_call->call_id == incoming_call_id)
+ break;
+ else
+ t_call = NULL;
+
+ call_list = call_list->next;
+ }
+
+ DBG("Create a new call");
+
+ if (t_call == NULL) {
+ t_call = g_new0(struct telephony_call, 1);
+ t_call->call_id = incoming_call_id;
+ t_call->call_path = g_strdup(incoming_path);
+ t_call->call_sender = g_strdup(sender);
+ t_call->call_number = g_strdup(incoming_number);
+
+ existing_call_list = g_slist_append(existing_call_list,
+ t_call);
+ }
+ return t_call;
+}
+
+gboolean _bt_hfp_is_call_exist(void)
+{
+ DBG("_bt_hfp_is_call_exist [%x]", existing_call_list);
+ if (existing_call_list)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static struct telephony_call *__bt_hfp_get_call_with_status(int call_status)
+{
+ DBG("Get Call with status %d", call_status);
+
+ GSList *temp_list = existing_call_list;
+
+ if (existing_call_list != NULL) {
+ while (temp_list != NULL) {
+ struct telephony_call *t_call = temp_list->data;
+ if (t_call->call_status == call_status)
+ return t_call;
+ temp_list = temp_list->next;
+ }
+ }
+
+ DBG("Existing call list is NULL. So return NULL");
+ return NULL;
+}
+
+static bt_hfp_agent_error_t __bt_hfp_modify_indicator(
+ const char *indicator_name,
+ int update_value)
+{
+ bt_ag_indicators_t *hf_ind = NULL;
+ int i;
+#ifdef TIZEN_MEDIA_ENHANCE
+ if(g_strcmp0(indicator_name,
+ HFP_AGENT_CALLSETUP_INDICATOR) == 0)
+ _bt_ag_agent_check_transport_state();
+#endif
+ for (i = 0; hfp_ag_ind[i].indicator_desc != NULL; i++) {
+ if (g_str_equal(hfp_ag_ind[i].indicator_desc,
+ indicator_name)) {
+ hf_ind = &hfp_ag_ind[i];
+ break;
+ }
+ }
+
+ if (hf_ind == NULL)
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ if (hf_ind->hfp_value == update_value && hf_ind->ignore)
+ return BT_HFP_AGENT_ERROR_NONE;
+
+ if (hf_ind->is_activated == FALSE)
+ return BT_HFP_AGENT_ERROR_NONE;
+
+ hf_ind->hfp_value = update_value;
+
+ DBG("updating hfp event indicator [%s] with value [%d]",
+ indicator_name, hf_ind->hfp_value);
+
+ return _bt_hfp_event_indicator(i);
+}
+
+static int __bt_hfp_get_indicator_value(
+ const bt_ag_indicators_t *ag_indicators,
+ const char *hf_desc)
+{
+ int x;
+ for (x = 0; ag_indicators[x].indicator_desc != NULL; x++) {
+ if (g_str_equal(ag_indicators[x].indicator_desc, hf_desc))
+ return ag_indicators[x].hfp_value;
+ }
+
+ return ERR_NOT_FOUND;
+}
+
+static void __bt_hfp_handle_call_conference(void)
+{
+ GSList *t_call_list;
+ struct telephony_call *t_active_call = NULL;
+ int t_active_call_count = 0;
+
+ struct telephony_call *t_held_call = NULL;
+ int t_held_call_count = 0;
+
+ for (t_call_list = existing_call_list; t_call_list != NULL;
+ t_call_list = t_call_list->next) {
+
+ struct telephony_call *t_call = t_call_list->data;
+
+ if (t_call->call_status == HFP_CALL_STATUS_ACTIVE) {
+ if (t_active_call == NULL)
+ t_active_call = t_call;
+
+ t_active_call_count++;
+
+ if (t_active_call_count >= 2) {
+ if (!t_active_call->call_conference)
+ t_active_call->call_conference = TRUE;
+ t_call->call_conference = TRUE;
+ }
+
+ } else if (t_call->call_status == HFP_CALL_STATUS_HOLD) {
+ if (t_held_call == NULL)
+ t_held_call = t_call;
+
+ t_held_call_count++;
+
+ if (t_held_call_count >= 2) {
+ if (!t_held_call->call_conference)
+ t_held_call->call_conference = TRUE;
+ t_call->call_conference = TRUE;
+ }
+ }
+ }
+
+ if (t_held_call_count == 1) {
+ if (t_held_call->call_conference)
+ t_held_call->call_conference = FALSE;
+ }
+
+ if (t_active_call_count == 1) {
+ if (t_active_call->call_conference)
+ t_active_call->call_conference = FALSE;
+ }
+}
+
+static gboolean __bt_hfp_on_call_hold_timeout(gpointer t_data)
+{
+ int status;
+
+ if (__bt_hfp_get_call_with_status(HFP_CALL_STATUS_HOLD)) {
+ if (__bt_hfp_get_call_with_status(HFP_CALL_STATUS_ACTIVE))
+ status = INDICATOR_EVENT_CALLHELD_MULTIPLE;
+ else
+ status = INDICATOR_EVENT_CALLHELD_ON_HOLD;
+ } else {
+ status = INDICATOR_EVENT_CALLHELD_NONE;
+ }
+
+ __bt_hfp_modify_indicator("callheld", status);
+
+ call_on_hold_timer = 0;
+ return FALSE;
+}
+
+static void __bt_hfp_handle_call_on_hold_request(void)
+{
+ DBG(" Starting the timer for call on hold");
+ if (call_on_hold_timer)
+ g_source_remove(call_on_hold_timer);
+
+ call_on_hold_timer = g_timeout_add(250, __bt_hfp_on_call_hold_timeout,
+ NULL);
+ DBG(" returning from the timer call");
+}
+
+static void __bt_hfp_set_call_status(struct telephony_call *t_call,
+ int call_status)
+{
+ int call_held = 0;
+ int org_status = t_call->call_status;
+
+ call_held = __bt_hfp_get_indicator_value(hfp_ag_ind, "callheld");
+
+ if (org_status == call_status) {
+ DBG("Ignore the CSD Call state change to existing state");
+ return;
+ }
+
+ t_call->call_status = call_status;
+
+ DBG(" call status is %d", call_status);
+
+ switch (call_status) {
+ case HFP_CALL_STATUS_IDLE:
+ if (t_call->call_setup) {
+ __bt_hfp_modify_indicator("callsetup",
+ INDICATOR_EVENT_CALLSETUP_INACTIVE);
+ if (!t_call->call_originating)
+ _bt_calling_stopped_indicator();
+ }
+
+ g_free(t_call->call_number);
+ t_call->call_number = NULL;
+ t_call->call_originating = FALSE;
+ t_call->call_emergency = FALSE;
+ t_call->call_on_hold = FALSE;
+ t_call->call_conference = FALSE;
+ t_call->call_setup = FALSE;
+ break;
+
+ case HFP_CALL_STATUS_COMING:
+ t_call->call_originating = FALSE;
+ t_call->call_setup = TRUE;
+ __bt_hfp_modify_indicator("callsetup",
+ INDICATOR_EVENT_CALLSETUP_INCOMING);
+ break;
+
+ case HFP_CALL_STATUS_CREATE:
+ t_call->call_originating = TRUE;
+ t_call->call_setup = TRUE;
+ break;
+
+ case HFP_CALL_STATUS_MO_ALERTING:
+ __bt_hfp_modify_indicator("callsetup",
+ INDICATOR_EVENT_CALLSETUP_ALERTING);
+ break;
+
+ case HFP_CALL_STATUS_MT_ALERTING: {
+ int t_number = AGENT_NUMBER_TYPE_TELEPHONY;
+
+ if (t_call->call_number == NULL) {
+ t_number = AGENT_NUMBER_TYPE_TELEPHONY;
+ } else {
+ if (t_call->call_number[0] == '+' ||
+ strncmp(t_call->call_number, "00", 2) == 0)
+ t_number = AGENT_NUMBER_TYPE_INTERNATIONAL;
+ }
+
+ if (org_status == HFP_CALL_STATUS_WAITING)
+ _bt_incoming_call_indicator(t_call->call_number,
+ t_number);
+ }
+ break;
+
+ case HFP_CALL_STATUS_ACTIVE:
+ DBG(" This is an Active call");
+ if (t_call->call_on_hold) {
+ t_call->call_on_hold = FALSE;
+ __bt_hfp_handle_call_on_hold_request();
+ } else {
+ if (!g_slist_find(agent_active_call_list, t_call)) {
+ DBG(" This call is not in the active call list. So Add it to the list.\n");
+ agent_active_call_list =
+ g_slist_prepend(agent_active_call_list,
+ t_call);
+ }
+ if (g_slist_length(agent_active_call_list) == 1) {
+ DBG(" Update indicator to show the call presence.\n");
+ __bt_hfp_modify_indicator("call",
+ INDICATOR_EVENT_CALL_ACTIVE);
+ }
+
+ __bt_hfp_modify_indicator("callsetup",
+ INDICATOR_EVENT_CALLSETUP_INACTIVE);
+ __bt_hfp_handle_call_on_hold_request();
+
+ if (!t_call->call_originating)
+ _bt_calling_stopped_indicator();
+
+ t_call->call_setup = FALSE;
+ }
+ break;
+
+ case HFP_CALL_STATUS_MO_RELEASE:
+ case HFP_CALL_STATUS_MT_RELEASE:
+ agent_active_call_list = g_slist_remove(agent_active_call_list,
+ t_call);
+ if (g_slist_length(agent_active_call_list) == 0)
+ __bt_hfp_modify_indicator("call",
+ INDICATOR_EVENT_CALL_INACTIVE);
+
+ if (org_status == HFP_CALL_STATUS_HOLD) {
+ __bt_hfp_modify_indicator("callheld", INDICATOR_EVENT_CALLHELD_NONE);
+ }
+
+ if ((org_status == HFP_CALL_STATUS_MO_ALERTING) ||
+ (org_status == HFP_CALL_STATUS_COMING) ||
+ (org_status == HFP_CALL_STATUS_CREATE) ||
+ (org_status == HFP_CALL_STATUS_WAITING)) {
+ __bt_hfp_modify_indicator("callsetup",
+ INDICATOR_EVENT_CALLSETUP_INACTIVE);
+ }
+
+ if (org_status == HFP_CALL_STATUS_COMING) {
+ if (!t_call->call_originating)
+ _bt_calling_stopped_indicator();
+ }
+ existing_call_list = g_slist_remove(existing_call_list, t_call);
+ __bt_hfp_free_call(t_call);
+ break;
+
+ case HFP_CALL_STATUS_HOLD:
+ t_call->call_on_hold = TRUE;
+ __bt_hfp_handle_call_on_hold_request();
+ break;
+
+ case HFP_CALL_STATUS_TERMINATED:
+ if (t_call->call_on_hold &&
+ !__bt_hfp_get_call_with_status(HFP_CALL_STATUS_HOLD)) {
+ __bt_hfp_modify_indicator("callheld",
+ INDICATOR_EVENT_CALLHELD_NONE);
+ return;
+ }
+
+ if (call_held == INDICATOR_EVENT_CALLHELD_MULTIPLE &&
+ __bt_hfp_get_call_with_status(HFP_CALL_STATUS_HOLD) &&
+ !__bt_hfp_get_call_with_status(HFP_CALL_STATUS_ACTIVE))
+ __bt_hfp_modify_indicator("callheld",
+ INDICATOR_EVENT_CALLHELD_ON_HOLD);
+ break;
+
+ case HFP_CALL_STATUS_PROCEEDING:
+ case HFP_CALL_STATUS_SWAP_INITIATED:
+ case HFP_CALL_STATUS_RETRIEVE_INITIATED:
+ case HFP_CALL_STATUS_RECONNECT_PENDING:
+ case HFP_CALL_STATUS_HOLD_INITIATED:
+ case HFP_CALL_STATUS_WAITING:
+ case HFP_CALL_STATUS_ANSWERED:
+ break;
+
+ default:
+ break;
+ }
+
+ /* Update the call conference status for each of the call */
+ __bt_hfp_handle_call_conference();
+}
+
+bt_hfp_agent_error_t _bt_hfp_incoming_call(const char *call_path,
+ const char *incoming_number,
+ uint32_t incoming_call_id,
+ const char *sender)
+{
+ struct telephony_call *t_call = NULL;
+ bt_hfp_agent_error_t hfp_err = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+ int t_number = AGENT_NUMBER_TYPE_TELEPHONY;
+ int error;
+
+ if (sender == NULL || call_path == NULL)
+ return BT_HFP_AGENT_ERROR_INVALID_PARAM;
+
+ if (!__bt_hfp_check_for_callpath(call_path, sender))
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ if (!__bt_hfp_is_call_allowed(call_path))
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ /* Its a new call, so create a list for it*/
+ t_call = __bt_hfp_create_new_call(call_path, incoming_call_id,
+ incoming_number,
+ sender);
+
+ /*get the type of the incoming number*/
+ if (t_call->call_number == NULL) {
+ t_number = AGENT_NUMBER_TYPE_TELEPHONY;
+ ERR("call_number is NULL");
+ } else {
+ if (t_call->call_number[0] == '+' || strncmp(
+ t_call->call_number, "00", 2) == 0)
+ t_number = AGENT_NUMBER_TYPE_INTERNATIONAL;
+
+ if (__bt_hfp_get_call_with_status(HFP_CALL_STATUS_ACTIVE) ||
+ __bt_hfp_get_call_with_status(HFP_CALL_STATUS_HOLD)) {
+ error = _bt_call_waiting_indicator(t_call->call_number,
+ t_number);
+ if (error != 0)
+ ERR(" Fail to update CCWA information");
+
+ if (update_events) {
+ hfp_err = __bt_hfp_modify_indicator(
+ HFP_AGENT_CALLSETUP_INDICATOR,
+ HFP_INCOMING_CALLSETUP);
+ if (hfp_err != BT_HFP_AGENT_ERROR_NONE)
+ ERR("Failed to update the indicators");
+ }
+ __bt_hfp_set_call_status(t_call, HFP_CALL_STATUS_WAITING);
+ } else {
+ DBG(" It is an incoming call");
+
+ if (update_events) {
+ hfp_err = __bt_hfp_modify_indicator(
+ HFP_AGENT_CALLSETUP_INDICATOR,
+ HFP_INCOMING_CALLSETUP);
+ if (hfp_err != BT_HFP_AGENT_ERROR_NONE)
+ ERR("Failed to update the indicators");
+ }
+
+ error = _bt_incoming_call_indicator(t_call->call_number,
+ t_number);
+
+ __bt_hfp_set_call_status(t_call, HFP_CALL_STATUS_COMING);
+
+ if (error == -ENODEV)
+ return BT_HFP_AGENT_ERROR_NOT_CONNECTED;
+ else if (error == -EBUSY)
+ return BT_HFP_AGENT_ERROR_BUSY;
+ }
+ }
+
+ return hfp_err;
+}
+
+bt_hfp_agent_error_t _bt_hfp_outgoing_call(const char *call_path,
+ const char *number,
+ uint32_t call_id, const char *sender)
+{
+ struct telephony_call *t_call = NULL;
+ bt_hfp_agent_error_t ret = BT_HFP_AGENT_ERROR_NONE;
+ gboolean err = FALSE;
+
+
+ err = __bt_hfp_check_for_callpath(call_path, sender);
+ if (!err)
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ /*check if the call_path exisits in the active call list, if not
+ don't allow as the call may be initated by some other application*/
+
+ err = __bt_hfp_is_call_allowed(call_path);
+ if (!err)
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ /* create a new call for the call_path */
+ t_call = __bt_hfp_create_new_call(call_path, call_id, number, sender);
+
+ __bt_hfp_set_call_status(t_call, HFP_CALL_STATUS_CREATE);
+
+ ret = __bt_hfp_modify_indicator(HFP_AGENT_CALLSETUP_INDICATOR,
+ HFP_OUTGOING_CALLSETUP);
+ if (ret != BT_HFP_AGENT_ERROR_NONE)
+ DBG("Error in updating indicator");
+
+ return ret;
+}
+
+bt_hfp_agent_error_t _bt_hfp_change_call_status(const char *call_path,
+ const char *number, uint32_t call_status,
+ uint32_t call_id, const char *sender)
+{
+ GSList *call_list = existing_call_list;
+ struct telephony_call *t_call = NULL;
+ gboolean ret = FALSE;
+
+ if (call_status > AG_MAX_LENGTH)
+ return BT_HFP_AGENT_ERROR_INVALID_PARAM;
+
+ ret = __bt_hfp_check_for_callpath(call_path, sender);
+
+ if (!ret)
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ ret = __bt_hfp_is_call_allowed(call_path);
+ if (!ret)
+ return BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ /* find call with the given call_id*/
+ DBG(" Find call with the given call Id from the list");
+ while (call_list != NULL) {
+ t_call = call_list->data;
+
+ if (t_call->call_id == call_id) {
+ DBG("Call Id Match");
+ break;
+ } else {
+ t_call = NULL;
+ }
+
+ call_list = call_list->next;
+ }
+
+ if (t_call == NULL) {
+ DBG("t_call is NULL. So create new call");
+ t_call = __bt_hfp_create_new_call(call_path,
+ call_id, number, sender);
+ }
+
+ __bt_hfp_set_call_status(t_call, call_status);
+
+ return BT_HFP_AGENT_ERROR_NONE;
+}
+
+static int __bt_hfp_update_battery_strength(int32_t battery_strength)
+{
+ int bat_strength = 0;
+ int x, change_value;
+
+ DBG(" Battery strength is.... %d", battery_strength);
+
+ /* get the current battery level */
+ for (x = 0; hfp_ag_ind[x].indicator_desc != NULL; x++) {
+ if (g_str_equal(hfp_ag_ind[x].indicator_desc, "battchg"))
+ bat_strength = hfp_ag_ind[x].hfp_value;
+ }
+
+ /* We need to send battery status ranging from 0-5 */
+ if (battery_strength < 5)
+ change_value = 0;
+ else if (battery_strength >= 100)
+ change_value = 5;
+ else
+ change_value = battery_strength / 20 + 1;
+
+ if (bat_strength == change_value) {
+ DBG("no change in battery strength");
+ return 0;
+ }
+
+ if (__bt_hfp_modify_indicator("battchg",
+ change_value) == BT_HFP_AGENT_ERROR_NONE)
+ return 1;
+
+ return 0;
+}
+
+static int __bt_hfp_update_signal_strength(int32_t signal_strength_bars)
+{
+ if (signal_strength_bars < 0)
+ signal_strength_bars = 0;
+ else if (signal_strength_bars > 5)
+ signal_strength_bars = 5;
+
+ if (network_info.signal_strength == signal_strength_bars) {
+ DBG("no change in signal strength");
+ return 0;
+ }
+
+ network_info.signal_strength = signal_strength_bars;
+
+ if (__bt_hfp_modify_indicator("signal",
+ signal_strength_bars) == BT_HFP_AGENT_ERROR_NONE)
+ return 1;
+
+ return 0;
+}
+
+static int __bt_hfp_update_registration_status(uint8_t register_status)
+{
+ bt_hfp_agent_error_t reg_ret = BT_HFP_AGENT_ERROR_NOT_AVAILABLE;
+
+ DBG("Updating registration status to.... %d", register_status);
+
+ if (network_info.network_status == register_status) {
+ DBG("No change in registration status");
+ return 0;
+ }
+
+ if (register_status == BT_AGENT_NETWORK_REG_STATUS_ROAMING) {
+ reg_ret = __bt_hfp_modify_indicator("roam",
+ INDICATOR_EVENT_ROAM_ACTIVE);
+
+ if (network_info.network_status >
+ BT_AGENT_NETWORK_REG_STATUS_ROAMING)
+ reg_ret = __bt_hfp_modify_indicator("service",
+ INDICATOR_EVENT_SERVICE_PRESENT);
+ } else if (register_status == BT_AGENT_NETWORK_REG_STATUS_HOME) {
+ reg_ret = __bt_hfp_modify_indicator("roam",
+ INDICATOR_EVENT_ROAM_INACTIVE);
+
+ if (network_info.network_status >
+ BT_AGENT_NETWORK_REG_STATUS_ROAMING)
+ reg_ret = __bt_hfp_modify_indicator("service",
+ INDICATOR_EVENT_SERVICE_PRESENT);
+ } else if (register_status == BT_AGENT_NETWORK_REG_STATUS_OFFLINE ||
+ register_status == BT_AGENT_NETWORK_REG_STATUS_SEARCHING ||
+ register_status == BT_AGENT_NETWORK_REG_STATUS_NO_SIM ||
+ register_status == BT_AGENT_NETWORK_REG_STATUS_POWEROFF ||
+ register_status == BT_AGENT_NETWORK_REG_STATUS_POWERSAFE ||
+ register_status == BT_AGENT_NETWORK_REG_STATUS_NO_COVERAGE ||
+ register_status == BT_AGENT_NETWORK_REG_STATUS_REJECTED ||
+ register_status == BT_AGENT_NETWORK_REG_STATUS_UNKOWN) {
+ if (network_info.network_status <
+ BT_AGENT_NETWORK_REG_STATUS_OFFLINE)
+ reg_ret = __bt_hfp_modify_indicator("service",
+ INDICATOR_EVENT_SERVICE_NONE);
+ }
+
+ network_info.network_status = register_status;
+ if (reg_ret == BT_HFP_AGENT_ERROR_NONE)
+ return 1;
+
+ return 0;
+}
+
+int _bt_hfp_set_property_value(const char *property, int value)
+{
+ int ret = 0;
+
+ DBG("Property is %s", property);
+
+ if (g_str_equal("RegistrationChanged", property))
+ ret = __bt_hfp_update_registration_status(value);
+
+ else if (g_str_equal("SignalBarsChanged", property))
+ ret = __bt_hfp_update_signal_strength(value);
+
+ else if (g_str_equal("BatteryBarsChanged", property))
+ ret = __bt_hfp_update_battery_strength(value);
+
+ return ret;
+}
+
+int _bt_hfp_set_property_name(const char *property, const char *operator_name)
+{
+ int ret = 0;
+
+ if (operator_name == NULL)
+ return 0;
+
+ if (g_str_equal("OperatorNameChanged", property)) {
+ g_free(network_info.network_operator_name);
+ network_info.network_operator_name =
+ g_strndup(operator_name, 16);
+ ret = 1;
+ }
+
+ if (g_str_equal("SubscriberNumberChanged", property)) {
+ g_free(ag_subscriber_num);
+ ag_subscriber_num = g_strdup(operator_name);
+ DBG("HFP: subscriber_number updated: %s", ag_subscriber_num);
+ ret = 1;
+ }
+ return ret;
+}
+
+static int __bt_hfp_answer_call(struct telephony_call *t_call)
+{
+ if (t_call->call_id != 0 && t_call->call_path != NULL &&
+ t_call->call_sender != NULL) {
+ _bt_ag_agent_answer_call(t_call->call_id,
+ t_call->call_path,
+ t_call->call_sender);
+ return 0;
+ }
+ return -1;
+}
+
+void _bt_hfp_answer_call_request(void *t_device)
+{
+ struct telephony_call *t_call;
+
+ t_call = __bt_hfp_get_call_with_status(HFP_CALL_STATUS_COMING);
+
+ if (t_call == NULL)
+ t_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_MT_ALERTING);
+
+ if (t_call == NULL)
+ t_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_PROCEEDING);
+
+ if (t_call == NULL)
+ t_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_WAITING);
+
+ if (t_call == NULL) {
+ _bt_answer_call_response(t_device,
+ HFP_STATE_MNGR_ERR_NOT_ALLOWED);
+ return;
+ }
+
+ if (__bt_hfp_answer_call(t_call) < 0)
+ _bt_answer_call_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ else
+ _bt_answer_call_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+}
+
+
+void _bt_hfp_dial_number_request(const char *dial_number, void *t_device)
+{
+ int call_flag = caller_id;
+ bt_hfp_agent_error_t error_code = 0;
+
+ if (strncmp(dial_number, "#31#", 4) == 0) {
+ dial_number = dial_number + 4;
+ call_flag = ALLOW_CALL_FLAG;
+ } else if (strncmp(dial_number, "*31#", 4) == 0) {
+ dial_number = dial_number + 4;
+ call_flag = RESTRAIN_CALL_FLAG;
+ } else if (dial_number[0] == '>') {
+ int dial_location = strtol(&dial_number[1], NULL, 0);
+
+ error_code = _bt_ag_agent_dial_memory(dial_location);
+
+ if (error_code == BT_HFP_AGENT_ERROR_NONE)
+ _bt_dial_number_response(t_device,
+ HFP_STATE_MNGR_ERR_NONE);
+ else
+ _bt_dial_number_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ return;
+ }
+
+ error_code = _bt_ag_agent_dial_num(dial_number, call_flag);
+
+ if (error_code == BT_HFP_AGENT_ERROR_NONE) {
+ _bt_dial_number_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+ return;
+ }
+
+ _bt_dial_number_response(t_device, HFP_STATE_MNGR_ERR_AG_FAILURE);
+
+}
+
+void _bt_hfp_update_event_request(int indicator, void *t_device)
+{
+ if (indicator == 1)
+ update_events = TRUE;
+ else
+ update_events = FALSE;
+
+ _bt_event_reporting_response(t_device,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+static int __bt_bt_hfp_reject_call(struct telephony_call *t_call)
+{
+ gboolean ret;
+
+ if (t_call != NULL) {
+ DBG(" rejecting call from sender %s with call path %s and call id %d",
+ t_call->call_sender,
+ t_call->call_path,
+ t_call->call_id);
+
+ ret = _bt_ag_agent_reject_call(t_call->call_id,
+ t_call->call_path,
+ t_call->call_sender);
+ if (ret)
+ return 0;
+ }
+
+ return -1;
+}
+
+static int __bt_hfp_release_call(struct telephony_call *t_call)
+{
+ gboolean ret = _bt_ag_agent_release_call(t_call->call_id,
+ t_call->call_path,
+ t_call->call_sender);
+ if (!ret)
+ return -1;
+
+ return 0;
+}
+
+static int __bt_hfp_release_conference(void)
+{
+ GSList *temp_list = existing_call_list;
+
+ while (temp_list != NULL) {
+ struct telephony_call *t_call = temp_list->data;
+
+ if (t_call->call_conference)
+ __bt_hfp_release_call(t_call);
+
+ temp_list = temp_list->next;
+ }
+ return 0;
+}
+
+void _bt_hfp_terminate_call_request(void *t_device)
+{
+ struct telephony_call *t_call;
+ struct telephony_call *t_alert = NULL;
+ int t_error = 0;
+
+ t_call = __bt_hfp_get_call_with_status(HFP_CALL_STATUS_ACTIVE);
+
+ if (t_call == NULL) {
+ DBG("Find non-idle call");
+ GSList *temp_call_list = existing_call_list;
+ while (temp_call_list != NULL) {
+ t_call = temp_call_list->data;
+
+ if (t_call->call_status == HFP_AGENT_CALL_IDLE)
+ temp_call_list = temp_call_list->next;
+ else
+ break;
+ }
+ }
+
+ if (t_call == NULL) {
+ DBG("Seems like there are no active calls. So do not allow the call");
+ _bt_terminate_call_response(t_device,
+ HFP_STATE_MNGR_ERR_NOT_ALLOWED);
+ return;
+ }
+
+ if (__bt_hfp_get_call_with_status(HFP_CALL_STATUS_WAITING) != NULL) {
+ int value = 1;
+ t_error = _bt_ag_agent_threeway_call(value, t_call->call_path,
+ t_call->call_sender);
+ } else if ((t_alert = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_CREATE))
+ != NULL) {
+ t_error = __bt_bt_hfp_reject_call(t_alert);
+ } else if ((t_alert = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_MO_ALERTING))
+ != NULL) {
+ t_error = __bt_bt_hfp_reject_call(t_alert);
+ } else if ((t_alert = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_COMING)) != NULL) {
+ t_error = __bt_bt_hfp_reject_call(t_alert);
+ } else if (t_call->call_conference)
+ t_error = __bt_hfp_release_conference();
+ else
+ t_error = __bt_hfp_release_call(t_call);
+
+ if (t_error < 0)
+ _bt_terminate_call_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ else
+ _bt_terminate_call_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_call_hold_request(const char *t_cmd, void *t_device)
+{
+
+ struct telephony_call *t_call = NULL;
+ GSList *t_sender_list = call_senders_paths;
+ sender_info_t *sender_info = NULL;
+ uint32_t t_chld_value;
+
+ t_call = __bt_hfp_get_call_with_status(HFP_CALL_STATUS_ACTIVE);
+ if (t_call == NULL) {
+ if ((t_call =
+ __bt_hfp_get_call_with_status(HFP_CALL_STATUS_HOLD))
+ == NULL) {
+ if ((t_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_WAITING)) == NULL) {
+ /* means there is no outgoing call*/
+ _bt_call_hold_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ return;
+ }
+ }
+ }
+
+ while (t_sender_list != NULL) {
+ sender_info = t_sender_list->data;
+ if (sender_info == NULL) {
+ _bt_call_hold_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ return;
+ }
+ if (g_strcmp0(t_call->call_path, sender_info->sender_path)
+ == 0)
+ break;
+
+ t_sender_list = t_sender_list->next;
+ }
+
+ t_chld_value = strtoul(&t_cmd[0], NULL, 0);
+ gboolean ret = _bt_ag_agent_threeway_call(t_chld_value,
+ t_call->call_path,
+ t_call->call_sender);
+
+ if (ret == TRUE)
+ _bt_call_hold_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+ else {
+ _bt_call_hold_response(t_device, HFP_STATE_MNGR_ERR_AG_FAILURE);
+ }
+}
+
+void _bt_hfp_key_press_request(const char *t_key_press, void *t_device)
+{
+ struct telephony_call *t_active_call;
+ struct telephony_call *t_waiting_call;
+ int t_error = 0;
+
+ t_waiting_call = __bt_hfp_get_call_with_status(HFP_CALL_STATUS_COMING);
+
+ if (t_waiting_call == NULL)
+ t_waiting_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_MT_ALERTING);
+
+ if (t_waiting_call == NULL)
+ t_waiting_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_PROCEEDING);
+
+ t_active_call = __bt_hfp_get_call_with_status(HFP_CALL_STATUS_ACTIVE);
+
+
+ if (t_waiting_call != NULL)
+ t_error = __bt_hfp_answer_call(t_waiting_call);
+ else if (t_active_call != NULL)
+ t_error = __bt_hfp_release_call(t_active_call);
+ else {
+ if (_bt_ag_agent_dial_last_num(t_device) !=
+ BT_HFP_AGENT_ERROR_NONE)
+ _bt_dial_number_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ else
+ _bt_dial_number_response(t_device,
+ HFP_STATE_MNGR_ERR_NONE);
+ return;
+ }
+
+ if (t_error < 0)
+ _bt_key_press_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ else
+ _bt_key_press_response(t_device,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_last_dialed_number_request(void *t_device)
+{
+ bt_hfp_agent_error_t error = _bt_ag_agent_dial_last_num(t_device);
+
+ if (error != BT_HFP_AGENT_ERROR_NONE)
+ _bt_dial_number_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ else
+ _bt_dial_number_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_channel_dtmf_request(char t_tone, void *t_device)
+{
+ char buf[2] = { t_tone, '\0' };
+ char *tone_buffer = buf;
+
+ struct telephony_call *t_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_ACTIVE);
+ if (t_call == NULL) {
+ t_call = __bt_hfp_get_call_with_status(HFP_CALL_STATUS_HOLD);
+ if (t_call == NULL) {
+ t_call = __bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_WAITING);
+ if (t_call == NULL) {
+ /* if this point is reached,
+ it means there is no ongoing call */
+ _bt_transmit_dtmf_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ return;
+ }
+ }
+ }
+
+ if (_bt_ag_agent_send_dtmf(tone_buffer, t_call->call_path,
+ t_call->call_sender) != BT_HFP_AGENT_ERROR_NONE) {
+ _bt_transmit_dtmf_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ return;
+ }
+
+ _bt_transmit_dtmf_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_vendor_cmd_request(const char *cmd,
+ void *t_device)
+{
+ GSList *t_sender_list = call_senders_paths;
+ sender_info_t *sender_info = NULL;
+ GSList *l;
+ bt_hfp_agent_error_t error = BT_HFP_AGENT_ERROR_NONE;
+
+ if (NULL != t_sender_list) {
+ for (l = t_sender_list; l != NULL; l = l->next) {
+ sender_info = l->data;
+ error = _bt_ag_agent_vendor_cmd(cmd,
+ sender_info->sender_path,
+ sender_info->sender_name);
+ if (error != BT_HFP_AGENT_ERROR_NONE)
+ break;
+ }
+ }
+
+ if (error != BT_HFP_AGENT_ERROR_NONE)
+ _bt_vendor_cmd_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ else
+ _bt_vendor_cmd_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_subscriber_number_request(void *t_device)
+{
+ if (ag_subscriber_num != NULL) {
+
+ int t_number = AGENT_NUMBER_TYPE_TELEPHONY;
+
+ if (ag_subscriber_num[0] == '+' || strncmp(
+ ag_subscriber_num, "00", 2) == 0)
+ t_number = AGENT_NUMBER_TYPE_INTERNATIONAL;
+
+ _bt_subscriber_number_indicator(ag_subscriber_num,
+ t_number, AGENT_SUBSCRIBER_SERVICE_VOICE);
+ }
+
+ _bt_subscriber_number_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+}
+
+static int __bt_hfp_get_call_status(struct telephony_call *t_call)
+{
+ switch (t_call->call_status) {
+ case HFP_CALL_STATUS_IDLE:
+ case HFP_CALL_STATUS_MO_RELEASE:
+ case HFP_CALL_STATUS_MT_RELEASE:
+ case HFP_CALL_STATUS_TERMINATED:
+ return -1;
+
+ case HFP_CALL_STATUS_ANSWERED:
+ case HFP_CALL_STATUS_ACTIVE:
+ case HFP_CALL_STATUS_RECONNECT_PENDING:
+ case HFP_CALL_STATUS_SWAP_INITIATED:
+ case HFP_CALL_STATUS_HOLD_INITIATED:
+ return AGENT_CALL_STATUS_ACTIVE;
+
+ case HFP_CALL_STATUS_RETRIEVE_INITIATED:
+ case HFP_CALL_STATUS_HOLD:
+ return AGENT_CALL_STATUS_HELD;
+
+ case HFP_CALL_STATUS_WAITING:
+ return AGENT_CALL_STATUS_WAITING;
+
+ case HFP_CALL_STATUS_CREATE:
+ return AGENT_CALL_STATUS_DIALING;
+
+ case HFP_CALL_STATUS_PROCEEDING:
+ if (t_call->call_originating)
+ return AGENT_CALL_STATUS_DIALING;
+ if (g_slist_length(agent_active_call_list) > 0)
+ return AGENT_CALL_STATUS_WAITING;
+ else
+ return AGENT_CALL_STATUS_INCOMING;
+
+ case HFP_CALL_STATUS_COMING:
+ if (g_slist_length(agent_active_call_list) > 0)
+ return AGENT_CALL_STATUS_WAITING;
+ else
+ return AGENT_CALL_STATUS_INCOMING;
+
+ case HFP_CALL_STATUS_MO_ALERTING:
+ return AGENT_CALL_STATUS_ALERTING;
+
+ case HFP_CALL_STATUS_MT_ALERTING:
+ return AGENT_CALL_STATUS_INCOMING;
+
+ default:
+ return -1;
+ }
+}
+
+void _bt_list_current_calls(void *t_device)
+{
+ GSList *t_call_list = existing_call_list;
+ int t_status;
+ int t_number = AGENT_NUMBER_TYPE_TELEPHONY;
+ int t_direction, t_call_conference;
+ int index;
+
+ while (t_call_list != NULL) {
+ struct telephony_call *t_call = t_call_list->data;
+ t_status = __bt_hfp_get_call_status(t_call);
+ if (t_status >= 0) {
+ if (t_call->call_originating != TRUE)
+ t_direction = AGENT_CALL_DIRECTION_INCOMING;
+ else
+ t_direction = AGENT_CALL_DIRECTION_OUTGOING;
+
+ if (t_call->call_conference != TRUE)
+ t_call_conference = AGENT_CALL_MULTIPARTY_NO;
+ else
+ t_call_conference = AGENT_CALL_MULTIPARTY_YES;
+
+ if (t_call->call_number == NULL) {
+ t_number = AGENT_NUMBER_TYPE_TELEPHONY;
+ } else {
+ if (t_call->call_number[0] == '+' || strncmp(
+ t_call->call_number, "00", 2) == 0)
+ t_number = AGENT_NUMBER_TYPE_INTERNATIONAL;
+ }
+
+ index = t_call->call_id;
+ _bt_list_current_call_indicator(t_device, index, t_direction,
+ AGENT_CALL_MODE_VOICE,
+ t_status,
+ t_call->call_number,
+ t_call_conference,
+ t_number);
+ }
+ t_call_list = t_call_list->next;
+ }
+ _bt_list_current_calls_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_release_all_calls_by_sender(const char *sender)
+{
+ GSList *temp_list = existing_call_list;
+ GSList *next_list;
+
+ if(!sender)
+ return;
+
+ DBG("sender [%s]", sender);
+
+ while (temp_list != NULL) {
+ struct telephony_call *t_call = temp_list->data;
+
+ if (g_strcmp0(t_call->call_sender, sender) == 0) {
+ INFO("terminate call[%d]", t_call->call_id);
+ next_list = temp_list->next;
+ __bt_hfp_set_call_status(t_call, HFP_CALL_STATUS_MT_RELEASE);
+ temp_list = next_list;
+ } else
+ temp_list = temp_list->next;
+ }
+}
+
+void _bt_hfp_noise_red_and_echo_cancel_request(gboolean t_enable,
+ void *t_device)
+{
+ if (_bt_hfp_agent_nrec_status(t_enable, t_device) == TRUE)
+ _bt_nr_and_ec_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+ else
+ _bt_nr_and_ec_response(t_device, HFP_STATE_MNGR_ERR_AG_FAILURE);
+
+ return;
+}
+
+void _bt_hfp_voice_dial_request(gboolean t_enable, void *t_device)
+{
+ gboolean ret = FALSE;
+ int call_state = 0;
+
+ if (vconf_get_int(VCONFKEY_CALL_STATE, &call_state) < 0)
+ ERR("vconf_get_int is failed");
+
+ if ((t_enable == TRUE && call_state == 0) || t_enable == FALSE)
+ ret = _bt_ag_agent_voice_dial(t_enable);
+
+ if (ret == TRUE)
+ _bt_voice_dial_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+ else
+ _bt_voice_dial_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+
+ return;
+}
+
+void _bt_hfp_set_indicators(const char *t_command, void *t_device)
+{
+ const char delims = ',';
+ char *str = NULL;
+ int i = 0;
+ if (t_command == NULL)
+ goto fail;
+
+ str = strchr(t_command, '=');
+ while (hfp_ag_ind[i].indicator_desc != NULL && str != NULL) {
+ str++;
+
+ if ((g_strcmp0(hfp_ag_ind[i].indicator_desc, "call") != 0) &&
+ (g_strcmp0(hfp_ag_ind[i].indicator_desc, "callheld") != 0) &&
+ (g_strcmp0(hfp_ag_ind[i].indicator_desc, "callsetup") != 0)) {
+
+ if (*str == '0') {
+ hfp_ag_ind[i].is_activated = FALSE;
+ } else if (*str == '1') {
+ hfp_ag_ind[i].is_activated = TRUE;
+ } else {
+ DBG(" no change in is_activated for[%s]\n",
+ hfp_ag_ind[i].indicator_desc);
+ }
+ }
+ str = strchr(str, delims);
+ i++;
+ }
+
+ _bt_indicators_activation_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+ return;
+
+fail:
+ _bt_indicators_activation_response(t_device,
+ HFP_STATE_MNGR_ERR_INVALID_CHAR_IN_STRING);
+ return;
+}
+
+static int __bt_hfp_get_phonebook_count(const char *path, uint32_t *max_size,
+ uint32_t *used)
+{
+#ifndef TIZEN_WEARABLE
+ GDBusConnection *g_conn;
+ GDBusProxy *g_proxy;
+ GError *err = NULL;
+ GVariant *ret = NULL;
+ uint32_t max = 0;
+ uint32_t size = 0;
+
+ g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+
+ if (!g_conn) {
+ if (err) {
+ ERR("Unable to connect to gdbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return -1;
+ }
+
+ g_proxy = g_dbus_proxy_new_sync(g_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ PHONEBOOK_AGENT_BUS_NAME, PHONEBOOK_AGENT_PATH,
+ PHONEBOOK_AGENT_INTERFACE, NULL, &err);
+
+ if (!g_proxy) {
+ if (err) {
+ ERR("Unable to connect to gdbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return -1;
+ }
+
+ ret = g_dbus_proxy_call_sync(g_proxy, "GetPhonebookSizeAt",
+ g_variant_new("(s)",
+ path),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &err);
+
+ if (ret == NULL) {
+ ERR("dbus call failed");
+ if (err != NULL) {
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ err->code, err->message);
+
+ g_clear_error(&err);
+ }
+ }
+ if (ret != NULL) {
+ g_variant_get(ret, "(u)", &size);
+ g_variant_unref(ret);
+ }
+ DBG("Size returned %d", size);
+ if ((g_strcmp0(path, "\"SM\"") == 0) ||
+ (g_strcmp0(path, "\"ME\"") == 0)) {
+ max = AGENT_MAX_PB_COUNT;
+ } else if ((g_strcmp0(path, "\"DC\"") == 0) ||
+ (g_strcmp0(path, "\"MC\"") == 0) ||
+ (g_strcmp0(path, "\"RC\"") == 0)) {
+ max = AGENT_MAX_CALLLOG_COUNT;
+ }
+
+ if (max_size)
+ *max_size = max;
+ if (used) {
+ if (size > max)
+ *used = max;
+ else
+ *used = size;
+ }
+
+ if (g_conn)
+ g_object_unref(g_conn);
+ if (g_proxy)
+ g_object_unref(g_proxy);
+#endif
+ return 0;
+}
+
+void _bt_hfp_select_phonebook_memory_status(void *t_device)
+{
+ int32_t path_id = ag_pb_info.path_id;
+ uint32_t used = 0;
+ uint32_t max_size = 0;
+
+ hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
+
+ if (path_id < 0 || path_id >= AGENT_PB_STORE_LIST_SIZE)
+ path_id = 0;
+
+ if (__bt_hfp_get_phonebook_count(agent_pb_store_list[path_id],
+ &max_size, &used))
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+
+ _bt_select_phonebook_memory_status_response(t_device,
+ agent_pb_store_list[path_id],
+ max_size, used,
+ err);
+}
+
+static char *__bt_hfp_get_supported_list(const char *char_list[],
+ unsigned int size)
+{
+ GString *strng;
+
+ int index = 0;
+
+ if (char_list == NULL || size == 0)
+ return NULL;
+
+ strng = g_string_new("(");
+
+ while (index < size) {
+ if (index > 0)
+ g_string_append(strng, ",");
+
+ g_string_append(strng, char_list[index]);
+ index++;
+ }
+
+ g_string_append(strng, ")");
+
+ return g_string_free(strng, FALSE);
+}
+
+void _bt_hfp_select_phonebook_memory_list(void *t_device)
+{
+ char *str;
+
+ str = __bt_hfp_get_supported_list(agent_pb_store_list,
+ AGENT_PB_STORE_LIST_SIZE);
+
+ _bt_select_phonebook_memory_list_response(t_device,
+ str, HFP_STATE_MNGR_ERR_NONE);
+
+ g_free(str);
+}
+
+void _bt_hfp_select_phonebook_memory(void *t_device, const gchar *pb_path)
+{
+ int i = 0;
+ hfp_state_manager_err_t err;
+
+ while (i < AGENT_PB_STORE_LIST_SIZE) {
+ if (strcmp(agent_pb_store_list[i], pb_path) == 0)
+ break;
+ i++;
+ }
+
+ if (i >= 0 && i < AGENT_PB_STORE_LIST_SIZE) {
+ err = HFP_STATE_MNGR_ERR_NONE;
+ ag_pb_info.path_id = i;
+ } else {
+ err = HFP_STATE_MNGR_ERR_INVALID_CHAR_IN_STRING;
+ }
+ _bt_select_phonebook_memory_response(t_device, err);
+}
+
+void _bt_hfp_read_phonebook_entries_list(void *t_device)
+{
+ hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
+
+ int32_t path_id = ag_pb_info.path_id;
+ uint32_t used = 0;
+
+ if (path_id < 0 || path_id >= AGENT_PB_STORE_LIST_SIZE)
+ err = HFP_STATE_MNGR_ERR_INVALID_INDEX;
+ else {
+ if (__bt_hfp_get_phonebook_count(agent_pb_store_list[path_id],
+ NULL, &used) != 0) {
+ err = HFP_STATE_MNGR_ERR_NOT_ALLOWED;
+ }
+ }
+
+ _bt_read_phonebook_entries_list_response(t_device, used,
+ AGENT_PB_NUMBER_MAX_LENGTH, AGENT_PB_NAME_MAX_LENGTH,
+ err);
+}
+
+static int __bt_hfp_get_phonebook_entries(int start_index, int end_index)
+{
+#ifdef TIZEN_WEARABLE
+ int count = 0;
+#else
+ GDBusConnection *g_conn;
+ GDBusProxy *g_proxy;
+ GError *err = NULL;
+ GVariant *ret = NULL;
+ int count = 0;
+ GVariant *value = NULL;
+ GVariant *tuple = NULL;
+ const char *name = NULL;
+ const char *number = NULL;
+
+ char *uni_name;
+ char *uni_number;
+
+ uint32_t handle = 0;
+
+ g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+
+ if (!g_conn) {
+ if (err) {
+ ERR("Unable to connect to gdbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return -1;
+ }
+
+ g_proxy = g_dbus_proxy_new_sync(g_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ PHONEBOOK_AGENT_BUS_NAME, PHONEBOOK_AGENT_PATH,
+ PHONEBOOK_AGENT_INTERFACE, NULL, &err);
+ if (!g_proxy) {
+ if (err) {
+ ERR("Unable to connect to gdbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ return -1;
+ }
+
+ ret = g_dbus_proxy_call_sync(g_proxy, "GetPhonebookEntriesAt",
+ g_variant_new("(sii)",
+ agent_pb_store_list[ag_pb_info.path_id],
+ start_index, end_index),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &err);
+
+ if (ret == NULL) {
+ ERR("Dbus call failed");
+ if (err != NULL) {
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ err->code, err->message);
+
+ g_clear_error(&err);
+ } else {
+ ERR("error returned was NULL");
+ }
+ return -1;
+ } else {
+ tuple = g_variant_get_child_value(ret, 0);
+ if (tuple != NULL) {
+ int number_contacts = g_variant_n_children(tuple);
+ DBG("number of contacts %d", number_contacts);
+ while (count < number_contacts) {
+ value = NULL;
+
+ value = g_variant_get_child_value(tuple, count);
+
+ g_variant_get(value, "(ssu)", &name, &number, &handle);
+ count++;
+ uni_name = g_strndup(name, AGENT_PB_NAME_MAX_LENGTH);
+ uni_number = g_strndup(number, AGENT_PB_NAME_MAX_LENGTH);
+
+ _bt_read_phonebook_entries_indicator(uni_name,
+ uni_number, handle);
+ g_variant_unref(value);
+ g_free(uni_name);
+ g_free(uni_number);
+ g_free(name);
+ g_free(number);
+ }
+ g_variant_unref(tuple);
+ }
+ }
+ g_variant_unref(ret);
+ if (g_conn)
+ g_object_unref(g_conn);
+ if (g_proxy)
+ g_object_unref(g_proxy);
+#endif
+ return count;
+}
+
+void _bt_hfp_read_phonebook_entries(void *t_device, const char *cmd)
+{
+ int start_index = 0;
+ int end_index = 0;
+
+ int count = 0;
+
+ char *str = NULL;
+ char *next = NULL;
+
+ hfp_state_manager_err_t err;
+
+ if (cmd == NULL)
+ return;
+
+ str = g_strdup(cmd);
+ next = strchr(str, ',');
+
+ if (next) {
+ *next = '\0';
+ next++;
+
+ end_index = strtol(next, NULL, 10);
+ }
+
+ start_index = strtol(str, NULL, 10);
+
+ g_free(str);
+
+ count = __bt_hfp_get_phonebook_entries(start_index, end_index);
+
+ if (count < 0)
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+ else if (count == 0)
+ err = HFP_STATE_MNGR_ERR_INVALID_INDEX;
+ else
+ err = HFP_STATE_MNGR_ERR_NONE;
+
+ _bt_read_phonebook_entries_response(t_device, err);
+}
+
+void _bt_hfp_find_phonebook_entries_status(void *t_device)
+{
+ _bt_find_phonebook_entries_status_indicator(
+ AGENT_PB_NUMBER_MAX_LENGTH,
+ AGENT_PB_NAME_MAX_LENGTH);
+
+ _bt_find_phonebook_entries_status_response(t_device,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+static int __bt_hfp_find_pb_entries(const char *str)
+{
+ return 0;
+}
+
+void _bt_hfp_find_phonebook_entries(void *t_device, const char *cmd)
+{
+ gchar *st = NULL;
+ gchar *unquoted = NULL;
+
+ hfp_state_manager_err_t err = HFP_STATE_MNGR_ERR_NONE;
+
+ /* remove quote and compress */
+ st = strchr(cmd, '"');
+ if (st == NULL)
+ unquoted = g_strdup(cmd);
+ else {
+ gchar *end = NULL;
+
+ end = strrchr(cmd, '"');
+ if (end == NULL)
+ unquoted = g_strdup(cmd);
+ else
+ unquoted = g_strndup(st + 1, end - st - 1);
+ }
+
+ if (__bt_hfp_find_pb_entries(unquoted))
+ err = HFP_STATE_MNGR_ERR_AG_FAILURE;
+
+ _bt_find_phonebook_entries_response(t_device, err);
+
+ g_free(unquoted);
+}
+
+void _bt_hfp_get_character_set(void *t_device)
+{
+ _bt_supported_character_generic_response(t_device,
+ (char *)agent_supported_character_set[ag_pb_info.charset_id],
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_list_supported_character(void *t_device)
+{
+ char *str;
+
+ str = __bt_hfp_get_supported_list(agent_supported_character_set,
+ AGENT_SUPPORTED_CHARACTER_SET_SIZE);
+
+ _bt_supported_character_generic_response(t_device,
+ str, HFP_STATE_MNGR_ERR_NONE);
+
+ g_free(str);
+}
+
+void _bt_hfp_set_character_set(void *t_device, const char *cmd)
+{
+ int index = 0;
+
+ while (index < AGENT_SUPPORTED_CHARACTER_SET_SIZE) {
+ if (strcmp(agent_supported_character_set[index], cmd) == 0) {
+ _bt_set_characterset_generic_response(t_device,
+ HFP_STATE_MNGR_ERR_NONE);
+
+ ag_pb_info.charset_id = index;
+ return;
+ }
+ index++;
+ }
+
+ _bt_set_characterset_generic_response(t_device,
+ HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
+ return;
+}
+
+void _bt_hfp_signal_quality_reply(int32_t rssi, int32_t ber,
+ void *t_device)
+{
+ DBG("signal_quality_reply");
+
+ if (rssi == -1 && ber == -1) {
+ _bt_signal_quality_response(t_device, rssi, ber,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+ } else {
+ _bt_signal_quality_response(t_device, rssi, ber,
+ HFP_STATE_MNGR_ERR_NONE);
+ }
+}
+
+void _bt_hfp_battery_property_reply(void *data, int32_t bcs,
+ int32_t bcl)
+{
+ if (bcs == -1 || bcl == -1) {
+ _bt_battery_charge_status_response(data, bcs,
+ bcl, HFP_STATE_MNGR_ERR_AG_FAILURE);
+ } else {
+ _bt_battery_charge_status_response(data, bcs,
+ bcl, HFP_STATE_MNGR_ERR_NONE);
+ }
+
+ return;
+}
+
+void _bt_hfp_get_battery_property(void *t_device)
+{
+ _bt_ag_agent_get_battery_status(t_device);
+}
+
+void _bt_hfp_operator_reply(char *operator_name, void *t_device)
+{
+ if (operator_name == NULL)
+ goto failed;
+
+ network_info.network_operator_name = g_strndup(operator_name, 16);
+
+ _bt_operator_selection_indicator(AGENT_OPERATOR_MODE_AUTO,
+ operator_name);
+ _bt_operator_selection_response(t_device, HFP_STATE_MNGR_ERR_NONE);
+ return;
+
+failed:
+ _bt_operator_selection_indicator(AGENT_OPERATOR_MODE_AUTO, "UNKNOWN");
+ _bt_operator_selection_response(t_device,
+ HFP_STATE_MNGR_ERR_AG_FAILURE);
+}
+
+void _bt_hfp_get_operator_selection_request(void *t_device)
+{
+ _bt_ag_agent_get_operator_name(t_device);
+}
+
+void _bt_hfp_response_and_hold_request(void *t_device)
+{
+ _bt_response_and_hold_response(t_device,
+ HFP_STATE_MNGR_ERR_NOT_SUPPORTED);
+}
+
+void _bt_get_activity_status(void *t_device)
+{
+ DBG("telephony-tizen: telephony_get_activity_status");
+
+ if (NULL != (__bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_MT_ALERTING)) ||
+ NULL != (__bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_MO_ALERTING)) ||
+ NULL != (__bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_COMING)) ||
+ NULL != (__bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_CREATE)))
+ _bt_hfp_get_activity_status_rsp(t_device,
+ HFP_AGENT_ACTIVITY_STATUS_RINGING,
+ HFP_STATE_MNGR_ERR_NONE);
+ else if (NULL != (__bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_WAITING)) ||
+ NULL != (__bt_hfp_get_call_with_status(
+ HFP_CALL_STATUS_ACTIVE)))
+ _bt_hfp_get_activity_status_rsp(t_device,
+ HFP_AGENT_ACTIVITY_STATUS_CALL_IN_PROGRESS,
+ HFP_STATE_MNGR_ERR_NONE);
+ else
+ _bt_hfp_get_activity_status_rsp(t_device,
+ HFP_AGENT_ACTIVITY_STATUS_READY,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_get_imei_number_reply(char *imei_number, void *t_device)
+{
+ _bt_hfp_get_equipment_identity_rsp(t_device, imei_number,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_get_imsi_reply(char *mcc, char *mnc, char *msin, void *t_device)
+{
+ if (mcc != NULL && mnc != NULL && msin != NULL)
+ _bt_hfp_get_imsi_rsp(t_device, mcc, mnc, msin,
+ HFP_STATE_MNGR_ERR_NONE);
+ else
+ _bt_hfp_get_imsi_rsp(t_device,NULL,NULL,NULL,
+ HFP_STATE_MNGR_ERR_NOT_ALLOWED);
+}
+
+void _bt_hfp_get_creg_status_reply(int n, int status, void *t_device)
+{
+ _bt_hfp_get_creg_status_rsp(t_device, n, status,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_get_equipment_identity_req(void *t_device)
+{
+ _bt_ag_agent_get_imei_number(t_device);
+}
+
+void _bt_hfp_get_model_info_reply(char *model, void *t_device)
+{
+ _bt_hfp_get_model_info_rsp(t_device, model,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_get_model_info_req(void *t_device)
+{
+ _bt_ag_agent_get_model_name(t_device);
+}
+
+void _bt_hfp_get_device_manufacturer_reply(char *manufacturer, void *t_device)
+{
+ _bt_hfp_get_device_manufacturer_rsp(t_device, manufacturer,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_get_device_manufacturer_req(void *t_device)
+{
+ _bt_ag_agent_get_manufacturer_name(t_device);
+}
+
+void _bt_hfp_get_imsi_req(void *t_device)
+{
+ _bt_ag_agent_get_imsi(t_device);
+}
+
+void _bt_hfp_get_creg_status_req(void *t_device)
+{
+ _bt_ag_agent_get_creg_status(t_device);
+}
+
+void _bt_hfp_get_revision_info_reply(char *revision, void *t_device)
+{
+ _bt_hfp_get_revision_info_rsp(t_device, revision,
+ HFP_STATE_MNGR_ERR_NONE);
+}
+
+void _bt_hfp_get_revision_info_req(void *t_device)
+{
+ _bt_ag_agent_get_revision_information(t_device);
+}
+
--- /dev/null
+[D-BUS Service]
+Name=org.bluez.ag_agent
+Exec=/usr/bin/bluetooth-ag-agent
+User=system
+Group=system
--- /dev/null
+AddressBlacklist=00:1B:52,0C:D9:C1,00:1E:AE,38:C0:96,BC:6A:29,64:D4:BD,30:14:4A,00:0E:9F,00:17:CA,00:26:7E,00:0B:24,00:24:0B,08:76:95,00:05:C9
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(bluetooth-hf-agent C)
+
+SET(SRCS bluetooth-hf-agent.c)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs_hf_agent
+ REQUIRED
+ dlog aul bluetooth-api alarm-service capi-appfw-app-manager
+ glib-2.0 gio-2.0 gio-unix-2.0 capi-system-device vconf)
+
+FOREACH(flag ${pkgs_hf_agent_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_hf_agent_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.bluez.hf_agent.service
+ DESTINATION share/dbus-1/system-services)
--- /dev/null
+/*
+ * Bluetooth-hf-agent
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Chethan T N <chethan.tn@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <aul.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+#include <device/power.h>
+#include <app_manager.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+#include <bundle_internal.h>
+
+#include "bluetooth-hf-agent.h"
+
+#define BT_AGENT_SYSPOPUP_MAX_ATTEMPT 3
+#define CALL_APP_ID "org.tizen.call-ui"
+
+#define MAX_WAITING_DELAY 8
+#define READ_TX_POWER_MIN -30
+
+#define BT_ADDRESS_STRING_SIZE 18
+#define BT_AT_COMMAND_BUFFER_MAX 4000
+#define BT_HF_ERROR_RESP "\r\nERROR\r\n"
+#define BT_HF_COMMAND_TIMEOUT 3
+
+#define ret_if(expr) \
+ do { \
+ if (expr) { \
+ ERR("(%s) return", #expr); \
+ return; \
+ } \
+ } while (0)
+
+static GMainLoop *gmain_loop = NULL;
+static char *g_obj_path;
+
+static GDBusConnection *gdbus_conn;
+static GDBusProxy *service_gproxy;
+static int owner_sig_id = -1;
+int g_id = 0;
+uint16_t hf_ver;
+
+#define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"
+#define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
+
+/*Below Inrospection data is exposed to bluez from agent*/
+static const gchar hf_agent_bluez_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.bluez.Profile1'>"
+" <method name='NewConnection'>"
+" <arg type='o' name='device' direction='in'/>"
+" <arg type='h' name='fd' direction='in'/>"
+" <arg type='a{sv}' name='options' direction='in'/>"
+" </method>"
+" <method name='RequestDisconnection'>"
+" <arg type='o' name='device' direction='in'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+/*Below Inrospection data is exposed to application from agent*/
+static const gchar hf_agent_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.tizen.HfApp'>"
+" <method name='AnswerCall'>"
+" </method>"
+" <method name='TerminateCall'>"
+" </method>"
+" <method name='InitiateCall'>"
+" <arg type='s' name='phoneno' direction='in'/>"
+" </method>"
+" <method name='VoiceRecognition'>"
+" <arg type='i' name='status' direction='in'/>"
+" </method>"
+" <method name='ScoDisconnect'>"
+" </method>"
+" <method name='SpeakerGain'>"
+" <arg type='u' name='gain' direction='in'/>"
+" </method>"
+" <method name='SendDtmf'>"
+" <arg type='s' name='dtmf' direction='in'/>"
+" </method>"
+" <method name='SendAtCmd'>"
+" <arg type='s' name='atcmd' direction='in'/>"
+" </method>"
+" <method name='ReleaseAndAccept'>"
+" </method>"
+" <method name='CallSwap'>"
+" </method>"
+" <method name='ReleaseAllCall'>"
+" </method>"
+" <method name='JoinCall'>"
+" </method>"
+" <method name='GetCurrentCodec'>"
+" <arg type='i' name='codec' direction='out'/>"
+" </method>"
+" <method name='RequestCallList'>"
+" <arg type='i' name='count' direction='out'/>"
+" <arg type='a(siiii)' name='callList' direction='out'/>"
+" </method>"
+" <method name='GetAudioConnected'>"
+" <arg type='i' name='status' direction='out'/>"
+" </method>"
+" <method name='IsHfConnected'>"
+" <arg type='b' name='status' direction='out'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+static bt_hf_agent_info_t bt_hf_info;
+static gboolean is_hf_connected = FALSE;
+static int32_t current_codec_id = BT_HF_CODEC_ID_CVSD;
+static int32_t sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
+
+static char global_buff[BT_AT_COMMAND_BUFFER_MAX] = {0,};
+int send_flag;
+
+static char prev_cmd[BT_HF_CMD_BUF_SIZE];
+
+typedef struct {
+ int idx;
+ int dir;
+ int status;
+ int mode;
+ int multi_party;
+ int type;
+ char *number;
+} hf_call_list_info_t;
+
+static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error);
+
+static gboolean __bt_hf_agent_emit_property_changed(
+ GDBusConnection *connection,
+ const char *path,
+ const char *interface,
+ const char *name,
+ GVariant *property);
+
+static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
+ bt_hf_agent_info_t *bt_hf_info);
+static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info);
+static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info);
+static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
+ gsize count);
+static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
+ gchar *data, gsize count);
+
+static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
+ gsize count);
+static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
+ gchar *data, gchar *response, gsize count);
+static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indies);
+static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indies);
+static guint __bt_hf_get_hold_mpty_features(gchar *features);
+static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info);
+static void __bt_hf_agent_sigterm_handler(int signo);
+static gboolean __bt_hf_agent_release(void);
+
+static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info);
+static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info);
+static gboolean __bt_hf_agent_connection(gint32 fd, const gchar * object_path);
+static gboolean __bt_hf_agent_connection_release(void);
+
+struct indicator {
+ gchar descr[BT_HF_INDICATOR_DESCR_SIZE];
+ gint value;
+};
+
+static int _hf_agent_answer_call(GDBusMethodInvocation *context);
+
+static int _hf_agent_terminate_call(GDBusMethodInvocation *context);
+
+static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no);
+
+static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context,
+ unsigned int gain);
+
+static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd);
+
+static int _hf_agent_voice_recognition(GDBusMethodInvocation *context,
+ unsigned int status);
+
+static gboolean bt_hf_agent_sco_disconnect(void);
+
+static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf);
+
+static GVariant *bt_hf_agent_request_call_list(void);
+
+static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd);
+
+static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf);
+static GQuark __bt_hf_agent_error_quark(void)
+{
+ DBG("");
+
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string("hf-agent");
+
+ return quark;
+}
+
+static GError *__bt_hf_agent_set_error(bt_hf_agent_error_t error)
+{
+ ERR("error[%d]", error);
+
+ switch (error) {
+ case BT_HF_AGENT_ERROR_NOT_AVAILABLE:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_NOT_AVAILABLE);
+ case BT_HF_AGENT_ERROR_NOT_CONNECTED:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_NOT_CONNECTED);
+ case BT_HF_AGENT_ERROR_CONNECTION_FAILED:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_NOT_CONNECTION_FAILED);
+ case BT_HF_AGENT_ERROR_BUSY:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_BUSY);
+ case BT_HF_AGENT_ERROR_INVALID_PARAM:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_INVALID_PARAM);
+ case BT_HF_AGENT_ERROR_ALREADY_EXIST:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_ALREADY_EXIST);
+ case BT_HF_AGENT_ERROR_ALREADY_CONNECTED:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_ALREADY_CONNECTED);
+ case BT_HF_AGENT_ERROR_NO_MEMORY:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_NO_MEMORY);
+ case BT_HF_AGENT_ERROR_I_O_ERROR:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_I_O_ERROR);
+ case BT_HF_AGENT_ERROR_APPLICATION:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_OPERATION_NOT_AVAILABLE);
+ case BT_HF_AGENT_ERROR_NOT_ALLOWED:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_OPERATION_NOT_ALLOWED);
+ case BT_HF_AGENT_ERROR_NOT_SUPPORTED:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_OPERATION_NOT_SUPPORTED);
+ case BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_INVALID_FILE_DESCRIPTOR);
+ case BT_HF_AGENT_ERROR_INTERNAL:
+ default:
+ return g_error_new(BT_HF_AGENT_ERROR, error,
+ BT_ERROR_INTERNAL);
+ }
+}
+
+static void __bt_hf_lock_display(int timeout)
+{
+ int ret;
+
+ ret = device_power_request_lock(POWER_LOCK_DISPLAY, timeout);
+ if (ret >= 0)
+ DBG("Lock PM state as current state!");
+ else
+ ERR("deviced error!");
+}
+
+static void __bt_hf_unlock_display()
+{
+ int ret;
+
+ ret = device_power_release_lock(POWER_LOCK_DISPLAY);
+ if (ret >= 0)
+ DBG("UnLock PM state");
+ else
+ ERR("deviced error!");
+}
+
+static void __hf_agent_method(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *context,
+ gpointer user_data)
+{
+ DBG("+");
+
+ INFO("method %s", method_name);
+ int ret = 0;
+ GError *err;
+
+ if (g_strcmp0(method_name, "NewConnection") == 0) {
+ gint32 fd;
+ int index;
+ GDBusMessage *msg;
+ GUnixFDList *fd_list;
+ const gchar *object_path;
+ GVariant *options;
+
+ g_variant_get(parameters, "(oha{sv})",
+ &object_path, &index, &options);
+
+ msg = g_dbus_method_invocation_get_message(context);
+ fd_list = g_dbus_message_get_unix_fd_list(msg);
+ if (fd_list == NULL) {
+ ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
+ goto fail;
+ }
+
+ fd = g_unix_fd_list_get(fd_list, index, NULL);
+ if (fd == -1) {
+ ret = BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR;
+ goto fail;
+ }
+
+ DBG("FD is = [%d], Object path = [%s]", fd, object_path);
+
+ if (!__bt_hf_agent_connection(fd, object_path)) {
+ ret = BT_HF_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ g_dbus_method_invocation_return_value(context, NULL);
+ } else if (g_strcmp0(method_name, "RequestDisconnection") == 0) {
+ if (!__bt_hf_agent_connection_release()) {
+ ret = BT_HF_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+ INFO_C("Disconnected [HF role] [Terminated by local host]");
+ g_dbus_method_invocation_return_value(context, NULL);
+ } else if (g_strcmp0(method_name, "Release") == 0) {
+ if (!__bt_hf_agent_connection_release()) {
+ ret = BT_HF_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ g_dbus_method_invocation_return_value(context, NULL);
+ } else if (g_strcmp0(method_name, "AnswerCall") == 0) {
+ DBG("Going to call AnswerCall");
+ ret = _hf_agent_answer_call(context);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "TerminateCall") == 0) {
+ DBG("Going to call TerminateCall");
+ ret = _hf_agent_terminate_call(context);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "InitiateCall") == 0) {
+ char *phoneno = NULL;
+
+ g_variant_get(parameters, "(&s)", &phoneno);
+
+ DBG_SECURE("Going to call InitiateCall, Number is = [%s]\n", phoneno);
+ ret = _hf_agent_dial_no(NULL, phoneno);
+ if (ret)
+ goto fail;
+
+ g_dbus_method_invocation_return_value(context, NULL);
+
+ } else if (g_strcmp0(method_name, "VoiceRecognition") == 0) {
+ int status = 0;
+
+ g_variant_get(parameters, "(i)", &status);
+
+ DBG("Going to call VoiceRecognition, Status [%d]", status);
+ ret = _hf_agent_voice_recognition(context, status);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "ScoDisconnect") == 0) {
+ DBG("Going to call ScoDisconnect");
+ if (!bt_hf_agent_sco_disconnect()) {
+ ret = BT_HF_AGENT_ERROR_INTERNAL;
+ goto fail;
+ }
+
+ g_dbus_method_invocation_return_value(context, NULL);
+ } else if (g_strcmp0(method_name, "SpeakerGain") == 0) {
+ unsigned int gain = 0;
+
+ g_variant_get(parameters, "(u)", &gain);
+
+ DBG("Going to call SpeakerGain, gain is = [%d]\n", gain);
+ ret = _hf_agent_set_speaker_gain(context, gain);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "SendDtmf") == 0) {
+ char *dtmf = NULL;
+
+ g_variant_get(parameters, "(&s)", &dtmf);
+
+ DBG("Going to call SendDtmf, dtmf is = [%s]\n", dtmf);
+ ret = _hf_agent_send_dtmf(NULL, dtmf);
+ if (ret)
+ goto fail;
+ g_dbus_method_invocation_return_value(context, NULL);
+
+ } else if (g_strcmp0(method_name, "SendAtCmd") == 0) {
+ char *cmd = NULL;
+
+ g_variant_get(parameters, "(&s)", &cmd);
+
+ DBG("Going to call SendAtCmd, cmd is = [%s]\n", cmd);
+ ret = bt_hf_agent_send_at_cmd(context, cmd);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "ReleaseAndAccept") == 0) {
+ DBG("Going to call ReleaseAndAccept");
+ ret = _hf_agent_send_3way_cmd(context,
+ BT_HF_RELEASE_AND_ACCEPT);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "CallSwap") == 0) {
+ DBG("Going to call CallSwap");
+ ret = _hf_agent_send_3way_cmd(context,
+ BT_HF_ACCEPT_AND_HOLD);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "ReleaseAllCall") == 0) {
+ DBG("Going to call ReleaseAllCall");
+ ret = _hf_agent_send_3way_cmd(context, BT_HF_RELEASE_ALL);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "JoinCall") == 0) {
+ DBG("Going to call JoinCall");
+ ret = _hf_agent_send_3way_cmd(context, BT_HF_JOIN_CALL);
+ if (ret)
+ goto fail;
+
+ } else if (g_strcmp0(method_name, "GetCurrentCodec") == 0) {
+ DBG("Going to call GetCurrentCodec");
+ INFO("Current codec : %d", current_codec_id);
+ g_dbus_method_invocation_return_value(context,
+ g_variant_new("(i)", current_codec_id));
+ } else if (g_strcmp0(method_name, "RequestCallList") == 0) {
+ GVariant *call_var;
+
+ DBG("Going to call RequestCallList");
+ call_var = bt_hf_agent_request_call_list();
+ if (!call_var) {
+ ret = BT_HF_AGENT_ERROR_NOT_AVAILABLE;
+ goto fail;
+ }
+ g_dbus_method_invocation_return_value(context, call_var);
+ } else if (g_strcmp0(method_name, "GetAudioConnected") == 0) {
+ DBG("Going to call GetAudioConnected");
+ g_dbus_method_invocation_return_value(context,
+ g_variant_new("(i)", sco_audio_connected));
+ } else if (g_strcmp0(method_name, "IsHfConnected") == 0) {
+ DBG("Going to call IsHfConnected");
+ INFO("is_hf_connected : %s", is_hf_connected ? "Connected":"Disconnected");
+
+ g_dbus_method_invocation_return_value(context,
+ g_variant_new("(b)", is_hf_connected));
+ }
+ INFO("-");
+ return;
+
+fail:
+ err = __bt_hf_agent_set_error(ret);
+ g_dbus_method_invocation_return_gerror(context, err);
+ g_error_free(err);
+ INFO("-");
+}
+
+static const GDBusInterfaceVTable method_table = {
+ __hf_agent_method,
+ NULL,
+ NULL,
+};
+
+static GDBusNodeInfo *__bt_hf_create_method_node_info
+ (const gchar *introspection_data)
+{
+ if (introspection_data == NULL)
+ return NULL;
+
+ return g_dbus_node_info_new_for_xml(introspection_data, NULL);
+}
+
+static GDBusConnection *__bt_hf_get_gdbus_connection(void)
+{
+ GDBusConnection *local_system_gconn = NULL;
+ GError *err = NULL;
+
+ if (gdbus_conn == NULL) {
+ gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (!gdbus_conn) {
+ if (err) {
+ ERR("Unable to connect to dbus: %s", err->message);
+ g_clear_error(&err);
+ }
+ gdbus_conn = NULL;
+ }
+ } else if (g_dbus_connection_is_closed(gdbus_conn)) {
+ local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+
+ if (!local_system_gconn) {
+ ERR("Unable to connect to dbus: %s", err->message);
+ g_clear_error(&err);
+ }
+
+ gdbus_conn = local_system_gconn;
+ }
+
+ return gdbus_conn;
+}
+
+static gboolean __bt_hf_register_profile_methods(void)
+{
+ DBG("+");
+ GError *error = NULL;
+ guint object_id;
+ guint owner_id;
+ GDBusNodeInfo *node_info;
+ gchar *path;
+ GDBusConnection *conn;
+
+ owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
+ BT_HF_SERVICE_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL, NULL, NULL,
+ NULL, NULL);
+
+ DBG("owner_id is [%d]", owner_id);
+
+ node_info = __bt_hf_create_method_node_info(
+ hf_agent_bluez_introspection_xml);
+ if (node_info == NULL)
+ return FALSE;
+
+ path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
+ DBG("path is [%s]", path);
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return FALSE;
+ }
+
+ object_id = g_dbus_connection_register_object(conn, path,
+ node_info->interfaces[0],
+ &method_table,
+ NULL, NULL, &error);
+ if (object_id == 0) {
+ ERR("Failed to register: %s", error->message);
+ g_error_free(error);
+ g_dbus_node_info_unref(node_info);
+ g_free(path);
+ return FALSE;
+ }
+ g_free(path);
+ g_dbus_node_info_unref(node_info);
+
+ node_info = __bt_hf_create_method_node_info(hf_agent_introspection_xml);
+ if (node_info == NULL)
+ return FALSE;
+
+ path = g_strdup(BT_HF_AGENT_OBJECT_PATH);
+ DBG("path is [%s]", path);
+
+ object_id = g_dbus_connection_register_object(conn, path,
+ node_info->interfaces[0],
+ &method_table,
+ NULL, NULL, &error);
+ if (object_id == 0) {
+ ERR("Failed to register: %s", error->message);
+ g_error_free(error);
+ g_dbus_node_info_unref(node_info);
+ g_free(path);
+ return FALSE;
+ }
+ g_free(path);
+ g_dbus_node_info_unref(node_info);
+
+ DBG("-");
+ return TRUE;
+}
+
+static GDBusProxy *__bt_hf_gdbus_init_service_proxy(const gchar *service,
+ const gchar *path, const gchar *interface)
+{
+ DBG("+");
+
+ GDBusProxy *proxy;
+ GError *err = NULL;
+ GDBusConnection *conn;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return NULL;
+ }
+
+ proxy = g_dbus_proxy_new_sync(conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ service, path,
+ interface, NULL, &err);
+
+ if (!proxy) {
+ if (err) {
+ ERR("Unable to create proxy: %s", err->message);
+ g_clear_error(&err);
+ }
+ return NULL;
+ }
+
+ DBG("-");
+ return proxy;
+}
+
+static GDBusProxy *__bt_hf_gdbus_get_service_proxy(const gchar *service,
+ const gchar *path, const gchar *interface)
+{
+ return (service_gproxy) ? service_gproxy :
+ __bt_hf_gdbus_init_service_proxy(service,
+ path, interface);
+}
+
+static char __bt_hf_agent_get_tx_power(char *address)
+{
+ GVariant *ret;
+ GDBusProxy *proxy;
+ GError *error = NULL;
+ char result = READ_TX_POWER_MIN; /* default minimum */
+
+ proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME, g_obj_path,
+ BLUEZ_HF_INTERFACE_NAME);
+ if (!proxy) {
+ ERR("Proxy is NULL");
+ return result;
+ }
+
+ ret = g_dbus_proxy_call_sync(proxy,
+ "GetTxPowerLevel", g_variant_new("(s)", address),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ if (ret == NULL) {
+ ERR("DBus is failed");
+ if (error != NULL) {
+ /* Dbus gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ return result;
+ }
+ g_variant_get(ret, "(y)", &result);
+ DBG("TX power level = %d", result);
+ g_variant_unref(ret);
+ return result;
+}
+
+static int __bt_hf_agent_gdbus_method_send(const char *service,
+ GVariant *path, const char *interface,
+ const char *method)
+{
+ DBG("+");
+
+ GVariant *ret;
+ GDBusProxy *proxy;
+ GError *error = NULL;
+
+ proxy = __bt_hf_gdbus_get_service_proxy(service, g_obj_path, interface);
+ if (!proxy)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ ret = g_dbus_proxy_call_sync(proxy,
+ method, path,
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ if (ret == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("dBUS-RPC is failed");
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+
+ g_clear_error(&error);
+ }
+ return BT_HF_AGENT_ERROR_INTERNAL;
+ }
+
+ g_variant_unref(ret);
+
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+static void __bt_hf_agent_release_queue(void)
+{
+ int i, len;
+ bt_hf_agent_send_at_info *cmd;
+ GError *err;
+
+ len = g_slist_length(bt_hf_info.cmd_send_queue);
+ for (i = 0; i < len; ++i) {
+ cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
+ if (cmd && cmd->context) {
+ DBG("Pending context found for %.6s[%d]",
+ cmd->at_cmd, cmd->id);
+ err = __bt_hf_agent_set_error(BT_HF_AGENT_ERROR_INTERNAL);
+ g_dbus_method_invocation_return_gerror(cmd->context, err);
+ g_error_free(err);
+ }
+ if (cmd && cmd->timer_id)
+ g_source_remove(cmd->timer_id);
+ }
+ g_slist_free(bt_hf_info.cmd_send_queue);
+ bt_hf_info.cmd_send_queue = NULL;
+ send_flag = 0;
+}
+
+static gboolean __bt_hf_monitor_timer_cb(gpointer data)
+{
+ DBG("+");
+ bt_hf_agent_send_at_info *cmd = data;
+ ERR_C("Monitor timer came becuase of timeout for sendflag %d, %s",
+ send_flag, cmd->at_cmd);
+ /* In the case of ATD, we have to inform the remote to end the call */
+ if (strstr(cmd->at_cmd, "ATD") || strstr(cmd->at_cmd, "BLDN")) {
+ INFO_C("Sending CHUP for remote call termination");
+ __bt_hf_send_only_without_queue(&bt_hf_info, BT_HF_END_CALL,
+ strlen(BT_HF_END_CALL));
+ /* Here there is a high posisbility that we do not get response
+ * for CHUP. Hence we need to decrement send_flag to process further
+ * incomming packets because we already incremented it in the CHUP case. */
+ if (send_flag)
+ send_flag--;
+
+ /* In the case of ATD, prev_cmd will be always ATD, because we will not
+ * allow further commands. For safer side again set prev_cmd as ATD */
+ strcpy(prev_cmd, "ATD");
+ }
+ hf_handle_rx_at_cmd(&bt_hf_info, BT_HF_ERROR_RESP);
+
+ DBG("-");
+
+ return FALSE;
+}
+
+
+gboolean __bt_hf_agent_add_queue(GDBusMethodInvocation *context, char *at,
+ int count, gboolean pending_flag)
+{
+ int i, len;
+ if (bt_hf_info.slc == FALSE)
+ return FALSE;
+
+ if (pending_flag)
+ DBG("*** Add Pending queue request for = %s **** ", at);
+ else
+ DBG("Add Pending queue respnse for = %s ", at);
+
+ bt_hf_agent_send_at_info *cmd = g_new0(bt_hf_agent_send_at_info, 1);
+ cmd->id = ++g_id;
+ memcpy(cmd->at_cmd, at, count);
+ cmd->count = count;
+ cmd->context = context;
+ cmd->pending = pending_flag;
+ bt_hf_info.cmd_send_queue = g_slist_append(bt_hf_info.cmd_send_queue,
+ cmd);
+ len = g_slist_length(bt_hf_info.cmd_send_queue);
+ for (i = 0; i < len; ++i) {
+ cmd = g_slist_nth_data(bt_hf_info.cmd_send_queue, i);
+ DBG("Q> %.6s[%d]", cmd->at_cmd, cmd->id);
+ }
+
+ /* We need to have base timeout + tolerance value to process other request */
+ if (strstr(at, "ATD") || strstr(at, "BLDN")) {
+ /* Android 15 seconds timeout in case of ATD timeout in flight mode */
+ cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT * 5 + len,
+ __bt_hf_monitor_timer_cb, cmd);
+ } else {
+ cmd->timer_id = g_timeout_add_seconds(BT_HF_COMMAND_TIMEOUT + len,
+ __bt_hf_monitor_timer_cb, cmd);
+ }
+ return TRUE;
+}
+
+/*
+Below methods exposed to Applicatoins
+*/
+static gboolean __bt_hf_agent_emit_signal(GDBusConnection *connection,
+ const char *path, const char *interface,
+ const char *signal_name, GVariant *param)
+{
+ GError *error = NULL;
+ gboolean ret;
+ ret = g_dbus_connection_emit_signal(connection,
+ NULL, path,
+ interface, signal_name,
+ param, &error);
+ if (!ret) {
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ }
+ INFO_C("Emit Signal [%s]", signal_name);
+
+ return ret;
+}
+
+static gboolean __bt_hf_agent_emit_property_changed(
+ GDBusConnection *connection,
+ const char *path,
+ const char *interface,
+ const char *name,
+ GVariant *property)
+{
+ DBG("+");
+
+ GError *error = NULL;
+ gboolean ret;
+ ret = g_dbus_connection_emit_signal(connection,
+ NULL, path, interface,
+ "PropertyChanged",
+ g_variant_new("s(v)", name, property),
+ &error);
+ if (!ret) {
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ }
+ DBG("-");
+ return ret;
+}
+
+/*
+Below methods exposed to Bluez
+*/
+
+static void __bt_hf_agent_handle_ind_change(bt_hf_agent_info_t *bt_hf_info,
+ guint index, gint value)
+{
+ GDBusConnection *conn;
+ gchar *name;
+ struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
+ if (ind == NULL) {
+ ERR("Indicator is NULL");
+ return;
+ }
+
+ name = ind->descr;
+ ind->value = value;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return;
+ }
+
+ INFO("Indicator name is %s, value = [%d]", name, value);
+ if (!strcmp(name, "\"call\"")) {
+ bt_hf_info->ciev_call_status = value;
+ if (value > 0) {
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallStarted", NULL);
+ bt_hf_info->is_dialing = FALSE;
+ bt_hf_info->call_active = TRUE;
+ } else if (bt_hf_info->call_active) {
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallEnded", NULL);
+ bt_hf_info->call_active = FALSE;
+ }
+
+ } else if (!strcmp(name, "\"callsetup\"")) {
+ bt_hf_info->ciev_call_setup_status = value;
+ if (value == 0 && bt_hf_info->is_dialing) {
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallTerminated",
+ NULL);
+ bt_hf_info->is_dialing = FALSE;
+ } else if (!bt_hf_info->is_dialing && value > 0)
+ bt_hf_info->is_dialing = TRUE;
+
+ if (bt_hf_info->ciev_call_status == 0 &&
+ bt_hf_info->ciev_call_setup_status == 0)
+ __bt_hf_agent_emit_signal(gdbus_conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallEnded", NULL);
+
+ } else if (!strcmp(name, "\"callheld\"")) {
+ if (value == 0) { /* No calls held*/
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "NoCallsHeld",
+ NULL);
+ } else if (value == 1) {
+ /*Call is placed on hold or active/held calls swapped */
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallsSwapped", NULL);
+ bt_hf_info->is_dialing = FALSE;
+ } else {
+ /*Call on hold, no active call*/
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallOnHold", NULL);
+ bt_hf_info->is_dialing = FALSE;
+ }
+ } else if (!strcmp(name, "\"service\""))
+ __bt_hf_agent_emit_property_changed(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "RegistrationStatus",
+ g_variant_new("(q)", value));
+ else if (!strcmp(name, "\"signal\""))
+ __bt_hf_agent_emit_property_changed(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE, "SignalStrength",
+ g_variant_new("(q)", value));
+ else if (!strcmp(name, "\"roam\""))
+ __bt_hf_agent_emit_property_changed(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE, "RoamingStatus",
+ g_variant_new("(q)", value));
+ else if (!strcmp(name, "\"battchg\""))
+ __bt_hf_agent_emit_property_changed(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE, "BatteryCharge",
+ g_variant_new("(q)", value));
+}
+
+
+static gboolean __bt_hf_agent_launch_call_app(const char *launch_type,
+ const char *number)
+{
+ bundle *b;
+ bool is_running;
+
+ DBG("+");
+ app_manager_is_running(CALL_APP_ID, &is_running);
+ if (is_running)
+ return FALSE;
+
+ DBG_SECURE("Launch type = %s, number(%s)", launch_type, number);
+
+ b = bundle_create();
+ if (NULL == b) {
+ ERR("bundle_create() Failed");
+ return FALSE;
+ }
+
+ bundle_add(b, "launch-type", launch_type);
+
+ if (strlen(number) != 0)
+ bundle_add(b, "number", number);
+
+ bundle_add(b, "carrier-type", "BT");
+ DBG("For 3G, carrier-type: BT has been added");
+
+ aul_launch_app(CALL_APP_ID, b);
+ bundle_free(b);
+
+ DBG("-");
+
+ return TRUE;
+}
+
+static void __bt_hf_agent_handle_voice_activation(gint value)
+{
+ GDBusConnection *conn;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return;
+ }
+
+ __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "VoiceRecognition",
+ g_variant_new("(i)", value));
+
+ return;
+}
+
+static void __bt_hf_agent_handle_speaker_gain(gint value)
+{
+ GDBusConnection *conn;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return;
+ }
+
+ __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE, "VolumeSpeaker",
+ g_variant_new("(i)", value));
+
+ return;
+}
+
+static int __bt_hf_agent_handle_ccwa(bt_hf_agent_info_t *bt_hf_info,
+ const gchar *buf)
+{
+ GDBusConnection *conn;
+ gchar *ccwa;
+ gchar number[BT_HF_CALLER_NUM_SIZE];
+ gchar *sep;
+ char fmt_str[BT_HF_FMT_STR_SIZE];
+ int len = strlen(buf);
+
+ DBG("__bt_hf_agent_handle_ccwa +");
+ if (len > BT_HF_CALLER_NUM_SIZE + 10) {
+ ERR("buf len %d is too long", len);
+ return 1;
+ }
+
+ if ((ccwa = strstr(buf, "\r\n+CCWA"))) {
+ snprintf(fmt_str, sizeof(fmt_str), "\r\n+CCWA: \"%%%ds", sizeof(number) - 1);
+ if (sscanf(ccwa, fmt_str, number) == 1) {
+ sep = strchr(number, '"');
+ sep[0] = '\0';
+
+ ccwa = number;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return 1;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE, "CallWaiting",
+ g_variant_new("(s)", ccwa));
+ } else {
+ ERR_SECURE("CCWA '%s' is Call Wating", buf);
+ return 1;
+ }
+ }
+ DBG("__bt_hf_agent_handle_ccwa -");
+ return 0;
+}
+
+static GSList *__bt_hf_prepare_call_list(const char *buf) {
+ GSList *call_list = NULL;
+ char *str = NULL;
+ char *ptr = NULL;
+ char *temp = NULL;
+ char *sp;
+ char delim_sep[] = "\r\n";
+ char temp_buf[BT_HF_DATA_BUF_SIZE] = {0,};
+
+ hf_call_list_info_t *call_info;
+
+ DBG("+");
+ strncpy(temp_buf, buf, BT_HF_DATA_BUF_SIZE - 1);
+
+ str = strtok_r(temp_buf, delim_sep, &sp);
+ while (str != NULL) {
+ if (!(strstr(str, "+CLCC:"))) {
+ str = strtok_r(NULL, delim_sep, &sp);
+ continue;
+ }
+
+ call_info = g_new0(hf_call_list_info_t, 1);
+
+ sscanf(str, "+CLCC: %1d,%1d, %1d, %1d, %1d",
+ &call_info->idx, &call_info->dir,
+ &call_info->status, &call_info->mode,
+ &call_info->multi_party);
+ DBG("Index = [%d], Direction = [%d], Status = [%d], Mode = [%d], Multi_party = [%d]\n",
+ call_info->idx, call_info->dir, call_info->status,
+ call_info->mode, call_info->multi_party);
+
+ ptr = strstr(str, "\"");
+ if (ptr) {
+ temp = strstr(ptr + 1, "\"");
+ if (temp) {
+ *temp = '\0';
+ DBG_SECURE("\tPhone Number = [%s]\n", ptr + 1);
+ call_info->number = g_strdup(ptr + 1);
+
+ if (strstr(temp + 1, ",")) {
+ temp += 2;
+ DBG("\tType = [%s]\n", temp);
+ call_info->type = atoi(temp);
+ }
+ }
+ } else {
+ /*In case of no phone no. in CLCC respnse, we should launch call application
+ * with NULL string. By doing so "unknown" shall be displayed*/
+ DBG("Phone number does not exist\n");
+ call_info->number = g_strdup("");
+ }
+
+ call_list = g_slist_append(call_list, call_info);
+ str = strtok_r(NULL, delim_sep, &sp);
+ }
+ DBG("-");
+ return call_list;
+}
+
+static GSList *__bt_hf_get_call_list(bt_hf_agent_info_t *bt_hf_info)
+{
+ char buf[BT_HF_DATA_BUF_SIZE] = {0,};
+ GSList *call_list = NULL;
+
+ DBG("+");
+
+ /* Send CLCC when the callsetup */
+ __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLLIST, buf,
+ sizeof(BT_HF_CALLLIST) - 1);
+ DBG_SECURE("Receive CLCC response buffer = '%s'", buf);
+
+ call_list = __bt_hf_prepare_call_list(buf);
+ DBG("-");
+ return call_list;
+}
+
+static void __bt_hf_call_info_free(void *data)
+{
+ DBG("+");
+
+ hf_call_list_info_t *call_info = data;
+ g_free(call_info->number);
+ g_free(call_info);
+
+ DBG("-");
+}
+
+static void __bt_hf_free_call_list(GSList *call_list)
+{
+ DBG("+");
+
+ g_slist_free_full(call_list, __bt_hf_call_info_free);
+
+ DBG("-");
+}
+
+static void __bt_hf_launch_call_using_call_list(GSList *call_list,
+ bt_hf_agent_info_t *bt_hf_info)
+{
+ guint len;
+ const char *launch_type_str;
+ hf_call_list_info_t *call_info;
+
+ DBG("+");
+ if (call_list == NULL)
+ return;
+
+ len = g_slist_length(call_list);
+
+ while (len--) {
+ call_info = g_slist_nth_data(call_list, len);
+
+ /* Launch based on below conditions
+ * DC - Active call which is initiated from H
+ * MR - Alerting call which is initiated from H
+ * MT - Incoming call */
+ if (call_info->status == BT_HF_CALL_STAT_ACTIVE) {
+ launch_type_str = "DC";
+ } else {
+ if (call_info->dir == BT_HF_CALL_DIR_INCOMING)
+ launch_type_str = "MT";
+ else
+ launch_type_str = "MR";
+ }
+
+ if (__bt_hf_agent_launch_call_app(launch_type_str,
+ call_info->number) == FALSE)
+ DBG("call app launching failed");
+ }
+ DBG("-");
+}
+
+static GVariant *__bt_hf_agent_get_call_status_info(GSList *call_list)
+{
+ DBG("+");
+
+ int32_t call_count;
+ gchar *caller;
+ hf_call_list_info_t *call_info;
+
+ GVariantBuilder *builder;
+ GVariant *var_data;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a(siiii)"));
+
+ call_count = g_slist_length(call_list);
+ DBG("Total call count = '%d'", call_count);
+
+ while (call_count--) {
+ call_info = g_slist_nth_data(call_list, call_count);
+ INFO("Idx=%d, Dir=%d, status=%d, mode=%d, mparty=%d",
+ call_info->idx, call_info->dir, call_info->status,
+ call_info->mode, call_info->multi_party);
+ caller = call_info->number;
+
+ g_variant_builder_add(builder, "(siiii)",
+ caller, call_info->dir, call_info->status,
+ call_info->multi_party, call_info->idx);
+ }
+ var_data = g_variant_new("(ia(siiii))",
+ g_slist_length(call_list), builder);
+
+ g_variant_builder_unref(builder);
+ DBG("-");
+ return var_data;
+}
+
+static void __bt_hf_clear_prev_sent_cmd(void)
+{
+ if (prev_cmd[0] != 0)
+ ERR("No sent command");
+
+ memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
+
+ return;
+}
+
+static void __bt_hf_agent_send_call_status_info(GSList *call_list)
+{
+ GDBusConnection *conn;
+ GVariant *var_data;
+
+ var_data = __bt_hf_agent_get_call_status_info(call_list);
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return;
+ }
+
+ if (conn)
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallStatusUpdate",
+ var_data);
+}
+
+static void __bt_hf_agent_handle_call_list(bt_hf_agent_info_t *bt_hf_info)
+{
+ int ret;
+
+ __bt_hf_lock_display(0);
+
+ bt_hf_info->context = NULL;
+
+ /* Send CLCC. The response will be handled in the handler */
+ ret = __bt_hf_send_only(bt_hf_info, BT_HF_CALLLIST,
+ sizeof(BT_HF_CALLLIST) - 1);
+ if (!ret)
+ ERR("Failed to send CLCC");
+
+ __bt_hf_unlock_display();
+}
+
+static void __bt_hf_agent_request_call_list_info(bt_hf_agent_info_t *bt_hf_info,
+ guint index)
+{
+ char *name;
+ struct indicator *ind = g_slist_nth_data(bt_hf_info->indies, index - 1);
+ if (ind == NULL) {
+ ERR("Indicator is NULL");
+ return;
+ }
+ name = ind->descr;
+ DBG("name : %s", name);
+
+ if ((strcmp(name, "\"callsetup\"") != 0) &&
+ (strcmp(name, "\"call\"") != 0) &&
+ (strcmp(name, "\"callheld\"") != 0))
+ return;
+
+ __bt_hf_lock_display(0);
+
+ __bt_hf_agent_handle_call_list(bt_hf_info);
+
+ __bt_hf_unlock_display();
+
+}
+
+static gboolean __bt_hf_send_available_codec(bt_hf_agent_info_t *bt_hf_info, int send_only)
+{
+ gchar buf[BT_HF_DATA_BUF_SIZE];
+ gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
+ gboolean ret;
+
+ snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_AVAILABLE_CODEC,
+ BT_HF_CODEC_ID_CVSD, BT_HF_CODEC_ID_MSBC);
+ if (send_only) {
+ bt_hf_info->context = NULL;
+
+ ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
+ return TRUE;
+ } else {
+ ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
+ strlen(cmd_buf));
+ }
+ if (!ret || !strstr(buf, "OK"))
+ return FALSE;
+
+ return TRUE;
+}
+
+static int _hf_agent_codec_setup(const char *addr, guint codec_id)
+{
+ int ret;
+
+ if (!g_obj_path) {
+ ERR("g_obj_path is NULL\n");
+ return BT_HF_AGENT_ERROR_INTERNAL;
+ }
+
+ switch (codec_id) {
+ case BT_HF_CODEC_ID_CVSD:
+ INFO("Set NB parameters");
+ ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
+ g_variant_new("(ss)", "Handsfree", addr),
+ BT_ADAPTER_INTERFACE,
+ "SetNbParameters");
+ break;
+ case BT_HF_CODEC_ID_MSBC:
+ INFO("Set WBS parameters");
+ ret = __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
+ g_variant_new("(ss)", "Handsfree", addr),
+ BT_ADAPTER_INTERFACE,
+ "SetWbsParameters");
+ break;
+ default:
+ ret = BT_HF_AGENT_ERROR_INTERNAL;
+ ERR("Invalid Codec\n");
+ break;
+ }
+
+ if (ret)
+ ERR("Failed to setup the Codec\n");
+ else
+ current_codec_id = codec_id;
+
+ return ret;
+}
+
+static void __bt_hf_agent_handle_codec_select(bt_hf_agent_info_t *bt_hf_info,
+ guint codec_id)
+{
+ gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
+ gboolean ret;
+
+ if (codec_id != BT_HF_CODEC_ID_CVSD && codec_id != BT_HF_CODEC_ID_MSBC) {
+ INFO("Codec id doesn't match, so send available codec again");
+ ret = __bt_hf_send_available_codec(bt_hf_info, 1);
+ if (!ret)
+ ERR("Failed to send avalable codec");
+ return;
+ }
+
+ /* HF should be ready accpet SCO connection before sending theresponse for
+ "\r\n+BCS=>Codec ID\r\n", Keep the BT chip ready to recevie encoded SCO data */
+ ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, codec_id);
+
+ snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_CODEC_SELECT, codec_id);
+
+ bt_hf_info->context = NULL;
+
+ ret = __bt_hf_send_only(bt_hf_info, cmd_buf, strlen(cmd_buf));
+ if (!ret)
+ ERR("Failed to select the Codec");
+}
+
+void __bt_hf_agent_print_at_buffer(char *message, const char *buf)
+{
+
+ int i = 0;
+ char s[BT_HF_DATA_BUF_SIZE] = {0, };
+ gboolean hide = FALSE;
+
+ gboolean has_clcc = FALSE;
+ gboolean has_clip = FALSE;
+ gboolean has_ccwa = FALSE;
+ char *xsat_ptr;
+
+ strncpy(s, buf, BT_HF_DATA_BUF_SIZE - 1);
+
+ has_clcc = strstr(buf, "CLCC:") ? TRUE : FALSE;
+ if (has_clcc == TRUE)
+ goto done;
+ has_clip = strstr(buf, "+CLIP:") ? TRUE : FALSE;
+ if (has_clip == TRUE)
+ goto done;
+ has_ccwa = strstr(buf, "+CCWA:") ? TRUE : FALSE;
+
+done:
+ /* +XSAT: 11,DISC */
+ xsat_ptr = strstr(s, "11,DISC,");
+ if (xsat_ptr) {
+ xsat_ptr = xsat_ptr + 8;
+ int x = 0;
+ while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
+ xsat_ptr[x] = 'X';
+ x++;
+ }
+ }
+
+ /* AT+XSAT=11,Q_CT,X,XXXX */
+ xsat_ptr = strstr(s, "11,Q_CT,");
+ if (xsat_ptr) {
+ xsat_ptr = xsat_ptr + 8;
+ int x = 0;
+ while (xsat_ptr[x] != '\0' && xsat_ptr[x] != '\r' && xsat_ptr[x] != '\n') {
+ if (x > 1) /* ignore 0 and 1 position */
+ xsat_ptr[x] = 'X';
+ x++;
+ }
+ }
+
+ i = 0;
+ while (s[i] != '\0') {
+ if (s[i] == '\r' || s[i] == '\n') {
+ s[i] = '.';
+ } else {
+ if (s[i] == '\"')
+ hide = hide ? FALSE : TRUE;
+ else if ((has_clcc || has_clip || has_ccwa) && hide) {
+ if (i % 2)
+ s[i] = 'X';
+ }
+ }
+ i++;
+ }
+ if (message)
+ INFO("%s Buffer = %s, Length = %d ", message, s, strlen(s));
+ else
+ INFO("%s", s);
+}
+
+static int __bt_hf_agent_handler_ciev(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ gchar indicator[BT_HF_INDICATOR_DESCR_SIZE + 4];
+ gchar *sep;
+ gint value;
+ guint index;
+ char fmt_str[BT_HF_FMT_STR_SIZE];
+
+ DBG("++++++++ __bt_hf_agent_handler_ciev +++++++++");
+
+ snprintf(fmt_str, sizeof(fmt_str), "\r\n+CIEV:%%%ds\r\n", sizeof(indicator) - 1);
+ if (sscanf(buf, fmt_str, indicator) == 1) {
+ sep = strchr(indicator, ',');
+ sep[0] = '\0';
+ sep += 1;
+ index = atoi(indicator);
+ value = atoi(sep);
+ __bt_hf_agent_handle_ind_change(bt_hf_info, index, value);
+
+ if (bt_hf_info->ciev_call_status == 0 &&
+ bt_hf_info->ciev_call_setup_status == 0)
+ INFO("No active call");
+ else
+ /* Request CLCC based on indicator change for call/callsetup/callHeld */
+ __bt_hf_agent_request_call_list_info(bt_hf_info, index);
+ }
+ DBG("--------- __bt_hf_agent_handler_ciev ------------");
+ return 0;
+}
+
+static void __bt_hf_agent_handle_ven_samsung(bt_hf_agent_info_t *bt_hf_info,
+ gint app_id, const char *msg)
+{
+ /* Whomesoever wants need to handle it */
+ char *sig_name = "SamsungXSAT";
+ GDBusConnection *conn;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ sig_name,
+ g_variant_new("(is)", app_id, msg));
+}
+
+static int __bt_hf_agent_handler_ring(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ DBG("++++++++ __bt_hf_agent_handler_ring ++++++++");
+ DBG("---------__bt_hf_agent_handler_ring --------");
+
+ return 0;
+}
+
+static int __bt_hf_agent_handler_clip(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ DBG("+++++++++ __bt_hf_agent_handler_clip ++++++++");
+ DBG("---------__bt_hf_agent_handler_clip --------");
+
+ return 0;
+}
+
+static int __bt_hf_agent_handler_bvra(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ DBG("+++++++++ __bt_hf_agent_handler_bvra +++++++++");
+ gint value;
+ if (sscanf(buf, "\r\n+BVRA:%1d\r\n", &value) == 1)
+ __bt_hf_agent_handle_voice_activation(value);
+
+ DBG("---------__bt_hf_agent_handler_bvra --------");
+ return 0;
+}
+
+static int __bt_hf_agent_handler_bcs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ guint codec_id;
+ DBG("+++++++++ __bt_hf_agent_handler_bcs +++++++++-");
+ if (sscanf(buf, "\r\n+BCS:%3d\r\n", &codec_id))
+ __bt_hf_agent_handle_codec_select(bt_hf_info, codec_id);
+
+ DBG("---------__bt_hf_agent_handler_bcs --------");
+ return 0;
+}
+
+static int __bt_hf_agent_handler_vgs(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ gint value;
+ DBG("+++++++++ __bt_hf_agent_handler_vgs +++++++++");
+ if (sscanf(buf, "\r\n+VGS:%2d\r\n", &value))
+ __bt_hf_agent_handle_speaker_gain(value);
+
+ DBG("---------__bt_hf_agent_handler_vgs --------");
+
+ return 0;
+}
+
+static int __bt_hf_agent_handler_ccwa(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ DBG("+++++++++ __bt_hf_agent_handler_ccwa ++++++++");
+ __bt_hf_agent_handle_ccwa(bt_hf_info, buf);
+ DBG("---------__bt_hf_agent_handler_ccwa --------");
+
+ return 0;
+}
+
+
+static int __bt_hf_agent_handler_xsat(bt_hf_agent_info_t *bt_hf_info,
+ const char *buf)
+{
+ gint app_id;
+ char msg[BT_HF_DATA_BUF_SIZE];
+ char fmt_str[BT_HF_CMD_BUF_SIZE];
+
+ DBG("+++++++++ __bt_hf_agent_handler_xsat +++++++++");
+ snprintf(fmt_str, sizeof(fmt_str), "\r\n+XSAT:%%d,%%%ds\r\n", sizeof(msg) - 1);
+ if (sscanf(buf, fmt_str, &app_id, msg)) {
+ if (app_id == 2 && strstr(msg, "READTXPOWER")) {
+ char cmd_buf[BT_HF_CMD_BUF_SIZE * 2] = {0, };
+ char power = __bt_hf_agent_get_tx_power(bt_hf_info->remote_addr);
+ snprintf(cmd_buf, sizeof(cmd_buf), "AT+XSAT: 2,%d", power);
+ bt_hf_agent_send_at_cmd(NULL, cmd_buf);
+ } else {
+ __bt_hf_agent_handle_ven_samsung(bt_hf_info, app_id, msg);
+ }
+ }
+
+ DBG("---------__bt_hf_agent_handler_xsat --------");
+
+ return 0;
+}
+
+static int __bt_hf_agent_handler_cme_error(bt_hf_agent_info_t *bt_hf_info,
+ const char *buf)
+{
+ DBG("+++++++++ __bt_hf_agent_handler_cme_error ++++++++");
+
+ GDBusConnection *conn;
+
+ if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return 0;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallTerminated",
+ NULL);
+ }
+
+ __bt_hf_clear_prev_sent_cmd();
+
+ return 0;
+}
+
+static int __bt_hf_agent_handler_response_ok(bt_hf_agent_info_t *bt_hf_info,
+ const char *buf)
+{
+ DBG("+++++++++ __bt_hf_agent_handler_response_ok ++++++++");
+
+ __bt_hf_clear_prev_sent_cmd();
+
+ return 0;
+}
+
+static int __bt_hf_agent_handler_response_err(bt_hf_agent_info_t *bt_hf_info,
+ const char *buf)
+{
+ DBG("+++++++++ __bt_hf_agent_handler_response_err ++++++++");
+ GDBusConnection *conn;
+
+ if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return 0;
+ }
+
+ __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallTerminated",
+ NULL);
+ }
+ __bt_hf_clear_prev_sent_cmd();
+
+ return 0;
+}
+
+static int __bt_hf_agent_handler_response_serr(bt_hf_agent_info_t *bt_hf_info,
+ const char *buf)
+{
+ DBG("+");
+ GDBusConnection *conn;
+
+ if (strstr(prev_cmd, "ATD") || strstr(prev_cmd, BT_HF_REDIAL)) {
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return 0;
+ }
+
+ __bt_hf_agent_emit_signal(conn, BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallTerminated",
+ NULL);
+ }
+
+ __bt_hf_clear_prev_sent_cmd();
+
+ DBG("-");
+ return 0;
+}
+
+static int __bt_hf_agent_handler_clcc(bt_hf_agent_info_t *bt_hf_info, const char *buffer)
+{
+
+ GSList *call_list = NULL;
+ DBG("+++++++++ __bt_hf_agent_handler_clcc ++++++++");
+ DBG_SECURE("Receive CLCC response buffer = '%s'", buffer);
+
+ __bt_hf_lock_display(0);
+
+ call_list = __bt_hf_prepare_call_list(buffer);
+
+ if (call_list == NULL)
+ goto done;
+
+ __bt_hf_launch_call_using_call_list(call_list, bt_hf_info);
+
+ __bt_hf_agent_send_call_status_info(call_list);
+
+ __bt_hf_free_call_list(call_list);
+
+done:
+ __bt_hf_unlock_display();
+ DBG("---------__bt_hf_agent_handler_clcc --------");
+ return 0;
+}
+
+static struct hf_event hf_event_callbacks[] = {
+ { "\r\n+CIEV:", __bt_hf_agent_handler_ciev },
+ { "\r\nRING", __bt_hf_agent_handler_ring },
+ { "\r\n+CLIP:", __bt_hf_agent_handler_clip },
+ { "\r\n+BVRA:", __bt_hf_agent_handler_bvra },
+ { "\r\n+BCS:", __bt_hf_agent_handler_bcs },
+ { "\r\n+VGS:", __bt_hf_agent_handler_vgs },
+ { "\r\n+CCWA:", __bt_hf_agent_handler_ccwa },
+ { "\r\n+XSAT:", __bt_hf_agent_handler_xsat },
+ {"\r\n+CLCC:", __bt_hf_agent_handler_clcc },
+ { 0 }
+};
+
+static struct hf_event hf_event_resp_callbacks[] = {
+ { "\r\n+CME ERROR:", __bt_hf_agent_handler_cme_error },
+ { "\r\nOK\r\n", __bt_hf_agent_handler_response_ok },
+ { "ERROR", __bt_hf_agent_handler_response_err },
+ { "SERR", __bt_hf_agent_handler_response_serr },
+ { 0 }
+};
+
+bt_hf_agent_send_at_info *__bt_hf_agent_find_next(bt_hf_agent_info_t *bt_hf_info)
+{
+ int len;
+ int i;
+ bt_hf_agent_send_at_info *cmd;
+ len = g_slist_length(bt_hf_info->cmd_send_queue);
+ for (i = 0; i < len; ++i) {
+ cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, i);
+ DBG("F> %.6s[%d]", cmd->at_cmd, cmd->id);
+ }
+ len = g_slist_length(bt_hf_info->cmd_send_queue);
+ DBG("Context queue length = %d", len);
+ if (len == 0)
+ return NULL;
+
+ cmd = g_slist_nth_data(bt_hf_info->cmd_send_queue, 0);
+ if (cmd) {
+ bt_hf_info->cmd_send_queue = g_slist_remove(bt_hf_info->cmd_send_queue, cmd);
+ DBG("NEXT[%d] Found %s, context = 0x%x, pending = %d", cmd->id,
+ cmd->at_cmd, cmd->context, cmd->pending);
+ return cmd;
+ }
+
+ DBG("**** Not found any pending command on list length %d ****", len);
+
+ return NULL;
+}
+
+static int hf_handle_rx_at_cmd(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ struct hf_event *ev;
+ int ret = -EINVAL;
+ bt_hf_agent_send_at_info *cmd = NULL;
+
+ __bt_hf_agent_print_at_buffer("Processing [Rx cmd]:", buf);
+
+ for (ev = hf_event_resp_callbacks; ev->cmd; ev++) {
+ if (strstr(buf, ev->cmd)) {
+ if (send_flag)
+ send_flag--;
+ DBG("Send flag value = %d(after)", send_flag);
+ ret = ev->callback(bt_hf_info, buf);
+ }
+ }
+
+ if (ret != -EINVAL)
+ goto done;
+
+ for (ev = hf_event_callbacks; ev->cmd; ev++) {
+ if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) {
+ ret = ev->callback(bt_hf_info, buf);
+ break;
+ }
+ }
+
+ return ret;
+done:
+
+ cmd = __bt_hf_agent_find_next(bt_hf_info);
+
+ if (cmd && cmd->context) {
+ DBG("Pending context found for %.6s[%d]", cmd->at_cmd, cmd->id);
+ g_dbus_method_invocation_return_value(cmd->context, NULL);
+ if (cmd->timer_id)
+ g_source_remove(cmd->timer_id);
+ g_free(cmd);
+ cmd = NULL;
+ }
+
+ if (cmd == NULL)
+ cmd = __bt_hf_agent_find_next(bt_hf_info);
+
+ if (cmd && cmd->pending && send_flag == 0) {
+ DBG("Pending only found of %.6s[%d]", cmd->at_cmd, cmd->id);
+ __bt_hf_send_only_without_queue(bt_hf_info,
+ cmd->at_cmd, cmd->count);
+ cmd->pending = FALSE;
+ bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
+ cmd);
+ DBG("Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
+ } else {
+ if (cmd) {
+ DBG("Pending free for %.6s[%d] - send_flag = %d",
+ cmd->at_cmd, cmd->id, send_flag);
+ if (cmd->timer_id)
+ g_source_remove(cmd->timer_id);
+ g_free(cmd);
+ }
+
+
+
+ /* Need to process further pending */
+ cmd = __bt_hf_agent_find_next(bt_hf_info);
+ if (cmd) {
+ if (cmd->pending && send_flag == 0) {
+ DBG("2nd Pending only found of %.6s[%d]",
+ cmd->at_cmd, cmd->id);
+ __bt_hf_send_only_without_queue(bt_hf_info,
+ cmd->at_cmd, cmd->count);
+ cmd->pending = FALSE;
+ }
+ bt_hf_info->cmd_send_queue = g_slist_prepend(bt_hf_info->cmd_send_queue,
+ cmd);
+ DBG("2nd Prepend %.6s[%d]", cmd->at_cmd, cmd->id);
+ }
+ }
+ return ret;
+}
+
+static int hf_handle_append_clcc_buff(char *cmd_buf, const char *buf)
+{
+ int buf_length;
+ int cmd_length = 0;
+ int cmd_buf_len = 0;
+ char *pos_start, *pos_end;
+ const char *datap = buf;
+
+ cmd_buf_len = strlen(cmd_buf);
+ buf_length = strlen(buf);
+ DBG("buf_length = %d, cmd_buf_len = %d", buf_length, cmd_buf_len);
+
+ if (buf_length > 0 && strstr(datap, "+CLCC")) {
+ pos_start = strstr(datap, "\r\n");
+ if (pos_start == NULL) {
+ ERR("Invalid AT command signature..\n");
+ return 0;
+ }
+
+ pos_end = g_strrstr(datap, "+CLCC");
+ if (pos_end == NULL) {
+ ERR("Invalid AT command signature..\n");
+ return 0;
+ }
+ pos_end = strstr(pos_end, "\r\n");
+ cmd_length = (pos_end - pos_start) + 2;
+ INFO("CLCC balance Cmd Length = %d\n", cmd_length);
+ memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
+ cmd_buf[cmd_buf_len + cmd_length] = '\0';
+
+ if (strstr(cmd_buf, "\r\nOK\r\n")) {
+ pos_end = strstr(datap, "\r\nOK\r\n");
+ cmd_length = (pos_end - pos_start);
+ memcpy(cmd_buf + cmd_buf_len, pos_start, cmd_length);
+ cmd_buf[cmd_buf_len + cmd_length] = '\0';
+ INFO("New CLCC balance Cmd Length = %d", cmd_length);
+ }
+ }
+ return cmd_length;
+}
+
+
+static int hf_handle_rx_at_buff(bt_hf_agent_info_t *bt_hf_info, const char *buf)
+{
+ int buf_length;
+ int cmd_length;
+ char *pos_start, *pos_end;
+ int tmp;
+ gchar cmd_buf[BT_HF_DATA_BUF_SIZE] = {0,};
+ const char *datap = buf;
+
+ __bt_hf_agent_print_at_buffer("[HF AT CMD] Recv >>>>>:", buf);
+
+ buf_length = strlen(buf);
+
+ while (buf_length > 0) {
+ pos_start = strstr(datap, "\r\n");
+ if (pos_start == NULL) {
+ ERR("Invalid AT command start signature..\n");
+ break;
+ }
+
+ datap += 2;
+ pos_end = strstr(datap, "\r\n");
+ if (pos_end == NULL) {
+ ERR("Invalid AT command end signature..\n");
+ break;
+ }
+ cmd_length = (pos_end - pos_start) + 2;
+ DBG("Cmd Length = %d\n", cmd_length);
+
+ memcpy(cmd_buf, pos_start, cmd_length);
+ cmd_buf[cmd_length] = '\0';
+
+ buf_length = buf_length - cmd_length;
+ datap = datap + cmd_length - 2;
+
+ /* We need to pass all the CLCC's together to its handler */
+ if (strstr(cmd_buf, "+CLCC")) {
+ tmp = hf_handle_append_clcc_buff(cmd_buf, datap);
+ datap += tmp;
+ buf_length = buf_length - tmp;
+ }
+ hf_handle_rx_at_cmd(bt_hf_info, cmd_buf);
+ DBG("Pending buf_length = %d\n", buf_length);
+ }
+ return TRUE;
+
+}
+static gboolean __bt_hf_agent_data_cb(GIOChannel *chan, GIOCondition cond,
+ bt_hf_agent_info_t *bt_hf_info)
+{
+ gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
+ gsize read;
+ GError *gerr = NULL;
+ gboolean recvd_ok = FALSE;
+ gboolean recvd_error = FALSE;
+ gboolean recvd_sec_error = FALSE;
+
+ if (cond & (G_IO_ERR | G_IO_HUP)) {
+ ERR("ERR or HUP on RFCOMM socket");
+ INFO_C("Disconnected [HF role] [Terminated by remote dev]");
+ is_hf_connected = FALSE;
+ bt_hf_info->slc = FALSE;
+ __bt_hf_agent_release();
+ return FALSE;
+ }
+
+ if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, &gerr)
+ != G_IO_STATUS_NORMAL) {
+ if (gerr) {
+ ERR("Read failed, cond = [%d], Err msg = [%s]",
+ cond, gerr->message);
+ g_error_free(gerr);
+ }
+ return TRUE;
+ }
+ buf[read] = '\0';
+ recvd_ok = NULL != strstr(buf, BT_HF_OK_RESPONSE);
+ recvd_error = NULL != strstr(buf, BT_HF_ERROR_RESPONSE);
+ recvd_sec_error = NULL != strstr(buf, BT_HF_SEC_ERROR_RESPONSE);
+ DBG("<-------Received data --send flag status = %d ----->", send_flag);
+
+ /* Once service level connection is established we need to handle
+ * all the intermediate AT commands */
+ if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
+ return TRUE;
+
+ if (send_flag) {
+ strncat(global_buff, buf,
+ (BT_AT_COMMAND_BUFFER_MAX - 1) - strlen(global_buff));
+ if (!(recvd_ok || recvd_error || recvd_sec_error)) {
+ __bt_hf_agent_print_at_buffer("Concat ()", global_buff);
+ } else {
+ DBG("*** Received terminator.. process Rx buffer ***");
+ hf_handle_rx_at_buff(bt_hf_info, global_buff);
+ memset(global_buff, 0, sizeof(global_buff));
+ }
+ } else {
+ INFO("*** Received Direct AT buffer packet handling ****");
+ hf_handle_rx_at_buff(bt_hf_info, buf);
+ }
+ return TRUE;
+}
+
+static void __bt_hf_agent_start_watch(bt_hf_agent_info_t *bt_hf_info)
+{
+ bt_hf_info->watch_id = g_io_add_watch(bt_hf_info->io_chan,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) __bt_hf_agent_data_cb, bt_hf_info);
+}
+
+static void __bt_hf_agent_stop_watch(bt_hf_agent_info_t *bt_hf_info)
+{
+ if (bt_hf_info->watch_id > 0) {
+ g_source_remove(bt_hf_info->watch_id);
+ bt_hf_info->watch_id = 0;
+ }
+}
+
+static gboolean __bt_hf_channel_write(GIOChannel *io, gchar *data,
+ gsize count)
+{
+ gsize written = 0;
+ GIOStatus status;
+
+ while (count > 0) {
+ status = g_io_channel_write_chars(io, data, count, &written,
+ NULL);
+ if (status != G_IO_STATUS_NORMAL)
+ return FALSE;
+
+ data += written;
+ count -= written;
+ }
+ return TRUE;
+}
+
+static gboolean __bt_hf_send_only_without_queue(bt_hf_agent_info_t *bt_hf_info,
+ gchar *data, gsize count)
+{
+ GIOChannel *io_chan = bt_hf_info->io_chan;
+ if (!__bt_hf_channel_write(io_chan, data, count))
+ return FALSE;
+
+ g_io_channel_flush(io_chan, NULL);
+
+ if (count > 2 && data[2] == 'D') { /* ATDXXXXX */
+ INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
+ count, count - 6, "ATDXXXXXXX");
+ snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", data);
+ } else {
+ INFO("No queue....Send only buffer size =[%d] - Send <<<<<| %s",
+ count, data);
+ }
+
+ send_flag++;
+ /* DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
+ * send_flag, count, data); */
+ return TRUE;
+
+}
+
+static gboolean __bt_hf_send_only(bt_hf_agent_info_t *bt_hf_info, gchar *data,
+ gsize count)
+{
+ gboolean pending = FALSE;
+ GIOChannel *io_chan = bt_hf_info->io_chan;
+
+ if (send_flag) {
+ pending = TRUE;
+ }
+ __bt_hf_agent_add_queue(bt_hf_info->context, data, count, pending);
+
+ if (pending)
+ return TRUE;
+
+ if (!__bt_hf_channel_write(io_chan, data, count))
+ return FALSE;
+
+ g_io_channel_flush(io_chan, NULL);
+
+ if (count > 2 && data[2] == 'D') /* ATDXXXXX */
+ INFO("Send only buffer size =[%d] No len = %d - Send <<<<<| %s",
+ count, count - 6, "ATDXXXXXXX");
+ else
+ INFO("Send only buffer size =[%d] - Send <<<<<| %s", count, data);
+
+ send_flag++;
+ DBG("Ref %d(after) on Send only buffer size =[%d] - Send <<<<<| %s",
+ send_flag, count, data);
+ return TRUE;
+}
+
+static gboolean __bt_hf_send_and_read(bt_hf_agent_info_t *bt_hf_info,
+ gchar *data, gchar *response, gsize count)
+{
+ GIOChannel *io_chan = bt_hf_info->io_chan;
+ gsize rd_size = 0;
+ gboolean recvd_ok = FALSE;
+ gboolean recvd_error = FALSE;
+ gboolean recvd_sec_error = FALSE;
+ gchar *resp_buf = response;
+ gsize toread = BT_HF_DATA_BUF_SIZE - 1;
+ int i = 0;
+ int fd;
+ int err;
+ struct pollfd p;
+ GDBusConnection *conn;
+
+ /* Should not send cmds if DUT send a command and wait the response */
+ if (prev_cmd[0] != 0) {
+ INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
+ return FALSE;
+ }
+
+ memset(resp_buf, 0, BT_HF_DATA_BUF_SIZE);
+
+ if (!__bt_hf_channel_write(io_chan, data, count))
+ return FALSE;
+
+ g_io_channel_flush(io_chan, NULL);
+
+ __bt_hf_agent_print_at_buffer("[HF AT CMD] Send <<<<<:", data);
+
+ fd = g_io_channel_unix_get_fd(io_chan);
+ p.fd = fd;
+ p.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
+
+ /* Maximun 8 seconds of poll or 8 minus no of cmd received */
+ for (i = 1; i <= MAX_WAITING_DELAY; i++) {
+ DBG("Loop Counter = %d", i);
+ p.revents = 0;
+ err = poll(&p, 1, 1000);
+ if (err < 0) {
+ ERR("Loop Counter = %d, >>>> Poll error happen", i);
+ return FALSE;
+ } else if (err == 0) {
+ INFO("Loop Counter = %d, >>>> Poll Timeout", i);
+ }
+
+ if (p.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ ERR("Loop Counter = %d, >> Poll ERR/HUP/INV (%d)",
+ i, p.revents);
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return FALSE;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "Disconnected",
+ g_variant_new("(s)",
+ bt_hf_info->remote_addr));
+
+ bt_hf_info->state = BT_HF_STATE_DISCONNECTED;
+ return FALSE;
+ }
+
+ if (p.revents & POLLIN) {
+ rd_size = read(fd, resp_buf, toread);
+ resp_buf[rd_size] = '\0';
+ DBG_SECURE("size = %d, Buffer=[%s]", rd_size, resp_buf);
+ recvd_ok = NULL != strstr(resp_buf, BT_HF_OK_RESPONSE);
+ recvd_error = NULL != strstr(resp_buf, BT_HF_ERROR_RESPONSE);
+ recvd_sec_error = NULL != strstr(resp_buf, BT_HF_SEC_ERROR_RESPONSE);
+
+ resp_buf += rd_size;
+ toread -= rd_size;
+
+ if (recvd_ok || recvd_error || recvd_sec_error) {
+ DBG("Break Loop Counter = %d", i);
+ break;
+ }
+ }
+ }
+
+ /* Once service level connection is established we need to handle
+ * all the intermediate AT commands */
+ if (bt_hf_info->state == BT_HF_STATE_CONNECTED)
+ hf_handle_rx_at_buff(bt_hf_info, response);
+ return TRUE;
+}
+
+static GSList *__bt_hf_parse_indicator_names(gchar *names, GSList *indices)
+{
+ struct indicator *ind;
+ gchar *cur = names - 1;
+ GSList *list = indices;
+ gchar *next;
+
+ DBG("Indicator buffer = %s", names);
+ __bt_hf_agent_print_at_buffer("Indicator names :", names);
+ while (cur != NULL) {
+ cur += 2;
+ next = strstr(cur, ",(");
+ ind = g_new0(struct indicator, 1);
+ g_strlcpy(ind->descr, cur, BT_HF_INDICATOR_DESCR_SIZE);
+ ind->descr[(intptr_t) next - (intptr_t) cur] = '\0';
+ list = g_slist_append(list, (gpointer) ind);
+ cur = strstr(next + 1, ",(");
+ }
+ return list;
+}
+
+static GSList *__bt_hf_parse_indicator_values(gchar *values, GSList *indices)
+{
+ gint val;
+ struct indicator *ind;
+ GSList *runner = indices;
+
+ gchar *cur = values - 1;
+ DBG("Indicator string = %s", values);
+ __bt_hf_agent_print_at_buffer("Indicator values :", values);
+ while (cur != NULL) {
+ cur += 1;
+ sscanf(cur, "%1d", &val);
+ cur = strchr(cur, ',');
+ ind = g_slist_nth_data(runner, 0);
+ ind->value = val;
+ runner = g_slist_next(runner);
+ }
+ return indices;
+}
+
+static guint __bt_hf_get_hold_mpty_features(gchar *features)
+{
+ guint result = 0;
+
+ if (strstr(features, "0"))
+ result |= BT_HF_CHLD_0;
+
+ if (strstr(features, "1"))
+ result |= BT_HF_CHLD_1;
+
+ if (strstr(features, "1x"))
+ result |= BT_HF_CHLD_1x;
+
+ if (strstr(features, "2"))
+ result |= BT_HF_CHLD_2;
+
+ if (strstr(features, "2x"))
+ result |= BT_HF_CHLD_2x;
+
+ if (strstr(features, "3"))
+ result |= BT_HF_CHLD_3;
+
+ if (strstr(features, "4"))
+ result |= BT_HF_CHLD_4;
+
+ return result;
+}
+
+static gboolean __bt_hf_agent_sco_conn_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+{
+ bt_hf_agent_info_t *bt_hf_info = user_data;
+ GDBusConnection *conn;
+
+ DBG("");
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ close(bt_hf_info->cli_sco_fd);
+ g_io_channel_unref(chan);
+ DBG("Emit AudioDisconnected Signal");
+
+ sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return FALSE;
+ }
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "AudioDisconnected", NULL);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean __bt_agent_query_and_update_call_list(gpointer data)
+{
+ DBG("+");
+ bt_hf_agent_info_t *bt_hf_info = data;
+
+ if (bt_hf_info->cli_sco_fd >= 0)
+ __bt_hf_agent_handle_call_list(bt_hf_info);
+ else
+ INFO("SCO Audio is already disconnected");
+
+ DBG("-");
+
+ return FALSE;
+}
+
+static gboolean __bt_hf_agent_sco_accept_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+{
+ bt_hf_agent_info_t *bt_hf_info = user_data;
+ int sco_skt;
+ int cli_sco_sock;
+ GIOChannel *sco_io;
+ GDBusConnection *conn;
+
+ INFO("Incoming SCO....");
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ sco_skt = g_io_channel_unix_get_fd(chan);
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ close(sco_skt);
+ return FALSE;
+ }
+
+ cli_sco_sock = accept(sco_skt, NULL, NULL);
+ if (cli_sco_sock < 0)
+ return FALSE;
+
+ bt_hf_info->cli_sco_fd = cli_sco_sock;
+
+ sco_io = g_io_channel_unix_new(cli_sco_sock);
+ g_io_channel_set_close_on_unref(sco_io, TRUE);
+ g_io_channel_set_encoding(sco_io, NULL, NULL);
+ g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_buffered(sco_io, FALSE);
+
+ g_io_add_watch(sco_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ __bt_hf_agent_sco_conn_cb, bt_hf_info);
+
+ /* S-Voice app requires the AudioConnected signal earlier */
+ DBG("Emit AudioConnected Signal");
+
+ sco_audio_connected = BT_HF_AUDIO_CONNECTED;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return FALSE;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "AudioConnected", NULL);
+
+ /* In the case of incoming call, the call app is already launched,
+ * hence AudioConnected signal is enough to update the call status.
+ * In the case of outgoing call we need to lauch the callapp.
+ */
+
+ g_idle_add(__bt_agent_query_and_update_call_list, bt_hf_info);
+
+ return TRUE;
+}
+
+void _bt_convert_addr_string_to_type_rev(unsigned char *addr,
+ const char *address)
+{
+ int i;
+ char *ptr = NULL;
+
+ ret_if(address == NULL);
+ ret_if(addr == NULL);
+
+ for (i = 0; i < 6; i++) {
+ addr[5 - i] = strtol(address, &ptr, 16);
+ if (ptr[0] != '\0') {
+ if (ptr[0] != ':')
+ return;
+
+ address = ptr + 1;
+ }
+ }
+}
+
+static gboolean __bt_hf_agent_sco_accept(bt_hf_agent_info_t *bt_hf_info)
+{
+ struct sockaddr_sco addr;
+ GIOChannel *sco_io;
+ bdaddr_t bd_addr = {{0},};
+ int sco_skt;
+
+ if (bt_hf_info->state != BT_HF_STATE_CONNECTED)
+ return FALSE;
+
+ /* Create socket */
+ sco_skt = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sco_skt < 0) {
+ ERR("Can't create socket:\n");
+ return FALSE;
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+
+ DBG("Bind to address %s", bt_hf_info->remote_addr);
+
+ _bt_convert_addr_string_to_type_rev(bd_addr.b, bt_hf_info->remote_addr);
+ memcpy(&addr.sco_bdaddr, &bd_addr, sizeof(bdaddr_t));
+
+ if (bind(sco_skt, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERR("Can't bind socket:\n");
+ goto error;
+ }
+
+ if (listen(sco_skt, 1)) {
+ ERR("Can not listen on the socket:\n");
+ goto error;
+ }
+
+ sco_io = g_io_channel_unix_new(sco_skt);
+ g_io_channel_set_close_on_unref(sco_io, TRUE);
+ g_io_channel_set_encoding(sco_io, NULL, NULL);
+ g_io_channel_set_flags(sco_io, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_buffered(sco_io, FALSE);
+
+ bt_hf_info->sco_fd = sco_skt;
+ bt_hf_info->sco_io_chan = sco_io;
+
+ bt_hf_info->sco_watch_id = g_io_add_watch(sco_io,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, __bt_hf_agent_sco_accept_cb, bt_hf_info);
+
+ g_io_channel_unref(sco_io);
+
+ return TRUE;
+
+error:
+ close(sco_skt);
+ return FALSE;
+}
+
+static gboolean __bt_get_supported_indicators(bt_hf_agent_info_t *bt_hf_info)
+{
+ gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
+ gboolean ret;
+
+ ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_SUPP, buf,
+ sizeof(BT_HF_INDICATORS_SUPP) - 1);
+ if (!ret || !strstr(buf, "+CIND:"))
+ return FALSE;
+
+ bt_hf_info->indies = __bt_hf_parse_indicator_names(strchr(buf, '('), NULL);
+
+ return TRUE;
+}
+
+static gboolean __bt_get_bia_cmd(bt_hf_agent_info_t *bt_hf_info, gchar *cmd, gsize cmd_size)
+{
+ GSList *l;
+ gsize ret;
+
+ if (bt_hf_info == NULL || cmd == NULL) {
+ ERR("Invalid parameter");
+ return FALSE;
+ }
+
+ ret = g_strlcpy(cmd, BT_HF_INDICATORS_ACTIVATION, cmd_size);
+
+ for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l)) {
+ ret = g_strlcat(cmd, "0,", cmd_size);
+ if (ret >= cmd_size) {
+ ERR("Too many indices");
+ return FALSE;
+ }
+
+ }
+
+ cmd[ret - 1] = '\0';
+ DBG("BIA Str : %s", cmd);
+
+ ret = g_strlcat(cmd, "\r", cmd_size);
+ if (ret >= cmd_size) {
+ ERR("Too many indices");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean __bt_get_current_indicators(bt_hf_agent_info_t *bt_hf_info)
+{
+ gchar buf[BT_HF_DATA_BUF_SIZE] = {0,};
+ gboolean ret;
+ gchar *str;
+ GSList *l;
+ int index = 1;
+
+ ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_VAL, buf,
+ sizeof(BT_HF_INDICATORS_VAL) - 1);
+ if (!ret || !strstr(buf, "+CIND:"))
+ return FALSE;
+
+ /* if buf has other command prefix, skip it */
+ str = strstr(buf, "+CIND");
+ if (str == NULL)
+ return FALSE;
+
+ bt_hf_info->indies = __bt_hf_parse_indicator_values(str + 6, bt_hf_info->indies);
+
+ /* Parse the updated value */
+ for (l = bt_hf_info->indies; l != NULL; l = g_slist_next(l), ++index) {
+ struct indicator *ind = l->data;
+ if (!ind) {
+ DBG("Index is NULL");
+ break;
+ }
+
+ if (0 == g_strcmp0(ind->descr, "\"call\"")) {
+ DBG("CIND Match found index = %d, %s, value = %d",
+ index, ind->descr, ind->value);
+ bt_hf_info->ciev_call_status = ind->value;
+ if (ind->value > 0) {
+ bt_hf_info->is_dialing = FALSE;
+ bt_hf_info->call_active = TRUE;
+ }
+ } else if (0 == g_strcmp0(ind->descr, "\"callsetup\"")) {
+ DBG("CIND Match found index = %d, %s, value = %d",
+ index, ind->descr, ind->value);
+ bt_hf_info->ciev_call_setup_status = ind->value;
+ if (!bt_hf_info->is_dialing && ind->value > 0)
+ bt_hf_info->is_dialing = TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean __bt_establish_service_level_conn(bt_hf_agent_info_t *bt_hf_info)
+{
+ gchar buf[BT_HF_DATA_BUF_SIZE];
+ gchar cmd_buf[BT_HF_CMD_BUF_SIZE] = {0};
+ gboolean ret;
+ char *buf_ptr;
+ guint feature = BT_HF_FEATURE_EC_ANDOR_NR |
+ BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
+ BT_HF_FEATURE_CLI_PRESENTATION |
+ BT_HF_FEATURE_VOICE_RECOGNITION |
+ BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+ BT_HF_FEATURE_ENHANCED_CALL_STATUS |
+ BT_HF_FEATURE_CODEC_NEGOTIATION;
+
+ snprintf(cmd_buf, sizeof(cmd_buf), BT_HF_FEATURES, feature);
+ ret = __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf,
+ strlen(cmd_buf));
+ if (!ret )
+ return FALSE;
+
+ buf_ptr = strstr(buf, "\r\n+BRSF:");
+ if (buf_ptr == NULL)
+ return FALSE;
+
+ if (!ret || sscanf(buf_ptr, "\r\n+BRSF:%5d", &bt_hf_info->ag_features) != 1)
+ return FALSE;
+ INFO("Gateway supported features are 0x%X", bt_hf_info->ag_features);
+
+ if (bt_hf_info->ag_features & BT_AG_FEATURE_CODEC_NEGOTIATION) {
+ ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_MSBC);
+ if (ret != BT_HF_AGENT_ERROR_NONE)
+ ERR("Unable to set the default WBC codec");
+
+ ret = __bt_hf_send_available_codec(bt_hf_info, 0);
+ if (!ret)
+ return FALSE;
+ } else {
+ /* Default codec is NB */
+ ret = _hf_agent_codec_setup(bt_hf_info->remote_addr, BT_HF_CODEC_ID_CVSD);
+ if (ret != BT_HF_AGENT_ERROR_NONE)
+ ERR("Unable to set the default NBC codec");
+ }
+
+ ret = __bt_get_supported_indicators(bt_hf_info);
+ if (!ret)
+ return FALSE;
+
+
+ ret = __bt_get_current_indicators(bt_hf_info);
+ if (!ret)
+ return FALSE;
+
+ ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_INDICATORS_ENABLE, buf,
+ sizeof(BT_HF_INDICATORS_ENABLE) - 1);
+ if (!ret || !strstr(buf, "OK"))
+ return FALSE;
+
+ if ((bt_hf_info->ag_features & BT_AG_FEATURE_3WAY) != 0) {
+ ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_HOLD_MPTY_SUPP,
+ buf, sizeof(BT_HF_HOLD_MPTY_SUPP) - 1);
+ if (!ret || !strstr(buf, "+CHLD:")) {
+ ERR("Unable to get the CHLD Supported info");
+ return FALSE;
+ }
+ bt_hf_info->hold_multiparty_features = __bt_hf_get_hold_mpty_features(
+ strchr(buf, '('));
+ } else
+ bt_hf_info->hold_multiparty_features = 0;
+
+ INFO("Service layer connection successfully established...!");
+
+ __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLER_IDENT_ENABLE, buf,
+ sizeof(BT_HF_CALLER_IDENT_ENABLE) - 1);
+ __bt_hf_send_and_read(bt_hf_info, BT_HF_CARRIER_FORMAT, buf,
+ sizeof(BT_HF_CARRIER_FORMAT) - 1);
+ __bt_hf_send_and_read(bt_hf_info, BT_HF_CALLWAIT_NOTI_ENABLE, buf,
+ sizeof(BT_HF_CALLWAIT_NOTI_ENABLE) - 1);
+
+ if ((bt_hf_info->ag_features & BT_AG_FEATURE_NREC) != 0)
+ __bt_hf_send_and_read(bt_hf_info, BT_HF_NREC, buf,
+ sizeof(BT_HF_NREC) - 1);
+
+ if ((bt_hf_info->ag_features & BT_AG_FEATURE_EXTENDED_RES_CODE) != 0)
+ __bt_hf_send_and_read(bt_hf_info, BT_HF_EXTENDED_RESULT_CODE,
+ buf, sizeof(BT_HF_EXTENDED_RESULT_CODE) - 1);
+
+ if (__bt_get_bia_cmd(bt_hf_info, cmd_buf, sizeof(cmd_buf)) == TRUE)
+ __bt_hf_send_and_read(bt_hf_info, cmd_buf, buf, strlen(cmd_buf));
+ else
+ ERR("__bt_get_bia_cmd is failed");
+
+ ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_XSAT, buf,
+ sizeof(BT_HF_XSAT) - 1);
+ if (ret)
+ DBG("sent BT_HF_XSAT");
+ else
+ ERR("BT_HF_XSAT sending failed");
+
+ /* send Bluetooth Samsung Support Feature cmd */
+ ret = __bt_hf_send_and_read(bt_hf_info, BT_HF_BSSF, buf,
+ sizeof(BT_HF_BSSF) - 1);
+ if (ret)
+ INFO("SLC completed with all commands");
+ else
+ ERR("BT_HF_BSSF sending failed");
+
+ bt_hf_info->slc = TRUE;
+ send_flag = FALSE;
+ g_id = 0;
+ memset(global_buff, 0, sizeof(global_buff));
+ return TRUE;
+}
+
+static void __bt_hf_agent_sigterm_handler(int signo)
+{
+ ERR_C("***** Signal handler came with signal %d *****", signo);
+ GDBusConnection *conn;
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "CallEnded", NULL);
+ DBG("CallEnded Signal done");
+ if (gmain_loop) {
+ g_main_loop_quit(gmain_loop);
+ DBG("Exiting");
+ gmain_loop = NULL;
+ } else {
+ INFO_C("Terminating HF agent");
+ exit(0);
+ }
+}
+
+static void __bt_convert_addr_type_to_rev_string(char *address,
+ unsigned char *addr)
+{
+ ret_if(address == NULL);
+ ret_if(addr == NULL);
+
+ g_snprintf(address, BT_ADDRESS_STRING_SIZE,
+ "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
+}
+
+
+static gboolean __bt_hf_agent_release_after(gpointer user_data)
+{
+ if (__bt_hf_agent_release() == FALSE)
+ ERR("Unable to release hf connection");
+
+ return FALSE;
+}
+
+static gboolean __bt_agent_request_service_level_conn(gpointer data)
+{
+ char *remote_addr;
+ int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
+ GDBusConnection *conn;
+
+ DBG("+");
+ memset(prev_cmd, 0, BT_HF_CMD_BUF_SIZE);
+
+ if (!__bt_establish_service_level_conn(&bt_hf_info)) {
+ ERR("Service Level Connection is fail");
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (conn) {
+ remote_addr = bt_hf_info.remote_addr;
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "Connected",
+ g_variant_new("(s)", remote_addr));
+ }
+ bt_hf_info.state = BT_HF_STATE_CONNECTED;
+
+ if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
+ DBG("BT device state is : 0x%X", bt_device_state);
+ bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
+ if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0) {
+ ERR("vconf_set_int failed");
+ }
+ } else {
+ ERR("vconf_get_int failed");
+ }
+
+ g_idle_add(__bt_hf_agent_release_after, NULL);
+
+ goto done;
+ }
+
+ bt_hf_info.state = BT_HF_STATE_CONNECTED;
+
+ __bt_hf_agent_sco_accept(&bt_hf_info);
+
+ __bt_hf_agent_start_watch(&bt_hf_info);
+
+ remote_addr = bt_hf_info.remote_addr;
+
+ INFO_SECURE("Address is : %s", remote_addr);
+ INFO_C("Connected [HF role]");
+
+ if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
+ DBG("BT device state is : 0x%X", bt_device_state);
+ bt_device_state |= VCONFKEY_BT_DEVICE_AG_CONNECTED;
+ if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0) {
+ ERR("vconf_set_int failed");
+ }
+ } else {
+ ERR("vconf_get_int failed");
+ }
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return FALSE;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "Connected",
+ g_variant_new("(s)", remote_addr));
+
+ /* Request the call list and launch call app if required */
+ __bt_hf_agent_handle_call_list(&bt_hf_info);
+
+done:
+ DBG("-");
+ return FALSE;
+}
+
+static gboolean __bt_hf_agent_connection(gint32 fd, const gchar *obj_path)
+{
+ GIOFlags flags;
+
+ struct sockaddr_remote address;
+ socklen_t address_len;
+ bt_hf_info.path = g_strdup(obj_path);
+
+ INFO_C("**** New HFP connection ****");
+
+ is_hf_connected = TRUE;
+
+ address_len = sizeof(address);
+ if (getpeername(fd, (struct sockaddr *) &address, &address_len) != 0)
+ ERR("BD_ADDR is NULL");
+
+ DBG("RFCOMM connection for HFP is completed. Fd = [%d]\n", fd);
+ bt_hf_info.fd = fd;
+ bt_hf_info.io_chan = g_io_channel_unix_new(bt_hf_info.fd);
+ flags = g_io_channel_get_flags(bt_hf_info.io_chan);
+
+ flags &= ~G_IO_FLAG_NONBLOCK;
+ flags &= G_IO_FLAG_MASK;
+ g_io_channel_set_flags(bt_hf_info.io_chan, flags, NULL);
+ g_io_channel_set_encoding(bt_hf_info.io_chan, NULL, NULL);
+ g_io_channel_set_buffered(bt_hf_info.io_chan, FALSE);
+
+ bt_hf_info.remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
+ __bt_convert_addr_type_to_rev_string(bt_hf_info.remote_addr,
+ address.remote_bdaddr.b);
+
+ g_idle_add(__bt_agent_request_service_level_conn, NULL);
+
+ return TRUE;
+}
+
+static void __bt_hf_agent_indicator_free(gpointer mem)
+{
+ g_free(mem);
+}
+
+static gboolean __bt_hf_agent_release(void)
+{
+ int bt_device_state = VCONFKEY_BT_DEVICE_NONE;
+ GDBusConnection *conn;
+
+ if (bt_hf_info.state == BT_HF_STATE_DISCONNECTED) {
+ ERR("hf is already disconnected");
+ return FALSE;
+ }
+
+ if (bt_hf_info.indies) {
+ g_slist_free_full(bt_hf_info.indies, __bt_hf_agent_indicator_free);
+ bt_hf_info.indies = NULL;
+ }
+
+ if (bt_hf_info.io_chan) {
+ g_io_channel_shutdown(bt_hf_info.io_chan, TRUE, NULL);
+ g_io_channel_unref(bt_hf_info.io_chan);
+ bt_hf_info.io_chan = NULL;
+ }
+
+ if (bt_hf_info.sco_watch_id > 0) {
+ g_source_remove(bt_hf_info.sco_watch_id);
+ bt_hf_info.sco_watch_id = 0;
+ }
+
+ bt_hf_info.state = BT_HF_STATE_DISCONNECTED;
+
+ __bt_hf_agent_release_queue();
+
+ if (vconf_get_int(VCONFKEY_BT_DEVICE, &bt_device_state) == 0) {
+ DBG("BT device state is : 0x%X", bt_device_state);
+ bt_device_state ^= VCONFKEY_BT_DEVICE_AG_CONNECTED;
+ if (vconf_set_int(VCONFKEY_BT_DEVICE, bt_device_state) != 0) {
+ ERR("vconf_set_int failed");
+ }
+ } else {
+ ERR("vconf_get_int failed");
+ }
+
+ __bt_hf_agent_stop_watch(&bt_hf_info);
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return FALSE;
+ }
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "Disconnected",
+ g_variant_new("(s)", bt_hf_info.remote_addr));
+
+ g_free(bt_hf_info.path);
+ bt_hf_info.path = NULL;
+
+ g_free(bt_hf_info.remote_addr);
+ bt_hf_info.remote_addr = NULL;
+
+ is_hf_connected = FALSE;
+
+ return TRUE;
+}
+
+static gboolean __bt_hf_agent_connection_release(void)
+{
+ return __bt_hf_agent_release();
+}
+
+static int __bt_hf_register_profile(const char *uuid, uint16_t version,
+ const char *name, const char *object, uint16_t features)
+{
+ DBG("+");
+ GDBusProxy *proxy;
+ GVariant *ret;
+ GError *error = NULL;
+ GVariantBuilder *builder;
+ gchar *path = NULL;
+
+ proxy = __bt_hf_gdbus_get_service_proxy(BLUEZ_SERVICE_NAME,
+ "/org/bluez", BLUEZ_PROFILE_MGMT_INTERFACE);
+
+ if (proxy == NULL)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(builder, "{sv}",
+ "Name", g_variant_new("s",
+ name));
+ g_variant_builder_add(builder, "{sv}",
+ "Version", g_variant_new("q", version));
+
+ g_variant_builder_add(builder, "{sv}",
+ "features", g_variant_new("q", features));
+
+ ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
+ g_variant_new("(osa{sv})", path,
+ HFP_HF_UUID, builder),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+
+ g_variant_builder_unref(builder);
+
+ if (ret == NULL) {
+ /* dBUS-RPC is failed */
+ ERR("dBUS-RPC is failed");
+ if (error != NULL) {
+ /* dBUS gives error cause */
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ g_free(path);
+ return BT_HF_AGENT_ERROR_INTERNAL;
+ }
+ g_variant_unref(ret);
+ g_free(path);
+
+ DBG("-");
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+static void __bt_hf_agent_register(void)
+{
+ DBG("+");
+ int ret;
+ char *name;
+ uint16_t version = hf_ver;
+ uint16_t features = bt_hf_info.feature;
+
+ gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
+ name = g_strdup("Hands-Free");
+
+ ret = __bt_hf_register_profile(HFP_HF_UUID, version, name, path,
+ features);
+ if (ret)
+ ERR("Error in register");
+
+ g_free(path);
+ g_free(name);
+
+ DBG("-");
+ return;
+}
+
+static void __bt_hf_agent_unregister(void)
+{
+ DBG("+");
+
+ gchar *path = g_strdup(BT_HF_BLUEZ_OBJECT_PATH);
+
+ if (g_obj_path) {
+ __bt_hf_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
+ g_variant_new("(o)", path),
+ BLUEZ_HF_INTERFACE_NAME,
+ "UnregisterAgent");
+ g_free(g_obj_path);
+ g_obj_path = NULL;
+ }
+
+ g_free(path);
+
+ DBG("-");
+ return;
+}
+
+static void __bt_hf_agent_filter_cb(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ DBG("+");
+ char *path = NULL;
+
+ GVariant *optional_param;
+
+ if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
+
+ g_variant_get(parameters, "(&o@a{sa{sv}})",
+ &path, &optional_param);
+ if (!path) {
+ ERR("Invalid adapter path");
+ return;
+ }
+
+ if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
+ g_obj_path = g_strdup(path);
+ INFO("Adapter Path = [%s]", path);
+ __bt_hf_agent_register();
+ }
+ } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
+ g_variant_get(parameters, "(&o@as)", &path, &optional_param);
+ if (!path)
+ __bt_hf_agent_unregister();
+ }
+ DBG("-");
+}
+
+static void __bt_hf_agent_dbus_init(void)
+{
+ GDBusConnection *conn;
+
+ DBG("+");
+
+ conn = __bt_hf_get_gdbus_connection();
+ if (conn == NULL) {
+ ERR("Error in creating the gdbus connection\n");
+ return;
+ }
+ if (!__bt_hf_register_profile_methods()) {
+ ERR("Error in register_profile_methods\n");
+ return;
+ }
+
+ owner_sig_id = g_dbus_connection_signal_subscribe(conn,
+ NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
+ __bt_hf_agent_filter_cb, NULL, NULL);
+ DBG("-");
+ return;
+}
+
+static void __bt_hf_agent_dbus_deinit(void)
+{
+
+ if (service_gproxy) {
+ g_object_unref(service_gproxy);
+ service_gproxy = NULL;
+ }
+
+ if (gdbus_conn) {
+ if (owner_sig_id != -1)
+ g_dbus_connection_signal_unsubscribe(gdbus_conn,
+ owner_sig_id);
+
+ g_object_unref(gdbus_conn);
+ gdbus_conn = NULL;
+ }
+ return;
+}
+
+static int _hf_agent_answer_call(GDBusMethodInvocation *context)
+{
+ int ret;
+
+ DBG("+\n");
+ if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
+ ERR("HF not Connected");
+ return BT_HF_AGENT_ERROR_NOT_CONNECTED;
+ }
+ bt_hf_info.context = context;
+
+ ret = __bt_hf_send_only(&bt_hf_info, BT_HF_ANSWER_CALL,
+ sizeof(BT_HF_ANSWER_CALL) - 1);
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ DBG("-\n");
+ return BT_HF_AGENT_ERROR_NONE;
+
+}
+
+static int _hf_agent_terminate_call(GDBusMethodInvocation *context)
+{
+ int ret;
+
+ DBG("+\n");
+ if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
+ ERR("HF not Connected");
+ return BT_HF_AGENT_ERROR_NOT_CONNECTED;
+ }
+
+ bt_hf_info.context = context;
+
+ ret = __bt_hf_send_only(&bt_hf_info, BT_HF_END_CALL,
+ sizeof(BT_HF_END_CALL) - 1);
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ DBG("-\n");
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+static int _hf_agent_dial_no(GDBusMethodInvocation *context, char *no)
+{
+ int ret;
+ char buf[BT_MAX_TEL_NUM_STR + 6] = {0};
+
+ if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
+ ERR("HF not Connected");
+ return BT_HF_AGENT_ERROR_NOT_CONNECTED;
+ }
+
+ bt_hf_info.context = context;
+
+ if (strlen(no) > 0) {
+ snprintf(buf, sizeof(buf), BT_HF_DIAL_NO, no);
+
+ if (strstr(prev_cmd, "ATD") && bt_hf_info.ciev_call_status == 0
+ && bt_hf_info.ciev_call_setup_status == 0) {
+ INFO("RAD POPUP CANCEL CASE. send ATD w/o response - KOR REQUEST");
+ ret = __bt_hf_send_only_without_queue(&bt_hf_info, buf, strlen(buf));
+ if (send_flag)
+ send_flag--;
+ } else {
+ ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
+ }
+
+ /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
+ snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", buf);
+
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ return BT_HF_AGENT_ERROR_NONE;
+ }
+
+ /* prev_cmd is meant for only meant for ATD & AT+BLDN Error handling */
+ snprintf(prev_cmd, BT_HF_CMD_BUF_SIZE, "%s", BT_HF_REDIAL);
+
+ ret = __bt_hf_send_only(&bt_hf_info, BT_HF_REDIAL,
+ sizeof(BT_HF_REDIAL) - 1);
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+static int _hf_agent_voice_recognition(GDBusMethodInvocation *context, unsigned int status)
+{
+ int ret;
+ char buf[20] = {0};
+
+ if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
+ ERR("HF not Connected");
+ return BT_HF_AGENT_ERROR_NOT_CONNECTED;
+ }
+
+ snprintf(buf, sizeof(buf), BT_HF_VOICE_RECOGNITION, status);
+
+ bt_hf_info.context = context;
+
+ ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+static int _hf_agent_set_speaker_gain(GDBusMethodInvocation *context, unsigned int gain)
+{
+ int ret;
+ char buf[20] = {0};
+
+ if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
+ ERR("HF not Connected");
+ return BT_HF_AGENT_ERROR_NOT_CONNECTED;
+ }
+
+ if (gain > BT_HF_MAX_SPEAKER_GAIN)
+ return BT_HF_AGENT_ERROR_INVALID_PARAM;
+
+ snprintf(buf, sizeof(buf), BT_HF_SPEAKER_GAIN, gain);
+
+ bt_hf_info.context = context;
+
+ ret = __bt_hf_send_only(&bt_hf_info, buf,
+ strlen(buf));
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ return BT_HF_AGENT_ERROR_NONE;
+
+}
+
+static int _hf_agent_send_dtmf(GDBusMethodInvocation *context, char *dtmf)
+{
+ int ret;
+ char buf[20] = {0};
+
+ if (strlen(dtmf) <= 0)
+ return BT_HF_AGENT_ERROR_INVALID_PARAM;
+
+ if (bt_hf_info.state != BT_HF_STATE_CONNECTED) {
+ ERR("HF not Connected");
+ return BT_HF_AGENT_ERROR_NOT_CONNECTED;
+ }
+
+ snprintf(buf, sizeof(buf), BT_HF_DTMF, dtmf);
+
+ bt_hf_info.context = context;
+
+ ret = __bt_hf_send_only(&bt_hf_info, buf, strlen(buf));
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+
+static int _hf_agent_send_3way_cmd(GDBusMethodInvocation *context, char *cmd)
+{
+ int ret;
+
+ if (strlen(cmd) <= 0)
+ return BT_HF_AGENT_ERROR_INVALID_PARAM;
+
+ bt_hf_info.context = context;
+
+ ret = __bt_hf_send_only(&bt_hf_info, cmd,
+ strlen(cmd));
+ if (!ret)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+static gboolean bt_hf_agent_sco_disconnect(void)
+{
+ DBG("+");
+ GDBusConnection *conn;
+
+ close(bt_hf_info.cli_sco_fd);
+ bt_hf_info.cli_sco_fd = -1;
+
+ DBG("Emit AudioDisconnected Signal");
+ conn = __bt_hf_get_gdbus_connection();
+ if (!conn) {
+ ERR("Unable to get connection");
+ return FALSE;
+ }
+
+ sco_audio_connected = BT_HF_AUDIO_DISCONNECTED;
+
+ __bt_hf_agent_emit_signal(conn,
+ BT_HF_AGENT_OBJECT_PATH,
+ BT_HF_SERVICE_INTERFACE,
+ "AudioDisconnected", NULL);
+ DBG("-");
+ return TRUE;
+}
+
+static GVariant *bt_hf_agent_request_call_list(void)
+{
+ GSList *call_list = NULL;
+ GVariant *var_data;
+ DBG("+");
+
+ call_list = __bt_hf_get_call_list(&bt_hf_info);
+ if (!call_list) {
+ INFO("call list is NULL");
+ return NULL;
+ }
+
+ var_data = __bt_hf_agent_get_call_status_info(call_list);
+ __bt_hf_free_call_list(call_list);
+
+ DBG("-");
+ return var_data;
+}
+
+static int bt_hf_agent_send_at_cmd(GDBusMethodInvocation *context, char *atcmd)
+
+{
+ gboolean ret;
+ char cmd_buf[BT_MAX_TEL_NUM_STR + 20] = {0, };
+
+ DBG("+");
+
+ if (atcmd == NULL)
+ return BT_HF_AGENT_ERROR_INVALID_PARAM;
+
+ if (bt_hf_info.state != BT_HF_STATE_CONNECTED)
+ return BT_HF_AGENT_ERROR_NOT_CONNECTED;
+
+ /* Should not send cmds if DUT has sent a command and waiting for response */
+ if (prev_cmd[0] != 0) {
+ INFO("DUT is waiting a respond for previous TX cmd. Skip sending.");
+ return BT_HF_AGENT_ERROR_INTERNAL;
+ }
+
+ strncpy(cmd_buf, atcmd, sizeof(cmd_buf) - 2);
+ strncat(cmd_buf, "\r", (sizeof(cmd_buf) - 1) - strlen(cmd_buf));
+
+ bt_hf_info.context = context;
+
+ ret = __bt_hf_send_only(&bt_hf_info, cmd_buf, strlen(cmd_buf));
+ if (ret == FALSE)
+ return BT_HF_AGENT_ERROR_INTERNAL;
+
+ DBG("-");
+ return BT_HF_AGENT_ERROR_NONE;
+}
+
+static uint32_t __bt_hf_agent_get_hf_features(void)
+{
+
+ uint32_t hf_features = BT_HF_FEATURE_EC_ANDOR_NR |
+ BT_HF_FEATURE_CALL_WAITING_AND_3WAY |
+ BT_HF_FEATURE_CLI_PRESENTATION |
+ BT_HF_FEATURE_VOICE_RECOGNITION |
+ BT_HF_FEATURE_REMOTE_VOLUME_CONTROL |
+ BT_HF_FEATURE_ENHANCED_CALL_STATUS |
+ BT_HF_FEATURE_CODEC_NEGOTIATION;
+
+ hf_ver = HFP_VERSION_1_6;
+
+ return hf_features;
+}
+
+int main(void)
+{
+ struct sigaction sa;
+ const char *pkg_name = "org.tizen.hf_agent";
+ uint32_t hf_features;
+
+ INFO("Starting Bluetooth HF agent");
+
+ g_type_init();
+
+ hf_features = __bt_hf_agent_get_hf_features();
+ bt_hf_info.feature = (uint16_t) hf_features & 0x3F;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = __bt_hf_agent_sigterm_handler;
+ sigaction(SIGTERM, &sa, NULL);
+
+ /* Temporarily, block the below signal for debugging */
+// sigaction(SIGSEGV, &sa, NULL);
+// sigaction(SIGABRT, &sa, NULL);
+ gmain_loop = g_main_loop_new(NULL, FALSE);
+
+ if (gmain_loop == NULL) {
+ ERR("GMainLoop create failed\n");
+ return EXIT_FAILURE;
+ }
+
+ __bt_hf_agent_dbus_init();
+ g_main_loop_run(gmain_loop);
+
+ __bt_hf_agent_dbus_deinit();
+
+ if (gmain_loop)
+ g_main_loop_unref(gmain_loop);
+
+ INFO("Terminating Bluetooth HF agent");
+ return 0;
+}
--- /dev/null
+/*
+ * Bluetooth-hf-agent
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ *
+ * 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_HF_AGENT_H_
+#define __DEF_BT_HF_AGENT_H_
+
+#undef LOG_TAG
+#define LOG_TAG "BLUETOOTH_HF_AGENT"
+
+#define LOG_COLOR_RESET "\033[0m"
+#define LOG_COLOR_RED "\033[31m"
+#define LOG_COLOR_YELLOW "\033[33m"
+#define LOG_COLOR_GREEN "\033[32m"
+#define LOG_COLOR_BLUE "\033[36m"
+#define LOG_COLOR_PURPLE "\033[35m"
+
+#define DBG(fmt, args...) SLOGD(fmt, ##args)
+#define INFO(fmt, args...) SLOGI(fmt, ##args)
+#define ERR(fmt, args...) SLOGE(fmt, ##args)
+#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args)
+#define INFO_SECURE(fmt, args...) SECURE_SLOGI(fmt, ##args)
+#define ERR_SECURE(fmt, args...) SECURE_SLOGE(fmt, ##args)
+#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args)
+#define INFO_C(fmt, arg...) \
+ SLOGI_IF(TRUE, LOG_COLOR_BLUE" "fmt" "LOG_COLOR_RESET, ##arg)
+#define ERR_C(fmt, arg...) \
+ SLOGI_IF(TRUE, LOG_COLOR_RED" "fmt" "LOG_COLOR_RESET, ##arg)
+
+
+#include <unistd.h>
+#include <dlog.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+
+#define BTPROTO_SCO 2
+
+#define BT_HF_DATA_BUF_SIZE 1024
+#define BT_HF_CMD_BUF_SIZE 32
+#define BT_HF_INDICATOR_DESCR_SIZE 20
+#define BT_HF_CALLER_NUM_SIZE 64 /* size of number + type */
+#define BT_HF_FMT_STR_SIZE 32
+
+#define BT_HF_AGENT_ERROR (__bt_hf_agent_error_quark())
+
+#define BT_ERROR_INTERNAL "InternalError"
+#define BT_ERROR_NOT_AVAILABLE "NotAvailable"
+#define BT_ERROR_NOT_CONNECTED "NotConnected"
+#define BT_ERROR_NOT_CONNECTION_FAILED "ConnectionFailed"
+#define BT_ERROR_BUSY "InProgress"
+#define BT_ERROR_INVALID_PARAM "InvalidArguments"
+#define BT_ERROR_ALREADY_EXIST "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_OPERATION_NOT_ALLOWED "Operation not allowed"
+#define BT_ERROR_OPERATION_NOT_SUPPORTED "Operation not supported"
+#define BT_ERROR_INVALID_FILE_DESCRIPTOR "Invalid File Descriptor"
+
+typedef enum {
+ BT_HF_AGENT_ERROR_NONE,
+ BT_HF_AGENT_ERROR_INTERNAL,
+ BT_HF_AGENT_ERROR_NOT_AVAILABLE,
+ BT_HF_AGENT_ERROR_NOT_CONNECTED,
+ BT_HF_AGENT_ERROR_CONNECTION_FAILED,
+ BT_HF_AGENT_ERROR_BUSY,
+ BT_HF_AGENT_ERROR_INVALID_PARAM,
+ BT_HF_AGENT_ERROR_ALREADY_EXIST,
+ BT_HF_AGENT_ERROR_ALREADY_CONNECTED,
+ BT_HF_AGENT_ERROR_NO_MEMORY,
+ BT_HF_AGENT_ERROR_I_O_ERROR,
+ BT_HF_AGENT_ERROR_APPLICATION,
+ BT_HF_AGENT_ERROR_NOT_ALLOWED,
+ BT_HF_AGENT_ERROR_NOT_SUPPORTED,
+ BT_HF_AGENT_ERROR_INVALID_FILE_DESCRIPTOR,
+} bt_hf_agent_error_t;
+
+/* Extended Audio Gateway Error Result Codes */
+typedef enum {
+ BT_AG_CME_ERROR_NONE = -1,
+ BT_AG_CME_ERROR_AG_FAILURE = 0,
+ BT_AG_CME_ERROR_NO_PHONE_CONNECTION = 1,
+ BT_AG_CME_ERROR_NOT_ALLOWED = 3,
+ BT_AG_CME_ERROR_NOT_SUPPORTED = 4,
+ BT_AG_CME_ERROR_PH_SIM_PIN_REQUIRED = 5,
+ BT_AG_CME_ERROR_SIM_NOT_INSERTED = 10,
+ BT_AG_CME_ERROR_SIM_PIN_REQUIRED = 11,
+ BT_AG_CME_ERROR_SIM_PUK_REQUIRED = 12,
+ BT_AG_CME_ERROR_SIM_FAILURE = 13,
+ BT_AG_CME_ERROR_SIM_BUSY = 14,
+ BT_AG_CME_ERROR_INCORRECT_PASSWORD = 16,
+ BT_AG_CME_ERROR_SIM_PIN2_REQUIRED = 17,
+ BT_AG_CME_ERROR_SIM_PUK2_REQUIRED = 18,
+ BT_AG_CME_ERROR_MEMORY_FULL = 20,
+ BT_AG_CME_ERROR_INVALID_INDEX = 21,
+ BT_AG_CME_ERROR_MEMORY_FAILURE = 23,
+ BT_AG_CME_ERROR_TEXT_STRING_TOO_LONG = 24,
+ BT_AG_CME_ERROR_INVALID_TEXT_STRING = 25,
+ BT_AG_CME_ERROR_DIAL_STRING_TOO_LONG = 26,
+ BT_AG_CME_ERROR_INVALID_DIAL_STRING = 27,
+ BT_AG_CME_ERROR_NO_NETWORK_SERVICE = 30,
+ BT_AG_CME_ERROR_NETWORK_TIMEOUT = 31,
+ BT_AG_CME_ERROR_NETWORK_NOT_ALLOWED = 32,
+} bt_ag_cme_error_t;
+
+typedef enum {
+ BT_HF_CALL_DIR_OUTGOING,
+ BT_HF_CALL_DIR_INCOMING,
+} bt_hf_call_direction_t;
+
+/* Call status as per spec */
+typedef enum {
+ BT_HF_CALL_STAT_ACTIVE,
+ BT_HF_CALL_STAT_HELD,
+ BT_HF_CALL_STAT_DIALING,
+ BT_HF_CALL_STAT_ALERTING,
+ BT_HF_CALL_STAT_INCOMING,
+ BT_HF_CALL_STAT_WAITING,
+} bt_hf_call_status_t;
+
+enum hfp_version {
+ HFP_VERSION_1_5 = 0x0105,
+ HFP_VERSION_1_6 = 0x0106,
+ HFP_VERSION_LATEST = HFP_VERSION_1_6,
+};
+
+/*Handsfree supported features*/
+#define BT_HF_FEATURE_EC_ANDOR_NR 0x0001
+#define BT_HF_FEATURE_CALL_WAITING_AND_3WAY 0x0002
+#define BT_HF_FEATURE_CLI_PRESENTATION 0x0004
+#define BT_HF_FEATURE_VOICE_RECOGNITION 0x0008
+#define BT_HF_FEATURE_REMOTE_VOLUME_CONTROL 0x0010
+#define BT_HF_FEATURE_ENHANCED_CALL_STATUS 0x0020
+#define BT_HF_FEATURE_ENHANCED_CALL_CONTROL 0x0040
+#define BT_HF_FEATURE_CODEC_NEGOTIATION 0x0080
+
+/*AG suported feature*/
+#define BT_AG_FEATURE_3WAY 0x1
+#define BT_AG_FEATURE_NREC 0x0002
+#define BT_AG_FEATURE_EXTENDED_RES_CODE 0x100
+#define BT_AG_FEATURE_CODEC_NEGOTIATION 0x0200
+
+#define BT_HF_CODEC_ID_CVSD 1
+#define BT_HF_CODEC_ID_MSBC 2
+
+#define BT_HF_AUDIO_DISCONNECTED 0
+#define BT_HF_AUDIO_CONNECTED 1
+
+#define BT_MAX_TEL_NUM_STR 100
+
+#define BT_HF_FEATURES "AT+BRSF=%d\r" /* = 0x7F = All features supported */
+#define BT_HF_INDICATORS_SUPP "AT+CIND=?\r"
+#define BT_HF_INDICATORS_VAL "AT+CIND?\r"
+#define BT_HF_INDICATORS_ENABLE "AT+CMER=3,0,0,1\r"
+#define BT_HF_HOLD_MPTY_SUPP "AT+CHLD=?\r"
+#define BT_HF_CALLER_IDENT_ENABLE "AT+CLIP=1\r"
+#define BT_HF_CARRIER_FORMAT "AT+COPS=3,0\r"
+#define BT_HF_EXTENDED_RESULT_CODE "AT+CMEE=1\r"
+#define BT_HF_INDICATORS_ACTIVATION "AT+BIA="
+#define BT_HF_ANSWER_CALL "ATA\r"
+#define BT_HF_END_CALL "AT+CHUP\r"
+#define BT_HF_REDIAL "AT+BLDN\r"
+#define BT_HF_DIAL_NO "ATD%.100s;\r"
+#define BT_HF_VOICE_RECOGNITION "AT+BVRA=%d\r"
+#define BT_HF_XSAT "AT+XSAT=00,TY,WA\r"
+#define BT_HF_BSSF "AT+BSSF=8\r"
+#define BT_HF_CALLLIST "AT+CLCC\r"
+#define BT_HF_AVAILABLE_CODEC "AT+BAC=%d,%d\r"
+#define BT_HF_CODEC_SELECT "AT+BCS=%d\r"
+#define BT_HF_SPEAKER_GAIN "AT+VGS=%d\r"
+#define BT_HF_DTMF "AT+VTS=%s\r"
+#define BT_HF_NREC "AT+NREC=0\r"
+#define BT_HF_CALLWAIT_NOTI_ENABLE "AT+CCWA=1\r"
+#define BT_HF_RELEASE_ALL "AT+CHLD=0\r"
+#define BT_HF_RELEASE_AND_ACCEPT "AT+CHLD=1\r"
+#define BT_HF_ACCEPT_AND_HOLD "AT+CHLD=2\r"
+#define BT_HF_JOIN_CALL "AT+CHLD=3\r"
+
+#define BT_MAX_EVENT_STR_LENGTH 50
+#define BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS 200
+
+#define BT_HF_MAX_SPEAKER_GAIN 15
+#define BT_HF_MIN_SPEAKER_GAIN 0
+
+
+typedef enum {
+ BT_AGENT_EVENT_HANDSFREE_CONNECT = 0x1100,
+ BT_AGENT_EVENT_HANDSFREE_DISCONNECT = 0x1200,
+} bt_hfp_agent_event_type_t;
+
+/* Hold and multipary AG features.
+ * Comments below are copied from hands-free spec for reference */
+/* Releases all held calls or sets User Determined User Busy (UDUB)
+ * for a waiting call */
+#define BT_HF_CHLD_0 0x01
+/* Releases all active calls (if any exist) and accepts the other
+ * (held or waiting) call */
+#define BT_HF_CHLD_1 0x02
+/* Releases specified active call only <x> */
+#define BT_HF_CHLD_1x 0x04
+/* Places all active calls (if any exist) on hold and accepts the other
+ * (held or waiting) call */
+#define BT_HF_CHLD_2 0x08
+/* Request private consultation mode with specified call <x> (Place all
+ * calls on hold EXCEPT the call <x>) */
+#define BT_HF_CHLD_2x 0x10
+/* Adds a held call to the conversation */
+#define BT_HF_CHLD_3 0x20
+/* Connects the two calls and disconnects the subscriber from both calls
+ * (Explicit Call Transfer). Support for this value and its associated
+ * functionality is optional for the HF. */
+#define BT_HF_CHLD_4 0x40
+
+#define BT_HF_OK_RESPONSE "\r\nOK\r\n"
+#define BT_HF_ERROR_RESPONSE "ERROR"
+#define BT_HF_SEC_ERROR_RESPONSE "SERR"
+
+#define BT_HF_SERVICE_NAME "org.bluez.hf_agent"
+#define BT_HF_AGENT_OBJECT_PATH "/org/bluez/handsfree_agent"
+#define BT_HF_SERVICE_INTERFACE "org.tizen.HfApp"
+
+#define BT_HF_BLUEZ_OBJECT_PATH "/org/tizen/handsfree"
+#define BT_HF_BLUEZ_INTERFACE "org.bluez.HandsfreeAgent"
+
+#define BLUEZ_SERVICE_NAME "org.bluez"
+#define BLUEZ_HF_INTERFACE_NAME "org.bluez.HandsfreeGateway"
+
+#define PM_SERVICE_NAME "org.tizen.system.deviced"
+#define PM_OBJECT_PATH "/Org/Tizen/System/DeviceD/Display"
+#define PM_INTERFACE_NAME "org.tizen.system.deviced.display"
+#define AT_CMD_BUFF_SIZE 500
+#define BLUEZ_PROFILE_MGMT_INTERFACE "org.bluez.ProfileManager1"
+#define BT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
+#define BT_ADAPTER_INTERFACE "org.bluez.Adapter1"
+
+#define retv_if(expr, val) \
+ do { \
+ if (expr) { \
+ ERR("(%s) return", #expr); \
+ return (val); \
+ } \
+ } while (0)
+
+typedef enum {
+ BT_HF_STATE_DISCONNECTED,
+ BT_HF_STATE_CONNECTED
+} bt_hf_state_t;
+
+typedef struct {
+ guint32 fd;
+ gint sco_fd;
+ gint cli_sco_fd;
+
+ GIOChannel *io_chan;
+ GIOChannel *sco_io_chan;
+ bt_hf_state_t state;
+
+ guint watch_id;
+ guint sco_watch_id;
+ guint cli_sco_watch_id;
+
+ guint ag_features;
+ guint hold_multiparty_features;
+ GSList *indies;
+
+ gboolean is_dialing;
+ gboolean call_active;
+
+ guint ciev_call_status;
+ guint ciev_call_setup_status;
+
+ guint32 feature;
+
+ char *remote_addr;
+ int slc;
+ GSList *cmd_list;
+ GSList *cmd_send_queue;
+
+ GDBusMethodInvocation *context;
+ char *path;
+}bt_hf_agent_info_t;
+
+typedef struct {
+ int id;
+ char at_cmd[AT_CMD_BUFF_SIZE];
+ int count;
+ GDBusMethodInvocation *context;
+ int pending;
+ int timer_id;
+} bt_hf_agent_send_at_info;
+
+struct hf_event {
+ const char *cmd;
+ int (*callback) (bt_hf_agent_info_t *bt_hf_info, const char *buf);
+};
+
+typedef struct {
+ unsigned char b[6];
+} __attribute__((packed)) bdaddr_t;
+
+/* Remote socket address */
+struct sockaddr_remote {
+ sa_family_t family;
+ bdaddr_t remote_bdaddr;
+ uint8_t channel;
+};
+
+/* SCO socket address */
+struct sockaddr_sco {
+ sa_family_t sco_family;
+ bdaddr_t sco_bdaddr;
+};
+
+#endif /* __DEF_BT_HF_AGENT_H_ */
--- /dev/null
+[D-BUS Service]
+Name=org.bluez.hf_agent
+Exec=/usr/bin/bluetooth-hf-agent
+User=root
+++ /dev/null
-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/system-services)
+++ /dev/null
-/*
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <glib.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <signal.h>
-
-#include <TapiUtility.h>
-#include <ITapiSim.h>
-
-#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: <rssi>,<ber>
- <ber> 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:<number>
-*/
-#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;
-}
+++ /dev/null
-/*
- * 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 <unistd.h>
-#include <dlog.h>
-#include <stdio.h>
-
-#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_ */
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<node name="/">
- <interface name="Org.Hfp.App.Interface">
-
- <method name="RegisterApplication">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="path"/>
- </method>
-
- <method name="UnregisterApplication">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="path"/>
- </method>
-
- <method name="IncomingCall">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="path"/>
- <arg type="s" name="number"/>
- <arg type="i" name="id"/>
- </method>
-
- <method name="OutgoingCall">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="path"/>
- <arg type="s" name="number"/>
- <arg type="i" name="id"/>
- </method>
-
- <method name="ChangeCallStatus">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="path"/>
- <arg type="i" name="status"/>
- <arg type="i" name="id"/>
- </method>
-
- <method name="GetProperties">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- </method>
-
- </interface>
-
- <interface name="Org.Hfp.Bluez.Interface">
-
- <method name="AnswerCall">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="u" name="callid"/>
- <arg type="s" name="path"/>
- <arg type="s" name="sender"/>
- </method>
-
- <method name="ReleaseCall">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="u" name="callid"/>
- <arg type="s" name="path"/>
- <arg type="s" name="sender"/>
- </method>
-
- <method name="RejectCall">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="u" name="callid"/>
- <arg type="s" name="path"/>
- <arg type="s" name="sender"/>
- </method>
-
- <method name="ThreewayCall">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="u" name="value"/>
- <arg type="s" name="path"/>
- <arg type="s" name="sender"/>
- </method>
-
- <method name="DialLastNum">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- </method>
-
- <method name="DialNum">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="Number"/>
- <arg type="u" name="flags"/>
- </method>
-
- <method name="DialMemory">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="i" name="location"/>
- </method>
-
- <method name="SendDtmf">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="dtmf"/>
- <arg type="s" name="path"/>
- <arg type="s" name="sender"/>
- </method>
-
- <method name="VoiceDial">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="b" name="activate"/>
- </method>
-
- <method name="GetBatteryStatus">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="i" name="bcl" direction="out"/>
- <arg type="i" name="bcs" direction="out"/>
- </method>
-
- <method name="GetSignalQuality">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="i" name="rssi" direction="out"/>
- <arg type="i" name="ber" direction="out"/>
- </method>
-
- <method name="GetOperatorName">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="s" name="operator" direction="out"/>
- </method>
-
- <method name="NrecStatus">
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <arg type="b" name="status"/>
- </method>
-
- </interface>
-</node>
+++ /dev/null
-[D-BUS Service]
-Name=org.bluez.hfp_agent
-Exec=/usr/bin/bluetooth-hfp-agent
-User=root
INCLUDE(FindPkgConfig)
pkg_check_modules(pkgs_map_agent
REQUIRED
- dlog vconf)
+ dbus-glib-1 dlog msg-service tapi vconf)
FOREACH(flag ${pkgs_map_agent_CFLAGS})
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${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")
+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)
+ DESTINATION share/dbus-1/system-services)
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
*
* 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
+ * 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,
*
*/
-#if 0
-
#include <stdio.h>
#include <stdlib.h>
#include <string.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 <TelSms.h>
+#include <TapiUtility.h>
+#include <ITapiNetText.h>
#include <bluetooth_map_agent.h>
-
#include <map_bmessage.h>
-#define OBEX_CLIENT_SERVICE "org.openobex.client"
-#define OBEX_CLIENT_INTERFACE "org.openobex.Client"
-#define OBEX_CLIENT_PATH "/"
+#define OBEX_CLIENT_SERVICE "org.bluez.obex"
+#define OBEX_CLIENT_INTERFACE "org.bluez.obex.Client1"
+#define OBEX_CLIENT_PATH "/org/bluez/obex"
+
#define MNS_CLIENT_INTERFACE "org.openobex.MessageNotification"
#define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct("GValueArray", \
G_TYPE_INVALID))
static msg_handle_t g_msg_handle = NULL;
+static TapiHandle *g_tapi_handle = NULL;
+static TelSmsAddressInfo_t *g_sca_info = NULL;
+static DBusGProxy *g_mns_proxy;
#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_TEMPLATE "TEMPLATE"
+#define BT_MAP_DELETED_FOLDER_NAME "DELETED"
#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_SUBJECT_MAX_LEN 50
#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 LANGUAGE "LANGUAGE:%s\r\n"
#define LENGTH "LENGTH:%d\r\n"
#define MSG_BODY "BEGIN:MSG\r\n%s\r\nEND:MSG\r\n"
+#define MSG_BODY_BEGIN "BEGIN:MSG\r\n"
+#define MSG_BODY_END "\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;
+GSList *id_list = NULL;
guint64 current_push_map_id;
+typedef enum {
+ SMS_TON_UNKNOWN = 0, /* unknown */
+ SMS_TON_INTERNATIONAL = 1, /* international number */
+ SMS_TON_NATIONAL = 2, /* national number */
+ SMS_TON_NETWORK_SPECIFIC = 3, /* network specific number */
+ SMS_TON_DEDICATED_ACCESS = 4, /* subscriber number */
+ SMS_TON_ALPHA_NUMERIC = 5, /* alphanumeric, GSM 7-bit default */
+ SMS_TON_ABBREVIATED_NUMBER = 6, /* abbreviated number */
+ SMS_TON_RESERVED_FOR_EXT = 7 /* reserved for extension */
+} bt_sim_type_of_num_t;
+
struct id_info {
guint64 map_id;
int uid;
gchar *remote_addr,
gboolean status,
DBusGMethodInvocation *context);
-
+static gboolean bluetooth_map_destroy_agent(BluetoothMapAgent *agent,
+ DBusGMethodInvocation *context);
#include "bluetooth_map_agent_glue.h"
static void bluetooth_map_agent_init(BluetoothMapAgent *obj)
{
- DBG("+\n");
-
+ FN_START;
g_assert(obj != NULL);
+ FN_END;
}
static void bluetooth_map_agent_finalize(GObject *obj)
{
- DBG("+\n");
-
+ FN_START;
G_OBJECT_CLASS(bluetooth_map_agent_parent_class)->finalize(obj);
+ FN_END;
}
static void bluetooth_map_agent_class_init(BluetoothMapAgentClass *klass)
{
+ FN_START;
GObjectClass *object_class = (GObjectClass *) klass;
g_assert(klass != NULL);
dbus_g_object_type_install_info(BLUETOOTH_MAP_TYPE_AGENT,
&dbus_glib_bluetooth_map_object_info);
+ FN_END;
}
static GQuark __bt_map_agent_error_quark(void)
{
+ FN_START;
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string("agent");
+ FN_END;
return quark;
}
static GError *__bt_map_agent_error(bt_map_agent_error_t error,
const char *err_msg)
{
+ FN_START;
return g_error_new(BT_MAP_AGENT_ERROR, error, err_msg, NULL);
}
-static guint64 _bt_validate_uid(int uid)
+static void __bt_mns_client_event_notify(gchar *event, guint64 handle,
+ gchar *folder, gchar *old_folder,
+ gchar *msg_type);
+
+static char *__bt_get_truncated_utf8_string(char *src)
+{
+ FN_START;
+ char *p = src;
+ char *next;
+ char dest[BT_MAP_SUBJECT_MAX_LEN] = {0,};
+ int count;
+ int i = 0;
+
+ if (src == NULL)
+ return FALSE;
+
+ while (*p != '\0' && i < sizeof(dest)) {
+ next = g_utf8_next_char(p);
+ count = next - p;
+
+ while (count > 0 && ((i + count) < sizeof(dest))) {
+ dest[i++] = *p;
+ p++;
+ count --;
+ }
+ p = next;
+ }
+
+ FN_END;
+ return g_strdup(dest);
+}
+
+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);
+ FN_START;
+ 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;
- }
- }
+ if (info->uid == uid) {
+ DBG("uid = %d\n", uid);
+ return info->map_id;
+ }
+ }
- return 0;
+ FN_END;
+ 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;
+ FN_START;
+ static guint64 map_id;
+ struct id_info *info;
+ guint64 test;
- test = _bt_validate_uid(uid);
- DBG("test: %llx\n", test);
- if (test)
- return test;
+ DBG("Add id: %d\n", uid);
+ test = __bt_validate_uid(uid);
+ DBG("test: %llx\n", test);
+ if (test)
+ return test;
- info = g_new0(struct id_info, 1);
+ info = g_new0(struct id_info, 1);
- map_id++;
+ map_id++;
- info->map_id = map_id;
- info->uid = uid;
- DBG("map_id = %llx, uid = %d \n", info->map_id, info->uid);
+ 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);
+ id_list = g_slist_append(id_list, info);
- return map_id;
+ FN_END;
+ return map_id;
}
static int __bt_get_id(guint64 map_id)
{
- DBG("get id\n");
- struct id_info *info;
- int count;
+ FN_START;
+ struct id_info *info;
+ int count;
int i;
- count = g_slist_length(id_list);
+ count = g_slist_length(id_list);
- for (i = 0; i < count; i++) {
- info = (struct id_info *)g_slist_nth_data(id_list, i);
+ 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;
- }
+ if (info->map_id == map_id)
+ return info->uid;
+ }
- return -1;
+ FN_END;
+ return -1;
}
static int __bt_get_uid(gchar *handle)
{
+ FN_START;
guint64 map_id;
int uid;
uid = __bt_get_id(map_id);
+ FN_END;
return uid;
}
static int __bt_update_id(guint64 map_id, int new_uid)
{
- DBG("update id\n");
+ FN_START;
struct id_info *info;
int i;
int count;
}
}
- return -1;
+ FN_END;
+ return -1;
}
static void __bt_remove_list(GSList *id_list)
{
+ FN_START;
if (!id_list)
return;
- DBG("Removing id list\n");
- g_slist_free_full(id_list, g_free);
+ DBG("Removing id list\n");
+ g_slist_free_full(id_list, g_free);
+ FN_END;
+}
+
+static int __bt_get_folder_id(char *folder_path)
+{
+ FN_START;
+ int folder_id = -1;
+ int i;
+ char *folder;
+ msg_struct_list_s folder_list = {0,};
+ msg_error_t err;
+ msg_struct_t p_folder;
+ DBG_SECURE("folder_path %s\n", folder_path);
+
+ folder = strrchr(folder_path, '/');
+ if (NULL == folder)
+ folder = folder_path;
+ else
+ folder++;
+
+ err = msg_get_folder_list(g_msg_handle, &folder_list);
+ if (err != MSG_SUCCESS)
+ goto done;
+
+ for (i = 0; i < folder_list.nCount; i++) {
+ char folder_name[BT_MAP_MSG_INFO_MAX] = {0, };
+
+ p_folder = folder_list.msg_struct_info[i];
+
+ 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_SECURE("folder_name %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)
+ goto done;
+
+ DBG("folder_id %d", folder_id);
+ break;
+ }
+ }
+
+done:
+ if (folder_list.msg_struct_info)
+ msg_release_list_struct(&folder_list);
+
+ FN_END;
+ return folder_id;
+
}
+static void __bt_add_deleted_folder(void)
+{
+ FN_START;
+ msg_error_t err;
+ msg_struct_t folder_info = msg_create_struct(MSG_STRUCT_FOLDER_INFO);
+
+ err = msg_set_int_value(folder_info, MSG_FOLDER_INFO_TYPE_INT,
+ MSG_FOLDER_TYPE_USER_DEF);
+ if (err != MSG_SUCCESS) {
+ ERR("Failed adding type %d", err);
+ msg_release_struct(&folder_info);
+ return;
+ }
+
+ err = msg_set_str_value(folder_info, MSG_FOLDER_INFO_NAME_STR,
+ "DELETED", MAX_FOLDER_NAME_SIZE);
+ if (err != MSG_SUCCESS) {
+ ERR("Failed adding str %d", err);
+ msg_release_struct(&folder_info);
+ return;
+ }
+
+ err = msg_add_folder(g_msg_handle, folder_info);
+ if (err != MSG_SUCCESS) {
+ ERR("Failed adding folder %d", err);
+ msg_release_struct(&folder_info);
+ return;
+ }
+
+ msg_release_struct(&folder_info);
+ FN_END;
+}
static gchar *__bt_get_folder_name(int id)
{
+ FN_START;
int ret;
+ int i;
+ int folder_id;
+ gboolean path_found = FALSE;
char folder_name[BT_MAP_MSG_INFO_MAX] = {0,};
- msg_struct_list_s g_folderList;
+ msg_struct_list_s folder_list = {0,};
msg_struct_t p_folder;
- ret = msg_get_folder_list(g_msg_handle, &g_folderList);
+ ret = msg_get_folder_list(g_msg_handle, &folder_list);
if (ret != MSG_SUCCESS)
- goto done;
+ return g_strdup("TELECOM/MSG");
+
+ if (folder_list.msg_struct_info == NULL)
+ return g_strdup("TELECOM/MSG");
- p_folder = g_folderList.msg_struct_info[id];
+ for (i = 0; i < folder_list.nCount; i++) {
+ p_folder = folder_list.msg_struct_info[i];
- ret = msg_get_str_value(p_folder, MSG_FOLDER_INFO_NAME_STR,
+ ret = msg_get_int_value(p_folder,
+ MSG_FOLDER_INFO_ID_INT,
+ &folder_id);
+ if (ret != MSG_SUCCESS)
+ break;
+ DBG("folder_id %d, id = %d", folder_id, id);
+ if (folder_id == 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;
+ if (ret != MSG_SUCCESS)
+ break;
- return g_strdup_printf("TELECOM/MSG/%s", folder_name);
+ path_found = TRUE;
+ DBG_SECURE("folder_name %s", folder_name);
+ break;
+ }
+ }
-done:
- return g_strdup("TELECOM/MSG");
+ if (folder_list.msg_struct_info) {
+ ret = msg_release_list_struct(&folder_list);
+ ERR("Err %d", ret);
+ }
+
+ FN_END;
+ if (path_found != TRUE)
+ return g_strdup("TELECOM/MSG");
+ else
+ return g_strdup_printf("TELECOM/MSG/%s", folder_name);
}
static void __get_msg_timestamp(time_t *ltime, char *timestamp)
{
+ FN_START;
struct tm local_time;
int year;
int month;
local_time.tm_mday, local_time.tm_hour,
local_time.tm_min, local_time.tm_sec);
+ FN_END;
return;
}
+#define SET_TON_NPI(dest, ton, npi) { \
+ dest = 0x80; \
+ dest |= (ton & 0x07) << 4; \
+ dest |= npi & 0x0F; \
+}
+
+static int __bt_ascii_to_upper(int ch)
+{
+ return (('a' <= (ch) && (ch) <= 'z') ? ((ch) - ('a'-'A')) : (ch));
+}
+
+static int __bt_sms_pack_gsm_code(gchar *p_out, const char *data, int in_len)
+{
+ FN_START;
+ int i;
+ int pos;
+ int shift = 0;
+
+ for (pos = 0, i = 0; i < in_len; pos++, i++) {
+ /* pack the low bits */
+ p_out[pos] = data[i] >> shift;
+
+ if (i + 1 < in_len) {
+ /* pack the high bits using the low bits
+ of the next character */
+ p_out[pos] |= data[i+1] << (7 - shift);
+
+ shift++;
+
+ if (shift == 7) {
+ shift = 0;
+ i++;
+ }
+ }
+ }
+
+ FN_END;
+ return pos;
+}
+
+static void __bt_sms_conv_digit_to_bcd(gchar *p_bcd, char *p_digits, int digit_len)
+{
+ FN_START;
+ int i;
+ int j;
+ int digit;
+ unsigned char higher;
+ unsigned char lower;
+
+ if (p_bcd == NULL || p_digits == NULL)
+ return;
+
+ /* 0123456789 -> 1032547698 */
+ for (i = 0, j = 0; i < digit_len; i = i + 2, j++) {
+ if (p_digits[i] == '*')
+ digit = 0x0A;
+ else if (p_digits[i] == '#')
+ digit = 0x0B;
+ else if (__bt_ascii_to_upper(p_digits[i]) == 'P')
+ digit = 0x0C;
+ else
+ digit = (int) (p_digits[i] - '0');
+
+ lower = digit & 0x0F;
+
+ if (digit_len != i + 1) {
+ if (p_digits[i+1] == '*')
+ digit = 0x0A;
+ else if (p_digits[i+1] == '#')
+ digit = 0x0B;
+ else if (__bt_ascii_to_upper(p_digits[i+1]) == 'P')
+ digit = 0x0C;
+ else
+ digit = (int) (p_digits[i+1] - '0');
+
+ higher = digit & 0x0F;
+ } else {
+ higher = 0xFF;
+ }
+
+ p_bcd[j] = (higher << 4) | lower;
+ }
+ FN_END;
+}
+
+static int __bt_sms_encode_addr(gchar *addr_field, char *dial_num,
+ int dial_num_len, int ton, int npi)
+{
+ FN_START;
+ int index = 0;
+
+ if (dial_num == NULL || addr_field == NULL)
+ return -1;
+
+ if (dial_num[0] == '+') {
+ dial_num++;
+ dial_num_len--;
+ ton = SMS_TON_INTERNATIONAL;
+ }
+
+ if (ton != SMS_TON_ALPHA_NUMERIC) {
+ /* Origination address length address length */
+ addr_field[index++] = (unsigned char)dial_num_len;
+ } else {
+ addr_field[index] = (unsigned char)
+ (((dial_num_len * 7 + 7) / 8) * 2);
+
+ if (((dial_num_len * 7) % 8) <= 4)
+ addr_field[index]--;
+
+ index++;
+ }
+
+ SET_TON_NPI(addr_field[index], ton, npi);
+ index++; /* SET_TON_NPI */
+
+ if (ton != SMS_TON_ALPHA_NUMERIC) {
+ __bt_sms_conv_digit_to_bcd(&addr_field[index],
+ (char *)dial_num, dial_num_len);
+
+ if (dial_num_len % 2)
+ index += (dial_num_len / 2) + 1;
+ else
+ index += dial_num_len / 2;
+ } else {
+ index += __bt_sms_pack_gsm_code(&addr_field[index],
+ dial_num, (int)dial_num_len);
+ }
+
+ FN_END;
+ return index;
+}
+
+static int __bt_sms_encode_time(gchar *addr_field, time_t *tm)
+{
+ FN_START;
+ int index = 0;
+ struct tm ltime;
+ int year;
+ int month;
+
+ if (!localtime_r(tm, <ime))
+ return index;
+
+ year = ltime.tm_year + 1900; /* years since 1900 */
+ year = year % 100;
+ month = ltime.tm_mon + 1; /* months since January */
+
+ addr_field[index++] = ((year % 10) << 4) + (year / 10);
+ addr_field[index++] = ((month % 10) << 4) + (month / 10);
+ addr_field[index++] = ((ltime.tm_mday % 10) << 4) +
+ (ltime.tm_mday / 10);
+ addr_field[index++] = ((ltime.tm_hour % 10) << 4) +
+ (ltime.tm_hour / 10);
+ addr_field[index++] = ((ltime.tm_min % 10) << 4) + (ltime.tm_min / 10);
+ addr_field[index++] = ((ltime.tm_sec % 10) << 4) + (ltime.tm_sec / 10);
+ addr_field[index] = 0x00;
+
+ FN_END;
+ return index;
+}
+
+static gchar *__bt_get_sms_pdu_from_msg_data(gchar *number,
+ char *msg, time_t tm,
+ int *msg_pdu_len)
+{
+ FN_START;
+ gchar packet[TAPI_NETTEXT_MSG_SIZE_MAX] = {0,};
+ int index = 0;
+
+ packet[index] = 0x00; /* Since SCA is unknown for stored messages */
+ index++;
+
+ /* TP-MTI : Type of message */
+ packet[index] = 0x00; /* SMS-DELIVER PDU */
+
+ /* TP-MMS bit is set to 1 as we support only SMS */
+ packet[index] |= 0x04;
+ index++;
+
+ /* TP-OA : Mobile originating address */
+ index += __bt_sms_encode_addr(packet+index,
+ number, strlen(number),
+ g_sca_info->Ton, g_sca_info->Npi);
+
+ /* TP-PID : Since we use only SMS so set to 0 */
+ packet[index++] = 0x00;
+
+ /* TP-DCS : Data Coding Scheme, default value set */
+ packet[index++] = 0x00;
+
+ /* TP-SCTS : Message timestamp */
+ index += __bt_sms_encode_time(packet+index, &tm);
+ index++;
+ /* TP-UDL : Message body length */
+ packet[index++] = strlen(msg);
+
+ /* TP-UD : Message body */
+ index += __bt_sms_pack_gsm_code(packet + index, msg, strlen(msg));
+
+ *msg_pdu_len = index;
+
+ FN_END;
+ return g_memdup(packet, index);
+}
+
+static void __bt_get_sms_sca(TapiHandle *handle, int result, void *data,
+ void *user_data)
+{
+ FN_START;
+ TelSmsAddressInfo_t *scaInfo = data;
+
+ DBG("__bt_get_sms_sca 0x%x", result);
+
+ if (data == NULL) {
+ g_sca_info = g_malloc0(sizeof(TelSmsAddressInfo_t));
+ g_sca_info->Ton = 0;
+ g_sca_info->Npi = 0;
+ g_sca_info->DialNumLen = 0;
+ return;
+ }
+
+ g_sca_info = g_malloc0(sizeof(TelSmsAddressInfo_t));
+ g_sca_info->Ton = scaInfo->Ton;
+ g_sca_info->Npi = scaInfo->Npi;
+ g_sca_info->DialNumLen = scaInfo->DialNumLen;
+ FN_END;
+}
+
static char *__bt_prepare_msg_bmseg(msg_struct_t msg_info, gboolean attach,
gboolean transcode)
{
+ FN_START;
int ret;
int m_type = MSG_TYPE_SMS;
int folder_id;
int count;
+ int dptime = 0;
+ int j;
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;
+ char name_value[MAX_DISPLAY_NAME_LEN] = {0,};
+
+ msg_list_handle_t addr_list = NULL;
+ msg_struct_t addr_info = NULL;
- msg_struct_list_s *addr_list = NULL;
GString *msg;
+ gchar *folder_path = NULL;
+ gchar *msg_pdu;
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);
+ INFO("read_status %d\n", read_status);
}
if (read_status)
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:
+ INFO("m_type %d\n", m_type);
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);
+ 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);
+ ret = msg_get_list_handle(msg_info, MSG_MESSAGE_ADDR_LIST_HND,
+ (void **)&addr_list);
if (ret == MSG_SUCCESS) {
- count = addr_list->nCount;
+ count = msg_list_length(addr_list);
DBG("count %d \n", count);
- while (count > 0) {
- msg_struct_t addr_info = NULL;
- addr_info = addr_list->msg_struct_info[count - 1];
+
+ if (count > 0) {
+ addr_info = (msg_struct_t)msg_list_nth_data(addr_list,
+ 0);
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);
+ DBG_SECURE("addr_value %s\n", addr_value);
msg_get_str_value(addr_info,
MSG_ADDRESS_INFO_DISPLAYNAME_STR,
- name_value, MAX_ADDRESS_VAL_LEN);
+ name_value, MAX_DISPLAY_NAME_LEN);
if (!strlen(name_value))
g_stpcpy(name_value, addr_value);
- DBG("name_value %s\n", name_value);
+ DBG_SECURE("name_value %s\n", name_value);
g_string_append_printf(msg, VCARD, name_value,
addr_value);
- count--;
}
}
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);
+ 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);
+
+ msg_get_int_value(msg_info,
+ MSG_MESSAGE_DISPLAY_TIME_INT, &dptime);
+
+ ret = msg_get_str_value(msg_info, MSG_MESSAGE_SMS_DATA_STR,
+ msg_body, BT_MAP_MSG_BODY_MAX);
+ if (ret == MSG_SUCCESS) {
+ int msg_pdu_len = 0;
+ msg_pdu = __bt_get_sms_pdu_from_msg_data(addr_value,
+ msg_body, dptime,
+ &msg_pdu_len);
+ if (msg_pdu) {
+ DBG("msg_pdu_len = %d", msg_pdu_len);
+
+ g_string_append_printf(msg, LENGTH, msg_pdu_len);
+ g_string_append(msg, MSG_BODY_BEGIN);
+ for (j = 0; j < msg_pdu_len; j++)
+ g_string_append_printf(msg, "%02x",
+ msg_pdu[j]);
+
+ g_string_append(msg, MSG_BODY_END);
+ g_free(msg_pdu);
+ }
+ }
}
g_string_append(msg, END_BBODY);
g_string_append(msg, END_BENV);
g_string_append(msg, END_BMSEG);
+ g_free(folder_path);
+ FN_END;
return g_string_free(msg, FALSE);
}
static void __bt_message_info_free(struct message_info msg_info)
{
+ FN_START;
g_free(msg_info.handle);
g_free(msg_info.subject);
g_free(msg_info.datetime);
g_free(msg_info.reception_status);
g_free(msg_info.size);
g_free(msg_info.attachment_size);
+ FN_END;
}
static struct message_info __bt_message_info_get(msg_struct_t msg_struct_handle)
{
+ FN_START;
struct message_info msg_info = {0,};
int ret;
int msg_id;
int data_size;
int priority;
int direction_type;
+ int count;
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,};
+ char name_value[MAX_DISPLAY_NAME_LEN] = {0,};
msg_info.text = FALSE;
msg_info.protect = FALSE;
msg_struct_t msg = NULL;
msg_struct_t send_opt = NULL;
- msg_struct_list_s *addr_list = NULL;
+ msg_list_handle_t addr_list = NULL;
msg_struct_t addr_info = NULL;
ret = msg_get_int_value(msg_struct_handle, MSG_MESSAGE_ID_INT, &msg_id);
msg_info.handle = g_strdup(msg_handle);
msg = msg_create_struct(MSG_STRUCT_MESSAGE_INFO);
+ if (msg == NULL)
+ goto next;
+
send_opt = msg_create_struct(MSG_STRUCT_SENDOPT);
+ if (send_opt == NULL)
+ goto next;
ret = msg_get_message(g_msg_handle,
(msg_message_id_t)msg_id,
goto next;
}
- ret = msg_get_list_handle(msg, MSG_MESSAGE_ADDR_LIST_STRUCT,
+ ret = msg_get_list_handle(msg, MSG_MESSAGE_ADDR_LIST_HND,
(void **)&addr_list);
if (ret != MSG_SUCCESS) {
DBG("ret = %d\n", ret);
goto next;
}
- addr_info = addr_list->msg_struct_info[0];
+ count = msg_list_length(addr_list);
- 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);
+ if (count != 0) {
+ addr_info = (msg_struct_t)msg_list_nth_data(addr_list, 0);
- 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);
+ ret = msg_get_str_value(addr_info,
+ MSG_ADDRESS_INFO_ADDRESS_VALUE_STR,
+ addr_value, MAX_ADDRESS_VAL_LEN);
+ if (ret == MSG_SUCCESS)
+ DBG_SECURE("addr_value %s\n", addr_value);
- if (!strlen(name_value))
- g_stpcpy(name_value, addr_value);
+ ret = msg_get_str_value(addr_info,
+ MSG_ADDRESS_INFO_DISPLAYNAME_STR,
+ name_value, MAX_DISPLAY_NAME_LEN);
+
+ if (ret == MSG_SUCCESS)
+ DBG_SECURE("name_value %s\n", name_value);
- DBG("name_value %s\n", name_value);
+ if (!strlen(name_value))
+ g_stpcpy(name_value, addr_value);
+
+ DBG_SECURE("name_value %s\n", name_value);
+ }
- ret = msg_get_int_value(msg, MSG_MESSAGE_DIRECTION_INT, &direction_type);
+ ret = msg_get_int_value(msg, MSG_MESSAGE_DIRECTION_INT,
+ &direction_type);
if (ret != MSG_SUCCESS)
goto next;
msg_release_struct(&msg);
msg_release_struct(&send_opt);
- ret = msg_get_int_value(msg_struct_handle, MSG_MESSAGE_DISPLAY_TIME_INT, &dptime);
+ g_free(msg_info.handle);
+
+ 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);
}
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);
+ msg_info.type = g_strdup("SMS_GSM");
- 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_str_value(msg_struct_handle,
+ MSG_MESSAGE_SMS_DATA_STR, msg_body,
+ BT_MAP_MSG_BODY_MAX);
+ if (ret == MSG_SUCCESS) {
+ DBG_SECURE("SMS subject %s", msg_body);
+ if (strlen(msg_body)) {
+ msg_info.text = TRUE ;
+ msg_info.subject = __bt_get_truncated_utf8_string(msg_body);
}
}
msg_info.priority = TRUE;
}
+ FN_END;
return msg_info;
}
msg_struct_t msg,
void *user_param)
{
- DBusGProxy *mns_proxy;
- GError *error = NULL;
-
+ FN_START;
int msg_id = 0;
int msg_type = 0;
- int ret = MSG_SUCCESS;
-
- char *message_type = NULL;
+ int ret;
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);
+ if (!g_mns_proxy) {
+ INFO("MNS Client not connected");
+ return;
+ }
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);
+ if (msg_type != MSG_TYPE_SMS) {
+ INFO("Not a SMS");
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);
+ ret = msg_get_int_value(msg, MSG_MESSAGE_ID_INT, &msg_id);
+ if (ret != MSG_SUCCESS)
+ return;;
+
+ uid = __bt_add_id(msg_id);
+
+ __bt_mns_client_event_notify("NewMessage", uid,
+ "TELECOM/MSG/INBOX", "",
+ "SMS_GSM");
+
+ FN_END;
+ return;
+}
+
+static void __bluetooth_map_msg_sent_status_cb(msg_handle_t handle,
+ msg_struct_t msg,
+ void *user_param)
+{
+ FN_START;
+ int ret;
+ int status;
+
+ if (!g_mns_proxy) {
+ INFO("MNS Client not connected");
+ return;
}
- DBG("-\n");
- g_free(message_type);
- g_object_unref(mns_proxy);
+ ret = msg_get_int_value(msg, MSG_SENT_STATUS_NETWORK_STATUS_INT,
+ &status);
+ if (ret != MSG_SUCCESS)
+ return;
+
+ if (status == MSG_NETWORK_SEND_SUCCESS) {
+ INFO("MSG SENT SUCCESS !!! ");
+ __bt_mns_client_event_notify("MessageShift",
+ current_push_map_id,
+ "TELECOM/MSG/SENT",
+ "TELECOM/MSG/OUTBOX",
+ "SMS_GSM");
+
+ __bt_mns_client_event_notify("SendingSuccess",
+ current_push_map_id,
+ "TELECOM/MSG/SENT", "",
+ "SMS_GSM");
+ } else {
+ ERR("MSG SENT FAIL !!! [%d]", status);
+ __bt_mns_client_event_notify("SendingFailure",
+ current_push_map_id,
+ "TELECOM/MSG/OUTBOX", "",
+ "SMS_GSM");
+ }
+
+ FN_END;
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
+ FN_START;
+ msg_error_t err;
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;
+ return FALSE;
}
+ if (-1 == __bt_get_folder_id(BT_MAP_DELETED_FOLDER_NAME))
+ __bt_add_deleted_folder();
+
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;
+ return FALSE;
}
- if (msg_ret || email_ret)
- return TRUE;
- else
+ err = msg_reg_sent_status_callback(g_msg_handle,
+ __bluetooth_map_msg_sent_status_cb,
+ NULL);
+ if (err != MSG_SUCCESS) {
+ ERR("msg_reg_sent_status_callback error = %d\n", err);
return FALSE;
+ }
-#else
-
- return msg_ret;
-
-#endif
+ FN_END;
+ return TRUE;
}
static void __bluetooth_map_stop_service()
{
+ FN_START;
+ msg_error_t err = MSG_SUCCESS;
+ int folder_id;
+
+ folder_id = __bt_get_folder_id(BT_MAP_DELETED_FOLDER_NAME);
+ if (-1 != folder_id) {
+ err = msg_delete_folder(g_msg_handle, folder_id);
+ if (err != MSG_SUCCESS)
+ ERR("Delete folder failed");
+ }
+
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
+ FN_END;
return;
}
-#ifdef SUPPORT_EMAIL
-static int __bt_store_mail(email_mailbox_type_e type, char *subject,
- char *body, char *recepients)
+static gboolean __bt_validate_utf8(char **text)
{
- 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;
+ FN_START;
+ if (g_utf8_validate(*text, -1, NULL))
+ return TRUE;
-fail:
- return 0;
+ FN_END;
+ return FALSE;
}
-static int __bt_email_send(char *subject, char *body, char* recepients)
+static gboolean __bt_validate_msg_data(struct message_info *msg_info)
{
- 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);
- }
+ FN_START;
+ if (msg_info == NULL)
+ return FALSE;
- return mail_id;
-}
-#endif
+ if (msg_info->subject)
+ return __bt_validate_utf8(&msg_info->subject);
-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");
+ if (msg_info->sender_name)
+ return __bt_validate_utf8(&msg_info->sender_name);
- folder = strrchr(folder_path, '/');
- if (NULL == folder)
- return -1;
-
- folder++;
+ if (msg_info->sender_addressing)
+ return __bt_validate_utf8(&msg_info->sender_addressing);
- DBG("folderName %s\n", folder);
+ if (msg_info->replyto_addressing)
+ return __bt_validate_utf8(&msg_info->replyto_addressing);
- err = msg_get_folder_list(g_msg_handle, &folder_list);
- if (err != MSG_SUCCESS)
- return -1;
+ if (msg_info->recipient_name)
+ return __bt_validate_utf8(&msg_info->recipient_name);
- 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;
+ if (msg_info->recipient_addressing)
+ return __bt_validate_utf8(&msg_info->recipient_addressing);
+ FN_END;
+ return TRUE;
}
-msg_error_t __bt_send_sms(int msg_id, msg_struct_t pMsg, msg_struct_t pSendOpt)
+msg_error_t __bt_send_sms(int msg_id, msg_struct_t p_msg, msg_struct_t p_send_opt)
{
+ FN_START;
msg_error_t err;
- msg_struct_t pReq;
+ msg_struct_t p_req;
- pReq = msg_create_struct(MSG_STRUCT_REQUEST_INFO);
+ p_req = 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);
+ msg_set_int_value(p_msg, MSG_MESSAGE_ID_INT, msg_id);
+ msg_set_struct_handle(p_req, MSG_REQUEST_MESSAGE_HND, p_msg);
+ msg_set_struct_handle(p_req, MSG_REQUEST_SENDOPT_HND, p_send_opt);
- 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);
+ err = msg_sms_send_message(g_msg_handle, p_req);
+ if (err != MSG_SUCCESS)
+ ERR("Failed msg_sms_send_message %d", err);
- msg_release_struct(&pReq);
+ msg_release_struct(&p_req);
+ FN_END;
return err;
}
static int __bt_push_sms(gboolean send, int folder_id, char *body,
GSList *recepients)
{
- DBG("+ \n");
+ FN_START;
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;
+ int msg_id = -1;
msg_info = msg_create_struct(MSG_STRUCT_MESSAGE_INFO);
if (msg_info == NULL)
goto fail;
if (body) {
- err = msg_set_str_value(msg_info, MSG_MESSAGE_SMS_DATA_STR, body,
- strlen(body));
+ err = msg_set_str_value(msg_info,
+ MSG_MESSAGE_SMS_DATA_STR,
+ body, strlen(body));
if (err != MSG_SUCCESS)
goto fail;
} else {
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++) {
+ msg_struct_t tmp_addr;
char *address = (char *)g_slist_nth_data(recepients, i);
if (address == NULL) {
- DBG("[ERROR] address is value NULL, skip");
+ ERR("[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_list_add_item(msg_info,
+ MSG_MESSAGE_ADDR_LIST_HND, &tmp_addr);
- msg_set_int_value(addr_list->msg_struct_info[i],
- MSG_ADDRESS_INFO_RECIPIENT_TYPE_INT,
- MSG_RECIPIENTS_TYPE_TO);
+ msg_set_int_value(tmp_addr,
+ 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));
+ msg_set_str_value(tmp_addr,
+ MSG_ADDRESS_INFO_ADDRESS_VALUE_STR,
+ address, strlen(address));
}
}
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;
- }
- }
+ if (send == TRUE)
+ __bt_send_sms(msg_id, msg_info, send_opt);
+
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;
+ FN_END;
+ return msg_id;
}
static void __bt_mns_client_connect(char *address)
{
- DBusGProxy *mns_proxy;
+ FN_START;
GHashTable *hash;
- GValue *addr_value;
GValue *tgt_value;
GError *error = NULL;
const char *session_path = NULL;
- DBG("+ address %s\n", address);
+ if (g_mns_proxy) {
+ DBG_SECURE("MNS Client already connected to %s", address);
+ return;
+ }
- mns_proxy = dbus_g_proxy_new_for_name(g_connection, OBEX_CLIENT_SERVICE,
+ g_mns_proxy = dbus_g_proxy_new_for_name(g_connection,
+ OBEX_CLIENT_SERVICE,
OBEX_CLIENT_PATH,
OBEX_CLIENT_INTERFACE);
- if (mns_proxy == NULL) {
+ if (!g_mns_proxy) {
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_proxy_call(g_mns_proxy, "CreateSession", &error,
+ G_TYPE_STRING,address,
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);
+ ERR("Error [%s]", error->message);
g_error_free(error);
g_hash_table_destroy(hash);
- g_object_unref(mns_proxy);
+ g_object_unref(g_mns_proxy);
+ g_mns_proxy = NULL;
return;
}
DBG("g_mns_path = %s\n", g_mns_path);
g_hash_table_destroy(hash);
- g_object_unref(mns_proxy);
- DBG("-\n");
+ FN_END;
return;
}
static void __bt_mns_client_disconnect()
{
- DBusGProxy *mns_proxy;
+ FN_START;
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");
+ if (!g_mns_proxy) {
+ ERR("No proxy to disconnect");
return;
}
- dbus_g_proxy_call(mns_proxy, "RemoveSession", &error,
+ dbus_g_proxy_call(g_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);
+ ERR("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);
+ g_object_unref(g_mns_proxy);
+ g_mns_proxy = NULL;
- DBG("-\n");
+ FN_END;
return;
}
+static void __bt_mns_client_event_notify(gchar *event, guint64 handle,
+ gchar *folder, gchar *old_folder,
+ gchar *msg_type)
+{
+ FN_START;
+ GError *error = NULL;
+ DBusGProxy *mns_proxy;
+
+ if (!g_mns_proxy) {
+ ERR("No client proxy");
+ 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");
+ return;
+ }
+
+ dbus_g_proxy_call(mns_proxy, "SendEvent", &error,
+ G_TYPE_STRING, event,
+ G_TYPE_UINT64, handle,
+ G_TYPE_STRING, folder,
+ G_TYPE_STRING, old_folder,
+ G_TYPE_STRING, msg_type,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ if (error) {
+ ERR("Error [%s]", error->message);
+ g_error_free(error);
+ }
+
+ g_object_unref(mns_proxy);
+ FN_END;
+}
+
static gboolean bluetooth_map_get_folder_tree(BluetoothMapAgent *agent,
DBusGMethodInvocation *context)
{
+ FN_START;
GPtrArray *array = g_ptr_array_new();
GValue value;
GError *error = NULL;
int ret;
gboolean msg_ret = TRUE;
- msg_struct_list_s g_folderList;
+ msg_struct_list_s folder_list = {0,};
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) {
+ if (msg_get_folder_list(g_msg_handle, &folder_list) != MSG_SUCCESS) {
msg_ret = FALSE;
goto done;
}
- for (i = 0; i < g_folderList.nCount; i++) {
- p_folder = g_folderList.msg_struct_info[i];
+ for (i = 0; i < folder_list.nCount; i++) {
+ p_folder = folder_list.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,
if (ret != MSG_SUCCESS)
continue;
+ if (g_strstr_len(folder_name, -1, BT_MAP_MSG_TEMPLATE))
+ 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_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 (folder_list.msg_struct_info)
+ msg_release_list_struct(&folder_list);
+
if (msg_ret == FALSE) {
g_ptr_array_free(array, TRUE);
} else {
dbus_g_method_return(context, array);
g_ptr_array_free(array, TRUE);
+ FN_END;
return TRUE;
}
}
gchar *folder_name, guint16 max,
DBusGMethodInvocation *context)
{
+ FN_START;
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
+ int folder_id = -1;
+ int folder_len;
+ bool read;
+ guint64 count = 0;
+ gboolean newmsg = FALSE;
+
+ msg_struct_list_s folder_list = {0,};
+ msg_struct_list_s msg_list = {0,};
+ msg_struct_t list_cond;
if (g_msg_handle == NULL)
goto fail;
+ if (!folder_name)
+ goto fail;
+
+ folder_len = strlen(folder_name);
+ /* In case of parent folders send empty message listing */
+ if (!g_ascii_strncasecmp(folder_name, "/", folder_len) ||
+ !g_ascii_strncasecmp(folder_name, "/telecom", folder_len) ||
+ !g_ascii_strncasecmp(folder_name, "/telecom/msg", folder_len))
+ goto done;
+
folder = strrchr(folder_name, '/');
if (NULL == folder)
folder = folder_name;
else
folder++;
- ret = msg_get_folder_list(g_msg_handle, &g_folderList);
+ ret = msg_get_folder_list(g_msg_handle, &folder_list);
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, };
+ for (i = 0; i < folder_list.nCount; i++) {
+ char f_name[BT_MAP_MSG_INFO_MAX] = {0, };
+ msg_struct_t p_folder = folder_list.msg_struct_info[i];
- ret = msg_get_str_value(pFolder, MSG_FOLDER_INFO_NAME_STR,
- folderName, BT_MAP_MSG_INFO_MAX);
+ ret = msg_get_str_value(p_folder, MSG_FOLDER_INFO_NAME_STR,
+ f_name, 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,
+ if (!g_ascii_strncasecmp(f_name, folder, strlen(folder))) {
+ ret = msg_get_int_value(p_folder, MSG_FOLDER_INFO_ID_INT,
&folder_id);
if (ret != MSG_SUCCESS)
goto fail;
- else
- DBG("folder_id %d \n", folder_id);
+
+ 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)
+ if (folder_id == -1)
goto fail;
- count = msg_list.nCount;
+ list_cond = msg_create_struct(MSG_STRUCT_MSG_LIST_CONDITION);
+ ret = msg_set_int_value(list_cond,
+ MSG_LIST_CONDITION_FOLDER_ID_INT,
+ folder_id);
+ if (ret != MSG_SUCCESS)
+ goto fail;
- 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);
+ ret = msg_set_int_value(list_cond,
+ MSG_LIST_CONDITION_MSGTYPE_INT, MSG_TYPE_SMS);
+ if (ret != MSG_SUCCESS)
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);
+ ret = msg_get_message_list2(g_msg_handle, list_cond, &msg_list);
+
+ msg_release_struct(&list_cond);
+
+ if (ret != MSG_SUCCESS)
goto fail;
- }
- if (unread_cnt != 0)
- newmsg = TRUE;
- else
- newmsg = FALSE;
+ count = msg_list.nCount;
- msg_release_struct(&count_info);
+ for (i = 0; i < count; i++) {
+ msg_get_bool_value(msg_list.msg_struct_info[i],
+ MSG_MESSAGE_READ_BOOL, &read);
+ if (read == false) {
+ newmsg = TRUE;
+ break;
+ }
+ }
+
+ DBG("count = %llx, newmsg = %d, max = %d", count, newmsg, max);
- DBG("MaxlistCount %d \n", max);
if (max == 0)
goto done;
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);
-*/
+ if (!__bt_validate_msg_data(&msg_info)) {
+ __bt_message_info_free(msg_info);
+ count--;
+ continue;
+ }
dbus_g_type_struct_set(&value, 0, msg_info.handle,
1, msg_info.subject,
13, msg_info.read,
14, msg_info.sent,
15, msg_info.protect,
- 16, msg_info.replyto_addressing, G_MAXUINT);
+ 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);
+done:
+ if (folder_list.msg_struct_info)
+ ret = msg_release_list_struct(&folder_list);
- g_free(filter_list);
- g_free(sorting_rule_list);
- g_free(type);
-#endif
+ if (msg_list.msg_struct_info)
+ ret = msg_release_list_struct(&msg_list);
-done:
- DBG("Request completed \n");
dbus_g_method_return(context, newmsg, count, array);
g_ptr_array_free(array, TRUE);
- DBG("Request completed successfully \n");
+ FN_END;
return TRUE;
fail:
+ if (folder_list.msg_struct_info)
+ ret = msg_release_list_struct(&folder_list);
+
+ if (msg_list.msg_struct_info)
+ ret = msg_release_list_struct(&msg_list);
+
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);
+ ERR("fail -");
return FALSE;
}
gboolean first_request,
DBusGMethodInvocation *context)
{
- DBG("+ \n");
+ FN_START;
char *buf = NULL;
int message_id = 0;
- int msg_type = BT_SMS;
GError *error = NULL;
+ msg_error_t msg_err;
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);
+ if (g_msg_handle == NULL)
+ goto fail;
- fclose(body_file);
+ msg = msg_create_struct(MSG_STRUCT_MESSAGE_INFO);
+ if (!msg)
+ goto fail;
- if (read_size != email_size)
- goto fail;
- } else
- buf = (char *)g_strdup("");
+ send_opt = msg_create_struct(MSG_STRUCT_SENDOPT);
+ if (!send_opt)
+ goto fail;
- email_free_mail_data(&mail_data, 1);
-#endif
- } else {
- DBG("msg_type not supported %d \n", msg_type);
+ 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);
dbus_g_method_return(context, FALSE, buf);
+ msg_release_struct(&msg);
+ msg_release_struct(&send_opt);
g_free(buf);
- DBG("- \n");
+ FN_END;
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);
+ ERR("fail - \n");
return FALSE;
}
gchar *folder_name,
DBusGMethodInvocation *context)
{
- DBG("+\n");
- GError *error = NULL;
+ FN_START;
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;
+ DBG_SECURE("folder_name = %s\n", folder_name);
handle = __bt_add_id(-1);
current_push_map_id = handle;
DBG("opt.native = %d\n", opt.native);
dbus_g_method_return(context, handle);
- DBG("-\n");
+ FN_END;
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");
+ FN_START;
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);
+ INFO("BMSG is \n %s", bmsg);
struct bmsg_data *bmsg_info = NULL;
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);
+ body = bmsg_get_msg_body(bmsg_info, opt.native);
if (body == NULL)
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);
+ bmsg_free_bmsg(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");
+ FN_END;
return FALSE;
}
dbus_g_method_return(context);
- DBG("-\n");
+ FN_END;
return TRUE;
}
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,
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
+ FN_START;
+ int msg_id;
GError *error = NULL;
+ msg_error_t msg_err;
- DBG("+\n");
-
- message_id = __bt_get_uid(handle);
- if (message_id == -1)
+ msg_id = __bt_get_uid(handle);
+ if (msg_id == -1)
goto fail;
- DBG("message_id = %d, read_status = %d\n", message_id, read_status);
+ DBG("msg_id = %d, read_status = %d\n", msg_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
+ msg_err = msg_update_read_status(g_msg_handle, msg_id,
+ read_status);
+ if (msg_err != MSG_SUCCESS)
goto fail;
dbus_g_method_return(context);
- DBG("-\n");
+ FN_END;
return TRUE;
fail:
dbus_g_method_return_error(context, error);
g_error_free(error);
+ ERR("fail -\n");
return FALSE;
}
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
+ FN_START;
+ int msg_id = 0;
+ int folder_id;
+ int del_folder_id;
+ gchar *folder_name = NULL;
+ guint64 map_id;
GError *error = NULL;
+ msg_error_t err;
+ msg_struct_t msg = NULL;
+ msg_struct_t send_opt = NULL;
- DBG("+\n");
+ msg_id = __bt_get_uid(handle);
+ if (msg_id == -1)
+ goto fail;
- message_id = __bt_get_uid(handle);
- if (message_id == -1)
+ if (g_msg_handle == NULL)
goto fail;
- DBG("message_id = %d, delete_status = %d\n", message_id, delete_status);
+ msg = msg_create_struct(MSG_STRUCT_MESSAGE_INFO);
+ if (msg == NULL)
+ goto fail;
- 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) {
+ send_opt = msg_create_struct(MSG_STRUCT_SENDOPT);
+ if (send_opt == NULL)
+ goto fail;
- if (email_get_mail_data(message_id, &mail_data) !=
- EMAIL_ERROR_NONE)
- goto fail;
+ err = msg_get_message(g_msg_handle,
+ (msg_message_id_t)msg_id,
+ msg, send_opt);
+ if (err != MSG_SUCCESS)
+ 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;
+ err = msg_get_int_value(msg, MSG_MESSAGE_FOLDER_ID_INT,
+ &folder_id);
+ if (err != MSG_SUCCESS)
+ goto fail;
+
+ folder_name = __bt_get_folder_name(folder_id);
+ del_folder_id = __bt_get_folder_id(BT_MAP_DELETED_FOLDER_NAME);
+ map_id = __bt_validate_uid(msg_id);
+
+ DBG("msg_id = %d, delete_status = %d\n", msg_id, delete_status);
+
+ if (-1 == del_folder_id) {
+ ERR("Delete folder not present");
+ if (delete_status == TRUE) {
+ err = msg_delete_message(g_msg_handle, msg_id);
+ if (err != MSG_SUCCESS)
+ goto fail;
}
- email_free_mail_data(&mail_data, 1);
-#endif
- } else
- goto fail;
+ } else {
+ if (delete_status == TRUE) {
+ err = msg_move_msg_to_folder(g_msg_handle, msg_id, del_folder_id);
+ if (err == MSG_SUCCESS) {
+ __bt_mns_client_event_notify("MessageShift",
+ map_id,
+ "TELECOM/MSG/DELETED",
+ folder_name,
+ "SMS_GSM");
+ }
+ } else {
+ if (folder_id != del_folder_id) {
+ DBG("Message not in delete folder");
+ goto fail;
+ }
+
+ err = msg_move_msg_to_folder(g_msg_handle, msg_id, MSG_INBOX_ID);
+ if (err == MSG_SUCCESS) {
+ __bt_mns_client_event_notify("MessageShift",
+ map_id,
+ "TELECOM/MSG/INBOX",
+ "TELECOM/MSG/DELETED",
+ "SMS_GSM");
+ }
+ }
+ }
+ g_free(folder_name);
+ msg_release_struct(&msg);
+ msg_release_struct(&send_opt);
dbus_g_method_return(context);
- DBG("-\n");
+ FN_END;
return TRUE;
fail:
+ g_free(folder_name);
+
+ msg_release_struct(&msg);
+ msg_release_struct(&send_opt);
+
error = __bt_map_agent_error(BT_MAP_AGENT_ERROR_INTERNAL,
"InternalError");
dbus_g_method_return_error(context, error);
g_error_free(error);
+ ERR("fail -\n");
return FALSE;
}
gboolean status,
DBusGMethodInvocation *context)
{
- DBG("remote_addr = %s \n", remote_addr);
+ FN_START;
+ DBG_SECURE("remote_addr = %s \n", remote_addr);
if (status == TRUE)
__bt_mns_client_connect(remote_addr);
return TRUE;
}
-#endif
-
+static gboolean bluetooth_map_destroy_agent(BluetoothMapAgent *agent,
+ DBusGMethodInvocation *context)
+{
+ FN_START;
+ g_main_loop_quit(g_mainloop);
+ return TRUE;
+}
-int main(int argc, char **argv)
+int main(void)
{
-#if 0
+ FN_START;
BluetoothMapAgent *bluetooth_map_obj = NULL;
DBusGProxy *bus_proxy = NULL;
guint result = 0;
+ int ret;
GError *error = NULL;
+ DBG("Starting Bluetooth MAP agent");
g_type_init();
}
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;
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,
if (__bluetooth_map_start_service() == FALSE)
goto failure;
+ g_tapi_handle = tel_init(NULL);
+ if (!g_tapi_handle)
+ goto failure;
+
+ ret = tel_get_sms_sca(g_tapi_handle, 0, __bt_get_sms_sca, NULL);
+ if (ret != TAPI_API_SUCCESS) {
+ ERR("TAPI err = %d", ret);
+ 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();
+ tel_deinit(g_tapi_handle);
+ g_free(g_sca_info);
+
+ __bt_mns_client_disconnect();
+
if (bus_proxy)
g_object_unref(bus_proxy);
if (bluetooth_map_obj)
if (g_connection)
dbus_g_connection_unref(g_connection);
-
__bluetooth_map_stop_service();
+ DBG("Bluetooth MAP agent Terminated successfully\n");
+ FN_END;
return EXIT_FAILURE;
-#endif
- return 0;
}
-
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
*
* 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
+ * 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,
#define BT_MAP_SERVICE_INTERFACE "org.bluez.MapAgent"
#undef LOG_TAG
-#define LOG_TAG "BLUETOOTH_AGENT_MESSAGE"
-
+#define LOG_TAG "BLUETOOTH_AGENT_MAP"
+#define INFO(fmt, args...) SLOGI(fmt, ##args)
#define DBG(fmt, args...) SLOGD(fmt, ##args)
#define ERR(fmt, args...) SLOGE(fmt, ##args)
+#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args)
+#define ERR_SECURE(fmt, args...) SECURE_SLOGE(fmt, ##args)
+
+#define FUCNTION_CALLS
+#ifdef FUCNTION_CALLS
+#define FN_START DBG("ENTER==>")
+#define FN_END DBG("EXIT===>")
+#else
+#define FN_START
+#define FN_END
+#endif
+
+#define retv_if(expr, val) \
+ do { \
+ if (expr) { \
+ ERR("(%s) return", #expr); \
+ return (val); \
+ } \
+ } while (0)
+
#endif /* __DEF_BT_AGENT_H_ */
<arg type="b" name="status"/>
<arg type="u" name="update_err" direction="out"/>
</method>
+ <method name="DestroyAgent">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
</interface>
</node>
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
*
* 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
+ * 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,
*
*/
-#if 0
-
#include <stdio.h>
#include <string.h>
#include <glib.h>
-#include <map_bmessage.h>
+#include <ITapiNetText.h>
+#include <map_bmessage.h>
#include <bluetooth_map_agent.h>
#define CRLF_LEN 2
+#define BT_SMS_DATA_MAX_LEN 165
#define BMSG_TAG "BEGIN:BMSG\r\n"
#define VER_TAG "VERSION:"
#define LANGUAGE_TAG "LANGUAGE:"
#define LENGTH_TAG "LENGTH:"
+static guint8 g_enc_lvl = 1;
void print_bmsg(struct bmsg_data *bmsg)
{
+ FN_START;
if (bmsg == NULL)
return;
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);
+ DBG_SECURE("bmsg->folder = %s", bmsg->folder);
+
+ if (bmsg->originator_vcard_data) {
+ DBG_SECURE("bmsg->originator_vcard_data->version = %s",
+ bmsg->originator_vcard_data->version);
+ DBG_SECURE("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);
if (rvcard->version != NULL)
DBG("vcard->version = %s\n", rvcard->version);
if (rvcard->n != NULL)
- DBG("vcard->n = %s\n", rvcard->n);
+ DBG_SECURE("vcard->n = %s\n", rvcard->n);
if (rvcard->fn != NULL)
- DBG("vcard->fn = %s\n", rvcard->fn);
+ DBG_SECURE("vcard->fn = %s\n", rvcard->fn);
if (rvcard->tel != NULL)
- DBG("vcard->tel = %s\n", rvcard->tel);
+ DBG_SECURE("vcard->tel = %s\n", rvcard->tel);
if (rvcard->email != NULL)
- DBG("vcard->email = %s\n", rvcard->email);
+ DBG_SECURE("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 = %"
+ DBG_SECURE("env_data->body_content->length = %"
G_GUINT64_FORMAT "\n",
env_data->body_content->length);
- DBG("env_data->body_content->msg = %s\n",
+ DBG_SECURE("env_data->body_content->msg = %s\n",
env_data->body_content->msg);
}
env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
}
+ FN_END;
+}
+
+static gchar *__bt_unpack_gsm7bit_msg(const char* pdu, int in_len)
+{
+ FN_START;
+ int i;
+ int pos = 0;
+ int shift = 0;
+ gchar data[BT_SMS_DATA_MAX_LEN + 1] = {0,};
+
+ for (i = 0; i < in_len; i++) {
+ if (shift == 0) {
+ data[i] = pdu[pos] & 0x7F;
+
+ shift = 7;
+ pos++;
+ } else {
+ data[i] = (pdu[pos - 1] >> shift) |
+ (pdu[pos] << (8 - shift));
+ data[i] &= 0x7F;
+
+ shift--;
+ if (shift > 0)
+ pos++;
+ }
+ }
+
+ DBG_SECURE("msg = %s\n", data);
+ FN_END;
+ return g_strdup(data);
+}
+
+static gchar *__bt_get_msg_body_from_pdu(gchar *pdu, guint64 pdu_len)
+{
+ FN_START;
+ int index = 0;
+ int i;
+ int j = 0;
+ int dcs;
+ int udh = 0;
+ int coding_scheme;
+ int phone_num_len = 0;
+ char temp[3];
+ char msg_data[BT_SMS_DATA_MAX_LEN + 1] = {0,};
+ unsigned char pdu_data[TAPI_NETTEXT_MSG_SIZE_MAX] = {0,};
+
+ for (i = 0; i < (pdu_len - 1);) {
+ snprintf(temp, sizeof(temp), "%c%c", pdu[i], pdu[i+1]);
+
+ pdu_data[j] = g_ascii_strtoull(temp, NULL, 16);
+ DBG("pdu_data = %02x\n", pdu_data[j]);
+ j++;
+ i = i + 2;
+ }
+
+ DBG("pdu[%d] = %x\n", index, pdu_data[index]);
+ if (pdu[index] == 0x00)
+ index++;
+ else
+ index = index + pdu_data[index];
+
+ /* TP-MTI */
+ index = index + 1;
+
+ if (pdu_data[index] & 0x40)
+ udh = 1;
+
+ DBG("udh = %d", udh);
+
+ /* TP-MR */
+ index = index + 1;
+
+ /* phone number length */
+ index = index + 1;
+ DBG("pdu[%d] = %x\n", index, pdu_data[index]);
+
+ if ((pdu_data[index] % 2) == 0)
+ phone_num_len = pdu_data[index] / 2;
+ else
+ phone_num_len = pdu_data[index] / 2 + 1;
+
+ DBG("phone_num_len [%d]\n", phone_num_len);
+
+ /* phone number type */
+ index = index + 1;
+
+ /* phone_num_len/2 encoded phone num length */
+ index = index + phone_num_len;
+
+ /* TP-PID */
+ index = index + 1;
+
+ /* TP-DCS */
+ index = index + 1;
+
+ dcs = pdu_data[index];
+ coding_scheme = (dcs & 0x0C) >> 2;
+ DBG("coding_scheme = %d\n", coding_scheme);
+
+ /* TP-VP */
+ index = index + 1;
+
+ /* TP-UDL */
+ index = index + 1;
+ int udl = pdu_data[index];
+ DBG("udl = %x\n", udl);
+
+ /* message body */
+ index = index + 1;
+
+ memcpy(msg_data, (void*)&pdu_data[index], udl);
+
+ FN_END;
+ return __bt_unpack_gsm7bit_msg(msg_data, udl);
+}
+
+static gchar *__bt_get_valid_number(gchar* num)
+{
+ FN_START;
+ int len;
+ int i = 0;
+ int j = 0;
+ gchar *valid_num;
+
+ if (!num)
+ return NULL;
+
+ len = strlen(num);
+
+ valid_num = g_malloc0(len + 1);
+ retv_if(valid_num == NULL, NULL);
+
+ for (i = 0, j = 0; i < len; i++) {
+
+ if (num[i] != '-') {
+ valid_num[j] = num[i];
+ j++;
+ }
+ }
+
+ valid_num[j] = '\0';
+
+ FN_END;
+ return valid_num;
}
char *bmsg_get_msg_folder(struct bmsg_data *bmsg)
{
+ FN_START;
return g_strdup(bmsg->folder);
}
-char *bmsg_get_msg_body(struct bmsg_data *bmsg)
+char *bmsg_get_msg_body(struct bmsg_data *bmsg, gboolean utf)
{
+ FN_START;
struct benv_data *env_data;
int i = 0;
while (env_data != NULL) {
if (env_data->body_content != NULL) {
- DBG("env_data->body_content->msg = %s\n",
+ DBG_SECURE("env_data->body_content->msg = %s\n",
env_data->body_content->msg);
- DBG("env_data->body_content->length = %"
+ DBG_SECURE("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);
+
+ if (utf == FALSE) {
+ return __bt_get_msg_body_from_pdu(
+ env_data->body_content->msg,
+ env_data->body_content->length);
+ } else {
+ return g_strndup(
+ env_data->body_content->msg,
+ env_data->body_content->length);
+ }
}
i++;
env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
}
+ FN_END;
return NULL;
}
GSList *bmsg_get_msg_recepients(struct bmsg_data *bmsg)
{
+ FN_START;
struct benv_data *env_data;
GSList *receiver = NULL;
int i = 0;
k++;
if (rvcard->tel != NULL) {
- DBG("vcard->tel = %s\n", rvcard->tel);
- receiver = g_slist_append(receiver, rvcard->tel);
+ DBG_SECURE("vcard->tel = %s\n", rvcard->tel);
+ receiver = g_slist_append(receiver,
+ rvcard->tel);
}
rvcard = g_slist_nth_data(env_data->recipient_vcard, k);
env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
}
-
+ FN_END;
return receiver;
}
void bmsg_free_vcard_data(struct bmsg_vcard *vcard_data)
{
+ FN_START;
if (vcard_data == NULL)
return;
g_free(vcard_data->tel);
g_free(vcard_data->email);
g_free(vcard_data);
-
+ FN_END;
return;
}
void bmsg_free_bmsg(struct bmsg_data *bmsg)
{
+ FN_START;
struct benv_data *env_data;
int i = 0;
env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
}
+ FN_END;
done:
g_free(bmsg);
}
gchar *bmsg_get_parse_sub_block(char **sub_block_data, char *element)
{
+ FN_START;
gchar *start;
gchar *end;
gchar *block_start;
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);
done:
g_free(start);
g_free(end);
+ FN_END;
return sub_block;
}
gchar *bmsg_get_tag_data(char **block_data, char *element)
{
+ FN_START;
gchar *end = "\r\n";
gchar *block_start;
gchar *block_end;
size_t offset;
size_t len;
- DBG("");
-
if (*block_data == NULL || element == 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;
-
+ FN_END;
return sub_block;
}
struct bmsg_bbody *bmsg_get_bbody_data(gchar *block_data)
{
- gchar *bbody_block_data_start;
- gchar *temp;
+ FN_START;
struct bmsg_bbody *bbody;
- DBG("");
-
- bbody_block_data_start = block_data;
+ gchar *temp;
+ gchar *bbody_block_data_start = block_data;
bbody = g_new0(struct bmsg_bbody, 1);
bbody->msg = bmsg_get_parse_sub_block(&block_data, "MSG");
g_free(bbody_block_data_start);
-
+ FN_END;
return bbody;
}
struct bmsg_vcard *bmsg_get_vcard_data(gchar *sub_block_data)
{
- gchar *vcard_block_data_start;
+ FN_START;
struct bmsg_vcard *vcard;
- DBG("");
-
- vcard_block_data_start = sub_block_data;
+ gchar *num;
+ gchar *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);
+ num = bmsg_get_tag_data(&sub_block_data, VCARD_TEL_TAG);
+ vcard->tel = __bt_get_valid_number(num);
vcard->email = bmsg_get_tag_data(&sub_block_data, VCARD_EMAIL_TAG);
g_free(vcard_block_data_start);
-
+ g_free(num);
+ FN_END;
return vcard;
}
struct benv_data *bmsg_get_env_encapsulation_data(gchar **sub_block_data)
{
+ FN_START;
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)
+ if (g_enc_lvl > 3)
return NULL;
struct benv_data *rec_data = g_new0(struct benv_data, 1);
- rec_data->encapsulation_level = lvl;
- lvl++;
+ rec_data->encapsulation_level = g_enc_lvl;
+ g_enc_lvl++;
while (is_valid != NULL) {
gchar *vcard_data = NULL;
vcard_data = bmsg_get_parse_sub_block(sub_block_data, "VCARD");
if (vcard_data == NULL) {
- DBG("parse error\n");
+ ERR("parse error\n");
g_free(rec_data);
return NULL;
}
bbody_data = bmsg_get_parse_sub_block(sub_block_data, "BBODY");
if (bbody_data == NULL) {
- DBG("parse error\n");
+ ERR("parse error\n");
return rec_data;
}
rec_data->body_content = bmsg_get_bbody_data(bbody_data);
-
+ FN_END;
return rec_data;
}
struct bmsg_envelope *bmsg_get_envelope_data(gchar **block_data)
{
- gchar *env_block_data_start;
+ FN_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");
rec_data = bmsg_get_env_encapsulation_data(
&sub_block_data);
}
+ g_free(sub_block_data);
sub_block_data = bmsg_get_parse_sub_block(&sub_block_data,
"BENV");
}
g_free(sub_block_data);
-
+ FN_END;
return envelope_data;
}
-struct bmsg_data * bmsg_parse(gchar *buf)
+struct bmsg_data *bmsg_parse(gchar *buf)
{
+ FN_START;
gchar *block_data;
gchar *sub_block_data;
gchar *block_data_start;
struct bmsg_data *bmsg;
- DBG("");
+ g_enc_lvl = 1;
block_data = bmsg_get_parse_sub_block(&buf, "BMSG");
if (block_data == 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;
+ if (sub_block_data != NULL) {
+ 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)
DBG("Parse done");
print_bmsg(bmsg);
-
+ FN_END;
return bmsg;
parse_fail:
- DBG("Parse fail");
- bmsg_free_bmsg(bmsg);
+ g_free(block_data_start);
+ ERR("Parse fail");
+ bmsg_free_bmsg(bmsg);
+ FN_END;
return NULL;
}
-#endif
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
*
* 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
+ * 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,
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);
+char *bmsg_get_msg_body(struct bmsg_data *bmsg, gboolean utf);
GSList *bmsg_get_msg_recepients(struct bmsg_data *bmsg);
+void bmsg_free_bmsg(struct bmsg_data *bmsg);
#ifdef __cplusplus
}
[D-BUS Service]
Name=org.bluez.map_agent
Exec=/usr/bin/bluetooth-map-agent
-User=root
Name: bluetooth-agent
Summary: Bluetooth agent packages that support various external profiles
-Version: 0.0.9
-Release: 2
+Version: 0.1.0
+Release: 1
Group: Network & Connectivity/Bluetooth
License: Apache-2.0
Source0: %{name}-%{version}.tar.gz
Source1001: bluetooth-agent.manifest
+Requires(post): sys-assert
+BuildRequires: pkgconfig(aul)
+BuildRequires: pkgconfig(bluetooth-api)
+%if "%{?profile}" == "wearable"
+BuildRequires: pkgconfig(alarm-service)
+BuildRequires: pkgconfig(capi-appfw-app-manager)
+BuildRequires: pkgconfig(capi-system-device)
+%else
BuildRequires: pkgconfig(contacts-service2)
-BuildRequires: pkgconfig(dbus-glib-1)
BuildRequires: pkgconfig(msg-service)
-BuildRequires: pkgconfig(email-service)
+%endif
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(dbus-glib-1)
BuildRequires: pkgconfig(tapi)
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(vconf)
BuildRequires: pkgconfig(appsvc)
+BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(capi-media-image-util)
+BuildRequires: pkgconfig(libexif)
BuildRequires: cmake
%description
cp %{SOURCE1001} .
%build
-cmake . -DCMAKE_INSTALL_PREFIX=/usr
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+export CFLAGS="$CFLAGS -DTIZEN_MEDIA_ENHANCE"
+export CFLAGS="$CFLAGS -DTIZEN_BT_HFP_AG_ENABLE"
+
+%if "%{?profile}" == "wearable"
+export CFLAGS="$CFLAGS -DTIZEN_WEARABLE"
+export CFLAGS="$CFLAGS -DTIZEN_SUPPORT_LUNAR_DEVICE"
+%else
+%if "%{?tizen_target_name}" == "Z130H"
+export CFLAGS="$CFLAGS -DTIZEN_KIRAN"
+%endif
+%endif
+
+export CFLAGS+=" -fpie -DPBAP_SIM_ENABLE"
+
+export CFLAGS+=" -fpie -fvisibility=hidden"
+export LDFLAGS+=" -Wl,--rpath=/usr/lib -Wl,--as-needed -Wl,--unresolved-symbols=ignore-in-shared-libs -pie"
+
+cmake . -DCMAKE_INSTALL_PREFIX=/usr \
+%if "%{?profile}" == "wearable"
+ -DTIZEN_WEARABLE=1 \
+%else
+ -DTIZEN_WEARABLE=0 \
+%endif
+ -DTIZEN_BT_HFP_AG_ENABLE=1
make VERBOSE=1
rm -rf %{buildroot}
%make_install
+install -D -m 0644 LICENSE %{buildroot}%{_datadir}/license/bluetooth-agent
+
%files
%manifest %{name}.manifest
%defattr(-, root, root)
+%if "%{?profile}" == "wearable"
+%{_bindir}/bluetooth-hf-agent
+%{_datadir}/dbus-1/system-services/org.bluez.hf_agent.service
+%else
%{_bindir}/bluetooth-map-agent
-#%{_bindir}/bluetooth-pb-agent
-#%{_bindir}/bluetooth-hfp-agent
-#%{_datadir}/dbus-1/system-services/org.bluez.pb_agent.service
-%{_datadir}/dbus-1/services/org.bluez.map_agent.service
-#%{_datadir}/dbus-1/system-services/org.bluez.hfp_agent.service
+%{_bindir}/bluetooth-pb-agent
+%{_datadir}/dbus-1/system-services/org.bluez.pb_agent.service
+%{_datadir}/dbus-1/system-services/org.bluez.map_agent.service
+%{_datadir}/dbus-1/system-services/org.bluez.ag_agent.service
+%{_bindir}/bluetooth-ag-agent
+%attr(0666,-,-) /opt/var/lib/bluetooth/voice-recognition-blacklist
+%endif
+%{_datadir}/license/bluetooth-agent
INCLUDE(FindPkgConfig)
pkg_check_modules(pkgs_pb_agent
REQUIRED
- dbus-glib-1 dlog contacts-service2 tapi vconf)
+ dbus-glib-1 dlog contacts-service2 tapi vconf capi-media-image-util libexif)
FOREACH(flag ${pkgs_pb_agent_CFLAGS})
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ * Jaekyun Lee <jkyun.leek@samsung.com>
*
* 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
+ * 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,
#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;
TapiHandle *tapi_handle;
gchar *tel_number;
-
- GHashTable *contact_list;
-
guint timeout_id;
PhoneBookType pb_type;
G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
static guint signals[LAST_SIGNAL] = { 0 };
+static guint total_missed_call_count = 0;
+static guint unnotified_missed_call_count = 0;
static GMainLoop *mainloop = NULL;
const char *filename,
GError **error);
+static gboolean bluetooth_pb_destroy_agent(BluetoothPbAgent *agent,
+ DBusGMethodInvocation *context);
+
static void __bluetooth_pb_dbus_return_error(DBusGMethodInvocation *context,
gint code,
const gchar *message);
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(int addressbook);
static contacts_query_h __bluetooth_pb_query_person_number(void);
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,
static void bluetooth_pb_agent_init(BluetoothPbAgent *agent)
{
+ FN_START;
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;
+ FN_END;
}
static void bluetooth_pb_agent_class_init(BluetoothPbAgentClass *klass)
{
+ FN_START;
GObjectClass *object_class = (GObjectClass *) klass;
klass->clear = bluetooth_pb_agent_clear;
dbus_g_object_type_install_info(BLUETOOTH_PB_TYPE_AGENT,
&dbus_glib_bluetooth_pb_object_info);
+ FN_END;
}
static void bluetooth_pb_agent_finalize(GObject *obj)
{
+ FN_START;
BluetoothPbAgent *agent = BLUETOOTH_PB_AGENT(obj);
- DBG("+\n");
-
if (agent->tapi_handle) {
tel_deinit(agent->tapi_handle);
agent->tapi_handle = NULL;
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;
G_OBJECT_CLASS(bluetooth_pb_agent_parent_class)->finalize(obj);
+ FN_END;
}
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;
- }
-
+ FN_START;
agent->pb_type = TELECOM_NONE;
+ FN_END;
}
static gboolean bluetooth_pb_get_phonebook_folder_list(BluetoothPbAgent *agent,
const gchar ***folder_list,
GError **error)
{
+ FN_START;
gint size;
gint i;
gchar **folder;
*folder_list = (const gchar **)folder;
+ FN_END;
return TRUE;
}
guint16 list_start_offset,
DBusGMethodInvocation *context)
{
+ FN_START;
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",
+ INFO("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);
vcards_str = (gchar **) g_ptr_array_free(vcards, FALSE);
- dbus_g_method_return(context, vcards_str, new_missed_call);
+ if (pb_type == TELECOM_MCH) {
+ dbus_g_method_return(context, vcards_str, unnotified_missed_call_count);
+ INFO("Notified [%d] missed call count", unnotified_missed_call_count);
+ unnotified_missed_call_count = 0;
+ } else {
+ dbus_g_method_return(context, vcards_str, 0);
+ }
g_strfreev(vcards_str);
+ FN_END;
return TRUE;
}
const char *name,
DBusGMethodInvocation *context)
{
+ FN_START;
PhoneBookType pb_type = TELECOM_NONE;
-
- guint new_missed_call = 0;
guint count = 0;
- DBG("name: %s\n", name);
+ DBG_SECURE("name: %s\n", name);
__bluetooth_pb_agent_timeout_add_seconds(agent);
}
/* for owner */
+#ifdef PBAP_SIM_ENABLE
+ if (pb_type == TELECOM_PB || pb_type == SIM_PB)
+ count++;
+#else
if (pb_type == TELECOM_PB)
count++;
+#endif
+ if (pb_type == TELECOM_MCH) {
+ dbus_g_method_return(context, count, unnotified_missed_call_count);
+ INFO("Notified [%d] missed call count", unnotified_missed_call_count);
+ unnotified_missed_call_count = 0;
+ } else {
+ dbus_g_method_return(context, count, 0);
+ }
- __bluetooth_pb_get_count_new_missed_call(&new_missed_call);
-
- dbus_g_method_return(context, count, new_missed_call);
-
+ FN_END;
return TRUE;
}
const char *name,
DBusGMethodInvocation *context)
{
+ FN_START;
PhoneBookType pb_type = TELECOM_NONE;
GPtrArray *ptr_array;
- DBG("name: %s\n", name);
+ DBG_SECURE("name: %s\n", name);
__bluetooth_pb_agent_timeout_add_seconds(agent);
__bluetooth_pb_get_list(agent, pb_type, ptr_array);
- dbus_g_method_return(context, ptr_array);
+// __bluetooth_pb_get_count_new_missed_call(&new_missed_call);
+ INFO("pb_type[%d] / number of missed_call[%d]", pb_type, unnotified_missed_call_count);
+
+ if (pb_type == TELECOM_MCH) {
+ dbus_g_method_return(context, ptr_array, unnotified_missed_call_count);
+ INFO("Notified [%d] missed call count", unnotified_missed_call_count);
+ unnotified_missed_call_count = 0;
+ } else {
+ dbus_g_method_return(context, ptr_array, 0);
+ }
if (ptr_array)
g_ptr_array_free(ptr_array, TRUE);
+ FN_END;
return TRUE;
}
guint8 format,
DBusGMethodInvocation *context)
{
+ FN_START;
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",
+ DBG_SECURE("folder: %s id: %s filter: %ld format: %d\n",
folder, id, filter, format);
__bluetooth_pb_agent_timeout_add_seconds(agent);
/* 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);
+ if (_bluetooth_get_contact_addressbook(handle) == PBAP_ADDRESSBOOK_PHONE)
+ str = _bluetooth_pb_vcard_contact(handle, filter, format);
}
break;
+
case TELECOM_ICH:
- str = _bluetooth_pb_vcard_call(cid, filter, format, "RECEIVED");
+ str = _bluetooth_pb_vcard_call(handle, filter, format, "RECEIVED");
break;
case TELECOM_OCH:
- str = _bluetooth_pb_vcard_call(cid, filter, format, "DIALED");
+ str = _bluetooth_pb_vcard_call(handle, filter, format, "DIALED");
break;
case TELECOM_MCH:
- str = _bluetooth_pb_vcard_call(cid, filter, format, "MISSED");
+ str = _bluetooth_pb_vcard_call(handle, 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);
+ handle, &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);
+ str = _bluetooth_pb_vcard_call(handle, filter, format, attr);
contacts_record_destroy(record, TRUE);
break;
}
+#ifdef PBAP_SIM_ENABLE
+ case SIM_PB:
+ if (handle == 0) {
+ str = _bluetooth_pb_vcard_contact_owner(agent->tel_number,
+ filter, format);
+ } else {
+ if (_bluetooth_get_contact_addressbook(handle) == PBAP_ADDRESSBOOK_SIM)
+ str = _bluetooth_pb_vcard_contact(handle, filter, format);
+ }
+ break;
+#endif
default:
__bluetooth_pb_dbus_return_error(context,
G_FILE_ERROR_INVAL,
dbus_g_method_return(context, str);
g_free(str);
+ FN_END;
return TRUE;
}
const gchar *command,
DBusGMethodInvocation *context)
{
+ FN_START;
PhoneBookType pb_type = TELECOM_NONE;
guint count = 0;
dbus_g_method_return(context, count);
+ FN_END;
return TRUE;
}
gint end_index,
DBusGMethodInvocation *context)
{
+ FN_START;
PhoneBookType pb_type = TELECOM_NONE;
GPtrArray *ptr_array = NULL;
if (ptr_array)
g_ptr_array_free(ptr_array, TRUE);
+ FN_END;
return TRUE;
}
const gchar *find_text,
DBusGMethodInvocation *context)
{
+ FN_START;
PhoneBookType pb_type = TELECOM_NONE;
GPtrArray *ptr_array = NULL;
if (ptr_array)
g_ptr_array_free(ptr_array, TRUE);
+ FN_END;
return TRUE;
}
static gboolean bluetooth_pb_get_total_object_count(BluetoothPbAgent *agent,
gchar *path, DBusGMethodInvocation *context)
{
+ FN_START;
guint count = 0;
PhoneBookType pb_type = TELECOM_NONE;
DBG("%s() %d\n", __FUNCTION__, __LINE__);
+ FN_END;
return TRUE;
}
#if 0
static int __bluetooth_pb_agent_read_file(const char *file_path, char **stream)
{
+ FN_START;
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");
+ ERR("Invalid data \n");
return -1;
}
- DBG("file_path = %s\n", file_path);
+ DBG_SECURE("file_path = %s\n", file_path);
if ((fp = fopen(file_path, "r+")) == NULL) {
- DBG("Cannot open %s\n", file_path);
+ ERR_SECURE("Cannot open %s\n", file_path);
return -1;
}
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);
+ ERR_SECURE("Some problem in the file size [%s] \n", file_path);
fclose(fp);
fp = NULL;
return -1;
return -1;
}
} else {
- DBG("Some problem in the file [%s] \n", file_path);
+ ERR_SECURE("Some problem in the file [%s] \n", file_path);
fclose(fp);
fp = NULL;
return -1;
fclose(fp);
fp = NULL;
}
- DBG("Cannot open %s\n", file_path);
+ DBG_SECURE("Cannot open %s\n", file_path);
return -1;
}
fclose(fp);
fp = NULL;
}
+ FN_END;
return 0;
}
#endif
static gboolean bluetooth_pb_add_contact(BluetoothPbAgent *agent, const char *filename,
GError **error)
{
+ FN_START;
/* Contact API is changed, Temporary blocked */
#if 0
CTSstruct *contact_record = NULL;
int err = 0;
char *stream = NULL;
- DBG("file_path = %s\n", filename);
+ DBG_SECURE("file_path = %s\n", filename);
err = contacts_svc_connect();
- DBG("contact_db_service_connect fucntion call [error] = %d \n", err);
+ ERR("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);
+ ERR("contacts_svc_disconnect fucntion call [error] = %d \n", err);
if (NULL != stream) {
free(stream);
contacts_svc_insert_contact(0, contact_record);
}
} else {
- DBG("Fail \n");
+ ERR("Fail \n");
}
err = contacts_svc_disconnect();
- DBG("contacts_svc_disconnect fucntion call [error] = %d \n", err);
+ ERR("contacts_svc_disconnect fucntion call [error] = %d \n", err);
if (NULL != stream) {
free(stream);
stream = NULL;
}
#endif
-
+ FN_END;
return TRUE;
}
gint code,
const gchar *message)
{
+ FN_START;
GQuark quark;
GError *error = NULL;
dbus_g_method_return_error(context, error);
g_error_free(error);
+ FN_END;
}
static PhoneBookType __bluetooth_pb_get_pb_type(const char *name)
{
+ FN_START;
gchar *suffix = ".vcf";
gint len;
gint size;
return i;
}
+ FN_END;
return TELECOM_NONE;
}
static PhoneBookType __bluetooth_pb_get_storage_pb_type(const char *name)
{
+ FN_START;
if (name == NULL)
return TELECOM_NONE;
if (g_strcmp0(name, "\"MC\"") == 0)
return TELECOM_MCH;
+ FN_END;
return TELECOM_NONE;
}
gint *match,
gint size)
{
+ FN_START;
gint i;
gint status;
return status;
}
+ FN_END;
return CONTACTS_ERROR_NONE;
}
static contacts_query_h __bluetooth_pb_query_phone_log(gint *match,
gint size)
{
+ FN_START;
contacts_query_h query = NULL;
contacts_filter_h filter = NULL;
contacts_filter_destroy(filter);
+ FN_END;
return query;
}
-static contacts_query_h __bluetooth_pb_query_person(void)
+bool __bt_is_matching_addressbook(const char *addressbook_name, int addressbook)
{
+ bool is_sim_addressbook = _bt_is_sim_addressbook(addressbook_name);
+
+ if ((is_sim_addressbook == false
+ && addressbook == PBAP_ADDRESSBOOK_PHONE) ||
+ (is_sim_addressbook == true
+ && addressbook == PBAP_ADDRESSBOOK_SIM))
+ return true;
+
+ return false;
+}
+
+static contacts_query_h __bluetooth_pb_query_person(int addressbook)
+{
+ FN_START;
contacts_query_h query = NULL;
+ contacts_filter_h filter = NULL;
+ contacts_list_h recordList = NULL;
+ contacts_record_h record = NULL;
+ char* addressbook_name = NULL;
+ int address_book_id = 0;
+ int count = 0;
+ unsigned int i = 0;
gint status;
+ bool is_first_condition = true;
+ DBG("Addressbook [%d]", addressbook);
+ /* Create query*/
+ status = contacts_query_create(_contacts_person_contact._uri, &query);
+ if (status != 0) {
+ ERR("Could not create query");
+ return NULL;
+ }
+
+ /* Create addressbook Filter*/
+ contacts_db_get_all_records(_contacts_address_book._uri, 0, 0, &recordList);
+ contacts_filter_create(_contacts_person_contact._uri, &filter);
+ contacts_list_get_count(recordList, &count);
+
+ for (i = 0; i < count; i++) {
+ status = contacts_list_get_current_record_p(recordList, &record);
+ if (status != CONTACTS_ERROR_NONE) {
+ ERR("Contact list get api failed %d", status);
+ goto next;
+ }
+ status = contacts_record_get_str_p(record, _contacts_address_book.name,
+ &addressbook_name);
+ if (status != CONTACTS_ERROR_NONE) {
+ ERR("Contact record get api failed %d", status);
+ goto next;
+ }
+ status = contacts_record_get_int(record, _contacts_address_book.id,
+ &address_book_id);
+ if (status != CONTACTS_ERROR_NONE) {
+ ERR("contacts record get int api failed %d", status);
+ goto next;
+ }
+
+ DBG("Addressbook ID: [%d] Addressbook Name: [%s]",
+ address_book_id, addressbook_name);
+
+ if (__bt_is_matching_addressbook(addressbook_name,
+ addressbook)) {
+ if (is_first_condition)
+ is_first_condition = false;
+ else
+ contacts_filter_add_operator(filter,
+ CONTACTS_FILTER_OPERATOR_OR);
+ DBG("SELECTED Addressbook ID: [%d] Addressbook Name: [%s]",
+ address_book_id, addressbook_name);
+ status = contacts_filter_add_int(filter,
+ _contacts_person_contact.address_book_id,
+ CONTACTS_MATCH_EQUAL, address_book_id);
+ if (status != CONTACTS_ERROR_NONE)
+ ERR("Contact filter add failed %d", status);
+ }
+next:
+ if (contacts_list_next(recordList) != CONTACTS_ERROR_NONE)
+ break;
+ }
- status = contacts_query_create(_contacts_person._uri,
- &query);
+ contacts_list_destroy(recordList, true);
+ status = contacts_query_set_filter(query, filter);
if (status != CONTACTS_ERROR_NONE)
- return NULL;
+ ERR("Could not Apply Filter");
+ contacts_filter_destroy(filter);
+ FN_END;
return query;
}
static contacts_query_h __bluetooth_pb_query_person_number(void)
{
+ FN_START;
contacts_query_h query = NULL;
gint status;
if (status != CONTACTS_ERROR_NONE)
return NULL;
+ FN_END;
return query;
}
static contacts_query_h __bluetooth_pb_query_phone_log_incoming(void)
{
- gint size = 2;
+ FN_START;
+ gint size = 4;
gint match[] = {
CONTACTS_PLOG_TYPE_VOICE_INCOMMING,
- CONTACTS_PLOG_TYPE_VIDEO_INCOMMING
+ CONTACTS_PLOG_TYPE_VIDEO_INCOMMING,
+ CONTACTS_PLOG_TYPE_VOICE_REJECT,
+ CONTACTS_PLOG_TYPE_VIDEO_REJECT
};
+ FN_END;
return __bluetooth_pb_query_phone_log(match, size);
}
static contacts_query_h __bluetooth_pb_query_phone_log_outgoing(void)
{
+ FN_START;
gint size = 2;
gint match[] = {
CONTACTS_PLOG_TYPE_VOICE_OUTGOING,
CONTACTS_PLOG_TYPE_VIDEO_OUTGOING
};
+ FN_END;
return __bluetooth_pb_query_phone_log(match, size);
-
}
static contacts_query_h __bluetooth_pb_query_phone_log_missed(void)
{
+ FN_START;
gint size = 4;
gint match[] = {
CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN,
CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN
};
+ FN_END;
return __bluetooth_pb_query_phone_log(match, size);
}
static contacts_query_h __bluetooth_pb_query_phone_log_combined(void)
{
- gint size = 8;
+ FN_START;
+ gint size = 10;
gint match[] = {
CONTACTS_PLOG_TYPE_VOICE_INCOMMING,
CONTACTS_PLOG_TYPE_VIDEO_INCOMMING,
CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN,
CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_UNSEEN,
CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN,
- CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN
+ CONTACTS_PLOG_TYPE_VIDEO_INCOMMING_SEEN,
+ CONTACTS_PLOG_TYPE_VOICE_REJECT,
+ CONTACTS_PLOG_TYPE_VIDEO_REJECT
};
+ FN_END;
return __bluetooth_pb_query_phone_log(match, size);
}
static gboolean __bluetooth_pb_get_count(PhoneBookType pb_type,
guint *count)
{
+ FN_START;
contacts_query_h query = NULL;
gint status;
switch (pb_type) {
case TELECOM_PB:
- query = __bluetooth_pb_query_person();
+ query = __bluetooth_pb_query_person(PBAP_ADDRESSBOOK_PHONE);
break;
case TELECOM_ICH:
query = __bluetooth_pb_query_phone_log_incoming();
case TELECOM_CCH:
query = __bluetooth_pb_query_phone_log_combined();
break;
+#ifdef PBAP_SIM_ENABLE
+ case SIM_PB:
+ query = __bluetooth_pb_query_person(PBAP_ADDRESSBOOK_SIM);
+ break;
+#endif
default:
return FALSE;
}
*count = (gint) signed_count;
+ FN_END;
return TRUE;
}
static gboolean __bluetooth_pb_get_count_new_missed_call(guint *count)
{
+ FN_START;
contacts_query_h query = NULL;
gint status;
*count = (guint)signed_count;
+ FN_END;
return TRUE;
}
static const char *__bluetooth_pb_phone_log_get_log_type(contacts_record_h record)
{
+ FN_START;
gint status;
gint log_type;
switch (log_type) {
case CONTACTS_PLOG_TYPE_VOICE_INCOMMING:
case CONTACTS_PLOG_TYPE_VIDEO_INCOMMING:
+ case CONTACTS_PLOG_TYPE_VOICE_REJECT:
+ case CONTACTS_PLOG_TYPE_VIDEO_REJECT:
return "RECEIVED";
case CONTACTS_PLOG_TYPE_VOICE_OUTGOING:
case CONTACTS_PLOG_TYPE_VIDEO_OUTGOING:
default:
return NULL;
}
+ FN_END;
}
static void __bluetooth_pb_get_vcards(BluetoothPbAgent *agent,
guint16 list_start_offset,
GPtrArray *vcards)
{
+ FN_START;
contacts_list_h record_list = NULL;
contacts_query_h query = NULL;
switch (pb_type) {
case TELECOM_PB:
+#ifdef PBAP_SIM_ENABLE
+ case SIM_PB:
+#endif
/* for owner */
if (list_start_offset == 0) {
char *vcard;
offset = 0;
- if (limit > 0)
+ if (limit == 1)
+ return;
+ else if (limit > 1)
limit--;
}
- query = __bluetooth_pb_query_person();
+ if (pb_type == TELECOM_PB)
+ query = __bluetooth_pb_query_person(PBAP_ADDRESSBOOK_PHONE);
+#ifdef PBAP_SIM_ENABLE
+ else if(pb_type == SIM_PB)
+ query = __bluetooth_pb_query_person(PBAP_ADDRESSBOOK_SIM);
+#endif
+
property_id = _contacts_person.id;
break;
case TELECOM_ICH:
default:
return;
}
+ INFO("Limit is = %d and offset is =%d\n", limit, offset);
+
+ /* When limit is passed as ZERO to contacts_db_get_records_with_query API
+ * then this API will provide all available contacts in its database (unrestricted).
+ * Now consider a case when client requests for maxlistcount of 1 and start offset as 0
+ * then we have already read the owner card in above switch case and when it reads owner
+ * card it decrements the limit by 1.
+ */
+ if(limit != 0)
+ {
+ status = contacts_db_get_records_with_query(query, offset, limit, &record_list);
+
+ if (status != CONTACTS_ERROR_NONE) {
+ contacts_list_destroy(record_list, TRUE);
+ contacts_query_destroy(query);
+ 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);
+ status = contacts_list_first(record_list);
- if (status != CONTACTS_ERROR_NONE) {
- contacts_list_destroy(record_list, TRUE);
- contacts_query_destroy(query);
- return;
- }
+ if (status != CONTACTS_ERROR_NONE) {
+ contacts_list_destroy(record_list, TRUE);
+ contacts_query_destroy(query);
+ return;
+ }
- do {
- contacts_record_h record;
+ do {
+ contacts_record_h record;
- gint id;
+ gint id;
- gchar *vcard = NULL;
+ gchar *vcard = NULL;
- record = NULL;
- status = contacts_list_get_current_record_p(record_list, &record);
+ 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;
+ id = 0;
+ status = contacts_record_get_int(record, property_id, &id);
- if (status != CONTACTS_ERROR_NONE)
- continue;
+ 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);
+ 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);
- }
+ vcard = _bluetooth_pb_vcard_call(id, filter, format, attr);
+ }
- if (vcard)
- g_ptr_array_add(vcards, vcard);
+ if (vcard)
+ g_ptr_array_add(vcards, vcard);
- } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
+ } while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
+ contacts_list_destroy(record_list, TRUE);
+ }
- contacts_list_destroy(record_list, TRUE);
contacts_query_destroy(query);
+
+ FN_END;
}
static void __bluetooth_pb_get_contact_list(BluetoothPbAgent *agent,
contacts_query_h query,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_list_h record_list = NULL;
gint status;
- int i = 1;
/* Add owner */
if (ptr_array) {
status = contacts_db_get_records_with_query(query,
-1, -1, &record_list);
- if (status != CONTACTS_ERROR_NONE)
+ if (status != CONTACTS_ERROR_NONE) {
+ contacts_list_destroy(record_list, TRUE);
return;
+ }
status = contacts_list_first(record_list);
return;
}
- __bluetooth_pb_list_hash_reset(agent);
-
do {
contacts_record_h record;
id = 0;
status = contacts_record_get_int(record,
- _contacts_person.id,
+ _contacts_person_contact.person_id,
&id);
if (status != CONTACTS_ERROR_NONE)
continue;
- __bluetooth_pb_list_hash_insert(agent, i, id);
-
/* create list */
if (ptr_array) {
gchar *name;
number = _bluetooth_pb_number_from_person_id(id);
__bluetooth_pb_list_ptr_array_add(ptr_array,
- name, number, i);
+ name, number, id);
g_free(name);
g_free(number);
}
- i++;
-
} while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
contacts_list_destroy(record_list, TRUE);
+ FN_END;
}
static void __bluetooth_pb_get_phone_log_list(BluetoothPbAgent *agent,
contacts_query_h query,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_list_h record_list = NULL;
gint status;
- int i = 1;
status = contacts_db_get_records_with_query(query,
-1, -1, &record_list);
return;
}
- __bluetooth_pb_list_hash_reset(agent);
-
do {
contacts_record_h record;
if (status != CONTACTS_ERROR_NONE)
continue;
- __bluetooth_pb_list_hash_insert(agent, i, id);
-
/* create list */
if (ptr_array) {
gchar *name;
&number);
__bluetooth_pb_list_ptr_array_add(ptr_array,
- name, number, i);
+ name, number, id);
g_free(name);
}
- i++;
-
} while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
contacts_list_destroy(record_list, TRUE);
+ FN_END;
}
PhoneBookType pb_type,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_query_h query;
/* no requires refresh cache */
switch (pb_type) {
case TELECOM_PB:
- query = __bluetooth_pb_query_person();
+ query = __bluetooth_pb_query_person(PBAP_ADDRESSBOOK_PHONE);
__bluetooth_pb_get_contact_list(agent, query, ptr_array);
break;
case TELECOM_ICH:
query = __bluetooth_pb_query_phone_log_combined();
__bluetooth_pb_get_phone_log_list(agent, query, ptr_array);
break;
+#ifdef PBAP_SIM_ENABLE
+ case SIM_PB:
+ query = __bluetooth_pb_query_person(PBAP_ADDRESSBOOK_SIM);
+ __bluetooth_pb_get_contact_list(agent, query, ptr_array);
+ break;
+#endif
default:
return;
}
if (query)
contacts_query_destroy(query);
+ FN_END;
}
static void __bluetooth_pb_get_contact_list_number(BluetoothPbAgent *agent,
gint end_index,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_list_h record_list = NULL;
-
gint status;
-
gint i;
-
gint from;
gint to;
gint offset;
from - 1 , offset,
&record_list);
- if (status != CONTACTS_ERROR_NONE)
+ if (status != CONTACTS_ERROR_NONE) {
+ contacts_list_destroy(record_list, TRUE);
return;
+ }
status = contacts_list_first(record_list);
} while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
contacts_list_destroy(record_list, TRUE);
+ FN_END;
}
static void __bluetooth_pb_get_phone_log_list_number(BluetoothPbAgent *agent,
gint end_index,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_list_h record_list = NULL;
gint status;
from - 1 , offset,
&record_list);
- if (status != CONTACTS_ERROR_NONE)
+ if (status != CONTACTS_ERROR_NONE) {
+ contacts_list_destroy(record_list, TRUE);
return;
+ }
status = contacts_list_first(record_list);
if (status != CONTACTS_ERROR_NONE) {
status = contacts_record_get_int(record,
_contacts_phone_log.id,
&id);
+ if (status != CONTACTS_ERROR_NONE) {
+ ERR("contact_record_get_int api failed %d", status);
+ continue;
+ }
display_name = _bluetooth_pb_fn_from_phonelog_id(id);
} while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
contacts_list_destroy(record_list, TRUE);
+ FN_END;
}
static void __bluetooth_pb_get_list_number(BluetoothPbAgent *agent,
gint end_index,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_query_h query;
switch (pb_type) {
if (query)
contacts_query_destroy(query);
+ FN_END;
}
static void __bluetooth_pb_get_contact_list_name(BluetoothPbAgent *agent,
const gchar *find_text,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_list_h record_list = NULL;
gint status;
status = contacts_db_get_records_with_query(query,
-1, -1, &record_list);
- if (status != CONTACTS_ERROR_NONE)
+ if (status != CONTACTS_ERROR_NONE) {
+ contacts_list_destroy(record_list, TRUE);
return;
+ }
status = contacts_list_first(record_list);
i++;
} while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
+ contacts_list_destroy(record_list, TRUE);
+ FN_END;
}
static void __bluetooth_pb_get_phone_log_list_name(BluetoothPbAgent *agent,
const gchar *find_text,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_list_h record_list = NULL;
gint status;
-1, -1,
&record_list);
- if (status != CONTACTS_ERROR_NONE)
+ if (status != CONTACTS_ERROR_NONE) {
+ contacts_list_destroy(record_list, TRUE);
return;
+ }
status = contacts_list_first(record_list);
status = contacts_record_get_int(record,
_contacts_phone_log.id,
&id);
+ if (status != CONTACTS_ERROR_NONE) {
+ ERR("contacts_record_get_int failed %d", status);
+ continue;
+ }
display_name = _bluetooth_pb_fn_from_phonelog_id(id);
} while (contacts_list_next(record_list) == CONTACTS_ERROR_NONE);
contacts_list_destroy(record_list, TRUE);
+ FN_END;
}
static void __bluetooth_pb_get_list_name(BluetoothPbAgent *agent,
const gchar *find_text,
GPtrArray *ptr_array)
{
+ FN_START;
contacts_query_h query;
switch (pb_type) {
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;
+ FN_END;
}
static void __bluetooth_pb_list_ptr_array_add(GPtrArray *ptr_array,
const gchar *number,
gint handle)
{
+ FN_START;
GValue value = { 0, };
+ gchar *temp_name = g_strdup(name);
+ gchar *temp_number = g_strdup(number);
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),
+ 0, temp_name,
+ 1, temp_number,
2, handle,
G_MAXUINT);
g_ptr_array_add(ptr_array, g_value_get_boxed(&value));
+ g_free(temp_name);
+ g_free(temp_number)
+ FN_END;
}
static void __bluetooth_pb_list_ptr_array_free(gpointer data)
{
+ FN_START;
GValue value = { 0, };
gchar *name = NULL;
g_free(name);
g_free(number);
+ FN_END;
}
static void __bluetooth_pb_agent_signal_handler(int signum)
{
- if (mainloop)
+ FN_START;
+ if (mainloop) {
g_main_loop_quit(mainloop);
- else
+ } else {
+ DBG("Terminate Bluetooth PBAP agent");
exit(0);
+ }
}
static void __bluetooth_pb_contact_changed(const gchar *view_uri,
void *user_data)
{
+ FN_START;
BluetoothPbAgent *agent;
+ guint new_missed_call;
+ DBG("Received contact changed cb");
g_return_if_fail(BLUETOOTH_IS_PB_AGENT(user_data));
agent = BLUETOOTH_PB_AGENT(user_data);
+ g_object_ref(agent);
g_signal_emit(agent, signals[CLEAR], 0);
g_object_unref(agent);
+
+ __bluetooth_pb_get_count_new_missed_call(&new_missed_call);
+
+ if (new_missed_call > total_missed_call_count)
+ unnotified_missed_call_count += new_missed_call - total_missed_call_count;
+
+ INFO("Missed call count : #prev[%d], #current[%d], #unnotified[%d]",
+ total_missed_call_count, new_missed_call, unnotified_missed_call_count);
+
+ total_missed_call_count = new_missed_call;
+ FN_END;
}
static void __bluetooth_pb_agent_timeout_add_seconds(BluetoothPbAgent *agent)
{
+ FN_START;
g_return_if_fail(BLUETOOTH_IS_PB_AGENT(agent));
if(agent->timeout_id)
agent->timeout_id = g_timeout_add_seconds(BLUETOOTH_PB_AGENT_TIMEOUT,
__bluetooth_pb_agent_timeout_calback,
agent);
+ FN_END;
}
static gboolean __bluetooth_pb_agent_timeout_calback(gpointer user_data)
{
+ FN_START;
BluetoothPbAgent *agent;
g_return_val_if_fail(BLUETOOTH_IS_PB_AGENT(user_data), FALSE);
if (mainloop)
g_main_loop_quit(mainloop);
+ FN_END;
return FALSE;
}
void *data,
void *user_data)
{
+ FN_START;
BluetoothPbAgent *agent;
TelSimMsisdnList_t *number;
__bluetooth_pb_agent_dbus_init(agent);
- number = (TelSimMsisdnList_t *)data;
- agent->tel_number = g_strdup(number->list[0].num);
+ if (data != NULL) {
+ number = (TelSimMsisdnList_t *)data;
+ agent->tel_number = g_strdup(number->list[0].num);
+ }
tel_deinit(agent->tapi_handle);
agent->tapi_handle = NULL;
+ FN_END;
}
static void __bluetooth_pb_agent_dbus_init(BluetoothPbAgent *agent)
{
+ FN_START;
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);
+ ERR("Couldn't connect to system bus[%s]\n", error->message);
g_error_free(error);
return;
}
DBUS_INTERFACE_DBUS);
if (agent->proxy == NULL) {
- DBG("Failed to get a proxy for D-Bus\n");
+ ERR("Failed to get a proxy for D-Bus\n");
return;
}
G_TYPE_UINT, &result,
G_TYPE_INVALID)) {
if (error != NULL) {
- DBG("RequestName RPC failed[%s]\n", error->message);
+ ERR("RequestName RPC failed[%s]\n", error->message);
g_error_free(error);
}
}
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");
+ ERR("Failed to get the primary well-known name.\n");
g_object_unref(agent->proxy);
agent->proxy = NULL;
dbus_g_connection_register_g_object(agent->bus,
BT_PB_SERVICE_OBJECT_PATH,
G_OBJECT(agent));
+ FN_END;
+}
+
+static gboolean bluetooth_pb_destroy_agent(BluetoothPbAgent *agent,
+ DBusGMethodInvocation *context)
+{
+ FN_START;
+ g_main_loop_quit(mainloop);
+ FN_END;
+ return TRUE;
}
-int main(int argc, char **argv)
+int main(void)
{
+ FN_START;
BluetoothPbAgent *agent;
gint ret = EXIT_SUCCESS;
gint tapi_result;
struct sigaction sa;
+ DBG("Starting Bluetooth PBAP agent");
g_type_init();
mainloop = g_main_loop_new(NULL, FALSE);
if (mainloop == NULL) {
- DBG("Couldn't create GMainLoop\n");
+ ERR("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");
+ if (contacts_connect() != CONTACTS_ERROR_NONE) {
+ ERR("Can not connect contacts server\n");
g_object_unref(agent);
return EXIT_FAILURE;
}
- if (contacts_db_add_changed_cb(_contacts_event._uri,
+ __bluetooth_pb_get_count_new_missed_call(&total_missed_call_count);
+
+ if (contacts_db_add_changed_cb(_contacts_contact._uri,
+ __bluetooth_pb_contact_changed,
+ (void *)agent) != CONTACTS_ERROR_NONE) {
+ ERR("Can not add changed callback");
+ }
+
+ if (contacts_db_add_changed_cb(_contacts_phone_log._uri,
__bluetooth_pb_contact_changed,
- g_object_ref(agent)) != CONTACTS_ERROR_NONE) {
- DBG("Can not add changed callback");
+ (void *)agent) != CONTACTS_ERROR_NONE) {
+ ERR("Can not add changed callback");
}
/* set signal */
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);
+ if (contacts_db_remove_changed_cb(_contacts_phone_log._uri,
+ __bluetooth_pb_contact_changed,
+ (void *)agent) != CONTACTS_ERROR_NONE) {
+ ERR("Cannot remove changed callback");
}
+ if (contacts_db_remove_changed_cb(_contacts_contact._uri,
+ __bluetooth_pb_contact_changed,
+ (void *)agent) != CONTACTS_ERROR_NONE) {
+ ERR("Cannot remove changed callback");
+ }
- contacts_disconnect2();
+ if (contacts_disconnect() != CONTACTS_ERROR_NONE)
+ ERR("contacts_disconnect failed \n");
g_signal_emit(agent, signals[CLEAR], 0);
- if (agent)
- g_object_unref(agent);
+ g_object_unref(agent);
+ DBG("Terminate Bluetooth PBAP agent");
+ FN_END;
return ret;
}
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
*
* 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
+ * 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,
#define BT_PB_SERVICE_INTERFACE "org.bluez.PbAgent"
#undef LOG_TAG
-#define LOG_TAG "BLUETOOTH_AGENT_PHONEBOOK"
-
+#define LOG_TAG "BLUETOOTH_AGENT_PB"
+#define INFO(fmt, args...) SLOGI(fmt, ##args)
#define DBG(fmt, args...) SLOGD(fmt, ##args)
#define ERR(fmt, args...) SLOGE(fmt, ##args)
+#define DBG_SECURE(fmt, args...) SECURE_SLOGD(fmt, ##args)
+#define ERR_SECURE(fmt, args...) SECURE_SLOGE(fmt, ##args)
+
+#ifdef FUCNTION_CALLS
+#define FN_START DBG("ENTER==>")
+#define FN_END DBG("EXIT===>")
+#else
+#define FN_START
+#define FN_END
+#endif
+
+static gchar *bluetooth_pb_agent_folder_list[] = {
+ "/telecom/pb",
+ "/telecom/ich",
+ "/telecom/och",
+ "/telecom/mch",
+ "/telecom/cch",
+#ifdef PBAP_SIM_ENABLE
+ "/SIM1/telecom/pb",
+#endif
+ NULL
+};
+
+typedef enum {
+ TELECOM_PB = 0,
+ TELECOM_ICH,
+ TELECOM_OCH,
+ TELECOM_MCH,
+ TELECOM_CCH,
+#ifdef PBAP_SIM_ENABLE
+ SIM_PB,
+#endif
+ TELECOM_NONE
+} PhoneBookType;
+
#endif /* __DEF_BT_AGENT_H_ */
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg type="s" name="name"/>
<arg type="a(ssu)" name="phonebook_list" direction="out"/>
+ <arg type="u" name="new_missed_call" direction="out"/>
</method>
<method name="GetPhonebookEntry">
<arg type="s" name="filename"/>
</method>
+ <method name="DestroyAgent">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
+
<signal name="clear"/>
</interface>
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
+ * Jaekyun Lee <jkyun.lee@samsung.com>
*
* 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
+ * 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,
* limitations under the License.
*
*/
-
#include <time.h>
#include <string.h>
#include <stdarg.h>
-
-
+#include <stdlib.h>
+#include <stdio.h>
#include <glib.h>
#include <dbus/dbus-glib.h>
-
#include <vconf.h>
#include <dlog.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
#include <contacts.h>
+#include <image_util.h>
+//#include <image_util_product.h>
+#include <libexif/exif-data.h>
+#include <unistd.h>
#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)
+#include "bluetooth_pb_agent.h"
#define VCARD_FORMAT_2_1 0x0
#define VCARD_FORMAT_3_0 0x1
#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
+typedef struct {
+ const char *src;
+ const char *dest;
+ int ret;
+ contacts_record_h person;
+ GString *string;
+} bt_image_info_t;
+
+gchar dest_thumb_path[255];
+#define PBAP_IMAGE_THUMB_SIZE 48
+#define PBAP_THMB_PATH "_thumb"
+#define PBAP_THUMB_FILE_SIZE 4096
+#define PBAP_IMAGE_ENCODE_QUALITY 90
+#define PBAP_SECURITY_FILE_GROUP 6005
+#define PBAP_SECURITY_DEFAULT_PERMISSION 0660
+#define PBAP_SECURITY_DIR_DEFAULT_PERMISSION 0770
+#define PBAP_SECURITY_IMAGE_PERMISSION 0440
+
static gchar *__bluetooth_pb_vcard_escape(const gchar *str);
static gchar *__bluetooth_pb_vcard_strv_concat(gchar **strv,
static void __bluetooth_pb_vcard_append_n_v21(GString *string,
contacts_record_h contact);
+static void __bluetooth_pb_vcard_append_phonetic_first_v21(GString *string,
+ contacts_record_h contact);
+
static void __bluetooth_pb_vcard_append_tel_v21(GString *string,
contacts_record_h conatct);
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,
- ...);
+ gint phonelog_id,
+ guint64 filter,
+ guint8 format,
+ const gchar *first_name,
+ ...);
static gchar *__bluetooth_pb_vcard_real_call_v21(gint phonelog_id,
guint filter,
static gchar *__bluetooth_pb_name_from_contact(contacts_record_h contact);
+static gchar *__bluetooth_pb_phonetic_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)
{
+ FN_START;
GString *escaped;
gchar *st = NULL;
pos++;
st = pos;
- }
- else {
+ } else {
pos++;
}
}
g_string_append_len(escaped, st, (pos - st));
+ FN_END;
return g_string_free(escaped, FALSE);
}
static gchar *__bluetooth_pb_vcard_strv_concat(gchar **strv,
const gchar *separator)
{
+ FN_START;
GString *string = g_string_new(NULL);
gint i;
g_string_append(string, strv[i]);
}
+ FN_END;
return g_string_free(string, FALSE);
}
static gboolean __bluetooth_pb_vcard_qp_encode_check(const gchar *str)
{
+ FN_START;
gchar *pos = NULL;
if (str == NULL)
pos++;
}
+ FN_END;
return FALSE;
}
static gint __bluetooth_pb_vcard_qp_encode_strlen(const gchar *str,
gint len)
{
+ FN_START;
gchar *pos;
gint count = 0;
if (str == NULL)
return 0;
- if (strlen(str) < len )
+ if (strlen(str) < len)
length = -1;
pos = (gchar *)str;
count++;
}
+ FN_END;
return count;
}
gint len,
gint *line_pos)
{
+ FN_START;
int i;
if (str == NULL || len == 0)
g_string_append_printf(string, "=%02X", (guchar)*(str+i));
*line_pos += QP_ENC_LEN;
}
+ FN_END;
}
/* append plain visiable ascii character */
gchar ch,
gint *line_pos)
{
+ FN_START;
/* add soft linebreak when it exceed */
if (*line_pos + 1 > LINEBREAK_LEN) {
g_string_append(string, "=\r\n");
}
g_string_append_c(string, ch);
(*line_pos)++;
+ FN_END;
}
static void __bluetooth_pb_vcard_qp_encode_append(GString *string,
gint len,
gint *line_pos)
{
- gint length;
+ FN_START;
gint encode_len;
gint i = 0;
*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 */
+ /* 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);
+ __bluetooth_pb_vcard_qp_encode_append_to_hex(string,
+ pos, 1, line_pos);
i++;
continue;
next = g_utf8_next_char(pos);
ch_len = next - pos;
- __bluetooth_pb_vcard_qp_encode_append_to_hex(string, pos,
- ch_len, line_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);
+ __bluetooth_pb_vcard_qp_encode_append_printable_c(string, *pos,
+ line_pos);
i++;
}
+ FN_END;
}
-static gchar* __bluetooth_pb_vcard_qp_encode(const gchar *str)
+static gchar *__bluetooth_pb_vcard_qp_encode(const gchar *str)
{
+ FN_START;
GString *enc;
gchar *st_pos;
continue;
}
- /* split string with given delimeter '\r', '\n' or '\r\n' - newline */
- if (*pos == '\r' || *pos == '\n' ) {
+ /* 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);
+ __bluetooth_pb_vcard_qp_encode_append_to_hex(enc,
+ "\r\n", 2, &line_pos);
g_string_append(enc, "=\r\n ");
line_pos = 1;
__bluetooth_pb_vcard_qp_encode_append(enc, st_pos,
(pos - st_pos), &line_pos);
+ FN_END;
return g_string_free(enc, FALSE);
}
static void __bluetooth_pb_vcard_append_param_v21(GString *string,
const gchar *param)
{
+ FN_START;
gchar *pos = NULL;
if (param == NULL)
if (*pos != '\0')
g_string_append_printf(string, ";%s", pos);
+ FN_END;
}
static void __bluetooth_pb_vcard_append_qp_encode_v21(GString *string,
const gchar *param,
const gchar *value)
{
+ FN_START;
GString *property = NULL;
if (name == NULL)
g_string_append_printf(string, "%s\r\n", property->str);
g_string_free(property, TRUE);
+ FN_END;
}
gsize len,
gboolean folding)
{
+ FN_START;
gchar *enc = NULL;
if (name == NULL)
return;
+ DBG("base 64 encoding\n");
g_string_append(string, name);
enc = g_base64_encode((const guchar *)value, len);
-
if (folding == FALSE) {
g_string_append(string, enc);
} else {
gint i = 0;
/* count ' ' size for folding */
- gint fline_len = LINEBREAK_LEN -1;
+ 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);
+ 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");
+ DBG("base 64 encoding\n");
g_free(enc);
+ FN_END;
}
static void __bluetooth_pb_vcard_append_n_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
gchar *str;
str = __bluetooth_pb_name_from_contact(contact);
__bluetooth_pb_vcard_append_qp_encode_v21(string, "N", NULL, str);
g_free(str);
+ FN_END;
+}
+
+static void __bluetooth_pb_vcard_append_phonetic_first_v21(GString *string,
+ contacts_record_h contact)
+{
+ FN_START;
+ gchar *str;
+
+ str = __bluetooth_pb_phonetic_name_from_contact(contact);
+
+ if (str != NULL) {
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "SOUND", "X-IRMC-N", str);
+ g_free(str);
+ }
+ FN_END;
}
static void __bluetooth_pb_vcard_append_tel_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint i;
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);
+ if (paramv) {
+ param = __bluetooth_pb_vcard_strv_concat(paramv, ";");
+ g_strfreev(paramv);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "TEL", param,
+ escaped);
+ g_free(param);
+ }
g_free(escaped);
- g_free(param);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_fn_v21(GString *string,
contacts_record_h person)
{
+ FN_START;
gint status;
gchar *fn = NULL;
g_free(fn);
}
-static void __bluetooth_pb_vcard_append_photo_v21(GString *string,
- contacts_record_h person)
+static image_util_rotation_e __bt_pbap_get_rotation_info(const char *path)
{
- gint status;
+ FN_START;
+ ExifData *ed = NULL;
+ ExifEntry *entry;
+ image_util_rotation_e rotation = IMAGE_UTIL_ROTATION_NONE;
+ int orientation = 0;
- gsize len = 0;
+ ed = exif_data_new_from_file(path);
+ if (ed == NULL) {
+ ERR("exif_data_new_from_file : ExifData is NULL");
+ return IMAGE_UTIL_ROTATION_NONE;
+ }
- gchar *filename = NULL;
+ entry = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
+ if (entry) {
+ ExifByteOrder mByteOrder = exif_data_get_byte_order(ed);
+ orientation = (int)exif_get_short(entry->data, mByteOrder);
+ if (orientation < 0 || orientation > 8)
+ orientation = 0;
+ }
+
+ exif_data_unref(ed);
+ switch (orientation) {
+ case 1: /* Top-left */
+ rotation = IMAGE_UTIL_ROTATION_NONE;
+ break;
+ case 2: /* Top-right */
+ rotation = IMAGE_UTIL_ROTATION_FLIP_HORZ;
+ break;
+ case 3: /* Bottom-right */
+ rotation = IMAGE_UTIL_ROTATION_180;
+ break;
+ case 4: /* Bottom-left */
+ rotation = IMAGE_UTIL_ROTATION_FLIP_VERT;
+ break;
+ case 6: /* Right-top */
+ rotation = IMAGE_UTIL_ROTATION_90;
+ break;
+ case 8: /* Left-bottom */
+ rotation = IMAGE_UTIL_ROTATION_270;
+ break;
+ case 5: /* Left-top */
+ case 7: /* Right-bottom */
+ case 0:
+ default:
+ break;
+ };
+
+ FN_END;
+ return rotation;
+}
+
+
+static bool __bt_pbap_image_util_supported_jpeg_colorspace_cb(
+ image_util_colorspace_e colorspace, void *user_data)
+{
+ FN_START;
+ unsigned char *img_target = 0;
+ unsigned char *img_source = 0;
gchar *type = NULL;
gchar *param = NULL;
gchar *contents = NULL;
+ int width = 0;
+ int height = 0;
+ int resized_width = 0;
+ int resized_height = 0;
+ int dest_fd = 0;
+ unsigned int size_decode = 0;
+ image_util_rotation_e rotation;
+ image_util_error_e ret = 0;
+ gsize len = 0;
+ bt_image_info_t *info = (bt_image_info_t *)user_data;
+ rotation = __bt_pbap_get_rotation_info(info->src);
+ ret = image_util_decode_jpeg(info->src, colorspace, &img_source, &width,
+ &height, &size_decode);
+ if (ret != IMAGE_UTIL_ERROR_NONE) {
+ ERR("Can not decode");
+ memset(info, 0x00, sizeof(bt_image_info_t));
+ return true;
+ }
+
+ DBG("decoding completed width = %d, height = %d, size = %d\n", width,
+ height, size_decode);
+ if (width > PBAP_IMAGE_THUMB_SIZE || height > PBAP_IMAGE_THUMB_SIZE) {
+ if (width <= 0 || height <= 0) {
+ free(img_source);
+ ERR("image size error(%d)", PBAP_IMAGE_THUMB_SIZE);
+ memset(info, 0x00, sizeof(bt_image_info_t));
+ return false;
+ }
- status = contacts_record_get_str_p(person,
- _contacts_person.image_thumbnail_path,
- &filename);
-
- if (status != CONTACTS_ERROR_NONE)
- return;
+ if (width > height) {
+ resized_width = PBAP_IMAGE_THUMB_SIZE ;
+ resized_height = height * PBAP_IMAGE_THUMB_SIZE / width;
+ } else {
+ resized_height = PBAP_IMAGE_THUMB_SIZE;
+ resized_width = width * PBAP_IMAGE_THUMB_SIZE / height;
+ }
- type = __bluetooth_pb_contact_photo_type(filename);
+ if (resized_height % 8)
+ resized_height += 8 - (resized_height % 8);
+ if (resized_width % 8)
+ resized_width += 8 - (resized_width % 8);
+
+ DBG("original size[%d, %d] changed to resize[%d,%d]", width,
+ height, resized_width, resized_height);
+
+ ret = image_util_calculate_buffer_size(resized_width,
+ resized_height,
+ colorspace ,
+ &size_decode);
+
+ img_target = g_malloc0(size_decode);
+
+ /* do resize */
+ ret = image_util_resize(img_target, &resized_width,
+ &resized_height, img_source, width,
+ height, colorspace);
+ if (ret != IMAGE_UTIL_ERROR_NONE) {
+ ERR("image_util_resize failed(%d)", ret);
+ g_free(img_target);
+ free(img_source);
+ memset(info, 0x00, sizeof(bt_image_info_t));
+ return false;
+ }
+ free(img_source);
+ } else {
+ resized_width = width;
+ resized_height = height;
+ img_target = img_source;
+ }
+ DBG("Resized w = %d, ht = %d, size = %d\n", width, height, size_decode);
+
+ if (IMAGE_UTIL_ROTATION_NONE != rotation) {
+ int rotated_width, rotated_height;
+ unsigned char *img_rotate = 0;
+ img_rotate = g_malloc0(size_decode);
+ image_util_rotate(img_rotate, &rotated_width, &rotated_height,
+ rotation, img_target, resized_width,
+ resized_height, colorspace);
+ resized_width = rotated_width;
+ resized_height = rotated_height;
+ g_free(img_target);
+ img_target = img_rotate;
+ }
+
+ /* image encode */
+ ret = image_util_encode_jpeg(img_target, resized_width, resized_height,
+ colorspace, PBAP_IMAGE_ENCODE_QUALITY,
+ info->dest);
+ g_free(img_target);
+ if (ret != IMAGE_UTIL_ERROR_NONE) {
+ ERR("image_util_encode_jpeg failed(%d)", ret);
+ info->ret = CONTACTS_ERROR_INTERNAL;
+ goto done;
+ }
+ DBG("Encoding done\n");
+
+ dest_fd = open(info->dest, O_RDONLY);
+ if (dest_fd < 0) {
+ ERR("System : Open Failed(%d)", errno);
+ ERR_SECURE("Open : dest path(%s)", info->dest);
+ goto done;
+ }
+
+ ret = fchown(dest_fd, getuid(), PBAP_SECURITY_FILE_GROUP);
+ if (0 != ret) {
+ ERR("fchown Failed(%d)", errno);
+ DBG_SECURE("fchown : dest path(%s)", info->dest);
+ close(dest_fd);
+ goto done;
+ }
+
+ ret = fchmod(dest_fd, PBAP_SECURITY_IMAGE_PERMISSION);
+ if (0 != ret) {
+ ERR("fchmod Failed(%d)", errno);
+ ERR_SECURE("fchmod : dest path(%s)", info->dest);
+ close(dest_fd);
+ goto done;
+ }
+ close(dest_fd);
+
+ info->ret = CONTACTS_ERROR_NONE;
+ type = __bluetooth_pb_contact_photo_type(info->dest);
+ DBG("Cintact image thumb type is = %s\n", type);
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;
+ if (g_file_get_contents(info->dest, &contents, &len, NULL) == FALSE) {
+ ERR("can not read file contents:%s\n", info->dest);
+ goto done;
}
- __bluetooth_pb_vcard_append_base64_encode_v21(string,
+ __bluetooth_pb_vcard_append_base64_encode_v21(info->string,
"PHOTO", param, contents, len, TRUE);
+done:
g_free(param);
g_free(contents);
+ remove(info->dest);
+ memset(info, 0x00, sizeof(bt_image_info_t));
+ DBG("Cintact image thumb created successfuly\n");
+ FN_END;
+ return false;
+}
+
+static void __bluetooth_pb_vcard_append_photo_v21(GString *string,
+ contacts_record_h person)
+{
+ FN_START;
+ gint status;
+ gchar *filename = NULL;
+ int res = 0;
+ bt_image_info_t img_info;
+ struct stat stat_info;
+ gchar *type = NULL;
+ gchar *param = NULL;
+ gchar *contents = NULL;
+ gsize len = 0;
+ char *ptr = NULL;
+
+ status = contacts_record_get_str_p(person,
+ _contacts_person.image_thumbnail_path,
+ &filename);
+
+ if (status != CONTACTS_ERROR_NONE || NULL == filename)
+ return;
+
+ stat_info.st_size = 0;
+
+ if (0 > stat(filename, &stat_info)) {
+ ERR("fstat failed, file does not exist %s", filename);
+ }
+
+ if (PBAP_THUMB_FILE_SIZE > stat_info.st_size) {
+ DBG_SECURE("File size small, so use thubnail %s\n", filename);
+
+ 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);
+ g_free(param);
+ return;
+ }
+ DBG("Retrieved the contents of the file \n");
+ __bluetooth_pb_vcard_append_base64_encode_v21(string,
+ "PHOTO", param, contents, len, TRUE);
+
+ g_free(param);
+ g_free(contents);
+ return;
+ }
+
+ ptr = strrchr(filename, '.');
+ if (NULL != ptr) {
+ memset(dest_thumb_path, 0x00, sizeof(dest_thumb_path));
+ g_strlcpy(dest_thumb_path, filename, ptr - filename);
+ g_strlcat(dest_thumb_path, PBAP_THMB_PATH,
+ sizeof(dest_thumb_path));
+ g_strlcat(dest_thumb_path, ptr, sizeof(dest_thumb_path));
+ DBG("Thumbnail path is = %s", dest_thumb_path);
+ }
+ DBG_SECURE("filename = %s Thumbnail path is = %s", filename, dest_thumb_path);
+ img_info.src = filename;
+ img_info.dest = dest_thumb_path;
+ img_info.ret = CONTACTS_ERROR_INTERNAL;
+ img_info.person = person;
+ img_info.string = string;
+
+ res = image_util_foreach_supported_jpeg_colorspace(
+ __bt_pbap_image_util_supported_jpeg_colorspace_cb, &img_info);
+ if (res != IMAGE_UTIL_ERROR_NONE) {
+ ERR("Image resizing is failed");
+ }
+ FN_END;
}
static void __bluetooth_pb_vcard_append_bday_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
NULL, bday);
g_free(bday);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_adr_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
g_strfreev(addrv);
paramv = __bluetooth_pb_contact_addr_param(address);
- param = __bluetooth_pb_vcard_strv_concat(paramv, ";");
- g_strfreev(paramv);
+ if (paramv) {
+ param = __bluetooth_pb_vcard_strv_concat(paramv, ";");
+ g_strfreev(paramv);
- __bluetooth_pb_vcard_append_qp_encode_v21(string, "ADR",
- param, addr);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "ADR",
+ param, addr);
+ g_free(param);
+ }
- g_free(param);
g_free(addr);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_email_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
continue;
escaped = __bluetooth_pb_vcard_escape(tmp);
- __bluetooth_pb_vcard_append_qp_encode_v21(string, "EMAIL", NULL, escaped);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "EMAIL", NULL,
+ escaped);
g_free(escaped);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_title_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
gchar *escaped;
status = contacts_record_get_child_record_at_p(contact,
- _contacts_contact.company,i, &company);
+ _contacts_contact.company, i, &company);
if (status != CONTACTS_ERROR_NONE)
continue;
continue;
escaped = __bluetooth_pb_vcard_escape(title);
- __bluetooth_pb_vcard_append_qp_encode_v21(string, "TITLE", NULL, escaped);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "TITLE", NULL,
+ escaped);
g_free(escaped);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_role_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
continue;
escaped = __bluetooth_pb_vcard_escape(role);
- __bluetooth_pb_vcard_append_qp_encode_v21(string, "ROLE", NULL, escaped);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "ROLE", NULL,
+ escaped);
g_free(escaped);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_org_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
g_free(escaped);
}
- __bluetooth_pb_vcard_append_qp_encode_v21(string, "ORG", NULL, str->str);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "ORG", NULL,
+ str->str);
g_string_free(str, TRUE);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_note_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
continue;
escaped = __bluetooth_pb_vcard_escape(tmp);
- __bluetooth_pb_vcard_append_qp_encode_v21(string, "NOTE", NULL, escaped);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "NOTE", NULL,
+ escaped);
g_free(escaped);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_rev_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
gint time = 0;
gint status;
if (time <= 0)
return;
- gmtime_r((const time_t*)(&time), &result);
+ 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);
+ (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);
+ FN_END;
}
static void __bluetooth_pb_vcard_append_url_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint i;
continue;
escaped = __bluetooth_pb_vcard_escape(tmp);
- __bluetooth_pb_vcard_append_qp_encode_v21(string, "URL", NULL, escaped);
+ __bluetooth_pb_vcard_append_qp_encode_v21(string, "URL", NULL,
+ escaped);
g_free(escaped);
}
+ FN_END;
}
static void __bluetooth_pb_vcard_append_uid_v21(GString *string,
contacts_record_h contact)
{
+ FN_START;
int status;
gchar *uid = NULL;
__bluetooth_pb_vcard_append_qp_encode_v21(string, "UID", NULL, escaped);
g_free(escaped);
+ FN_END;
}
static void __bluetooth_pb_vcard_append_v30(GString *string,
const gchar *param,
const gchar *value)
{
+ FN_START;
if (string == NULL)
return;
if (name == NULL)
g_string_append(string, value);
g_string_append(string, "\r\n");
+ FN_END;
}
static void __bluetooth_pb_vcard_remove_v30(GString *string,
const gchar *property_name)
{
+ FN_START;
gchar *pos = NULL;
gchar *st_pos = NULL;
gboolean matched = FALSE;
- if(string == NULL || property_name == NULL)
+ if (string == NULL || property_name == NULL)
return;
pos = string->str;
- while(*pos != '\0') {
+ while (*pos != '\0') {
if (matched == FALSE) {
if (g_ascii_strncasecmp(pos, "\r\n", 2) == 0) {
gint attrlen = 0;
pos += 2;
attrlen = strlen(property_name);
- if (g_ascii_strncasecmp(pos, property_name, attrlen) == 0) {
+ if (g_ascii_strncasecmp(pos, property_name,
+ attrlen) == 0) {
pos += attrlen;
if (*pos == ':' || *pos == ';') {
}
continue;
}
- }
- else {
+ } 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));
+ g_string_erase(string,
+ (st_pos+2)-(string->str),
+ pos-(st_pos+2));
+
pos = st_pos;
matched = FALSE;
}
pos++;
}
+ FN_END;
}
static gchar *__bluetooth_pb_vcard_filter_v30(const gchar *vcard,
guint64 filter)
{
+ FN_START;
GString *string = NULL;
if (vcard == NULL)
if ((filter & VCARD_BDAY) == 0)
__bluetooth_pb_vcard_remove_v30(string, "BDAY");
- if ((filter & VCARD_ADR) == 0 )
+ if ((filter & VCARD_ADR) == 0)
__bluetooth_pb_vcard_remove_v30(string, "ADR");
- if ((filter & VCARD_EMAIL) == 0 )
+ if ((filter & VCARD_EMAIL) == 0)
__bluetooth_pb_vcard_remove_v30(string, "EMAIL");
- if ((filter & VCARD_TITLE) == 0 )
+ if ((filter & VCARD_TITLE) == 0)
__bluetooth_pb_vcard_remove_v30(string, "TITLE");
- if ((filter & VCARD_ROLE) == 0 )
+ if ((filter & VCARD_ROLE) == 0)
__bluetooth_pb_vcard_remove_v30(string, "ROLE");
- if ((filter & VCARD_ORG) == 0 )
+ if ((filter & VCARD_ORG) == 0)
__bluetooth_pb_vcard_remove_v30(string, "ORG");
- if ((filter & VCARD_NOTE) == 0 )
+ if ((filter & VCARD_NOTE) == 0)
__bluetooth_pb_vcard_remove_v30(string, "NOTE");
- if ((filter & VCARD_REV) == 0 )
+ if ((filter & VCARD_REV) == 0)
__bluetooth_pb_vcard_remove_v30(string, "REV");
- if ((filter & VCARD_URL) == 0 )
+ if ((filter & VCARD_URL) == 0)
__bluetooth_pb_vcard_remove_v30(string, "URL");
- if ((filter & VCARD_UID) == 0 )
+ if ((filter & VCARD_UID) == 0)
__bluetooth_pb_vcard_remove_v30(string, "UID");
- if ((filter & VCARD_NICKNAME) == 0 )
+ if ((filter & VCARD_NICKNAME) == 0)
__bluetooth_pb_vcard_remove_v30(string, "NICKNAME");
+ FN_END;
return g_string_free(string, FALSE);
}
const gchar *first_name,
va_list args)
{
+ FN_START;
contacts_record_h person = NULL;
contacts_record_h contact = NULL;
if (f == 0)
f = ~f;
+ DBG("filter[%x]\n", filter);
+
str = g_string_new("BEGIN:VCARD\r\nVERSION:2.1\r\n");
/* N, TEL is default */
gchar *number;
number = _bluetooth_pb_number_from_phonelog_id(phonelog_id);
- __bluetooth_pb_vcard_append_qp_encode_v21(str, "TEL", "X-0", number);
+ __bluetooth_pb_vcard_append_qp_encode_v21(str, "TEL", "X-0",
+ number);
g_free(number);
if (f & VCARD_FN)
__bluetooth_pb_vcard_append_fn_v21(str, person);
+/* Need to check filter
+ if (f & VCARD_SOUND)*/
+ __bluetooth_pb_vcard_append_phonetic_first_v21(str, contact);
if (f & VCARD_PHOTO)
__bluetooth_pb_vcard_append_photo_v21(str, person);
if (f & VCARD_BDAY)
gchar *escaped = NULL;
escaped = __bluetooth_pb_vcard_escape(value);
- __bluetooth_pb_vcard_append_qp_encode_v21(str, name, param, escaped);
+ __bluetooth_pb_vcard_append_qp_encode_v21(str, name,
+ param, escaped);
g_free(escaped);
}
contacts_record_destroy(contact, TRUE);
contacts_record_destroy(person, TRUE);
+ FN_END;
return g_string_free(str, FALSE);
}
const gchar *first_name,
va_list args)
{
+ FN_START;
contacts_record_h person = NULL;
GString *str = NULL;
if (status != CONTACTS_ERROR_NONE)
return NULL;
- str = g_string_new(vcard);
+ /* removing the END:VCARD\r\n" to append extra data */
+ str = g_string_new_len(vcard, (strlen(vcard)-11));
g_free(vcard);
/* append contents on vcard */
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 exist, we shall show only the phone number, which was
+ used for that phone log */
if (phonelog_id > 0) {
gchar *number;
g_free(number);
}
+ g_string_append(str, "END:VCARD\r\n");
+
vcard = g_string_free(str, FALSE);
/* temporary fixed for some application crash */
}
}
+ FN_END;
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,
- ...)
+ gint phonelog_id,
+ guint64 filter,
+ guint8 format,
+ const gchar *first_name,
+ ...)
{
- DBG("\n");
+ FN_START;
+ DBG(" format [%d]\n", format);
gchar *vcard = NULL;
va_list args;
va_start(args, first_name);
- switch(format) {
+ switch (format) {
case VCARD_FORMAT_3_0:
vcard = __bluetooth_pb_vcard_real_contact_valist_v30(person_id,
phonelog_id, filter,
va_end(args);
+ FN_END;
return vcard;
}
guint filter,
const char *attr)
{
+ FN_START;
GString *str;
gchar *number;
gchar *datetime = NULL;
datetime = __bluetooth_pb_phonelog_datetime(phonelog_id);
- __bluetooth_pb_vcard_append_qp_encode_v21(str, "X-IRMC-CALL-DATETIME",
- attr, datetime);
+ __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");
+ FN_END;
return g_string_free(str, FALSE);
}
guint filter,
const gchar *attr)
{
+ FN_START;
GString *str;
gchar *number;
g_string_append(str, "END:VCARD\r\n");
+ FN_END;
return g_string_free(str, FALSE);
}
guint8 format,
const gchar *attr)
{
- DBG("\n");
+ FN_START;
gchar *vcard = NULL;
- switch(format) {
+ switch (format) {
case VCARD_FORMAT_3_0:
vcard = __bluetooth_pb_vcard_real_call_v30(phonelog_id,
filter, attr);
break;
}
+ FN_END;
return vcard;
}
int *field,
gint field_size)
{
+ FN_START;
gchar **strv;
gint status;
strv[i] = __bluetooth_pb_vcard_escape(tmp);
}
+ FN_END;
return strv;
}
static gchar **__bluetooth_pb_contact_tel_param(contacts_record_h number)
{
+ FN_START;
gchar **strv = NULL;
const gint TEL_PARAM_LEN = 13;
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;
+ strv = g_new0(char *, TEL_PARAM_LEN + 1);/* tel param max size is 13 */
+
if (is_default) {
strv[i] = g_strdup("PREF");
i++;
}
/* CTS_NUM_TYPE_PCS is not part of vcard2.1 */
+ FN_END;
return strv;
}
static gchar *__bluetooth_pb_contact_photo_type(const gchar *filename)
{
+ FN_START;
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);
+ ERR_SECURE("file does not regular:%s\n", filename);
return NULL;
}
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 ||
+ 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)
+ 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 ||
+ 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)
+ 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, "png") == 0)
filetype = "PNG";
+ FN_END;
return g_strdup(filetype);
}
static gchar **__bluetooth_pb_contact_addr(contacts_record_h address)
{
+ FN_START;
const gint ADDR_LEN = 7;
gchar **strv = NULL;
strv = __bluetooth_pb_contact_add_field_str(address,
addr, ADDR_LEN);
+ FN_END;
return strv;
}
static gchar **__bluetooth_pb_contact_addr_param(contacts_record_h address)
{
-
+ FN_START;
contacts_address_type_e type;
gint status;
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;
+ strv = g_new0(gchar *, 7); /* ADDR param max size is 6 */
+
if (type & CONTACTS_ADDRESS_TYPE_HOME) {
strv[i] = g_strdup("HOME");
i++;
strv[i] = g_strdup("PARCEL");
i++;
}
+ FN_END;
return strv;
}
static gchar *__bluetooth_pb_phonelog_datetime(gint phonelog_id)
{
+ FN_START;
contacts_record_h phone_log;
char time_str[32] = {0,};
contacts_record_destroy(phone_log, TRUE);
+ FN_END;
return g_strdup(time_str);
}
static gchar *__bluetooth_pb_name_from_contact(contacts_record_h contact)
{
+ FN_START;
contacts_record_h name = NULL;
GString *str = g_string_new(NULL);
g_free(escape);
}
+ FN_END;
+ return g_string_free(str, FALSE);
+}
+
+static gchar *__bluetooth_pb_phonetic_name_from_contact(contacts_record_h contact)
+{
+ FN_START;
+ contacts_record_h name = NULL;
+
+ GString *str = g_string_new(NULL);
+
+ gint status;
+
+ gchar *phonetic_first = NULL;
+ gchar *phonetic_last = NULL;
+ gchar *escape = NULL;
+
+ status = contacts_record_get_child_record_at_p(contact,
+ _contacts_contact.name, 0, &name);
+
+ if (status != CONTACTS_ERROR_NONE)
+ return NULL;
+
+ status = contacts_record_get_str_p(name, _contacts_name.phonetic_first, &phonetic_first);
+
+ if (status != CONTACTS_ERROR_NONE)
+ return NULL;
+
+ if (phonetic_first == NULL)
+ return NULL;
+
+ status = contacts_record_get_str_p(name, _contacts_name.phonetic_last, &phonetic_last);
+
+ if ((status == CONTACTS_ERROR_NONE) && (phonetic_last != NULL)) {
+ escape = __bluetooth_pb_vcard_escape(phonetic_last);
+ g_string_append(str, escape);
+ g_free(escape);
+ g_string_append_c(str, ' ');
+ }
+
+ escape = __bluetooth_pb_vcard_escape(phonetic_first);
+ g_string_append(str, escape);
+
+ g_free(escape);
+ g_string_append_c(str, ';');
+ g_string_append_c(str, ';');
+ g_string_append_c(str, ';');
+ g_string_append_c(str, ';');
+
+ FN_END;
return g_string_free(str, FALSE);
}
+
static gchar *__bluetooth_pb_number_from_contact(contacts_record_h contact)
{
+ FN_START;
guint count = 0;
gint status;
str = g_strdup(tmp);
}
+ FN_END;
return str;
}
static gint __bluetooth_pb_person_id_from_phonelog_id(gint phonelog_id)
{
+ FN_START;
contacts_query_h query = NULL;
contacts_filter_h filter = NULL;
contacts_list_h record_list = NULL;
CONTACTS_MATCH_EQUAL,
phonelog_id);
- if (status != CONTACTS_ERROR_NONE) {
- contacts_filter_destroy(filter);
- return 0;
- }
+ if (status != CONTACTS_ERROR_NONE)
+ goto done;
status = contacts_query_create(_contacts_person_phone_log._uri, &query);
- if (status != CONTACTS_ERROR_NONE) {
- contacts_filter_destroy(filter);
- return 0;
- }
+ if (status != CONTACTS_ERROR_NONE)
+ goto done;
status = contacts_query_set_filter(query, filter);
- if (status != CONTACTS_ERROR_NONE) {
- contacts_filter_destroy(filter);
- contacts_query_destroy(query);
- return 0;
- }
+ if (status != CONTACTS_ERROR_NONE)
+ goto done;
- status = contacts_db_get_records_with_query(query, -1, -1, &record_list);
+ 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;
- }
+ if (status != CONTACTS_ERROR_NONE)
+ goto done;
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;
- }
+ if (status != CONTACTS_ERROR_NONE)
+ goto done;
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;
- }
+ if (status != CONTACTS_ERROR_NONE)
+ goto done;
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);
+ if (status != CONTACTS_ERROR_NONE)
+ goto done;
- return 0;
- }
+done:
+ if (record_list != NULL)
+ contacts_list_destroy(record_list, TRUE);
- contacts_list_destroy(record_list, TRUE);
contacts_filter_destroy(filter);
- contacts_query_destroy(query);
+ if (query != NULL)
+ contacts_query_destroy(query);
+
+ FN_END;
return person_id;
}
+int _bluetooth_get_contact_addressbook(gint person_id)
+{
+ contacts_record_h person = NULL;
+ contacts_record_h contact = NULL;
+ contacts_record_h addressbook = NULL;
+
+ char* addressbook_name = NULL;
+ gint contact_id = 0;
+ gint address_book_id = 0;
+ gint status;
+
+ status = contacts_db_get_record(_contacts_person._uri,
+ person_id,
+ &person);
+ if (status != CONTACTS_ERROR_NONE)
+ return PBAP_ADDRESSBOOK_PHONE; /* Default*/
+
+ status = contacts_record_get_int(person,
+ _contacts_person.display_contact_id,
+ &contact_id);
+ contacts_record_destroy(person, TRUE);
+
+ if (status != CONTACTS_ERROR_NONE)
+ return PBAP_ADDRESSBOOK_PHONE; /* Default*/
+
+ status = contacts_db_get_record(_contacts_contact._uri,
+ contact_id,
+ &contact);
+ if (status != CONTACTS_ERROR_NONE)
+ return PBAP_ADDRESSBOOK_PHONE; /* Default*/
+
+ status = contacts_record_get_int(contact,
+ _contacts_contact.address_book_id,
+ &address_book_id);
+ contacts_record_destroy(contact, TRUE);
+
+ if (status != CONTACTS_ERROR_NONE)
+ return PBAP_ADDRESSBOOK_PHONE; /* Default*/
+
+ status = contacts_db_get_record(_contacts_address_book._uri,
+ address_book_id,
+ &addressbook);
+ if (status != CONTACTS_ERROR_NONE)
+ return PBAP_ADDRESSBOOK_PHONE; /* Default*/
+
+ status = contacts_record_get_str_p(addressbook, _contacts_address_book.name,
+ &addressbook_name);
+ contacts_record_destroy(addressbook, TRUE);
+
+ if (status != CONTACTS_ERROR_NONE)
+ return PBAP_ADDRESSBOOK_PHONE; /* Default*/
+
+ if (address_book_id == 0 || _bt_is_sim_addressbook(addressbook_name) == false)
+ return PBAP_ADDRESSBOOK_PHONE;
+
+ return PBAP_ADDRESSBOOK_SIM;
+}
/* API for vcard */
gchar *_bluetooth_pb_vcard_contact(gint person_id,
guint64 filter,
guint8 format)
{
+ FN_START;
gchar *str = NULL;
if (person_id <= 0)
str = __bluetooth_pb_vcard_real_contact_with_properties(person_id, 0,
filter, format,
NULL);
+ FN_END;
return str;
}
guint64 filter,
guint8 format)
{
+ FN_START;
GString *str = g_string_new("BEGIN:VCARD\r\n");
gchar *fn;
gchar *name;
__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);
+ __bluetooth_pb_vcard_append_v30(str, "TEL", "TYPE=CELL",
+ number);
break;
case VCARD_FORMAT_2_1:
- default :
+ 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, "FN",
+ NULL, fn);
- __bluetooth_pb_vcard_append_qp_encode_v21(str, "TEL", "CELL", number);
+ __bluetooth_pb_vcard_append_qp_encode_v21(str, "TEL", "CELL",
+ number);
break;
}
g_free(fn);
g_free(name);
+ FN_END;
return g_string_free(str, FALSE);
}
guint8 format,
const gchar *attr)
{
+ FN_START;
gint person_id = 0;
gchar *str = NULL;
if (attr == NULL) {
- DBG("Unknown attribute type ignored\n");
+ ERR("Unknown attribute type ignored\n");
return NULL;
}
if (filter == 0 || (filter & VCARD_X_IRMC_CALL_DATETIME)) {
gchar *datetime = NULL;
- datetime = __bluetooth_pb_phonelog_datetime(phonelog_id);
+ datetime = __bluetooth_pb_phonelog_datetime(
+ phonelog_id);
- str = __bluetooth_pb_vcard_real_contact_with_properties(person_id,
+ str = __bluetooth_pb_vcard_real_contact_with_properties(
+ person_id,
phonelog_id,
filter, format,
"X-IRMC-CALL-DATETIME", attr, datetime,
NULL);
- if(datetime)
+ if (datetime)
g_free(datetime);
- }
- else {
- str = __bluetooth_pb_vcard_real_contact_with_properties(person_id,
+ } 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);
+ } else
+ str = __bluetooth_pb_vcard_real_call(phonelog_id, filter,
+ format, attr);
+ FN_END;
return str;
}
gchar *_bluetooth_pb_fn_from_person_id(gint person_id)
{
+ FN_START;
contacts_record_h person = NULL;
gint status;
contacts_record_destroy(person, TRUE);
+ FN_END;
return str;
}
gchar *_bluetooth_pb_name_from_person_id(gint person_id)
{
+ FN_START;
contacts_record_h person = NULL;
contacts_record_h contact = NULL;
return NULL;
}
- contacts_db_get_record(_contacts_contact._uri,
+ status = contacts_db_get_record(_contacts_contact._uri,
contact_id,
&contact);
contacts_record_destroy(contact, TRUE);
contacts_record_destroy(person, TRUE);
+ FN_END;
return str;
}
gchar *_bluetooth_pb_number_from_person_id(gint person_id)
{
+ FN_START;
contacts_record_h person = NULL;
contacts_record_h contact = NULL;
contacts_record_destroy(contact, TRUE);
contacts_record_destroy(person, TRUE);
+ FN_END;
return str;
}
gchar *_bluetooth_pb_fn_from_phonelog_id(gint phonelog_id)
{
+ FN_START;
gint person_id = 0;
gchar *str = NULL;
if (person_id > 0)
str = _bluetooth_pb_fn_from_person_id(person_id);
else
- str = _bluetooth_pb_number_from_phonelog_id(phonelog_id);
+ str = g_strdup("");
+ FN_END;
return str;
}
gchar *_bluetooth_pb_name_from_phonelog_id(gint phonelog_id)
{
+ FN_START;
gint person_id = 0;
gchar *str = NULL;
g_free(tmp);
}
+ FN_END;
return str;
}
gchar *_bluetooth_pb_number_from_phonelog_id(gint phonelog_id)
{
+ FN_START;
contacts_record_h phone_log;
gint status;
if (status != CONTACTS_ERROR_NONE)
return NULL;
- contacts_record_get_str_p(phone_log,
+ status = contacts_record_get_str_p(phone_log,
_contacts_phone_log.address,
&tmp);
contacts_record_destroy(phone_log, TRUE);
+ FN_END;
return str;
}
gchar *_bluetooth_pb_owner_name(void)
{
+ FN_START;
gchar *name;
name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
if (name == NULL)
name = g_strdup("My Name");
+ FN_END;
return name;
}
+
+bool _bt_is_sim_addressbook(const char *addressbook)
+{
+ return g_str_has_prefix(addressbook, SIM_ADDRESSBOOK_PREFIX);
+}
/*
- * bluetooth-agent
+ * Bluetooth-agent
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hocheol Seo <hocheol.seo@samsung.com>
+ * Girishashok Joshi <girish.joshi@samsung.com>
+ * Chanyeol Park <chanyeol.park@samsung.com>
*
* 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
+ * 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,
#include <glib.h>
+#define SIM_ADDRESSBOOK_PREFIX "http://tizen.samsung.com/addressbook/sim"
+
+typedef enum {
+ PBAP_ADDRESSBOOK_PHONE,
+ PBAP_ADDRESSBOOK_SIM,
+} bt_pbap_addressbook_e;
+
/* vcard */
gchar *_bluetooth_pb_vcard_contact(gint person_id,
guint64 filter,
gchar *_bluetooth_pb_owner_name(void);
+bool _bt_is_sim_addressbook(const char *addressbook);
+
#endif
[D-BUS Service]
Name=org.bluez.pb_agent
Exec=/usr/bin/bluetooth-pb-agent
-User=root