2 * Bluetooth protocol stack for Linux
4 * Copyright (c) 2000 - 2010 Samsung Electronics Co., Ltd.
6 * Contact: Chethan T N <chethan.tn@samsung.com>
8 * This library is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by the
10 * Free Software Foundation; either version 2.1 of the License, or (at your option)
13 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 * License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software Foundation, Inc., 51
20 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *//*:Associate with "Bluetooth" */
31 #include <glib-object.h>
33 #include <dbus/dbus.h>
37 #include "telephony.h"
41 /* CSD CALL plugin D-Bus definitions */
42 #define CSD_CALL_BUS_NAME "org.tizen.csd"
43 #define CSD_CALL_INTERFACE "org.tizen.csd.Call"
44 #define CSD_CALL_INSTANCE "org.tizen.csd.Call.Instance"
45 #define CSD_CALL_CONFERENCE_PATH "/org/tizen/csd/call/conference"
46 #define CSD_DEVICE_INTERFACE "org.tizen.device"
48 /* Phonebook definitions */
49 #define PHONEBOOK_BUS_NAME "org.bluez.pb_agent"
50 #define PHONEBOOK_PATH "/org/bluez/pb_agent"
51 #define PHONEBOOK_INTERFACE "org.bluez.PbAgent.At"
53 #define CALL_FLAG_NONE 0
54 #define CALL_FLAG_PRESENTATION_ALLOWED 0x01
55 #define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
57 #define TELEPHONY_CSD_INTERFACE "org.tizen.telephony.csd"
58 #define TELEPHONY_CSD_OBJECT_PATH "/org/tizen/csd"
60 #define HFP_AGENT_SERVICE "org.bluez.hfp_agent"
61 #define HFP_AGENT_PATH "/org/bluez/hfp_agent"
62 #define HFP_AGENT_INTERFACE "Org.Hfp.Bluez.Interface"
64 /* Call status values as exported by the CSD CALL plugin */
65 #define CSD_CALL_STATUS_IDLE 0
66 #define CSD_CALL_STATUS_CREATE 1
67 #define CSD_CALL_STATUS_COMING 2
68 #define CSD_CALL_STATUS_PROCEEDING 3
69 #define CSD_CALL_STATUS_MO_ALERTING 4
70 #define CSD_CALL_STATUS_MT_ALERTING 5
71 #define CSD_CALL_STATUS_WAITING 6
72 #define CSD_CALL_STATUS_ANSWERED 7
73 #define CSD_CALL_STATUS_ACTIVE 8
74 #define CSD_CALL_STATUS_MO_RELEASE 9
75 #define CSD_CALL_STATUS_MT_RELEASE 10
76 #define CSD_CALL_STATUS_HOLD_INITIATED 11
77 #define CSD_CALL_STATUS_HOLD 12
78 #define CSD_CALL_STATUS_RETRIEVE_INITIATED 13
79 #define CSD_CALL_STATUS_RECONNECT_PENDING 14
80 #define CSD_CALL_STATUS_TERMINATED 15
81 #define CSD_CALL_STATUS_SWAP_INITIATED 16
84 #define PREFFERED_MESSAGE_STORAGE_LIST "(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\")"
86 #define PREFFERED_MESSAGE_STORAGE_MAX 500
87 #define CALL_LOG_COUNT_MAX 30
88 #define PHONEBOOK_COUNT_MAX 1000
90 #define PHONEBOOK_NAME_MAX_LENGTH 20
91 #define PHONEBOOK_NUMBER_MAX_LENGTH 20
92 #define PHONEBOOK_MAX_CHARACTER_LENGTH 20
94 #define PHONEBOOK_READ_RESP_LENGTH 20
101 static const char *character_set_list[] = {
102 "\"UTF-8\"", "\"IRA\""
105 static const char *phonebook_store_list[] = {
106 "\"ME\"", "\"DC\"", "\"MC\"", "\"RC\""
109 #define CHARACTER_SET_LIST_SIZE (sizeof(character_set_list)/sizeof(const char *))
110 #define PHONEBOOK_STORE_LIST_SIZE (sizeof(phonebook_store_list)/sizeof(const char *))
119 const GsmUnicodeTable gsm_unicode_C3[] = {
120 {0xA8,0x04}, {0xA9,0x05}, {0xB9,0x06}, {0xAC,0x07}, {0xB2,0x08},
121 {0xB7,0x09}, {0x98,0x0B}, {0xB8,0x0C}, {0x85,0x0E}, {0xA5,0x0F},
122 {0x86,0x1C}, {0xA6,0x1D}, {0x9F,0x1E}, {0x89,0x1F}, {0x84,0x5B},
123 {0x96,0x5C}, {0x91,0x5D}, {0x9C,0x5E}, {0x80,0x5F}, {0xA4,0x7B},
124 {0xB6,0x7C}, {0xB1,0x7D}, {0xBC,0x7E}, {0xA0,0x7F},
128 const GsmUnicodeTable gsm_unicode_CE[] = {
129 {0x85,0x14}, {0xA1,0x50}, {0x98,0x19}, {0xA0,0x16}, {0x94,0x10},
130 {0xA6,0x12}, {0x93,0x13}, {0x9E,0x1A}, {0x9B,0x14}, {0xA8,0x17},
134 #define GSM_UNI_MAX_C3 (sizeof(gsm_unicode_C3)/sizeof(GsmUnicodeTable))
135 #define GSM_UNI_MAX_CE (sizeof(gsm_unicode_CE)/sizeof(GsmUnicodeTable))
138 static DBusConnection *ag_connection = NULL;
140 static GSList *calls = NULL;
142 static gboolean events_enabled = FALSE;
143 static uint32_t callerid = 0;
145 /* Reference count for determining the call indicator status */
146 static GSList *active_calls = NULL;
147 static GSList *sender_paths = NULL;
152 unsigned int watch_id;
155 static struct indicator telephony_ag_indicators[] =
157 { "battchg", "0-5", 5, TRUE },
158 /* signal strength in terms of bars */
159 { "signal", "0-5", 0, TRUE },
160 { "service", "0,1", 0, TRUE },
161 { "call", "0,1", 0, TRUE },
162 { "callsetup", "0-3", 0, TRUE },
163 { "callheld", "0-2", 0, FALSE },
164 { "roam", "0,1", 0, TRUE },
168 static char *call_status_str[] = {
182 "RETRIEVE_INITIATED",
189 enum net_registration_status {
190 NETWORK_REG_STATUS_HOME,
191 NETWORK_REG_STATUS_ROAMING,
192 NETWORK_REG_STATUS_OFFLINE,
193 NETWORK_REG_STATUS_SEARCHING,
194 NETWORK_REG_STATUS_NO_SIM,
195 NETWORK_REG_STATUS_POWEROFF,
196 NETWORK_REG_STATUS_POWERSAFE,
197 NETWORK_REG_STATUS_NO_COVERAGE,
198 NETWORK_REG_STATUS_REJECTED,
199 NETWORK_REG_STATUS_UNKOWN
205 gboolean originating;
220 .operator_name = NULL,
221 .status = NETWORK_REG_STATUS_UNKOWN,
222 /* Init as 0 meaning inactive mode. In modem power off state
223 * can be be -1, but we treat all values as 0s regardless
224 * inactive or power off. */
228 /* Supported set of call hold operations */
229 /*static const char *telephony_chld_str = "0,1,1x,2,2x,3,4";*/
230 static const char *telephony_chld_str = "0,1,2,3";
233 static char *subscriber_number = NULL; /* Subscriber number */
244 static void call_set_status(struct csd_call *call, dbus_uint32_t status);
246 static void free_sender_path(sender_path_t *s_path)
251 g_free(s_path->path);
252 g_free(s_path->sender);
256 static void free_sender_list()
260 for (l = sender_paths; l != NULL; l = l->next) {
261 free_sender_path(l->data);
263 g_slist_free(sender_paths);
268 static int telephony_remove_from_sender_list(const char *sender, const char *path)
271 sender_path_t *s_path;
273 if (sender == NULL || path == NULL)
276 for (l = sender_paths; l != NULL; l = l->next) {
280 if (g_strcmp0(s_path->path, path) == 0) {
281 g_dbus_remove_watch(ag_connection, s_path->watch_id);
282 sender_paths = g_slist_remove(sender_paths, s_path);
283 free_sender_path(s_path);
285 /*Free sender_paths if no application is registered*/
286 if (0 == g_slist_length(sender_paths)) {
287 g_slist_free(sender_paths);
296 static void remove_call_with_sender(gchar *sender)
305 for (l = calls; l != NULL; l = l->next) {
306 struct csd_call *call = l->data;
308 if (g_strcmp0(call->sender, sender) == 0)
309 /* Release the Call and inform headset */
310 call_set_status(call, CSD_CALL_STATUS_MT_RELEASE);
316 static void telephony_app_exit_cb(DBusConnection *conn, void *user_data)
318 sender_path_t *s_path = (sender_path_t *)user_data;
325 /* check any active call from application */
326 remove_call_with_sender(s_path->sender);
328 if (!telephony_remove_from_sender_list(s_path->sender, s_path->path))
329 DBG("Application removed \n");
331 DBG("Application not removed \n");
335 static gboolean telephony_is_registered(const char *path)
338 sender_path_t *s_path;
340 if (path == NULL || sender_paths == NULL)
343 for (l = sender_paths; l != NULL; l = l->next) {
348 if (g_strcmp0(s_path->path, path) == 0) {
355 static gboolean telephony_is_call_allowed(const char *path)
362 /*if call list doesn't exist the call should be allowed, since its a new call*/
366 for (l = calls; l != NULL; l = l->next) {
367 struct csd_call *call = l->data;
369 if (g_strcmp0(call->path, path) == 0)
376 static int telephony_add_to_sender_list(const char *sender, const char *path)
378 sender_path_t *s_path;
380 if (sender == NULL || path == NULL)
383 /*check if already registered*/
384 if (telephony_is_registered(path)) {
388 s_path = g_new0(sender_path_t, 1);
389 s_path->path = g_strdup(path);
390 s_path->sender = g_strdup(sender);
391 s_path->watch_id = g_dbus_add_disconnect_watch(ag_connection, sender,
392 telephony_app_exit_cb, s_path, NULL);
393 sender_paths = g_slist_append(sender_paths, s_path);
397 static struct csd_call *find_call_with_id(uint32_t call_id)
402 for (l = calls; l != NULL; l = l->next) {
403 struct csd_call *call = l->data;
405 if (call->call_id == call_id)
412 static struct csd_call *find_non_held_call(void)
416 for (l = calls; l != NULL; l = l->next) {
417 struct csd_call *call = l->data;
419 if (call->status == CSD_CALL_STATUS_IDLE)
422 if (call->status != CSD_CALL_STATUS_HOLD)
429 static struct csd_call *find_non_idle_call(void)
433 for (l = calls; l != NULL; l = l->next) {
434 struct csd_call *call = l->data;
436 if (call->status != CSD_CALL_STATUS_IDLE)
443 static struct csd_call *find_call_with_status(int status)
448 for (l = calls; l != NULL; l = l->next) {
449 struct csd_call *call = l->data;
451 if (call->status == status)
458 static void csd_call_free(struct csd_call *call)
464 g_free(call->number);
465 g_free(call->sender);
470 static int reject_call(struct csd_call *call)
476 DBG("telephony-tizen: reject_call ");
478 msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
479 HFP_AGENT_INTERFACE, "RejectCall");
481 error("Unable to allocate new D-Bus message");
484 DBG(" Path =[ %s] and Call id = [%d]\n", call->path, call->call_id);
485 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
486 DBUS_TYPE_STRING, &call->path,
487 DBUS_TYPE_STRING, &call->sender,
488 DBUS_TYPE_INVALID)) {
490 DBG("dbus_message_append_args -ENOMEM\n");
491 dbus_message_unref(msg);
495 g_dbus_send_message(ag_connection, msg);
503 static int release_call(struct csd_call *call)
509 DBG("telephony-tizen: release_call ");
511 msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
512 HFP_AGENT_INTERFACE, "ReleaseCall");
514 error("Unable to allocate new D-Bus message");
517 DBG("Path =[ %s] and Call id = [%d]\n", call->path, call->call_id);
518 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
519 DBUS_TYPE_STRING, &call->path,
520 DBUS_TYPE_STRING, &call->sender,
521 DBUS_TYPE_INVALID)) {
523 DBG("dbus_message_append_args -ENOMEM\n");
524 dbus_message_unref(msg);
528 g_dbus_send_message(ag_connection, msg);
535 static int release_conference(void)
541 for (l = calls; l != NULL; l = l->next) {
542 struct csd_call *call = l->data;
544 if (call->conference)
553 static int dbus_method_call_send(const char *dest, const char *path,
554 const char *interface, const char *method,
555 DBusPendingCallNotifyFunction cb,
556 void *user_data, int type, ...)
559 DBusPendingCall *call;
564 msg = dbus_message_new_method_call(dest, path, interface, method);
566 error("Unable to allocate new D-Bus %s message", method);
570 va_start(args, type);
572 if (!dbus_message_append_args_valist(msg, type, args)) {
573 dbus_message_unref(msg);
581 g_dbus_send_message(ag_connection, msg);
585 if (!dbus_connection_send_with_reply(ag_connection, msg, &call, -1)) {
586 error("Sending %s failed", method);
587 dbus_message_unref(msg);
591 dbus_pending_call_set_notify(call, cb, user_data, NULL);
592 dbus_message_unref(msg);
598 static int answer_call(struct csd_call *call)
603 msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
604 HFP_AGENT_INTERFACE, "AnswerCall");
606 error("Unable to allocate new D-Bus message");
610 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
611 DBUS_TYPE_STRING, &call->path,
612 DBUS_TYPE_STRING, &call->sender,
613 DBUS_TYPE_INVALID)) {
615 DBG("dbus_message_append_args -ENOMEM\n");
616 dbus_message_unref(msg);
619 g_dbus_send_message(ag_connection, msg);
624 static int reject_accept_call(struct csd_call *call, void *telephony_device)
626 uint32_t chld_value = 1;
628 return dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
629 HFP_AGENT_INTERFACE, "ThreewayCall",
630 NULL, telephony_device,
631 DBUS_TYPE_UINT32, &chld_value,
632 DBUS_TYPE_STRING, &call->path,
633 DBUS_TYPE_STRING, &call->sender,
637 static int number_type(const char *number)
640 return NUMBER_TYPE_TELEPHONY;
642 if (number[0] == '+' || strncmp(number, "00", 2) == 0)
643 return NUMBER_TYPE_INTERNATIONAL;
645 return NUMBER_TYPE_TELEPHONY;
648 /* Since we dont have support from voice call regarding call conference this */
649 /* function will handle both join and split scenarios */
651 /* This function checks the status of each call in the list and set/unset */
652 /* conference status based on below algorithm */
653 /* If more that one active/held calls are there, conf flag of those calls will be set */
654 /* If only one active/held call is there, conf flag of those calls will be unset */
655 static void handle_conference(void)
658 struct csd_call *first_active_call = NULL;
659 struct csd_call *first_held_call = NULL;
660 int active_call_count = 0;
661 int held_call_count = 0;
663 for (l = calls; l != NULL; l = l->next) {
664 struct csd_call *call = l->data;
666 if (call->status == CSD_CALL_STATUS_ACTIVE) {
667 if (first_active_call == NULL)
668 first_active_call = call;
672 if (active_call_count >= 2) {
673 if (!first_active_call->conference)
674 first_active_call->conference = TRUE;
675 call->conference = TRUE;
678 } else if (call->status == CSD_CALL_STATUS_HOLD) {
679 if (first_held_call == NULL)
680 first_held_call = call;
684 if (held_call_count >= 2) {
685 if (!first_held_call->conference)
686 first_held_call->conference = TRUE;
687 call->conference = TRUE;
692 if (active_call_count == 1) {
693 if (first_active_call->conference)
694 first_active_call->conference = FALSE;
697 if (held_call_count == 1) {
698 if (first_held_call->conference)
699 first_held_call->conference = FALSE;
703 static void call_set_status(struct csd_call *call, dbus_uint32_t status)
705 dbus_uint32_t prev_status;
710 callheld = telephony_get_indicator(telephony_ag_indicators, "callheld");
712 prev_status = call->status;
713 DBG("Call %s Call id %d changed from %s to %s", call->path, call->call_id,
714 call_status_str[prev_status], call_status_str[status]);
716 if (prev_status == status) {
717 DBG("Ignoring CSD Call state change to existing state");
721 call->status = (int) status;
724 case CSD_CALL_STATUS_IDLE:
726 telephony_update_indicator(telephony_ag_indicators,
728 EV_CALLSETUP_INACTIVE);
729 if (!call->originating)
730 telephony_calling_stopped_ind();
733 g_free(call->number);
735 call->originating = FALSE;
736 call->emergency = FALSE;
737 call->on_hold = FALSE;
738 call->conference = FALSE;
741 case CSD_CALL_STATUS_CREATE:
742 call->originating = TRUE;
745 case CSD_CALL_STATUS_COMING:
746 call->originating = FALSE;
749 case CSD_CALL_STATUS_PROCEEDING:
751 case CSD_CALL_STATUS_MO_ALERTING:
752 telephony_update_indicator(telephony_ag_indicators, "callsetup",
753 EV_CALLSETUP_ALERTING);
755 case CSD_CALL_STATUS_MT_ALERTING:
756 /* Some headsets expect incoming call notification before they
757 * can send ATA command. When call changed status from waiting
758 * to alerting we need to send missing notification. Otherwise
759 * headsets like Nokia BH-108 or BackBeat 903 are unable to
760 * answer incoming call that was previously waiting. */
761 if (prev_status == CSD_CALL_STATUS_WAITING)
762 telephony_incoming_call_ind(call->number,
763 number_type(call->number));
765 case CSD_CALL_STATUS_WAITING:
767 case CSD_CALL_STATUS_ANSWERED:
769 case CSD_CALL_STATUS_ACTIVE:
771 call->on_hold = FALSE;
772 if (find_call_with_status(CSD_CALL_STATUS_HOLD))
773 telephony_update_indicator(telephony_ag_indicators,
775 EV_CALLHELD_MULTIPLE);
777 telephony_update_indicator(telephony_ag_indicators,
781 if (!g_slist_find(active_calls, call))
782 active_calls = g_slist_prepend(active_calls, call);
783 if (g_slist_length(active_calls) == 1)
784 telephony_update_indicator(telephony_ag_indicators,
787 /* Upgrade callheld status if necessary */
788 if (callheld == EV_CALLHELD_ON_HOLD)
789 telephony_update_indicator(telephony_ag_indicators,
791 EV_CALLHELD_MULTIPLE);
792 telephony_update_indicator(telephony_ag_indicators,
794 EV_CALLSETUP_INACTIVE);
795 if (!call->originating)
796 telephony_calling_stopped_ind();
800 case CSD_CALL_STATUS_MO_RELEASE:
801 case CSD_CALL_STATUS_MT_RELEASE:
802 active_calls = g_slist_remove(active_calls, call);
803 if (g_slist_length(active_calls) == 0)
804 telephony_update_indicator(telephony_ag_indicators, "call",
807 if ((prev_status == CSD_CALL_STATUS_MO_ALERTING) ||
808 (prev_status == CSD_CALL_STATUS_COMING) ||
809 (prev_status == CSD_CALL_STATUS_CREATE) ||
810 (prev_status == CSD_CALL_STATUS_WAITING)) {
811 telephony_update_indicator(telephony_ag_indicators,
813 EV_CALLSETUP_INACTIVE);
816 if (prev_status == CSD_CALL_STATUS_COMING) {
817 if (!call->originating)
818 telephony_calling_stopped_ind();
820 calls = g_slist_remove(calls, call);
824 case CSD_CALL_STATUS_HOLD_INITIATED:
826 case CSD_CALL_STATUS_HOLD:
827 call->on_hold = TRUE;
828 if (find_non_held_call())
829 telephony_update_indicator(telephony_ag_indicators,
831 EV_CALLHELD_MULTIPLE);
833 telephony_update_indicator(telephony_ag_indicators,
835 EV_CALLHELD_ON_HOLD);
837 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
839 case CSD_CALL_STATUS_RECONNECT_PENDING:
841 case CSD_CALL_STATUS_TERMINATED:
843 !find_call_with_status(CSD_CALL_STATUS_HOLD)) {
844 telephony_update_indicator(telephony_ag_indicators,
850 if (callheld == EV_CALLHELD_MULTIPLE &&
851 find_call_with_status(CSD_CALL_STATUS_HOLD) &&
852 !find_call_with_status(CSD_CALL_STATUS_ACTIVE))
853 telephony_update_indicator(telephony_ag_indicators,
855 EV_CALLHELD_ON_HOLD);
857 case CSD_CALL_STATUS_SWAP_INITIATED:
860 error("Unknown call status %u", status);
864 /* Update the conference status of each call */
870 static void telephony_chld_reply(DBusPendingCall *call, void *data)
872 DBusMessage *reply = dbus_pending_call_steal_reply(call);
877 dbus_error_init(&derr);
878 if (!dbus_set_error_from_message(&derr, reply)) {
879 DBG("chld reply: cmd is valid");
880 telephony_dial_number_rsp(data, CME_ERROR_NONE);
884 DBG("chld_reply reply: %s", derr.message);
886 dbus_error_free(&derr);
887 telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
890 dbus_message_unref(reply);
893 void telephony_call_hold_req(void *telephony_device, const char *cmd)
896 struct csd_call *call;
900 sender_path_t *s_path = NULL;
904 DBG("telephony-tizen: got call hold request %s", cmd);
906 /* Find any Ongoing call, in active/held/waiting */
907 if (NULL == (call = find_call_with_status(CSD_CALL_STATUS_ACTIVE)))
908 if (NULL == (call = find_call_with_status(
909 CSD_CALL_STATUS_HOLD)))
910 if (NULL == (call = find_call_with_status(
911 CSD_CALL_STATUS_WAITING))) {
912 DBG("No Onging Call \n");
913 telephony_call_hold_rsp(telephony_device,
914 CME_ERROR_AG_FAILURE);
918 /*Get sender path using call path*/
919 for (l = sender_paths; l != NULL; l = l->next) {
921 if (s_path == NULL) {
922 telephony_call_hold_rsp(telephony_device,
923 CME_ERROR_AG_FAILURE);
926 if (g_strcmp0(s_path->path, call->path) == 0)
930 if (s_path == NULL) {
931 telephony_call_hold_rsp(telephony_device,
932 CME_ERROR_AG_FAILURE);
937 chld_value = strtoul(idx, NULL, 0);
939 DBG("Sender = %s path = %s \n", s_path->sender, s_path->path);
941 err = dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
942 HFP_AGENT_INTERFACE, "ThreewayCall",
943 telephony_chld_reply, telephony_device,
944 DBUS_TYPE_UINT32, &chld_value,
945 DBUS_TYPE_STRING, &call->path,
946 DBUS_TYPE_STRING, &call->sender,
950 telephony_call_hold_rsp(telephony_device,
951 CME_ERROR_AG_FAILURE);
955 static int update_registration_status(uint8_t status)
963 if (net.status == new_status)
966 switch (new_status) {
967 case NETWORK_REG_STATUS_HOME:
968 ret = telephony_update_indicator(telephony_ag_indicators, "roam",
971 if (net.status > NETWORK_REG_STATUS_ROAMING) {
972 ret = telephony_update_indicator(telephony_ag_indicators,
977 case NETWORK_REG_STATUS_ROAMING:
978 ret = telephony_update_indicator(telephony_ag_indicators, "roam",
981 if (net.status > NETWORK_REG_STATUS_ROAMING) {
982 ret = telephony_update_indicator(telephony_ag_indicators,
987 case NETWORK_REG_STATUS_OFFLINE:
988 case NETWORK_REG_STATUS_SEARCHING:
989 case NETWORK_REG_STATUS_NO_SIM:
990 case NETWORK_REG_STATUS_POWEROFF:
991 case NETWORK_REG_STATUS_POWERSAFE:
992 case NETWORK_REG_STATUS_NO_COVERAGE:
993 case NETWORK_REG_STATUS_REJECTED:
994 case NETWORK_REG_STATUS_UNKOWN:
995 if (net.status < NETWORK_REG_STATUS_OFFLINE) {
996 ret = telephony_update_indicator(telephony_ag_indicators,
1003 net.status = new_status;
1005 DBG("telephony-tizen: registration status changed: %d", status);
1011 static int update_signal_strength(int32_t signal_bars)
1015 if (signal_bars < 0) {
1016 DBG("signal strength smaller than expected: %d < 0",
1019 } else if (signal_bars > 5) {
1020 DBG("signal strength greater than expected: %d > 5",
1025 if (net.signal_bars == signal_bars)
1028 net.signal_bars = signal_bars;
1029 DBG("telephony-tizen: signal strength updated: %d/5", signal_bars);
1031 return telephony_update_indicator(telephony_ag_indicators, "signal", signal_bars);
1034 static int update_battery_strength(int32_t battery_level)
1036 int current_battchg = 0;
1040 current_battchg = telephony_get_indicator(telephony_ag_indicators, "battchg");
1042 if (battery_level < 0) {
1043 DBG("Battery strength smaller than expected: %d < 0",
1046 } else if (battery_level > 5) {
1047 DBG("Battery strength greater than expected: %d > 5",
1051 if (current_battchg == battery_level)
1054 DBG("telephony-tizen: battery strength updated: %d/5", battery_level);
1057 return telephony_update_indicator(telephony_ag_indicators,
1058 "battchg", battery_level);
1062 static int update_operator_name(const char *name)
1068 g_free(net.operator_name);
1069 net.operator_name = g_strndup(name, 16);
1070 DBG("telephony-tizen: operator name updated: %s", name);
1075 static int update_subscriber_number(const char *number)
1081 g_free(subscriber_number);
1082 subscriber_number = g_strdup(number);
1083 DBG("telephony-tizen: subscriber_number updated: %s", subscriber_number);
1088 static DBusMessage *telephony_error_reply(DBusMessage *msg, int error)
1092 return btd_error_not_available(msg);
1094 return btd_error_not_connected(msg);
1096 return btd_error_busy(msg);
1098 return btd_error_invalid_args(msg);
1100 return btd_error_already_exists(msg);
1102 return btd_error_failed(msg, "No memory");
1104 return btd_error_failed(msg, "I/O error");
1106 return dbus_message_new_method_return(msg);
1110 static struct csd_call *create_call(DBusMessage *msg, const char *path,
1111 const char *number, uint32_t call_id,
1115 struct csd_call *call;
1117 call = find_call_with_id(call_id);
1119 call = g_new0(struct csd_call, 1);
1120 call->path = g_strdup(path);
1121 call->call_id = call_id;
1122 call->number = g_strdup(number);
1123 call->sender = g_strdup(sender);
1124 calls = g_slist_append(calls, call);
1129 static DBusMessage *incoming(DBusConnection *conn, DBusMessage *msg,
1132 const char *number, *call_path;
1134 struct csd_call *call;
1138 DBG("telephony_incoming()\n");
1140 if (!dbus_message_get_args(msg, NULL,
1141 DBUS_TYPE_STRING, &call_path,
1142 DBUS_TYPE_STRING, &number,
1143 DBUS_TYPE_UINT32, &call_id,
1144 DBUS_TYPE_STRING, &sender,
1145 DBUS_TYPE_INVALID)) {
1147 return btd_error_invalid_args(msg);
1150 ret = telephony_is_registered(call_path);
1152 return telephony_error_reply(msg, -ENOENT);
1154 /*Check in the active call list, if any of the call_path exists if not don't allow
1155 the call since it is initated by other applicatoin*/
1157 ret = telephony_is_call_allowed(call_path);
1159 return telephony_error_reply(msg, -ENOENT);
1162 call = create_call(msg, call_path, number, call_id, sender);
1164 DBG("Incoming call to %s from number %s call id %d", call_path, number, call_id);
1165 ret = telephony_update_indicator(telephony_ag_indicators, "callsetup",
1166 EV_CALLSETUP_INCOMING);
1168 return telephony_error_reply(msg, ret);
1170 if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
1171 find_call_with_status(CSD_CALL_STATUS_HOLD)) {
1172 ret = telephony_call_waiting_ind(call->number,
1173 number_type(call->number));
1175 return telephony_error_reply(msg, ret);
1177 call_set_status(call, CSD_CALL_STATUS_WAITING);
1179 ret = telephony_incoming_call_ind(call->number,
1180 number_type(call->number));
1182 return telephony_error_reply(msg, ret);
1184 call_set_status(call, CSD_CALL_STATUS_COMING);
1187 return dbus_message_new_method_return(msg);
1190 static DBusMessage *outgoing(DBusConnection *conn, DBusMessage *msg,
1193 const char *number, *call_path;
1195 struct csd_call *call;
1200 DBG("telephony_outgoing_call()\n");
1202 if (!dbus_message_get_args(msg, NULL,
1203 DBUS_TYPE_STRING, &call_path,
1204 DBUS_TYPE_STRING, &number,
1205 DBUS_TYPE_UINT32, &call_id,
1206 DBUS_TYPE_STRING, &sender,
1207 DBUS_TYPE_INVALID)) {
1208 return btd_error_invalid_args(msg);
1211 ret = telephony_is_registered(call_path);
1213 return telephony_error_reply(msg, -ENOENT);
1215 /*Check in the active call list, if any of the call_path exists if not don't allow
1216 the call since it is initated by other applicatoin*/
1218 ret = telephony_is_call_allowed(call_path);
1220 return telephony_error_reply(msg, -ENOENT);
1222 call = create_call(msg, call_path, number, call_id, sender);
1224 DBG("Outgoing call to %s from number %s call id %d", call_path, number, call_id);
1226 call_set_status(call, CSD_CALL_STATUS_CREATE);
1228 ret = telephony_update_indicator(telephony_ag_indicators, "callsetup",
1229 EV_CALLSETUP_OUTGOING);
1231 return telephony_error_reply(msg, ret);
1234 return dbus_message_new_method_return(msg);
1237 static DBusMessage *set_call_status(DBusConnection *conn, DBusMessage *msg,
1240 struct csd_call *call;
1241 dbus_uint32_t status, call_id;
1242 const char *call_path;
1248 if (!dbus_message_get_args(msg, NULL,
1249 DBUS_TYPE_STRING, &call_path,
1250 DBUS_TYPE_UINT32, &status,
1251 DBUS_TYPE_UINT32, &call_id,
1252 DBUS_TYPE_STRING, &sender,
1253 DBUS_TYPE_INVALID)) {
1254 error("Unexpected paramters in Instance.CallStatus() signal");
1255 return btd_error_invalid_args(msg);
1259 return btd_error_invalid_args(msg);
1262 ret = telephony_is_registered(call_path);
1264 return telephony_error_reply(msg, -ENOENT);
1266 ret = telephony_is_call_allowed(call_path);
1268 return telephony_error_reply(msg, -ENOENT);
1270 DBG("status = [%d] and call_id = [%d] \n", status, call_id);
1272 call = find_call_with_id(call_id);
1275 call_path is equal to CSD_CALL_PATH then we should update the call list
1276 since the call_path is sent from native AG applicaton
1278 Added for updation of the call status if the call is not added in the call list
1280 call = create_call(msg, call_path, NULL, call_id, sender);
1282 call_set_status(call, status);
1284 return dbus_message_new_method_return(msg);
1287 static DBusMessage *register_telephony_agent(DBusConnection *conn, DBusMessage *msg,
1297 if (!dbus_message_get_args(msg, NULL,
1298 DBUS_TYPE_BOOLEAN, &flag,
1299 DBUS_TYPE_STRING, &path,
1300 DBUS_TYPE_STRING, &sender,
1301 DBUS_TYPE_INVALID)) {
1302 error("Unexpected parameters in RegisterSenderPath");
1303 return btd_error_invalid_args(msg);
1306 DBG("flag = %d \n", flag);
1307 DBG("Sender = %s \n", sender);
1308 DBG("path = %s \n", path);
1311 ret = telephony_add_to_sender_list(sender, path);
1313 ret = telephony_remove_from_sender_list(sender, path);
1316 return telephony_error_reply(msg, ret);
1320 return dbus_message_new_method_return(msg);
1323 static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
1326 const char *property;
1327 DBusMessageIter iter;
1328 DBusMessageIter sub;
1331 if (!dbus_message_iter_init(msg, &iter))
1332 return btd_error_invalid_args(msg);
1334 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1335 return btd_error_invalid_args(msg);
1337 dbus_message_iter_get_basic(&iter, &property);
1338 dbus_message_iter_next(&iter);
1340 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1341 return btd_error_invalid_args(msg);
1342 dbus_message_iter_recurse(&iter, &sub);
1344 if (g_str_equal("RegistrationChanged", property)) {
1346 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BYTE)
1347 return btd_error_invalid_args(msg);
1349 dbus_message_iter_get_basic(&sub, &value);
1351 ret = update_registration_status(value);
1353 return telephony_error_reply(msg, ret);
1354 } else if (g_str_equal("OperatorNameChanged", property)) {
1356 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
1357 return btd_error_invalid_args(msg);
1359 dbus_message_iter_get_basic(&sub, &name);
1361 ret = update_operator_name(name);
1363 return telephony_error_reply(msg, ret);
1364 } else if (g_str_equal("SignalBarsChanged", property)) {
1366 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INT32)
1367 return btd_error_invalid_args(msg);
1369 dbus_message_iter_get_basic(&sub, &value);
1370 ret = update_signal_strength(value);
1372 return telephony_error_reply(msg, ret);
1374 } else if (g_str_equal("BatteryBarsChanged", property)) {
1376 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INT32)
1377 return btd_error_invalid_args(msg);
1379 dbus_message_iter_get_basic(&sub, &value);
1380 ret = update_battery_strength(value);
1382 return telephony_error_reply(msg, ret);
1384 } else if (g_str_equal("SubscriberNumberChanged", property)) {
1386 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
1387 return btd_error_invalid_args(msg);
1389 dbus_message_iter_get_basic(&sub, &number);
1390 ret = update_subscriber_number(number);
1392 return telephony_error_reply(msg, ret);
1395 return dbus_message_new_method_return(msg);
1398 static GDBusMethodTable telephony_methods[] = {
1399 { GDBUS_METHOD("Incoming",
1400 GDBUS_ARGS({ "path", "s" }, { "number", "s" },
1401 { "id", "u" }, { "sender", "s" }),
1404 { GDBUS_METHOD("Outgoing",
1405 GDBUS_ARGS({ "path", "s" }, { "number", "s" },
1406 { "id", "u" }, { "sender", "s" }),
1409 { GDBUS_METHOD("SetCallStatus",
1410 GDBUS_ARGS({ "path", "s" }, { "status", "u" },
1411 { "id", "u" }, { "sender", "s" }),
1414 { GDBUS_METHOD("RegisterTelephonyAgent",
1415 GDBUS_ARGS({ "flag", "b" }, { "path", "s" },
1418 register_telephony_agent) },
1419 { GDBUS_METHOD("SetProperty",
1420 GDBUS_ARGS({ "name", "s" }, { "property", "v" }),
1426 static void path_unregister(void *data)
1429 g_dbus_unregister_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
1430 TELEPHONY_CSD_INTERFACE);
1434 /*API's that shall be ported*/
1435 int telephony_init(void)
1437 uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1438 AG_FEATURE_REJECT_A_CALL |
1439 AG_FEATURE_ENHANCED_CALL_STATUS |
1440 AG_FEATURE_THREE_WAY_CALLING |
1441 AG_FEATURE_VOICE_RECOGNITION;
1446 ag_connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1448 if (!g_dbus_register_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
1449 TELEPHONY_CSD_INTERFACE,
1450 telephony_methods, NULL, NULL,
1451 NULL, path_unregister)) {
1452 error("D-Bus failed to register %s interface", TELEPHONY_CSD_INTERFACE);
1456 /* Reset indicators */
1457 for (i = 0; telephony_ag_indicators[i].desc != NULL; i++) {
1458 if (g_str_equal(telephony_ag_indicators[i].desc, "battchg"))
1459 telephony_ag_indicators[i].val = 5;
1461 telephony_ag_indicators[i].val = 0;
1464 /*Initializatoin of the indicators*/
1465 telephony_ready_ind(features, telephony_ag_indicators,
1467 telephony_chld_str);
1472 void telephony_exit(void)
1476 g_free(net.operator_name);
1477 net.operator_name = NULL;
1479 g_free(subscriber_number);
1480 subscriber_number = NULL;
1482 net.status = NETWORK_REG_STATUS_UNKOWN;
1483 net.signal_bars = 0;
1485 g_slist_free(active_calls);
1486 active_calls = NULL;
1488 g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
1489 g_slist_free(calls);
1494 g_dbus_unregister_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
1495 TELEPHONY_CSD_INTERFACE);
1497 dbus_connection_unref(ag_connection);
1498 ag_connection = NULL;
1503 void telephony_device_connected(void *telephony_device)
1505 DBG("telephony-tizen: device %p connected", telephony_device);
1508 void telephony_device_disconnected(void *telephony_device)
1510 DBG("telephony-tizen: device %p disconnected", telephony_device);
1511 events_enabled = FALSE;
1514 void telephony_event_reporting_req(void *telephony_device, int ind)
1516 events_enabled = ind == 1 ? TRUE : FALSE;
1518 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
1521 void telephony_response_and_hold_req(void *telephony_device, int rh)
1523 DBG("telephony-tizen: response_and_hold_req - device %p disconnected",
1526 telephony_response_and_hold_rsp(telephony_device,
1527 CME_ERROR_NOT_SUPPORTED);
1530 static void telephony_dial_number_reply(DBusPendingCall *call, void *data)
1532 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1535 DBG("redial_reply");
1537 dbus_error_init(&derr);
1538 if (!dbus_set_error_from_message(&derr, reply)) {
1539 DBG("hfg reply: dial done successfully");
1540 telephony_dial_number_rsp(data, CME_ERROR_NONE);
1544 DBG("dial_reply reply: %s", derr.message);
1546 dbus_error_free(&derr);
1547 telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
1550 dbus_message_unref(reply);
1553 void telephony_dial_number_req(void *telephony_device, const char *number)
1555 uint32_t flags = callerid;
1557 DBG("telephony-tizen: dial request to %s", number);
1559 if (strncmp(number, "*31#", 4) == 0) {
1561 flags = CALL_FLAG_PRESENTATION_ALLOWED;
1562 } else if (strncmp(number, "#31#", 4) == 0) {
1564 flags = CALL_FLAG_PRESENTATION_RESTRICTED;
1565 } else if (number[0] == '>') {
1566 int location = strtol(&number[1], NULL, 0);
1568 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE,
1569 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1571 telephony_dial_number_reply, telephony_device,
1572 DBUS_TYPE_INT32, &location,
1573 DBUS_TYPE_INVALID)) {
1574 telephony_dial_number_rsp(telephony_device,
1575 CME_ERROR_AG_FAILURE);
1580 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1581 HFP_AGENT_INTERFACE, "DialNum",
1583 DBUS_TYPE_STRING, &number,
1584 DBUS_TYPE_UINT32, &flags,
1585 DBUS_TYPE_INVALID)) {
1586 telephony_dial_number_rsp(telephony_device,
1587 CME_ERROR_AG_FAILURE);
1591 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
1595 void telephony_terminate_call_req(void *telephony_device)
1597 struct csd_call *call;
1598 struct csd_call *alerting;
1603 call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1605 call = find_non_idle_call();
1608 error("No active call");
1609 telephony_terminate_call_rsp(telephony_device,
1610 CME_ERROR_NOT_ALLOWED);
1614 if (NULL != find_call_with_status(CSD_CALL_STATUS_WAITING))
1615 err = reject_accept_call(call, telephony_device);
1616 else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_CREATE)))
1617 err = reject_call(alerting);
1618 else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING)))
1619 err = reject_call(alerting);
1620 else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_COMING)))
1621 err = reject_call(alerting);
1622 else if (call->conference)
1623 err = release_conference();
1625 err = release_call(call);
1628 telephony_terminate_call_rsp(telephony_device,
1629 CME_ERROR_AG_FAILURE);
1631 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
1636 void telephony_answer_call_req(void *telephony_device)
1638 struct csd_call *call;
1640 call = find_call_with_status(CSD_CALL_STATUS_COMING);
1642 call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1645 call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1648 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
1651 telephony_answer_call_rsp(telephony_device,
1652 CME_ERROR_NOT_ALLOWED);
1656 if (answer_call(call) < 0)
1657 telephony_answer_call_rsp(telephony_device,
1658 CME_ERROR_AG_FAILURE);
1660 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
1664 void telephony_key_press_req(void *telephony_device, const char *keys)
1666 struct csd_call *active, *waiting;
1669 DBG("telephony-tizen: got key press request for %s", keys);
1671 waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
1673 waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1675 waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1677 active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1680 err = answer_call(waiting);
1682 err = release_call(active);
1684 /*As per the HSP1.2 specification, for user action - Cellular phone can perform
1685 predefined user action. In our case we shall support Last no. dial*/
1686 dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1687 HFP_AGENT_INTERFACE, "DialLastNum",
1688 telephony_dial_number_reply, telephony_device,
1694 telephony_key_press_rsp(telephony_device,
1695 CME_ERROR_AG_FAILURE);
1697 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
1700 void telephony_last_dialed_number_req(void *telephony_device)
1702 DBG("telephony-tizen: last dialed number request");
1704 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1705 HFP_AGENT_INTERFACE, "DialLastNum",
1706 telephony_dial_number_reply, telephony_device,
1707 DBUS_TYPE_INVALID)) {
1708 telephony_dial_number_rsp(telephony_device,
1709 CME_ERROR_AG_FAILURE);
1713 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
1715 char buf[2] = { tone, '\0' }, *buf_ptr = buf;
1716 struct csd_call *call;
1718 DBG("telephony-tizen: transmit dtmf: %s", buf);
1720 /* Find any Ongoing call, in active/held/waiting */
1721 if (NULL == (call = find_call_with_status(CSD_CALL_STATUS_ACTIVE)))
1722 if (NULL == (call = find_call_with_status(
1723 CSD_CALL_STATUS_HOLD)))
1724 if (NULL == (call = find_call_with_status(
1725 CSD_CALL_STATUS_WAITING))) {
1726 DBG("No Onging Call \n");
1727 telephony_transmit_dtmf_rsp(telephony_device,
1728 CME_ERROR_AG_FAILURE);
1732 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1733 HFP_AGENT_INTERFACE, "SendDtmf",
1735 DBUS_TYPE_STRING, &buf_ptr,
1736 DBUS_TYPE_STRING, &call->path,
1737 DBUS_TYPE_STRING, &call->sender,
1738 DBUS_TYPE_INVALID)) {
1739 telephony_transmit_dtmf_rsp(telephony_device,
1740 CME_ERROR_AG_FAILURE);
1744 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
1747 static int csd_status_to_hfp(struct csd_call *call)
1749 switch (call->status) {
1750 case CSD_CALL_STATUS_IDLE:
1751 case CSD_CALL_STATUS_MO_RELEASE:
1752 case CSD_CALL_STATUS_MT_RELEASE:
1753 case CSD_CALL_STATUS_TERMINATED:
1755 case CSD_CALL_STATUS_CREATE:
1756 return CALL_STATUS_DIALING;
1757 case CSD_CALL_STATUS_WAITING:
1758 return CALL_STATUS_WAITING;
1759 case CSD_CALL_STATUS_PROCEEDING:
1760 /* PROCEEDING can happen in outgoing/incoming */
1761 if (call->originating)
1762 return CALL_STATUS_DIALING;
1764 * PROCEEDING is followed by WAITING CSD status, therefore
1765 * second incoming call status indication is set immediately
1768 if (g_slist_length(active_calls) > 0)
1769 return CALL_STATUS_WAITING;
1771 return CALL_STATUS_INCOMING;
1772 case CSD_CALL_STATUS_COMING:
1773 if (g_slist_length(active_calls) > 0)
1774 return CALL_STATUS_WAITING;
1776 return CALL_STATUS_INCOMING;
1777 case CSD_CALL_STATUS_MO_ALERTING:
1778 return CALL_STATUS_ALERTING;
1779 case CSD_CALL_STATUS_MT_ALERTING:
1780 return CALL_STATUS_INCOMING;
1781 case CSD_CALL_STATUS_ANSWERED:
1782 case CSD_CALL_STATUS_ACTIVE:
1783 case CSD_CALL_STATUS_RECONNECT_PENDING:
1784 case CSD_CALL_STATUS_SWAP_INITIATED:
1785 case CSD_CALL_STATUS_HOLD_INITIATED:
1786 return CALL_STATUS_ACTIVE;
1787 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
1788 case CSD_CALL_STATUS_HOLD:
1789 return CALL_STATUS_HELD;
1795 void telephony_list_current_calls_req(void *telephony_device)
1800 DBG("telephony-tizen: list current calls request");
1802 for (l = calls, i = 1; l != NULL; l = l->next, i++) {
1803 struct csd_call *call = l->data;
1804 int status, direction, multiparty;
1806 status = csd_status_to_hfp(call);
1810 direction = call->originating ?
1811 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
1813 multiparty = call->conference ?
1814 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
1816 telephony_list_current_call_ind(i, direction, status,
1817 CALL_MODE_VOICE, multiparty,
1819 number_type(call->number));
1822 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
1826 static void telephony_operator_reply(DBusPendingCall *call, void *telephony_device)
1828 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1830 const gchar *operator_name;
1832 DBG("telephony_operator_reply\n");
1834 dbus_error_init(&derr);
1836 if (dbus_set_error_from_message(&derr, reply)) {
1837 DBG("telephony_operator_reply error:%s", derr.message);
1841 if (!dbus_message_get_args(reply, NULL,
1842 DBUS_TYPE_STRING, &operator_name,
1846 DBG("telephony_operator_reply -operator_name:%s", operator_name);
1847 net.operator_name = g_strndup(operator_name, 16);
1849 telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
1851 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
1855 dbus_error_free(&derr);
1856 telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "UNKOWN");
1857 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
1860 void telephony_operator_selection_req(void *telephony_device)
1864 err = dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1865 HFP_AGENT_INTERFACE, "GetOperatorName",
1866 telephony_operator_reply, telephony_device,
1869 telephony_operator_selection_rsp(telephony_device,
1870 CME_ERROR_AG_FAILURE);
1873 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
1875 DBG("telephony-tizen: got %s NR and EC request",
1876 enable ? "enable" : "disable");
1878 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1879 HFP_AGENT_INTERFACE, "NrecStatus",
1880 NULL, NULL, DBUS_TYPE_BOOLEAN, &enable,
1881 DBUS_TYPE_INVALID)) {
1882 telephony_nr_and_ec_rsp(telephony_device,
1883 CME_ERROR_AG_FAILURE);
1887 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
1890 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
1893 DBG("telephony-tizen: got %s voice dial request",
1894 enable ? "enable" : "disable");
1896 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1897 HFP_AGENT_INTERFACE, "VoiceDial",
1898 NULL, NULL, DBUS_TYPE_BOOLEAN, &enable,
1899 DBUS_TYPE_INVALID)) {
1900 telephony_voice_dial_rsp(telephony_device,
1901 CME_ERROR_AG_FAILURE);
1905 telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
1908 void telephony_subscriber_number_req(void *telephony_device)
1910 DBG("telephony-tizen: subscriber number request");
1911 if (subscriber_number)
1912 telephony_subscriber_number_ind(subscriber_number,
1913 number_type(subscriber_number),
1914 SUBSCRIBER_SERVICE_VOICE);
1915 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
1918 static char *get_supported_list(const char *list[], unsigned int size)
1923 if (list == NULL || size == 0)
1926 str = g_string_new("(");
1929 g_string_append(str, ",");
1931 g_string_append(str, list[i]);
1935 g_string_append(str, ")");
1937 return g_string_free(str, FALSE);
1940 static int convert_utf8_gsm(uint8_t ascii, uint8_t utf_8, uint8_t *gsm)
1944 if (ascii == 0xC3) {
1945 for (i = 0; i < GSM_UNI_MAX_C3 ; i++) {
1946 if (gsm_unicode_C3[i].utf_8 == utf_8) {
1947 *gsm = gsm_unicode_C3[i].gsm;
1951 } else if (ascii == 0xCE) {
1952 for (i = 0; i < GSM_UNI_MAX_CE ; i++) {
1953 if (gsm_unicode_CE[i].utf_8 == utf_8) {
1954 *gsm = gsm_unicode_CE[i].gsm;
1963 static void get_unicode_string(const char *name, char *unicodename)
1965 if (NULL != name && NULL != unicodename) {
1966 int len = strlen(name);
1972 if (len > PHONEBOOK_MAX_CHARACTER_LENGTH)
1973 len = PHONEBOOK_MAX_CHARACTER_LENGTH;
1975 for (x = 0, y = 0 ; x < len ; x++, y++) {
1976 if (x < (len - 1)) {
1977 if (convert_utf8_gsm(name[x], name[x+1],
1978 (uint8_t *)&unicodename[y])) {
1984 if (name[x] == '_') {
1985 unicodename[y] = ' ';
1989 unicodename[y] = name[x];
1995 static int get_phonebook_count(const char *path, uint32_t *max_size,
1998 DBusConnection *conn;
1999 DBusMessage *message, *reply;
2005 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2007 DBG("Can't get on system bus");
2011 message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
2013 PHONEBOOK_INTERFACE,
2014 "GetPhonebookSizeAt");
2016 DBG("Can't allocate new message");
2017 dbus_connection_unref(conn);
2021 dbus_message_append_args(message, DBUS_TYPE_STRING, &path,
2024 dbus_error_init(&error);
2026 reply = dbus_connection_send_with_reply_and_block(conn,
2027 message, -1, &error);
2030 if (dbus_error_is_set(&error) == TRUE) {
2031 DBG("%s", error.message);
2032 dbus_error_free(&error);
2034 DBG("Failed to get contacts");
2036 dbus_message_unref(message);
2037 dbus_connection_unref(conn);
2041 if (!dbus_message_get_args(reply, &error,
2042 DBUS_TYPE_UINT32, &size,
2043 DBUS_TYPE_INVALID)) {
2044 DBG("Can't get reply arguments\n");
2045 if (dbus_error_is_set(&error)) {
2046 DBG("%s\n", error.message);
2047 dbus_error_free(&error);
2049 dbus_message_unref(reply);
2050 dbus_message_unref(message);
2051 dbus_connection_unref(conn);
2055 if ((g_strcmp0(path, "\"SM\"") == 0) ||
2056 (g_strcmp0(path, "\"ME\"") == 0)) {
2057 max = PHONEBOOK_COUNT_MAX;
2059 if ((g_strcmp0(path, "\"DC\"") == 0) ||
2060 (g_strcmp0(path, "\"MC\"") == 0) ||
2061 (g_strcmp0(path, "\"RC\"") == 0)) {
2062 max = CALL_LOG_COUNT_MAX;
2075 dbus_message_unref(reply);
2076 dbus_message_unref(message);
2077 dbus_connection_unref(conn);
2082 static int read_phonebook_entries(int start_index, int end_index)
2084 DBusConnection *conn;
2085 DBusMessage *message, *reply;
2086 DBusMessageIter iter, iter_struct;
2091 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2093 DBG("Can't get on system bus");
2097 message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
2099 PHONEBOOK_INTERFACE,
2100 "GetPhonebookEntriesAt");
2102 DBG("Can't allocate new message");
2103 dbus_connection_unref(conn);
2107 dbus_message_append_args(message,
2109 &phonebook_store_list[ag_pb_info.path_id],
2110 DBUS_TYPE_INT32, &start_index,
2111 DBUS_TYPE_INT32, &end_index,
2114 dbus_error_init(&error);
2116 reply = dbus_connection_send_with_reply_and_block(conn,
2117 message, -1, &error);
2120 if (dbus_error_is_set(&error) == TRUE) {
2121 DBG("%s", error.message);
2122 dbus_error_free(&error);
2124 DBG("Failed to get contacts");
2127 dbus_message_unref(message);
2128 dbus_connection_unref(conn);
2133 dbus_message_iter_init(reply, &iter);
2134 dbus_message_iter_recurse(&iter, &iter_struct);
2136 while(dbus_message_iter_get_arg_type(&iter_struct) ==
2138 const char *name = NULL;
2139 const char *number = NULL;
2144 uint32_t handle = 0;
2146 DBusMessageIter entry_iter;
2148 dbus_message_iter_recurse(&iter_struct,&entry_iter);
2150 dbus_message_iter_get_basic(&entry_iter, &name);
2151 dbus_message_iter_next(&entry_iter);
2152 dbus_message_iter_get_basic(&entry_iter, &number);
2153 dbus_message_iter_next(&entry_iter);
2154 dbus_message_iter_get_basic(&entry_iter, &handle);
2155 dbus_message_iter_next(&entry_iter);
2157 dbus_message_iter_next(&iter_struct);
2159 uni_name = g_strndup(name, PHONEBOOK_NAME_MAX_LENGTH);
2160 uni_number = g_strndup(number, PHONEBOOK_NAME_MAX_LENGTH);
2162 telephony_read_phonebook_entries_ind(uni_name,
2163 uni_number, handle);
2171 dbus_message_unref(message);
2172 dbus_message_unref(reply);
2173 dbus_connection_unref(conn);
2178 static int find_phonebook_entries(const char *str)
2180 DBusConnection *conn;
2181 DBusMessage *message, *reply;
2182 DBusMessageIter iter, iter_struct;
2185 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2187 DBG("Can't get on system bus");
2191 message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
2193 PHONEBOOK_INTERFACE,
2194 "GetPhonebookEntriesFindAt");
2196 DBG("Can't allocate new message");
2197 dbus_connection_unref(conn);
2201 dbus_message_append_args(message,
2203 &phonebook_store_list[ag_pb_info.path_id],
2204 DBUS_TYPE_STRING, &str,
2207 dbus_error_init(&error);
2209 reply = dbus_connection_send_with_reply_and_block(conn,
2210 message, -1, &error);
2213 if (dbus_error_is_set(&error) == TRUE) {
2214 DBG("%s", error.message);
2215 dbus_error_free(&error);
2217 DBG("Failed to get contacts");
2220 dbus_message_unref(message);
2221 dbus_connection_unref(conn);
2226 dbus_message_iter_init(reply, &iter);
2227 dbus_message_iter_recurse(&iter, &iter_struct);
2229 while(dbus_message_iter_get_arg_type(&iter_struct) ==
2231 const char *name = NULL;
2232 const char *number = NULL;
2237 uint32_t handle = 0;
2239 DBusMessageIter entry_iter;
2241 dbus_message_iter_recurse(&iter_struct,&entry_iter);
2243 dbus_message_iter_get_basic(&entry_iter, &name);
2244 dbus_message_iter_next(&entry_iter);
2245 dbus_message_iter_get_basic(&entry_iter, &number);
2246 dbus_message_iter_next(&entry_iter);
2247 dbus_message_iter_get_basic(&entry_iter, &handle);
2248 dbus_message_iter_next(&entry_iter);
2250 dbus_message_iter_next(&iter_struct);
2252 uni_name = g_strndup(name, PHONEBOOK_NAME_MAX_LENGTH);
2253 uni_number = g_strndup(number, PHONEBOOK_NAME_MAX_LENGTH);
2255 telephony_find_phonebook_entries_ind(uni_name, uni_number, handle);
2261 dbus_message_unref(message);
2262 dbus_message_unref(reply);
2263 dbus_connection_unref(conn);
2268 void telephony_select_phonebook_memory_status(void *telephony_device)
2270 int32_t path_id = ag_pb_info.path_id;
2274 cme_error_t err = CME_ERROR_NONE;
2277 DBG("telephony-tizen: telephony_read_phonebook_store\n");
2279 if (path_id < 0 || path_id >= PHONEBOOK_STORE_LIST_SIZE)
2282 if (get_phonebook_count(phonebook_store_list[path_id],
2284 err = CME_ERROR_AG_FAILURE;
2286 telephony_select_phonebook_memory_status_rsp(telephony_device,
2287 phonebook_store_list[path_id],
2292 void telephony_select_phonebook_memory_list(void *telephony_device)
2295 For Blue & Me car kit we may have to add the
2296 patch here(similar to the patch done in H1 and H2 )
2300 str = get_supported_list(phonebook_store_list,
2301 PHONEBOOK_STORE_LIST_SIZE);
2303 DBG("telephony-tizen: telephony_select_phonebook_memory_list %d :%s\n",
2304 PHONEBOOK_STORE_LIST_SIZE, str);
2306 telephony_select_phonebook_memory_list_rsp(telephony_device,
2307 str, CME_ERROR_NONE);
2312 void telephony_select_phonebook_memory(void *telephony_device, const gchar *path)
2318 DBG("telephony-tizen: telephony_select_phonebook_memory\n");
2319 DBG("set phonebook type to [%s]\n", path);
2321 while (i < PHONEBOOK_STORE_LIST_SIZE) {
2322 if (strcmp(phonebook_store_list[i], path) == 0)
2328 if (i >= 0 && i < PHONEBOOK_STORE_LIST_SIZE) {
2329 err = CME_ERROR_NONE;
2330 ag_pb_info.path_id = i;
2332 err = CME_ERROR_INVALID_TEXT_STRING;
2334 telephony_select_phonebook_memory_rsp(telephony_device, err);
2337 void telephony_read_phonebook_entries_list(void *telephony_device)
2339 cme_error_t err = CME_ERROR_NONE;
2341 int32_t path_id = ag_pb_info.path_id;
2344 DBG("telephony-tizen: telephony_read_phonebook_entries_list\n");
2346 if (path_id < 0 || path_id >= PHONEBOOK_STORE_LIST_SIZE)
2347 err = CME_ERROR_INVALID_INDEX;
2349 if (get_phonebook_count(phonebook_store_list[path_id],
2350 NULL, &used) != 0) {
2351 err = CME_ERROR_NOT_ALLOWED;
2355 telephony_read_phonebook_entries_list_rsp(telephony_device, used,
2356 PHONEBOOK_NUMBER_MAX_LENGTH, PHONEBOOK_NAME_MAX_LENGTH,
2360 void telephony_read_phonebook_entries(void *telephony_device, const char *cmd)
2362 int start_index = 0;
2372 DBG("telephony-tizen: telephony_read_phonebook_entries\n");
2377 str = g_strdup(cmd);
2378 next = strchr(str, ',');
2384 end_index = strtol(next, NULL, 10);
2387 start_index = strtol(str, NULL, 10);
2391 count = read_phonebook_entries(start_index, end_index);
2394 err = CME_ERROR_AG_FAILURE;
2395 else if (count == 0)
2396 err = CME_ERROR_INVALID_INDEX;
2398 err = CME_ERROR_NONE;
2400 telephony_read_phonebook_entries_rsp(telephony_device, err);
2403 void telephony_find_phonebook_entries_status(void *telephony_device)
2405 telephony_find_phonebook_entries_status_ind(
2406 PHONEBOOK_NUMBER_MAX_LENGTH,
2407 PHONEBOOK_NAME_MAX_LENGTH);
2409 telephony_find_phonebook_entries_status_rsp(telephony_device,
2413 void telephony_find_phonebook_entries(void *telephony_device, const char *cmd)
2416 gchar *unquoted = NULL;
2418 cme_error_t err = CME_ERROR_NONE;
2420 DBG("telephony-tizen: telephony_find_phonebook_entry\n");
2422 /* remove quote and compress */
2423 st = strchr(cmd, '"');
2425 unquoted = g_strdup(cmd);
2429 end = strrchr(cmd, '"');
2431 unquoted = g_strdup(cmd);
2433 unquoted = g_strndup(st + 1, end - st - 1);
2436 if (find_phonebook_entries(unquoted))
2437 err = CME_ERROR_AG_FAILURE;
2439 telephony_find_phonebook_entries_rsp(telephony_device, err);
2444 void telephony_get_preffered_store_capacity(void *telephony_device)
2446 DBG("telephony-tizen: telephony_list_preffered_store_capcity\n");
2448 telephony_get_preffered_store_capacity_rsp(telephony_device,
2449 PREFFERED_MESSAGE_STORAGE_MAX,
2453 void telephony_list_preffered_store(void *telephony_device)
2455 DBG("telephony-tizen: telephony_list_preffered_store_capcity\n");
2457 telephony_list_preffered_store_rsp(telephony_device,
2458 PREFFERED_MESSAGE_STORAGE_LIST,
2463 void telephony_set_preffered_store_capcity(void *telephony_device, const char *cmd)
2468 void telephony_get_character_set(void *telephony_device)
2470 DBG("telephony-tizen: telephony_get_character_set\n");
2472 telephony_supported_character_generic_rsp(telephony_device,
2473 (char *)character_set_list[ag_pb_info.charset_id],
2478 void telephony_list_supported_character(void *telephony_device)
2482 str = get_supported_list(character_set_list,
2483 CHARACTER_SET_LIST_SIZE);
2485 DBG("telephony-tizen: telephony_list_supported_character_set %d :%s\n",
2486 CHARACTER_SET_LIST_SIZE, str);
2488 telephony_supported_character_generic_rsp(telephony_device,
2489 str, CME_ERROR_NONE);
2494 void telephony_set_characterset(void *telephony_device, const char *cmd)
2496 DBG("telephony-tizen: telephony_set_characterset [%s]\n", cmd);
2500 while (i < CHARACTER_SET_LIST_SIZE) {
2501 if (strcmp(character_set_list[i], cmd) == 0) {
2502 telephony_set_characterset_generic_rsp(telephony_device,
2504 ag_pb_info.charset_id = i;
2511 telephony_set_characterset_generic_rsp(telephony_device,
2512 CME_ERROR_NOT_SUPPORTED);
2517 static void telephony_get_battery_property_reply(
2518 DBusPendingCall *call, void *data)
2520 DBusMessage *reply = dbus_pending_call_steal_reply(call);
2525 DBG("battery_property_reply");
2527 dbus_error_init(&derr);
2528 if (dbus_set_error_from_message(&derr, reply)) {
2529 DBG("battery_property_reply: %s", derr.message);
2530 dbus_error_free(&derr);
2531 telephony_battery_charge_status_rsp(data, bcs,
2532 bcl, CME_ERROR_AG_FAILURE);
2536 if (dbus_message_get_args(reply, NULL,
2537 DBUS_TYPE_INT32, &bcs,
2538 DBUS_TYPE_INT32, &bcl,
2539 DBUS_TYPE_INVALID) == FALSE) {
2540 DBG("get_signal_quality_reply: Invalid arguments");
2541 telephony_battery_charge_status_rsp(data, bcs,
2542 bcl, CME_ERROR_AG_FAILURE);
2547 telephony_battery_charge_status_rsp(data, bcs,
2548 bcl, CME_ERROR_NONE);
2551 dbus_message_unref(reply);
2554 void telephony_get_battery_property(void *telephony_device)
2556 DBG("telephony-tizen: telephony_get_battery_property\n");
2558 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
2559 HFP_AGENT_INTERFACE, "GetBatteryStatus",
2560 telephony_get_battery_property_reply,
2561 telephony_device, DBUS_TYPE_INVALID)) {
2562 telephony_battery_charge_status_rsp(telephony_device, 0, 0,
2563 CME_ERROR_AG_FAILURE);
2567 static void telephony_get_signal_quality_reply(DBusPendingCall *call,
2570 DBusMessage *reply = dbus_pending_call_steal_reply(call);
2575 DBG("get_signal_quality_reply");
2577 dbus_error_init(&derr);
2578 if (dbus_set_error_from_message(&derr, reply)) {
2579 DBG("get_signal_quality_reply: %s", derr.message);
2580 dbus_error_free(&derr);
2581 telephony_signal_quality_rsp(data, rssi,
2582 ber, CME_ERROR_AG_FAILURE);
2586 if (dbus_message_get_args(reply, NULL,
2587 DBUS_TYPE_INT32, &rssi,
2588 DBUS_TYPE_INT32, &ber,
2589 DBUS_TYPE_INVALID) == FALSE) {
2590 DBG("get_signal_quality_reply: Invalid arguments");
2591 telephony_signal_quality_rsp(data, rssi,
2592 ber, CME_ERROR_AG_FAILURE);
2597 telephony_signal_quality_rsp(data, rssi,
2598 ber, CME_ERROR_NONE);
2601 dbus_message_unref(reply);
2604 void telephony_get_signal_quality(void *telephony_device)
2606 DBG("telephony-tizen: telephony_get_signal_quality\n");
2608 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
2609 HFP_AGENT_INTERFACE, "GetSignalQuality",
2610 telephony_get_signal_quality_reply,
2611 telephony_device, DBUS_TYPE_INVALID)) {
2612 telephony_signal_quality_rsp(telephony_device, 0, 0,
2613 CME_ERROR_AG_FAILURE);