Home | History | Annotate | Download | only in audio
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2008-2010  Nokia Corporation
      6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) holtmann.org>
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <stdlib.h>
     30 #include <stdio.h>
     31 #include <unistd.h>
     32 #include <fcntl.h>
     33 #include <stdint.h>
     34 #include <string.h>
     35 #include <glib.h>
     36 #include <dbus/dbus.h>
     37 #include <gdbus.h>
     38 
     39 #include "log.h"
     40 #include "telephony.h"
     41 #include "error.h"
     42 
     43 /* SSC D-Bus definitions */
     44 #define SSC_DBUS_NAME  "com.nokia.phone.SSC"
     45 #define SSC_DBUS_IFACE "com.nokia.phone.SSC"
     46 #define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
     47 
     48 /* libcsnet D-Bus definitions */
     49 #define CSD_CSNET_BUS_NAME	"com.nokia.csd.CSNet"
     50 #define CSD_CSNET_PATH		"/com/nokia/csd/csnet"
     51 #define CSD_CSNET_IFACE		"com.nokia.csd.CSNet"
     52 #define CSD_CSNET_REGISTRATION	"com.nokia.csd.CSNet.NetworkRegistration"
     53 #define CSD_CSNET_OPERATOR	"com.nokia.csd.CSNet.NetworkOperator"
     54 #define CSD_CSNET_SIGNAL	"com.nokia.csd.CSNet.SignalStrength"
     55 
     56 enum net_registration_status {
     57 	NETWORK_REG_STATUS_HOME,
     58 	NETWORK_REG_STATUS_ROAMING,
     59 	NETWORK_REG_STATUS_OFFLINE,
     60 	NETWORK_REG_STATUS_SEARCHING,
     61 	NETWORK_REG_STATUS_NO_SIM,
     62 	NETWORK_REG_STATUS_POWEROFF,
     63 	NETWORK_REG_STATUS_POWERSAFE,
     64 	NETWORK_REG_STATUS_NO_COVERAGE,
     65 	NETWORK_REG_STATUS_REJECTED,
     66 	NETWORK_REG_STATUS_UNKOWN
     67 };
     68 
     69 /* CSD CALL plugin D-Bus definitions */
     70 #define CSD_CALL_BUS_NAME	"com.nokia.csd.Call"
     71 #define CSD_CALL_INTERFACE	"com.nokia.csd.Call"
     72 #define CSD_CALL_INSTANCE	"com.nokia.csd.Call.Instance"
     73 #define CSD_CALL_CONFERENCE	"com.nokia.csd.Call.Conference"
     74 #define CSD_CALL_PATH		"/com/nokia/csd/call"
     75 #define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
     76 
     77 /* Call status values as exported by the CSD CALL plugin */
     78 #define CSD_CALL_STATUS_IDLE			0
     79 #define CSD_CALL_STATUS_CREATE			1
     80 #define CSD_CALL_STATUS_COMING			2
     81 #define CSD_CALL_STATUS_PROCEEDING		3
     82 #define CSD_CALL_STATUS_MO_ALERTING		4
     83 #define CSD_CALL_STATUS_MT_ALERTING		5
     84 #define CSD_CALL_STATUS_WAITING			6
     85 #define CSD_CALL_STATUS_ANSWERED		7
     86 #define CSD_CALL_STATUS_ACTIVE			8
     87 #define CSD_CALL_STATUS_MO_RELEASE		9
     88 #define CSD_CALL_STATUS_MT_RELEASE		10
     89 #define CSD_CALL_STATUS_HOLD_INITIATED		11
     90 #define CSD_CALL_STATUS_HOLD			12
     91 #define CSD_CALL_STATUS_RETRIEVE_INITIATED	13
     92 #define CSD_CALL_STATUS_RECONNECT_PENDING	14
     93 #define CSD_CALL_STATUS_TERMINATED		15
     94 #define CSD_CALL_STATUS_SWAP_INITIATED		16
     95 
     96 #define CALL_FLAG_NONE				0
     97 #define CALL_FLAG_PRESENTATION_ALLOWED		0x01
     98 #define CALL_FLAG_PRESENTATION_RESTRICTED	0x02
     99 
    100 /* SIM Phonebook D-Bus definitions */
    101 #define CSD_SIMPB_BUS_NAME			"com.nokia.csd.SIM"
    102 #define CSD_SIMPB_INTERFACE			"com.nokia.csd.SIM.Phonebook"
    103 #define CSD_SIMPB_PATH				"/com/nokia/csd/sim/phonebook"
    104 
    105 #define CSD_SIMPB_TYPE_ADN			"ADN"
    106 #define CSD_SIMPB_TYPE_FDN			"FDN"
    107 #define CSD_SIMPB_TYPE_SDN			"SDN"
    108 #define CSD_SIMPB_TYPE_VMBX			"VMBX"
    109 #define CSD_SIMPB_TYPE_MBDN			"MBDN"
    110 #define CSD_SIMPB_TYPE_EN			"EN"
    111 #define CSD_SIMPB_TYPE_MSISDN			"MSISDN"
    112 
    113 struct csd_call {
    114 	char *object_path;
    115 	int status;
    116 	gboolean originating;
    117 	gboolean emergency;
    118 	gboolean on_hold;
    119 	gboolean conference;
    120 	char *number;
    121 	gboolean setup;
    122 };
    123 
    124 static struct {
    125 	char *operator_name;
    126 	uint8_t status;
    127 	int32_t signal_bars;
    128 } net = {
    129 	.operator_name = NULL,
    130 	.status = NETWORK_REG_STATUS_UNKOWN,
    131 	/* Init as 0 meaning inactive mode. In modem power off state
    132 	 * can be be -1, but we treat all values as 0s regardless
    133 	 * inactive or power off. */
    134 	.signal_bars = 0,
    135 };
    136 
    137 struct pending_req {
    138 	DBusPendingCall *call;
    139 	void *user_data;
    140 };
    141 
    142 static int get_property(const char *iface, const char *prop);
    143 
    144 static DBusConnection *connection = NULL;
    145 
    146 static GSList *calls = NULL;
    147 static GSList *watches = NULL;
    148 static GSList *pending = NULL;
    149 
    150 /* Reference count for determining the call indicator status */
    151 static GSList *active_calls = NULL;
    152 
    153 static char *msisdn = NULL;	/* Subscriber number */
    154 static char *vmbx = NULL;	/* Voice mailbox number */
    155 
    156 /* HAL battery namespace key values */
    157 static int battchg_cur = -1;	/* "battery.charge_level.current" */
    158 static int battchg_last = -1;	/* "battery.charge_level.last_full" */
    159 static int battchg_design = -1;	/* "battery.charge_level.design" */
    160 
    161 static gboolean get_calls_active = FALSE;
    162 
    163 static gboolean events_enabled = FALSE;
    164 
    165 /* Supported set of call hold operations */
    166 static const char *chld_str = "0,1,1x,2,2x,3,4";
    167 
    168 /* Timer for tracking call creation requests */
    169 static guint create_request_timer = 0;
    170 
    171 static struct indicator maemo_indicators[] =
    172 {
    173 	{ "battchg",	"0-5",	5,	TRUE },
    174 	/* signal strength in terms of bars */
    175 	{ "signal",	"0-5",	0,	TRUE },
    176 	{ "service",	"0,1",	0,	TRUE },
    177 	{ "call",	"0,1",	0,	TRUE },
    178 	{ "callsetup",	"0-3",	0,	TRUE },
    179 	{ "callheld",	"0-2",	0,	FALSE },
    180 	{ "roam",	"0,1",	0,	TRUE },
    181 	{ NULL }
    182 };
    183 
    184 static char *call_status_str[] = {
    185 	"IDLE",
    186 	"CREATE",
    187 	"COMING",
    188 	"PROCEEDING",
    189 	"MO_ALERTING",
    190 	"MT_ALERTING",
    191 	"WAITING",
    192 	"ANSWERED",
    193 	"ACTIVE",
    194 	"MO_RELEASE",
    195 	"MT_RELEASE",
    196 	"HOLD_INITIATED",
    197 	"HOLD",
    198 	"RETRIEVE_INITIATED",
    199 	"RECONNECT_PENDING",
    200 	"TERMINATED",
    201 	"SWAP_INITIATED",
    202 	"???"
    203 };
    204 
    205 static struct csd_call *find_call(const char *path)
    206 {
    207 	GSList *l;
    208 
    209 	for (l = calls; l != NULL; l = l->next) {
    210 		struct csd_call *call = l->data;
    211 
    212 		if (g_str_equal(call->object_path, path))
    213 			return call;
    214 	}
    215 
    216 	return NULL;
    217 }
    218 
    219 static struct csd_call *find_non_held_call(void)
    220 {
    221 	GSList *l;
    222 
    223 	for (l = calls; l != NULL; l = l->next) {
    224 		struct csd_call *call = l->data;
    225 
    226 		if (call->status == CSD_CALL_STATUS_IDLE)
    227 			continue;
    228 
    229 		if (call->status != CSD_CALL_STATUS_HOLD)
    230 			return call;
    231 	}
    232 
    233 	return NULL;
    234 }
    235 
    236 static struct csd_call *find_non_idle_call(void)
    237 {
    238 	GSList *l;
    239 
    240 	for (l = calls; l != NULL; l = l->next) {
    241 		struct csd_call *call = l->data;
    242 
    243 		if (call->status != CSD_CALL_STATUS_IDLE)
    244 			return call;
    245 	}
    246 
    247 	return NULL;
    248 }
    249 
    250 static struct csd_call *find_call_with_status(int status)
    251 {
    252 	GSList *l;
    253 
    254 	for (l = calls; l != NULL; l = l->next) {
    255 		struct csd_call *call = l->data;
    256 
    257 		if (call->status == status)
    258 			return call;
    259 	}
    260 
    261 	return NULL;
    262 }
    263 
    264 static int release_conference(void)
    265 {
    266 	DBusMessage *msg;
    267 
    268 	DBG("telephony-maemo6: releasing conference call");
    269 
    270 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
    271 						CSD_CALL_CONFERENCE_PATH,
    272 						CSD_CALL_INSTANCE,
    273 						"Release");
    274 	if (!msg) {
    275 		error("Unable to allocate new D-Bus message");
    276 		return -ENOMEM;
    277 	}
    278 
    279 	g_dbus_send_message(connection, msg);
    280 
    281 	return 0;
    282 }
    283 
    284 static int release_call(struct csd_call *call)
    285 {
    286 	DBusMessage *msg;
    287 
    288 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
    289 						call->object_path,
    290 						CSD_CALL_INSTANCE,
    291 						"Release");
    292 	if (!msg) {
    293 		error("Unable to allocate new D-Bus message");
    294 		return -ENOMEM;
    295 	}
    296 
    297 	g_dbus_send_message(connection, msg);
    298 
    299 	return 0;
    300 }
    301 
    302 static int answer_call(struct csd_call *call)
    303 {
    304 	DBusMessage *msg;
    305 
    306 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
    307 						call->object_path,
    308 						CSD_CALL_INSTANCE,
    309 						"Answer");
    310 	if (!msg) {
    311 		error("Unable to allocate new D-Bus message");
    312 		return -ENOMEM;
    313 	}
    314 
    315 	g_dbus_send_message(connection, msg);
    316 
    317 	return 0;
    318 }
    319 
    320 static int split_call(struct csd_call *call)
    321 {
    322 	DBusMessage *msg;
    323 
    324 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
    325 						call->object_path,
    326 						CSD_CALL_INSTANCE,
    327 						"Split");
    328 	if (!msg) {
    329 		error("Unable to allocate new D-Bus message");
    330 		return -ENOMEM;
    331 	}
    332 
    333 	g_dbus_send_message(connection, msg);
    334 
    335 	return 0;
    336 }
    337 
    338 static int unhold_call(struct csd_call *call)
    339 {
    340 	DBusMessage *msg;
    341 
    342 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    343 						CSD_CALL_INTERFACE,
    344 						"Unhold");
    345 	if (!msg) {
    346 		error("Unable to allocate new D-Bus message");
    347 		return -ENOMEM;
    348 	}
    349 
    350 	g_dbus_send_message(connection, msg);
    351 
    352 	return 0;
    353 }
    354 
    355 static int hold_call(struct csd_call *call)
    356 {
    357 	DBusMessage *msg;
    358 
    359 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    360 						CSD_CALL_INTERFACE,
    361 						"Hold");
    362 	if (!msg) {
    363 		error("Unable to allocate new D-Bus message");
    364 		return -ENOMEM;
    365 	}
    366 
    367 	g_dbus_send_message(connection, msg);
    368 
    369 	return 0;
    370 }
    371 
    372 static int swap_calls(void)
    373 {
    374 	DBusMessage *msg;
    375 
    376 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    377 						CSD_CALL_INTERFACE,
    378 						"Swap");
    379 	if (!msg) {
    380 		error("Unable to allocate new D-Bus message");
    381 		return -ENOMEM;
    382 	}
    383 
    384 	g_dbus_send_message(connection, msg);
    385 
    386 	return 0;
    387 }
    388 
    389 static int create_conference(void)
    390 {
    391 	DBusMessage *msg;
    392 
    393 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    394 						CSD_CALL_INTERFACE,
    395 						"Conference");
    396 	if (!msg) {
    397 		error("Unable to allocate new D-Bus message");
    398 		return -ENOMEM;
    399 	}
    400 
    401 	g_dbus_send_message(connection, msg);
    402 
    403 	return 0;
    404 }
    405 
    406 static int call_transfer(void)
    407 {
    408 	DBusMessage *msg;
    409 
    410 	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    411 						CSD_CALL_INTERFACE,
    412 						"Transfer");
    413 	if (!msg) {
    414 		error("Unable to allocate new D-Bus message");
    415 		return -ENOMEM;
    416 	}
    417 
    418 	g_dbus_send_message(connection, msg);
    419 
    420 	return 0;
    421 }
    422 
    423 static int number_type(const char *number)
    424 {
    425 	if (number == NULL)
    426 		return NUMBER_TYPE_TELEPHONY;
    427 
    428 	if (number[0] == '+' || strncmp(number, "00", 2) == 0)
    429 		return NUMBER_TYPE_INTERNATIONAL;
    430 
    431 	return NUMBER_TYPE_TELEPHONY;
    432 }
    433 
    434 void telephony_device_connected(void *telephony_device)
    435 {
    436 	struct csd_call *coming;
    437 
    438 	DBG("telephony-maemo6: device %p connected", telephony_device);
    439 
    440 	coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
    441 	if (coming) {
    442 		if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
    443 			telephony_call_waiting_ind(coming->number,
    444 						number_type(coming->number));
    445 		else
    446 			telephony_incoming_call_ind(coming->number,
    447 						number_type(coming->number));
    448 	}
    449 }
    450 
    451 static void pending_req_finalize(struct pending_req *req)
    452 {
    453 	if (!dbus_pending_call_get_completed(req->call))
    454 		dbus_pending_call_cancel(req->call);
    455 
    456 	dbus_pending_call_unref(req->call);
    457 	g_free(req);
    458 }
    459 
    460 static void remove_pending_by_data(gpointer data, gpointer user_data)
    461 {
    462 	struct pending_req *req = data;
    463 
    464 	if (req->user_data == user_data) {
    465 		pending = g_slist_remove(pending, req);
    466 		pending_req_finalize(req);
    467 	}
    468 }
    469 
    470 void telephony_device_disconnected(void *telephony_device)
    471 {
    472 	DBG("telephony-maemo6: device %p disconnected", telephony_device);
    473 	events_enabled = FALSE;
    474 
    475 	g_slist_foreach(pending, remove_pending_by_data, telephony_device);
    476 }
    477 
    478 void telephony_event_reporting_req(void *telephony_device, int ind)
    479 {
    480 	events_enabled = ind == 1 ? TRUE : FALSE;
    481 
    482 	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
    483 }
    484 
    485 void telephony_response_and_hold_req(void *telephony_device, int rh)
    486 {
    487 	telephony_response_and_hold_rsp(telephony_device,
    488 						CME_ERROR_NOT_SUPPORTED);
    489 }
    490 
    491 void telephony_terminate_call_req(void *telephony_device)
    492 {
    493 	struct csd_call *call;
    494 	struct csd_call *alerting;
    495 	int err;
    496 
    497 	call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
    498 	if (!call)
    499 		call = find_non_idle_call();
    500 
    501 	if (!call) {
    502 		error("No active call");
    503 		telephony_terminate_call_rsp(telephony_device,
    504 						CME_ERROR_NOT_ALLOWED);
    505 		return;
    506 	}
    507 
    508 	alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING);
    509 	if (call->on_hold && alerting)
    510 		err = release_call(alerting);
    511 	else if (call->conference)
    512 		err = release_conference();
    513 	else
    514 		err = release_call(call);
    515 
    516 	if (err < 0)
    517 		telephony_terminate_call_rsp(telephony_device,
    518 						CME_ERROR_AG_FAILURE);
    519 	else
    520 		telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
    521 }
    522 
    523 void telephony_answer_call_req(void *telephony_device)
    524 {
    525 	struct csd_call *call;
    526 
    527 	call = find_call_with_status(CSD_CALL_STATUS_COMING);
    528 	if (!call)
    529 		call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
    530 
    531 	if (!call)
    532 		call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
    533 
    534 	if (!call)
    535 		call = find_call_with_status(CSD_CALL_STATUS_WAITING);
    536 
    537 	if (!call) {
    538 		telephony_answer_call_rsp(telephony_device,
    539 						CME_ERROR_NOT_ALLOWED);
    540 		return;
    541 	}
    542 
    543 	if (answer_call(call) < 0)
    544 		telephony_answer_call_rsp(telephony_device,
    545 						CME_ERROR_AG_FAILURE);
    546 	else
    547 		telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
    548 }
    549 
    550 static int send_method_call(const char *dest, const char *path,
    551 				const char *interface, const char *method,
    552 				DBusPendingCallNotifyFunction cb,
    553 				void *user_data, int type, ...)
    554 {
    555 	DBusMessage *msg;
    556 	DBusPendingCall *call;
    557 	va_list args;
    558 	struct pending_req *req;
    559 
    560 	msg = dbus_message_new_method_call(dest, path, interface, method);
    561 	if (!msg) {
    562 		error("Unable to allocate new D-Bus %s message", method);
    563 		return -ENOMEM;
    564 	}
    565 
    566 	va_start(args, type);
    567 
    568 	if (!dbus_message_append_args_valist(msg, type, args)) {
    569 		dbus_message_unref(msg);
    570 		va_end(args);
    571 		return -EIO;
    572 	}
    573 
    574 	va_end(args);
    575 
    576 	if (!cb) {
    577 		g_dbus_send_message(connection, msg);
    578 		return 0;
    579 	}
    580 
    581 	if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
    582 		error("Sending %s failed", method);
    583 		dbus_message_unref(msg);
    584 		return -EIO;
    585 	}
    586 
    587 	dbus_pending_call_set_notify(call, cb, user_data, NULL);
    588 
    589 	req = g_new0(struct pending_req, 1);
    590 	req->call = call;
    591 	req->user_data = user_data;
    592 
    593 	pending = g_slist_prepend(pending, req);
    594 	dbus_message_unref(msg);
    595 
    596 	return 0;
    597 }
    598 
    599 static struct pending_req *find_request(const DBusPendingCall *call)
    600 {
    601 	GSList *l;
    602 
    603 	for (l = pending; l; l = l->next) {
    604 		struct pending_req *req = l->data;
    605 
    606 		if (req->call == call)
    607 			return req;
    608 	}
    609 
    610 	return NULL;
    611 }
    612 
    613 static void remove_pending(DBusPendingCall *call)
    614 {
    615 	struct pending_req *req = find_request(call);
    616 
    617 	pending = g_slist_remove(pending, req);
    618 	pending_req_finalize(req);
    619 }
    620 
    621 static void create_call_reply(DBusPendingCall *call, void *user_data)
    622 {
    623 	DBusError err;
    624 	DBusMessage *reply;
    625 	void *telephony_device = user_data;
    626 
    627 	reply = dbus_pending_call_steal_reply(call);
    628 
    629 	dbus_error_init(&err);
    630 	if (dbus_set_error_from_message(&err, reply)) {
    631 		error("csd replied with an error: %s, %s",
    632 				err.name, err.message);
    633 		if (g_strcmp0(err.name,
    634 				"com.nokia.csd.Call.Error.CSInactive") == 0)
    635 			telephony_dial_number_rsp(telephony_device,
    636 						CME_ERROR_NO_NETWORK_SERVICE);
    637 		else
    638 			telephony_dial_number_rsp(telephony_device,
    639 							CME_ERROR_AG_FAILURE);
    640 		dbus_error_free(&err);
    641 	} else
    642 		telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
    643 
    644 	dbus_message_unref(reply);
    645 	remove_pending(call);
    646 }
    647 
    648 void telephony_last_dialed_number_req(void *telephony_device)
    649 {
    650 	int ret;
    651 
    652 	DBG("telephony-maemo6: last dialed number request");
    653 
    654 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    655 				CSD_CALL_INTERFACE, "CreateFromLast",
    656 				create_call_reply, telephony_device,
    657 				DBUS_TYPE_INVALID);
    658 	if (ret < 0)
    659 		telephony_dial_number_rsp(telephony_device,
    660 						CME_ERROR_AG_FAILURE);
    661 }
    662 
    663 static const char *memory_dial_lookup(int location)
    664 {
    665 	if (location == 1)
    666 		return vmbx;
    667 	else
    668 		return NULL;
    669 }
    670 
    671 void telephony_dial_number_req(void *telephony_device, const char *number)
    672 {
    673 	int ret;
    674 
    675 	DBG("telephony-maemo6: dial request to %s", number);
    676 
    677 	if (strncmp(number, "*31#", 4) == 0)
    678 		number += 4;
    679 	else if (strncmp(number, "#31#", 4) == 0)
    680 		number += 4;
    681 	else if (number[0] == '>') {
    682 		const char *location = &number[1];
    683 
    684 		number = memory_dial_lookup(strtol(&number[1], NULL, 0));
    685 		if (!number) {
    686 			error("No number at memory location %s", location);
    687 			telephony_dial_number_rsp(telephony_device,
    688 						CME_ERROR_INVALID_INDEX);
    689 			return;
    690 		}
    691 	}
    692 
    693 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    694 				CSD_CALL_INTERFACE, "Create",
    695 				create_call_reply, telephony_device,
    696 				DBUS_TYPE_STRING, &number,
    697 				DBUS_TYPE_INVALID);
    698 	if (ret < 0)
    699 		telephony_dial_number_rsp(telephony_device,
    700 						CME_ERROR_AG_FAILURE);
    701 }
    702 
    703 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
    704 {
    705 	int ret;
    706 	char buf[2] = { tone, '\0' }, *buf_ptr = buf;
    707 
    708 	DBG("telephony-maemo6: transmit dtmf: %s", buf);
    709 
    710 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
    711 				CSD_CALL_INTERFACE, "SendDTMF",
    712 				NULL, NULL,
    713 				DBUS_TYPE_STRING, &buf_ptr,
    714 				DBUS_TYPE_INVALID);
    715 	if (ret < 0) {
    716 		telephony_transmit_dtmf_rsp(telephony_device,
    717 						CME_ERROR_AG_FAILURE);
    718 		return;
    719 	}
    720 
    721 	telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
    722 }
    723 
    724 void telephony_subscriber_number_req(void *telephony_device)
    725 {
    726 	DBG("telephony-maemo6: subscriber number request");
    727 	if (msisdn)
    728 		telephony_subscriber_number_ind(msisdn,
    729 						number_type(msisdn),
    730 						SUBSCRIBER_SERVICE_VOICE);
    731 	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
    732 }
    733 
    734 static int csd_status_to_hfp(struct csd_call *call)
    735 {
    736 	switch (call->status) {
    737 	case CSD_CALL_STATUS_IDLE:
    738 	case CSD_CALL_STATUS_MO_RELEASE:
    739 	case CSD_CALL_STATUS_MT_RELEASE:
    740 	case CSD_CALL_STATUS_TERMINATED:
    741 		return -1;
    742 	case CSD_CALL_STATUS_CREATE:
    743 		return CALL_STATUS_DIALING;
    744 	case CSD_CALL_STATUS_WAITING:
    745 		return CALL_STATUS_WAITING;
    746 	case CSD_CALL_STATUS_PROCEEDING:
    747 		/* PROCEEDING can happen in outgoing/incoming */
    748 		if (call->originating)
    749 			return CALL_STATUS_DIALING;
    750 		else
    751 			return CALL_STATUS_INCOMING;
    752 	case CSD_CALL_STATUS_COMING:
    753 		return CALL_STATUS_INCOMING;
    754 	case CSD_CALL_STATUS_MO_ALERTING:
    755 		return CALL_STATUS_ALERTING;
    756 	case CSD_CALL_STATUS_MT_ALERTING:
    757 		return CALL_STATUS_INCOMING;
    758 	case CSD_CALL_STATUS_ANSWERED:
    759 	case CSD_CALL_STATUS_ACTIVE:
    760 	case CSD_CALL_STATUS_RECONNECT_PENDING:
    761 	case CSD_CALL_STATUS_SWAP_INITIATED:
    762 	case CSD_CALL_STATUS_HOLD_INITIATED:
    763 		return CALL_STATUS_ACTIVE;
    764 	case CSD_CALL_STATUS_RETRIEVE_INITIATED:
    765 	case CSD_CALL_STATUS_HOLD:
    766 		return CALL_STATUS_HELD;
    767 	default:
    768 		return -1;
    769 	}
    770 }
    771 
    772 void telephony_list_current_calls_req(void *telephony_device)
    773 {
    774 	GSList *l;
    775 	int i;
    776 
    777 	DBG("telephony-maemo6: list current calls request");
    778 
    779 	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
    780 		struct csd_call *call = l->data;
    781 		int status, direction, multiparty;
    782 
    783 		status = csd_status_to_hfp(call);
    784 		if (status < 0)
    785 			continue;
    786 
    787 		direction = call->originating ?
    788 				CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
    789 
    790 		multiparty = call->conference ?
    791 				CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
    792 
    793 		telephony_list_current_call_ind(i, direction, status,
    794 						CALL_MODE_VOICE, multiparty,
    795 						call->number,
    796 						number_type(call->number));
    797 	}
    798 
    799 	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
    800 }
    801 
    802 void telephony_operator_selection_req(void *telephony_device)
    803 {
    804 	telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
    805 				net.operator_name ? net.operator_name : "");
    806 	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
    807 }
    808 
    809 static void foreach_call_with_status(int status,
    810 					int (*func)(struct csd_call *call))
    811 {
    812 	GSList *l;
    813 
    814 	for (l = calls; l != NULL; l = l->next) {
    815 		struct csd_call *call = l->data;
    816 
    817 		if (call->status == status)
    818 			func(call);
    819 	}
    820 }
    821 
    822 void telephony_call_hold_req(void *telephony_device, const char *cmd)
    823 {
    824 	const char *idx;
    825 	struct csd_call *call;
    826 	int err = 0;
    827 
    828 	DBG("telephony-maemo6: got call hold request %s", cmd);
    829 
    830 	if (strlen(cmd) > 1)
    831 		idx = &cmd[1];
    832 	else
    833 		idx = NULL;
    834 
    835 	if (idx)
    836 		call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
    837 	else
    838 		call = NULL;
    839 
    840 	switch (cmd[0]) {
    841 	case '0':
    842 		if (find_call_with_status(CSD_CALL_STATUS_WAITING))
    843 			foreach_call_with_status(CSD_CALL_STATUS_WAITING,
    844 								release_call);
    845 		else
    846 			foreach_call_with_status(CSD_CALL_STATUS_HOLD,
    847 								release_call);
    848 		break;
    849 	case '1':
    850 		if (idx) {
    851 			if (call)
    852 				err = release_call(call);
    853 			break;
    854 		}
    855 		foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
    856 		call = find_call_with_status(CSD_CALL_STATUS_WAITING);
    857 		if (call)
    858 			err = answer_call(call);
    859 		break;
    860 	case '2':
    861 		if (idx) {
    862 			if (call)
    863 				err = split_call(call);
    864 		} else {
    865 			struct csd_call *held, *wait;
    866 
    867 			call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
    868 			held = find_call_with_status(CSD_CALL_STATUS_HOLD);
    869 			wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
    870 
    871 			if (wait)
    872 				err = answer_call(wait);
    873 			else if (call && held)
    874 				err = swap_calls();
    875 			else {
    876 				if (call)
    877 					err = hold_call(call);
    878 				if (held)
    879 					err = unhold_call(held);
    880 			}
    881 		}
    882 		break;
    883 	case '3':
    884 		if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
    885 				find_call_with_status(CSD_CALL_STATUS_WAITING))
    886 			err = create_conference();
    887 		break;
    888 	case '4':
    889 		err = call_transfer();
    890 		break;
    891 	default:
    892 		DBG("Unknown call hold request");
    893 		break;
    894 	}
    895 
    896 	if (err)
    897 		telephony_call_hold_rsp(telephony_device,
    898 					CME_ERROR_AG_FAILURE);
    899 	else
    900 		telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
    901 }
    902 
    903 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
    904 {
    905 	DBG("telephony-maemo6: got %s NR and EC request",
    906 			enable ? "enable" : "disable");
    907 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
    908 }
    909 
    910 void telephony_key_press_req(void *telephony_device, const char *keys)
    911 {
    912 	struct csd_call *active, *waiting;
    913 	int err;
    914 
    915 	DBG("telephony-maemo6: got key press request for %s", keys);
    916 
    917 	waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
    918 	if (!waiting)
    919 		waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
    920 	if (!waiting)
    921 		waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
    922 
    923 	active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
    924 
    925 	if (waiting)
    926 		err = answer_call(waiting);
    927 	else if (active)
    928 		err = release_call(active);
    929 	else
    930 		err = 0;
    931 
    932 	if (err < 0)
    933 		telephony_key_press_rsp(telephony_device,
    934 							CME_ERROR_AG_FAILURE);
    935 	else
    936 		telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
    937 }
    938 
    939 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
    940 {
    941 	DBG("telephony-maemo6: got %s voice dial request",
    942 			enable ? "enable" : "disable");
    943 
    944 	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
    945 }
    946 
    947 static void handle_incoming_call(DBusMessage *msg)
    948 {
    949 	const char *number, *call_path;
    950 	struct csd_call *call;
    951 
    952 	if (!dbus_message_get_args(msg, NULL,
    953 					DBUS_TYPE_OBJECT_PATH, &call_path,
    954 					DBUS_TYPE_STRING, &number,
    955 					DBUS_TYPE_INVALID)) {
    956 		error("Unexpected parameters in Call.Coming() signal");
    957 		return;
    958 	}
    959 
    960 	call = find_call(call_path);
    961 	if (!call) {
    962 		error("Didn't find any matching call object for %s",
    963 				call_path);
    964 		return;
    965 	}
    966 
    967 	DBG("Incoming call to %s from number %s", call_path, number);
    968 
    969 	g_free(call->number);
    970 	call->number = g_strdup(number);
    971 
    972 	if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
    973 			find_call_with_status(CSD_CALL_STATUS_HOLD))
    974 		telephony_call_waiting_ind(call->number,
    975 						number_type(call->number));
    976 	else
    977 		telephony_incoming_call_ind(call->number,
    978 						number_type(call->number));
    979 
    980 	telephony_update_indicator(maemo_indicators, "callsetup",
    981 					EV_CALLSETUP_INCOMING);
    982 }
    983 
    984 static void handle_outgoing_call(DBusMessage *msg)
    985 {
    986 	const char *number, *call_path;
    987 	struct csd_call *call;
    988 
    989 	if (!dbus_message_get_args(msg, NULL,
    990 					DBUS_TYPE_OBJECT_PATH, &call_path,
    991 					DBUS_TYPE_STRING, &number,
    992 					DBUS_TYPE_INVALID)) {
    993 		error("Unexpected parameters in Call.Created() signal");
    994 		return;
    995 	}
    996 
    997 	call = find_call(call_path);
    998 	if (!call) {
    999 		error("Didn't find any matching call object for %s",
   1000 				call_path);
   1001 		return;
   1002 	}
   1003 
   1004 	DBG("Outgoing call from %s to number %s", call_path, number);
   1005 
   1006 	g_free(call->number);
   1007 	call->number = g_strdup(number);
   1008 
   1009 	if (create_request_timer) {
   1010 		g_source_remove(create_request_timer);
   1011 		create_request_timer = 0;
   1012 	}
   1013 }
   1014 
   1015 static gboolean create_timeout(gpointer user_data)
   1016 {
   1017 	telephony_update_indicator(maemo_indicators, "callsetup",
   1018 					EV_CALLSETUP_INACTIVE);
   1019 	create_request_timer = 0;
   1020 	return FALSE;
   1021 }
   1022 
   1023 static void handle_create_requested(DBusMessage *msg)
   1024 {
   1025 	DBG("Call.CreateRequested()");
   1026 
   1027 	if (create_request_timer)
   1028 		g_source_remove(create_request_timer);
   1029 
   1030 	create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
   1031 
   1032 	telephony_update_indicator(maemo_indicators, "callsetup",
   1033 					EV_CALLSETUP_OUTGOING);
   1034 }
   1035 
   1036 static void call_set_status(struct csd_call *call, dbus_uint32_t status)
   1037 {
   1038 	dbus_uint32_t prev_status;
   1039 	int callheld = telephony_get_indicator(maemo_indicators, "callheld");
   1040 
   1041 	prev_status = call->status;
   1042 	DBG("Call %s changed from %s to %s", call->object_path,
   1043 		call_status_str[prev_status], call_status_str[status]);
   1044 
   1045 	if (prev_status == status) {
   1046 		DBG("Ignoring CSD Call state change to existing state");
   1047 		return;
   1048 	}
   1049 
   1050 	call->status = (int) status;
   1051 
   1052 	switch (status) {
   1053 	case CSD_CALL_STATUS_IDLE:
   1054 		if (call->setup) {
   1055 			telephony_update_indicator(maemo_indicators,
   1056 							"callsetup",
   1057 							EV_CALLSETUP_INACTIVE);
   1058 			if (!call->originating)
   1059 				telephony_calling_stopped_ind();
   1060 		}
   1061 
   1062 		g_free(call->number);
   1063 		call->number = NULL;
   1064 		call->originating = FALSE;
   1065 		call->emergency = FALSE;
   1066 		call->on_hold = FALSE;
   1067 		call->conference = FALSE;
   1068 		call->setup = FALSE;
   1069 		break;
   1070 	case CSD_CALL_STATUS_CREATE:
   1071 		call->originating = TRUE;
   1072 		call->setup = TRUE;
   1073 		break;
   1074 	case CSD_CALL_STATUS_COMING:
   1075 		call->originating = FALSE;
   1076 		call->setup = TRUE;
   1077 		break;
   1078 	case CSD_CALL_STATUS_PROCEEDING:
   1079 		break;
   1080 	case CSD_CALL_STATUS_MO_ALERTING:
   1081 		telephony_update_indicator(maemo_indicators, "callsetup",
   1082 						EV_CALLSETUP_ALERTING);
   1083 		break;
   1084 	case CSD_CALL_STATUS_MT_ALERTING:
   1085 		/* Some headsets expect incoming call notification before they
   1086 		 * can send ATA command. When call changed status from waiting
   1087 		 * to alerting we need to send missing notification. Otherwise
   1088 		 * headsets like Nokia BH-108 or BackBeat 903 are unable to
   1089 		 * answer incoming call that was previously waiting. */
   1090 		if (prev_status == CSD_CALL_STATUS_WAITING)
   1091 			telephony_incoming_call_ind(call->number,
   1092 						number_type(call->number));
   1093 		break;
   1094 	case CSD_CALL_STATUS_WAITING:
   1095 		break;
   1096 	case CSD_CALL_STATUS_ANSWERED:
   1097 		break;
   1098 	case CSD_CALL_STATUS_ACTIVE:
   1099 		if (call->on_hold) {
   1100 			call->on_hold = FALSE;
   1101 			if (find_call_with_status(CSD_CALL_STATUS_HOLD))
   1102 				telephony_update_indicator(maemo_indicators,
   1103 							"callheld",
   1104 							EV_CALLHELD_MULTIPLE);
   1105 			else
   1106 				telephony_update_indicator(maemo_indicators,
   1107 							"callheld",
   1108 							EV_CALLHELD_NONE);
   1109 		} else {
   1110 			if (!g_slist_find(active_calls, call))
   1111 				active_calls = g_slist_prepend(active_calls, call);
   1112 			if (g_slist_length(active_calls) == 1)
   1113 				telephony_update_indicator(maemo_indicators,
   1114 								"call",
   1115 								EV_CALL_ACTIVE);
   1116 			/* Upgrade callheld status if necessary */
   1117 			if (callheld == EV_CALLHELD_ON_HOLD)
   1118 				telephony_update_indicator(maemo_indicators,
   1119 							"callheld",
   1120 							EV_CALLHELD_MULTIPLE);
   1121 			telephony_update_indicator(maemo_indicators,
   1122 							"callsetup",
   1123 							EV_CALLSETUP_INACTIVE);
   1124 			if (!call->originating)
   1125 				telephony_calling_stopped_ind();
   1126 			call->setup = FALSE;
   1127 		}
   1128 		break;
   1129 	case CSD_CALL_STATUS_MO_RELEASE:
   1130 	case CSD_CALL_STATUS_MT_RELEASE:
   1131 		active_calls = g_slist_remove(active_calls, call);
   1132 		if (g_slist_length(active_calls) == 0)
   1133 			telephony_update_indicator(maemo_indicators, "call",
   1134 							EV_CALL_INACTIVE);
   1135 		break;
   1136 	case CSD_CALL_STATUS_HOLD_INITIATED:
   1137 		break;
   1138 	case CSD_CALL_STATUS_HOLD:
   1139 		call->on_hold = TRUE;
   1140 		if (find_non_held_call())
   1141 			telephony_update_indicator(maemo_indicators,
   1142 							"callheld",
   1143 							EV_CALLHELD_MULTIPLE);
   1144 		else
   1145 			telephony_update_indicator(maemo_indicators,
   1146 							"callheld",
   1147 							EV_CALLHELD_ON_HOLD);
   1148 		break;
   1149 	case CSD_CALL_STATUS_RETRIEVE_INITIATED:
   1150 		break;
   1151 	case CSD_CALL_STATUS_RECONNECT_PENDING:
   1152 		break;
   1153 	case CSD_CALL_STATUS_TERMINATED:
   1154 		if (call->on_hold &&
   1155 				!find_call_with_status(CSD_CALL_STATUS_HOLD))
   1156 			telephony_update_indicator(maemo_indicators,
   1157 							"callheld",
   1158 							EV_CALLHELD_NONE);
   1159 		else if (callheld == EV_CALLHELD_MULTIPLE &&
   1160 				find_call_with_status(CSD_CALL_STATUS_HOLD))
   1161 			telephony_update_indicator(maemo_indicators,
   1162 							"callheld",
   1163 							EV_CALLHELD_ON_HOLD);
   1164 		break;
   1165 	case CSD_CALL_STATUS_SWAP_INITIATED:
   1166 		break;
   1167 	default:
   1168 		error("Unknown call status %u", status);
   1169 		break;
   1170 	}
   1171 }
   1172 
   1173 static void handle_call_status(DBusMessage *msg, const char *call_path)
   1174 {
   1175 	struct csd_call *call;
   1176 	dbus_uint32_t status, cause_type, cause;
   1177 
   1178 	if (!dbus_message_get_args(msg, NULL,
   1179 					DBUS_TYPE_UINT32, &status,
   1180 					DBUS_TYPE_UINT32, &cause_type,
   1181 					DBUS_TYPE_UINT32, &cause,
   1182 					DBUS_TYPE_INVALID)) {
   1183 		error("Unexpected paramters in Instance.CallStatus() signal");
   1184 		return;
   1185 	}
   1186 
   1187 	call = find_call(call_path);
   1188 	if (!call) {
   1189 		error("Didn't find any matching call object for %s",
   1190 				call_path);
   1191 		return;
   1192 	}
   1193 
   1194 	if (status > 16) {
   1195 		error("Invalid call status %u", status);
   1196 		return;
   1197 	}
   1198 
   1199 	call_set_status(call, status);
   1200 }
   1201 
   1202 static void handle_conference(DBusMessage *msg, gboolean joined)
   1203 {
   1204 	const char *path;
   1205 	struct csd_call *call;
   1206 
   1207 	if (!dbus_message_get_args(msg, NULL,
   1208 					DBUS_TYPE_OBJECT_PATH, &path,
   1209 					DBUS_TYPE_INVALID)) {
   1210 		error("Unexpected parameters in Conference.%s",
   1211 					dbus_message_get_member(msg));
   1212 		return;
   1213 	}
   1214 
   1215 	call = find_call(path);
   1216 	if (!call) {
   1217 		error("Conference signal for unknown call %s", path);
   1218 		return;
   1219 	}
   1220 
   1221 	DBG("Call %s %s the conference", path, joined ? "joined" : "left");
   1222 
   1223 	call->conference = joined;
   1224 }
   1225 
   1226 static uint8_t str2status(const char *state)
   1227 {
   1228 	if (g_strcmp0(state, "Home") == 0)
   1229 		return NETWORK_REG_STATUS_HOME;
   1230 	else if (g_strcmp0(state, "Roaming") == 0)
   1231 		return NETWORK_REG_STATUS_ROAMING;
   1232 	else if (g_strcmp0(state, "Offline") == 0)
   1233 		return NETWORK_REG_STATUS_OFFLINE;
   1234 	else if (g_strcmp0(state, "Searching") == 0)
   1235 		return NETWORK_REG_STATUS_SEARCHING;
   1236 	else if (g_strcmp0(state, "NoSim") == 0)
   1237 		return NETWORK_REG_STATUS_NO_SIM;
   1238 	else if (g_strcmp0(state, "Poweroff") == 0)
   1239 		return NETWORK_REG_STATUS_POWEROFF;
   1240 	else if (g_strcmp0(state, "Powersafe") == 0)
   1241 		return NETWORK_REG_STATUS_POWERSAFE;
   1242 	else if (g_strcmp0(state, "NoCoverage") == 0)
   1243 		return NETWORK_REG_STATUS_NO_COVERAGE;
   1244 	else if (g_strcmp0(state, "Reject") == 0)
   1245 		return NETWORK_REG_STATUS_REJECTED;
   1246 	else
   1247 		return NETWORK_REG_STATUS_UNKOWN;
   1248 }
   1249 
   1250 static void update_registration_status(const char *status)
   1251 {
   1252 	uint8_t new_status;
   1253 
   1254 	new_status = str2status(status);
   1255 
   1256 	if (net.status == new_status)
   1257 		return;
   1258 
   1259 	switch (new_status) {
   1260 	case NETWORK_REG_STATUS_HOME:
   1261 		telephony_update_indicator(maemo_indicators, "roam",
   1262 							EV_ROAM_INACTIVE);
   1263 		if (net.status > NETWORK_REG_STATUS_ROAMING)
   1264 			telephony_update_indicator(maemo_indicators,
   1265 							"service",
   1266 							EV_SERVICE_PRESENT);
   1267 		break;
   1268 	case NETWORK_REG_STATUS_ROAMING:
   1269 		telephony_update_indicator(maemo_indicators, "roam",
   1270 							EV_ROAM_ACTIVE);
   1271 		if (net.status > NETWORK_REG_STATUS_ROAMING)
   1272 			telephony_update_indicator(maemo_indicators,
   1273 							"service",
   1274 							EV_SERVICE_PRESENT);
   1275 		break;
   1276 	case NETWORK_REG_STATUS_OFFLINE:
   1277 	case NETWORK_REG_STATUS_SEARCHING:
   1278 	case NETWORK_REG_STATUS_NO_SIM:
   1279 	case NETWORK_REG_STATUS_POWEROFF:
   1280 	case NETWORK_REG_STATUS_POWERSAFE:
   1281 	case NETWORK_REG_STATUS_NO_COVERAGE:
   1282 	case NETWORK_REG_STATUS_REJECTED:
   1283 	case NETWORK_REG_STATUS_UNKOWN:
   1284 		if (net.status < NETWORK_REG_STATUS_OFFLINE)
   1285 			telephony_update_indicator(maemo_indicators,
   1286 							"service",
   1287 							EV_SERVICE_NONE);
   1288 		break;
   1289 	}
   1290 
   1291 	net.status = new_status;
   1292 
   1293 	DBG("telephony-maemo6: registration status changed: %s", status);
   1294 }
   1295 
   1296 static void handle_registration_changed(DBusMessage *msg)
   1297 {
   1298 	const char *status;
   1299 
   1300 	if (!dbus_message_get_args(msg, NULL,
   1301 					DBUS_TYPE_STRING, &status,
   1302 					DBUS_TYPE_INVALID)) {
   1303 		error("Unexpected parameters in RegistrationChanged");
   1304 		return;
   1305 	}
   1306 
   1307 	update_registration_status(status);
   1308 }
   1309 
   1310 static void update_signal_strength(int32_t signal_bars)
   1311 {
   1312 	if (signal_bars < 0) {
   1313 		DBG("signal strength smaller than expected: %d < 0",
   1314 								signal_bars);
   1315 		signal_bars = 0;
   1316 	} else if (signal_bars > 5) {
   1317 		DBG("signal strength greater than expected: %d > 5",
   1318 								signal_bars);
   1319 		signal_bars = 5;
   1320 	}
   1321 
   1322 	if (net.signal_bars == signal_bars)
   1323 		return;
   1324 
   1325 	telephony_update_indicator(maemo_indicators, "signal", signal_bars);
   1326 
   1327 	net.signal_bars = signal_bars;
   1328 	DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
   1329 }
   1330 
   1331 static void handle_signal_bars_changed(DBusMessage *msg)
   1332 {
   1333 	int32_t signal_bars;
   1334 
   1335 	if (!dbus_message_get_args(msg, NULL,
   1336 					DBUS_TYPE_INT32, &signal_bars,
   1337 					DBUS_TYPE_INVALID)) {
   1338 		error("Unexpected parameters in SignalBarsChanged");
   1339 		return;
   1340 	}
   1341 
   1342 	update_signal_strength(signal_bars);
   1343 }
   1344 
   1345 static gboolean iter_get_basic_args(DBusMessageIter *iter,
   1346 					int first_arg_type, ...)
   1347 {
   1348 	int type;
   1349 	va_list ap;
   1350 
   1351 	va_start(ap, first_arg_type);
   1352 
   1353 	for (type = first_arg_type; type != DBUS_TYPE_INVALID;
   1354 			type = va_arg(ap, int)) {
   1355 		void *value = va_arg(ap, void *);
   1356 		int real_type = dbus_message_iter_get_arg_type(iter);
   1357 
   1358 		if (real_type != type) {
   1359 			error("iter_get_basic_args: expected %c but got %c",
   1360 					(char) type, (char) real_type);
   1361 			break;
   1362 		}
   1363 
   1364 		dbus_message_iter_get_basic(iter, value);
   1365 		dbus_message_iter_next(iter);
   1366 	}
   1367 
   1368 	va_end(ap);
   1369 
   1370 	return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
   1371 }
   1372 
   1373 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
   1374 {
   1375 	DBusError err;
   1376 	DBusMessage *reply;
   1377 	dbus_int32_t level;
   1378 	int *value = user_data;
   1379 
   1380 	reply = dbus_pending_call_steal_reply(call);
   1381 
   1382 	dbus_error_init(&err);
   1383 	if (dbus_set_error_from_message(&err, reply)) {
   1384 		error("hald replied with an error: %s, %s",
   1385 				err.name, err.message);
   1386 		dbus_error_free(&err);
   1387 		goto done;
   1388 	}
   1389 
   1390 	if (!dbus_message_get_args(reply, NULL,
   1391 				DBUS_TYPE_INT32, &level,
   1392 				DBUS_TYPE_INVALID)) {
   1393 		error("Unexpected args in hald reply");
   1394 		goto done;
   1395 	}
   1396 
   1397 	*value = (int) level;
   1398 
   1399 	if (value == &battchg_last)
   1400 		DBG("telephony-maemo6: battery.charge_level.last_full is %d",
   1401 				*value);
   1402 	else if (value == &battchg_design)
   1403 		DBG("telephony-maemo6: battery.charge_level.design is %d",
   1404 				*value);
   1405 	else
   1406 		DBG("telephony-maemo6: battery.charge_level.current is %d",
   1407 				*value);
   1408 
   1409 	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
   1410 		int new, max;
   1411 
   1412 		if (battchg_last > 0)
   1413 			max = battchg_last;
   1414 		else
   1415 			max = battchg_design;
   1416 
   1417 		new = battchg_cur * 5 / max;
   1418 
   1419 		telephony_update_indicator(maemo_indicators, "battchg", new);
   1420 	}
   1421 
   1422 done:
   1423 	dbus_message_unref(reply);
   1424 	remove_pending(call);
   1425 }
   1426 
   1427 static void hal_get_integer(const char *path, const char *key, void *user_data)
   1428 {
   1429 	send_method_call("org.freedesktop.Hal", path,
   1430 				"org.freedesktop.Hal.Device",
   1431 				"GetPropertyInteger",
   1432 				hal_battery_level_reply, user_data,
   1433 				DBUS_TYPE_STRING, &key,
   1434 				DBUS_TYPE_INVALID);
   1435 }
   1436 
   1437 static void handle_hal_property_modified(DBusMessage *msg)
   1438 {
   1439 	DBusMessageIter iter, array;
   1440 	dbus_int32_t num_changes;
   1441 	const char *path;
   1442 
   1443 	path = dbus_message_get_path(msg);
   1444 
   1445 	dbus_message_iter_init(msg, &iter);
   1446 
   1447 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
   1448 		error("Unexpected signature in hal PropertyModified signal");
   1449 		return;
   1450 	}
   1451 
   1452 	dbus_message_iter_get_basic(&iter, &num_changes);
   1453 	dbus_message_iter_next(&iter);
   1454 
   1455 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
   1456 		error("Unexpected signature in hal PropertyModified signal");
   1457 		return;
   1458 	}
   1459 
   1460 	dbus_message_iter_recurse(&iter, &array);
   1461 
   1462 	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
   1463 		DBusMessageIter prop;
   1464 		const char *name;
   1465 		dbus_bool_t added, removed;
   1466 
   1467 		dbus_message_iter_recurse(&array, &prop);
   1468 
   1469 		if (!iter_get_basic_args(&prop,
   1470 					DBUS_TYPE_STRING, &name,
   1471 					DBUS_TYPE_BOOLEAN, &added,
   1472 					DBUS_TYPE_BOOLEAN, &removed,
   1473 					DBUS_TYPE_INVALID)) {
   1474 			error("Invalid hal PropertyModified parameters");
   1475 			break;
   1476 		}
   1477 
   1478 		if (g_str_equal(name, "battery.charge_level.last_full"))
   1479 			hal_get_integer(path, name, &battchg_last);
   1480 		else if (g_str_equal(name, "battery.charge_level.current"))
   1481 			hal_get_integer(path, name, &battchg_cur);
   1482 		else if (g_str_equal(name, "battery.charge_level.design"))
   1483 			hal_get_integer(path, name, &battchg_design);
   1484 
   1485 		dbus_message_iter_next(&array);
   1486 	}
   1487 }
   1488 
   1489 static void csd_call_free(struct csd_call *call)
   1490 {
   1491 	if (!call)
   1492 		return;
   1493 
   1494 	g_free(call->object_path);
   1495 	g_free(call->number);
   1496 
   1497 	g_free(call);
   1498 }
   1499 
   1500 static void parse_call_list(DBusMessageIter *iter)
   1501 {
   1502 	do {
   1503 		DBusMessageIter call_iter;
   1504 		struct csd_call *call;
   1505 		const char *object_path, *number;
   1506 		dbus_uint32_t status;
   1507 		dbus_bool_t originating, terminating, emerg, on_hold, conf;
   1508 
   1509 		if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
   1510 			error("Unexpected signature in GetCallInfoAll reply");
   1511 			break;
   1512 		}
   1513 
   1514 		dbus_message_iter_recurse(iter, &call_iter);
   1515 
   1516 		if (!iter_get_basic_args(&call_iter,
   1517 					DBUS_TYPE_OBJECT_PATH, &object_path,
   1518 					DBUS_TYPE_UINT32, &status,
   1519 					DBUS_TYPE_BOOLEAN, &originating,
   1520 					DBUS_TYPE_BOOLEAN, &terminating,
   1521 					DBUS_TYPE_BOOLEAN, &emerg,
   1522 					DBUS_TYPE_BOOLEAN, &on_hold,
   1523 					DBUS_TYPE_BOOLEAN, &conf,
   1524 					DBUS_TYPE_STRING, &number,
   1525 					DBUS_TYPE_INVALID)) {
   1526 			error("Parsing call D-Bus parameters failed");
   1527 			break;
   1528 		}
   1529 
   1530 		call = find_call(object_path);
   1531 		if (!call) {
   1532 			call = g_new0(struct csd_call, 1);
   1533 			call->object_path = g_strdup(object_path);
   1534 			calls = g_slist_append(calls, call);
   1535 			DBG("telephony-maemo6: new csd call instance at %s",
   1536 								object_path);
   1537 		}
   1538 
   1539 		if (status == CSD_CALL_STATUS_IDLE)
   1540 			continue;
   1541 
   1542 		/* CSD gives incorrect call_hold property sometimes */
   1543 		if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
   1544 				(call->status == CSD_CALL_STATUS_HOLD &&
   1545 								!on_hold)) {
   1546 			error("Conflicting call status and on_hold property!");
   1547 			on_hold = call->status == CSD_CALL_STATUS_HOLD;
   1548 		}
   1549 
   1550 		call->originating = originating;
   1551 		call->on_hold = on_hold;
   1552 		call->conference = conf;
   1553 		g_free(call->number);
   1554 		call->number = g_strdup(number);
   1555 
   1556 		/* Update indicators */
   1557 		call_set_status(call, status);
   1558 
   1559 	} while (dbus_message_iter_next(iter));
   1560 }
   1561 
   1562 static void update_operator_name(const char *name)
   1563 {
   1564 	if (name == NULL)
   1565 		return;
   1566 
   1567 	g_free(net.operator_name);
   1568 	net.operator_name = g_strndup(name, 16);
   1569 	DBG("telephony-maemo6: operator name updated: %s", name);
   1570 }
   1571 
   1572 static void get_property_reply(DBusPendingCall *call, void *user_data)
   1573 {
   1574 	char *prop = user_data;
   1575 	DBusError err;
   1576 	DBusMessage *reply;
   1577 	DBusMessageIter iter, sub;
   1578 
   1579 	reply = dbus_pending_call_steal_reply(call);
   1580 
   1581 	dbus_error_init(&err);
   1582 	if (dbus_set_error_from_message(&err, reply)) {
   1583 		error("csd replied with an error: %s, %s",
   1584 				err.name, err.message);
   1585 		dbus_error_free(&err);
   1586 		goto done;
   1587 	}
   1588 
   1589 	dbus_message_iter_init(reply, &iter);
   1590 
   1591 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
   1592 		error("Unexpected signature in Get return");
   1593 		goto done;
   1594 	}
   1595 
   1596 	dbus_message_iter_recurse(&iter, &sub);
   1597 
   1598 	if (g_strcmp0(prop, "RegistrationStatus") == 0) {
   1599 		const char *status;
   1600 
   1601 		dbus_message_iter_get_basic(&sub, &status);
   1602 		update_registration_status(status);
   1603 
   1604 		get_property(CSD_CSNET_OPERATOR, "OperatorName");
   1605 		get_property(CSD_CSNET_SIGNAL, "SignalBars");
   1606 	} else if (g_strcmp0(prop, "OperatorName") == 0) {
   1607 		const char *name;
   1608 
   1609 		dbus_message_iter_get_basic(&sub, &name);
   1610 		update_operator_name(name);
   1611 	} else if (g_strcmp0(prop, "SignalBars") == 0) {
   1612 		int32_t signal_bars;
   1613 
   1614 		dbus_message_iter_get_basic(&sub, &signal_bars);
   1615 		update_signal_strength(signal_bars);
   1616 	}
   1617 
   1618 done:
   1619 	g_free(prop);
   1620 	dbus_message_unref(reply);
   1621 	remove_pending(call);
   1622 }
   1623 
   1624 static int get_property(const char *iface, const char *prop)
   1625 {
   1626 	return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
   1627 				DBUS_INTERFACE_PROPERTIES, "Get",
   1628 				get_property_reply, g_strdup(prop),
   1629 				DBUS_TYPE_STRING, &iface,
   1630 				DBUS_TYPE_STRING, &prop,
   1631 				DBUS_TYPE_INVALID);
   1632 }
   1633 
   1634 static void handle_operator_name_changed(DBusMessage *msg)
   1635 {
   1636 	const char *name;
   1637 
   1638 	if (!dbus_message_get_args(msg, NULL,
   1639 					DBUS_TYPE_STRING, &name,
   1640 					DBUS_TYPE_INVALID)) {
   1641 		error("Unexpected parameters in OperatorNameChanged");
   1642 		return;
   1643 	}
   1644 
   1645 	update_operator_name(name);
   1646 }
   1647 
   1648 static void call_info_reply(DBusPendingCall *call, void *user_data)
   1649 {
   1650 	DBusError err;
   1651 	DBusMessage *reply;
   1652 	DBusMessageIter iter, sub;;
   1653 
   1654 	get_calls_active = FALSE;
   1655 
   1656 	reply = dbus_pending_call_steal_reply(call);
   1657 
   1658 	dbus_error_init(&err);
   1659 	if (dbus_set_error_from_message(&err, reply)) {
   1660 		error("csd replied with an error: %s, %s",
   1661 				err.name, err.message);
   1662 		dbus_error_free(&err);
   1663 		goto done;
   1664 	}
   1665 
   1666 	dbus_message_iter_init(reply, &iter);
   1667 
   1668 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
   1669 		error("Unexpected signature in GetCallInfoAll return");
   1670 		goto done;
   1671 	}
   1672 
   1673 	dbus_message_iter_recurse(&iter, &sub);
   1674 
   1675 	parse_call_list(&sub);
   1676 
   1677 	get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
   1678 
   1679 done:
   1680 	dbus_message_unref(reply);
   1681 	remove_pending(call);
   1682 }
   1683 
   1684 
   1685 static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
   1686 {
   1687 	DBusError derr;
   1688 	DBusMessage *reply;
   1689 	const char *name, *number, *secondname, *additionalnumber, *email;
   1690 	int index;
   1691 	char **number_type = user_data;
   1692 
   1693 	reply = dbus_pending_call_steal_reply(call);
   1694 
   1695 	dbus_error_init(&derr);
   1696 	if (dbus_set_error_from_message(&derr, reply)) {
   1697 		error("%s.ReadFirst replied with an error: %s, %s",
   1698 				CSD_SIMPB_INTERFACE, derr.name, derr.message);
   1699 		dbus_error_free(&derr);
   1700 		if (number_type == &vmbx)
   1701 			vmbx = g_strdup(getenv("VMBX_NUMBER"));
   1702 		goto done;
   1703 	}
   1704 
   1705 	dbus_error_init(&derr);
   1706 	if (dbus_message_get_args(reply, NULL,
   1707 				DBUS_TYPE_INT32, &index,
   1708 				DBUS_TYPE_STRING, &name,
   1709 				DBUS_TYPE_STRING, &number,
   1710 				DBUS_TYPE_STRING, &secondname,
   1711 				DBUS_TYPE_STRING, &additionalnumber,
   1712 				DBUS_TYPE_STRING, &email,
   1713 				DBUS_TYPE_INVALID) == FALSE) {
   1714 		error("Unable to parse %s.ReadFirst arguments: %s, %s",
   1715 				CSD_SIMPB_INTERFACE, derr.name, derr.message);
   1716 		dbus_error_free(&derr);
   1717 		goto done;
   1718 	}
   1719 
   1720 	if (number_type == &msisdn) {
   1721 		g_free(msisdn);
   1722 		msisdn = g_strdup(number);
   1723 		DBG("Got MSISDN %s (%s)", number, name);
   1724 	} else {
   1725 		g_free(vmbx);
   1726 		vmbx = g_strdup(number);
   1727 		DBG("Got voice mailbox number %s (%s)", number, name);
   1728 	}
   1729 
   1730 done:
   1731 	dbus_message_unref(reply);
   1732 	remove_pending(call);
   1733 }
   1734 
   1735 static void csd_init(void)
   1736 {
   1737 	const char *pb_type;
   1738 	int ret;
   1739 
   1740 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
   1741 				CSD_CALL_INTERFACE, "GetCallInfoAll",
   1742 				call_info_reply, NULL, DBUS_TYPE_INVALID);
   1743 	if (ret < 0) {
   1744 		error("Unable to sent GetCallInfoAll method call");
   1745 		return;
   1746 	}
   1747 
   1748 	get_calls_active = TRUE;
   1749 
   1750 	pb_type = CSD_SIMPB_TYPE_MSISDN;
   1751 
   1752 	ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
   1753 				CSD_SIMPB_INTERFACE, "ReadFirst",
   1754 				phonebook_read_reply, &msisdn,
   1755 				DBUS_TYPE_STRING, &pb_type,
   1756 				DBUS_TYPE_INVALID);
   1757 	if (ret < 0) {
   1758 		error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
   1759 		return;
   1760 	}
   1761 
   1762 	/* Voicemail should be in MBDN index 0 */
   1763 	pb_type = CSD_SIMPB_TYPE_MBDN;
   1764 
   1765 	ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
   1766 				CSD_SIMPB_INTERFACE, "ReadFirst",
   1767 				phonebook_read_reply, &vmbx,
   1768 				DBUS_TYPE_STRING, &pb_type,
   1769 				DBUS_TYPE_INVALID);
   1770 	if (ret < 0) {
   1771 		error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
   1772 		return;
   1773 	}
   1774 }
   1775 
   1776 static void handle_modem_state(DBusMessage *msg)
   1777 {
   1778 	const char *state;
   1779 
   1780 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
   1781 							DBUS_TYPE_INVALID)) {
   1782 		error("Unexpected modem state parameters");
   1783 		return;
   1784 	}
   1785 
   1786 	DBG("SSC modem state: %s", state);
   1787 
   1788 	if (calls != NULL || get_calls_active)
   1789 		return;
   1790 
   1791 	if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
   1792 		csd_init();
   1793 }
   1794 
   1795 static void modem_state_reply(DBusPendingCall *call, void *user_data)
   1796 {
   1797 	DBusMessage *reply = dbus_pending_call_steal_reply(call);
   1798 	DBusError err;
   1799 
   1800 	dbus_error_init(&err);
   1801 	if (dbus_set_error_from_message(&err, reply)) {
   1802 		error("get_modem_state: %s, %s", err.name, err.message);
   1803 		dbus_error_free(&err);
   1804 	} else
   1805 		handle_modem_state(reply);
   1806 
   1807 	dbus_message_unref(reply);
   1808 	remove_pending(call);
   1809 }
   1810 
   1811 static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
   1812 								void *data)
   1813 {
   1814 	const char *path = dbus_message_get_path(msg);
   1815 
   1816 	if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
   1817 		handle_incoming_call(msg);
   1818 	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
   1819 		handle_outgoing_call(msg);
   1820 	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
   1821 							"CreateRequested"))
   1822 		handle_create_requested(msg);
   1823 	else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
   1824 		handle_call_status(msg, path);
   1825 	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
   1826 		handle_conference(msg, TRUE);
   1827 	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
   1828 		handle_conference(msg, FALSE);
   1829 	else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
   1830 				"RegistrationChanged"))
   1831 		handle_registration_changed(msg);
   1832 	else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
   1833 				"OperatorNameChanged"))
   1834 		handle_operator_name_changed(msg);
   1835 	else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
   1836 				"SignalBarsChanged"))
   1837 		handle_signal_bars_changed(msg);
   1838 	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
   1839 					"PropertyModified"))
   1840 		handle_hal_property_modified(msg);
   1841 	else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
   1842 						"modem_state_changed_ind"))
   1843 		handle_modem_state(msg);
   1844 
   1845 	return TRUE;
   1846 }
   1847 
   1848 static void add_watch(const char *sender, const char *path,
   1849 				const char *interface, const char *member)
   1850 {
   1851 	guint watch;
   1852 
   1853 	watch = g_dbus_add_signal_watch(connection, sender, path, interface,
   1854 					member, signal_filter, NULL, NULL);
   1855 
   1856 	watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
   1857 }
   1858 
   1859 static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
   1860 {
   1861 	DBusError err;
   1862 	DBusMessage *reply;
   1863 	DBusMessageIter iter, sub;
   1864 	const char *path;
   1865 	int type;
   1866 
   1867 	reply = dbus_pending_call_steal_reply(call);
   1868 
   1869 	dbus_error_init(&err);
   1870 	if (dbus_set_error_from_message(&err, reply)) {
   1871 		error("hald replied with an error: %s, %s",
   1872 				err.name, err.message);
   1873 		dbus_error_free(&err);
   1874 		goto done;
   1875 	}
   1876 
   1877 	dbus_message_iter_init(reply, &iter);
   1878 
   1879 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
   1880 		error("Unexpected signature in FindDeviceByCapability return");
   1881 		goto done;
   1882 	}
   1883 
   1884 	dbus_message_iter_recurse(&iter, &sub);
   1885 
   1886 	type = dbus_message_iter_get_arg_type(&sub);
   1887 
   1888 	if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
   1889 		error("No hal device with battery capability found");
   1890 		goto done;
   1891 	}
   1892 
   1893 	dbus_message_iter_get_basic(&sub, &path);
   1894 
   1895 	DBG("telephony-maemo6: found battery device at %s", path);
   1896 
   1897 	add_watch(NULL, path, "org.freedesktop.Hal.Device",
   1898 							"PropertyModified");
   1899 
   1900 	hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
   1901 	hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
   1902 	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
   1903 
   1904 done:
   1905 	dbus_message_unref(reply);
   1906 	remove_pending(call);
   1907 }
   1908 
   1909 int telephony_init(void)
   1910 {
   1911 	const char *battery_cap = "battery";
   1912 	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
   1913 				AG_FEATURE_INBAND_RINGTONE |
   1914 				AG_FEATURE_REJECT_A_CALL |
   1915 				AG_FEATURE_ENHANCED_CALL_STATUS |
   1916 				AG_FEATURE_ENHANCED_CALL_CONTROL |
   1917 				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
   1918 				AG_FEATURE_THREE_WAY_CALLING;
   1919 	int i;
   1920 
   1921 	DBG("");
   1922 
   1923 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
   1924 
   1925 	add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL);
   1926 	add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL);
   1927 	add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL);
   1928 	add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged");
   1929 	add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged");
   1930 	add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged");
   1931 	add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind");
   1932 
   1933 	if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
   1934 					"get_modem_state", modem_state_reply,
   1935 					NULL, DBUS_TYPE_INVALID) < 0)
   1936 		error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
   1937 
   1938 	/* Reset indicators */
   1939 	for (i = 0; maemo_indicators[i].desc != NULL; i++) {
   1940 		if (g_str_equal(maemo_indicators[i].desc, "battchg"))
   1941 			maemo_indicators[i].val = 5;
   1942 		else
   1943 			maemo_indicators[i].val = 0;
   1944 	}
   1945 
   1946 	telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
   1947 								chld_str);
   1948 	if (send_method_call("org.freedesktop.Hal",
   1949 				"/org/freedesktop/Hal/Manager",
   1950 				"org.freedesktop.Hal.Manager",
   1951 				"FindDeviceByCapability",
   1952 				hal_find_device_reply, NULL,
   1953 				DBUS_TYPE_STRING, &battery_cap,
   1954 				DBUS_TYPE_INVALID) < 0)
   1955 		error("Unable to send HAL method call");
   1956 
   1957 	return 0;
   1958 }
   1959 
   1960 static void remove_watch(gpointer data)
   1961 {
   1962 	g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
   1963 }
   1964 
   1965 void telephony_exit(void)
   1966 {
   1967 	DBG("");
   1968 
   1969 	g_free(net.operator_name);
   1970 	net.operator_name = NULL;
   1971 
   1972 	net.status = NETWORK_REG_STATUS_UNKOWN;
   1973 	net.signal_bars = 0;
   1974 
   1975 	g_slist_free(active_calls);
   1976 	active_calls = NULL;
   1977 
   1978 	g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
   1979 	g_slist_free(calls);
   1980 	calls = NULL;
   1981 
   1982 	g_slist_foreach(pending, (GFunc) pending_req_finalize, NULL);
   1983 	g_slist_free(pending);
   1984 	pending = NULL;
   1985 
   1986 	g_slist_foreach(watches, (GFunc) remove_watch, NULL);
   1987 	g_slist_free(watches);
   1988 	watches = NULL;
   1989 
   1990 	dbus_connection_unref(connection);
   1991 	connection = NULL;
   1992 
   1993 	telephony_deinit();
   1994 }
   1995