3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2009-2010 Intel Corporation
6 * Copyright (C) 2006-2009 Nokia Corporation
7 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 #include <dbus/dbus.h>
38 #include <bluetooth/sdp.h>
40 #include "glib-helper.h"
42 #include "telephony.h"
44 enum net_registration_status {
45 NETWORK_REG_STATUS_HOME = 0x00,
46 NETWORK_REG_STATUS_ROAM,
47 NETWORK_REG_STATUS_NOSERV
59 static DBusConnection *connection = NULL;
60 static char *modem_obj_path = NULL;
61 static char *last_dialed_number = NULL;
62 static GSList *calls = NULL;
63 static GSList *watches = NULL;
64 static GSList *pending = NULL;
66 #define OFONO_BUS_NAME "org.ofono"
67 #define OFONO_PATH "/"
68 #define OFONO_MODEM_INTERFACE "org.ofono.Modem"
69 #define OFONO_MANAGER_INTERFACE "org.ofono.Manager"
70 #define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration"
71 #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
72 #define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
74 /* HAL battery namespace key values */
75 static int battchg_cur = -1; /* "battery.charge_level.current" */
76 static int battchg_last = -1; /* "battery.charge_level.last_full" */
77 static int battchg_design = -1; /* "battery.charge_level.design" */
84 .status = NETWORK_REG_STATUS_NOSERV,
86 .operator_name = NULL,
89 static const char *chld_str = "0,1,1x,2,2x,3,4";
90 static char *subscriber_number = NULL;
92 static gboolean events_enabled = FALSE;
94 static struct indicator ofono_indicators[] =
96 { "battchg", "0-5", 5, TRUE },
97 { "signal", "0-5", 5, TRUE },
98 { "service", "0,1", 1, TRUE },
99 { "call", "0,1", 0, TRUE },
100 { "callsetup", "0-3", 0, TRUE },
101 { "callheld", "0-2", 0, FALSE },
102 { "roam", "0,1", 0, TRUE },
106 static struct voice_call *find_vc(const char *path)
110 for (l = calls; l != NULL; l = l->next) {
111 struct voice_call *vc = l->data;
113 if (g_str_equal(vc->obj_path, path))
120 static struct voice_call *find_vc_with_status(int status)
124 for (l = calls; l != NULL; l = l->next) {
125 struct voice_call *vc = l->data;
127 if (vc->status == status)
134 static struct voice_call *find_vc_without_status(int status)
138 for (l = calls; l != NULL; l = l->next) {
139 struct voice_call *call = l->data;
141 if (call->status != status)
148 static int number_type(const char *number)
151 return NUMBER_TYPE_TELEPHONY;
153 if (number[0] == '+' || strncmp(number, "00", 2) == 0)
154 return NUMBER_TYPE_INTERNATIONAL;
156 return NUMBER_TYPE_TELEPHONY;
159 void telephony_device_connected(void *telephony_device)
161 struct voice_call *coming;
163 DBG("telephony-ofono: device %p connected", telephony_device);
165 coming = find_vc_with_status(CALL_STATUS_ALERTING);
167 if (find_vc_with_status(CALL_STATUS_ACTIVE))
168 telephony_call_waiting_ind(coming->number,
169 number_type(coming->number));
171 telephony_incoming_call_ind(coming->number,
172 number_type(coming->number));
176 void telephony_device_disconnected(void *telephony_device)
178 DBG("telephony-ofono: device %p disconnected", telephony_device);
179 events_enabled = FALSE;
182 void telephony_event_reporting_req(void *telephony_device, int ind)
184 events_enabled = ind == 1 ? TRUE : FALSE;
186 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
189 void telephony_response_and_hold_req(void *telephony_device, int rh)
191 telephony_response_and_hold_rsp(telephony_device,
192 CME_ERROR_NOT_SUPPORTED);
195 void telephony_last_dialed_number_req(void *telephony_device)
197 DBG("telephony-ofono: last dialed number request");
199 if (last_dialed_number)
200 telephony_dial_number_req(telephony_device, last_dialed_number);
202 telephony_last_dialed_number_rsp(telephony_device,
203 CME_ERROR_NOT_ALLOWED);
206 static int send_method_call(const char *dest, const char *path,
207 const char *interface, const char *method,
208 DBusPendingCallNotifyFunction cb,
209 void *user_data, int type, ...)
212 DBusPendingCall *call;
215 msg = dbus_message_new_method_call(dest, path, interface, method);
217 error("Unable to allocate new D-Bus %s message", method);
221 va_start(args, type);
223 if (!dbus_message_append_args_valist(msg, type, args)) {
224 dbus_message_unref(msg);
232 g_dbus_send_message(connection, msg);
236 if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
237 error("Sending %s failed", method);
238 dbus_message_unref(msg);
242 dbus_pending_call_set_notify(call, cb, user_data, NULL);
243 pending = g_slist_prepend(pending, call);
244 dbus_message_unref(msg);
249 static int answer_call(struct voice_call *vc)
251 DBG("%s", vc->number);
252 return send_method_call(OFONO_BUS_NAME, vc->obj_path,
253 OFONO_VC_INTERFACE, "Answer",
254 NULL, NULL, DBUS_TYPE_INVALID);
257 static int release_call(struct voice_call *vc)
259 DBG("%s", vc->number);
260 return send_method_call(OFONO_BUS_NAME, vc->obj_path,
261 OFONO_VC_INTERFACE, "Hangup",
262 NULL, NULL, DBUS_TYPE_INVALID);
265 static int release_answer_calls(void)
268 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
269 OFONO_VCMANAGER_INTERFACE,
271 NULL, NULL, DBUS_TYPE_INVALID);
274 static int split_call(struct voice_call *call)
276 DBG("%s", call->number);
277 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
278 OFONO_VCMANAGER_INTERFACE,
281 DBUS_TYPE_OBJECT_PATH,
287 static int swap_calls(void)
290 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
291 OFONO_VCMANAGER_INTERFACE,
293 NULL, NULL, DBUS_TYPE_INVALID);
296 static int create_conference(void)
299 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
300 OFONO_VCMANAGER_INTERFACE,
302 NULL, NULL, DBUS_TYPE_INVALID);
305 static int release_conference(void)
308 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
309 OFONO_VCMANAGER_INTERFACE,
311 NULL, NULL, DBUS_TYPE_INVALID);
314 static int call_transfer(void)
317 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
318 OFONO_VCMANAGER_INTERFACE,
320 NULL, NULL, DBUS_TYPE_INVALID);
323 void telephony_terminate_call_req(void *telephony_device)
325 struct voice_call *call;
326 struct voice_call *alerting;
329 call = find_vc_with_status(CALL_STATUS_ACTIVE);
334 error("No active call");
335 telephony_terminate_call_rsp(telephony_device,
336 CME_ERROR_NOT_ALLOWED);
340 alerting = find_vc_with_status(CALL_STATUS_ALERTING);
341 if (call->status == CALL_STATUS_HELD && alerting)
342 err = release_call(alerting);
343 else if (call->conference)
344 err = release_conference();
346 err = release_call(call);
349 telephony_terminate_call_rsp(telephony_device,
350 CME_ERROR_AG_FAILURE);
352 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
355 void telephony_answer_call_req(void *telephony_device)
357 struct voice_call *vc;
360 vc = find_vc_with_status(CALL_STATUS_INCOMING);
362 vc = find_vc_with_status(CALL_STATUS_ALERTING);
365 vc = find_vc_with_status(CALL_STATUS_WAITING);
368 telephony_answer_call_rsp(telephony_device,
369 CME_ERROR_NOT_ALLOWED);
373 ret = answer_call(vc);
375 telephony_answer_call_rsp(telephony_device,
376 CME_ERROR_AG_FAILURE);
380 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
383 void telephony_dial_number_req(void *telephony_device, const char *number)
388 DBG("telephony-ofono: dial request to %s", number);
390 if (!modem_obj_path) {
391 telephony_dial_number_rsp(telephony_device,
392 CME_ERROR_AG_FAILURE);
396 if (!strncmp(number, "*31#", 4)) {
399 } else if (!strncmp(number, "#31#", 4)) {
405 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
406 OFONO_VCMANAGER_INTERFACE,
408 DBUS_TYPE_STRING, &number,
409 DBUS_TYPE_STRING, &clir,
413 telephony_dial_number_rsp(telephony_device,
414 CME_ERROR_AG_FAILURE);
416 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
419 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
424 DBG("telephony-ofono: transmit dtmf: %c", tone);
426 if (!modem_obj_path) {
427 telephony_transmit_dtmf_rsp(telephony_device,
428 CME_ERROR_AG_FAILURE);
432 tone_string = g_strdup_printf("%c", tone);
433 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
434 OFONO_VCMANAGER_INTERFACE,
435 "SendTones", NULL, NULL,
436 DBUS_TYPE_STRING, &tone_string,
441 telephony_transmit_dtmf_rsp(telephony_device,
442 CME_ERROR_AG_FAILURE);
444 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
447 void telephony_subscriber_number_req(void *telephony_device)
449 DBG("telephony-ofono: subscriber number request");
451 if (subscriber_number)
452 telephony_subscriber_number_ind(subscriber_number,
453 NUMBER_TYPE_TELEPHONY,
454 SUBSCRIBER_SERVICE_VOICE);
455 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
458 void telephony_list_current_calls_req(void *telephony_device)
463 DBG("telephony-ofono: list current calls request");
465 for (l = calls, i = 1; l != NULL; l = l->next, i++) {
466 struct voice_call *vc = l->data;
467 int direction, multiparty;
469 direction = vc->originating ?
470 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
472 multiparty = vc->conference ?
473 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
475 DBG("call %s direction %d multiparty %d", vc->number,
476 direction, multiparty);
478 telephony_list_current_call_ind(i, direction, vc->status,
479 CALL_MODE_VOICE, multiparty,
480 vc->number, number_type(vc->number));
483 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
486 void telephony_operator_selection_req(void *telephony_device)
488 DBG("telephony-ofono: operator selection request");
490 telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
491 net.operator_name ? net.operator_name : "");
492 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
495 static void foreach_vc_with_status(int status,
496 int (*func)(struct voice_call *vc))
500 for (l = calls; l != NULL; l = l->next) {
501 struct voice_call *call = l->data;
503 if (call->status == status)
508 void telephony_call_hold_req(void *telephony_device, const char *cmd)
511 struct voice_call *call;
514 DBG("telephony-ofono: got call hold request %s", cmd);
522 call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
528 if (find_vc_with_status(CALL_STATUS_WAITING))
529 foreach_vc_with_status(CALL_STATUS_WAITING,
532 foreach_vc_with_status(CALL_STATUS_HELD, release_call);
537 err = release_call(call);
540 err = release_answer_calls();
545 err = split_call(call);
547 call = find_vc_with_status(CALL_STATUS_WAITING);
550 err = answer_call(call);
556 if (find_vc_with_status(CALL_STATUS_HELD) ||
557 find_vc_with_status(CALL_STATUS_WAITING))
558 err = create_conference();
561 err = call_transfer();
564 DBG("Unknown call hold request");
569 telephony_call_hold_rsp(telephony_device,
570 CME_ERROR_AG_FAILURE);
572 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
575 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
577 DBG("telephony-ofono: got %s NR and EC request",
578 enable ? "enable" : "disable");
580 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
583 void telephony_key_press_req(void *telephony_device, const char *keys)
585 struct voice_call *active, *incoming;
588 DBG("telephony-ofono: got key press request for %s", keys);
590 incoming = find_vc_with_status(CALL_STATUS_INCOMING);
592 active = find_vc_with_status(CALL_STATUS_ACTIVE);
595 err = answer_call(incoming);
597 err = release_call(active);
602 telephony_key_press_rsp(telephony_device,
603 CME_ERROR_AG_FAILURE);
605 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
608 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
610 DBG("telephony-ofono: got %s voice dial request",
611 enable ? "enable" : "disable");
613 telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
616 static gboolean iter_get_basic_args(DBusMessageIter *iter,
617 int first_arg_type, ...)
622 va_start(ap, first_arg_type);
624 for (type = first_arg_type; type != DBUS_TYPE_INVALID;
625 type = va_arg(ap, int)) {
626 void *value = va_arg(ap, void *);
627 int real_type = dbus_message_iter_get_arg_type(iter);
629 if (real_type != type) {
630 error("iter_get_basic_args: expected %c but got %c",
631 (char) type, (char) real_type);
635 dbus_message_iter_get_basic(iter, value);
636 dbus_message_iter_next(iter);
641 return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
644 static void call_free(void *data)
646 struct voice_call *vc = data;
648 DBG("%s", vc->obj_path);
650 if (vc->status == CALL_STATUS_ACTIVE)
651 telephony_update_indicator(ofono_indicators, "call",
654 telephony_update_indicator(ofono_indicators, "callsetup",
655 EV_CALLSETUP_INACTIVE);
657 if (vc->status == CALL_STATUS_INCOMING)
658 telephony_calling_stopped_ind();
660 g_dbus_remove_watch(connection, vc->watch);
661 g_free(vc->obj_path);
666 static gboolean handle_vc_property_changed(DBusConnection *conn,
667 DBusMessage *msg, void *data)
669 struct voice_call *vc = data;
670 const char *obj_path = dbus_message_get_path(msg);
671 DBusMessageIter iter, sub;
672 const char *property, *state;
674 DBG("path %s", obj_path);
676 dbus_message_iter_init(msg, &iter);
678 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
679 error("Unexpected signature in vc PropertyChanged signal");
683 dbus_message_iter_get_basic(&iter, &property);
684 DBG("property %s", property);
686 dbus_message_iter_next(&iter);
687 dbus_message_iter_recurse(&iter, &sub);
688 if (g_str_equal(property, "State")) {
689 dbus_message_iter_get_basic(&sub, &state);
690 DBG("State %s", state);
691 if (g_str_equal(state, "disconnected")) {
692 calls = g_slist_remove(calls, vc);
694 } else if (g_str_equal(state, "active")) {
695 telephony_update_indicator(ofono_indicators,
696 "call", EV_CALL_ACTIVE);
697 telephony_update_indicator(ofono_indicators,
699 EV_CALLSETUP_INACTIVE);
700 if (vc->status == CALL_STATUS_INCOMING)
701 telephony_calling_stopped_ind();
702 vc->status = CALL_STATUS_ACTIVE;
703 } else if (g_str_equal(state, "alerting")) {
704 telephony_update_indicator(ofono_indicators,
705 "callsetup", EV_CALLSETUP_ALERTING);
706 vc->status = CALL_STATUS_ALERTING;
707 vc->originating = TRUE;
708 } else if (g_str_equal(state, "incoming")) {
709 /* state change from waiting to incoming */
710 telephony_update_indicator(ofono_indicators,
711 "callsetup", EV_CALLSETUP_INCOMING);
712 telephony_incoming_call_ind(vc->number,
713 NUMBER_TYPE_TELEPHONY);
714 vc->status = CALL_STATUS_INCOMING;
715 vc->originating = FALSE;
716 } else if (g_str_equal(state, "held")) {
717 vc->status = CALL_STATUS_HELD;
718 if (find_vc_without_status(CALL_STATUS_HELD))
719 telephony_update_indicator(ofono_indicators,
721 EV_CALLHELD_MULTIPLE);
723 telephony_update_indicator(ofono_indicators,
725 EV_CALLHELD_ON_HOLD);
727 } else if (g_str_equal(property, "Multiparty")) {
728 dbus_bool_t multiparty;
730 dbus_message_iter_get_basic(&sub, &multiparty);
731 DBG("Multiparty %s", multiparty ? "True" : "False");
732 vc->conference = multiparty;
738 static struct voice_call *call_new(const char *path, DBusMessageIter *properties)
740 struct voice_call *vc;
744 vc = g_new0(struct voice_call, 1);
745 vc->obj_path = g_strdup(path);
746 vc->watch = g_dbus_add_signal_watch(connection, NULL, path,
747 OFONO_VC_INTERFACE, "PropertyChanged",
748 handle_vc_property_changed, vc, NULL);
750 while (dbus_message_iter_get_arg_type(properties)
751 == DBUS_TYPE_DICT_ENTRY) {
752 DBusMessageIter entry, value;
753 const char *property, *cli, *state;
754 dbus_bool_t multiparty;
756 dbus_message_iter_recurse(properties, &entry);
757 dbus_message_iter_get_basic(&entry, &property);
759 dbus_message_iter_next(&entry);
760 dbus_message_iter_recurse(&entry, &value);
762 if (g_str_equal(property, "LineIdentification")) {
763 dbus_message_iter_get_basic(&value, &cli);
765 vc->number = g_strdup(cli);
766 } else if (g_str_equal(property, "State")) {
767 dbus_message_iter_get_basic(&value, &state);
768 DBG("state %s", state);
769 if (g_str_equal(state, "incoming"))
770 vc->status = CALL_STATUS_INCOMING;
771 else if (g_str_equal(state, "dialing"))
772 vc->status = CALL_STATUS_DIALING;
773 else if (g_str_equal(state, "alerting"))
774 vc->status = CALL_STATUS_ALERTING;
775 else if (g_str_equal(state, "waiting"))
776 vc->status = CALL_STATUS_WAITING;
777 else if (g_str_equal(state, "held"))
778 vc->status = CALL_STATUS_HELD;
779 } else if (g_str_equal(property, "Multiparty")) {
780 dbus_message_iter_get_basic(&value, &multiparty);
781 DBG("Multipary %s", multiparty ? "True" : "False");
782 vc->conference = multiparty;
785 dbus_message_iter_next(properties);
788 switch (vc->status) {
789 case CALL_STATUS_INCOMING:
790 DBG("CALL_STATUS_INCOMING");
791 vc->originating = FALSE;
792 telephony_update_indicator(ofono_indicators, "callsetup",
793 EV_CALLSETUP_INCOMING);
794 telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
796 case CALL_STATUS_DIALING:
797 DBG("CALL_STATUS_DIALING");
798 vc->originating = TRUE;
799 g_free(last_dialed_number);
800 last_dialed_number = g_strdup(vc->number);
801 telephony_update_indicator(ofono_indicators, "callsetup",
802 EV_CALLSETUP_OUTGOING);
804 case CALL_STATUS_ALERTING:
805 DBG("CALL_STATUS_ALERTING");
806 vc->originating = TRUE;
807 g_free(last_dialed_number);
808 last_dialed_number = g_strdup(vc->number);
809 telephony_update_indicator(ofono_indicators, "callsetup",
810 EV_CALLSETUP_ALERTING);
812 case CALL_STATUS_WAITING:
813 DBG("CALL_STATUS_WAITING");
814 vc->originating = FALSE;
815 telephony_update_indicator(ofono_indicators, "callsetup",
816 EV_CALLSETUP_INCOMING);
817 telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
824 static void remove_pending(DBusPendingCall *call)
826 pending = g_slist_remove(pending, call);
827 dbus_pending_call_unref(call);
830 static void call_added(const char *path, DBusMessageIter *properties)
832 struct voice_call *vc;
840 vc = call_new(path, properties);
841 calls = g_slist_prepend(calls, vc);
844 static void get_calls_reply(DBusPendingCall *call, void *user_data)
848 DBusMessageIter iter, entry;
851 reply = dbus_pending_call_steal_reply(call);
853 dbus_error_init(&err);
854 if (dbus_set_error_from_message(&err, reply)) {
855 error("ofono replied with an error: %s, %s",
856 err.name, err.message);
857 dbus_error_free(&err);
861 dbus_message_iter_init(reply, &iter);
863 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
864 error("Unexpected signature");
868 dbus_message_iter_recurse(&iter, &entry);
870 while (dbus_message_iter_get_arg_type(&entry)
871 == DBUS_TYPE_STRUCT) {
873 DBusMessageIter value, properties;
875 dbus_message_iter_recurse(&entry, &value);
876 dbus_message_iter_get_basic(&value, &path);
878 dbus_message_iter_next(&value);
879 dbus_message_iter_recurse(&value, &properties);
881 call_added(path, &properties);
883 dbus_message_iter_next(&entry);
887 dbus_message_unref(reply);
888 remove_pending(call);
891 static void handle_network_property(const char *property, DBusMessageIter *variant)
893 const char *status, *operator;
894 unsigned int signals_bar;
896 if (g_str_equal(property, "Status")) {
897 dbus_message_iter_get_basic(variant, &status);
898 DBG("Status is %s", status);
899 if (g_str_equal(status, "registered")) {
900 net.status = NETWORK_REG_STATUS_HOME;
901 telephony_update_indicator(ofono_indicators,
902 "roam", EV_ROAM_INACTIVE);
903 telephony_update_indicator(ofono_indicators,
904 "service", EV_SERVICE_PRESENT);
905 } else if (g_str_equal(status, "roaming")) {
906 net.status = NETWORK_REG_STATUS_ROAM;
907 telephony_update_indicator(ofono_indicators,
908 "roam", EV_ROAM_ACTIVE);
909 telephony_update_indicator(ofono_indicators,
910 "service", EV_SERVICE_PRESENT);
912 net.status = NETWORK_REG_STATUS_NOSERV;
913 telephony_update_indicator(ofono_indicators,
914 "roam", EV_ROAM_INACTIVE);
915 telephony_update_indicator(ofono_indicators,
916 "service", EV_SERVICE_NONE);
918 } else if (g_str_equal(property, "Name")) {
919 dbus_message_iter_get_basic(variant, &operator);
920 DBG("Operator is %s", operator);
921 g_free(net.operator_name);
922 net.operator_name = g_strdup(operator);
923 } else if (g_str_equal(property, "SignalStrength")) {
924 dbus_message_iter_get_basic(variant, &signals_bar);
925 DBG("SignalStrength is %d", signals_bar);
926 net.signals_bar = signals_bar;
927 telephony_update_indicator(ofono_indicators, "signal",
928 (signals_bar + 20) / 21);
932 static int parse_network_properties(DBusMessageIter *properties)
936 /* Reset indicators */
937 for (i = 0; ofono_indicators[i].desc != NULL; i++) {
938 if (g_str_equal(ofono_indicators[i].desc, "battchg"))
939 ofono_indicators[i].val = 5;
941 ofono_indicators[i].val = 0;
944 while (dbus_message_iter_get_arg_type(properties)
945 == DBUS_TYPE_DICT_ENTRY) {
947 DBusMessageIter value, entry;
949 dbus_message_iter_recurse(properties, &entry);
950 dbus_message_iter_get_basic(&entry, &key);
952 dbus_message_iter_next(&entry);
953 dbus_message_iter_recurse(&entry, &value);
955 handle_network_property(key, &value);
957 dbus_message_iter_next(properties);
963 static void get_properties_reply(DBusPendingCall *call, void *user_data)
967 DBusMessageIter iter, properties;
971 reply = dbus_pending_call_steal_reply(call);
973 dbus_error_init(&err);
974 if (dbus_set_error_from_message(&err, reply)) {
975 error("ofono replied with an error: %s, %s",
976 err.name, err.message);
977 dbus_error_free(&err);
981 dbus_message_iter_init(reply, &iter);
983 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
984 error("Unexpected signature");
988 dbus_message_iter_recurse(&iter, &properties);
990 ret = parse_network_properties(&properties);
992 error("Unable to parse %s.GetProperty reply",
993 OFONO_NETWORKREG_INTERFACE);
997 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
998 OFONO_VCMANAGER_INTERFACE, "GetCalls",
999 get_calls_reply, NULL, DBUS_TYPE_INVALID);
1001 error("Unable to send %s.GetCalls",
1002 OFONO_VCMANAGER_INTERFACE);
1005 dbus_message_unref(reply);
1006 remove_pending(call);
1009 static void network_found(const char *path)
1015 modem_obj_path = g_strdup(path);
1017 ret = send_method_call(OFONO_BUS_NAME, path,
1018 OFONO_NETWORKREG_INTERFACE, "GetProperties",
1019 get_properties_reply, NULL, DBUS_TYPE_INVALID);
1021 error("Unable to send %s.GetProperties",
1022 OFONO_NETWORKREG_INTERFACE);
1025 static void modem_removed(const char *path)
1027 if (g_strcmp0(modem_obj_path, path) != 0)
1032 g_slist_free_full(calls, call_free);
1035 g_free(net.operator_name);
1036 net.operator_name = NULL;
1037 net.status = NETWORK_REG_STATUS_NOSERV;
1038 net.signals_bar = 0;
1040 g_free(modem_obj_path);
1041 modem_obj_path = NULL;
1044 static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces)
1048 while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) {
1051 dbus_message_iter_get_basic(ifaces, &iface);
1053 if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) {
1054 network_found(path);
1058 dbus_message_iter_next(ifaces);
1061 modem_removed(path);
1064 static void modem_added(const char *path, DBusMessageIter *properties)
1066 if (modem_obj_path != NULL) {
1067 DBG("Ignoring, modem already exist");
1073 while (dbus_message_iter_get_arg_type(properties)
1074 == DBUS_TYPE_DICT_ENTRY) {
1076 DBusMessageIter interfaces, value, entry;
1078 dbus_message_iter_recurse(properties, &entry);
1079 dbus_message_iter_get_basic(&entry, &key);
1081 dbus_message_iter_next(&entry);
1082 dbus_message_iter_recurse(&entry, &value);
1084 if (strcasecmp(key, "Interfaces") != 0)
1087 if (dbus_message_iter_get_arg_type(&value)
1088 != DBUS_TYPE_ARRAY) {
1089 error("Invalid Signature");
1093 dbus_message_iter_recurse(&value, &interfaces);
1095 parse_modem_interfaces(path, &interfaces);
1097 if (modem_obj_path != NULL)
1101 dbus_message_iter_next(properties);
1105 static void get_modems_reply(DBusPendingCall *call, void *user_data)
1109 DBusMessageIter iter, entry;
1112 reply = dbus_pending_call_steal_reply(call);
1114 dbus_error_init(&err);
1115 if (dbus_set_error_from_message(&err, reply)) {
1116 error("ofono replied with an error: %s, %s",
1117 err.name, err.message);
1118 dbus_error_free(&err);
1122 /* Skip modem selection if a modem already exist */
1123 if (modem_obj_path != NULL)
1126 dbus_message_iter_init(reply, &iter);
1128 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1129 error("Unexpected signature");
1133 dbus_message_iter_recurse(&iter, &entry);
1135 while (dbus_message_iter_get_arg_type(&entry)
1136 == DBUS_TYPE_STRUCT) {
1138 DBusMessageIter item, properties;
1140 dbus_message_iter_recurse(&entry, &item);
1141 dbus_message_iter_get_basic(&item, &path);
1143 dbus_message_iter_next(&item);
1144 dbus_message_iter_recurse(&item, &properties);
1146 modem_added(path, &properties);
1147 if (modem_obj_path != NULL)
1150 dbus_message_iter_next(&entry);
1154 dbus_message_unref(reply);
1155 remove_pending(call);
1158 static gboolean handle_network_property_changed(DBusConnection *conn,
1159 DBusMessage *msg, void *data)
1161 DBusMessageIter iter, variant;
1162 const char *property;
1164 dbus_message_iter_init(msg, &iter);
1166 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
1167 error("Unexpected signature in networkregistration"
1168 " PropertyChanged signal");
1171 dbus_message_iter_get_basic(&iter, &property);
1172 DBG("in handle_registration_property_changed(),"
1173 " the property is %s", property);
1175 dbus_message_iter_next(&iter);
1176 dbus_message_iter_recurse(&iter, &variant);
1178 handle_network_property(property, &variant);
1183 static void handle_modem_property(const char *path, const char *property,
1184 DBusMessageIter *variant)
1186 DBG("%s", property);
1188 if (g_str_equal(property, "Interfaces")) {
1189 DBusMessageIter interfaces;
1191 if (dbus_message_iter_get_arg_type(variant)
1192 != DBUS_TYPE_ARRAY) {
1193 error("Invalid signature");
1197 dbus_message_iter_recurse(variant, &interfaces);
1198 parse_modem_interfaces(path, &interfaces);
1202 static gboolean handle_modem_property_changed(DBusConnection *conn,
1203 DBusMessage *msg, void *data)
1205 DBusMessageIter iter, variant;
1206 const char *property, *path;
1208 path = dbus_message_get_path(msg);
1210 /* Ignore if modem already exist and paths doesn't match */
1211 if (modem_obj_path != NULL &&
1212 g_str_equal(path, modem_obj_path) == FALSE)
1215 dbus_message_iter_init(msg, &iter);
1217 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
1218 error("Unexpected signature in %s.%s PropertyChanged signal",
1219 dbus_message_get_interface(msg),
1220 dbus_message_get_member(msg));
1224 dbus_message_iter_get_basic(&iter, &property);
1226 dbus_message_iter_next(&iter);
1227 dbus_message_iter_recurse(&iter, &variant);
1229 handle_modem_property(path, property, &variant);
1234 static gboolean handle_vcmanager_call_added(DBusConnection *conn,
1235 DBusMessage *msg, void *data)
1237 DBusMessageIter iter, properties;
1238 const char *path = dbus_message_get_path(msg);
1240 /* Ignore call if modem path doesn't math */
1241 if (g_strcmp0(modem_obj_path, path) != 0)
1244 dbus_message_iter_init(msg, &iter);
1246 if (dbus_message_iter_get_arg_type(&iter)
1247 != DBUS_TYPE_OBJECT_PATH) {
1248 error("Unexpected signature in %s.%s signal",
1249 dbus_message_get_interface(msg),
1250 dbus_message_get_member(msg));
1254 dbus_message_iter_get_basic(&iter, &path);
1255 dbus_message_iter_next(&iter);
1256 dbus_message_iter_recurse(&iter, &properties);
1258 call_added(path, &properties);
1263 static void call_removed(const char *path)
1265 struct voice_call *vc;
1273 calls = g_slist_remove(calls, vc);
1277 static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
1278 DBusMessage *msg, void *data)
1280 const char *path = dbus_message_get_path(msg);
1282 /* Ignore call if modem path doesn't math */
1283 if (g_strcmp0(modem_obj_path, path) != 0)
1286 if (!dbus_message_get_args(msg, NULL,
1287 DBUS_TYPE_OBJECT_PATH, &path,
1288 DBUS_TYPE_INVALID)) {
1289 error("Unexpected signature in %s.%s signal",
1290 dbus_message_get_interface(msg),
1291 dbus_message_get_member(msg));
1300 static gboolean handle_manager_modem_added(DBusConnection *conn,
1301 DBusMessage *msg, void *data)
1303 DBusMessageIter iter, properties;
1306 if (modem_obj_path != NULL)
1309 dbus_message_iter_init(msg, &iter);
1311 if (dbus_message_iter_get_arg_type(&iter)
1312 != DBUS_TYPE_OBJECT_PATH) {
1313 error("Unexpected signature in %s.%s signal",
1314 dbus_message_get_interface(msg),
1315 dbus_message_get_member(msg));
1319 dbus_message_iter_get_basic(&iter, &path);
1320 dbus_message_iter_next(&iter);
1321 dbus_message_iter_recurse(&iter, &properties);
1323 modem_added(path, &properties);
1328 static gboolean handle_manager_modem_removed(DBusConnection *conn,
1329 DBusMessage *msg, void *data)
1333 if (!dbus_message_get_args(msg, NULL,
1334 DBUS_TYPE_OBJECT_PATH, &path,
1335 DBUS_TYPE_INVALID)) {
1336 error("Unexpected signature in %s.%s signal",
1337 dbus_message_get_interface(msg),
1338 dbus_message_get_member(msg));
1342 modem_removed(path);
1347 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
1352 int *value = user_data;
1354 reply = dbus_pending_call_steal_reply(call);
1356 dbus_error_init(&err);
1357 if (dbus_set_error_from_message(&err, reply)) {
1358 error("hald replied with an error: %s, %s",
1359 err.name, err.message);
1360 dbus_error_free(&err);
1364 dbus_error_init(&err);
1365 if (dbus_message_get_args(reply, &err,
1366 DBUS_TYPE_INT32, &level,
1367 DBUS_TYPE_INVALID) == FALSE) {
1368 error("Unable to parse GetPropertyInteger reply: %s, %s",
1369 err.name, err.message);
1370 dbus_error_free(&err);
1374 *value = (int) level;
1376 if (value == &battchg_last)
1377 DBG("telephony-ofono: battery.charge_level.last_full"
1379 else if (value == &battchg_design)
1380 DBG("telephony-ofono: battery.charge_level.design"
1383 DBG("telephony-ofono: battery.charge_level.current"
1386 if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
1389 if (battchg_last > 0)
1392 max = battchg_design;
1394 new = battchg_cur * 5 / max;
1396 telephony_update_indicator(ofono_indicators, "battchg", new);
1399 dbus_message_unref(reply);
1400 remove_pending(call);
1403 static void hal_get_integer(const char *path, const char *key, void *user_data)
1405 send_method_call("org.freedesktop.Hal", path,
1406 "org.freedesktop.Hal.Device",
1407 "GetPropertyInteger",
1408 hal_battery_level_reply, user_data,
1409 DBUS_TYPE_STRING, &key,
1413 static gboolean handle_hal_property_modified(DBusConnection *conn,
1414 DBusMessage *msg, void *data)
1417 DBusMessageIter iter, array;
1418 dbus_int32_t num_changes;
1420 path = dbus_message_get_path(msg);
1422 dbus_message_iter_init(msg, &iter);
1424 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
1425 error("Unexpected signature in hal PropertyModified signal");
1429 dbus_message_iter_get_basic(&iter, &num_changes);
1430 dbus_message_iter_next(&iter);
1432 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1433 error("Unexpected signature in hal PropertyModified signal");
1437 dbus_message_iter_recurse(&iter, &array);
1439 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1440 DBusMessageIter prop;
1442 dbus_bool_t added, removed;
1444 dbus_message_iter_recurse(&array, &prop);
1446 if (!iter_get_basic_args(&prop,
1447 DBUS_TYPE_STRING, &name,
1448 DBUS_TYPE_BOOLEAN, &added,
1449 DBUS_TYPE_BOOLEAN, &removed,
1450 DBUS_TYPE_INVALID)) {
1451 error("Invalid hal PropertyModified parameters");
1455 if (g_str_equal(name, "battery.charge_level.last_full"))
1456 hal_get_integer(path, name, &battchg_last);
1457 else if (g_str_equal(name, "battery.charge_level.current"))
1458 hal_get_integer(path, name, &battchg_cur);
1459 else if (g_str_equal(name, "battery.charge_level.design"))
1460 hal_get_integer(path, name, &battchg_design);
1462 dbus_message_iter_next(&array);
1468 static void add_watch(const char *sender, const char *path,
1469 const char *interface, const char *member,
1470 GDBusSignalFunction function)
1474 watch = g_dbus_add_signal_watch(connection, sender, path, interface,
1475 member, function, NULL, NULL);
1477 watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1480 static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
1484 DBusMessageIter iter, sub;
1488 DBG("begin of hal_find_device_reply()");
1489 reply = dbus_pending_call_steal_reply(call);
1491 dbus_error_init(&err);
1493 if (dbus_set_error_from_message(&err, reply)) {
1494 error("hald replied with an error: %s, %s",
1495 err.name, err.message);
1496 dbus_error_free(&err);
1500 dbus_message_iter_init(reply, &iter);
1502 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1503 error("Unexpected signature in hal_find_device_reply()");
1507 dbus_message_iter_recurse(&iter, &sub);
1509 type = dbus_message_iter_get_arg_type(&sub);
1511 if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
1512 error("No hal device with battery capability found");
1516 dbus_message_iter_get_basic(&sub, &path);
1518 DBG("telephony-ofono: found battery device at %s", path);
1520 add_watch(NULL, path, "org.freedesktop.Hal.Device",
1521 "PropertyModified", handle_hal_property_modified);
1523 hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
1524 hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
1525 hal_get_integer(path, "battery.charge_level.design", &battchg_design);
1527 dbus_message_unref(reply);
1528 remove_pending(call);
1531 static void handle_service_connect(DBusConnection *conn, void *user_data)
1533 DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
1535 send_method_call(OFONO_BUS_NAME, OFONO_PATH,
1536 OFONO_MANAGER_INTERFACE, "GetModems",
1537 get_modems_reply, NULL, DBUS_TYPE_INVALID);
1540 static void handle_service_disconnect(DBusConnection *conn, void *user_data)
1542 DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
1545 modem_removed(modem_obj_path);
1548 int telephony_init(void)
1550 uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1551 AG_FEATURE_INBAND_RINGTONE |
1552 AG_FEATURE_REJECT_A_CALL |
1553 AG_FEATURE_ENHANCED_CALL_STATUS |
1554 AG_FEATURE_ENHANCED_CALL_CONTROL |
1555 AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
1556 AG_FEATURE_THREE_WAY_CALLING;
1557 const char *battery_cap = "battery";
1561 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1563 add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE,
1564 "PropertyChanged", handle_modem_property_changed);
1565 add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
1566 "PropertyChanged", handle_network_property_changed);
1567 add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
1568 "ModemAdded", handle_manager_modem_added);
1569 add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
1570 "ModemRemoved", handle_manager_modem_removed);
1571 add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
1572 "CallAdded", handle_vcmanager_call_added);
1573 add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
1574 "CallRemoved", handle_vcmanager_call_removed);
1576 watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
1577 handle_service_connect,
1578 handle_service_disconnect,
1583 watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1585 ret = send_method_call("org.freedesktop.Hal",
1586 "/org/freedesktop/Hal/Manager",
1587 "org.freedesktop.Hal.Manager",
1588 "FindDeviceByCapability",
1589 hal_find_device_reply, NULL,
1590 DBUS_TYPE_STRING, &battery_cap,
1595 DBG("telephony_init() successfully");
1597 telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
1603 static void remove_watch(gpointer data)
1605 g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
1608 static void pending_free(void *data)
1610 DBusPendingCall *call = data;
1612 if (!dbus_pending_call_get_completed(call))
1613 dbus_pending_call_cancel(call);
1615 dbus_pending_call_unref(call);
1618 void telephony_exit(void)
1622 g_free(last_dialed_number);
1623 last_dialed_number = NULL;
1626 modem_removed(modem_obj_path);
1628 g_slist_free_full(watches, remove_watch);
1631 g_slist_free_full(pending, pending_free);
1634 dbus_connection_unref(connection);