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