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 "org.tizen.csd.Call.Conference"
46 #define CSD_CALL_PATH "/org/tizen/csd/call"
47 #define CSD_CALL_CONFERENCE_PATH "/org/tizen/csd/call/conference"
48 #define CSD_CALL_SENDER_PATH "/org/tizen/csd/call/sender"
50 /* libcsnet D-Bus definitions */
51 #define CSD_CSNET_BUS_NAME "org.tizen.csd.CSNet"
52 #define CSD_CSNET_PATH "/org/tizen/csd/csnet"
53 #define CSD_CSNET_IFACE "org.tizen.csd.CSNet"
54 #define CSD_CSNET_REGISTRATION "org.tizen.csd.CSNet.NetworkRegistration"
55 #define CSD_CSNET_OPERATOR "org.tizen.csd.CSNet.NetworkOperator"
56 #define CSD_CSNET_SIGNAL "org.tizen.csd.CSNet.SignalStrength"
57 #define CSD_TELEPHONE_BATTERY "org.tizen.csd.CSNet.BatteryStrength"
58 #define CSD_CSNET_SUBSCRIBER "org.tizen.csd.CSNet.SubscriberNumber"
61 #define CALL_FLAG_NONE 0
62 #define CALL_FLAG_PRESENTATION_ALLOWED 0x01
63 #define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
65 /* Call status values as exported by the CSD CALL plugin */
66 #define CSD_CALL_STATUS_IDLE 0
67 #define CSD_CALL_STATUS_CREATE 1
68 #define CSD_CALL_STATUS_COMING 2
69 #define CSD_CALL_STATUS_PROCEEDING 3
70 #define CSD_CALL_STATUS_MO_ALERTING 4
71 #define CSD_CALL_STATUS_MT_ALERTING 5
72 #define CSD_CALL_STATUS_WAITING 6
73 #define CSD_CALL_STATUS_ANSWERED 7
74 #define CSD_CALL_STATUS_ACTIVE 8
75 #define CSD_CALL_STATUS_MO_RELEASE 9
76 #define CSD_CALL_STATUS_MT_RELEASE 10
77 #define CSD_CALL_STATUS_HOLD_INITIATED 11
78 #define CSD_CALL_STATUS_HOLD 12
79 #define CSD_CALL_STATUS_RETRIEVE_INITIATED 13
80 #define CSD_CALL_STATUS_RECONNECT_PENDING 14
81 #define CSD_CALL_STATUS_TERMINATED 15
82 #define CSD_CALL_STATUS_SWAP_INITIATED 16
84 #define CALL_FLAG_NONE 0
85 #define CALL_FLAG_PRESENTATION_ALLOWED 0x01
86 #define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
89 #define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct ("GValueArray",\
90 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
92 #define PHONEBOOK_STORE_LIST "(\"SM\",\"ME\",\"DC\",\"MC\",\"RC\")"
93 #define PHONEBOOK_STORE_LIST_BLUENME "(\"ME\",\"DC\",\"MC\",\"RC\")"
94 #define PREFFERED_MESSAGE_STORAGE_LIST "(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\")"
95 #define PHONEBOOK_CHARACTER_SET_LIST "(\"IRA\",\"GSM\",\"UCS2\")"
96 #define PHONEBOOK_CHARACTER_SET_SUPPORTED "\"GSM\""
98 #define PREFFERED_MESSAGE_STORAGE_MAX 500
99 #define CALL_LOG_COUNT_MAX 30
100 #define PHONEBOOK_COUNT_MAX 1000
102 #define PHONEBOOK_PATH_LENGTH 5
103 #define PHONEBOOK_NAME_MAX_LENGTH 20
104 #define PHONEBOOK_NUMBER_MAX_LENGTH 20
105 #define PHONEBOOK_MAX_CHARACTER_LENGTH 20
107 #define PHONEBOOK_READ_RESP_LENGTH 20
116 const GsmUnicodeTable gsm_unicode_C3[] = {
117 {0xA8,0x04},{0xA9,0x05},{0xB9,0x06},{0xAC,0x07},{0xB2,0x08},
118 {0xB7,0x09},{0x98,0x0B},{0xB8,0x0C},{0x85,0x0E},{0xA5,0x0F},
119 {0x86,0x1C},{0xA6,0x1D},{0x9F,0x1E},{0x89,0x1F},{0x84,0x5B},
120 {0x96,0x5C},{0x91,0x5D},{0x9C,0x5E},{0x80,0x5F},{0xA4,0x7B},
121 {0xB6,0x7C},{0xB1,0x7D},{0xBC,0x7E},{0xA0,0x7F},
125 const GsmUnicodeTable gsm_unicode_CE[] = {
126 {0x85,0x14},{0xA1,0x50},{0x98,0x19},{0xA0,0x16},{0x94,0x10},
127 {0xA6,0x12},{0x93,0x13},{0x9E,0x1A},{0x9B,0x14},{0xA8,0x17},
131 #define GSM_UNI_MAX_C3 (sizeof(gsm_unicode_C3)/sizeof(GsmUnicodeTable))
132 #define GSM_UNI_MAX_CE (sizeof(gsm_unicode_CE)/sizeof(GsmUnicodeTable))
135 static DBusConnection *ag_connection = NULL;
137 static GSList *calls = NULL;
138 static GSList *watches = NULL;
140 static gboolean events_enabled = FALSE;
141 static uint32_t callerid = 0;
143 /* Reference count for determining the call indicator status */
144 static GSList *active_calls = NULL;
146 static struct indicator telephony_ag_indicators[] =
148 { "battchg", "0-5", 5, TRUE },
149 /* signal strength in terms of bars */
150 { "signal", "0-5", 0, TRUE },
151 { "service", "0,1", 0, TRUE },
152 { "call", "0,1", 0, TRUE },
153 { "callsetup", "0-3", 0, TRUE },
154 { "callheld", "0-2", 0, FALSE },
155 { "roam", "0,1", 0, TRUE },
159 static char *call_status_str[] = {
173 "RETRIEVE_INITIATED",
180 enum net_registration_status {
181 NETWORK_REG_STATUS_HOME,
182 NETWORK_REG_STATUS_ROAMING,
183 NETWORK_REG_STATUS_OFFLINE,
184 NETWORK_REG_STATUS_SEARCHING,
185 NETWORK_REG_STATUS_NO_SIM,
186 NETWORK_REG_STATUS_POWEROFF,
187 NETWORK_REG_STATUS_POWERSAFE,
188 NETWORK_REG_STATUS_NO_COVERAGE,
189 NETWORK_REG_STATUS_REJECTED,
190 NETWORK_REG_STATUS_UNKOWN
196 gboolean originating;
210 .operator_name = NULL,
211 .status = NETWORK_REG_STATUS_UNKOWN,
212 /* Init as 0 meaning inactive mode. In modem power off state
213 * can be be -1, but we treat all values as 0s regardless
214 * inactive or power off. */
218 /* Supported set of call hold operations */
219 /*static const char *telephony_chld_str = "0,1,1x,2,2x,3,4";*/
220 static const char *telephony_chld_str = "0,1,2,3";
223 static char *subscriber_number = NULL; /* Subscriber number */
227 char path[PHONEBOOK_PATH_LENGTH];
239 static struct csd_call *find_call(uint32_t call_id)
244 for (l = calls; l != NULL; l = l->next) {
245 struct csd_call *call = l->data;
247 if (call->call_id == call_id)
254 static struct csd_call *find_non_held_call(void)
258 for (l = calls; l != NULL; l = l->next) {
259 struct csd_call *call = l->data;
261 if (call->status == CSD_CALL_STATUS_IDLE)
264 if (call->status != CSD_CALL_STATUS_HOLD)
271 static struct csd_call *find_non_idle_call(void)
275 for (l = calls; l != NULL; l = l->next) {
276 struct csd_call *call = l->data;
278 if (call->status != CSD_CALL_STATUS_IDLE)
285 static struct csd_call *find_call_with_status(int status)
290 for (l = calls; l != NULL; l = l->next) {
291 struct csd_call *call = l->data;
293 if (call->status == status)
300 static void foreach_call_with_status(int status,
301 int (*func)(struct csd_call *call))
305 for (l = calls; l != NULL; l = l->next) {
306 struct csd_call *call = l->data;
308 if (call->status == status)
313 static void csd_call_free(struct csd_call *call)
318 g_free(call->object_path);
319 g_free(call->number);
324 static int release_conference(void)
330 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
331 CSD_CALL_CONFERENCE_PATH,
335 error("Unable to allocate new D-Bus message");
339 g_dbus_send_message(ag_connection, msg);
346 static int reject_call(struct csd_call *call)
352 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
357 error("Unable to allocate new D-Bus message");
360 DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
361 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
362 DBUS_TYPE_INVALID)) {
364 DBG("dbus_message_append_args -ERROR\n");
365 dbus_message_unref(msg);
369 g_dbus_send_message(ag_connection, msg);
376 static int release_call(struct csd_call *call)
382 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
387 error("Unable to allocate new D-Bus message");
390 DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
391 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
392 DBUS_TYPE_INVALID)) {
394 DBG("dbus_message_append_args -ERROR\n");
395 dbus_message_unref(msg);
399 g_dbus_send_message(ag_connection, msg);
406 static int dbus_method_call_send(const char *dest, const char *path,
407 const char *interface, const char *method,
408 DBusPendingCallNotifyFunction cb,
409 void *user_data, int type, ...)
412 DBusPendingCall *call;
417 msg = dbus_message_new_method_call(dest, path, interface, method);
419 error("Unable to allocate new D-Bus %s message", method);
423 va_start(args, type);
425 if (!dbus_message_append_args_valist(msg, type, args)) {
426 dbus_message_unref(msg);
434 g_dbus_send_message(ag_connection, msg);
438 if (!dbus_connection_send_with_reply(ag_connection, msg, &call, -1)) {
439 error("Sending %s failed", method);
440 dbus_message_unref(msg);
444 dbus_pending_call_set_notify(call, cb, user_data, NULL);
445 dbus_message_unref(msg);
451 static int answer_call(struct csd_call *call)
456 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
461 error("Unable to allocate new D-Bus message");
465 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
466 DBUS_TYPE_INVALID)) {
468 DBG("dbus_message_append_args -ERROR\n");
469 dbus_message_unref(msg);
472 g_dbus_send_message(ag_connection, msg);
477 static int number_type(const char *number)
480 return NUMBER_TYPE_TELEPHONY;
482 if (number[0] == '+' || strncmp(number, "00", 2) == 0)
483 return NUMBER_TYPE_INTERNATIONAL;
485 return NUMBER_TYPE_TELEPHONY;
488 static void call_set_status(struct csd_call *call, dbus_uint32_t status)
490 dbus_uint32_t prev_status;
495 callheld = telephony_get_indicator(telephony_ag_indicators, "callheld");
497 prev_status = call->status;
498 DBG("Call %s Call id %d changed from %s to %s", call->object_path, call->call_id,
499 call_status_str[prev_status], call_status_str[status]);
501 if (prev_status == status) {
502 DBG("Ignoring CSD Call state change to existing state");
506 call->status = (int) status;
509 case CSD_CALL_STATUS_IDLE:
511 telephony_update_indicator(telephony_ag_indicators,
513 EV_CALLSETUP_INACTIVE);
514 if (!call->originating)
515 telephony_calling_stopped_ind();
518 g_free(call->number);
520 call->originating = FALSE;
521 call->emergency = FALSE;
522 call->on_hold = FALSE;
523 call->conference = FALSE;
526 case CSD_CALL_STATUS_CREATE:
527 call->originating = TRUE;
530 case CSD_CALL_STATUS_COMING:
531 call->originating = FALSE;
534 case CSD_CALL_STATUS_PROCEEDING:
536 case CSD_CALL_STATUS_MO_ALERTING:
537 telephony_update_indicator(telephony_ag_indicators, "callsetup",
538 EV_CALLSETUP_ALERTING);
540 case CSD_CALL_STATUS_MT_ALERTING:
541 /* Some headsets expect incoming call notification before they
542 * can send ATA command. When call changed status from waiting
543 * to alerting we need to send missing notification. Otherwise
544 * headsets like Nokia BH-108 or BackBeat 903 are unable to
545 * answer incoming call that was previously waiting. */
546 if (prev_status == CSD_CALL_STATUS_WAITING)
547 telephony_incoming_call_ind(call->number,
548 number_type(call->number));
550 case CSD_CALL_STATUS_WAITING:
552 case CSD_CALL_STATUS_ANSWERED:
554 case CSD_CALL_STATUS_ACTIVE:
556 call->on_hold = FALSE;
557 if (find_call_with_status(CSD_CALL_STATUS_HOLD))
558 telephony_update_indicator(telephony_ag_indicators,
560 EV_CALLHELD_MULTIPLE);
562 telephony_update_indicator(telephony_ag_indicators,
566 if (!g_slist_find(active_calls, call))
567 active_calls = g_slist_prepend(active_calls, call);
568 if (g_slist_length(active_calls) == 1)
569 telephony_update_indicator(telephony_ag_indicators,
572 /* Upgrade callheld status if necessary */
573 if (callheld == EV_CALLHELD_ON_HOLD)
574 telephony_update_indicator(telephony_ag_indicators,
576 EV_CALLHELD_MULTIPLE);
577 telephony_update_indicator(telephony_ag_indicators,
579 EV_CALLSETUP_INACTIVE);
580 if (!call->originating)
581 telephony_calling_stopped_ind();
585 case CSD_CALL_STATUS_MO_RELEASE:
586 case CSD_CALL_STATUS_MT_RELEASE:
587 active_calls = g_slist_remove(active_calls, call);
588 if (g_slist_length(active_calls) == 0)
589 telephony_update_indicator(telephony_ag_indicators, "call",
592 if ((prev_status == CSD_CALL_STATUS_MO_ALERTING) ||
593 (prev_status == CSD_CALL_STATUS_COMING) ||
594 (prev_status == CSD_CALL_STATUS_CREATE) ||
595 (prev_status == CSD_CALL_STATUS_WAITING)) {
596 telephony_update_indicator(telephony_ag_indicators,
598 EV_CALLSETUP_INACTIVE);
601 if (prev_status == CSD_CALL_STATUS_COMING) {
602 if (!call->originating)
603 telephony_calling_stopped_ind();
605 calls = g_slist_remove(calls, call);
608 case CSD_CALL_STATUS_HOLD_INITIATED:
610 case CSD_CALL_STATUS_HOLD:
611 call->on_hold = TRUE;
612 if (find_non_held_call())
613 telephony_update_indicator(telephony_ag_indicators,
615 EV_CALLHELD_MULTIPLE);
617 telephony_update_indicator(telephony_ag_indicators,
619 EV_CALLHELD_ON_HOLD);
621 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
623 case CSD_CALL_STATUS_RECONNECT_PENDING:
625 case CSD_CALL_STATUS_TERMINATED:
627 !find_call_with_status(CSD_CALL_STATUS_HOLD)) {
628 telephony_update_indicator(telephony_ag_indicators,
634 if (callheld == EV_CALLHELD_MULTIPLE &&
635 find_call_with_status(CSD_CALL_STATUS_HOLD) &&
636 !find_call_with_status(CSD_CALL_STATUS_ACTIVE))
637 telephony_update_indicator(telephony_ag_indicators,
639 EV_CALLHELD_ON_HOLD);
641 case CSD_CALL_STATUS_SWAP_INITIATED:
644 error("Unknown call status %u", status);
651 * This API shall invoke a dbus method call to bluetooth framework to split the call
653 * @return This function returns zero on success.
654 * @param[in] call Pointer to the Call information structure.
657 static int split_call(struct csd_call *call)
664 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
669 error("Unable to allocate new D-Bus message");
673 g_dbus_send_message(ag_connection, msg);
680 * This API shall invoke a dbus method call to bluetooth framework to swap the calls
682 * @return This function returns zero on success.
686 static int swap_calls(void)
691 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
695 error("Unable to allocate new D-Bus message");
699 g_dbus_send_message(ag_connection, msg);
706 * This API shall invoke a dbus method call to bluetooth framework to hold the call
708 * @return This function returns zero on success.
709 * @param[in] call Pointer to the Call information structure.
712 static int hold_call(struct csd_call *call)
717 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
721 error("Unable to allocate new D-Bus message");
725 DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
727 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
728 DBUS_TYPE_INVALID)) {
730 DBG("dbus_message_append_args -ERROR\n");
731 dbus_message_unref(msg);
735 g_dbus_send_message(ag_connection, msg);
744 * This API shall invoke a dbus method call to bluetooth framework to unhold the call
746 * @return This function returns zero on success.
747 * @param[in] call Pointer to the Call information structure.
750 static int unhold_call(struct csd_call *call)
755 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
759 error("Unable to allocate new D-Bus message");
764 DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
766 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
767 DBUS_TYPE_INVALID)) {
769 DBG("dbus_message_append_args -ERROR\n");
770 dbus_message_unref(msg);
774 g_dbus_send_message(ag_connection, msg);
782 * This API shall invoke a dbus method call to bluetooth framework to create conmference calls
784 * @return This function returns zero on success.
788 static int create_conference(void)
793 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
797 error("Unable to allocate new D-Bus message");
801 g_dbus_send_message(ag_connection, msg);
807 * This API shall invoke a dbus method call to bluetooth framework to transfer the call
809 * @return This function returns zero on success.
813 static int call_transfer(void)
818 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
822 error("Unable to allocate new D-Bus message");
826 g_dbus_send_message(ag_connection, msg);
832 static void telephony_chld_reply(DBusPendingCall *call, void *data)
834 DBusMessage *reply = dbus_pending_call_steal_reply(call);
839 dbus_error_init(&derr);
840 if (!dbus_set_error_from_message(&derr, reply)) {
841 DBG("chld reply: cmd is valid");
842 telephony_dial_number_rsp(data, CME_ERROR_NONE);
846 DBG("chld_reply reply: %s", derr.message);
848 dbus_error_free(&derr);
849 telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
852 dbus_message_unref(reply);
855 void telephony_call_hold_req(void *telephony_device, const char *cmd)
858 struct csd_call *call;
870 call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
876 if (find_call_with_status(CSD_CALL_STATUS_WAITING))
877 foreach_call_with_status(CSD_CALL_STATUS_WAITING,
880 foreach_call_with_status(CSD_CALL_STATUS_HOLD,
886 err = release_call(call);
889 foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
890 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
892 err = answer_call(call);
895 struct csd_call *held;
896 held = find_call_with_status(CSD_CALL_STATUS_HOLD);
898 err = unhold_call(held);
904 err = split_call(call);
906 struct csd_call *held, *wait;
908 call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
909 held = find_call_with_status(CSD_CALL_STATUS_HOLD);
910 wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
913 err = answer_call(wait);
914 else if (call && held)
918 err = hold_call(call);
920 err = unhold_call(held);
925 if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
926 find_call_with_status(CSD_CALL_STATUS_WAITING))
927 err = create_conference();
930 err = call_transfer();
933 DBG("Unknown call hold request");
938 telephony_call_hold_rsp(telephony_device,
939 CME_ERROR_AG_FAILURE);
941 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
944 chld_value = strtol(idx, NULL, 0);
946 err = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
947 CSD_CALL_INSTANCE, "Threeway",
948 telephony_chld_reply, telephony_device,
949 DBUS_TYPE_INT32, &chld_value,
953 telephony_call_hold_rsp(telephony_device,
954 CME_ERROR_AG_FAILURE);
959 static void handle_incoming_call(DBusMessage *msg)
962 const char *number, *call_path;
963 struct csd_call *call;
967 DBG("handle_incoming_call()\n");
969 if (!dbus_message_get_args(msg, NULL,
970 DBUS_TYPE_OBJECT_PATH, &call_path,
971 DBUS_TYPE_STRING, &number,
972 DBUS_TYPE_UINT32, &call_id,
973 DBUS_TYPE_INVALID)) {
974 error("Unexpected parameters in Call.Coming() signal");
978 call = g_new0(struct csd_call, 1);
979 call->object_path = g_strdup(call_path);
980 call->call_id = call_id;
981 call->number = g_strdup(number);
982 calls = g_slist_append(calls, call);
984 DBG("Incoming call to %s from number %s call id %d", call_path, number, call_id);
986 if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
987 find_call_with_status(CSD_CALL_STATUS_HOLD)) {
988 telephony_call_waiting_ind(call->number,
989 number_type(call->number));
990 call_set_status(call, CSD_CALL_STATUS_WAITING);
992 telephony_incoming_call_ind(call->number,
993 number_type(call->number));
995 call_set_status(call, CSD_CALL_STATUS_COMING);
997 telephony_update_indicator(telephony_ag_indicators, "callsetup",
998 EV_CALLSETUP_INCOMING);
1002 static void update_registration_status(uint8_t status)
1007 new_status = status;
1009 if (net.status == new_status)
1012 switch (new_status) {
1013 case NETWORK_REG_STATUS_HOME:
1014 telephony_update_indicator(telephony_ag_indicators, "roam",
1016 if (net.status > NETWORK_REG_STATUS_ROAMING)
1017 telephony_update_indicator(telephony_ag_indicators,
1019 EV_SERVICE_PRESENT);
1021 case NETWORK_REG_STATUS_ROAMING:
1022 telephony_update_indicator(telephony_ag_indicators, "roam",
1024 if (net.status > NETWORK_REG_STATUS_ROAMING)
1025 telephony_update_indicator(telephony_ag_indicators,
1027 EV_SERVICE_PRESENT);
1029 case NETWORK_REG_STATUS_OFFLINE:
1030 case NETWORK_REG_STATUS_SEARCHING:
1031 case NETWORK_REG_STATUS_NO_SIM:
1032 case NETWORK_REG_STATUS_POWEROFF:
1033 case NETWORK_REG_STATUS_POWERSAFE:
1034 case NETWORK_REG_STATUS_NO_COVERAGE:
1035 case NETWORK_REG_STATUS_REJECTED:
1036 case NETWORK_REG_STATUS_UNKOWN:
1037 if (net.status < NETWORK_REG_STATUS_OFFLINE)
1038 telephony_update_indicator(telephony_ag_indicators,
1044 net.status = new_status;
1049 static void update_signal_strength(int32_t signal_bars)
1053 if (signal_bars < 0) {
1054 DBG("signal strength smaller than expected: %d < 0",
1057 } else if (signal_bars > 5) {
1058 DBG("signal strength greater than expected: %d > 5",
1063 if (net.signal_bars == signal_bars)
1066 telephony_update_indicator(telephony_ag_indicators, "signal", signal_bars);
1068 net.signal_bars = signal_bars;
1073 static void update_battery_strength(int32_t battery_level)
1075 int current_battchg = 0;
1079 current_battchg = telephony_get_indicator(telephony_ag_indicators, "battchg");
1081 if (battery_level < 0) {
1082 DBG("Battery strength smaller than expected: %d < 0",
1085 } else if (battery_level > 5) {
1086 DBG("Battery strength greater than expected: %d > 5",
1090 if (current_battchg == battery_level)
1093 telephony_update_indicator(telephony_ag_indicators,
1094 "battchg", battery_level);
1101 static void handle_outgoing_call(DBusMessage *msg)
1103 const char *number, *call_path;
1104 struct csd_call *call;
1108 DBG("handle_outgoing_call()\n");
1110 if (!dbus_message_get_args(msg, NULL,
1111 DBUS_TYPE_OBJECT_PATH, &call_path,
1112 DBUS_TYPE_STRING, &number,
1113 DBUS_TYPE_UINT32, &call_id,
1114 DBUS_TYPE_INVALID)) {
1115 error("Unexpected parameters in Call.Coming() signal");
1119 call = g_new0(struct csd_call, 1);
1120 call->object_path = g_strdup(call_path);
1121 call->call_id = call_id;
1122 call->number = g_strdup(number);
1123 calls = g_slist_append(calls, call);
1125 DBG("Outgoing call to %s from number %s call id %d", call_path, number, call_id);
1127 call_set_status(call, CSD_CALL_STATUS_CREATE);
1129 telephony_update_indicator(telephony_ag_indicators, "callsetup",
1130 EV_CALLSETUP_OUTGOING);
1134 static void handle_create_requested(DBusMessage *msg)
1137 DBG("handle_create_requested()\n");
1141 static void handle_call_status(DBusMessage *msg, const char *call_path)
1143 struct csd_call *call;
1144 dbus_uint32_t status, call_id;
1147 if (!dbus_message_get_args(msg, NULL,
1148 DBUS_TYPE_UINT32, &status,
1149 DBUS_TYPE_UINT32, &call_id,
1150 DBUS_TYPE_INVALID)) {
1151 error("Unexpected paramters in Instance.CallStatus() signal");
1155 DBG("status = [%d] and call_id = [%d]\n", status, call_id);
1156 call = find_call(call_id);
1159 call_path is equal to CSD_CALL_PATH then we should update the call list
1160 since the call_path is sent from native AG applicaton
1162 Added for updation of the call status if the call is not added inthe call list
1164 if (g_str_equal(CSD_CALL_PATH, call_path)) {
1165 call = g_new0(struct csd_call, 1);
1166 call->object_path = g_strdup(call_path);
1167 call->call_id = call_id;
1168 calls = g_slist_append(calls, call);
1173 error("Invalid call status %u", status);
1177 call_set_status(call, status);
1181 static void update_operator_name(const char *name)
1187 g_free(net.operator_name);
1188 net.operator_name = g_strndup(name, 16);
1192 static void update_subscriber_number(const char *number)
1198 g_free(subscriber_number);
1199 subscriber_number = g_strdup(number);
1203 static void handle_conference(DBusMessage *msg, gboolean joined)
1206 DBG("handle_conference()\n");
1210 static void handle_registration_changed(DBusMessage *msg)
1215 DBG("handle_registration_changed()\n");
1217 if (!dbus_message_get_args(msg, NULL,
1218 DBUS_TYPE_BYTE, &status,
1219 DBUS_TYPE_INVALID)) {
1220 error("Unexpected parameters in RegistrationChanged");
1224 update_registration_status((uint8_t) status);
1228 static void handle_operator_name_changed(DBusMessage *msg)
1234 if (!dbus_message_get_args(msg, NULL,
1235 DBUS_TYPE_STRING, &name,
1236 DBUS_TYPE_INVALID)) {
1237 error("Unexpected parameters in OperatorNameChanged");
1241 update_operator_name(name);
1245 static void handle_signal_bars_changed(DBusMessage *msg)
1247 int32_t signal_bars;
1251 if (!dbus_message_get_args(msg, NULL,
1252 DBUS_TYPE_INT32, &signal_bars,
1253 DBUS_TYPE_INVALID)) {
1254 error("Unexpected parameters in SignalBarsChanged");
1258 update_signal_strength(signal_bars);
1262 static void handle_battery_bars_changed(DBusMessage *msg)
1264 int32_t battery_level;
1268 if (!dbus_message_get_args(msg, NULL,
1269 DBUS_TYPE_INT32, &battery_level,
1270 DBUS_TYPE_INVALID)) {
1271 error("Unexpected parameters in SignalBarsChanged");
1275 update_battery_strength(battery_level);
1279 static void handle_subscriber_number_changed(DBusMessage *msg)
1285 if (!dbus_message_get_args(msg, NULL,
1286 DBUS_TYPE_STRING, &number,
1287 DBUS_TYPE_INVALID)) {
1288 error("Unexpected parameters in SubscriberNumberChanged");
1292 update_subscriber_number(number);
1295 static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
1298 const char *path = NULL;
1302 path = dbus_message_get_path(msg);
1304 if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
1305 handle_incoming_call(msg);
1306 else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
1307 handle_outgoing_call(msg);
1308 else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
1310 handle_create_requested(msg);
1311 else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
1312 handle_call_status(msg, path);
1313 else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
1314 handle_conference(msg, TRUE);
1315 else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
1316 handle_conference(msg, FALSE);
1317 else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
1318 "RegistrationChanged"))
1319 handle_registration_changed(msg);
1320 else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
1321 "OperatorNameChanged"))
1322 handle_operator_name_changed(msg);
1323 else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
1324 "SignalBarsChanged"))
1325 handle_signal_bars_changed(msg);
1326 else if (dbus_message_is_signal(msg, CSD_TELEPHONE_BATTERY,
1327 "BatteryBarsChanged"))
1328 handle_battery_bars_changed(msg);
1329 else if (dbus_message_is_signal(msg, CSD_CSNET_SUBSCRIBER,
1330 "SubscriberNumberChanged"))
1331 handle_subscriber_number_changed(msg);
1337 static void dbus_add_watch(const char *sender, const char *path,
1338 const char *interface, const char *member)
1342 watch = g_dbus_add_signal_watch(ag_connection, sender, path, interface,
1343 member, signal_filter, NULL, NULL);
1345 watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1348 static const char *telephony_memory_dial_lookup(int location)
1350 /*memory dial not supported*/
1357 /*API's that shall be ported*/
1359 int telephony_init(void)
1361 uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1362 AG_FEATURE_REJECT_A_CALL |
1363 AG_FEATURE_ENHANCED_CALL_STATUS |
1364 AG_FEATURE_THREE_WAY_CALLING;
1369 ag_connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1371 dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_INTERFACE, NULL);
1372 dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_INSTANCE, NULL);
1373 dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_CONFERENCE, NULL);
1374 dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_REGISTRATION,
1375 "RegistrationChanged");
1376 dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_OPERATOR,
1377 "OperatorNameChanged");
1378 dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SIGNAL,
1379 "SignalBarsChanged");
1380 dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_TELEPHONE_BATTERY,
1381 "BatteryBarsChanged");
1382 dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SUBSCRIBER,
1383 "SubscriberNumberChanged");
1385 /* Reset indicators */
1386 for (i = 0; telephony_ag_indicators[i].desc != NULL; i++) {
1387 if (g_str_equal(telephony_ag_indicators[i].desc, "battchg"))
1388 telephony_ag_indicators[i].val = 5;
1390 telephony_ag_indicators[i].val = 0;
1393 /*Initializatoin of the indicators*/
1394 telephony_ready_ind(features, telephony_ag_indicators, BTRH_NOT_SUPPORTED,
1395 telephony_chld_str);
1400 static void remove_watch(gpointer data)
1402 g_dbus_remove_watch(ag_connection, GPOINTER_TO_UINT(data));
1405 void telephony_exit(void)
1409 g_free(net.operator_name);
1410 net.operator_name = NULL;
1412 g_free(subscriber_number);
1413 subscriber_number = NULL;
1415 net.status = NETWORK_REG_STATUS_UNKOWN;
1416 net.signal_bars = 0;
1418 g_slist_free(active_calls);
1419 active_calls = NULL;
1421 g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
1422 g_slist_free(calls);
1425 g_slist_foreach(watches, (GFunc) remove_watch, NULL);
1426 g_slist_free(watches);
1429 dbus_connection_unref(ag_connection);
1430 ag_connection = NULL;
1435 void telephony_device_connected(void *telephony_device)
1439 void telephony_device_disconnected(void *telephony_device)
1441 events_enabled = FALSE;
1444 void telephony_event_reporting_req(void *telephony_device, int ind)
1446 events_enabled = ind == 1 ? TRUE : FALSE;
1448 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
1451 void telephony_response_and_hold_req(void *telephony_device, int rh)
1453 telephony_response_and_hold_rsp(telephony_device,
1454 CME_ERROR_NOT_SUPPORTED);
1457 static void telephony_dial_number_reply(DBusPendingCall *call, void *data)
1459 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1462 DBG("redial_reply");
1464 dbus_error_init(&derr);
1465 if (!dbus_set_error_from_message(&derr, reply)) {
1466 DBG("hfg reply: dial done successfully");
1467 telephony_dial_number_rsp(data, CME_ERROR_NONE);
1471 DBG("dial_reply reply: %s", derr.message);
1473 dbus_error_free(&derr);
1474 telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
1477 dbus_message_unref(reply);
1480 void telephony_dial_number_req(void *telephony_device, const char *number)
1482 uint32_t flags = callerid;
1484 if (strncmp(number, "*31#", 4) == 0) {
1486 flags = CALL_FLAG_PRESENTATION_ALLOWED;
1487 } else if (strncmp(number, "#31#", 4) == 0) {
1489 flags = CALL_FLAG_PRESENTATION_RESTRICTED;
1490 } else if (number[0] == '>') {
1491 int location = strtol(&number[1], NULL, 0);
1493 if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1494 CSD_CALL_INTERFACE, "DialMemory",
1495 telephony_dial_number_reply, telephony_device,
1496 DBUS_TYPE_INT32, &location,
1497 DBUS_TYPE_INVALID)) {
1498 telephony_dial_number_rsp(telephony_device,
1499 CME_ERROR_AG_FAILURE);
1504 if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1505 CSD_CALL_INTERFACE, "DialNo",
1507 DBUS_TYPE_STRING, &number,
1508 DBUS_TYPE_UINT32, &flags,
1509 DBUS_TYPE_INVALID)) {
1510 telephony_dial_number_rsp(telephony_device,
1511 CME_ERROR_AG_FAILURE);
1515 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
1519 void telephony_terminate_call_req(void *telephony_device)
1521 struct csd_call *call;
1522 struct csd_call *alerting;
1527 call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1529 call = find_non_idle_call();
1532 error("No active call");
1533 telephony_terminate_call_rsp(telephony_device,
1534 CME_ERROR_NOT_ALLOWED);
1538 if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_CREATE)))
1539 err = reject_call(alerting);
1540 else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING)))
1541 err = reject_call(alerting);
1542 else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_COMING)))
1543 err = reject_call(alerting);
1544 else if (call->conference)
1545 err = release_conference();
1547 err = release_call(call);
1550 telephony_terminate_call_rsp(telephony_device,
1551 CME_ERROR_AG_FAILURE);
1553 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
1558 void telephony_answer_call_req(void *telephony_device)
1560 struct csd_call *call;
1562 call = find_call_with_status(CSD_CALL_STATUS_COMING);
1564 call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1567 call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1570 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
1573 telephony_answer_call_rsp(telephony_device,
1574 CME_ERROR_NOT_ALLOWED);
1578 if (answer_call(call) < 0)
1579 telephony_answer_call_rsp(telephony_device,
1580 CME_ERROR_AG_FAILURE);
1582 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
1586 void telephony_key_press_req(void *telephony_device, const char *keys)
1588 struct csd_call *active, *waiting;
1591 waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
1593 waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1595 waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1597 active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1600 err = answer_call(waiting);
1602 err = release_call(active);
1607 telephony_key_press_rsp(telephony_device,
1608 CME_ERROR_AG_FAILURE);
1610 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
1613 void telephony_last_dialed_number_req(void *telephony_device)
1615 if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1616 CSD_CALL_INTERFACE, "DialLastNo",
1617 telephony_dial_number_reply, telephony_device,
1618 DBUS_TYPE_INVALID)) {
1619 telephony_dial_number_rsp(telephony_device,
1620 CME_ERROR_AG_FAILURE);
1624 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
1626 char buf[2] = { tone, '\0' }, *buf_ptr = buf;
1628 if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1629 CSD_CALL_INTERFACE, "SendDtmf",
1631 DBUS_TYPE_STRING, &buf_ptr,
1632 DBUS_TYPE_INVALID)) {
1633 telephony_transmit_dtmf_rsp(telephony_device,
1634 CME_ERROR_AG_FAILURE);
1638 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
1641 static int csd_status_to_hfp(struct csd_call *call)
1643 switch (call->status) {
1644 case CSD_CALL_STATUS_IDLE:
1645 case CSD_CALL_STATUS_MO_RELEASE:
1646 case CSD_CALL_STATUS_MT_RELEASE:
1647 case CSD_CALL_STATUS_TERMINATED:
1649 case CSD_CALL_STATUS_CREATE:
1650 return CALL_STATUS_DIALING;
1651 case CSD_CALL_STATUS_WAITING:
1652 return CALL_STATUS_WAITING;
1653 case CSD_CALL_STATUS_PROCEEDING:
1654 /* PROCEEDING can happen in outgoing/incoming */
1655 if (call->originating)
1656 return CALL_STATUS_DIALING;
1658 * PROCEEDING is followed by WAITING CSD status, therefore
1659 * second incoming call status indication is set immediately
1662 if (g_slist_length(active_calls) > 0)
1663 return CALL_STATUS_WAITING;
1665 return CALL_STATUS_INCOMING;
1666 case CSD_CALL_STATUS_COMING:
1667 if (g_slist_length(active_calls) > 0)
1668 return CALL_STATUS_WAITING;
1670 return CALL_STATUS_INCOMING;
1671 case CSD_CALL_STATUS_MO_ALERTING:
1672 return CALL_STATUS_ALERTING;
1673 case CSD_CALL_STATUS_MT_ALERTING:
1674 return CALL_STATUS_INCOMING;
1675 case CSD_CALL_STATUS_ANSWERED:
1676 case CSD_CALL_STATUS_ACTIVE:
1677 case CSD_CALL_STATUS_RECONNECT_PENDING:
1678 case CSD_CALL_STATUS_SWAP_INITIATED:
1679 case CSD_CALL_STATUS_HOLD_INITIATED:
1680 return CALL_STATUS_ACTIVE;
1681 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
1682 case CSD_CALL_STATUS_HOLD:
1683 return CALL_STATUS_HELD;
1689 void telephony_list_current_calls_req(void *telephony_device)
1694 for (l = calls, i = 1; l != NULL; l = l->next, i++) {
1695 struct csd_call *call = l->data;
1696 int status, direction, multiparty;
1698 status = csd_status_to_hfp(call);
1702 direction = call->originating ?
1703 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
1705 multiparty = call->conference ?
1706 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
1708 telephony_list_current_call_ind(i, direction, status,
1709 CALL_MODE_VOICE, multiparty,
1711 number_type(call->number));
1714 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
1718 void telephony_operator_selection_req(void *telephony_device)
1720 telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
1721 net.operator_name ? net.operator_name : "");
1722 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
1725 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
1727 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
1730 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
1732 telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
1735 void telephony_subscriber_number_req(void *telephony_device)
1737 if (subscriber_number)
1738 telephony_subscriber_number_ind(subscriber_number,
1739 number_type(subscriber_number),
1740 SUBSCRIBER_SERVICE_VOICE);
1741 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
1744 void telephony_list_phonebook_store(void *telephony_device)
1747 For Blue & Me car kit we may have to add the
1748 patch here(similar to the patch done in H1 and H2 )
1750 telephony_list_phonebook_store_rsp(telephony_device,
1751 PHONEBOOK_STORE_LIST, CME_ERROR_NONE);
1754 static int get_phonebook_count(const char *path, uint32_t *max_size,
1757 DBusConnection *conn;
1758 DBusMessageIter iter;
1759 DBusMessageIter value;
1760 DBusMessage *message, *reply;
1763 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1765 DBG("Can't get on system bus");
1769 message = dbus_message_new_method_call("org.bluez.pb_agent",
1770 "/org/bluez/pb_agent",
1771 "org.bluez.PbAgent",
1774 DBG("Can't allocate new message");
1775 dbus_connection_unref(conn);
1778 dbus_message_iter_init_append(message, &iter);
1779 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &path);
1781 dbus_message_iter_close_container(&iter, &value);
1782 dbus_error_init(&error);
1784 reply = dbus_connection_send_with_reply_and_block(conn,
1785 message, -1, &error);
1788 if (dbus_error_is_set(&error) == TRUE) {
1789 DBG("%s", error.message);
1790 dbus_error_free(&error);
1792 DBG("Failed to get contacts");
1794 dbus_message_unref(message);
1795 dbus_connection_unref(conn);
1799 if (!dbus_message_get_args(reply, &error,
1800 DBUS_TYPE_UINT32, used,
1801 DBUS_TYPE_INVALID)) {
1802 DBG("Can't get reply arguments\n");
1803 if (dbus_error_is_set(&error)) {
1804 DBG("%s\n", error.message);
1805 dbus_error_free(&error);
1807 dbus_message_unref(reply);
1808 dbus_message_unref(message);
1809 dbus_connection_unref(conn);
1813 if ((g_strcmp0(path, "SM") == 0) || (g_strcmp0(path, "ME") == 0)) {
1814 *max_size = PHONEBOOK_COUNT_MAX;
1816 if (*used > PHONEBOOK_COUNT_MAX)
1817 *used = PHONEBOOK_COUNT_MAX;
1819 if ((g_strcmp0(path, "DC") == 0) || (g_strcmp0(path, "MC") == 0) ||
1820 (g_strcmp0(path, "RC") == 0)) {
1821 *max_size = CALL_LOG_COUNT_MAX;
1823 if (*used > CALL_LOG_COUNT_MAX)
1824 *used = CALL_LOG_COUNT_MAX;
1827 dbus_message_unref(reply);
1828 dbus_message_unref(message);
1829 dbus_connection_unref(conn);
1834 void telephony_read_phonebook_store(void *telephony_device)
1836 if ('\0' != ag_pb_info.path[0]) {
1838 Check the phone path ag_pb_info.path[] to which path it was set.
1839 If the path is NULL then set to "SM" and get the max_size and used
1840 counts from the phonebook type through dbus call to pbap agent
1842 if (!get_phonebook_count(ag_pb_info.path, &ag_pb_info.max_size,
1844 telephony_read_phonebook_store_rsp(telephony_device,
1846 ag_pb_info.max_size,
1850 telephony_read_phonebook_store_rsp(telephony_device,
1852 ag_pb_info.max_size,
1854 CME_ERROR_AG_FAILURE);
1858 void telephony_set_phonebook_store(void *telephony_device, const char *path)
1861 DBG("set phonebook type to [%s]\n", path);
1862 g_strlcpy(ag_pb_info.path, path, sizeof(ag_pb_info.path));
1866 void telephony_read_phonebook_attributes(void *telephony_device)
1868 uint32_t total_count = 0;
1869 uint32_t used_count = 0;
1871 if ('\0' != ag_pb_info.path[0]) {
1873 Check the phone path ag_pb_info.path[] to which path it was set.
1874 If the path is NULL then set to "SM" and get the max_size and used
1875 counts from the phonebook type through dbus call to pbap agent
1877 telephony_read_phonebook_attributes_rsp(telephony_device,
1878 ag_pb_info.max_size, PHONEBOOK_NUMBER_MAX_LENGTH,
1879 PHONEBOOK_NAME_MAX_LENGTH, CME_ERROR_NONE);
1883 static int convert_utf8_gsm(uint8_t ascii, uint8_t utf_8, uint8_t *gsm)
1887 if (ascii == 0xC3) {
1888 for (i = 0; i < GSM_UNI_MAX_C3 ; i++) {
1889 if (gsm_unicode_C3[i].utf_8 == utf_8) {
1890 *gsm = gsm_unicode_C3[i].gsm;
1894 } else if (ascii == 0xCE) {
1895 for (i = 0; i < GSM_UNI_MAX_CE ; i++) {
1896 if (gsm_unicode_CE[i].utf_8 == utf_8) {
1897 *gsm = gsm_unicode_CE[i].gsm;
1904 static void get_unicode_string(const char *name, char *unicodename)
1906 if (NULL != name || NULL != unicodename) {
1907 int len = strlen(name);
1911 if (len > PHONEBOOK_MAX_CHARACTER_LENGTH)
1912 len = PHONEBOOK_MAX_CHARACTER_LENGTH;
1913 for (x = 0, y = 0 ; x < len ; x++, y++) {
1914 if (x < (len - 1)) {
1915 if (convert_utf8_gsm(name[x], name[x+1] ,
1916 (uint8_t *)&unicodename[y])) {
1922 if (name[x] == '_') {
1923 unicodename[y] = ' ';
1927 unicodename[y] = name[x];
1934 static int send_read_phonebook_resp(void *telephony_device, int32_t index,
1935 const char *name, const char *number)
1940 msg = g_new0(gchar, PHONEBOOK_NAME_MAX_LENGTH +
1941 PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3);
1944 char nm[PHONEBOOK_NAME_MAX_LENGTH + 1] = {0,};
1945 char nb[PHONEBOOK_NAME_MAX_LENGTH + 1] = {0,};
1947 get_unicode_string(name, nm);
1948 get_unicode_string(number, nb);
1950 snprintf(msg, PHONEBOOK_NAME_MAX_LENGTH +
1951 PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3,
1952 "%d,\"%s\",0,\"%s\"", index, nb, nm);
1954 ret = telephony_read_phonebook_rsp(telephony_device, msg,
1962 static int get_phonebook_list(void *telephony_device, const char* path,
1963 int32_t start_index, int32_t end_index)
1965 DBusConnection *conn;
1966 DBusMessage *message, *reply;
1968 DBusMessageIter iter, iter_struct, entry;
1970 if ((start_index > (int) ag_pb_info.max_size) || (start_index <= 0) ||
1971 (start_index > PHONEBOOK_COUNT_MAX)) {
1975 if (end_index > (int) ag_pb_info.max_size)
1976 end_index = PHONEBOOK_COUNT_MAX ;
1978 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1980 DBG("Can't get on system bus");
1984 message = dbus_message_new_method_call("org.bluez.pb_agent",
1985 "/org/bluez/pb_agent",
1986 "org.bluez.PbAgent",
1987 "GetPhonebookList");
1989 DBG("Can't allocate new message");
1992 dbus_error_init(&error);
1994 reply = dbus_connection_send_with_reply_and_block(conn,
1995 message, -1, &error);
1998 if (dbus_error_is_set(&error) == TRUE) {
1999 DBG("%s", error.message);
2000 dbus_error_free(&error);
2002 DBG("Failed to get contacts");
2007 dbus_message_iter_init(reply, &iter);
2008 dbus_message_iter_recurse(&iter, &iter_struct);
2011 while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
2012 const char *name = NULL;
2013 const char *tel = NULL;
2014 uint32_t handle = 0;
2016 dbus_message_iter_recurse(&iter_struct, &entry);
2018 dbus_message_iter_get_basic(&entry, &name);
2019 dbus_message_iter_next(&entry);
2020 dbus_message_iter_get_basic(&entry, &tel);
2021 dbus_message_iter_next(&entry);
2022 dbus_message_iter_get_basic(&entry, &handle);
2024 DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
2026 /*form the packet and sent to the remote headset*/
2027 if (-1 == end_index) {
2028 if (send_read_phonebook_resp(telephony_device,
2029 start_index, name, tel))
2030 DBG("send_read_phonebook_resp - ERROR\n");
2033 if (idx >= start_index || idx <= end_index) {
2034 if (send_read_phonebook_resp(telephony_device, idx, name, tel)) {
2035 DBG("send_read_phonebook_resp - ERROR\n");
2036 telephony_read_phonebook_rsp(telephony_device, NULL,
2037 CME_ERROR_AG_FAILURE);
2039 dbus_message_unref(message);
2040 dbus_message_unref(reply);
2041 dbus_connection_unref(conn);
2048 dbus_message_iter_next(&iter_struct);
2051 telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
2053 dbus_message_unref(message);
2054 dbus_message_unref(reply);
2055 dbus_connection_unref(conn);
2057 /*Process the List and send response*/
2061 static int get_call_log_list(void *telephony_device, char* path ,
2062 int32_t start_index, int32_t end_index)
2064 DBusConnection *conn;
2065 DBusMessage *message = NULL, *reply;
2067 DBusMessageIter iter, iter_struct, entry;
2070 if ((start_index > (int) ag_pb_info.max_size) || (start_index <= 0) ||
2071 (start_index > CALL_LOG_COUNT_MAX)) {
2075 if (end_index > (int) ag_pb_info.max_size)
2076 end_index = CALL_LOG_COUNT_MAX ;
2079 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2081 DBG("Can't get on system bus");
2085 if (g_strcmp0(ag_pb_info.path, "DC") == 0) {
2086 message = dbus_message_new_method_call("org.bluez.pb_agent",
2087 "/org/bluez/pb_agent",
2088 "org.bluez.PbAgent",
2089 "GetOutgoingCallsList");
2090 } else if (g_strcmp0(ag_pb_info.path, "MC") == 0) {
2091 message = dbus_message_new_method_call("org.bluez.pb_agent",
2092 "/org/bluez/pb_agent",
2093 "org.bluez.PbAgent",
2094 "GetMissedCallsList");
2095 } else if (g_strcmp0(ag_pb_info.path, "RC") == 0) {
2096 message = dbus_message_new_method_call("org.bluez.pb_agent",
2097 "/org/bluez/pb_agent",
2098 "org.bluez.PbAgent",
2099 "GetIncomingCallsList");
2102 DBG("Can't allocate new message");
2103 dbus_connection_unref(conn);
2106 dbus_error_init(&error);
2108 reply = dbus_connection_send_with_reply_and_block(conn,
2109 message, -1, &error);
2112 if (dbus_error_is_set(&error) == TRUE) {
2113 DBG("%s", error.message);
2114 dbus_error_free(&error);
2116 DBG("Failed to get contacts");
2118 dbus_message_unref(message);
2119 dbus_connection_unref(conn);
2123 dbus_message_iter_init(reply, &iter);
2124 dbus_message_iter_recurse(&iter, &iter_struct);
2127 while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
2128 const char *name = NULL;
2129 const char *tel = NULL;
2130 uint32_t handle = 0;
2132 dbus_message_iter_recurse(&iter_struct, &entry);
2134 dbus_message_iter_get_basic(&entry, &name);
2135 dbus_message_iter_next(&entry);
2136 dbus_message_iter_get_basic(&entry, &tel);
2137 dbus_message_iter_next(&entry);
2138 dbus_message_iter_get_basic(&entry, &handle);
2140 DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
2142 /*form the packet and sent to the remote headset*/
2143 if (-1 == end_index) {
2144 if (send_read_phonebook_resp(telephony_device,
2145 start_index, name, tel))
2146 DBG("send_read_phonebook_resp - ERROR\n");
2149 if (idx >= start_index || idx <= end_index) {
2150 /* Need to form the time stamp pkt also */
2151 if (send_read_phonebook_resp(telephony_device, idx, name, tel)) {
2152 DBG("send_read_phonebook_resp - ERROR\n");
2153 telephony_read_phonebook_rsp(telephony_device, NULL,
2154 CME_ERROR_AG_FAILURE);
2156 dbus_message_unref(message);
2157 dbus_message_unref(reply);
2158 dbus_connection_unref(conn);
2165 dbus_message_iter_next(&iter_struct);
2168 telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
2170 dbus_message_unref(message);
2171 dbus_message_unref(reply);
2172 dbus_connection_unref(conn);
2174 /*Process the List and send response*/
2178 void telephony_read_phonebook(void *telephony_device, const char *cmd)
2183 int32_t start_index;
2185 ptr = (char *) strchr(cmd, (int32_t)',');
2187 start_index = strtol(cmd, NULL, 0);
2189 DBG("start_index = [%d] \n", start_index);
2192 start_index = strtol(cmd, NULL, 0);
2193 end_index = strtol(ptr, NULL, 0);
2194 DBG("start_index = [%d], end_index = [%d] \n",
2195 start_index, end_index);
2198 if ((g_strcmp0(ag_pb_info.path, "SM") == 0) ||
2199 (g_strcmp0(ag_pb_info.path, "ME") == 0)) {
2200 if (get_phonebook_list(telephony_device, ag_pb_info.path,
2201 start_index, end_index)) {
2202 telephony_read_phonebook_rsp(telephony_device, NULL,
2203 CME_ERROR_AG_FAILURE);
2207 if ((g_strcmp0(ag_pb_info.path, "DC") == 0) ||
2208 (g_strcmp0(ag_pb_info.path, "MC") == 0) ||
2209 (g_strcmp0(ag_pb_info.path, "RC") == 0)) {
2210 if (get_call_log_list(telephony_device, ag_pb_info.path,
2211 start_index, end_index)) {
2212 telephony_read_phonebook_rsp(telephony_device, NULL,
2213 CME_ERROR_AG_FAILURE);
2219 Using the start and end index get the contact list from the pbap agent and
2220 send the data to remote headset.
2225 void telephony_find_phonebook_entry_properties(void *telephony_device)
2227 telephony_find_phonebook_entry_properties_rsp(telephony_device,
2228 PHONEBOOK_NUMBER_MAX_LENGTH,
2229 PHONEBOOK_NAME_MAX_LENGTH,
2234 void telephony_find_phonebook_entry(void *telephony_device, const char *cmd)
2237 Get the contact that matches with the string "cmd" and send it back to the
2238 remote headset Need a dbus API to pbap agent that does the above operation
2242 void telephony_get_preffered_store_capacity(void *telephony_device)
2244 telephony_get_preffered_store_capacity_rsp(telephony_device,
2245 PREFFERED_MESSAGE_STORAGE_MAX,
2249 void telephony_list_preffered_store(void *telephony_device)
2251 telephony_list_preffered_store_rsp(telephony_device,
2252 PREFFERED_MESSAGE_STORAGE_LIST,
2257 void telephony_set_preffered_store_capcity(void *telephony_device, const char *cmd)
2261 void telephony_get_character_set(void *telephony_device)
2263 telephony_supported_character_generic_rsp(telephony_device,
2264 PHONEBOOK_CHARACTER_SET_SUPPORTED,
2269 void telephony_list_supported_character(void *telephony_device)
2271 telephony_supported_character_generic_rsp(telephony_device,
2272 PHONEBOOK_CHARACTER_SET_LIST,
2277 void telephony_set_characterset(void *telephony_device, const char *cmd)