3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2008-2009 Nokia Corporation
6 * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <dbus/dbus.h>
40 #include "telephony.h"
42 /* libcsnet D-Bus definitions */
43 #define NETWORK_BUS_NAME "com.nokia.phone.net"
44 #define NETWORK_INTERFACE "Phone.Net"
45 #define NETWORK_PATH "/com/nokia/phone/net"
47 /* Mask bits for supported services */
48 #define NETWORK_MASK_GPRS_SUPPORT 0x01
49 #define NETWORK_MASK_CS_SERVICES 0x02
50 #define NETWORK_MASK_EGPRS_SUPPORT 0x04
51 #define NETWORK_MASK_HSDPA_AVAIL 0x08
52 #define NETWORK_MASK_HSUPA_AVAIL 0x10
54 /* network get cell info: cell type */
55 #define NETWORK_UNKNOWN_CELL 0
56 #define NETWORK_GSM_CELL 1
57 #define NETWORK_WCDMA_CELL 2
59 enum net_registration_status {
60 NETWORK_REG_STATUS_HOME = 0x00,
61 NETWORK_REG_STATUS_ROAM,
62 NETWORK_REG_STATUS_ROAM_BLINK,
63 NETWORK_REG_STATUS_NOSERV,
64 NETWORK_REG_STATUS_NOSERV_SEARCHING,
65 NETWORK_REG_STATUS_NOSERV_NOTSEARCHING,
66 NETWORK_REG_STATUS_NOSERV_NOSIM,
67 NETWORK_REG_STATUS_POWER_OFF = 0x08,
68 NETWORK_REG_STATUS_NSPS,
69 NETWORK_REG_STATUS_NSPS_NO_COVERAGE,
70 NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW
74 NETWORK_GSM_HOME_PLMN = 0,
75 NETWORK_GSM_PREFERRED_PLMN,
76 NETWORK_GSM_FORBIDDEN_PLMN,
77 NETWORK_GSM_OTHER_PLMN,
78 NETWORK_GSM_NO_PLMN_AVAIL
81 enum network_alpha_tag_name_type {
82 NETWORK_HARDCODED_LATIN_OPER_NAME = 0,
83 NETWORK_HARDCODED_USC2_OPER_NAME,
84 NETWORK_NITZ_SHORT_OPER_NAME,
85 NETWORK_NITZ_FULL_OPER_NAME,
88 #define TELEPHONY_MAEMO_PATH "/com/nokia/MaemoTelephony"
89 #define TELEPHONY_MAEMO_INTERFACE "com.nokia.MaemoTelephony"
91 #define CALLERID_BASE "/var/lib/bluetooth/maemo-callerid-"
92 #define ALLOWED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-allowed"
93 #define RESTRICTED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-restricted"
94 #define NONE_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-none"
96 static uint32_t callerid = 0;
98 /* CSD CALL plugin D-Bus definitions */
99 #define CSD_CALL_BUS_NAME "com.nokia.csd.Call"
100 #define CSD_CALL_INTERFACE "com.nokia.csd.Call"
101 #define CSD_CALL_INSTANCE "com.nokia.csd.Call.Instance"
102 #define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference"
103 #define CSD_CALL_PATH "/com/nokia/csd/call"
105 /* Call status values as exported by the CSD CALL plugin */
106 #define CSD_CALL_STATUS_IDLE 0
107 #define CSD_CALL_STATUS_CREATE 1
108 #define CSD_CALL_STATUS_COMING 2
109 #define CSD_CALL_STATUS_PROCEEDING 3
110 #define CSD_CALL_STATUS_MO_ALERTING 4
111 #define CSD_CALL_STATUS_MT_ALERTING 5
112 #define CSD_CALL_STATUS_WAITING 6
113 #define CSD_CALL_STATUS_ANSWERED 7
114 #define CSD_CALL_STATUS_ACTIVE 8
115 #define CSD_CALL_STATUS_MO_RELEASE 9
116 #define CSD_CALL_STATUS_MT_RELEASE 10
117 #define CSD_CALL_STATUS_HOLD_INITIATED 11
118 #define CSD_CALL_STATUS_HOLD 12
119 #define CSD_CALL_STATUS_RETRIEVE_INITIATED 13
120 #define CSD_CALL_STATUS_RECONNECT_PENDING 14
121 #define CSD_CALL_STATUS_TERMINATED 15
122 #define CSD_CALL_STATUS_SWAP_INITIATED 16
124 #define CALL_FLAG_NONE 0
125 #define CALL_FLAG_PRESENTATION_ALLOWED 0x01
126 #define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
128 /* SIM Phonebook D-Bus definitions */
129 #define SIM_PHONEBOOK_BUS_NAME "com.nokia.phone.SIM"
130 #define SIM_PHONEBOOK_INTERFACE "Phone.Sim.Phonebook"
131 #define SIM_PHONEBOOK_PATH "/com/nokia/phone/SIM/phonebook"
133 #define PHONEBOOK_INDEX_FIRST_ENTRY 0xFFFF
134 #define PHONEBOOK_INDEX_NEXT_FREE_LOCATION 0xFFFE
136 enum sim_phonebook_type {
137 SIM_PHONEBOOK_TYPE_ADN = 0x0,
138 SIM_PHONEBOOK_TYPE_SDN,
139 SIM_PHONEBOOK_TYPE_FDN,
140 SIM_PHONEBOOK_TYPE_VMBX,
141 SIM_PHONEBOOK_TYPE_MBDN,
142 SIM_PHONEBOOK_TYPE_EN,
143 SIM_PHONEBOOK_TYPE_MSISDN
146 enum sim_phonebook_location_type {
147 SIM_PHONEBOOK_LOCATION_EXACT = 0x0,
148 SIM_PHONEBOOK_LOCATION_NEXT
154 gboolean originating;
166 uint32_t operator_code;
167 uint32_t country_code;
168 uint8_t network_type;
169 uint8_t supported_services;
170 uint16_t signals_bar;
173 .status = NETWORK_REG_STATUS_NOSERV,
178 .network_type = NETWORK_GSM_NO_PLMN_AVAIL,
179 .supported_services = 0,
181 .operator_name = NULL,
184 static guint csd_watch = 0;
186 static DBusConnection *connection = NULL;
188 static GSList *calls = NULL;
190 /* Reference count for determining the call indicator status */
191 static GSList *active_calls = NULL;
193 static char *msisdn = NULL; /* Subscriber number */
194 static char *vmbx = NULL; /* Voice mailbox number */
196 /* HAL battery namespace key values */
197 static int battchg_cur = -1; /* "battery.charge_level.current" */
198 static int battchg_last = -1; /* "battery.charge_level.last_full" */
199 static int battchg_design = -1; /* "battery.charge_level.design" */
201 static gboolean events_enabled = FALSE;
203 /* Supported set of call hold operations */
204 static const char *chld_str = "0,1,1x,2,2x,3,4";
206 /* Response and hold state
208 * 0 = incoming call is put on hold in the AG
209 * 1 = held incoming call is accepted in the AG
210 * 2 = held incoming call is rejected in the AG
212 static int response_and_hold = -1;
214 static char *last_dialed_number = NULL;
216 /* Timer for tracking call creation requests */
217 static guint create_request_timer = 0;
219 static struct indicator maemo_indicators[] =
221 { "battchg", "0-5", 5, TRUE },
222 { "signal", "0-5", 5, TRUE },
223 { "service", "0,1", 1, TRUE },
224 { "call", "0,1", 0, TRUE },
225 { "callsetup", "0-3", 0, TRUE },
226 { "callheld", "0-2", 0, FALSE },
227 { "roam", "0,1", 0, TRUE },
231 static char *call_status_str[] = {
245 "RETRIEVE_INITIATED",
252 static struct csd_call *find_call(const char *path)
256 for (l = calls; l != NULL; l = l->next) {
257 struct csd_call *call = l->data;
259 if (g_str_equal(call->object_path, path))
266 static struct csd_call *find_non_held_call(void)
270 for (l = calls; l != NULL; l = l->next) {
271 struct csd_call *call = l->data;
273 if (call->status == CSD_CALL_STATUS_IDLE)
276 if (call->status != CSD_CALL_STATUS_HOLD)
283 static struct csd_call *find_non_idle_call(void)
287 for (l = calls; l != NULL; l = l->next) {
288 struct csd_call *call = l->data;
290 if (call->status != CSD_CALL_STATUS_IDLE)
297 static struct csd_call *find_call_with_status(int status)
301 for (l = calls; l != NULL; l = l->next) {
302 struct csd_call *call = l->data;
304 if (call->status == status)
311 static int release_call(struct csd_call *call)
315 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
320 error("Unable to allocate new D-Bus message");
324 g_dbus_send_message(connection, msg);
329 static int answer_call(struct csd_call *call)
333 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
338 error("Unable to allocate new D-Bus message");
342 g_dbus_send_message(connection, msg);
347 static int split_call(struct csd_call *call)
351 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
356 error("Unable to allocate new D-Bus message");
360 g_dbus_send_message(connection, msg);
365 static int unhold_call(struct csd_call *call)
369 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
373 error("Unable to allocate new D-Bus message");
377 g_dbus_send_message(connection, msg);
382 static int hold_call(struct csd_call *call)
386 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
390 error("Unable to allocate new D-Bus message");
394 g_dbus_send_message(connection, msg);
399 static int swap_calls(void)
403 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
407 error("Unable to allocate new D-Bus message");
411 g_dbus_send_message(connection, msg);
416 static int create_conference(void)
420 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
424 error("Unable to allocate new D-Bus message");
428 g_dbus_send_message(connection, msg);
433 static int call_transfer(void)
437 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
441 error("Unable to allocate new D-Bus message");
445 g_dbus_send_message(connection, msg);
450 static int number_type(const char *number)
453 return NUMBER_TYPE_TELEPHONY;
455 if (number[0] == '+' || strncmp(number, "00", 2) == 0)
456 return NUMBER_TYPE_INTERNATIONAL;
458 return NUMBER_TYPE_TELEPHONY;
461 void telephony_device_connected(void *telephony_device)
463 struct csd_call *coming;
465 debug("telephony-maemo: device %p connected", telephony_device);
467 coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
469 if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
470 telephony_call_waiting_ind(coming->number,
471 number_type(coming->number));
473 telephony_incoming_call_ind(coming->number,
474 number_type(coming->number));
478 void telephony_device_disconnected(void *telephony_device)
480 debug("telephony-maemo: device %p disconnected", telephony_device);
481 events_enabled = FALSE;
484 void telephony_event_reporting_req(void *telephony_device, int ind)
486 events_enabled = ind == 1 ? TRUE : FALSE;
488 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
491 void telephony_response_and_hold_req(void *telephony_device, int rh)
493 response_and_hold = rh;
495 telephony_response_and_hold_ind(response_and_hold);
497 telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NONE);
500 void telephony_last_dialed_number_req(void *telephony_device)
502 debug("telephony-maemo: last dialed number request");
504 if (last_dialed_number)
505 telephony_dial_number_req(telephony_device,
508 telephony_last_dialed_number_rsp(telephony_device,
509 CME_ERROR_NOT_ALLOWED);
512 void telephony_terminate_call_req(void *telephony_device)
514 struct csd_call *call;
516 call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
518 call = find_non_idle_call();
521 error("No active call");
522 telephony_terminate_call_rsp(telephony_device,
523 CME_ERROR_NOT_ALLOWED);
527 if (release_call(call) < 0)
528 telephony_terminate_call_rsp(telephony_device,
529 CME_ERROR_AG_FAILURE);
531 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
534 void telephony_answer_call_req(void *telephony_device)
536 struct csd_call *call;
538 call = find_call_with_status(CSD_CALL_STATUS_COMING);
540 call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
543 call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
546 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
549 telephony_answer_call_rsp(telephony_device,
550 CME_ERROR_NOT_ALLOWED);
554 if (answer_call(call) < 0)
555 telephony_answer_call_rsp(telephony_device,
556 CME_ERROR_AG_FAILURE);
558 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
561 static int send_method_call(const char *dest, const char *path,
562 const char *interface, const char *method,
563 DBusPendingCallNotifyFunction cb,
564 void *user_data, int type, ...)
567 DBusPendingCall *call;
570 msg = dbus_message_new_method_call(dest, path, interface, method);
572 error("Unable to allocate new D-Bus %s message", method);
576 va_start(args, type);
578 if (!dbus_message_append_args_valist(msg, type, args)) {
579 dbus_message_unref(msg);
587 g_dbus_send_message(connection, msg);
591 if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
592 error("Sending %s failed", method);
593 dbus_message_unref(msg);
597 dbus_pending_call_set_notify(call, cb, user_data, NULL);
598 dbus_pending_call_unref(call);
599 dbus_message_unref(msg);
604 static const char *memory_dial_lookup(int location)
612 void telephony_dial_number_req(void *telephony_device, const char *number)
614 uint32_t flags = callerid;
617 debug("telephony-maemo: dial request to %s", number);
619 if (strncmp(number, "*31#", 4) == 0) {
621 flags = CALL_FLAG_PRESENTATION_ALLOWED;
622 } else if (strncmp(number, "#31#", 4) == 0) {
624 flags = CALL_FLAG_PRESENTATION_RESTRICTED;
625 } else if (number[0] == '>') {
626 const char *location = &number[1];
628 number = memory_dial_lookup(strtol(&number[1], NULL, 0));
630 error("No number at memory location %s", location);
631 telephony_dial_number_rsp(telephony_device,
632 CME_ERROR_INVALID_INDEX);
637 ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
638 CSD_CALL_INTERFACE, "CreateWith",
640 DBUS_TYPE_STRING, &number,
641 DBUS_TYPE_UINT32, &flags,
644 telephony_dial_number_rsp(telephony_device,
645 CME_ERROR_AG_FAILURE);
649 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
652 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
655 char buf[2] = { tone, '\0' }, *buf_ptr = buf;
657 debug("telephony-maemo: transmit dtmf: %s", buf);
659 ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
660 CSD_CALL_INTERFACE, "SendDTMF",
662 DBUS_TYPE_STRING, &buf_ptr,
665 telephony_transmit_dtmf_rsp(telephony_device,
666 CME_ERROR_AG_FAILURE);
670 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
673 void telephony_subscriber_number_req(void *telephony_device)
675 debug("telephony-maemo: subscriber number request");
677 telephony_subscriber_number_ind(msisdn,
679 SUBSCRIBER_SERVICE_VOICE);
680 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
683 static int csd_status_to_hfp(struct csd_call *call)
685 switch (call->status) {
686 case CSD_CALL_STATUS_IDLE:
687 case CSD_CALL_STATUS_MO_RELEASE:
688 case CSD_CALL_STATUS_MT_RELEASE:
689 case CSD_CALL_STATUS_TERMINATED:
691 case CSD_CALL_STATUS_CREATE:
692 return CALL_STATUS_DIALING;
693 case CSD_CALL_STATUS_WAITING:
694 return CALL_STATUS_WAITING;
695 case CSD_CALL_STATUS_PROCEEDING:
696 /* PROCEEDING can happen in outgoing/incoming */
697 if (call->originating)
698 return CALL_STATUS_DIALING;
700 return CALL_STATUS_INCOMING;
701 case CSD_CALL_STATUS_COMING:
702 return CALL_STATUS_INCOMING;
703 case CSD_CALL_STATUS_MO_ALERTING:
704 return CALL_STATUS_ALERTING;
705 case CSD_CALL_STATUS_MT_ALERTING:
706 return CALL_STATUS_INCOMING;
707 case CSD_CALL_STATUS_ANSWERED:
708 case CSD_CALL_STATUS_ACTIVE:
709 case CSD_CALL_STATUS_RECONNECT_PENDING:
710 case CSD_CALL_STATUS_SWAP_INITIATED:
711 case CSD_CALL_STATUS_HOLD_INITIATED:
712 return CALL_STATUS_ACTIVE;
713 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
714 case CSD_CALL_STATUS_HOLD:
715 return CALL_STATUS_HELD;
721 void telephony_list_current_calls_req(void *telephony_device)
726 debug("telephony-maemo: list current calls request");
728 for (l = calls, i = 1; l != NULL; l = l->next, i++) {
729 struct csd_call *call = l->data;
730 int status, direction, multiparty;
732 status = csd_status_to_hfp(call);
736 direction = call->originating ?
737 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
739 multiparty = call->conference ?
740 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
742 telephony_list_current_call_ind(i, direction, status,
743 CALL_MODE_VOICE, multiparty,
745 number_type(call->number));
748 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
751 void telephony_operator_selection_req(void *telephony_device)
753 telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
754 net.operator_name ? net.operator_name : "");
755 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
758 static void foreach_call_with_status(int status,
759 int (*func)(struct csd_call *call))
763 for (l = calls; l != NULL; l = l->next) {
764 struct csd_call *call = l->data;
766 if (call->status == status)
771 void telephony_call_hold_req(void *telephony_device, const char *cmd)
774 struct csd_call *call;
777 debug("telephony-maemo: got call hold request %s", cmd);
785 call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
791 foreach_call_with_status(CSD_CALL_STATUS_HOLD, release_call);
792 foreach_call_with_status(CSD_CALL_STATUS_WAITING,
798 err = release_call(call);
801 foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
802 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
804 err = answer_call(call);
809 err = split_call(call);
811 struct csd_call *held, *wait;
813 call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
814 held = find_call_with_status(CSD_CALL_STATUS_HOLD);
815 wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
818 err = answer_call(wait);
819 else if (call && held)
823 err = hold_call(call);
825 err = unhold_call(held);
830 if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
831 find_call_with_status(CSD_CALL_STATUS_WAITING))
832 err = create_conference();
835 err = call_transfer();
838 debug("Unknown call hold request");
843 telephony_call_hold_rsp(telephony_device,
844 CME_ERROR_AG_FAILURE);
846 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
849 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
851 debug("telephony-maemo: got %s NR and EC request",
852 enable ? "enable" : "disable");
853 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
856 void telephony_key_press_req(void *telephony_device, const char *keys)
858 struct csd_call *active, *waiting;
861 debug("telephony-maemo: got key press request for %s", keys);
863 waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
865 waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
867 waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
869 active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
872 err = answer_call(waiting);
874 err = release_call(active);
879 telephony_key_press_rsp(telephony_device,
880 CME_ERROR_AG_FAILURE);
882 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
885 static void handle_incoming_call(DBusMessage *msg)
887 const char *number, *call_path;
888 struct csd_call *call;
890 if (!dbus_message_get_args(msg, NULL,
891 DBUS_TYPE_OBJECT_PATH, &call_path,
892 DBUS_TYPE_STRING, &number,
893 DBUS_TYPE_INVALID)) {
894 error("Unexpected parameters in Call.Coming() signal");
898 call = find_call(call_path);
900 error("Didn't find any matching call object for %s",
905 debug("Incoming call to %s from number %s", call_path, number);
907 g_free(call->number);
908 call->number = g_strdup(number);
910 telephony_update_indicator(maemo_indicators, "callsetup",
911 EV_CALLSETUP_INCOMING);
913 if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
914 telephony_call_waiting_ind(call->number,
915 number_type(call->number));
917 telephony_incoming_call_ind(call->number,
918 number_type(call->number));
921 static void handle_outgoing_call(DBusMessage *msg)
923 const char *number, *call_path;
924 struct csd_call *call;
926 if (!dbus_message_get_args(msg, NULL,
927 DBUS_TYPE_OBJECT_PATH, &call_path,
928 DBUS_TYPE_STRING, &number,
929 DBUS_TYPE_INVALID)) {
930 error("Unexpected parameters in Call.Created() signal");
934 call = find_call(call_path);
936 error("Didn't find any matching call object for %s",
941 debug("Outgoing call from %s to number %s", call_path, number);
943 g_free(call->number);
944 call->number = g_strdup(number);
946 g_free(last_dialed_number);
947 last_dialed_number = g_strdup(number);
949 if (create_request_timer) {
950 g_source_remove(create_request_timer);
951 create_request_timer = 0;
955 static gboolean create_timeout(gpointer user_data)
957 telephony_update_indicator(maemo_indicators, "callsetup",
958 EV_CALLSETUP_INACTIVE);
959 create_request_timer = 0;
963 static void handle_create_requested(DBusMessage *msg)
965 debug("Call.CreateRequested()");
967 if (create_request_timer)
968 g_source_remove(create_request_timer);
970 create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
972 telephony_update_indicator(maemo_indicators, "callsetup",
973 EV_CALLSETUP_OUTGOING);
976 static void handle_call_status(DBusMessage *msg, const char *call_path)
978 struct csd_call *call;
979 dbus_uint32_t status, cause_type, cause;
980 int callheld = telephony_get_indicator(maemo_indicators, "callheld");
982 if (!dbus_message_get_args(msg, NULL,
983 DBUS_TYPE_UINT32, &status,
984 DBUS_TYPE_UINT32, &cause_type,
985 DBUS_TYPE_UINT32, &cause,
986 DBUS_TYPE_INVALID)) {
987 error("Unexpected paramters in Instance.CallStatus() signal");
991 call = find_call(call_path);
993 error("Didn't find any matching call object for %s",
999 error("Invalid call status %u", status);
1003 debug("Call %s changed from %s to %s", call_path,
1004 call_status_str[call->status], call_status_str[status]);
1006 if (call->status == (int) status) {
1007 debug("Ignoring CSD Call state change to existing state");
1011 call->status = (int) status;
1014 case CSD_CALL_STATUS_IDLE:
1016 telephony_update_indicator(maemo_indicators,
1018 EV_CALLSETUP_INACTIVE);
1019 if (!call->originating)
1020 telephony_calling_stopped_ind();
1023 g_free(call->number);
1024 call->number = NULL;
1025 call->originating = FALSE;
1026 call->emergency = FALSE;
1027 call->on_hold = FALSE;
1028 call->conference = FALSE;
1029 call->setup = FALSE;
1031 case CSD_CALL_STATUS_CREATE:
1032 call->originating = TRUE;
1035 case CSD_CALL_STATUS_COMING:
1036 call->originating = FALSE;
1039 case CSD_CALL_STATUS_PROCEEDING:
1041 case CSD_CALL_STATUS_MO_ALERTING:
1042 telephony_update_indicator(maemo_indicators, "callsetup",
1043 EV_CALLSETUP_ALERTING);
1045 case CSD_CALL_STATUS_MT_ALERTING:
1047 case CSD_CALL_STATUS_WAITING:
1049 case CSD_CALL_STATUS_ANSWERED:
1051 case CSD_CALL_STATUS_ACTIVE:
1052 if (call->on_hold) {
1053 call->on_hold = FALSE;
1054 if (find_call_with_status(CSD_CALL_STATUS_HOLD))
1055 telephony_update_indicator(maemo_indicators,
1057 EV_CALLHELD_MULTIPLE);
1059 telephony_update_indicator(maemo_indicators,
1063 if (!g_slist_find(active_calls, call))
1064 active_calls = g_slist_prepend(active_calls, call);
1065 if (g_slist_length(active_calls) == 1)
1066 telephony_update_indicator(maemo_indicators,
1069 /* Upgrade callheld status if necessary */
1070 if (callheld == EV_CALLHELD_ON_HOLD)
1071 telephony_update_indicator(maemo_indicators,
1073 EV_CALLHELD_MULTIPLE);
1074 telephony_update_indicator(maemo_indicators,
1076 EV_CALLSETUP_INACTIVE);
1077 if (!call->originating)
1078 telephony_calling_stopped_ind();
1079 call->setup = FALSE;
1082 case CSD_CALL_STATUS_MO_RELEASE:
1083 case CSD_CALL_STATUS_MT_RELEASE:
1084 active_calls = g_slist_remove(active_calls, call);
1085 if (g_slist_length(active_calls) == 0)
1086 telephony_update_indicator(maemo_indicators, "call",
1089 case CSD_CALL_STATUS_HOLD_INITIATED:
1091 case CSD_CALL_STATUS_HOLD:
1092 call->on_hold = TRUE;
1093 if (find_non_held_call())
1094 telephony_update_indicator(maemo_indicators,
1096 EV_CALLHELD_MULTIPLE);
1098 telephony_update_indicator(maemo_indicators,
1100 EV_CALLHELD_ON_HOLD);
1102 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
1104 case CSD_CALL_STATUS_RECONNECT_PENDING:
1106 case CSD_CALL_STATUS_TERMINATED:
1107 if (call->on_hold &&
1108 !find_call_with_status(CSD_CALL_STATUS_HOLD))
1109 telephony_update_indicator(maemo_indicators,
1112 else if (callheld == EV_CALLHELD_MULTIPLE &&
1113 find_call_with_status(CSD_CALL_STATUS_HOLD))
1114 telephony_update_indicator(maemo_indicators,
1116 EV_CALLHELD_ON_HOLD);
1118 case CSD_CALL_STATUS_SWAP_INITIATED:
1121 error("Unknown call status %u", status);
1126 static void handle_conference(DBusMessage *msg, gboolean joined)
1129 struct csd_call *call;
1131 if (!dbus_message_get_args(msg, NULL,
1132 DBUS_TYPE_OBJECT_PATH, &path,
1133 DBUS_TYPE_INVALID)) {
1134 error("Unexpected parameters in Conference.%s",
1135 dbus_message_get_member(msg));
1139 call = find_call(path);
1141 error("Conference signal for unknown call %s", path);
1145 debug("Call %s %s the conference", path, joined ? "joined" : "left");
1147 call->conference = joined;
1150 static void get_operator_name_reply(DBusPendingCall *pending_call,
1156 dbus_int32_t net_err;
1158 reply = dbus_pending_call_steal_reply(pending_call);
1160 dbus_error_init(&err);
1161 if (dbus_set_error_from_message(&err, reply)) {
1162 error("get_operator_name failed: %s, %s",
1163 err.name, err.message);
1164 dbus_error_free(&err);
1168 dbus_error_init(&err);
1169 if (!dbus_message_get_args(reply, &err,
1170 DBUS_TYPE_STRING, &name,
1171 DBUS_TYPE_INT32, &net_err,
1172 DBUS_TYPE_INVALID)) {
1173 error("Unexpected get_operator_name reply parameters: %s, %s",
1174 err.name, err.message);
1175 dbus_error_free(&err);
1180 error("get_operator_name failed with code %d", net_err);
1184 if (strlen(name) == 0)
1187 g_free(net.operator_name);
1188 net.operator_name = g_strdup(name);
1190 debug("telephony-maemo: operator name updated: %s", name);
1193 dbus_message_unref(reply);
1196 static void resolve_operator_name(uint32_t operator, uint32_t country)
1198 uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME;
1200 send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
1201 NETWORK_INTERFACE, "get_operator_name",
1202 get_operator_name_reply, NULL,
1203 DBUS_TYPE_BYTE, &name_type,
1204 DBUS_TYPE_UINT32, &operator,
1205 DBUS_TYPE_UINT32, &country,
1209 static void update_registration_status(uint8_t status, uint16_t lac,
1211 uint32_t operator_code,
1212 uint32_t country_code,
1213 uint8_t network_type,
1214 uint8_t supported_services)
1216 if (net.status != status) {
1218 case NETWORK_REG_STATUS_HOME:
1219 telephony_update_indicator(maemo_indicators, "roam",
1221 if (net.status >= NETWORK_REG_STATUS_NOSERV)
1222 telephony_update_indicator(maemo_indicators,
1224 EV_SERVICE_PRESENT);
1226 case NETWORK_REG_STATUS_ROAM:
1227 case NETWORK_REG_STATUS_ROAM_BLINK:
1228 telephony_update_indicator(maemo_indicators, "roam",
1230 if (net.status >= NETWORK_REG_STATUS_NOSERV)
1231 telephony_update_indicator(maemo_indicators,
1233 EV_SERVICE_PRESENT);
1235 case NETWORK_REG_STATUS_NOSERV:
1236 case NETWORK_REG_STATUS_NOSERV_SEARCHING:
1237 case NETWORK_REG_STATUS_NOSERV_NOTSEARCHING:
1238 case NETWORK_REG_STATUS_NOSERV_NOSIM:
1239 case NETWORK_REG_STATUS_POWER_OFF:
1240 case NETWORK_REG_STATUS_NSPS:
1241 case NETWORK_REG_STATUS_NSPS_NO_COVERAGE:
1242 case NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW:
1243 if (net.status < NETWORK_REG_STATUS_NOSERV)
1244 telephony_update_indicator(maemo_indicators,
1250 net.status = status;
1254 net.cell_id = cell_id;
1256 if (net.operator_code != operator_code ||
1257 net.country_code != country_code) {
1258 g_free(net.operator_name);
1259 net.operator_name = NULL;
1260 resolve_operator_name(operator_code, country_code);
1261 net.operator_code = operator_code;
1262 net.country_code = country_code;
1265 net.network_type = network_type;
1266 net.supported_services = supported_services;
1269 static void handle_registration_status_change(DBusMessage *msg)
1272 dbus_uint16_t lac, network_type, supported_services;
1273 dbus_uint32_t cell_id, operator_code, country_code;
1275 if (!dbus_message_get_args(msg, NULL,
1276 DBUS_TYPE_BYTE, &status,
1277 DBUS_TYPE_UINT16, &lac,
1278 DBUS_TYPE_UINT32, &cell_id,
1279 DBUS_TYPE_UINT32, &operator_code,
1280 DBUS_TYPE_UINT32, &country_code,
1281 DBUS_TYPE_BYTE, &network_type,
1282 DBUS_TYPE_BYTE, &supported_services,
1283 DBUS_TYPE_INVALID)) {
1284 error("Unexpected parameters in registration_status_change");
1288 update_registration_status(status, lac, cell_id, operator_code,
1289 country_code, network_type,
1290 supported_services);
1293 static void update_signal_strength(uint8_t signals_bar)
1297 if (signals_bar > 100) {
1298 debug("signals_bar greater than expected: %u", signals_bar);
1302 if (net.signals_bar == signals_bar)
1305 /* A simple conversion from 0-100 to 0-5 (used by HFP) */
1306 signal = (signals_bar + 20) / 21;
1308 telephony_update_indicator(maemo_indicators, "signal", signal);
1310 net.signals_bar = signals_bar;
1312 debug("Signal strength updated: %u/100, %d/5", signals_bar, signal);
1315 static void handle_signal_strength_change(DBusMessage *msg)
1317 uint8_t signals_bar, rssi_in_dbm;
1319 if (!dbus_message_get_args(msg, NULL,
1320 DBUS_TYPE_BYTE, &signals_bar,
1321 DBUS_TYPE_BYTE, &rssi_in_dbm,
1322 DBUS_TYPE_INVALID)) {
1323 error("Unexpected parameters in signal_strength_change");
1327 update_signal_strength(signals_bar);
1330 static gboolean iter_get_basic_args(DBusMessageIter *iter,
1331 int first_arg_type, ...)
1336 va_start(ap, first_arg_type);
1338 for (type = first_arg_type; type != DBUS_TYPE_INVALID;
1339 type = va_arg(ap, int)) {
1340 void *value = va_arg(ap, void *);
1341 int real_type = dbus_message_iter_get_arg_type(iter);
1343 if (real_type != type) {
1344 error("iter_get_basic_args: expected %c but got %c",
1345 (char) type, (char) real_type);
1349 dbus_message_iter_get_basic(iter, value);
1350 dbus_message_iter_next(iter);
1355 return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
1358 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
1363 int *value = user_data;
1365 reply = dbus_pending_call_steal_reply(call);
1367 dbus_error_init(&err);
1368 if (dbus_set_error_from_message(&err, reply)) {
1369 error("hald replied with an error: %s, %s",
1370 err.name, err.message);
1371 dbus_error_free(&err);
1375 dbus_message_get_args(reply, NULL,
1376 DBUS_TYPE_INT32, &level,
1379 *value = (int) level;
1381 if (value == &battchg_last)
1382 debug("telephony-maemo: battery.charge_level.last_full is %d",
1384 else if (value == &battchg_design)
1385 debug("telephony-maemo: battery.charge_level.design is %d",
1388 debug("telephony-maemo: battery.charge_level.current is %d",
1391 if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
1394 if (battchg_last > 0)
1397 max = battchg_design;
1399 new = battchg_cur * 5 / max;
1401 telephony_update_indicator(maemo_indicators, "battchg", new);
1404 dbus_message_unref(reply);
1407 static void hal_get_integer(const char *path, const char *key, void *user_data)
1409 send_method_call("org.freedesktop.Hal", path,
1410 "org.freedesktop.Hal.Device",
1411 "GetPropertyInteger",
1412 hal_battery_level_reply, user_data,
1413 DBUS_TYPE_STRING, &key,
1417 static void handle_hal_property_modified(DBusMessage *msg)
1419 DBusMessageIter iter, array;
1420 dbus_int32_t num_changes;
1423 path = dbus_message_get_path(msg);
1425 dbus_message_iter_init(msg, &iter);
1427 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
1428 error("Unexpected signature in hal PropertyModified signal");
1432 dbus_message_iter_get_basic(&iter, &num_changes);
1433 dbus_message_iter_next(&iter);
1435 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1436 error("Unexpected signature in hal PropertyModified signal");
1440 dbus_message_iter_recurse(&iter, &array);
1442 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1443 DBusMessageIter prop;
1445 dbus_bool_t added, removed;
1447 dbus_message_iter_recurse(&array, &prop);
1449 if (!iter_get_basic_args(&prop,
1450 DBUS_TYPE_STRING, &name,
1451 DBUS_TYPE_BOOLEAN, &added,
1452 DBUS_TYPE_BOOLEAN, &removed,
1453 DBUS_TYPE_INVALID)) {
1454 error("Invalid hal PropertyModified parameters");
1458 if (g_str_equal(name, "battery.charge_level.last_full"))
1459 hal_get_integer(path, name, &battchg_last);
1460 else if (g_str_equal(name, "battery.charge_level.current"))
1461 hal_get_integer(path, name, &battchg_cur);
1462 else if (g_str_equal(name, "battery.charge_level.design"))
1463 hal_get_integer(path, name, &battchg_design);
1465 dbus_message_iter_next(&array);
1469 static DBusHandlerResult signal_filter(DBusConnection *conn,
1470 DBusMessage *msg, void *data)
1472 const char *path = dbus_message_get_path(msg);
1474 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
1475 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1477 if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
1478 handle_incoming_call(msg);
1479 else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
1480 handle_outgoing_call(msg);
1481 else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
1483 handle_create_requested(msg);
1484 else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
1485 handle_call_status(msg, path);
1486 else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
1487 handle_conference(msg, TRUE);
1488 else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
1489 handle_conference(msg, FALSE);
1490 else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
1491 "registration_status_change"))
1492 handle_registration_status_change(msg);
1493 else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
1494 "signal_strength_change"))
1495 handle_signal_strength_change(msg);
1496 else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
1497 "PropertyModified"))
1498 handle_hal_property_modified(msg);
1500 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1503 static void csd_call_free(struct csd_call *call)
1508 g_free(call->object_path);
1509 g_free(call->number);
1514 static void parse_call_list(DBusMessageIter *iter)
1517 DBusMessageIter call_iter;
1518 struct csd_call *call;
1519 const char *object_path, *number;
1520 dbus_uint32_t status;
1521 dbus_bool_t originating, terminating, emerg, on_hold, conf;
1523 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
1524 error("Unexpected signature in GetCallInfoAll reply");
1528 dbus_message_iter_recurse(iter, &call_iter);
1530 if (!iter_get_basic_args(&call_iter,
1531 DBUS_TYPE_OBJECT_PATH, &object_path,
1532 DBUS_TYPE_UINT32, &status,
1533 DBUS_TYPE_BOOLEAN, &originating,
1534 DBUS_TYPE_BOOLEAN, &terminating,
1535 DBUS_TYPE_BOOLEAN, &emerg,
1536 DBUS_TYPE_BOOLEAN, &on_hold,
1537 DBUS_TYPE_BOOLEAN, &conf,
1538 DBUS_TYPE_STRING, &number,
1539 DBUS_TYPE_INVALID)) {
1540 error("Parsing call D-Bus parameters failed");
1544 call = find_call(object_path);
1546 call = g_new0(struct csd_call, 1);
1547 call->object_path = g_strdup(object_path);
1548 call->status = (int) status;
1549 calls = g_slist_append(calls, call);
1550 debug("telephony-maemo: new csd call instance at %s",
1554 if (call->status == CSD_CALL_STATUS_IDLE)
1557 /* CSD gives incorrect call_hold property sometimes */
1558 if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
1559 (call->status == CSD_CALL_STATUS_HOLD &&
1561 error("Conflicting call status and on_hold property!");
1562 on_hold = call->status == CSD_CALL_STATUS_HOLD;
1565 call->originating = originating;
1566 call->on_hold = on_hold;
1567 call->conference = conf;
1568 g_free(call->number);
1569 call->number = g_strdup(number);
1571 } while (dbus_message_iter_next(iter));
1574 static void signal_strength_reply(DBusPendingCall *call, void *user_data)
1578 uint8_t signals_bar, rssi_in_dbm;
1579 dbus_int32_t net_err;
1581 reply = dbus_pending_call_steal_reply(call);
1583 dbus_error_init(&err);
1584 if (dbus_set_error_from_message(&err, reply)) {
1585 error("Unable to get signal strength: %s, %s",
1586 err.name, err.message);
1587 dbus_error_free(&err);
1591 dbus_error_init(&err);
1592 if (!dbus_message_get_args(reply, NULL,
1593 DBUS_TYPE_BYTE, &signals_bar,
1594 DBUS_TYPE_BYTE, &rssi_in_dbm,
1595 DBUS_TYPE_INT32, &net_err,
1596 DBUS_TYPE_INVALID)) {
1597 error("Unable to parse signal_strength reply: %s, %s",
1598 err.name, err.message);
1599 dbus_error_free(&err);
1604 error("get_signal_strength failed with code %d", net_err);
1608 update_signal_strength(signals_bar);
1611 dbus_message_unref(reply);
1614 static int get_signal_strength(void)
1616 return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
1617 NETWORK_INTERFACE, "get_signal_strength",
1618 signal_strength_reply, NULL,
1622 static void registration_status_reply(DBusPendingCall *call, void *user_data)
1627 dbus_uint16_t lac, network_type, supported_services;
1628 dbus_uint32_t cell_id, operator_code, country_code;
1629 dbus_int32_t net_err;
1630 uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1631 AG_FEATURE_INBAND_RINGTONE |
1632 AG_FEATURE_REJECT_A_CALL |
1633 AG_FEATURE_ENHANCED_CALL_STATUS |
1634 AG_FEATURE_ENHANCED_CALL_CONTROL |
1635 AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
1636 AG_FEATURE_THREE_WAY_CALLING;
1638 reply = dbus_pending_call_steal_reply(call);
1640 dbus_error_init(&err);
1641 if (dbus_set_error_from_message(&err, reply)) {
1642 error("Unable to get registration status: %s, %s",
1643 err.name, err.message);
1644 dbus_error_free(&err);
1648 dbus_error_init(&err);
1649 if (!dbus_message_get_args(reply, NULL,
1650 DBUS_TYPE_BYTE, &status,
1651 DBUS_TYPE_UINT16, &lac,
1652 DBUS_TYPE_UINT32, &cell_id,
1653 DBUS_TYPE_UINT32, &operator_code,
1654 DBUS_TYPE_UINT32, &country_code,
1655 DBUS_TYPE_BYTE, &network_type,
1656 DBUS_TYPE_BYTE, &supported_services,
1657 DBUS_TYPE_INT32, &net_err,
1658 DBUS_TYPE_INVALID)) {
1659 error("Unable to parse registration_status_change reply:"
1660 " %s, %s", err.name, err.message);
1661 dbus_error_free(&err);
1666 error("get_registration_status failed with code %d", net_err);
1670 update_registration_status(status, lac, cell_id, operator_code,
1671 country_code, network_type,
1672 supported_services);
1674 telephony_ready_ind(features, maemo_indicators, response_and_hold,
1677 get_signal_strength();
1680 dbus_message_unref(reply);
1683 static int get_registration_status(void)
1685 return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
1686 NETWORK_INTERFACE, "get_registration_status",
1687 registration_status_reply, NULL,
1691 static void call_info_reply(DBusPendingCall *call, void *user_data)
1695 DBusMessageIter iter, sub;;
1697 reply = dbus_pending_call_steal_reply(call);
1699 dbus_error_init(&err);
1700 if (dbus_set_error_from_message(&err, reply)) {
1701 error("csd replied with an error: %s, %s",
1702 err.name, err.message);
1703 dbus_error_free(&err);
1707 dbus_message_iter_init(reply, &iter);
1709 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1710 error("Unexpected signature in GetCallInfoAll return");
1714 dbus_message_iter_recurse(&iter, &sub);
1716 parse_call_list(&sub);
1718 get_registration_status();
1721 dbus_message_unref(reply);
1724 static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
1728 DBusMessageIter iter, sub;
1730 char match_string[256];
1733 reply = dbus_pending_call_steal_reply(call);
1735 dbus_error_init(&err);
1736 if (dbus_set_error_from_message(&err, reply)) {
1737 error("hald replied with an error: %s, %s",
1738 err.name, err.message);
1739 dbus_error_free(&err);
1743 dbus_message_iter_init(reply, &iter);
1745 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1746 error("Unexpected signature in GetCallInfoAll return");
1750 dbus_message_iter_recurse(&iter, &sub);
1752 type = dbus_message_iter_get_arg_type(&sub);
1754 if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
1755 error("No hal device with battery capability found");
1759 dbus_message_iter_get_basic(&sub, &path);
1761 debug("telephony-maemo: found battery device at %s", path);
1763 snprintf(match_string, sizeof(match_string),
1766 "interface='org.freedesktop.Hal.Device',"
1767 "member='PropertyModified'", path);
1768 dbus_bus_add_match(connection, match_string, NULL);
1770 hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
1771 hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
1772 hal_get_integer(path, "battery.charge_level.design", &battchg_design);
1775 dbus_message_unref(reply);
1778 static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
1782 const char *name, *number;
1783 char **number_type = user_data;
1784 dbus_int32_t current_location, err;
1786 reply = dbus_pending_call_steal_reply(call);
1788 dbus_error_init(&derr);
1789 if (dbus_set_error_from_message(&derr, reply)) {
1790 error("SIM.Phonebook replied with an error: %s, %s",
1791 derr.name, derr.message);
1792 dbus_error_free(&derr);
1796 dbus_error_init(&derr);
1797 dbus_message_get_args(reply, NULL,
1798 DBUS_TYPE_STRING, &name,
1799 DBUS_TYPE_STRING, &number,
1800 DBUS_TYPE_INT32, ¤t_location,
1801 DBUS_TYPE_INT32, &err,
1804 if (dbus_error_is_set(&derr)) {
1805 error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
1806 derr.name, derr.message);
1807 dbus_error_free(&derr);
1812 error("SIM.Phonebook.read failed with error %d", err);
1813 if (number_type == &vmbx)
1814 vmbx = g_strdup(getenv("VMBX_NUMBER"));
1818 if (number_type == &msisdn) {
1820 msisdn = g_strdup(number);
1821 debug("Got MSISDN %s (%s)", number, name);
1824 vmbx = g_strdup(number);
1825 debug("Got voice mailbox number %s (%s)", number, name);
1829 dbus_message_unref(reply);
1832 static gboolean csd_init(gpointer user_data)
1834 char match_string[128];
1835 const char *battery_cap = "battery";
1836 dbus_uint32_t location;
1837 uint8_t pb_type, location_type;
1840 if (!dbus_connection_add_filter(connection, signal_filter,
1842 error("Can't add signal filter");
1846 snprintf(match_string, sizeof(match_string),
1847 "type=signal,interface=%s", CSD_CALL_INTERFACE);
1848 dbus_bus_add_match(connection, match_string, NULL);
1850 snprintf(match_string, sizeof(match_string),
1851 "type=signal,interface=%s", CSD_CALL_INSTANCE);
1852 dbus_bus_add_match(connection, match_string, NULL);
1854 snprintf(match_string, sizeof(match_string),
1855 "type=signal,interface=%s", CSD_CALL_CONFERENCE);
1856 dbus_bus_add_match(connection, match_string, NULL);
1858 snprintf(match_string, sizeof(match_string),
1859 "type=signal,interface=%s", NETWORK_INTERFACE);
1860 dbus_bus_add_match(connection, match_string, NULL);
1862 ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1863 CSD_CALL_INTERFACE, "GetCallInfoAll",
1864 call_info_reply, NULL, DBUS_TYPE_INVALID);
1866 error("Unable to sent GetCallInfoAll method call");
1870 ret = send_method_call("org.freedesktop.Hal",
1871 "/org/freedesktop/Hal/Manager",
1872 "org.freedesktop.Hal.Manager",
1873 "FindDeviceByCapability",
1874 hal_find_device_reply, NULL,
1875 DBUS_TYPE_STRING, &battery_cap,
1878 error("Unable to send HAL method call");
1882 pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
1883 location = PHONEBOOK_INDEX_FIRST_ENTRY;
1884 location_type = SIM_PHONEBOOK_LOCATION_NEXT;
1886 ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
1887 SIM_PHONEBOOK_INTERFACE, "read",
1888 phonebook_read_reply, &msisdn,
1889 DBUS_TYPE_BYTE, &pb_type,
1890 DBUS_TYPE_INT32, &location,
1891 DBUS_TYPE_BYTE, &location_type,
1894 error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
1898 pb_type = SIM_PHONEBOOK_TYPE_VMBX;
1899 location = PHONEBOOK_INDEX_FIRST_ENTRY;
1900 location_type = SIM_PHONEBOOK_LOCATION_NEXT;
1902 ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
1903 SIM_PHONEBOOK_INTERFACE, "read",
1904 phonebook_read_reply, &vmbx,
1905 DBUS_TYPE_BYTE, &pb_type,
1906 DBUS_TYPE_INT32, &location,
1907 DBUS_TYPE_BYTE, &location_type,
1910 error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
1917 static void csd_ready(DBusConnection *conn, void *user_data)
1919 g_dbus_remove_watch(conn, csd_watch);
1922 g_timeout_add_seconds(2, csd_init, NULL);
1925 static inline DBusMessage *invalid_args(DBusMessage *msg)
1927 return g_dbus_create_error(msg,"org.bluez.Error.InvalidArguments",
1928 "Invalid arguments in method call");
1931 static uint32_t get_callflag(const char *callerid_setting)
1933 if (callerid_setting != NULL) {
1934 if (g_str_equal(callerid_setting, "allowed"))
1935 return CALL_FLAG_PRESENTATION_ALLOWED;
1936 else if (g_str_equal(callerid_setting, "restricted"))
1937 return CALL_FLAG_PRESENTATION_RESTRICTED;
1939 return CALL_FLAG_NONE;
1941 return CALL_FLAG_NONE;
1944 static void generate_flag_file(const char *filename)
1948 if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
1949 g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
1950 g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
1953 fd = open(filename, O_WRONLY | O_CREAT, 0);
1958 static void save_callerid_to_file(const char *callerid_setting)
1960 char callerid_file[FILENAME_MAX];
1962 snprintf(callerid_file, sizeof(callerid_file), "%s%s",
1963 CALLERID_BASE, callerid_setting);
1965 if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
1966 rename(ALLOWED_FLAG_FILE, callerid_file);
1967 else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
1968 rename(RESTRICTED_FLAG_FILE, callerid_file);
1969 else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
1970 rename(NONE_FLAG_FILE, callerid_file);
1972 generate_flag_file(callerid_file);
1975 static uint32_t callerid_from_file(void)
1977 if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
1978 return CALL_FLAG_PRESENTATION_ALLOWED;
1979 else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
1980 return CALL_FLAG_PRESENTATION_RESTRICTED;
1981 else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
1982 return CALL_FLAG_NONE;
1984 return CALL_FLAG_NONE;
1987 static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
1990 const char *callerid_setting;
1992 if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING,
1994 DBUS_TYPE_INVALID) == FALSE)
1995 return invalid_args(msg);
1997 if (g_str_equal(callerid_setting, "allowed") ||
1998 g_str_equal(callerid_setting, "restricted") ||
1999 g_str_equal(callerid_setting, "none")) {
2000 save_callerid_to_file(callerid_setting);
2001 callerid = get_callflag(callerid_setting);
2002 debug("telephony-maemo setting callerid flag: %s",
2004 return dbus_message_new_method_return(msg);
2007 error("telephony-maemo: invalid argument %s for method call"
2008 " SetCallerId", callerid_setting);
2009 return invalid_args(msg);
2012 static GDBusMethodTable telephony_maemo_methods[] = {
2013 {"SetCallerId", "s", "", set_callerid,
2014 G_DBUS_METHOD_FLAG_ASYNC},
2018 int telephony_init(void)
2020 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2022 csd_watch = g_dbus_add_service_watch(connection, CSD_CALL_BUS_NAME,
2023 csd_ready, NULL, NULL, NULL);
2025 if (dbus_bus_name_has_owner(connection, CSD_CALL_BUS_NAME, NULL))
2026 csd_ready(connection, NULL);
2028 info("CSD not yet available. Waiting for it...");
2030 generate_flag_file(NONE_FLAG_FILE);
2031 callerid = callerid_from_file();
2033 if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
2034 TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
2035 NULL, NULL, NULL, NULL)) {
2036 error("telephony-maemo interface %s init failed on path %s",
2037 TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
2040 debug("telephony-maemo registering %s interface on path %s",
2041 TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
2046 void telephony_exit(void)
2049 g_dbus_remove_watch(connection, csd_watch);
2053 g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
2054 g_slist_free(calls);
2057 dbus_connection_remove_filter(connection, signal_filter, NULL);
2059 dbus_connection_unref(connection);