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>
41 #include "telephony.h"
43 enum net_registration_status {
44 NETWORK_REG_STATUS_HOME = 0x00,
45 NETWORK_REG_STATUS_ROAM,
46 NETWORK_REG_STATUS_NOSERV
58 static DBusConnection *connection = NULL;
59 static char *modem_obj_path = NULL;
60 static char *last_dialed_number = NULL;
61 static GSList *calls = NULL;
62 static GSList *watches = NULL;
63 static GSList *pending = NULL;
65 #define OFONO_BUS_NAME "org.ofono"
66 #define OFONO_PATH "/"
67 #define OFONO_MODEM_INTERFACE "org.ofono.Modem"
68 #define OFONO_MANAGER_INTERFACE "org.ofono.Manager"
69 #define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration"
70 #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
71 #define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
73 /* HAL battery namespace key values */
74 static int battchg_cur = -1; /* "battery.charge_level.current" */
75 static int battchg_last = -1; /* "battery.charge_level.last_full" */
76 static int battchg_design = -1; /* "battery.charge_level.design" */
83 .status = NETWORK_REG_STATUS_NOSERV,
85 .operator_name = NULL,
88 static const char *chld_str = "0,1,1x,2,2x,3,4";
89 static char *subscriber_number = NULL;
91 static gboolean events_enabled = FALSE;
93 static struct indicator ofono_indicators[] =
95 { "battchg", "0-5", 5, TRUE },
96 { "signal", "0-5", 5, TRUE },
97 { "service", "0,1", 1, TRUE },
98 { "call", "0,1", 0, TRUE },
99 { "callsetup", "0-3", 0, TRUE },
100 { "callheld", "0-2", 0, FALSE },
101 { "roam", "0,1", 0, TRUE },
105 static struct voice_call *find_vc(const char *path)
109 for (l = calls; l != NULL; l = l->next) {
110 struct voice_call *vc = l->data;
112 if (g_str_equal(vc->obj_path, path))
119 static struct voice_call *find_vc_with_status(int status)
123 for (l = calls; l != NULL; l = l->next) {
124 struct voice_call *vc = l->data;
126 if (vc->status == status)
133 static struct voice_call *find_vc_without_status(int status)
137 for (l = calls; l != NULL; l = l->next) {
138 struct voice_call *call = l->data;
140 if (call->status != status)
147 static int number_type(const char *number)
150 return NUMBER_TYPE_TELEPHONY;
152 if (number[0] == '+' || strncmp(number, "00", 2) == 0)
153 return NUMBER_TYPE_INTERNATIONAL;
155 return NUMBER_TYPE_TELEPHONY;
158 void telephony_device_connected(void *telephony_device)
160 struct voice_call *coming;
162 DBG("telephony-ofono: device %p connected", telephony_device);
164 coming = find_vc_with_status(CALL_STATUS_ALERTING);
166 if (find_vc_with_status(CALL_STATUS_ACTIVE))
167 telephony_call_waiting_ind(coming->number,
168 number_type(coming->number));
170 telephony_incoming_call_ind(coming->number,
171 number_type(coming->number));
175 void telephony_device_disconnected(void *telephony_device)
177 DBG("telephony-ofono: device %p disconnected", telephony_device);
178 events_enabled = FALSE;
181 void telephony_event_reporting_req(void *telephony_device, int ind)
183 events_enabled = ind == 1 ? TRUE : FALSE;
185 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
188 void telephony_response_and_hold_req(void *telephony_device, int rh)
190 telephony_response_and_hold_rsp(telephony_device,
191 CME_ERROR_NOT_SUPPORTED);
194 void telephony_last_dialed_number_req(void *telephony_device)
196 DBG("telephony-ofono: last dialed number request");
198 if (last_dialed_number)
199 telephony_dial_number_req(telephony_device, last_dialed_number);
201 telephony_last_dialed_number_rsp(telephony_device,
202 CME_ERROR_NOT_ALLOWED);
205 static int send_method_call(const char *dest, const char *path,
206 const char *interface, const char *method,
207 DBusPendingCallNotifyFunction cb,
208 void *user_data, int type, ...)
211 DBusPendingCall *call;
214 msg = dbus_message_new_method_call(dest, path, interface, method);
216 error("Unable to allocate new D-Bus %s message", method);
220 va_start(args, type);
222 if (!dbus_message_append_args_valist(msg, type, args)) {
223 dbus_message_unref(msg);
231 g_dbus_send_message(connection, msg);
235 if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
236 error("Sending %s failed", method);
237 dbus_message_unref(msg);
241 dbus_pending_call_set_notify(call, cb, user_data, NULL);
242 pending = g_slist_prepend(pending, call);
243 dbus_message_unref(msg);
248 static int answer_call(struct voice_call *vc)
250 DBG("%s", vc->number);
251 return send_method_call(OFONO_BUS_NAME, vc->obj_path,
252 OFONO_VC_INTERFACE, "Answer",
253 NULL, NULL, DBUS_TYPE_INVALID);
256 static int release_call(struct voice_call *vc)
258 DBG("%s", vc->number);
259 return send_method_call(OFONO_BUS_NAME, vc->obj_path,
260 OFONO_VC_INTERFACE, "Hangup",
261 NULL, NULL, DBUS_TYPE_INVALID);
264 static int release_answer_calls(void)
267 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
268 OFONO_VCMANAGER_INTERFACE,
270 NULL, NULL, DBUS_TYPE_INVALID);
273 static int split_call(struct voice_call *call)
275 DBG("%s", call->number);
276 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
277 OFONO_VCMANAGER_INTERFACE,
280 DBUS_TYPE_OBJECT_PATH,
286 static int swap_calls(void)
289 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
290 OFONO_VCMANAGER_INTERFACE,
292 NULL, NULL, DBUS_TYPE_INVALID);
295 static int create_conference(void)
298 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
299 OFONO_VCMANAGER_INTERFACE,
301 NULL, NULL, DBUS_TYPE_INVALID);
304 static int release_conference(void)
307 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
308 OFONO_VCMANAGER_INTERFACE,
310 NULL, NULL, DBUS_TYPE_INVALID);
313 static int call_transfer(void)
316 return send_method_call(OFONO_BUS_NAME, modem_obj_path,
317 OFONO_VCMANAGER_INTERFACE,
319 NULL, NULL, DBUS_TYPE_INVALID);
322 void telephony_terminate_call_req(void *telephony_device)
324 struct voice_call *call;
325 struct voice_call *alerting;
328 call = find_vc_with_status(CALL_STATUS_ACTIVE);
333 error("No active call");
334 telephony_terminate_call_rsp(telephony_device,
335 CME_ERROR_NOT_ALLOWED);
339 alerting = find_vc_with_status(CALL_STATUS_ALERTING);
340 if (call->status == CALL_STATUS_HELD && alerting)
341 err = release_call(alerting);
342 else if (call->conference)
343 err = release_conference();
345 err = release_call(call);
348 telephony_terminate_call_rsp(telephony_device,
349 CME_ERROR_AG_FAILURE);
351 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
354 void telephony_answer_call_req(void *telephony_device)
356 struct voice_call *vc;
359 vc = find_vc_with_status(CALL_STATUS_INCOMING);
361 vc = find_vc_with_status(CALL_STATUS_ALERTING);
364 vc = find_vc_with_status(CALL_STATUS_WAITING);
367 telephony_answer_call_rsp(telephony_device,
368 CME_ERROR_NOT_ALLOWED);
372 ret = answer_call(vc);
374 telephony_answer_call_rsp(telephony_device,
375 CME_ERROR_AG_FAILURE);
379 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
382 void telephony_dial_number_req(void *telephony_device, const char *number)
387 DBG("telephony-ofono: dial request to %s", number);
389 if (!modem_obj_path) {
390 telephony_dial_number_rsp(telephony_device,
391 CME_ERROR_AG_FAILURE);
395 if (!strncmp(number, "*31#", 4)) {
398 } else if (!strncmp(number, "#31#", 4)) {
404 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
405 OFONO_VCMANAGER_INTERFACE,
407 DBUS_TYPE_STRING, &number,
408 DBUS_TYPE_STRING, &clir,
412 telephony_dial_number_rsp(telephony_device,
413 CME_ERROR_AG_FAILURE);
415 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
418 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
423 DBG("telephony-ofono: transmit dtmf: %c", tone);
425 if (!modem_obj_path) {
426 telephony_transmit_dtmf_rsp(telephony_device,
427 CME_ERROR_AG_FAILURE);
431 tone_string = g_strdup_printf("%c", tone);
432 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
433 OFONO_VCMANAGER_INTERFACE,
434 "SendTones", NULL, NULL,
435 DBUS_TYPE_STRING, &tone_string,
440 telephony_transmit_dtmf_rsp(telephony_device,
441 CME_ERROR_AG_FAILURE);
443 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
446 void telephony_subscriber_number_req(void *telephony_device)
448 DBG("telephony-ofono: subscriber number request");
450 if (subscriber_number)
451 telephony_subscriber_number_ind(subscriber_number,
452 NUMBER_TYPE_TELEPHONY,
453 SUBSCRIBER_SERVICE_VOICE);
454 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
457 void telephony_list_current_calls_req(void *telephony_device)
462 DBG("telephony-ofono: list current calls request");
464 for (l = calls, i = 1; l != NULL; l = l->next, i++) {
465 struct voice_call *vc = l->data;
466 int direction, multiparty;
468 direction = vc->originating ?
469 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
471 multiparty = vc->conference ?
472 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
474 DBG("call %s direction %d multiparty %d", vc->number,
475 direction, multiparty);
477 telephony_list_current_call_ind(i, direction, vc->status,
478 CALL_MODE_VOICE, multiparty,
479 vc->number, number_type(vc->number));
482 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
485 void telephony_operator_selection_req(void *telephony_device)
487 DBG("telephony-ofono: operator selection request");
489 telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
490 net.operator_name ? net.operator_name : "");
491 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
494 static void foreach_vc_with_status(int status,
495 int (*func)(struct voice_call *vc))
499 for (l = calls; l != NULL; l = l->next) {
500 struct voice_call *call = l->data;
502 if (call->status == status)
507 void telephony_call_hold_req(void *telephony_device, const char *cmd)
510 struct voice_call *call;
513 DBG("telephony-ofono: got call hold request %s", cmd);
521 call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
527 if (find_vc_with_status(CALL_STATUS_WAITING))
528 foreach_vc_with_status(CALL_STATUS_WAITING,
531 foreach_vc_with_status(CALL_STATUS_HELD, release_call);
536 err = release_call(call);
539 err = release_answer_calls();
544 err = split_call(call);
546 call = find_vc_with_status(CALL_STATUS_WAITING);
549 err = answer_call(call);
555 if (find_vc_with_status(CALL_STATUS_HELD) ||
556 find_vc_with_status(CALL_STATUS_WAITING))
557 err = create_conference();
560 err = call_transfer();
563 DBG("Unknown call hold request");
568 telephony_call_hold_rsp(telephony_device,
569 CME_ERROR_AG_FAILURE);
571 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
574 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
576 DBG("telephony-ofono: got %s NR and EC request",
577 enable ? "enable" : "disable");
579 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
582 void telephony_key_press_req(void *telephony_device, const char *keys)
584 struct voice_call *active, *incoming;
587 DBG("telephony-ofono: got key press request for %s", keys);
589 incoming = find_vc_with_status(CALL_STATUS_INCOMING);
591 active = find_vc_with_status(CALL_STATUS_ACTIVE);
594 err = answer_call(incoming);
596 err = release_call(active);
601 telephony_key_press_rsp(telephony_device,
602 CME_ERROR_AG_FAILURE);
604 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
607 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
609 DBG("telephony-ofono: got %s voice dial request",
610 enable ? "enable" : "disable");
612 telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
615 static gboolean iter_get_basic_args(DBusMessageIter *iter,
616 int first_arg_type, ...)
621 va_start(ap, first_arg_type);
623 for (type = first_arg_type; type != DBUS_TYPE_INVALID;
624 type = va_arg(ap, int)) {
625 void *value = va_arg(ap, void *);
626 int real_type = dbus_message_iter_get_arg_type(iter);
628 if (real_type != type) {
629 error("iter_get_basic_args: expected %c but got %c",
630 (char) type, (char) real_type);
634 dbus_message_iter_get_basic(iter, value);
635 dbus_message_iter_next(iter);
640 return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
643 static void call_free(void *data)
645 struct voice_call *vc = data;
647 DBG("%s", vc->obj_path);
649 if (vc->status == CALL_STATUS_ACTIVE)
650 telephony_update_indicator(ofono_indicators, "call",
653 telephony_update_indicator(ofono_indicators, "callsetup",
654 EV_CALLSETUP_INACTIVE);
656 if (vc->status == CALL_STATUS_INCOMING)
657 telephony_calling_stopped_ind();
659 g_dbus_remove_watch(connection, vc->watch);
660 g_free(vc->obj_path);
665 static gboolean handle_vc_property_changed(DBusConnection *conn,
666 DBusMessage *msg, void *data)
668 struct voice_call *vc = data;
669 const char *obj_path = dbus_message_get_path(msg);
670 DBusMessageIter iter, sub;
671 const char *property, *state;
673 DBG("path %s", obj_path);
675 dbus_message_iter_init(msg, &iter);
677 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
678 error("Unexpected signature in vc PropertyChanged signal");
682 dbus_message_iter_get_basic(&iter, &property);
683 DBG("property %s", property);
685 dbus_message_iter_next(&iter);
686 dbus_message_iter_recurse(&iter, &sub);
687 if (g_str_equal(property, "State")) {
688 dbus_message_iter_get_basic(&sub, &state);
689 DBG("State %s", state);
690 if (g_str_equal(state, "disconnected")) {
691 calls = g_slist_remove(calls, vc);
693 } else if (g_str_equal(state, "active")) {
694 telephony_update_indicator(ofono_indicators,
695 "call", EV_CALL_ACTIVE);
696 telephony_update_indicator(ofono_indicators,
698 EV_CALLSETUP_INACTIVE);
699 if (vc->status == CALL_STATUS_INCOMING)
700 telephony_calling_stopped_ind();
701 vc->status = CALL_STATUS_ACTIVE;
702 } else if (g_str_equal(state, "alerting")) {
703 telephony_update_indicator(ofono_indicators,
704 "callsetup", EV_CALLSETUP_ALERTING);
705 vc->status = CALL_STATUS_ALERTING;
706 vc->originating = TRUE;
707 } else if (g_str_equal(state, "incoming")) {
708 /* state change from waiting to incoming */
709 telephony_update_indicator(ofono_indicators,
710 "callsetup", EV_CALLSETUP_INCOMING);
711 telephony_incoming_call_ind(vc->number,
712 NUMBER_TYPE_TELEPHONY);
713 vc->status = CALL_STATUS_INCOMING;
714 vc->originating = FALSE;
715 } else if (g_str_equal(state, "held")) {
716 vc->status = CALL_STATUS_HELD;
717 if (find_vc_without_status(CALL_STATUS_HELD))
718 telephony_update_indicator(ofono_indicators,
720 EV_CALLHELD_MULTIPLE);
722 telephony_update_indicator(ofono_indicators,
724 EV_CALLHELD_ON_HOLD);
726 } else if (g_str_equal(property, "Multiparty")) {
727 dbus_bool_t multiparty;
729 dbus_message_iter_get_basic(&sub, &multiparty);
730 DBG("Multiparty %s", multiparty ? "True" : "False");
731 vc->conference = multiparty;
737 static struct voice_call *call_new(const char *path, DBusMessageIter *properties)
739 struct voice_call *vc;
743 vc = g_new0(struct voice_call, 1);
744 vc->obj_path = g_strdup(path);
745 vc->watch = g_dbus_add_signal_watch(connection, NULL, path,
746 OFONO_VC_INTERFACE, "PropertyChanged",
747 handle_vc_property_changed, vc, NULL);
749 while (dbus_message_iter_get_arg_type(properties)
750 == DBUS_TYPE_DICT_ENTRY) {
751 DBusMessageIter entry, value;
752 const char *property, *cli, *state;
753 dbus_bool_t multiparty;
755 dbus_message_iter_recurse(properties, &entry);
756 dbus_message_iter_get_basic(&entry, &property);
758 dbus_message_iter_next(&entry);
759 dbus_message_iter_recurse(&entry, &value);
761 if (g_str_equal(property, "LineIdentification")) {
762 dbus_message_iter_get_basic(&value, &cli);
764 vc->number = g_strdup(cli);
765 } else if (g_str_equal(property, "State")) {
766 dbus_message_iter_get_basic(&value, &state);
767 DBG("state %s", state);
768 if (g_str_equal(state, "incoming"))
769 vc->status = CALL_STATUS_INCOMING;
770 else if (g_str_equal(state, "dialing"))
771 vc->status = CALL_STATUS_DIALING;
772 else if (g_str_equal(state, "alerting"))
773 vc->status = CALL_STATUS_ALERTING;
774 else if (g_str_equal(state, "waiting"))
775 vc->status = CALL_STATUS_WAITING;
776 else if (g_str_equal(state, "held"))
777 vc->status = CALL_STATUS_HELD;
778 } else if (g_str_equal(property, "Multiparty")) {
779 dbus_message_iter_get_basic(&value, &multiparty);
780 DBG("Multipary %s", multiparty ? "True" : "False");
781 vc->conference = multiparty;
784 dbus_message_iter_next(properties);
787 switch (vc->status) {
788 case CALL_STATUS_INCOMING:
789 DBG("CALL_STATUS_INCOMING");
790 vc->originating = FALSE;
791 telephony_update_indicator(ofono_indicators, "callsetup",
792 EV_CALLSETUP_INCOMING);
793 telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
795 case CALL_STATUS_DIALING:
796 DBG("CALL_STATUS_DIALING");
797 vc->originating = TRUE;
798 g_free(last_dialed_number);
799 last_dialed_number = g_strdup(vc->number);
800 telephony_update_indicator(ofono_indicators, "callsetup",
801 EV_CALLSETUP_OUTGOING);
803 case CALL_STATUS_ALERTING:
804 DBG("CALL_STATUS_ALERTING");
805 vc->originating = TRUE;
806 g_free(last_dialed_number);
807 last_dialed_number = g_strdup(vc->number);
808 telephony_update_indicator(ofono_indicators, "callsetup",
809 EV_CALLSETUP_ALERTING);
811 case CALL_STATUS_WAITING:
812 DBG("CALL_STATUS_WAITING");
813 vc->originating = FALSE;
814 telephony_update_indicator(ofono_indicators, "callsetup",
815 EV_CALLSETUP_INCOMING);
816 telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
823 static void remove_pending(DBusPendingCall *call)
825 pending = g_slist_remove(pending, call);
826 dbus_pending_call_unref(call);
829 static void call_added(const char *path, DBusMessageIter *properties)
831 struct voice_call *vc;
839 vc = call_new(path, properties);
840 calls = g_slist_prepend(calls, vc);
843 static void get_calls_reply(DBusPendingCall *call, void *user_data)
847 DBusMessageIter iter, entry;
850 reply = dbus_pending_call_steal_reply(call);
852 dbus_error_init(&err);
853 if (dbus_set_error_from_message(&err, reply)) {
854 error("ofono replied with an error: %s, %s",
855 err.name, err.message);
856 dbus_error_free(&err);
860 dbus_message_iter_init(reply, &iter);
862 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
863 error("Unexpected signature");
867 dbus_message_iter_recurse(&iter, &entry);
869 while (dbus_message_iter_get_arg_type(&entry)
870 == DBUS_TYPE_STRUCT) {
872 DBusMessageIter value, properties;
874 dbus_message_iter_recurse(&entry, &value);
875 dbus_message_iter_get_basic(&value, &path);
877 dbus_message_iter_next(&value);
878 dbus_message_iter_recurse(&value, &properties);
880 call_added(path, &properties);
882 dbus_message_iter_next(&entry);
886 dbus_message_unref(reply);
887 remove_pending(call);
890 static void handle_network_property(const char *property, DBusMessageIter *variant)
892 const char *status, *operator;
893 unsigned int signals_bar;
895 if (g_str_equal(property, "Status")) {
896 dbus_message_iter_get_basic(variant, &status);
897 DBG("Status is %s", status);
898 if (g_str_equal(status, "registered")) {
899 net.status = NETWORK_REG_STATUS_HOME;
900 telephony_update_indicator(ofono_indicators,
901 "roam", EV_ROAM_INACTIVE);
902 telephony_update_indicator(ofono_indicators,
903 "service", EV_SERVICE_PRESENT);
904 } else if (g_str_equal(status, "roaming")) {
905 net.status = NETWORK_REG_STATUS_ROAM;
906 telephony_update_indicator(ofono_indicators,
907 "roam", EV_ROAM_ACTIVE);
908 telephony_update_indicator(ofono_indicators,
909 "service", EV_SERVICE_PRESENT);
911 net.status = NETWORK_REG_STATUS_NOSERV;
912 telephony_update_indicator(ofono_indicators,
913 "roam", EV_ROAM_INACTIVE);
914 telephony_update_indicator(ofono_indicators,
915 "service", EV_SERVICE_NONE);
917 } else if (g_str_equal(property, "Name")) {
918 dbus_message_iter_get_basic(variant, &operator);
919 DBG("Operator is %s", operator);
920 g_free(net.operator_name);
921 net.operator_name = g_strdup(operator);
922 } else if (g_str_equal(property, "SignalStrength")) {
923 dbus_message_iter_get_basic(variant, &signals_bar);
924 DBG("SignalStrength is %d", signals_bar);
925 net.signals_bar = signals_bar;
926 telephony_update_indicator(ofono_indicators, "signal",
927 (signals_bar + 20) / 21);
931 static int parse_network_properties(DBusMessageIter *properties)
935 /* Reset indicators */
936 for (i = 0; ofono_indicators[i].desc != NULL; i++) {
937 if (g_str_equal(ofono_indicators[i].desc, "battchg"))
938 ofono_indicators[i].val = 5;
940 ofono_indicators[i].val = 0;
943 while (dbus_message_iter_get_arg_type(properties)
944 == DBUS_TYPE_DICT_ENTRY) {
946 DBusMessageIter value, entry;
948 dbus_message_iter_recurse(properties, &entry);
949 dbus_message_iter_get_basic(&entry, &key);
951 dbus_message_iter_next(&entry);
952 dbus_message_iter_recurse(&entry, &value);
954 handle_network_property(key, &value);
956 dbus_message_iter_next(properties);
962 static void get_properties_reply(DBusPendingCall *call, void *user_data)
966 DBusMessageIter iter, properties;
970 reply = dbus_pending_call_steal_reply(call);
972 dbus_error_init(&err);
973 if (dbus_set_error_from_message(&err, reply)) {
974 error("ofono replied with an error: %s, %s",
975 err.name, err.message);
976 dbus_error_free(&err);
980 dbus_message_iter_init(reply, &iter);
982 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
983 error("Unexpected signature");
987 dbus_message_iter_recurse(&iter, &properties);
989 ret = parse_network_properties(&properties);
991 error("Unable to parse %s.GetProperty reply",
992 OFONO_NETWORKREG_INTERFACE);
996 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
997 OFONO_VCMANAGER_INTERFACE, "GetCalls",
998 get_calls_reply, NULL, DBUS_TYPE_INVALID);
1000 error("Unable to send %s.GetCalls",
1001 OFONO_VCMANAGER_INTERFACE);
1004 dbus_message_unref(reply);
1005 remove_pending(call);
1008 static void network_found(const char *path)
1014 modem_obj_path = g_strdup(path);
1016 ret = send_method_call(OFONO_BUS_NAME, path,
1017 OFONO_NETWORKREG_INTERFACE, "GetProperties",
1018 get_properties_reply, NULL, DBUS_TYPE_INVALID);
1020 error("Unable to send %s.GetProperties",
1021 OFONO_NETWORKREG_INTERFACE);
1024 static void modem_removed(const char *path)
1026 if (g_strcmp0(modem_obj_path, path) != 0)
1031 g_slist_free_full(calls, call_free);
1034 g_free(net.operator_name);
1035 net.operator_name = NULL;
1036 net.status = NETWORK_REG_STATUS_NOSERV;
1037 net.signals_bar = 0;
1039 g_free(modem_obj_path);
1040 modem_obj_path = NULL;
1043 static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces)
1047 while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) {
1050 dbus_message_iter_get_basic(ifaces, &iface);
1052 if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) {
1053 network_found(path);
1057 dbus_message_iter_next(ifaces);
1060 modem_removed(path);
1063 static void modem_added(const char *path, DBusMessageIter *properties)
1065 if (modem_obj_path != NULL) {
1066 DBG("Ignoring, modem already exist");
1072 while (dbus_message_iter_get_arg_type(properties)
1073 == DBUS_TYPE_DICT_ENTRY) {
1075 DBusMessageIter interfaces, value, entry;
1077 dbus_message_iter_recurse(properties, &entry);
1078 dbus_message_iter_get_basic(&entry, &key);
1080 dbus_message_iter_next(&entry);
1081 dbus_message_iter_recurse(&entry, &value);
1083 if (strcasecmp(key, "Interfaces") != 0)
1086 if (dbus_message_iter_get_arg_type(&value)
1087 != DBUS_TYPE_ARRAY) {
1088 error("Invalid Signature");
1092 dbus_message_iter_recurse(&value, &interfaces);
1094 parse_modem_interfaces(path, &interfaces);
1096 if (modem_obj_path != NULL)
1100 dbus_message_iter_next(properties);
1104 static void get_modems_reply(DBusPendingCall *call, void *user_data)
1108 DBusMessageIter iter, entry;
1111 reply = dbus_pending_call_steal_reply(call);
1113 dbus_error_init(&err);
1114 if (dbus_set_error_from_message(&err, reply)) {
1115 error("ofono replied with an error: %s, %s",
1116 err.name, err.message);
1117 dbus_error_free(&err);
1121 /* Skip modem selection if a modem already exist */
1122 if (modem_obj_path != NULL)
1125 dbus_message_iter_init(reply, &iter);
1127 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1128 error("Unexpected signature");
1132 dbus_message_iter_recurse(&iter, &entry);
1134 while (dbus_message_iter_get_arg_type(&entry)
1135 == DBUS_TYPE_STRUCT) {
1137 DBusMessageIter item, properties;
1139 dbus_message_iter_recurse(&entry, &item);
1140 dbus_message_iter_get_basic(&item, &path);
1142 dbus_message_iter_next(&item);
1143 dbus_message_iter_recurse(&item, &properties);
1145 modem_added(path, &properties);
1146 if (modem_obj_path != NULL)
1149 dbus_message_iter_next(&entry);
1153 dbus_message_unref(reply);
1154 remove_pending(call);
1157 static gboolean handle_network_property_changed(DBusConnection *conn,
1158 DBusMessage *msg, void *data)
1160 DBusMessageIter iter, variant;
1161 const char *property;
1163 dbus_message_iter_init(msg, &iter);
1165 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
1166 error("Unexpected signature in networkregistration"
1167 " PropertyChanged signal");
1170 dbus_message_iter_get_basic(&iter, &property);
1171 DBG("in handle_registration_property_changed(),"
1172 " the property is %s", property);
1174 dbus_message_iter_next(&iter);
1175 dbus_message_iter_recurse(&iter, &variant);
1177 handle_network_property(property, &variant);
1182 static void handle_modem_property(const char *path, const char *property,
1183 DBusMessageIter *variant)
1185 DBG("%s", property);
1187 if (g_str_equal(property, "Interfaces")) {
1188 DBusMessageIter interfaces;
1190 if (dbus_message_iter_get_arg_type(variant)
1191 != DBUS_TYPE_ARRAY) {
1192 error("Invalid signature");
1196 dbus_message_iter_recurse(variant, &interfaces);
1197 parse_modem_interfaces(path, &interfaces);
1201 static gboolean handle_modem_property_changed(DBusConnection *conn,
1202 DBusMessage *msg, void *data)
1204 DBusMessageIter iter, variant;
1205 const char *property, *path;
1207 path = dbus_message_get_path(msg);
1209 /* Ignore if modem already exist and paths doesn't match */
1210 if (modem_obj_path != NULL &&
1211 g_str_equal(path, modem_obj_path) == FALSE)
1214 dbus_message_iter_init(msg, &iter);
1216 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
1217 error("Unexpected signature in %s.%s PropertyChanged signal",
1218 dbus_message_get_interface(msg),
1219 dbus_message_get_member(msg));
1223 dbus_message_iter_get_basic(&iter, &property);
1225 dbus_message_iter_next(&iter);
1226 dbus_message_iter_recurse(&iter, &variant);
1228 handle_modem_property(path, property, &variant);
1233 static gboolean handle_vcmanager_call_added(DBusConnection *conn,
1234 DBusMessage *msg, void *data)
1236 DBusMessageIter iter, properties;
1237 const char *path = dbus_message_get_path(msg);
1239 /* Ignore call if modem path doesn't math */
1240 if (g_strcmp0(modem_obj_path, path) != 0)
1243 dbus_message_iter_init(msg, &iter);
1245 if (dbus_message_iter_get_arg_type(&iter)
1246 != DBUS_TYPE_OBJECT_PATH) {
1247 error("Unexpected signature in %s.%s signal",
1248 dbus_message_get_interface(msg),
1249 dbus_message_get_member(msg));
1253 dbus_message_iter_get_basic(&iter, &path);
1254 dbus_message_iter_next(&iter);
1255 dbus_message_iter_recurse(&iter, &properties);
1257 call_added(path, &properties);
1262 static void call_removed(const char *path)
1264 struct voice_call *vc;
1272 calls = g_slist_remove(calls, vc);
1276 static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
1277 DBusMessage *msg, void *data)
1279 const char *path = dbus_message_get_path(msg);
1281 /* Ignore call if modem path doesn't math */
1282 if (g_strcmp0(modem_obj_path, path) != 0)
1285 if (!dbus_message_get_args(msg, NULL,
1286 DBUS_TYPE_OBJECT_PATH, &path,
1287 DBUS_TYPE_INVALID)) {
1288 error("Unexpected signature in %s.%s signal",
1289 dbus_message_get_interface(msg),
1290 dbus_message_get_member(msg));
1299 static gboolean handle_manager_modem_added(DBusConnection *conn,
1300 DBusMessage *msg, void *data)
1302 DBusMessageIter iter, properties;
1305 if (modem_obj_path != NULL)
1308 dbus_message_iter_init(msg, &iter);
1310 if (dbus_message_iter_get_arg_type(&iter)
1311 != DBUS_TYPE_OBJECT_PATH) {
1312 error("Unexpected signature in %s.%s signal",
1313 dbus_message_get_interface(msg),
1314 dbus_message_get_member(msg));
1318 dbus_message_iter_get_basic(&iter, &path);
1319 dbus_message_iter_next(&iter);
1320 dbus_message_iter_recurse(&iter, &properties);
1322 modem_added(path, &properties);
1327 static gboolean handle_manager_modem_removed(DBusConnection *conn,
1328 DBusMessage *msg, void *data)
1332 if (!dbus_message_get_args(msg, NULL,
1333 DBUS_TYPE_OBJECT_PATH, &path,
1334 DBUS_TYPE_INVALID)) {
1335 error("Unexpected signature in %s.%s signal",
1336 dbus_message_get_interface(msg),
1337 dbus_message_get_member(msg));
1341 modem_removed(path);
1346 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
1351 int *value = user_data;
1353 reply = dbus_pending_call_steal_reply(call);
1355 dbus_error_init(&err);
1356 if (dbus_set_error_from_message(&err, reply)) {
1357 error("hald replied with an error: %s, %s",
1358 err.name, err.message);
1359 dbus_error_free(&err);
1363 dbus_error_init(&err);
1364 if (dbus_message_get_args(reply, &err,
1365 DBUS_TYPE_INT32, &level,
1366 DBUS_TYPE_INVALID) == FALSE) {
1367 error("Unable to parse GetPropertyInteger reply: %s, %s",
1368 err.name, err.message);
1369 dbus_error_free(&err);
1373 *value = (int) level;
1375 if (value == &battchg_last)
1376 DBG("telephony-ofono: battery.charge_level.last_full"
1378 else if (value == &battchg_design)
1379 DBG("telephony-ofono: battery.charge_level.design"
1382 DBG("telephony-ofono: battery.charge_level.current"
1385 if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
1388 if (battchg_last > 0)
1391 max = battchg_design;
1393 new = battchg_cur * 5 / max;
1395 telephony_update_indicator(ofono_indicators, "battchg", new);
1398 dbus_message_unref(reply);
1399 remove_pending(call);
1402 static void hal_get_integer(const char *path, const char *key, void *user_data)
1404 send_method_call("org.freedesktop.Hal", path,
1405 "org.freedesktop.Hal.Device",
1406 "GetPropertyInteger",
1407 hal_battery_level_reply, user_data,
1408 DBUS_TYPE_STRING, &key,
1412 static gboolean handle_hal_property_modified(DBusConnection *conn,
1413 DBusMessage *msg, void *data)
1416 DBusMessageIter iter, array;
1417 dbus_int32_t num_changes;
1419 path = dbus_message_get_path(msg);
1421 dbus_message_iter_init(msg, &iter);
1423 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
1424 error("Unexpected signature in hal PropertyModified signal");
1428 dbus_message_iter_get_basic(&iter, &num_changes);
1429 dbus_message_iter_next(&iter);
1431 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1432 error("Unexpected signature in hal PropertyModified signal");
1436 dbus_message_iter_recurse(&iter, &array);
1438 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1439 DBusMessageIter prop;
1441 dbus_bool_t added, removed;
1443 dbus_message_iter_recurse(&array, &prop);
1445 if (!iter_get_basic_args(&prop,
1446 DBUS_TYPE_STRING, &name,
1447 DBUS_TYPE_BOOLEAN, &added,
1448 DBUS_TYPE_BOOLEAN, &removed,
1449 DBUS_TYPE_INVALID)) {
1450 error("Invalid hal PropertyModified parameters");
1454 if (g_str_equal(name, "battery.charge_level.last_full"))
1455 hal_get_integer(path, name, &battchg_last);
1456 else if (g_str_equal(name, "battery.charge_level.current"))
1457 hal_get_integer(path, name, &battchg_cur);
1458 else if (g_str_equal(name, "battery.charge_level.design"))
1459 hal_get_integer(path, name, &battchg_design);
1461 dbus_message_iter_next(&array);
1467 static void add_watch(const char *sender, const char *path,
1468 const char *interface, const char *member,
1469 GDBusSignalFunction function)
1473 watch = g_dbus_add_signal_watch(connection, sender, path, interface,
1474 member, function, NULL, NULL);
1476 watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1479 static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
1483 DBusMessageIter iter, sub;
1487 DBG("begin of hal_find_device_reply()");
1488 reply = dbus_pending_call_steal_reply(call);
1490 dbus_error_init(&err);
1492 if (dbus_set_error_from_message(&err, reply)) {
1493 error("hald replied with an error: %s, %s",
1494 err.name, err.message);
1495 dbus_error_free(&err);
1499 dbus_message_iter_init(reply, &iter);
1501 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1502 error("Unexpected signature in hal_find_device_reply()");
1506 dbus_message_iter_recurse(&iter, &sub);
1508 type = dbus_message_iter_get_arg_type(&sub);
1510 if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
1511 error("No hal device with battery capability found");
1515 dbus_message_iter_get_basic(&sub, &path);
1517 DBG("telephony-ofono: found battery device at %s", path);
1519 add_watch(NULL, path, "org.freedesktop.Hal.Device",
1520 "PropertyModified", handle_hal_property_modified);
1522 hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
1523 hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
1524 hal_get_integer(path, "battery.charge_level.design", &battchg_design);
1526 dbus_message_unref(reply);
1527 remove_pending(call);
1530 static void handle_service_connect(DBusConnection *conn, void *user_data)
1532 DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
1534 send_method_call(OFONO_BUS_NAME, OFONO_PATH,
1535 OFONO_MANAGER_INTERFACE, "GetModems",
1536 get_modems_reply, NULL, DBUS_TYPE_INVALID);
1539 static void handle_service_disconnect(DBusConnection *conn, void *user_data)
1541 DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
1544 modem_removed(modem_obj_path);
1547 int telephony_init(void)
1549 uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1550 AG_FEATURE_INBAND_RINGTONE |
1551 AG_FEATURE_REJECT_A_CALL |
1552 AG_FEATURE_ENHANCED_CALL_STATUS |
1553 AG_FEATURE_ENHANCED_CALL_CONTROL |
1554 AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
1555 AG_FEATURE_THREE_WAY_CALLING;
1556 const char *battery_cap = "battery";
1560 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1562 add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE,
1563 "PropertyChanged", handle_modem_property_changed);
1564 add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
1565 "PropertyChanged", handle_network_property_changed);
1566 add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
1567 "ModemAdded", handle_manager_modem_added);
1568 add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
1569 "ModemRemoved", handle_manager_modem_removed);
1570 add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
1571 "CallAdded", handle_vcmanager_call_added);
1572 add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
1573 "CallRemoved", handle_vcmanager_call_removed);
1575 watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
1576 handle_service_connect,
1577 handle_service_disconnect,
1582 watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1584 ret = send_method_call("org.freedesktop.Hal",
1585 "/org/freedesktop/Hal/Manager",
1586 "org.freedesktop.Hal.Manager",
1587 "FindDeviceByCapability",
1588 hal_find_device_reply, NULL,
1589 DBUS_TYPE_STRING, &battery_cap,
1594 DBG("telephony_init() successfully");
1596 telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
1602 static void remove_watch(gpointer data)
1604 g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
1607 static void pending_free(void *data)
1609 DBusPendingCall *call = data;
1611 if (!dbus_pending_call_get_completed(call))
1612 dbus_pending_call_cancel(call);
1614 dbus_pending_call_unref(call);
1617 void telephony_exit(void)
1621 g_free(last_dialed_number);
1622 last_dialed_number = NULL;
1625 modem_removed(modem_obj_path);
1627 g_slist_free_full(watches, remove_watch);
1630 g_slist_free_full(pending, pending_free);
1633 dbus_connection_unref(connection);