3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2008-2010 Nokia Corporation
6 * Copyright (C) 2004-2010 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>
39 #include <bluetooth/sdp.h>
42 #include "telephony.h"
45 /* SSC D-Bus definitions */
46 #define SSC_DBUS_NAME "com.nokia.phone.SSC"
47 #define SSC_DBUS_IFACE "com.nokia.phone.SSC"
48 #define SSC_DBUS_PATH "/com/nokia/phone/SSC"
50 /* libcsnet D-Bus definitions */
51 #define CSD_CSNET_BUS_NAME "com.nokia.csd.CSNet"
52 #define CSD_CSNET_PATH "/com/nokia/csd/csnet"
53 #define CSD_CSNET_IFACE "com.nokia.csd.CSNet"
54 #define CSD_CSNET_REGISTRATION "com.nokia.csd.CSNet.NetworkRegistration"
55 #define CSD_CSNET_OPERATOR "com.nokia.csd.CSNet.NetworkOperator"
56 #define CSD_CSNET_SIGNAL "com.nokia.csd.CSNet.SignalStrength"
58 enum net_registration_status {
59 NETWORK_REG_STATUS_HOME,
60 NETWORK_REG_STATUS_ROAMING,
61 NETWORK_REG_STATUS_OFFLINE,
62 NETWORK_REG_STATUS_SEARCHING,
63 NETWORK_REG_STATUS_NO_SIM,
64 NETWORK_REG_STATUS_POWEROFF,
65 NETWORK_REG_STATUS_POWERSAFE,
66 NETWORK_REG_STATUS_NO_COVERAGE,
67 NETWORK_REG_STATUS_REJECTED,
68 NETWORK_REG_STATUS_UNKOWN
71 /* CSD CALL plugin D-Bus definitions */
72 #define CSD_CALL_BUS_NAME "com.nokia.csd.Call"
73 #define CSD_CALL_INTERFACE "com.nokia.csd.Call"
74 #define CSD_CALL_INSTANCE "com.nokia.csd.Call.Instance"
75 #define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference"
76 #define CSD_CALL_PATH "/com/nokia/csd/call"
77 #define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
79 /* Call status values as exported by the CSD CALL plugin */
80 #define CSD_CALL_STATUS_IDLE 0
81 #define CSD_CALL_STATUS_CREATE 1
82 #define CSD_CALL_STATUS_COMING 2
83 #define CSD_CALL_STATUS_PROCEEDING 3
84 #define CSD_CALL_STATUS_MO_ALERTING 4
85 #define CSD_CALL_STATUS_MT_ALERTING 5
86 #define CSD_CALL_STATUS_WAITING 6
87 #define CSD_CALL_STATUS_ANSWERED 7
88 #define CSD_CALL_STATUS_ACTIVE 8
89 #define CSD_CALL_STATUS_MO_RELEASE 9
90 #define CSD_CALL_STATUS_MT_RELEASE 10
91 #define CSD_CALL_STATUS_HOLD_INITIATED 11
92 #define CSD_CALL_STATUS_HOLD 12
93 #define CSD_CALL_STATUS_RETRIEVE_INITIATED 13
94 #define CSD_CALL_STATUS_RECONNECT_PENDING 14
95 #define CSD_CALL_STATUS_TERMINATED 15
96 #define CSD_CALL_STATUS_SWAP_INITIATED 16
98 #define CALL_FLAG_NONE 0
99 #define CALL_FLAG_PRESENTATION_ALLOWED 0x01
100 #define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
102 /* SIM Phonebook D-Bus definitions */
103 #define CSD_SIMPB_BUS_NAME "com.nokia.csd.SIM"
104 #define CSD_SIMPB_INTERFACE "com.nokia.csd.SIM.Phonebook"
105 #define CSD_SIMPB_PATH "/com/nokia/csd/sim/phonebook"
107 #define CSD_SIMPB_TYPE_ADN "ADN"
108 #define CSD_SIMPB_TYPE_FDN "FDN"
109 #define CSD_SIMPB_TYPE_SDN "SDN"
110 #define CSD_SIMPB_TYPE_VMBX "VMBX"
111 #define CSD_SIMPB_TYPE_MBDN "MBDN"
112 #define CSD_SIMPB_TYPE_EN "EN"
113 #define CSD_SIMPB_TYPE_MSISDN "MSISDN"
115 /* OHM plugin D-Bus definitions */
116 #define OHM_BUS_NAME "com.nokia.NonGraphicFeedback1"
117 #define OHM_INTERFACE "com.nokia.NonGraphicFeedback1"
118 #define OHM_PATH "/com/nokia/NonGraphicFeedback1"
120 /* tone-genenerator D-Bus definitions */
121 #define TONEGEN_BUS_NAME "com.Nokia.Telephony.Tones"
122 #define TONEGEN_INTERFACE "com.Nokia.Telephony.Tones"
123 #define TONEGEN_PATH "/com/Nokia/Telephony/Tones"
125 /* tone-generator DTMF definitions */
126 #define DTMF_ASTERISK 10
127 #define DTMF_HASHMARK 11
133 #define FEEDBACK_TONE_DURATION 200
138 gboolean originating;
151 .operator_name = NULL,
152 .status = NETWORK_REG_STATUS_UNKOWN,
153 /* Init as 0 meaning inactive mode. In modem power off state
154 * can be be -1, but we treat all values as 0s regardless
155 * inactive or power off. */
160 DBusPendingCall *call;
164 static int get_property(const char *iface, const char *prop);
166 static DBusConnection *connection = NULL;
168 static GSList *calls = NULL;
169 static GSList *watches = NULL;
170 static GSList *pending = NULL;
172 /* Reference count for determining the call indicator status */
173 static GSList *active_calls = NULL;
175 /* Queue of DTMF tones to play */
176 static GSList *tones = NULL;
177 static guint create_tones_timer = 0;
179 static char *msisdn = NULL; /* Subscriber number */
180 static char *vmbx = NULL; /* Voice mailbox number */
182 /* HAL battery namespace key values */
183 static int battchg_cur = -1; /* "battery.charge_level.current" */
184 static int battchg_last = -1; /* "battery.charge_level.last_full" */
185 static int battchg_design = -1; /* "battery.charge_level.design" */
187 static gboolean get_calls_active = FALSE;
189 static gboolean events_enabled = FALSE;
191 /* Supported set of call hold operations */
192 static const char *chld_str = "0,1,1x,2,2x,3,4";
194 /* Timer for tracking call creation requests */
195 static guint create_request_timer = 0;
197 static struct indicator maemo_indicators[] =
199 { "battchg", "0-5", 5, TRUE },
200 /* signal strength in terms of bars */
201 { "signal", "0-5", 0, TRUE },
202 { "service", "0,1", 0, TRUE },
203 { "call", "0,1", 0, TRUE },
204 { "callsetup", "0-3", 0, TRUE },
205 { "callheld", "0-2", 0, FALSE },
206 { "roam", "0,1", 0, TRUE },
210 static char *call_status_str[] = {
224 "RETRIEVE_INITIATED",
231 static int send_method_call(const char *dest, const char *path,
232 const char *interface, const char *method,
233 DBusPendingCallNotifyFunction cb,
234 void *user_data, int type, ...)
237 DBusPendingCall *call;
239 struct pending_req *req;
241 msg = dbus_message_new_method_call(dest, path, interface, method);
243 error("Unable to allocate new D-Bus %s message", method);
247 va_start(args, type);
249 if (!dbus_message_append_args_valist(msg, type, args)) {
250 dbus_message_unref(msg);
258 g_dbus_send_message(connection, msg);
262 if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
263 error("Sending %s failed", method);
264 dbus_message_unref(msg);
268 dbus_pending_call_set_notify(call, cb, user_data, NULL);
270 req = g_new0(struct pending_req, 1);
272 req->user_data = user_data;
274 pending = g_slist_prepend(pending, req);
275 dbus_message_unref(msg);
280 static struct csd_call *find_call(const char *path)
284 for (l = calls; l != NULL; l = l->next) {
285 struct csd_call *call = l->data;
287 if (g_str_equal(call->object_path, path))
294 static struct csd_call *find_non_held_call(void)
298 for (l = calls; l != NULL; l = l->next) {
299 struct csd_call *call = l->data;
301 if (call->status == CSD_CALL_STATUS_IDLE)
304 if (call->status != CSD_CALL_STATUS_HOLD)
311 static struct csd_call *find_non_idle_call(void)
315 for (l = calls; l != NULL; l = l->next) {
316 struct csd_call *call = l->data;
318 if (call->status != CSD_CALL_STATUS_IDLE)
325 static struct csd_call *find_call_with_status(int status)
329 for (l = calls; l != NULL; l = l->next) {
330 struct csd_call *call = l->data;
332 if (call->status == status)
339 static int release_conference(void)
343 DBG("telephony-maemo6: releasing conference call");
345 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
346 CSD_CALL_CONFERENCE_PATH,
350 error("Unable to allocate new D-Bus message");
354 g_dbus_send_message(connection, msg);
359 static int release_call(struct csd_call *call)
363 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
368 error("Unable to allocate new D-Bus message");
372 g_dbus_send_message(connection, msg);
377 static int answer_call(struct csd_call *call)
381 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
386 error("Unable to allocate new D-Bus message");
390 g_dbus_send_message(connection, msg);
395 static struct pending_req *find_request(const DBusPendingCall *call)
399 for (l = pending; l; l = l->next) {
400 struct pending_req *req = l->data;
402 if (req->call == call)
409 static void pending_req_finalize(void *data)
411 struct pending_req *req = data;
413 if (!dbus_pending_call_get_completed(req->call))
414 dbus_pending_call_cancel(req->call);
416 dbus_pending_call_unref(req->call);
420 static void remove_pending(DBusPendingCall *call)
422 struct pending_req *req = find_request(call);
424 pending = g_slist_remove(pending, req);
425 pending_req_finalize(req);
428 static void stop_ringtone_reply(DBusPendingCall *call, void *user_data)
430 struct csd_call *coming = user_data;
432 remove_pending(call);
436 static int stop_ringtone_and_answer(struct csd_call *call)
440 ret = send_method_call(OHM_BUS_NAME, OHM_PATH,
441 OHM_INTERFACE, "StopRingtone",
442 stop_ringtone_reply, call,
445 return answer_call(call);
450 static int split_call(struct csd_call *call)
454 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
459 error("Unable to allocate new D-Bus message");
463 g_dbus_send_message(connection, msg);
468 static int unhold_call(struct csd_call *call)
472 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
476 error("Unable to allocate new D-Bus message");
480 g_dbus_send_message(connection, msg);
485 static int hold_call(struct csd_call *call)
489 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
493 error("Unable to allocate new D-Bus message");
497 g_dbus_send_message(connection, msg);
502 static int swap_calls(void)
506 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
510 error("Unable to allocate new D-Bus message");
514 g_dbus_send_message(connection, msg);
519 static int create_conference(void)
523 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
527 error("Unable to allocate new D-Bus message");
531 g_dbus_send_message(connection, msg);
536 static int call_transfer(void)
540 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
544 error("Unable to allocate new D-Bus message");
548 g_dbus_send_message(connection, msg);
553 static int number_type(const char *number)
556 return NUMBER_TYPE_TELEPHONY;
558 if (number[0] == '+' || strncmp(number, "00", 2) == 0)
559 return NUMBER_TYPE_INTERNATIONAL;
561 return NUMBER_TYPE_TELEPHONY;
564 void telephony_device_connected(void *telephony_device)
566 struct csd_call *coming;
568 DBG("telephony-maemo6: device %p connected", telephony_device);
570 coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
572 if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
573 telephony_call_waiting_ind(coming->number,
574 number_type(coming->number));
576 telephony_incoming_call_ind(coming->number,
577 number_type(coming->number));
581 static void remove_pending_by_data(gpointer data, gpointer user_data)
583 struct pending_req *req = data;
585 if (req->user_data == user_data) {
586 pending = g_slist_remove(pending, req);
587 pending_req_finalize(req);
591 void telephony_device_disconnected(void *telephony_device)
593 DBG("telephony-maemo6: device %p disconnected", telephony_device);
594 events_enabled = FALSE;
596 g_slist_foreach(pending, remove_pending_by_data, telephony_device);
599 void telephony_event_reporting_req(void *telephony_device, int ind)
601 events_enabled = ind == 1 ? TRUE : FALSE;
603 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
606 void telephony_response_and_hold_req(void *telephony_device, int rh)
608 telephony_response_and_hold_rsp(telephony_device,
609 CME_ERROR_NOT_SUPPORTED);
612 void telephony_terminate_call_req(void *telephony_device)
614 struct csd_call *call;
615 struct csd_call *alerting;
618 call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
620 call = find_non_idle_call();
623 error("No active call");
624 telephony_terminate_call_rsp(telephony_device,
625 CME_ERROR_NOT_ALLOWED);
629 alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING);
630 if (call->on_hold && alerting)
631 err = release_call(alerting);
632 else if (call->conference)
633 err = release_conference();
635 err = release_call(call);
638 telephony_terminate_call_rsp(telephony_device,
639 CME_ERROR_AG_FAILURE);
641 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
644 void telephony_answer_call_req(void *telephony_device)
646 struct csd_call *call;
648 call = find_call_with_status(CSD_CALL_STATUS_COMING);
650 call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
653 call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
656 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
659 telephony_answer_call_rsp(telephony_device,
660 CME_ERROR_NOT_ALLOWED);
664 if (stop_ringtone_and_answer(call) < 0)
665 telephony_answer_call_rsp(telephony_device,
666 CME_ERROR_AG_FAILURE);
668 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
671 static void create_call_reply(DBusPendingCall *call, void *user_data)
675 void *telephony_device = user_data;
677 reply = dbus_pending_call_steal_reply(call);
679 dbus_error_init(&err);
680 if (dbus_set_error_from_message(&err, reply)) {
681 error("csd replied with an error: %s, %s",
682 err.name, err.message);
683 if (g_strcmp0(err.name,
684 "com.nokia.csd.Call.Error.CSInactive") == 0)
685 telephony_dial_number_rsp(telephony_device,
686 CME_ERROR_NO_NETWORK_SERVICE);
688 telephony_dial_number_rsp(telephony_device,
689 CME_ERROR_AG_FAILURE);
690 dbus_error_free(&err);
692 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
694 dbus_message_unref(reply);
695 remove_pending(call);
698 void telephony_last_dialed_number_req(void *telephony_device)
702 DBG("telephony-maemo6: last dialed number request");
704 ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
705 CSD_CALL_INTERFACE, "CreateFromLast",
706 create_call_reply, telephony_device,
709 telephony_dial_number_rsp(telephony_device,
710 CME_ERROR_AG_FAILURE);
713 static const char *memory_dial_lookup(int location)
721 void telephony_dial_number_req(void *telephony_device, const char *number)
725 DBG("telephony-maemo6: dial request to %s", number);
727 if (strncmp(number, "*31#", 4) == 0)
729 else if (strncmp(number, "#31#", 4) == 0)
731 else if (number[0] == '>') {
732 const char *location = &number[1];
734 number = memory_dial_lookup(strtol(&number[1], NULL, 0));
736 error("No number at memory location %s", location);
737 telephony_dial_number_rsp(telephony_device,
738 CME_ERROR_INVALID_INDEX);
743 ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
744 CSD_CALL_INTERFACE, "Create",
745 create_call_reply, telephony_device,
746 DBUS_TYPE_STRING, &number,
749 telephony_dial_number_rsp(telephony_device,
750 CME_ERROR_AG_FAILURE);
753 static void start_dtmf_reply(DBusPendingCall *call, void *user_data)
758 reply = dbus_pending_call_steal_reply(call);
760 dbus_error_init(&err);
761 if (dbus_set_error_from_message(&err, reply)) {
762 error("csd replied with an error: %s, %s",
763 err.name, err.message);
765 dbus_error_free(&err);
767 send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
768 CSD_CALL_INTERFACE, "StopDTMF",
772 dbus_message_unref(reply);
773 remove_pending(call);
776 static void start_dtmf(void *telephony_device, char tone)
781 * Stop tone immediately, modem will place it in queue and play
784 ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
785 CSD_CALL_INTERFACE, "StartDTMF",
786 start_dtmf_reply, NULL,
787 DBUS_TYPE_BYTE, &tone,
790 telephony_transmit_dtmf_rsp(telephony_device,
791 CME_ERROR_AG_FAILURE);
795 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
798 static int tonegen_startevent(char tone)
801 dbus_uint32_t event_tone;
802 dbus_int32_t dbm0 = -15;
803 dbus_uint32_t duration = 150;
807 event_tone = DTMF_ASTERISK;
810 event_tone = DTMF_HASHMARK;
825 ret = g_ascii_digit_value(tone);
831 ret = send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
832 TONEGEN_INTERFACE, "StartEventTone",
834 DBUS_TYPE_UINT32, &event_tone,
835 DBUS_TYPE_INT32, &dbm0,
836 DBUS_TYPE_UINT32, &duration,
841 static gboolean stop_feedback_tone(gpointer user_data)
843 if (g_slist_length(tones) > 0) {
847 send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
848 TONEGEN_INTERFACE, "StopTone",
852 ptone = g_slist_nth_data(tones, 0);
853 tones = g_slist_remove(tones, ptone);
855 ret = tonegen_startevent(GPOINTER_TO_UINT(ptone));
865 static void tones_timer_notify(gpointer data)
867 send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
868 TONEGEN_INTERFACE, "StopTone",
874 create_tones_timer = 0;
877 static void start_feedback_tone(char tone)
879 if (!create_tones_timer) {
882 ret = tonegen_startevent(tone);
886 create_tones_timer = g_timeout_add_full(G_PRIORITY_DEFAULT,
887 FEEDBACK_TONE_DURATION,
892 glong dtmf_tone = tone;
894 DBG("add %c to queue", tone);
895 tones = g_slist_append(tones, GUINT_TO_POINTER(dtmf_tone));
899 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
901 DBG("telephony-maemo6: transmit dtmf: %c", tone);
903 start_dtmf(telephony_device, tone);
905 if (!find_call_with_status(CSD_CALL_STATUS_ACTIVE))
906 error("No active call");
908 start_feedback_tone(tone);
911 void telephony_subscriber_number_req(void *telephony_device)
913 DBG("telephony-maemo6: subscriber number request");
915 telephony_subscriber_number_ind(msisdn,
917 SUBSCRIBER_SERVICE_VOICE);
918 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
921 static int csd_status_to_hfp(struct csd_call *call)
923 switch (call->status) {
924 case CSD_CALL_STATUS_IDLE:
925 case CSD_CALL_STATUS_MO_RELEASE:
926 case CSD_CALL_STATUS_MT_RELEASE:
927 case CSD_CALL_STATUS_TERMINATED:
929 case CSD_CALL_STATUS_CREATE:
930 return CALL_STATUS_DIALING;
931 case CSD_CALL_STATUS_WAITING:
932 return CALL_STATUS_WAITING;
933 case CSD_CALL_STATUS_PROCEEDING:
934 /* PROCEEDING can happen in outgoing/incoming */
935 if (call->originating)
936 return CALL_STATUS_DIALING;
939 * PROCEEDING is followed by WAITING CSD status, therefore
940 * second incoming call status indication is set immediately
943 if (g_slist_length(active_calls) > 0)
944 return CALL_STATUS_WAITING;
946 return CALL_STATUS_INCOMING;
947 case CSD_CALL_STATUS_COMING:
948 if (g_slist_length(active_calls) > 0)
949 return CALL_STATUS_WAITING;
951 return CALL_STATUS_INCOMING;
952 case CSD_CALL_STATUS_MO_ALERTING:
953 return CALL_STATUS_ALERTING;
954 case CSD_CALL_STATUS_MT_ALERTING:
955 return CALL_STATUS_INCOMING;
956 case CSD_CALL_STATUS_ANSWERED:
957 case CSD_CALL_STATUS_ACTIVE:
958 case CSD_CALL_STATUS_RECONNECT_PENDING:
959 case CSD_CALL_STATUS_SWAP_INITIATED:
960 case CSD_CALL_STATUS_HOLD_INITIATED:
961 return CALL_STATUS_ACTIVE;
962 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
963 case CSD_CALL_STATUS_HOLD:
964 return CALL_STATUS_HELD;
970 void telephony_list_current_calls_req(void *telephony_device)
975 DBG("telephony-maemo6: list current calls request");
977 for (l = calls, i = 1; l != NULL; l = l->next, i++) {
978 struct csd_call *call = l->data;
979 int status, direction, multiparty;
981 status = csd_status_to_hfp(call);
985 direction = call->originating ?
986 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
988 multiparty = call->conference ?
989 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
991 telephony_list_current_call_ind(i, direction, status,
992 CALL_MODE_VOICE, multiparty,
994 number_type(call->number));
997 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
1000 void telephony_operator_selection_req(void *telephony_device)
1002 telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
1003 net.operator_name ? net.operator_name : "");
1004 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
1007 static void foreach_call_with_status(int status,
1008 int (*func)(struct csd_call *call))
1012 for (l = calls; l != NULL; l = l->next) {
1013 struct csd_call *call = l->data;
1015 if (call->status == status)
1020 void telephony_call_hold_req(void *telephony_device, const char *cmd)
1023 struct csd_call *call;
1026 DBG("telephony-maemo6: got call hold request %s", cmd);
1028 if (strlen(cmd) > 1)
1034 call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
1040 if (find_call_with_status(CSD_CALL_STATUS_WAITING))
1041 foreach_call_with_status(CSD_CALL_STATUS_WAITING,
1044 foreach_call_with_status(CSD_CALL_STATUS_HOLD,
1050 err = release_call(call);
1053 foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
1054 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
1056 err = answer_call(call);
1061 err = split_call(call);
1063 struct csd_call *held, *wait;
1065 call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1066 held = find_call_with_status(CSD_CALL_STATUS_HOLD);
1067 wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
1070 err = answer_call(wait);
1071 else if (call && held)
1075 err = hold_call(call);
1077 err = unhold_call(held);
1082 if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
1083 find_call_with_status(CSD_CALL_STATUS_WAITING))
1084 err = create_conference();
1087 err = call_transfer();
1090 DBG("Unknown call hold request");
1095 telephony_call_hold_rsp(telephony_device,
1096 CME_ERROR_AG_FAILURE);
1098 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
1101 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
1103 DBG("telephony-maemo6: got %s NR and EC request",
1104 enable ? "enable" : "disable");
1105 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
1108 void telephony_key_press_req(void *telephony_device, const char *keys)
1110 struct csd_call *active, *waiting;
1113 DBG("telephony-maemo6: got key press request for %s", keys);
1115 waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
1117 waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1119 waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1121 active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1124 err = answer_call(waiting);
1126 err = release_call(active);
1131 telephony_key_press_rsp(telephony_device,
1132 CME_ERROR_AG_FAILURE);
1134 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
1137 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
1139 DBG("telephony-maemo6: got %s voice dial request",
1140 enable ? "enable" : "disable");
1142 telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
1145 static void handle_incoming_call(DBusMessage *msg)
1147 const char *number, *call_path;
1148 struct csd_call *call;
1150 if (!dbus_message_get_args(msg, NULL,
1151 DBUS_TYPE_OBJECT_PATH, &call_path,
1152 DBUS_TYPE_STRING, &number,
1153 DBUS_TYPE_INVALID)) {
1154 error("Unexpected parameters in Call.Coming() signal");
1158 call = find_call(call_path);
1160 error("Didn't find any matching call object for %s",
1165 DBG("Incoming call to %s from number %s", call_path, number);
1167 g_free(call->number);
1168 call->number = g_strdup(number);
1170 if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
1171 find_call_with_status(CSD_CALL_STATUS_HOLD))
1172 telephony_call_waiting_ind(call->number,
1173 number_type(call->number));
1175 telephony_incoming_call_ind(call->number,
1176 number_type(call->number));
1178 telephony_update_indicator(maemo_indicators, "callsetup",
1179 EV_CALLSETUP_INCOMING);
1182 static void handle_outgoing_call(DBusMessage *msg)
1184 const char *number, *call_path;
1185 struct csd_call *call;
1187 if (!dbus_message_get_args(msg, NULL,
1188 DBUS_TYPE_OBJECT_PATH, &call_path,
1189 DBUS_TYPE_STRING, &number,
1190 DBUS_TYPE_INVALID)) {
1191 error("Unexpected parameters in Call.Created() signal");
1195 call = find_call(call_path);
1197 error("Didn't find any matching call object for %s",
1202 DBG("Outgoing call from %s to number %s", call_path, number);
1204 g_free(call->number);
1205 call->number = g_strdup(number);
1207 if (create_request_timer) {
1208 g_source_remove(create_request_timer);
1209 create_request_timer = 0;
1213 static gboolean create_timeout(gpointer user_data)
1215 telephony_update_indicator(maemo_indicators, "callsetup",
1216 EV_CALLSETUP_INACTIVE);
1217 create_request_timer = 0;
1221 static void handle_create_requested(DBusMessage *msg)
1223 DBG("Call.CreateRequested()");
1225 if (create_request_timer)
1226 g_source_remove(create_request_timer);
1228 create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
1230 telephony_update_indicator(maemo_indicators, "callsetup",
1231 EV_CALLSETUP_OUTGOING);
1234 static void call_set_status(struct csd_call *call, dbus_uint32_t status)
1236 dbus_uint32_t prev_status;
1237 int callheld = telephony_get_indicator(maemo_indicators, "callheld");
1239 prev_status = call->status;
1240 DBG("Call %s changed from %s to %s", call->object_path,
1241 call_status_str[prev_status], call_status_str[status]);
1243 if (prev_status == status) {
1244 DBG("Ignoring CSD Call state change to existing state");
1248 call->status = (int) status;
1251 case CSD_CALL_STATUS_IDLE:
1253 telephony_update_indicator(maemo_indicators,
1255 EV_CALLSETUP_INACTIVE);
1256 if (!call->originating)
1257 telephony_calling_stopped_ind();
1260 g_free(call->number);
1261 call->number = NULL;
1262 call->originating = FALSE;
1263 call->emergency = FALSE;
1264 call->on_hold = FALSE;
1265 call->conference = FALSE;
1266 call->setup = FALSE;
1268 case CSD_CALL_STATUS_CREATE:
1269 call->originating = TRUE;
1272 case CSD_CALL_STATUS_COMING:
1273 call->originating = FALSE;
1276 case CSD_CALL_STATUS_PROCEEDING:
1278 case CSD_CALL_STATUS_MO_ALERTING:
1279 telephony_update_indicator(maemo_indicators, "callsetup",
1280 EV_CALLSETUP_ALERTING);
1282 case CSD_CALL_STATUS_MT_ALERTING:
1283 /* Some headsets expect incoming call notification before they
1284 * can send ATA command. When call changed status from waiting
1285 * to alerting we need to send missing notification. Otherwise
1286 * headsets like Nokia BH-108 or BackBeat 903 are unable to
1287 * answer incoming call that was previously waiting. */
1288 if (prev_status == CSD_CALL_STATUS_WAITING)
1289 telephony_incoming_call_ind(call->number,
1290 number_type(call->number));
1292 case CSD_CALL_STATUS_WAITING:
1294 case CSD_CALL_STATUS_ANSWERED:
1296 case CSD_CALL_STATUS_ACTIVE:
1297 if (call->on_hold) {
1298 call->on_hold = FALSE;
1299 if (find_call_with_status(CSD_CALL_STATUS_HOLD))
1300 telephony_update_indicator(maemo_indicators,
1302 EV_CALLHELD_MULTIPLE);
1304 telephony_update_indicator(maemo_indicators,
1308 if (!g_slist_find(active_calls, call))
1309 active_calls = g_slist_prepend(active_calls, call);
1310 if (g_slist_length(active_calls) == 1)
1311 telephony_update_indicator(maemo_indicators,
1314 /* Upgrade callheld status if necessary */
1315 if (callheld == EV_CALLHELD_ON_HOLD)
1316 telephony_update_indicator(maemo_indicators,
1318 EV_CALLHELD_MULTIPLE);
1319 telephony_update_indicator(maemo_indicators,
1321 EV_CALLSETUP_INACTIVE);
1322 if (!call->originating)
1323 telephony_calling_stopped_ind();
1324 call->setup = FALSE;
1327 case CSD_CALL_STATUS_MO_RELEASE:
1328 case CSD_CALL_STATUS_MT_RELEASE:
1329 active_calls = g_slist_remove(active_calls, call);
1330 if (g_slist_length(active_calls) == 0)
1331 telephony_update_indicator(maemo_indicators, "call",
1334 if (create_tones_timer)
1335 g_source_remove(create_tones_timer);
1337 case CSD_CALL_STATUS_HOLD_INITIATED:
1339 case CSD_CALL_STATUS_HOLD:
1340 call->on_hold = TRUE;
1341 if (find_non_held_call())
1342 telephony_update_indicator(maemo_indicators,
1344 EV_CALLHELD_MULTIPLE);
1346 telephony_update_indicator(maemo_indicators,
1348 EV_CALLHELD_ON_HOLD);
1350 case CSD_CALL_STATUS_RETRIEVE_INITIATED:
1352 case CSD_CALL_STATUS_RECONNECT_PENDING:
1354 case CSD_CALL_STATUS_TERMINATED:
1355 if (call->on_hold &&
1356 !find_call_with_status(CSD_CALL_STATUS_HOLD)) {
1357 telephony_update_indicator(maemo_indicators,
1363 if (callheld == EV_CALLHELD_MULTIPLE &&
1364 find_call_with_status(CSD_CALL_STATUS_HOLD) &&
1365 !find_call_with_status(CSD_CALL_STATUS_ACTIVE))
1366 telephony_update_indicator(maemo_indicators,
1368 EV_CALLHELD_ON_HOLD);
1370 case CSD_CALL_STATUS_SWAP_INITIATED:
1373 error("Unknown call status %u", status);
1378 static void handle_call_status(DBusMessage *msg, const char *call_path)
1380 struct csd_call *call;
1381 dbus_uint32_t status, cause_type, cause;
1383 if (!dbus_message_get_args(msg, NULL,
1384 DBUS_TYPE_UINT32, &status,
1385 DBUS_TYPE_UINT32, &cause_type,
1386 DBUS_TYPE_UINT32, &cause,
1387 DBUS_TYPE_INVALID)) {
1388 error("Unexpected parameters in Instance.CallStatus() signal");
1392 call = find_call(call_path);
1394 error("Didn't find any matching call object for %s",
1400 error("Invalid call status %u", status);
1404 call_set_status(call, status);
1407 static void handle_conference(DBusMessage *msg, gboolean joined)
1410 struct csd_call *call;
1412 if (!dbus_message_get_args(msg, NULL,
1413 DBUS_TYPE_OBJECT_PATH, &path,
1414 DBUS_TYPE_INVALID)) {
1415 error("Unexpected parameters in Conference.%s",
1416 dbus_message_get_member(msg));
1420 call = find_call(path);
1422 error("Conference signal for unknown call %s", path);
1426 DBG("Call %s %s the conference", path, joined ? "joined" : "left");
1428 call->conference = joined;
1431 static uint8_t str2status(const char *state)
1433 if (g_strcmp0(state, "Home") == 0)
1434 return NETWORK_REG_STATUS_HOME;
1435 else if (g_strcmp0(state, "Roaming") == 0)
1436 return NETWORK_REG_STATUS_ROAMING;
1437 else if (g_strcmp0(state, "Offline") == 0)
1438 return NETWORK_REG_STATUS_OFFLINE;
1439 else if (g_strcmp0(state, "Searching") == 0)
1440 return NETWORK_REG_STATUS_SEARCHING;
1441 else if (g_strcmp0(state, "NoSim") == 0)
1442 return NETWORK_REG_STATUS_NO_SIM;
1443 else if (g_strcmp0(state, "Poweroff") == 0)
1444 return NETWORK_REG_STATUS_POWEROFF;
1445 else if (g_strcmp0(state, "Powersafe") == 0)
1446 return NETWORK_REG_STATUS_POWERSAFE;
1447 else if (g_strcmp0(state, "NoCoverage") == 0)
1448 return NETWORK_REG_STATUS_NO_COVERAGE;
1449 else if (g_strcmp0(state, "Reject") == 0)
1450 return NETWORK_REG_STATUS_REJECTED;
1452 return NETWORK_REG_STATUS_UNKOWN;
1455 static void update_registration_status(const char *status)
1459 new_status = str2status(status);
1461 if (net.status == new_status)
1464 switch (new_status) {
1465 case NETWORK_REG_STATUS_HOME:
1466 telephony_update_indicator(maemo_indicators, "roam",
1468 if (net.status > NETWORK_REG_STATUS_ROAMING)
1469 telephony_update_indicator(maemo_indicators,
1471 EV_SERVICE_PRESENT);
1473 case NETWORK_REG_STATUS_ROAMING:
1474 telephony_update_indicator(maemo_indicators, "roam",
1476 if (net.status > NETWORK_REG_STATUS_ROAMING)
1477 telephony_update_indicator(maemo_indicators,
1479 EV_SERVICE_PRESENT);
1481 case NETWORK_REG_STATUS_OFFLINE:
1482 case NETWORK_REG_STATUS_SEARCHING:
1483 case NETWORK_REG_STATUS_NO_SIM:
1484 case NETWORK_REG_STATUS_POWEROFF:
1485 case NETWORK_REG_STATUS_POWERSAFE:
1486 case NETWORK_REG_STATUS_NO_COVERAGE:
1487 case NETWORK_REG_STATUS_REJECTED:
1488 case NETWORK_REG_STATUS_UNKOWN:
1489 if (net.status < NETWORK_REG_STATUS_OFFLINE)
1490 telephony_update_indicator(maemo_indicators,
1496 net.status = new_status;
1498 DBG("telephony-maemo6: registration status changed: %s", status);
1501 static void handle_registration_changed(DBusMessage *msg)
1505 if (!dbus_message_get_args(msg, NULL,
1506 DBUS_TYPE_STRING, &status,
1507 DBUS_TYPE_INVALID)) {
1508 error("Unexpected parameters in RegistrationChanged");
1512 update_registration_status(status);
1515 static void update_signal_strength(int32_t signal_bars)
1517 if (signal_bars < 0) {
1518 DBG("signal strength smaller than expected: %d < 0",
1521 } else if (signal_bars > 5) {
1522 DBG("signal strength greater than expected: %d > 5",
1527 if (net.signal_bars == signal_bars)
1530 telephony_update_indicator(maemo_indicators, "signal", signal_bars);
1532 net.signal_bars = signal_bars;
1533 DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
1536 static void handle_signal_bars_changed(DBusMessage *msg)
1538 int32_t signal_bars;
1540 if (!dbus_message_get_args(msg, NULL,
1541 DBUS_TYPE_INT32, &signal_bars,
1542 DBUS_TYPE_INVALID)) {
1543 error("Unexpected parameters in SignalBarsChanged");
1547 update_signal_strength(signal_bars);
1550 static gboolean iter_get_basic_args(DBusMessageIter *iter,
1551 int first_arg_type, ...)
1556 va_start(ap, first_arg_type);
1558 for (type = first_arg_type; type != DBUS_TYPE_INVALID;
1559 type = va_arg(ap, int)) {
1560 void *value = va_arg(ap, void *);
1561 int real_type = dbus_message_iter_get_arg_type(iter);
1563 if (real_type != type) {
1564 error("iter_get_basic_args: expected %c but got %c",
1565 (char) type, (char) real_type);
1569 dbus_message_iter_get_basic(iter, value);
1570 dbus_message_iter_next(iter);
1575 return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
1578 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
1583 int *value = user_data;
1585 reply = dbus_pending_call_steal_reply(call);
1587 dbus_error_init(&err);
1588 if (dbus_set_error_from_message(&err, reply)) {
1589 error("hald replied with an error: %s, %s",
1590 err.name, err.message);
1591 dbus_error_free(&err);
1595 if (!dbus_message_get_args(reply, NULL,
1596 DBUS_TYPE_INT32, &level,
1597 DBUS_TYPE_INVALID)) {
1598 error("Unexpected args in hald reply");
1602 *value = (int) level;
1604 if (value == &battchg_last)
1605 DBG("telephony-maemo6: battery.charge_level.last_full is %d",
1607 else if (value == &battchg_design)
1608 DBG("telephony-maemo6: battery.charge_level.design is %d",
1611 DBG("telephony-maemo6: battery.charge_level.current is %d",
1614 if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
1617 if (battchg_last > 0)
1620 max = battchg_design;
1622 new = battchg_cur * 5 / max;
1624 telephony_update_indicator(maemo_indicators, "battchg", new);
1628 dbus_message_unref(reply);
1629 remove_pending(call);
1632 static void hal_get_integer(const char *path, const char *key, void *user_data)
1634 send_method_call("org.freedesktop.Hal", path,
1635 "org.freedesktop.Hal.Device",
1636 "GetPropertyInteger",
1637 hal_battery_level_reply, user_data,
1638 DBUS_TYPE_STRING, &key,
1642 static void handle_hal_property_modified(DBusMessage *msg)
1644 DBusMessageIter iter, array;
1645 dbus_int32_t num_changes;
1648 path = dbus_message_get_path(msg);
1650 dbus_message_iter_init(msg, &iter);
1652 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
1653 error("Unexpected signature in hal PropertyModified signal");
1657 dbus_message_iter_get_basic(&iter, &num_changes);
1658 dbus_message_iter_next(&iter);
1660 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1661 error("Unexpected signature in hal PropertyModified signal");
1665 dbus_message_iter_recurse(&iter, &array);
1667 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1668 DBusMessageIter prop;
1670 dbus_bool_t added, removed;
1672 dbus_message_iter_recurse(&array, &prop);
1674 if (!iter_get_basic_args(&prop,
1675 DBUS_TYPE_STRING, &name,
1676 DBUS_TYPE_BOOLEAN, &added,
1677 DBUS_TYPE_BOOLEAN, &removed,
1678 DBUS_TYPE_INVALID)) {
1679 error("Invalid hal PropertyModified parameters");
1683 if (g_str_equal(name, "battery.charge_level.last_full"))
1684 hal_get_integer(path, name, &battchg_last);
1685 else if (g_str_equal(name, "battery.charge_level.current"))
1686 hal_get_integer(path, name, &battchg_cur);
1687 else if (g_str_equal(name, "battery.charge_level.design"))
1688 hal_get_integer(path, name, &battchg_design);
1690 dbus_message_iter_next(&array);
1694 static void csd_call_free(void *data)
1696 struct csd_call *call = data;
1701 g_free(call->object_path);
1702 g_free(call->number);
1704 g_slist_foreach(pending, remove_pending_by_data, call);
1709 static void parse_call_list(DBusMessageIter *iter)
1712 DBusMessageIter call_iter;
1713 struct csd_call *call;
1714 const char *object_path, *number;
1715 dbus_uint32_t status;
1716 dbus_bool_t originating, terminating, emerg, on_hold, conf;
1718 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
1719 error("Unexpected signature in GetCallInfoAll reply");
1723 dbus_message_iter_recurse(iter, &call_iter);
1725 if (!iter_get_basic_args(&call_iter,
1726 DBUS_TYPE_OBJECT_PATH, &object_path,
1727 DBUS_TYPE_UINT32, &status,
1728 DBUS_TYPE_BOOLEAN, &originating,
1729 DBUS_TYPE_BOOLEAN, &terminating,
1730 DBUS_TYPE_BOOLEAN, &emerg,
1731 DBUS_TYPE_BOOLEAN, &on_hold,
1732 DBUS_TYPE_BOOLEAN, &conf,
1733 DBUS_TYPE_STRING, &number,
1734 DBUS_TYPE_INVALID)) {
1735 error("Parsing call D-Bus parameters failed");
1739 call = find_call(object_path);
1741 call = g_new0(struct csd_call, 1);
1742 call->object_path = g_strdup(object_path);
1743 calls = g_slist_append(calls, call);
1744 DBG("telephony-maemo6: new csd call instance at %s",
1748 if (status == CSD_CALL_STATUS_IDLE)
1751 /* CSD gives incorrect call_hold property sometimes */
1752 if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
1753 (call->status == CSD_CALL_STATUS_HOLD &&
1755 error("Conflicting call status and on_hold property!");
1756 on_hold = call->status == CSD_CALL_STATUS_HOLD;
1759 call->originating = originating;
1760 call->on_hold = on_hold;
1761 call->conference = conf;
1762 g_free(call->number);
1763 call->number = g_strdup(number);
1765 /* Update indicators */
1766 call_set_status(call, status);
1768 } while (dbus_message_iter_next(iter));
1771 static void update_operator_name(const char *name)
1776 g_free(net.operator_name);
1777 net.operator_name = g_strndup(name, 16);
1778 DBG("telephony-maemo6: operator name updated: %s", name);
1781 static void get_property_reply(DBusPendingCall *call, void *user_data)
1783 char *prop = user_data;
1786 DBusMessageIter iter, sub;
1788 reply = dbus_pending_call_steal_reply(call);
1790 dbus_error_init(&err);
1791 if (dbus_set_error_from_message(&err, reply)) {
1792 error("csd replied with an error: %s, %s",
1793 err.name, err.message);
1794 dbus_error_free(&err);
1798 dbus_message_iter_init(reply, &iter);
1800 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1801 error("Unexpected signature in Get return");
1805 dbus_message_iter_recurse(&iter, &sub);
1807 if (g_strcmp0(prop, "RegistrationStatus") == 0) {
1810 dbus_message_iter_get_basic(&sub, &status);
1811 update_registration_status(status);
1813 get_property(CSD_CSNET_OPERATOR, "OperatorName");
1814 get_property(CSD_CSNET_SIGNAL, "SignalBars");
1815 } else if (g_strcmp0(prop, "OperatorName") == 0) {
1818 dbus_message_iter_get_basic(&sub, &name);
1819 update_operator_name(name);
1820 } else if (g_strcmp0(prop, "SignalBars") == 0) {
1821 int32_t signal_bars;
1823 dbus_message_iter_get_basic(&sub, &signal_bars);
1824 update_signal_strength(signal_bars);
1829 dbus_message_unref(reply);
1830 remove_pending(call);
1833 static int get_property(const char *iface, const char *prop)
1835 return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
1836 DBUS_INTERFACE_PROPERTIES, "Get",
1837 get_property_reply, g_strdup(prop),
1838 DBUS_TYPE_STRING, &iface,
1839 DBUS_TYPE_STRING, &prop,
1843 static void handle_operator_name_changed(DBusMessage *msg)
1847 if (!dbus_message_get_args(msg, NULL,
1848 DBUS_TYPE_STRING, &name,
1849 DBUS_TYPE_INVALID)) {
1850 error("Unexpected parameters in OperatorNameChanged");
1854 update_operator_name(name);
1857 static void call_info_reply(DBusPendingCall *call, void *user_data)
1861 DBusMessageIter iter, sub;
1863 get_calls_active = FALSE;
1865 reply = dbus_pending_call_steal_reply(call);
1867 dbus_error_init(&err);
1868 if (dbus_set_error_from_message(&err, reply)) {
1869 error("csd replied with an error: %s, %s",
1870 err.name, err.message);
1871 dbus_error_free(&err);
1875 dbus_message_iter_init(reply, &iter);
1877 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1878 error("Unexpected signature in GetCallInfoAll return");
1882 dbus_message_iter_recurse(&iter, &sub);
1884 parse_call_list(&sub);
1886 get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
1889 dbus_message_unref(reply);
1890 remove_pending(call);
1894 static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
1898 const char *name, *number, *secondname, *additionalnumber, *email;
1900 char **number_type = user_data;
1902 reply = dbus_pending_call_steal_reply(call);
1904 dbus_error_init(&derr);
1905 if (dbus_set_error_from_message(&derr, reply)) {
1906 error("%s.ReadFirst replied with an error: %s, %s",
1907 CSD_SIMPB_INTERFACE, derr.name, derr.message);
1908 dbus_error_free(&derr);
1909 if (number_type == &vmbx)
1910 vmbx = g_strdup(getenv("VMBX_NUMBER"));
1914 dbus_error_init(&derr);
1915 if (dbus_message_get_args(reply, NULL,
1916 DBUS_TYPE_INT32, &index,
1917 DBUS_TYPE_STRING, &name,
1918 DBUS_TYPE_STRING, &number,
1919 DBUS_TYPE_STRING, &secondname,
1920 DBUS_TYPE_STRING, &additionalnumber,
1921 DBUS_TYPE_STRING, &email,
1922 DBUS_TYPE_INVALID) == FALSE) {
1923 error("Unable to parse %s.ReadFirst arguments: %s, %s",
1924 CSD_SIMPB_INTERFACE, derr.name, derr.message);
1925 dbus_error_free(&derr);
1929 if (number_type == &msisdn) {
1931 msisdn = g_strdup(number);
1932 DBG("Got MSISDN %s (%s)", number, name);
1935 vmbx = g_strdup(number);
1936 DBG("Got voice mailbox number %s (%s)", number, name);
1940 dbus_message_unref(reply);
1941 remove_pending(call);
1944 static void csd_init(void)
1946 const char *pb_type;
1949 ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1950 CSD_CALL_INTERFACE, "GetCallInfoAll",
1951 call_info_reply, NULL, DBUS_TYPE_INVALID);
1953 error("Unable to sent GetCallInfoAll method call");
1957 get_calls_active = TRUE;
1959 pb_type = CSD_SIMPB_TYPE_MSISDN;
1961 ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
1962 CSD_SIMPB_INTERFACE, "ReadFirst",
1963 phonebook_read_reply, &msisdn,
1964 DBUS_TYPE_STRING, &pb_type,
1967 error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
1971 /* Voicemail should be in MBDN index 0 */
1972 pb_type = CSD_SIMPB_TYPE_MBDN;
1974 ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
1975 CSD_SIMPB_INTERFACE, "ReadFirst",
1976 phonebook_read_reply, &vmbx,
1977 DBUS_TYPE_STRING, &pb_type,
1980 error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
1985 static void handle_modem_state(DBusMessage *msg)
1989 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
1990 DBUS_TYPE_INVALID)) {
1991 error("Unexpected modem state parameters");
1995 DBG("SSC modem state: %s", state);
1997 if (calls != NULL || get_calls_active)
2000 if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
2004 static void modem_state_reply(DBusPendingCall *call, void *user_data)
2006 DBusMessage *reply = dbus_pending_call_steal_reply(call);
2009 dbus_error_init(&err);
2010 if (dbus_set_error_from_message(&err, reply)) {
2011 error("get_modem_state: %s, %s", err.name, err.message);
2012 dbus_error_free(&err);
2014 handle_modem_state(reply);
2016 dbus_message_unref(reply);
2017 remove_pending(call);
2020 static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
2023 const char *path = dbus_message_get_path(msg);
2025 if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
2026 handle_incoming_call(msg);
2027 else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
2028 handle_outgoing_call(msg);
2029 else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
2031 handle_create_requested(msg);
2032 else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
2033 handle_call_status(msg, path);
2034 else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
2035 handle_conference(msg, TRUE);
2036 else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
2037 handle_conference(msg, FALSE);
2038 else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
2039 "RegistrationChanged"))
2040 handle_registration_changed(msg);
2041 else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
2042 "OperatorNameChanged"))
2043 handle_operator_name_changed(msg);
2044 else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
2045 "SignalBarsChanged"))
2046 handle_signal_bars_changed(msg);
2047 else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
2048 "PropertyModified"))
2049 handle_hal_property_modified(msg);
2050 else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
2051 "modem_state_changed_ind"))
2052 handle_modem_state(msg);
2057 static void add_watch(const char *sender, const char *path,
2058 const char *interface, const char *member)
2062 watch = g_dbus_add_signal_watch(connection, sender, path, interface,
2063 member, signal_filter, NULL, NULL);
2065 watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
2068 static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
2072 DBusMessageIter iter, sub;
2076 reply = dbus_pending_call_steal_reply(call);
2078 dbus_error_init(&err);
2079 if (dbus_set_error_from_message(&err, reply)) {
2080 error("hald replied with an error: %s, %s",
2081 err.name, err.message);
2082 dbus_error_free(&err);
2086 dbus_message_iter_init(reply, &iter);
2088 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
2089 error("Unexpected signature in FindDeviceByCapability return");
2093 dbus_message_iter_recurse(&iter, &sub);
2095 type = dbus_message_iter_get_arg_type(&sub);
2097 if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
2098 error("No hal device with battery capability found");
2102 dbus_message_iter_get_basic(&sub, &path);
2104 DBG("telephony-maemo6: found battery device at %s", path);
2106 add_watch(NULL, path, "org.freedesktop.Hal.Device",
2107 "PropertyModified");
2109 hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
2110 hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
2111 hal_get_integer(path, "battery.charge_level.design", &battchg_design);
2114 dbus_message_unref(reply);
2115 remove_pending(call);
2118 int telephony_init(void)
2120 const char *battery_cap = "battery";
2121 uint32_t features = AG_FEATURE_EC_ANDOR_NR |
2122 AG_FEATURE_INBAND_RINGTONE |
2123 AG_FEATURE_REJECT_A_CALL |
2124 AG_FEATURE_ENHANCED_CALL_STATUS |
2125 AG_FEATURE_ENHANCED_CALL_CONTROL |
2126 AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
2127 AG_FEATURE_THREE_WAY_CALLING;
2132 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2134 add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL);
2135 add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL);
2136 add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL);
2137 add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged");
2138 add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged");
2139 add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged");
2140 add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind");
2142 if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
2143 "get_modem_state", modem_state_reply,
2144 NULL, DBUS_TYPE_INVALID) < 0)
2145 error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
2147 /* Reset indicators */
2148 for (i = 0; maemo_indicators[i].desc != NULL; i++) {
2149 if (g_str_equal(maemo_indicators[i].desc, "battchg"))
2150 maemo_indicators[i].val = 5;
2152 maemo_indicators[i].val = 0;
2155 telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
2157 if (send_method_call("org.freedesktop.Hal",
2158 "/org/freedesktop/Hal/Manager",
2159 "org.freedesktop.Hal.Manager",
2160 "FindDeviceByCapability",
2161 hal_find_device_reply, NULL,
2162 DBUS_TYPE_STRING, &battery_cap,
2163 DBUS_TYPE_INVALID) < 0)
2164 error("Unable to send HAL method call");
2169 static void remove_watch(gpointer data)
2171 g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
2174 void telephony_exit(void)
2178 g_free(net.operator_name);
2179 net.operator_name = NULL;
2181 net.status = NETWORK_REG_STATUS_UNKOWN;
2182 net.signal_bars = 0;
2184 g_slist_free(active_calls);
2185 active_calls = NULL;
2187 g_slist_free_full(calls, csd_call_free);
2190 g_slist_free_full(pending, pending_req_finalize);
2193 g_slist_free_full(watches, remove_watch);
2196 dbus_connection_unref(connection);