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
#if 0 /* Disable hal */
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);
1530
#endif /* Disable hal */
1532
static void handle_service_connect(DBusConnection *conn, void *user_data)
1534
DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
1536
send_method_call(OFONO_BUS_NAME, OFONO_PATH,
1537
OFONO_MANAGER_INTERFACE, "GetModems",
1538
get_modems_reply, NULL, DBUS_TYPE_INVALID);
1541
static void handle_service_disconnect(DBusConnection *conn, void *user_data)
1543
DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
1546
modem_removed(modem_obj_path);
1549
int telephony_init(void)
1551
uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1552
AG_FEATURE_INBAND_RINGTONE |
1553
AG_FEATURE_REJECT_A_CALL |
1554
AG_FEATURE_ENHANCED_CALL_STATUS |
1555
AG_FEATURE_ENHANCED_CALL_CONTROL |
1556
AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
1557
AG_FEATURE_THREE_WAY_CALLING;
1558
const char *battery_cap = "battery";
1562
connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1564
add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE,
1565
"PropertyChanged", handle_modem_property_changed);
1566
add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
1567
"PropertyChanged", handle_network_property_changed);
1568
add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
1569
"ModemAdded", handle_manager_modem_added);
1570
add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
1571
"ModemRemoved", handle_manager_modem_removed);
1572
add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
1573
"CallAdded", handle_vcmanager_call_added);
1574
add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
1575
"CallRemoved", handle_vcmanager_call_removed);
1577
watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
1578
handle_service_connect,
1579
handle_service_disconnect,
1584
watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1586
#if 0 /* Disable hal */
1587
ret = send_method_call("org.freedesktop.Hal",
1588
"/org/freedesktop/Hal/Manager",
1589
"org.freedesktop.Hal.Manager",
1590
"FindDeviceByCapability",
1591
hal_find_device_reply, NULL,
1592
DBUS_TYPE_STRING, &battery_cap,
1597
DBG("telephony_init() successfully");
1599
telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
1605
static void remove_watch(gpointer data)
1607
g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
1610
static void pending_free(void *data)
1612
DBusPendingCall *call = data;
1614
if (!dbus_pending_call_get_completed(call))
1615
dbus_pending_call_cancel(call);
1617
dbus_pending_call_unref(call);
1620
void telephony_exit(void)
1624
g_free(last_dialed_number);
1625
last_dialed_number = NULL;
1628
modem_removed(modem_obj_path);
1630
g_slist_free_full(watches, remove_watch);
1633
g_slist_free_full(pending, pending_free);
1636
dbus_connection_unref(connection);