Home | History | Annotate | Download | only in audio
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2009-2010  Intel Corporation
      6  *  Copyright (C) 2006-2009  Nokia Corporation
      7  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) holtmann.org>
      8  *
      9  *
     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.
     14  *
     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.
     19  *
     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
     23  *
     24  */
     25 
     26 #ifdef HAVE_CONFIG_H
     27 #include <config.h>
     28 #endif
     29 
     30 #include <stdlib.h>
     31 #include <stdio.h>
     32 #include <string.h>
     33 #include <stdint.h>
     34 #include <glib.h>
     35 #include <dbus/dbus.h>
     36 #include <gdbus.h>
     37 
     38 #include "log.h"
     39 #include "telephony.h"
     40 
     41 enum net_registration_status {
     42 	NETWORK_REG_STATUS_HOME = 0x00,
     43 	NETWORK_REG_STATUS_ROAM,
     44 	NETWORK_REG_STATUS_NOSERV
     45 };
     46 
     47 struct voice_call {
     48 	char *obj_path;
     49 	int status;
     50 	gboolean originating;
     51 	gboolean conference;
     52 	char *number;
     53 	guint watch;
     54 };
     55 
     56 static DBusConnection *connection = NULL;
     57 static char *modem_obj_path = NULL;
     58 static char *last_dialed_number = NULL;
     59 static GSList *calls = NULL;
     60 static GSList *watches = NULL;
     61 static GSList *pending = NULL;
     62 
     63 #define OFONO_BUS_NAME "org.ofono"
     64 #define OFONO_PATH "/"
     65 #define OFONO_MODEM_INTERFACE "org.ofono.Modem"
     66 #define OFONO_MANAGER_INTERFACE "org.ofono.Manager"
     67 #define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration"
     68 #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
     69 #define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
     70 
     71 /* HAL battery namespace key values */
     72 static int battchg_cur = -1;    /* "battery.charge_level.current" */
     73 static int battchg_last = -1;   /* "battery.charge_level.last_full" */
     74 static int battchg_design = -1; /* "battery.charge_level.design" */
     75 
     76 static struct {
     77 	uint8_t status;
     78 	uint32_t signals_bar;
     79 	char *operator_name;
     80 } net = {
     81 	.status = NETWORK_REG_STATUS_NOSERV,
     82 	.signals_bar = 0,
     83 	.operator_name = NULL,
     84 };
     85 
     86 static const char *chld_str = "0,1,1x,2,2x,3,4";
     87 static char *subscriber_number = NULL;
     88 
     89 static gboolean events_enabled = FALSE;
     90 
     91 static struct indicator ofono_indicators[] =
     92 {
     93 	{ "battchg",	"0-5",	5,	TRUE },
     94 	{ "signal",	"0-5",	5,	TRUE },
     95 	{ "service",	"0,1",	1,	TRUE },
     96 	{ "call",	"0,1",	0,	TRUE },
     97 	{ "callsetup",	"0-3",	0,	TRUE },
     98 	{ "callheld",	"0-2",	0,	FALSE },
     99 	{ "roam",	"0,1",	0,	TRUE },
    100 	{ NULL }
    101 };
    102 
    103 static struct voice_call *find_vc(const char *path)
    104 {
    105 	GSList *l;
    106 
    107 	for (l = calls; l != NULL; l = l->next) {
    108 		struct voice_call *vc = l->data;
    109 
    110 		if (g_str_equal(vc->obj_path, path))
    111 			return vc;
    112 	}
    113 
    114 	return NULL;
    115 }
    116 
    117 static struct voice_call *find_vc_with_status(int status)
    118 {
    119 	GSList *l;
    120 
    121 	for (l = calls; l != NULL; l = l->next) {
    122 		struct voice_call *vc = l->data;
    123 
    124 		if (vc->status == status)
    125 			return vc;
    126 	}
    127 
    128 	return NULL;
    129 }
    130 
    131 static struct voice_call *find_vc_without_status(int status)
    132 {
    133 	GSList *l;
    134 
    135 	for (l = calls; l != NULL; l = l->next) {
    136 		struct voice_call *call = l->data;
    137 
    138 		if (call->status != status)
    139 			return call;
    140 	}
    141 
    142 	return NULL;
    143 }
    144 
    145 static int number_type(const char *number)
    146 {
    147 	if (number == NULL)
    148 		return NUMBER_TYPE_TELEPHONY;
    149 
    150 	if (number[0] == '+' || strncmp(number, "00", 2) == 0)
    151 		return NUMBER_TYPE_INTERNATIONAL;
    152 
    153 	return NUMBER_TYPE_TELEPHONY;
    154 }
    155 
    156 void telephony_device_connected(void *telephony_device)
    157 {
    158 	struct voice_call *coming;
    159 
    160 	DBG("telephony-ofono: device %p connected", telephony_device);
    161 
    162 	coming = find_vc_with_status(CALL_STATUS_ALERTING);
    163 	if (coming) {
    164 		if (find_vc_with_status(CALL_STATUS_ACTIVE))
    165 			telephony_call_waiting_ind(coming->number,
    166 						number_type(coming->number));
    167 		else
    168 			telephony_incoming_call_ind(coming->number,
    169 						number_type(coming->number));
    170 	}
    171 }
    172 
    173 void telephony_device_disconnected(void *telephony_device)
    174 {
    175 	DBG("telephony-ofono: device %p disconnected", telephony_device);
    176 	events_enabled = FALSE;
    177 }
    178 
    179 void telephony_event_reporting_req(void *telephony_device, int ind)
    180 {
    181 	events_enabled = ind == 1 ? TRUE : FALSE;
    182 
    183 	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
    184 }
    185 
    186 void telephony_response_and_hold_req(void *telephony_device, int rh)
    187 {
    188 	telephony_response_and_hold_rsp(telephony_device,
    189 						CME_ERROR_NOT_SUPPORTED);
    190 }
    191 
    192 void telephony_last_dialed_number_req(void *telephony_device)
    193 {
    194 	DBG("telephony-ofono: last dialed number request");
    195 
    196 	if (last_dialed_number)
    197 		telephony_dial_number_req(telephony_device, last_dialed_number);
    198 	else
    199 		telephony_last_dialed_number_rsp(telephony_device,
    200 				CME_ERROR_NOT_ALLOWED);
    201 }
    202 
    203 static int send_method_call(const char *dest, const char *path,
    204                                 const char *interface, const char *method,
    205                                 DBusPendingCallNotifyFunction cb,
    206                                 void *user_data, int type, ...)
    207 {
    208 	DBusMessage *msg;
    209 	DBusPendingCall *call;
    210 	va_list args;
    211 
    212 	msg = dbus_message_new_method_call(dest, path, interface, method);
    213 	if (!msg) {
    214 		error("Unable to allocate new D-Bus %s message", method);
    215 		return -ENOMEM;
    216 	}
    217 
    218 	va_start(args, type);
    219 
    220 	if (!dbus_message_append_args_valist(msg, type, args)) {
    221 		dbus_message_unref(msg);
    222 		va_end(args);
    223 		return -EIO;
    224 	}
    225 
    226 	va_end(args);
    227 
    228 	if (!cb) {
    229 		g_dbus_send_message(connection, msg);
    230 		return 0;
    231 	}
    232 
    233 	if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
    234 		error("Sending %s failed", method);
    235 		dbus_message_unref(msg);
    236 		return -EIO;
    237 	}
    238 
    239 	dbus_pending_call_set_notify(call, cb, user_data, NULL);
    240 	pending = g_slist_prepend(pending, call);
    241 	dbus_message_unref(msg);
    242 
    243 	return 0;
    244 }
    245 
    246 static int answer_call(struct voice_call *vc)
    247 {
    248 	DBG("%s", vc->number);
    249 	return send_method_call(OFONO_BUS_NAME, vc->obj_path,
    250 						OFONO_VC_INTERFACE, "Answer",
    251 						NULL, NULL, DBUS_TYPE_INVALID);
    252 }
    253 
    254 static int release_call(struct voice_call *vc)
    255 {
    256 	DBG("%s", vc->number);
    257 	return send_method_call(OFONO_BUS_NAME, vc->obj_path,
    258 						OFONO_VC_INTERFACE, "Hangup",
    259 						NULL, NULL, DBUS_TYPE_INVALID);
    260 }
    261 
    262 static int release_answer_calls(void)
    263 {
    264 	DBG("");
    265 	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
    266 						OFONO_VCMANAGER_INTERFACE,
    267 						"ReleaseAndAnswer",
    268 						NULL, NULL, DBUS_TYPE_INVALID);
    269 }
    270 
    271 static int split_call(struct voice_call *call)
    272 {
    273 	DBG("%s", call->number);
    274 	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
    275 						OFONO_VCMANAGER_INTERFACE,
    276 						"PrivateChat",
    277 						NULL, NULL,
    278 						DBUS_TYPE_OBJECT_PATH,
    279 						call->obj_path,
    280 						DBUS_TYPE_INVALID);
    281 	return -1;
    282 }
    283 
    284 static int swap_calls(void)
    285 {
    286 	DBG("");
    287 	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
    288 						OFONO_VCMANAGER_INTERFACE,
    289 						"SwapCalls",
    290 						NULL, NULL, DBUS_TYPE_INVALID);
    291 }
    292 
    293 static int create_conference(void)
    294 {
    295 	DBG("");
    296 	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
    297 						OFONO_VCMANAGER_INTERFACE,
    298 						"CreateMultiparty",
    299 						NULL, NULL, DBUS_TYPE_INVALID);
    300 }
    301 
    302 static int release_conference(void)
    303 {
    304 	DBG("");
    305 	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
    306 						OFONO_VCMANAGER_INTERFACE,
    307 						"HangupMultiparty",
    308 						NULL, NULL, DBUS_TYPE_INVALID);
    309 }
    310 
    311 static int call_transfer(void)
    312 {
    313 	DBG("");
    314 	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
    315 						OFONO_VCMANAGER_INTERFACE,
    316 						"Transfer",
    317 						NULL, NULL, DBUS_TYPE_INVALID);
    318 }
    319 
    320 void telephony_terminate_call_req(void *telephony_device)
    321 {
    322 	struct voice_call *call;
    323 	struct voice_call *alerting;
    324 	int err;
    325 
    326 	call = find_vc_with_status(CALL_STATUS_ACTIVE);
    327 	if (!call)
    328 		call = calls->data;
    329 
    330 	if (!call) {
    331 		error("No active call");
    332 		telephony_terminate_call_rsp(telephony_device,
    333 						CME_ERROR_NOT_ALLOWED);
    334 		return;
    335 	}
    336 
    337 	alerting = find_vc_with_status(CALL_STATUS_ALERTING);
    338 	if (call->status == CALL_STATUS_HELD && alerting)
    339 		err = release_call(alerting);
    340 	else if (call->conference)
    341 		err = release_conference();
    342 	else
    343 		err = release_call(call);
    344 
    345 	if (err < 0)
    346 		telephony_terminate_call_rsp(telephony_device,
    347 						CME_ERROR_AG_FAILURE);
    348 	else
    349 		telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
    350 }
    351 
    352 void telephony_answer_call_req(void *telephony_device)
    353 {
    354 	struct voice_call *vc;
    355 	int ret;
    356 
    357 	vc = find_vc_with_status(CALL_STATUS_INCOMING);
    358 	if (!vc)
    359 		vc = find_vc_with_status(CALL_STATUS_ALERTING);
    360 
    361 	if (!vc)
    362 		vc = find_vc_with_status(CALL_STATUS_WAITING);
    363 
    364 	if (!vc) {
    365 		telephony_answer_call_rsp(telephony_device,
    366 					CME_ERROR_NOT_ALLOWED);
    367 		return;
    368 	}
    369 
    370 	ret = answer_call(vc);
    371 	if (ret < 0) {
    372 		telephony_answer_call_rsp(telephony_device,
    373 					CME_ERROR_AG_FAILURE);
    374 		return;
    375 	}
    376 
    377 	telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
    378 }
    379 
    380 void telephony_dial_number_req(void *telephony_device, const char *number)
    381 {
    382 	const char *clir;
    383 	int ret;
    384 
    385 	DBG("telephony-ofono: dial request to %s", number);
    386 
    387 	if (!modem_obj_path) {
    388 		telephony_dial_number_rsp(telephony_device,
    389 					CME_ERROR_AG_FAILURE);
    390 		return;
    391 	}
    392 
    393 	if (!strncmp(number, "*31#", 4)) {
    394 		number += 4;
    395 		clir = "enabled";
    396 	} else if (!strncmp(number, "#31#", 4)) {
    397 		number += 4;
    398 		clir =  "disabled";
    399 	} else
    400 		clir = "default";
    401 
    402 	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
    403 			OFONO_VCMANAGER_INTERFACE,
    404                         "Dial", NULL, NULL,
    405 			DBUS_TYPE_STRING, &number,
    406 			DBUS_TYPE_STRING, &clir,
    407 			DBUS_TYPE_INVALID);
    408 
    409 	if (ret < 0)
    410 		telephony_dial_number_rsp(telephony_device,
    411 			CME_ERROR_AG_FAILURE);
    412 	else
    413 		telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
    414 }
    415 
    416 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
    417 {
    418 	char *tone_string;
    419 	int ret;
    420 
    421 	DBG("telephony-ofono: transmit dtmf: %c", tone);
    422 
    423 	if (!modem_obj_path) {
    424 		telephony_transmit_dtmf_rsp(telephony_device,
    425 					CME_ERROR_AG_FAILURE);
    426 		return;
    427 	}
    428 
    429 	tone_string = g_strdup_printf("%c", tone);
    430 	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
    431 			OFONO_VCMANAGER_INTERFACE,
    432 			"SendTones", NULL, NULL,
    433 			DBUS_TYPE_STRING, &tone_string,
    434 			DBUS_TYPE_INVALID);
    435 	g_free(tone_string);
    436 
    437 	if (ret < 0)
    438 		telephony_transmit_dtmf_rsp(telephony_device,
    439 			CME_ERROR_AG_FAILURE);
    440 	else
    441 		telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
    442 }
    443 
    444 void telephony_subscriber_number_req(void *telephony_device)
    445 {
    446 	DBG("telephony-ofono: subscriber number request");
    447 
    448 	if (subscriber_number)
    449 		telephony_subscriber_number_ind(subscriber_number,
    450 						NUMBER_TYPE_TELEPHONY,
    451 						SUBSCRIBER_SERVICE_VOICE);
    452 	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
    453 }
    454 
    455 void telephony_list_current_calls_req(void *telephony_device)
    456 {
    457 	GSList *l;
    458 	int i;
    459 
    460 	DBG("telephony-ofono: list current calls request");
    461 
    462 	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
    463 		struct voice_call *vc = l->data;
    464 		int direction, multiparty;
    465 
    466 		direction = vc->originating ?
    467 				CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
    468 
    469 		multiparty = vc->conference ?
    470 				CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
    471 
    472 		DBG("call %s direction %d multiparty %d", vc->number,
    473 							direction, multiparty);
    474 
    475 		telephony_list_current_call_ind(i, direction, vc->status,
    476 					CALL_MODE_VOICE, multiparty,
    477 					vc->number, number_type(vc->number));
    478 	}
    479 
    480 	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
    481 }
    482 
    483 void telephony_operator_selection_req(void *telephony_device)
    484 {
    485 	DBG("telephony-ofono: operator selection request");
    486 
    487 	telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
    488 				net.operator_name ? net.operator_name : "");
    489 	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
    490 }
    491 
    492 static void foreach_vc_with_status(int status,
    493 					int (*func)(struct voice_call *vc))
    494 {
    495 	GSList *l;
    496 
    497 	for (l = calls; l != NULL; l = l->next) {
    498 		struct voice_call *call = l->data;
    499 
    500 		if (call->status == status)
    501 			func(call);
    502 	}
    503 }
    504 
    505 void telephony_call_hold_req(void *telephony_device, const char *cmd)
    506 {
    507 	const char *idx;
    508 	struct voice_call *call;
    509 	int err = 0;
    510 
    511 	DBG("telephony-ofono: got call hold request %s", cmd);
    512 
    513 	if (strlen(cmd) > 1)
    514 		idx = &cmd[1];
    515 	else
    516 		idx = NULL;
    517 
    518 	if (idx)
    519 		call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
    520 	else
    521 		call = NULL;
    522 
    523 	switch (cmd[0]) {
    524 	case '0':
    525 		if (find_vc_with_status(CALL_STATUS_WAITING))
    526 			foreach_vc_with_status(CALL_STATUS_WAITING,
    527 								release_call);
    528 		else
    529 			foreach_vc_with_status(CALL_STATUS_HELD, release_call);
    530 		break;
    531 	case '1':
    532 		if (idx) {
    533 			if (call)
    534 				err = release_call(call);
    535 			break;
    536 		}
    537 		err = release_answer_calls();
    538 		break;
    539 	case '2':
    540 		if (idx) {
    541 			if (call)
    542 				err = split_call(call);
    543 		} else {
    544 			call = find_vc_with_status(CALL_STATUS_WAITING);
    545 
    546 			if (call)
    547 				err = answer_call(call);
    548 			else
    549 				err = swap_calls();
    550 		}
    551 		break;
    552 	case '3':
    553 		if (find_vc_with_status(CALL_STATUS_HELD) ||
    554 				find_vc_with_status(CALL_STATUS_WAITING))
    555 			err = create_conference();
    556 		break;
    557 	case '4':
    558 		err = call_transfer();
    559 		break;
    560 	default:
    561 		DBG("Unknown call hold request");
    562 		break;
    563 	}
    564 
    565 	if (err)
    566 		telephony_call_hold_rsp(telephony_device,
    567 					CME_ERROR_AG_FAILURE);
    568 	else
    569 		telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
    570 }
    571 
    572 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
    573 {
    574 	DBG("telephony-ofono: got %s NR and EC request",
    575 			enable ? "enable" : "disable");
    576 
    577 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
    578 }
    579 
    580 void telephony_key_press_req(void *telephony_device, const char *keys)
    581 {
    582 	struct voice_call *active, *incoming;
    583 	int err;
    584 
    585 	DBG("telephony-ofono: got key press request for %s", keys);
    586 
    587 	incoming = find_vc_with_status(CALL_STATUS_INCOMING);
    588 
    589 	active = find_vc_with_status(CALL_STATUS_ACTIVE);
    590 
    591 	if (incoming)
    592 		err = answer_call(incoming);
    593 	else if (active)
    594 		err = release_call(active);
    595 	else
    596 		err = 0;
    597 
    598 	if (err < 0)
    599 		telephony_key_press_rsp(telephony_device,
    600 							CME_ERROR_AG_FAILURE);
    601 	else
    602 		telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
    603 }
    604 
    605 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
    606 {
    607 	DBG("telephony-ofono: got %s voice dial request",
    608 			enable ? "enable" : "disable");
    609 
    610 	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
    611 }
    612 
    613 static gboolean iter_get_basic_args(DBusMessageIter *iter,
    614 					int first_arg_type, ...)
    615 {
    616 	int type;
    617 	va_list ap;
    618 
    619 	va_start(ap, first_arg_type);
    620 
    621 	for (type = first_arg_type; type != DBUS_TYPE_INVALID;
    622 		type = va_arg(ap, int)) {
    623 		void *value = va_arg(ap, void *);
    624 		int real_type = dbus_message_iter_get_arg_type(iter);
    625 
    626 		if (real_type != type) {
    627 			error("iter_get_basic_args: expected %c but got %c",
    628 				(char) type, (char) real_type);
    629 			break;
    630 		}
    631 
    632 		dbus_message_iter_get_basic(iter, value);
    633 		dbus_message_iter_next(iter);
    634 	}
    635 
    636 	va_end(ap);
    637 
    638 	return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
    639 }
    640 
    641 static void call_free(struct voice_call *vc)
    642 {
    643 	DBG("%s", vc->obj_path);
    644 
    645 	if (vc->status == CALL_STATUS_ACTIVE)
    646 		telephony_update_indicator(ofono_indicators, "call",
    647 							EV_CALL_INACTIVE);
    648 	else
    649 		telephony_update_indicator(ofono_indicators, "callsetup",
    650 							EV_CALLSETUP_INACTIVE);
    651 
    652 	if (vc->status == CALL_STATUS_INCOMING)
    653 		telephony_calling_stopped_ind();
    654 
    655 	g_dbus_remove_watch(connection, vc->watch);
    656 	g_free(vc->obj_path);
    657 	g_free(vc->number);
    658 	g_free(vc);
    659 }
    660 
    661 static gboolean handle_vc_property_changed(DBusConnection *conn,
    662 					DBusMessage *msg, void *data)
    663 {
    664 	struct voice_call *vc = data;
    665 	const char *obj_path = dbus_message_get_path(msg);
    666 	DBusMessageIter iter, sub;
    667 	const char *property, *state;
    668 
    669 	DBG("path %s", obj_path);
    670 
    671 	dbus_message_iter_init(msg, &iter);
    672 
    673 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
    674 		error("Unexpected signature in vc PropertyChanged signal");
    675 		return TRUE;
    676 	}
    677 
    678 	dbus_message_iter_get_basic(&iter, &property);
    679 	DBG("property %s", property);
    680 
    681 	dbus_message_iter_next(&iter);
    682 	dbus_message_iter_recurse(&iter, &sub);
    683 	if (g_str_equal(property, "State")) {
    684 		dbus_message_iter_get_basic(&sub, &state);
    685 		DBG("State %s", state);
    686 		if (g_str_equal(state, "disconnected")) {
    687 			calls = g_slist_remove(calls, vc);
    688 			call_free(vc);
    689 		} else if (g_str_equal(state, "active")) {
    690 			telephony_update_indicator(ofono_indicators,
    691 							"call", EV_CALL_ACTIVE);
    692 			telephony_update_indicator(ofono_indicators,
    693 							"callsetup",
    694 							EV_CALLSETUP_INACTIVE);
    695 			if (vc->status == CALL_STATUS_INCOMING)
    696 				telephony_calling_stopped_ind();
    697 			vc->status = CALL_STATUS_ACTIVE;
    698 		} else if (g_str_equal(state, "alerting")) {
    699 			telephony_update_indicator(ofono_indicators,
    700 					"callsetup", EV_CALLSETUP_ALERTING);
    701 			vc->status = CALL_STATUS_ALERTING;
    702 			vc->originating = TRUE;
    703 		} else if (g_str_equal(state, "incoming")) {
    704 			/* state change from waiting to incoming */
    705 			telephony_update_indicator(ofono_indicators,
    706 					"callsetup", EV_CALLSETUP_INCOMING);
    707 			telephony_incoming_call_ind(vc->number,
    708 						NUMBER_TYPE_TELEPHONY);
    709 			vc->status = CALL_STATUS_INCOMING;
    710 			vc->originating = FALSE;
    711 		} else if (g_str_equal(state, "held")) {
    712 			vc->status = CALL_STATUS_HELD;
    713 			if (find_vc_without_status(CALL_STATUS_HELD))
    714 				telephony_update_indicator(ofono_indicators,
    715 							"callheld",
    716 							EV_CALLHELD_MULTIPLE);
    717 			else
    718 				telephony_update_indicator(ofono_indicators,
    719 							"callheld",
    720 							EV_CALLHELD_ON_HOLD);
    721 		}
    722 	} else if (g_str_equal(property, "Multiparty")) {
    723 		dbus_bool_t multiparty;
    724 
    725 		dbus_message_iter_get_basic(&sub, &multiparty);
    726 		DBG("Multiparty %s", multiparty ? "True" : "False");
    727 		vc->conference = multiparty;
    728 	}
    729 
    730 	return TRUE;
    731 }
    732 
    733 static struct voice_call *call_new(const char *path, DBusMessageIter *properties)
    734 {
    735 	struct voice_call *vc;
    736 
    737 	DBG("%s", path);
    738 
    739 	vc = g_new0(struct voice_call, 1);
    740 	vc->obj_path = g_strdup(path);
    741 	vc->watch = g_dbus_add_signal_watch(connection, NULL, path,
    742 					OFONO_VC_INTERFACE, "PropertyChanged",
    743 					handle_vc_property_changed, vc, NULL);
    744 
    745 	while (dbus_message_iter_get_arg_type(properties)
    746 						== DBUS_TYPE_DICT_ENTRY) {
    747 		DBusMessageIter entry, value;
    748 		const char *property, *cli, *state;
    749 		dbus_bool_t multiparty;
    750 
    751 		dbus_message_iter_recurse(properties, &entry);
    752 		dbus_message_iter_get_basic(&entry, &property);
    753 
    754 		dbus_message_iter_next(&entry);
    755 		dbus_message_iter_recurse(&entry, &value);
    756 
    757 		if (g_str_equal(property, "LineIdentification")) {
    758 			dbus_message_iter_get_basic(&value, &cli);
    759 			DBG("cli %s", cli);
    760 			vc->number = g_strdup(cli);
    761 		} else if (g_str_equal(property, "State")) {
    762 			dbus_message_iter_get_basic(&value, &state);
    763 			DBG("state %s", state);
    764 			if (g_str_equal(state, "incoming"))
    765 				vc->status = CALL_STATUS_INCOMING;
    766 			else if (g_str_equal(state, "dialing"))
    767 				vc->status = CALL_STATUS_DIALING;
    768 			else if (g_str_equal(state, "alerting"))
    769 				vc->status = CALL_STATUS_ALERTING;
    770 			else if (g_str_equal(state, "waiting"))
    771 				vc->status = CALL_STATUS_WAITING;
    772 			else if (g_str_equal(state, "held"))
    773 				vc->status = CALL_STATUS_HELD;
    774 		} else if (g_str_equal(property, "Multiparty")) {
    775 			dbus_message_iter_get_basic(&value, &multiparty);
    776 			DBG("Multipary %s", multiparty ? "True" : "False");
    777 			vc->conference = multiparty;
    778 		}
    779 
    780 		dbus_message_iter_next(properties);
    781 	}
    782 
    783 	switch (vc->status) {
    784 	case CALL_STATUS_INCOMING:
    785 		DBG("CALL_STATUS_INCOMING");
    786 		vc->originating = FALSE;
    787 		telephony_update_indicator(ofono_indicators, "callsetup",
    788 					EV_CALLSETUP_INCOMING);
    789 		telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
    790 		break;
    791 	case CALL_STATUS_DIALING:
    792 		DBG("CALL_STATUS_DIALING");
    793 		vc->originating = TRUE;
    794 		g_free(last_dialed_number);
    795 		last_dialed_number = g_strdup(vc->number);
    796 		telephony_update_indicator(ofono_indicators, "callsetup",
    797 					EV_CALLSETUP_OUTGOING);
    798 		break;
    799 	case CALL_STATUS_ALERTING:
    800 		DBG("CALL_STATUS_ALERTING");
    801 		vc->originating = TRUE;
    802 		g_free(last_dialed_number);
    803 		last_dialed_number = g_strdup(vc->number);
    804 		telephony_update_indicator(ofono_indicators, "callsetup",
    805 					EV_CALLSETUP_ALERTING);
    806 		break;
    807 	case CALL_STATUS_WAITING:
    808 		DBG("CALL_STATUS_WAITING");
    809 		vc->originating = FALSE;
    810 		telephony_update_indicator(ofono_indicators, "callsetup",
    811 					EV_CALLSETUP_INCOMING);
    812 		telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
    813 		break;
    814 	}
    815 
    816 	return vc;
    817 }
    818 
    819 static void remove_pending(DBusPendingCall *call)
    820 {
    821 	pending = g_slist_remove(pending, call);
    822 	dbus_pending_call_unref(call);
    823 }
    824 
    825 static void call_added(const char *path, DBusMessageIter *properties)
    826 {
    827 	struct voice_call *vc;
    828 
    829 	DBG("%s", path);
    830 
    831 	vc = find_vc(path);
    832 	if (vc)
    833 		return;
    834 
    835 	vc = call_new(path, properties);
    836 	calls = g_slist_prepend(calls, vc);
    837 }
    838 
    839 static void get_calls_reply(DBusPendingCall *call, void *user_data)
    840 {
    841 	DBusError err;
    842 	DBusMessage *reply;
    843 	DBusMessageIter iter, entry;
    844 
    845 	DBG("");
    846 	reply = dbus_pending_call_steal_reply(call);
    847 
    848 	dbus_error_init(&err);
    849 	if (dbus_set_error_from_message(&err, reply)) {
    850 		error("ofono replied with an error: %s, %s",
    851 				err.name, err.message);
    852 		dbus_error_free(&err);
    853 		goto done;
    854 	}
    855 
    856 	dbus_message_iter_init(reply, &iter);
    857 
    858 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
    859 		error("Unexpected signature");
    860 		goto done;
    861 	}
    862 
    863 	dbus_message_iter_recurse(&iter, &entry);
    864 
    865 	while (dbus_message_iter_get_arg_type(&entry)
    866 						== DBUS_TYPE_STRUCT) {
    867 		const char *path;
    868 		DBusMessageIter value, properties;
    869 
    870 		dbus_message_iter_recurse(&entry, &value);
    871 		dbus_message_iter_get_basic(&value, &path);
    872 
    873 		dbus_message_iter_next(&value);
    874 		dbus_message_iter_recurse(&value, &properties);
    875 
    876 		call_added(path, &properties);
    877 
    878 		dbus_message_iter_next(&entry);
    879 	}
    880 
    881 done:
    882 	dbus_message_unref(reply);
    883 	remove_pending(call);
    884 }
    885 
    886 static void handle_network_property(const char *property, DBusMessageIter *variant)
    887 {
    888 	const char *status, *operator;
    889 	unsigned int signals_bar;
    890 
    891 	if (g_str_equal(property, "Status")) {
    892 		dbus_message_iter_get_basic(variant, &status);
    893 		DBG("Status is %s", status);
    894 		if (g_str_equal(status, "registered")) {
    895 			net.status = NETWORK_REG_STATUS_HOME;
    896 			telephony_update_indicator(ofono_indicators,
    897 						"roam", EV_ROAM_INACTIVE);
    898 			telephony_update_indicator(ofono_indicators,
    899 						"service", EV_SERVICE_PRESENT);
    900 		} else if (g_str_equal(status, "roaming")) {
    901 			net.status = NETWORK_REG_STATUS_ROAM;
    902 			telephony_update_indicator(ofono_indicators,
    903 						"roam", EV_ROAM_ACTIVE);
    904 			telephony_update_indicator(ofono_indicators,
    905 						"service", EV_SERVICE_PRESENT);
    906 		} else {
    907 			net.status = NETWORK_REG_STATUS_NOSERV;
    908 			telephony_update_indicator(ofono_indicators,
    909 						"roam", EV_ROAM_INACTIVE);
    910 			telephony_update_indicator(ofono_indicators,
    911 						"service", EV_SERVICE_NONE);
    912 		}
    913 	} else if (g_str_equal(property, "Name")) {
    914 		dbus_message_iter_get_basic(variant, &operator);
    915 		DBG("Operator is %s", operator);
    916 		g_free(net.operator_name);
    917 		net.operator_name = g_strdup(operator);
    918 	} else if (g_str_equal(property, "SignalStrength")) {
    919 		dbus_message_iter_get_basic(variant, &signals_bar);
    920 		DBG("SignalStrength is %d", signals_bar);
    921 		net.signals_bar = signals_bar;
    922 		telephony_update_indicator(ofono_indicators, "signal",
    923 						(signals_bar + 20) / 21);
    924 	}
    925 }
    926 
    927 static int parse_network_properties(DBusMessageIter *properties)
    928 {
    929 	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
    930 				AG_FEATURE_INBAND_RINGTONE |
    931 				AG_FEATURE_REJECT_A_CALL |
    932 				AG_FEATURE_ENHANCED_CALL_STATUS |
    933 				AG_FEATURE_ENHANCED_CALL_CONTROL |
    934 				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
    935 				AG_FEATURE_THREE_WAY_CALLING;
    936 	int i;
    937 
    938 	/* Reset indicators */
    939 	for (i = 0; ofono_indicators[i].desc != NULL; i++) {
    940 		if (g_str_equal(ofono_indicators[i].desc, "battchg"))
    941 			ofono_indicators[i].val = 5;
    942 		else
    943 			ofono_indicators[i].val = 0;
    944 	}
    945 
    946 	while (dbus_message_iter_get_arg_type(properties)
    947 						== DBUS_TYPE_DICT_ENTRY) {
    948 		const char *key;
    949 		DBusMessageIter value, entry;
    950 
    951 		dbus_message_iter_recurse(properties, &entry);
    952 		dbus_message_iter_get_basic(&entry, &key);
    953 
    954 		dbus_message_iter_next(&entry);
    955 		dbus_message_iter_recurse(&entry, &value);
    956 
    957 		handle_network_property(key, &value);
    958 
    959 		dbus_message_iter_next(properties);
    960 	}
    961 
    962 	telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
    963 								chld_str);
    964 
    965 	return 0;
    966 }
    967 
    968 static void get_properties_reply(DBusPendingCall *call, void *user_data)
    969 {
    970 	DBusError err;
    971 	DBusMessage *reply;
    972 	DBusMessageIter iter, properties;
    973 	int ret = 0;
    974 
    975 	DBG("");
    976 	reply = dbus_pending_call_steal_reply(call);
    977 
    978 	dbus_error_init(&err);
    979 	if (dbus_set_error_from_message(&err, reply)) {
    980 		error("ofono replied with an error: %s, %s",
    981 				err.name, err.message);
    982 		dbus_error_free(&err);
    983 		goto done;
    984 	}
    985 
    986 	dbus_message_iter_init(reply, &iter);
    987 
    988 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
    989 		error("Unexpected signature");
    990 		goto done;
    991 	}
    992 
    993 	dbus_message_iter_recurse(&iter, &properties);
    994 
    995 	ret = parse_network_properties(&properties);
    996 	if (ret < 0) {
    997 		error("Unable to parse %s.GetProperty reply",
    998 						OFONO_NETWORKREG_INTERFACE);
    999 		goto done;
   1000 	}
   1001 
   1002 	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
   1003 				OFONO_VCMANAGER_INTERFACE, "GetCalls",
   1004 				get_calls_reply, NULL, DBUS_TYPE_INVALID);
   1005 	if (ret < 0)
   1006 		error("Unable to send %s.GetCalls",
   1007 						OFONO_VCMANAGER_INTERFACE);
   1008 
   1009 done:
   1010 	dbus_message_unref(reply);
   1011 	remove_pending(call);
   1012 }
   1013 
   1014 static void network_found(const char *path)
   1015 {
   1016 	int ret;
   1017 
   1018 	DBG("%s", path);
   1019 
   1020 	modem_obj_path = g_strdup(path);
   1021 
   1022 	ret = send_method_call(OFONO_BUS_NAME, path,
   1023 				OFONO_NETWORKREG_INTERFACE, "GetProperties",
   1024 				get_properties_reply, NULL, DBUS_TYPE_INVALID);
   1025 	if (ret < 0)
   1026 		error("Unable to send %s.GetProperties",
   1027 						OFONO_NETWORKREG_INTERFACE);
   1028 }
   1029 
   1030 static void modem_removed(const char *path)
   1031 {
   1032 	if (g_strcmp0(modem_obj_path, path) != 0)
   1033 		return;
   1034 
   1035 	DBG("%s", path);
   1036 
   1037 	g_slist_foreach(calls, (GFunc) call_free, NULL);
   1038 	g_slist_free(calls);
   1039 	calls = NULL;
   1040 
   1041 	g_free(net.operator_name);
   1042 	net.operator_name = NULL;
   1043 	net.status = NETWORK_REG_STATUS_NOSERV;
   1044 	net.signals_bar = 0;
   1045 
   1046 	g_free(modem_obj_path);
   1047 	modem_obj_path = NULL;
   1048 }
   1049 
   1050 static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces)
   1051 {
   1052 	DBG("%s", path);
   1053 
   1054 	while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) {
   1055 		const char *iface;
   1056 
   1057 		dbus_message_iter_get_basic(ifaces, &iface);
   1058 
   1059 		if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) {
   1060 			network_found(path);
   1061 			return;
   1062 		}
   1063 
   1064 		dbus_message_iter_next(ifaces);
   1065 	}
   1066 
   1067 	modem_removed(path);
   1068 }
   1069 
   1070 static void modem_added(const char *path, DBusMessageIter *properties)
   1071 {
   1072 	if (modem_obj_path != NULL) {
   1073 		DBG("Ignoring, modem already exist");
   1074 		return;
   1075 	}
   1076 
   1077 	DBG("%s", path);
   1078 
   1079 	while (dbus_message_iter_get_arg_type(properties)
   1080 						== DBUS_TYPE_DICT_ENTRY) {
   1081 		const char *key;
   1082 		DBusMessageIter interfaces, value, entry;
   1083 
   1084 		dbus_message_iter_recurse(properties, &entry);
   1085 		dbus_message_iter_get_basic(&entry, &key);
   1086 
   1087 		dbus_message_iter_next(&entry);
   1088 		dbus_message_iter_recurse(&entry, &value);
   1089 
   1090 		if (strcasecmp(key, "Interfaces") != 0)
   1091 			goto next;
   1092 
   1093 		if (dbus_message_iter_get_arg_type(&value)
   1094 							!= DBUS_TYPE_ARRAY) {
   1095 			error("Invalid Signature");
   1096 			return;
   1097 		}
   1098 
   1099 		dbus_message_iter_recurse(&value, &interfaces);
   1100 
   1101 		parse_modem_interfaces(path, &interfaces);
   1102 
   1103 		if (modem_obj_path != NULL)
   1104 			return;
   1105 
   1106 	next:
   1107 		dbus_message_iter_next(properties);
   1108 	}
   1109 }
   1110 
   1111 static void get_modems_reply(DBusPendingCall *call, void *user_data)
   1112 {
   1113 	DBusError err;
   1114 	DBusMessage *reply;
   1115 	DBusMessageIter iter, entry;
   1116 
   1117 	DBG("");
   1118 	reply = dbus_pending_call_steal_reply(call);
   1119 
   1120 	dbus_error_init(&err);
   1121 	if (dbus_set_error_from_message(&err, reply)) {
   1122 		error("ofono replied with an error: %s, %s",
   1123 				err.name, err.message);
   1124 		dbus_error_free(&err);
   1125 		goto done;
   1126 	}
   1127 
   1128 	/* Skip modem selection if a modem already exist */
   1129 	if (modem_obj_path != NULL)
   1130 		goto done;
   1131 
   1132 	dbus_message_iter_init(reply, &iter);
   1133 
   1134 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
   1135 		error("Unexpected signature");
   1136 		goto done;
   1137 	}
   1138 
   1139 	dbus_message_iter_recurse(&iter, &entry);
   1140 
   1141 	while (dbus_message_iter_get_arg_type(&entry)
   1142 						== DBUS_TYPE_STRUCT) {
   1143 		const char *path;
   1144 		DBusMessageIter item, properties;
   1145 
   1146 		dbus_message_iter_recurse(&entry, &item);
   1147 		dbus_message_iter_get_basic(&item, &path);
   1148 
   1149 		dbus_message_iter_next(&item);
   1150 		dbus_message_iter_recurse(&item, &properties);
   1151 
   1152 		modem_added(path, &properties);
   1153 		if (modem_obj_path != NULL)
   1154 			break;
   1155 
   1156 		dbus_message_iter_next(&entry);
   1157 	}
   1158 
   1159 done:
   1160 	dbus_message_unref(reply);
   1161 	remove_pending(call);
   1162 }
   1163 
   1164 static gboolean handle_network_property_changed(DBusConnection *conn,
   1165 						DBusMessage *msg, void *data)
   1166 {
   1167 	DBusMessageIter iter, variant;
   1168 	const char *property;
   1169 
   1170 	dbus_message_iter_init(msg, &iter);
   1171 
   1172 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
   1173 		error("Unexpected signature in networkregistration"
   1174 					" PropertyChanged signal");
   1175 		return TRUE;
   1176 	}
   1177 	dbus_message_iter_get_basic(&iter, &property);
   1178 	DBG("in handle_registration_property_changed(),"
   1179 					" the property is %s", property);
   1180 
   1181 	dbus_message_iter_next(&iter);
   1182 	dbus_message_iter_recurse(&iter, &variant);
   1183 
   1184 	handle_network_property(property, &variant);
   1185 
   1186 	return TRUE;
   1187 }
   1188 
   1189 static void handle_modem_property(const char *path, const char *property,
   1190 						DBusMessageIter *variant)
   1191 {
   1192 	DBG("%s", property);
   1193 
   1194 	if (g_str_equal(property, "Interfaces")) {
   1195 		DBusMessageIter interfaces;
   1196 
   1197 		if (dbus_message_iter_get_arg_type(variant)
   1198 							!= DBUS_TYPE_ARRAY) {
   1199 			error("Invalid signature");
   1200 			return;
   1201 		}
   1202 
   1203 		dbus_message_iter_recurse(variant, &interfaces);
   1204 		parse_modem_interfaces(path, &interfaces);
   1205 	}
   1206 }
   1207 
   1208 static gboolean handle_modem_property_changed(DBusConnection *conn,
   1209 						DBusMessage *msg, void *data)
   1210 {
   1211 	DBusMessageIter iter, variant;
   1212 	const char *property, *path;
   1213 
   1214 	path = dbus_message_get_path(msg);
   1215 
   1216 	/* Ignore if modem already exist and paths doesn't match */
   1217 	if (modem_obj_path != NULL &&
   1218 				g_str_equal(path, modem_obj_path) == FALSE)
   1219 		return TRUE;
   1220 
   1221 	dbus_message_iter_init(msg, &iter);
   1222 
   1223 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
   1224 		error("Unexpected signature in %s.%s PropertyChanged signal",
   1225 					dbus_message_get_interface(msg),
   1226 					dbus_message_get_member(msg));
   1227 		return TRUE;
   1228 	}
   1229 
   1230 	dbus_message_iter_get_basic(&iter, &property);
   1231 
   1232 	dbus_message_iter_next(&iter);
   1233 	dbus_message_iter_recurse(&iter, &variant);
   1234 
   1235 	handle_modem_property(path, property, &variant);
   1236 
   1237 	return TRUE;
   1238 }
   1239 
   1240 static gboolean handle_vcmanager_call_added(DBusConnection *conn,
   1241 						DBusMessage *msg, void *data)
   1242 {
   1243 	DBusMessageIter iter, properties;
   1244 	const char *path = dbus_message_get_path(msg);
   1245 
   1246 	/* Ignore call if modem path doesn't math */
   1247 	if (g_strcmp0(modem_obj_path, path) != 0)
   1248 		return TRUE;
   1249 
   1250 	dbus_message_iter_init(msg, &iter);
   1251 
   1252 	if (dbus_message_iter_get_arg_type(&iter)
   1253 						!= DBUS_TYPE_OBJECT_PATH) {
   1254 		error("Unexpected signature in %s.%s signal",
   1255 					dbus_message_get_interface(msg),
   1256 					dbus_message_get_member(msg));
   1257 		return TRUE;
   1258 	}
   1259 
   1260 	dbus_message_iter_get_basic(&iter, &path);
   1261 	dbus_message_iter_next(&iter);
   1262 	dbus_message_iter_recurse(&iter, &properties);
   1263 
   1264 	call_added(path, &properties);
   1265 
   1266 	return TRUE;
   1267 }
   1268 
   1269 static void call_removed(const char *path)
   1270 {
   1271 	struct voice_call *vc;
   1272 
   1273 	DBG("%s", path);
   1274 
   1275 	vc = find_vc(path);
   1276 	if (vc == NULL)
   1277 		return;
   1278 
   1279 	calls = g_slist_remove(calls, vc);
   1280 	call_free(vc);
   1281 }
   1282 
   1283 static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
   1284 						DBusMessage *msg, void *data)
   1285 {
   1286 	const char *path = dbus_message_get_path(msg);
   1287 
   1288 	/* Ignore call if modem path doesn't math */
   1289 	if (g_strcmp0(modem_obj_path, path) != 0)
   1290 		return TRUE;
   1291 
   1292 	if (!dbus_message_get_args(msg, NULL,
   1293 				DBUS_TYPE_OBJECT_PATH, &path,
   1294 				DBUS_TYPE_INVALID)) {
   1295 		error("Unexpected signature in %s.%s signal",
   1296 					dbus_message_get_interface(msg),
   1297 					dbus_message_get_member(msg));
   1298 		return TRUE;
   1299 	}
   1300 
   1301 	call_removed(path);
   1302 
   1303 	return TRUE;
   1304 }
   1305 
   1306 static gboolean handle_manager_modem_added(DBusConnection *conn,
   1307 						DBusMessage *msg, void *data)
   1308 {
   1309 	DBusMessageIter iter, properties;
   1310 	const char *path;
   1311 
   1312 	if (modem_obj_path != NULL)
   1313 		return TRUE;
   1314 
   1315 	dbus_message_iter_init(msg, &iter);
   1316 
   1317 	if (dbus_message_iter_get_arg_type(&iter)
   1318 						!= DBUS_TYPE_OBJECT_PATH) {
   1319 		error("Unexpected signature in %s.%s signal",
   1320 					dbus_message_get_interface(msg),
   1321 					dbus_message_get_member(msg));
   1322 		return TRUE;
   1323 	}
   1324 
   1325 	dbus_message_iter_get_basic(&iter, &path);
   1326 	dbus_message_iter_next(&iter);
   1327 	dbus_message_iter_recurse(&iter, &properties);
   1328 
   1329 	modem_added(path, &properties);
   1330 
   1331 	return TRUE;
   1332 }
   1333 
   1334 static gboolean handle_manager_modem_removed(DBusConnection *conn,
   1335 						DBusMessage *msg, void *data)
   1336 {
   1337 	const char *path;
   1338 
   1339 	if (!dbus_message_get_args(msg, NULL,
   1340 				DBUS_TYPE_OBJECT_PATH, &path,
   1341 				DBUS_TYPE_INVALID)) {
   1342 		error("Unexpected signature in %s.%s signal",
   1343 					dbus_message_get_interface(msg),
   1344 					dbus_message_get_member(msg));
   1345 		return TRUE;
   1346 	}
   1347 
   1348 	modem_removed(path);
   1349 
   1350 	return TRUE;
   1351 }
   1352 
   1353 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
   1354 {
   1355 	DBusMessage *reply;
   1356 	DBusError err;
   1357 	dbus_int32_t level;
   1358 	int *value = user_data;
   1359 
   1360 	reply = dbus_pending_call_steal_reply(call);
   1361 
   1362 	dbus_error_init(&err);
   1363 	if (dbus_set_error_from_message(&err, reply)) {
   1364 		error("hald replied with an error: %s, %s",
   1365 				err.name, err.message);
   1366 		dbus_error_free(&err);
   1367 		goto done;
   1368 	}
   1369 
   1370 	dbus_error_init(&err);
   1371 	if (dbus_message_get_args(reply, &err,
   1372 				DBUS_TYPE_INT32, &level,
   1373 				DBUS_TYPE_INVALID) == FALSE) {
   1374 		error("Unable to parse GetPropertyInteger reply: %s, %s",
   1375 							err.name, err.message);
   1376 		dbus_error_free(&err);
   1377 		goto done;
   1378 	}
   1379 
   1380 	*value = (int) level;
   1381 
   1382 	if (value == &battchg_last)
   1383 		DBG("telephony-ofono: battery.charge_level.last_full"
   1384 					" is %d", *value);
   1385 	else if (value == &battchg_design)
   1386 		DBG("telephony-ofono: battery.charge_level.design"
   1387 					" is %d", *value);
   1388 	else
   1389 		DBG("telephony-ofono: battery.charge_level.current"
   1390 					" is %d", *value);
   1391 
   1392 	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
   1393 		int new, max;
   1394 
   1395 		if (battchg_last > 0)
   1396 			max = battchg_last;
   1397 		else
   1398 			max = battchg_design;
   1399 
   1400 		new = battchg_cur * 5 / max;
   1401 
   1402 		telephony_update_indicator(ofono_indicators, "battchg", new);
   1403 	}
   1404 done:
   1405 	dbus_message_unref(reply);
   1406 	remove_pending(call);
   1407 }
   1408 
   1409 static void hal_get_integer(const char *path, const char *key, void *user_data)
   1410 {
   1411 	send_method_call("org.freedesktop.Hal", path,
   1412 			"org.freedesktop.Hal.Device",
   1413 			"GetPropertyInteger",
   1414 			hal_battery_level_reply, user_data,
   1415 			DBUS_TYPE_STRING, &key,
   1416 			DBUS_TYPE_INVALID);
   1417 }
   1418 
   1419 static gboolean handle_hal_property_modified(DBusConnection *conn,
   1420 						DBusMessage *msg, void *data)
   1421 {
   1422 	const char *path;
   1423 	DBusMessageIter iter, array;
   1424 	dbus_int32_t num_changes;
   1425 
   1426 	path = dbus_message_get_path(msg);
   1427 
   1428 	dbus_message_iter_init(msg, &iter);
   1429 
   1430 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
   1431 		error("Unexpected signature in hal PropertyModified signal");
   1432 		return TRUE;
   1433 	}
   1434 
   1435 	dbus_message_iter_get_basic(&iter, &num_changes);
   1436 	dbus_message_iter_next(&iter);
   1437 
   1438 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
   1439 		error("Unexpected signature in hal PropertyModified signal");
   1440 		return TRUE;
   1441 	}
   1442 
   1443 	dbus_message_iter_recurse(&iter, &array);
   1444 
   1445 	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
   1446 		DBusMessageIter prop;
   1447 		const char *name;
   1448 		dbus_bool_t added, removed;
   1449 
   1450 		dbus_message_iter_recurse(&array, &prop);
   1451 
   1452 		if (!iter_get_basic_args(&prop,
   1453 					DBUS_TYPE_STRING, &name,
   1454 					DBUS_TYPE_BOOLEAN, &added,
   1455 					DBUS_TYPE_BOOLEAN, &removed,
   1456 					DBUS_TYPE_INVALID)) {
   1457 			error("Invalid hal PropertyModified parameters");
   1458 			break;
   1459 		}
   1460 
   1461 		if (g_str_equal(name, "battery.charge_level.last_full"))
   1462 			hal_get_integer(path, name, &battchg_last);
   1463 		else if (g_str_equal(name, "battery.charge_level.current"))
   1464 			hal_get_integer(path, name, &battchg_cur);
   1465 		else if (g_str_equal(name, "battery.charge_level.design"))
   1466 			hal_get_integer(path, name, &battchg_design);
   1467 
   1468 		dbus_message_iter_next(&array);
   1469 	}
   1470 
   1471 	return TRUE;
   1472 }
   1473 
   1474 static void add_watch(const char *sender, const char *path,
   1475 				const char *interface, const char *member,
   1476 				GDBusSignalFunction function)
   1477 {
   1478 	guint watch;
   1479 
   1480 	watch = g_dbus_add_signal_watch(connection, sender, path, interface,
   1481 					member, function, NULL, NULL);
   1482 
   1483 	watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
   1484 }
   1485 
   1486 static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
   1487 {
   1488 	DBusMessage *reply;
   1489 	DBusError err;
   1490 	DBusMessageIter iter, sub;
   1491 	int type;
   1492 	const char *path;
   1493 
   1494 	DBG("begin of hal_find_device_reply()");
   1495 	reply = dbus_pending_call_steal_reply(call);
   1496 
   1497 	dbus_error_init(&err);
   1498 
   1499 	if (dbus_set_error_from_message(&err, reply)) {
   1500 		error("hald replied with an error: %s, %s",
   1501 				err.name, err.message);
   1502 		dbus_error_free(&err);
   1503 		goto done;
   1504 	}
   1505 
   1506 	dbus_message_iter_init(reply, &iter);
   1507 
   1508 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
   1509 		error("Unexpected signature in hal_find_device_reply()");
   1510 		goto done;
   1511 	}
   1512 
   1513 	dbus_message_iter_recurse(&iter, &sub);
   1514 
   1515 	type = dbus_message_iter_get_arg_type(&sub);
   1516 
   1517 	if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
   1518 		error("No hal device with battery capability found");
   1519 		goto done;
   1520 	}
   1521 
   1522 	dbus_message_iter_get_basic(&sub, &path);
   1523 
   1524 	DBG("telephony-ofono: found battery device at %s", path);
   1525 
   1526 	add_watch(NULL, path, "org.freedesktop.Hal.Device",
   1527 			"PropertyModified", handle_hal_property_modified);
   1528 
   1529 	hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
   1530 	hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
   1531 	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
   1532 done:
   1533 	dbus_message_unref(reply);
   1534 	remove_pending(call);
   1535 }
   1536 
   1537 static void handle_service_connect(DBusConnection *conn, void *user_data)
   1538 {
   1539 	DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
   1540 
   1541 	send_method_call(OFONO_BUS_NAME, OFONO_PATH,
   1542 				OFONO_MANAGER_INTERFACE, "GetModems",
   1543 				get_modems_reply, NULL, DBUS_TYPE_INVALID);
   1544 }
   1545 
   1546 static void handle_service_disconnect(DBusConnection *conn, void *user_data)
   1547 {
   1548 	DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
   1549 
   1550 	if (modem_obj_path)
   1551 		modem_removed(modem_obj_path);
   1552 }
   1553 
   1554 int telephony_init(void)
   1555 {
   1556 	const char *battery_cap = "battery";
   1557 	int ret;
   1558 	guint watch;
   1559 
   1560 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
   1561 
   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);
   1574 
   1575 	watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
   1576 						handle_service_connect,
   1577 						handle_service_disconnect,
   1578 						NULL, NULL);
   1579 	if (watch == 0)
   1580 		return -ENOMEM;
   1581 
   1582 	watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
   1583 
   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,
   1590 				DBUS_TYPE_INVALID);
   1591 	if (ret < 0)
   1592 		return ret;
   1593 
   1594 	DBG("telephony_init() successfully");
   1595 
   1596 	return ret;
   1597 }
   1598 
   1599 static void remove_watch(gpointer data)
   1600 {
   1601 	g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
   1602 }
   1603 
   1604 void telephony_exit(void)
   1605 {
   1606 	DBG("");
   1607 
   1608 	g_free(last_dialed_number);
   1609 	last_dialed_number = NULL;
   1610 
   1611 	if (modem_obj_path)
   1612 		modem_removed(modem_obj_path);
   1613 
   1614 	g_slist_foreach(watches, (GFunc) remove_watch, NULL);
   1615 	g_slist_free(watches);
   1616 	watches = NULL;
   1617 
   1618 	g_slist_foreach(pending, (GFunc) dbus_pending_call_cancel, NULL);
   1619 	g_slist_foreach(pending, (GFunc) dbus_pending_call_unref, NULL);
   1620 	g_slist_free(pending);
   1621 	pending = NULL;
   1622 
   1623 	dbus_connection_unref(connection);
   1624 	connection = NULL;
   1625 
   1626 	telephony_deinit();
   1627 }
   1628