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