3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2008-2010 Nokia Corporation
6
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
36
#include <dbus/dbus.h>
40
#include "telephony.h"
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"
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"
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
68
/* Driver definitions */
69
#define TELEPHONY_MAEMO_PATH "/com/nokia/MaemoTelephony"
70
#define TELEPHONY_MAEMO_INTERFACE "com.nokia.MaemoTelephony"
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"
77
static uint32_t callerid = 0;
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"
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
106
#define CALL_FLAG_NONE 0
107
#define CALL_FLAG_PRESENTATION_ALLOWED 0x01
108
#define CALL_FLAG_PRESENTATION_RESTRICTED 0x02
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"
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"
126
gboolean originating;
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. */
147
static int get_property(const char *iface, const char *prop);
149
static DBusConnection *connection = NULL;
151
static GSList *calls = NULL;
152
static GSList *watches = NULL;
153
static GSList *pending = NULL;
155
/* Reference count for determining the call indicator status */
156
static GSList *active_calls = NULL;
158
static char *msisdn = NULL; /* Subscriber number */
159
static char *vmbx = NULL; /* Voice mailbox number */
161
/* HAL battery namespace key values */
162
static int battchg_cur = -1; /* "battery.charge_level.current" */
163
static int battchg_last = -1; /* "battery.charge_level.last_full" */
164
static int battchg_design = -1; /* "battery.charge_level.design" */
166
static gboolean get_calls_active = FALSE;
168
static gboolean events_enabled = FALSE;
170
/* Supported set of call hold operations */
171
static const char *chld_str = "0,1,1x,2,2x,3,4";
173
/* Response and hold state
175
* 0 = incoming call is put on hold in the AG
176
* 1 = held incoming call is accepted in the AG
177
* 2 = held incoming call is rejected in the AG
179
static int response_and_hold = -1;
181
static char *last_dialed_number = NULL;
183
/* Timer for tracking call creation requests */
184
static guint create_request_timer = 0;
186
static struct indicator maemo_indicators[] =
188
{ "battchg", "0-5", 5, TRUE },
189
/* signal strength in terms of bars */
190
{ "signal", "0-5", 0, TRUE },
191
{ "service", "0,1", 0, TRUE },
192
{ "call", "0,1", 0, TRUE },
193
{ "callsetup", "0-3", 0, TRUE },
194
{ "callheld", "0-2", 0, FALSE },
195
{ "roam", "0,1", 0, TRUE },
199
static char *call_status_str[] = {
213
"RETRIEVE_INITIATED",
220
static struct csd_call *find_call(const char *path)
224
for (l = calls; l != NULL; l = l->next) {
225
struct csd_call *call = l->data;
227
if (g_str_equal(call->object_path, path))
234
static struct csd_call *find_non_held_call(void)
238
for (l = calls; l != NULL; l = l->next) {
239
struct csd_call *call = l->data;
241
if (call->status == CSD_CALL_STATUS_IDLE)
244
if (call->status != CSD_CALL_STATUS_HOLD)
251
static struct csd_call *find_non_idle_call(void)
255
for (l = calls; l != NULL; l = l->next) {
256
struct csd_call *call = l->data;
258
if (call->status != CSD_CALL_STATUS_IDLE)
265
static struct csd_call *find_call_with_status(int status)
269
for (l = calls; l != NULL; l = l->next) {
270
struct csd_call *call = l->data;
272
if (call->status == status)
279
static int release_conference(void)
283
DBG("telephony-maemo6: releasing conference call");
285
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
286
CSD_CALL_CONFERENCE_PATH,
290
error("Unable to allocate new D-Bus message");
294
g_dbus_send_message(connection, msg);
299
static int release_call(struct csd_call *call)
303
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
308
error("Unable to allocate new D-Bus message");
312
g_dbus_send_message(connection, msg);
317
static int answer_call(struct csd_call *call)
321
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
326
error("Unable to allocate new D-Bus message");
330
g_dbus_send_message(connection, msg);
335
static int split_call(struct csd_call *call)
339
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
344
error("Unable to allocate new D-Bus message");
348
g_dbus_send_message(connection, msg);
353
static int unhold_call(struct csd_call *call)
357
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
361
error("Unable to allocate new D-Bus message");
365
g_dbus_send_message(connection, msg);
370
static int hold_call(struct csd_call *call)
374
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
378
error("Unable to allocate new D-Bus message");
382
g_dbus_send_message(connection, msg);
387
static int swap_calls(void)
391
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
395
error("Unable to allocate new D-Bus message");
399
g_dbus_send_message(connection, msg);
404
static int create_conference(void)
408
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
412
error("Unable to allocate new D-Bus message");
416
g_dbus_send_message(connection, msg);
421
static int call_transfer(void)
425
msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
429
error("Unable to allocate new D-Bus message");
433
g_dbus_send_message(connection, msg);
438
static int number_type(const char *number)
441
return NUMBER_TYPE_TELEPHONY;
443
if (number[0] == '+' || strncmp(number, "00", 2) == 0)
444
return NUMBER_TYPE_INTERNATIONAL;
446
return NUMBER_TYPE_TELEPHONY;
449
void telephony_device_connected(void *telephony_device)
451
struct csd_call *coming;
453
DBG("telephony-maemo6: device %p connected", telephony_device);
455
coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
457
if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
458
telephony_call_waiting_ind(coming->number,
459
number_type(coming->number));
461
telephony_incoming_call_ind(coming->number,
462
number_type(coming->number));
466
void telephony_device_disconnected(void *telephony_device)
468
DBG("telephony-maemo6: device %p disconnected", telephony_device);
469
events_enabled = FALSE;
472
void telephony_event_reporting_req(void *telephony_device, int ind)
474
events_enabled = ind == 1 ? TRUE : FALSE;
476
telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
479
void telephony_response_and_hold_req(void *telephony_device, int rh)
481
response_and_hold = rh;
483
telephony_response_and_hold_ind(response_and_hold);
485
telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NONE);
488
void telephony_last_dialed_number_req(void *telephony_device)
490
DBG("telephony-maemo6: last dialed number request");
492
if (last_dialed_number)
493
telephony_dial_number_req(telephony_device,
496
telephony_last_dialed_number_rsp(telephony_device,
497
CME_ERROR_NOT_ALLOWED);
500
void telephony_terminate_call_req(void *telephony_device)
502
struct csd_call *call;
503
struct csd_call *alerting;
506
call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
508
call = find_non_idle_call();
511
error("No active call");
512
telephony_terminate_call_rsp(telephony_device,
513
CME_ERROR_NOT_ALLOWED);
517
alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING);
518
if (call->on_hold && alerting)
519
err = release_call(alerting);
520
else if (call->conference)
521
err = release_conference();
523
err = release_call(call);
526
telephony_terminate_call_rsp(telephony_device,
527
CME_ERROR_AG_FAILURE);
529
telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
532
void telephony_answer_call_req(void *telephony_device)
534
struct csd_call *call;
536
call = find_call_with_status(CSD_CALL_STATUS_COMING);
538
call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
541
call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
544
call = find_call_with_status(CSD_CALL_STATUS_WAITING);
547
telephony_answer_call_rsp(telephony_device,
548
CME_ERROR_NOT_ALLOWED);
552
if (answer_call(call) < 0)
553
telephony_answer_call_rsp(telephony_device,
554
CME_ERROR_AG_FAILURE);
556
telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
559
static int send_method_call(const char *dest, const char *path,
560
const char *interface, const char *method,
561
DBusPendingCallNotifyFunction cb,
562
void *user_data, int type, ...)
565
DBusPendingCall *call;
568
msg = dbus_message_new_method_call(dest, path, interface, method);
570
error("Unable to allocate new D-Bus %s message", method);
574
va_start(args, type);
576
if (!dbus_message_append_args_valist(msg, type, args)) {
577
dbus_message_unref(msg);
585
g_dbus_send_message(connection, msg);
589
if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
590
error("Sending %s failed", method);
591
dbus_message_unref(msg);
595
dbus_pending_call_set_notify(call, cb, user_data, NULL);
596
pending = g_slist_prepend(pending, call);
597
dbus_message_unref(msg);
602
static const char *memory_dial_lookup(int location)
610
void telephony_dial_number_req(void *telephony_device, const char *number)
612
uint32_t flags = callerid;
615
DBG("telephony-maemo6: dial request to %s", number);
617
if (strncmp(number, "*31#", 4) == 0) {
619
flags = CALL_FLAG_PRESENTATION_ALLOWED;
620
} else if (strncmp(number, "#31#", 4) == 0) {
622
flags = CALL_FLAG_PRESENTATION_RESTRICTED;
623
} else if (number[0] == '>') {
624
const char *location = &number[1];
626
number = memory_dial_lookup(strtol(&number[1], NULL, 0));
628
error("No number at memory location %s", location);
629
telephony_dial_number_rsp(telephony_device,
630
CME_ERROR_INVALID_INDEX);
635
ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
636
CSD_CALL_INTERFACE, "CreateWith",
638
DBUS_TYPE_STRING, &number,
639
DBUS_TYPE_UINT32, &flags,
642
telephony_dial_number_rsp(telephony_device,
643
CME_ERROR_AG_FAILURE);
647
telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
650
void telephony_transmit_dtmf_req(void *telephony_device, char tone)
653
char buf[2] = { tone, '\0' }, *buf_ptr = buf;
655
DBG("telephony-maemo6: transmit dtmf: %s", buf);
657
ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
658
CSD_CALL_INTERFACE, "SendDTMF",
660
DBUS_TYPE_STRING, &buf_ptr,
663
telephony_transmit_dtmf_rsp(telephony_device,
664
CME_ERROR_AG_FAILURE);
668
telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
671
void telephony_subscriber_number_req(void *telephony_device)
673
DBG("telephony-maemo6: subscriber number request");
675
telephony_subscriber_number_ind(msisdn,
677
SUBSCRIBER_SERVICE_VOICE);
678
telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
681
static int csd_status_to_hfp(struct csd_call *call)
683
switch (call->status) {
684
case CSD_CALL_STATUS_IDLE:
685
case CSD_CALL_STATUS_MO_RELEASE:
686
case CSD_CALL_STATUS_MT_RELEASE:
687
case CSD_CALL_STATUS_TERMINATED:
689
case CSD_CALL_STATUS_CREATE:
690
return CALL_STATUS_DIALING;
691
case CSD_CALL_STATUS_WAITING:
692
return CALL_STATUS_WAITING;
693
case CSD_CALL_STATUS_PROCEEDING:
694
/* PROCEEDING can happen in outgoing/incoming */
695
if (call->originating)
696
return CALL_STATUS_DIALING;
698
return CALL_STATUS_INCOMING;
699
case CSD_CALL_STATUS_COMING:
700
return CALL_STATUS_INCOMING;
701
case CSD_CALL_STATUS_MO_ALERTING:
702
return CALL_STATUS_ALERTING;
703
case CSD_CALL_STATUS_MT_ALERTING:
704
return CALL_STATUS_INCOMING;
705
case CSD_CALL_STATUS_ANSWERED:
706
case CSD_CALL_STATUS_ACTIVE:
707
case CSD_CALL_STATUS_RECONNECT_PENDING:
708
case CSD_CALL_STATUS_SWAP_INITIATED:
709
case CSD_CALL_STATUS_HOLD_INITIATED:
710
return CALL_STATUS_ACTIVE;
711
case CSD_CALL_STATUS_RETRIEVE_INITIATED:
712
case CSD_CALL_STATUS_HOLD:
713
return CALL_STATUS_HELD;
719
void telephony_list_current_calls_req(void *telephony_device)
724
DBG("telephony-maemo6: list current calls request");
726
for (l = calls, i = 1; l != NULL; l = l->next, i++) {
727
struct csd_call *call = l->data;
728
int status, direction, multiparty;
730
status = csd_status_to_hfp(call);
734
direction = call->originating ?
735
CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
737
multiparty = call->conference ?
738
CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
740
telephony_list_current_call_ind(i, direction, status,
741
CALL_MODE_VOICE, multiparty,
743
number_type(call->number));
746
telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
749
void telephony_operator_selection_req(void *telephony_device)
751
telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
752
net.operator_name ? net.operator_name : "");
753
telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
756
static void foreach_call_with_status(int status,
757
int (*func)(struct csd_call *call))
761
for (l = calls; l != NULL; l = l->next) {
762
struct csd_call *call = l->data;
764
if (call->status == status)
769
void telephony_call_hold_req(void *telephony_device, const char *cmd)
772
struct csd_call *call;
775
DBG("telephony-maemo6: got call hold request %s", cmd);
783
call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
789
if (find_call_with_status(CSD_CALL_STATUS_WAITING))
790
foreach_call_with_status(CSD_CALL_STATUS_WAITING,
793
foreach_call_with_status(CSD_CALL_STATUS_HOLD,
799
err = release_call(call);
802
foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
803
call = find_call_with_status(CSD_CALL_STATUS_WAITING);
805
err = answer_call(call);
810
err = split_call(call);
812
struct csd_call *held, *wait;
814
call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
815
held = find_call_with_status(CSD_CALL_STATUS_HOLD);
816
wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
819
err = answer_call(wait);
820
else if (call && held)
824
err = hold_call(call);
826
err = unhold_call(held);
831
if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
832
find_call_with_status(CSD_CALL_STATUS_WAITING))
833
err = create_conference();
836
err = call_transfer();
839
DBG("Unknown call hold request");
844
telephony_call_hold_rsp(telephony_device,
845
CME_ERROR_AG_FAILURE);
847
telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
850
void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
852
DBG("telephony-maemo6: got %s NR and EC request",
853
enable ? "enable" : "disable");
854
telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
857
void telephony_key_press_req(void *telephony_device, const char *keys)
859
struct csd_call *active, *waiting;
862
DBG("telephony-maemo6: got key press request for %s", keys);
864
waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
866
waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
868
waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
870
active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
873
err = answer_call(waiting);
875
err = release_call(active);
880
telephony_key_press_rsp(telephony_device,
881
CME_ERROR_AG_FAILURE);
883
telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
886
void telephony_voice_dial_req(void *telephony_device, gboolean enable)
888
DBG("telephony-maemo6: got %s voice dial request",
889
enable ? "enable" : "disable");
891
telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
894
static void handle_incoming_call(DBusMessage *msg)
896
const char *number, *call_path;
897
struct csd_call *call;
899
if (!dbus_message_get_args(msg, NULL,
900
DBUS_TYPE_OBJECT_PATH, &call_path,
901
DBUS_TYPE_STRING, &number,
902
DBUS_TYPE_INVALID)) {
903
error("Unexpected parameters in Call.Coming() signal");
907
call = find_call(call_path);
909
error("Didn't find any matching call object for %s",
914
DBG("Incoming call to %s from number %s", call_path, number);
916
g_free(call->number);
917
call->number = g_strdup(number);
919
if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
920
find_call_with_status(CSD_CALL_STATUS_HOLD))
921
telephony_call_waiting_ind(call->number,
922
number_type(call->number));
924
telephony_incoming_call_ind(call->number,
925
number_type(call->number));
927
telephony_update_indicator(maemo_indicators, "callsetup",
928
EV_CALLSETUP_INCOMING);
931
static void handle_outgoing_call(DBusMessage *msg)
933
const char *number, *call_path;
934
struct csd_call *call;
936
if (!dbus_message_get_args(msg, NULL,
937
DBUS_TYPE_OBJECT_PATH, &call_path,
938
DBUS_TYPE_STRING, &number,
939
DBUS_TYPE_INVALID)) {
940
error("Unexpected parameters in Call.Created() signal");
944
call = find_call(call_path);
946
error("Didn't find any matching call object for %s",
951
DBG("Outgoing call from %s to number %s", call_path, number);
953
g_free(call->number);
954
call->number = g_strdup(number);
956
g_free(last_dialed_number);
957
last_dialed_number = g_strdup(number);
959
if (create_request_timer) {
960
g_source_remove(create_request_timer);
961
create_request_timer = 0;
965
static gboolean create_timeout(gpointer user_data)
967
telephony_update_indicator(maemo_indicators, "callsetup",
968
EV_CALLSETUP_INACTIVE);
969
create_request_timer = 0;
973
static void handle_create_requested(DBusMessage *msg)
975
DBG("Call.CreateRequested()");
977
if (create_request_timer)
978
g_source_remove(create_request_timer);
980
create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
982
telephony_update_indicator(maemo_indicators, "callsetup",
983
EV_CALLSETUP_OUTGOING);
986
static void handle_call_status(DBusMessage *msg, const char *call_path)
988
struct csd_call *call;
989
dbus_uint32_t status, cause_type, cause, prev_status;
990
int callheld = telephony_get_indicator(maemo_indicators, "callheld");
992
if (!dbus_message_get_args(msg, NULL,
993
DBUS_TYPE_UINT32, &status,
994
DBUS_TYPE_UINT32, &cause_type,
995
DBUS_TYPE_UINT32, &cause,
996
DBUS_TYPE_INVALID)) {
997
error("Unexpected paramters in Instance.CallStatus() signal");
1001
call = find_call(call_path);
1003
error("Didn't find any matching call object for %s",
1009
error("Invalid call status %u", status);
1013
prev_status = call->status;
1014
DBG("Call %s changed from %s to %s", call_path,
1015
call_status_str[prev_status], call_status_str[status]);
1017
if (prev_status == status) {
1018
DBG("Ignoring CSD Call state change to existing state");
1022
call->status = (int) status;
1025
case CSD_CALL_STATUS_IDLE:
1027
telephony_update_indicator(maemo_indicators,
1029
EV_CALLSETUP_INACTIVE);
1030
if (!call->originating)
1031
telephony_calling_stopped_ind();
1034
g_free(call->number);
1035
call->number = NULL;
1036
call->originating = FALSE;
1037
call->emergency = FALSE;
1038
call->on_hold = FALSE;
1039
call->conference = FALSE;
1040
call->setup = FALSE;
1042
case CSD_CALL_STATUS_CREATE:
1043
call->originating = TRUE;
1046
case CSD_CALL_STATUS_COMING:
1047
call->originating = FALSE;
1050
case CSD_CALL_STATUS_PROCEEDING:
1052
case CSD_CALL_STATUS_MO_ALERTING:
1053
telephony_update_indicator(maemo_indicators, "callsetup",
1054
EV_CALLSETUP_ALERTING);
1056
case CSD_CALL_STATUS_MT_ALERTING:
1057
/* Some headsets expect incoming call notification before they
1058
* can send ATA command. When call changed status from waiting
1059
* to alerting we need to send missing notification. Otherwise
1060
* headsets like Nokia BH-108 or BackBeat 903 are unable to
1061
* answer incoming call that was previously waiting. */
1062
if (prev_status == CSD_CALL_STATUS_WAITING)
1063
telephony_incoming_call_ind(call->number,
1064
number_type(call->number));
1066
case CSD_CALL_STATUS_WAITING:
1068
case CSD_CALL_STATUS_ANSWERED:
1070
case CSD_CALL_STATUS_ACTIVE:
1071
if (call->on_hold) {
1072
call->on_hold = FALSE;
1073
if (find_call_with_status(CSD_CALL_STATUS_HOLD))
1074
telephony_update_indicator(maemo_indicators,
1076
EV_CALLHELD_MULTIPLE);
1078
telephony_update_indicator(maemo_indicators,
1082
if (!g_slist_find(active_calls, call))
1083
active_calls = g_slist_prepend(active_calls, call);
1084
if (g_slist_length(active_calls) == 1)
1085
telephony_update_indicator(maemo_indicators,
1088
/* Upgrade callheld status if necessary */
1089
if (callheld == EV_CALLHELD_ON_HOLD)
1090
telephony_update_indicator(maemo_indicators,
1092
EV_CALLHELD_MULTIPLE);
1093
telephony_update_indicator(maemo_indicators,
1095
EV_CALLSETUP_INACTIVE);
1096
if (!call->originating)
1097
telephony_calling_stopped_ind();
1098
call->setup = FALSE;
1101
case CSD_CALL_STATUS_MO_RELEASE:
1102
case CSD_CALL_STATUS_MT_RELEASE:
1103
active_calls = g_slist_remove(active_calls, call);
1104
if (g_slist_length(active_calls) == 0)
1105
telephony_update_indicator(maemo_indicators, "call",
1108
case CSD_CALL_STATUS_HOLD_INITIATED:
1110
case CSD_CALL_STATUS_HOLD:
1111
call->on_hold = TRUE;
1112
if (find_non_held_call())
1113
telephony_update_indicator(maemo_indicators,
1115
EV_CALLHELD_MULTIPLE);
1117
telephony_update_indicator(maemo_indicators,
1119
EV_CALLHELD_ON_HOLD);
1121
case CSD_CALL_STATUS_RETRIEVE_INITIATED:
1123
case CSD_CALL_STATUS_RECONNECT_PENDING:
1125
case CSD_CALL_STATUS_TERMINATED:
1126
if (call->on_hold &&
1127
!find_call_with_status(CSD_CALL_STATUS_HOLD))
1128
telephony_update_indicator(maemo_indicators,
1131
else if (callheld == EV_CALLHELD_MULTIPLE &&
1132
find_call_with_status(CSD_CALL_STATUS_HOLD))
1133
telephony_update_indicator(maemo_indicators,
1135
EV_CALLHELD_ON_HOLD);
1137
case CSD_CALL_STATUS_SWAP_INITIATED:
1140
error("Unknown call status %u", status);
1145
static void handle_conference(DBusMessage *msg, gboolean joined)
1148
struct csd_call *call;
1150
if (!dbus_message_get_args(msg, NULL,
1151
DBUS_TYPE_OBJECT_PATH, &path,
1152
DBUS_TYPE_INVALID)) {
1153
error("Unexpected parameters in Conference.%s",
1154
dbus_message_get_member(msg));
1158
call = find_call(path);
1160
error("Conference signal for unknown call %s", path);
1164
DBG("Call %s %s the conference", path, joined ? "joined" : "left");
1166
call->conference = joined;
1169
static uint8_t str2status(const char *state)
1171
if (g_strcmp0(state, "Home") == 0)
1172
return NETWORK_REG_STATUS_HOME;
1173
else if (g_strcmp0(state, "Roaming") == 0)
1174
return NETWORK_REG_STATUS_ROAMING;
1175
else if (g_strcmp0(state, "Offline") == 0)
1176
return NETWORK_REG_STATUS_OFFLINE;
1177
else if (g_strcmp0(state, "Searching") == 0)
1178
return NETWORK_REG_STATUS_SEARCHING;
1179
else if (g_strcmp0(state, "NoSim") == 0)
1180
return NETWORK_REG_STATUS_NO_SIM;
1181
else if (g_strcmp0(state, "Poweroff") == 0)
1182
return NETWORK_REG_STATUS_POWEROFF;
1183
else if (g_strcmp0(state, "Powersafe") == 0)
1184
return NETWORK_REG_STATUS_POWERSAFE;
1185
else if (g_strcmp0(state, "NoCoverage") == 0)
1186
return NETWORK_REG_STATUS_NO_COVERAGE;
1187
else if (g_strcmp0(state, "Reject") == 0)
1188
return NETWORK_REG_STATUS_REJECTED;
1190
return NETWORK_REG_STATUS_UNKOWN;
1193
static void update_registration_status(const char *status)
1197
new_status = str2status(status);
1199
if (net.status == new_status)
1202
switch (new_status) {
1203
case NETWORK_REG_STATUS_HOME:
1204
telephony_update_indicator(maemo_indicators, "roam",
1206
if (net.status > NETWORK_REG_STATUS_ROAMING)
1207
telephony_update_indicator(maemo_indicators,
1209
EV_SERVICE_PRESENT);
1211
case NETWORK_REG_STATUS_ROAMING:
1212
telephony_update_indicator(maemo_indicators, "roam",
1214
if (net.status > NETWORK_REG_STATUS_ROAMING)
1215
telephony_update_indicator(maemo_indicators,
1217
EV_SERVICE_PRESENT);
1219
case NETWORK_REG_STATUS_OFFLINE:
1220
case NETWORK_REG_STATUS_SEARCHING:
1221
case NETWORK_REG_STATUS_NO_SIM:
1222
case NETWORK_REG_STATUS_POWEROFF:
1223
case NETWORK_REG_STATUS_POWERSAFE:
1224
case NETWORK_REG_STATUS_NO_COVERAGE:
1225
case NETWORK_REG_STATUS_REJECTED:
1226
case NETWORK_REG_STATUS_UNKOWN:
1227
if (net.status < NETWORK_REG_STATUS_OFFLINE)
1228
telephony_update_indicator(maemo_indicators,
1234
net.status = new_status;
1236
DBG("telephony-maemo6: registration status changed: %s", status);
1239
static void handle_registration_changed(DBusMessage *msg)
1243
if (!dbus_message_get_args(msg, NULL,
1244
DBUS_TYPE_STRING, &status,
1245
DBUS_TYPE_INVALID)) {
1246
error("Unexpected parameters in RegistrationChanged");
1250
update_registration_status(status);
1253
static void update_signal_strength(int32_t signal_bars)
1255
if (signal_bars < 0) {
1256
DBG("signal strength smaller than expected: %d < 0",
1259
} else if (signal_bars > 5) {
1260
DBG("signal strength greater than expected: %d > 5",
1265
if (net.signal_bars == signal_bars)
1268
telephony_update_indicator(maemo_indicators, "signal", signal_bars);
1270
net.signal_bars = signal_bars;
1271
DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
1274
static void handle_signal_bars_changed(DBusMessage *msg)
1276
int32_t signal_bars;
1278
if (!dbus_message_get_args(msg, NULL,
1279
DBUS_TYPE_INT32, &signal_bars,
1280
DBUS_TYPE_INVALID)) {
1281
error("Unexpected parameters in SignalBarsChanged");
1285
update_signal_strength(signal_bars);
1288
static gboolean iter_get_basic_args(DBusMessageIter *iter,
1289
int first_arg_type, ...)
1294
va_start(ap, first_arg_type);
1296
for (type = first_arg_type; type != DBUS_TYPE_INVALID;
1297
type = va_arg(ap, int)) {
1298
void *value = va_arg(ap, void *);
1299
int real_type = dbus_message_iter_get_arg_type(iter);
1301
if (real_type != type) {
1302
error("iter_get_basic_args: expected %c but got %c",
1303
(char) type, (char) real_type);
1307
dbus_message_iter_get_basic(iter, value);
1308
dbus_message_iter_next(iter);
1313
return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
1316
static void remove_pending(DBusPendingCall *call)
1318
pending = g_slist_remove(pending, call);
1319
dbus_pending_call_unref(call);
1322
static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
1327
int *value = user_data;
1329
reply = dbus_pending_call_steal_reply(call);
1331
dbus_error_init(&err);
1332
if (dbus_set_error_from_message(&err, reply)) {
1333
error("hald replied with an error: %s, %s",
1334
err.name, err.message);
1335
dbus_error_free(&err);
1339
if (!dbus_message_get_args(reply, NULL,
1340
DBUS_TYPE_INT32, &level,
1341
DBUS_TYPE_INVALID)) {
1342
error("Unexpected args in hald reply");
1346
*value = (int) level;
1348
if (value == &battchg_last)
1349
DBG("telephony-maemo6: battery.charge_level.last_full is %d",
1351
else if (value == &battchg_design)
1352
DBG("telephony-maemo6: battery.charge_level.design is %d",
1355
DBG("telephony-maemo6: battery.charge_level.current is %d",
1358
if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
1361
if (battchg_last > 0)
1364
max = battchg_design;
1366
new = battchg_cur * 5 / max;
1368
telephony_update_indicator(maemo_indicators, "battchg", new);
1372
dbus_message_unref(reply);
1373
remove_pending(call);
1376
static void hal_get_integer(const char *path, const char *key, void *user_data)
1378
send_method_call("org.freedesktop.Hal", path,
1379
"org.freedesktop.Hal.Device",
1380
"GetPropertyInteger",
1381
hal_battery_level_reply, user_data,
1382
DBUS_TYPE_STRING, &key,
1386
static void handle_hal_property_modified(DBusMessage *msg)
1388
DBusMessageIter iter, array;
1389
dbus_int32_t num_changes;
1392
path = dbus_message_get_path(msg);
1394
dbus_message_iter_init(msg, &iter);
1396
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
1397
error("Unexpected signature in hal PropertyModified signal");
1401
dbus_message_iter_get_basic(&iter, &num_changes);
1402
dbus_message_iter_next(&iter);
1404
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1405
error("Unexpected signature in hal PropertyModified signal");
1409
dbus_message_iter_recurse(&iter, &array);
1411
while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
1412
DBusMessageIter prop;
1414
dbus_bool_t added, removed;
1416
dbus_message_iter_recurse(&array, &prop);
1418
if (!iter_get_basic_args(&prop,
1419
DBUS_TYPE_STRING, &name,
1420
DBUS_TYPE_BOOLEAN, &added,
1421
DBUS_TYPE_BOOLEAN, &removed,
1422
DBUS_TYPE_INVALID)) {
1423
error("Invalid hal PropertyModified parameters");
1427
if (g_str_equal(name, "battery.charge_level.last_full"))
1428
hal_get_integer(path, name, &battchg_last);
1429
else if (g_str_equal(name, "battery.charge_level.current"))
1430
hal_get_integer(path, name, &battchg_cur);
1431
else if (g_str_equal(name, "battery.charge_level.design"))
1432
hal_get_integer(path, name, &battchg_design);
1434
dbus_message_iter_next(&array);
1438
static void csd_call_free(struct csd_call *call)
1443
g_free(call->object_path);
1444
g_free(call->number);
1449
static void parse_call_list(DBusMessageIter *iter)
1452
DBusMessageIter call_iter;
1453
struct csd_call *call;
1454
const char *object_path, *number;
1455
dbus_uint32_t status;
1456
dbus_bool_t originating, terminating, emerg, on_hold, conf;
1458
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
1459
error("Unexpected signature in GetCallInfoAll reply");
1463
dbus_message_iter_recurse(iter, &call_iter);
1465
if (!iter_get_basic_args(&call_iter,
1466
DBUS_TYPE_OBJECT_PATH, &object_path,
1467
DBUS_TYPE_UINT32, &status,
1468
DBUS_TYPE_BOOLEAN, &originating,
1469
DBUS_TYPE_BOOLEAN, &terminating,
1470
DBUS_TYPE_BOOLEAN, &emerg,
1471
DBUS_TYPE_BOOLEAN, &on_hold,
1472
DBUS_TYPE_BOOLEAN, &conf,
1473
DBUS_TYPE_STRING, &number,
1474
DBUS_TYPE_INVALID)) {
1475
error("Parsing call D-Bus parameters failed");
1479
call = find_call(object_path);
1481
call = g_new0(struct csd_call, 1);
1482
call->object_path = g_strdup(object_path);
1483
call->status = (int) status;
1484
calls = g_slist_append(calls, call);
1485
DBG("telephony-maemo6: new csd call instance at %s",
1489
if (call->status == CSD_CALL_STATUS_IDLE)
1492
/* CSD gives incorrect call_hold property sometimes */
1493
if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
1494
(call->status == CSD_CALL_STATUS_HOLD &&
1496
error("Conflicting call status and on_hold property!");
1497
on_hold = call->status == CSD_CALL_STATUS_HOLD;
1500
call->originating = originating;
1501
call->on_hold = on_hold;
1502
call->conference = conf;
1503
g_free(call->number);
1504
call->number = g_strdup(number);
1506
} while (dbus_message_iter_next(iter));
1509
static void update_operator_name(const char *name)
1514
g_free(net.operator_name);
1515
net.operator_name = g_strndup(name, 16);
1516
DBG("telephony-maemo6: operator name updated: %s", name);
1519
static void get_property_reply(DBusPendingCall *call, void *user_data)
1521
char *prop = user_data;
1524
DBusMessageIter iter, sub;
1526
reply = dbus_pending_call_steal_reply(call);
1528
dbus_error_init(&err);
1529
if (dbus_set_error_from_message(&err, reply)) {
1530
error("csd replied with an error: %s, %s",
1531
err.name, err.message);
1532
dbus_error_free(&err);
1536
dbus_message_iter_init(reply, &iter);
1538
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1539
error("Unexpected signature in Get return");
1543
dbus_message_iter_recurse(&iter, &sub);
1545
if (g_strcmp0(prop, "RegistrationStatus") == 0) {
1548
dbus_message_iter_get_basic(&sub, &status);
1549
update_registration_status(status);
1551
get_property(CSD_CSNET_OPERATOR, "OperatorName");
1552
get_property(CSD_CSNET_SIGNAL, "SignalBars");
1553
} else if (g_strcmp0(prop, "OperatorName") == 0) {
1556
dbus_message_iter_get_basic(&sub, &name);
1557
update_operator_name(name);
1558
} else if (g_strcmp0(prop, "SignalBars") == 0) {
1559
int32_t signal_bars;
1561
dbus_message_iter_get_basic(&sub, &signal_bars);
1562
update_signal_strength(signal_bars);
1567
dbus_message_unref(reply);
1568
remove_pending(call);
1571
static int get_property(const char *iface, const char *prop)
1573
return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
1574
DBUS_INTERFACE_PROPERTIES, "Get",
1575
get_property_reply, g_strdup(prop),
1576
DBUS_TYPE_STRING, &iface,
1577
DBUS_TYPE_STRING, &prop,
1581
static void handle_operator_name_changed(DBusMessage *msg)
1585
if (!dbus_message_get_args(msg, NULL,
1586
DBUS_TYPE_STRING, &name,
1587
DBUS_TYPE_INVALID)) {
1588
error("Unexpected parameters in OperatorNameChanged");
1592
update_operator_name(name);
1595
static void call_info_reply(DBusPendingCall *call, void *user_data)
1599
DBusMessageIter iter, sub;;
1601
get_calls_active = FALSE;
1603
reply = dbus_pending_call_steal_reply(call);
1605
dbus_error_init(&err);
1606
if (dbus_set_error_from_message(&err, reply)) {
1607
error("csd replied with an error: %s, %s",
1608
err.name, err.message);
1609
dbus_error_free(&err);
1613
dbus_message_iter_init(reply, &iter);
1615
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1616
error("Unexpected signature in GetCallInfoAll return");
1620
dbus_message_iter_recurse(&iter, &sub);
1622
parse_call_list(&sub);
1624
get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
1627
dbus_message_unref(reply);
1628
remove_pending(call);
1632
static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
1636
const char *name, *number, *secondname, *additionalnumber, *email;
1638
char **number_type = user_data;
1640
reply = dbus_pending_call_steal_reply(call);
1642
dbus_error_init(&derr);
1643
if (dbus_set_error_from_message(&derr, reply)) {
1644
error("%s.ReadFirst replied with an error: %s, %s",
1645
CSD_SIMPB_INTERFACE, derr.name, derr.message);
1646
dbus_error_free(&derr);
1647
if (number_type == &vmbx)
1648
vmbx = g_strdup(getenv("VMBX_NUMBER"));
1652
dbus_error_init(&derr);
1653
if (dbus_message_get_args(reply, NULL,
1654
DBUS_TYPE_INT32, &index,
1655
DBUS_TYPE_STRING, &name,
1656
DBUS_TYPE_STRING, &number,
1657
DBUS_TYPE_STRING, &secondname,
1658
DBUS_TYPE_STRING, &additionalnumber,
1659
DBUS_TYPE_STRING, &email,
1660
DBUS_TYPE_INVALID) == FALSE) {
1661
error("Unable to parse %s.ReadFirst arguments: %s, %s",
1662
CSD_SIMPB_INTERFACE, derr.name, derr.message);
1663
dbus_error_free(&derr);
1667
if (number_type == &msisdn) {
1669
msisdn = g_strdup(number);
1670
DBG("Got MSISDN %s (%s)", number, name);
1673
vmbx = g_strdup(number);
1674
DBG("Got voice mailbox number %s (%s)", number, name);
1678
dbus_message_unref(reply);
1679
remove_pending(call);
1682
static void csd_init(void)
1684
const char *pb_type;
1687
ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1688
CSD_CALL_INTERFACE, "GetCallInfoAll",
1689
call_info_reply, NULL, DBUS_TYPE_INVALID);
1691
error("Unable to sent GetCallInfoAll method call");
1695
get_calls_active = TRUE;
1697
pb_type = CSD_SIMPB_TYPE_MSISDN;
1699
ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
1700
CSD_SIMPB_INTERFACE, "ReadFirst",
1701
phonebook_read_reply, &msisdn,
1702
DBUS_TYPE_STRING, &pb_type,
1705
error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
1709
/* Voicemail should be in MBDN index 0 */
1710
pb_type = CSD_SIMPB_TYPE_MBDN;
1712
ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
1713
CSD_SIMPB_INTERFACE, "ReadFirst",
1714
phonebook_read_reply, &vmbx,
1715
DBUS_TYPE_STRING, &pb_type,
1718
error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
1723
static inline DBusMessage *invalid_args(DBusMessage *msg)
1725
return g_dbus_create_error(msg,"org.bluez.Error.InvalidArguments",
1726
"Invalid arguments in method call");
1729
static uint32_t get_callflag(const char *callerid_setting)
1731
if (callerid_setting != NULL) {
1732
if (g_str_equal(callerid_setting, "allowed"))
1733
return CALL_FLAG_PRESENTATION_ALLOWED;
1734
else if (g_str_equal(callerid_setting, "restricted"))
1735
return CALL_FLAG_PRESENTATION_RESTRICTED;
1737
return CALL_FLAG_NONE;
1739
return CALL_FLAG_NONE;
1742
static void generate_flag_file(const char *filename)
1746
if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
1747
g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
1748
g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
1751
fd = open(filename, O_WRONLY | O_CREAT, 0);
1756
static void save_callerid_to_file(const char *callerid_setting)
1758
char callerid_file[FILENAME_MAX];
1760
snprintf(callerid_file, sizeof(callerid_file), "%s%s",
1761
CALLERID_BASE, callerid_setting);
1763
if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
1764
rename(ALLOWED_FLAG_FILE, callerid_file);
1765
else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
1766
rename(RESTRICTED_FLAG_FILE, callerid_file);
1767
else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
1768
rename(NONE_FLAG_FILE, callerid_file);
1770
generate_flag_file(callerid_file);
1773
static uint32_t callerid_from_file(void)
1775
if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
1776
return CALL_FLAG_PRESENTATION_ALLOWED;
1777
else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
1778
return CALL_FLAG_PRESENTATION_RESTRICTED;
1779
else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
1780
return CALL_FLAG_NONE;
1782
return CALL_FLAG_NONE;
1785
static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
1788
const char *callerid_setting;
1790
if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING,
1792
DBUS_TYPE_INVALID) == FALSE)
1793
return invalid_args(msg);
1795
if (g_str_equal(callerid_setting, "allowed") ||
1796
g_str_equal(callerid_setting, "restricted") ||
1797
g_str_equal(callerid_setting, "none")) {
1798
save_callerid_to_file(callerid_setting);
1799
callerid = get_callflag(callerid_setting);
1800
DBG("telephony-maemo6 setting callerid flag: %s",
1802
return dbus_message_new_method_return(msg);
1805
error("telephony-maemo6: invalid argument %s for method call"
1806
" SetCallerId", callerid_setting);
1807
return invalid_args(msg);
1810
static DBusMessage *clear_lastnumber(DBusConnection *conn, DBusMessage *msg,
1813
g_free(last_dialed_number);
1814
last_dialed_number = NULL;
1816
return dbus_message_new_method_return(msg);
1819
static GDBusMethodTable telephony_maemo_methods[] = {
1820
{ "SetCallerId", "s", "", set_callerid,
1821
G_DBUS_METHOD_FLAG_ASYNC },
1822
{ "ClearLastNumber", "", "", clear_lastnumber },
1826
static void handle_modem_state(DBusMessage *msg)
1830
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
1831
DBUS_TYPE_INVALID)) {
1832
error("Unexpected modem state parameters");
1836
DBG("SSC modem state: %s", state);
1838
if (calls != NULL || get_calls_active)
1841
if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
1845
static void modem_state_reply(DBusPendingCall *call, void *user_data)
1847
DBusMessage *reply = dbus_pending_call_steal_reply(call);
1850
dbus_error_init(&err);
1851
if (dbus_set_error_from_message(&err, reply)) {
1852
error("get_modem_state: %s, %s", err.name, err.message);
1853
dbus_error_free(&err);
1855
handle_modem_state(reply);
1857
dbus_message_unref(reply);
1858
remove_pending(call);
1861
static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
1864
const char *path = dbus_message_get_path(msg);
1866
if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
1867
handle_incoming_call(msg);
1868
else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
1869
handle_outgoing_call(msg);
1870
else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
1872
handle_create_requested(msg);
1873
else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
1874
handle_call_status(msg, path);
1875
else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
1876
handle_conference(msg, TRUE);
1877
else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
1878
handle_conference(msg, FALSE);
1879
else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
1880
"RegistrationChanged"))
1881
handle_registration_changed(msg);
1882
else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
1883
"OperatorNameChanged"))
1884
handle_operator_name_changed(msg);
1885
else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
1886
"SignalBarsChanged"))
1887
handle_signal_bars_changed(msg);
1888
else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
1889
"PropertyModified"))
1890
handle_hal_property_modified(msg);
1891
else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
1892
"modem_state_changed_ind"))
1893
handle_modem_state(msg);
1898
static void add_watch(const char *sender, const char *path,
1899
const char *interface, const char *member)
1903
watch = g_dbus_add_signal_watch(connection, sender, path, interface,
1904
member, signal_filter, NULL, NULL);
1906
watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1909
static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
1913
DBusMessageIter iter, sub;
1917
reply = dbus_pending_call_steal_reply(call);
1919
dbus_error_init(&err);
1920
if (dbus_set_error_from_message(&err, reply)) {
1921
error("hald replied with an error: %s, %s",
1922
err.name, err.message);
1923
dbus_error_free(&err);
1927
dbus_message_iter_init(reply, &iter);
1929
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1930
error("Unexpected signature in FindDeviceByCapability return");
1934
dbus_message_iter_recurse(&iter, &sub);
1936
type = dbus_message_iter_get_arg_type(&sub);
1938
if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
1939
error("No hal device with battery capability found");
1943
dbus_message_iter_get_basic(&sub, &path);
1945
DBG("telephony-maemo6: found battery device at %s", path);
1947
add_watch(NULL, path, "org.freedesktop.Hal.Device",
1948
"PropertyModified");
1950
hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
1951
hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
1952
hal_get_integer(path, "battery.charge_level.design", &battchg_design);
1955
dbus_message_unref(reply);
1956
remove_pending(call);
1959
int telephony_init(void)
1961
const char *battery_cap = "battery";
1962
uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1963
AG_FEATURE_INBAND_RINGTONE |
1964
AG_FEATURE_REJECT_A_CALL |
1965
AG_FEATURE_ENHANCED_CALL_STATUS |
1966
AG_FEATURE_ENHANCED_CALL_CONTROL |
1967
AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
1968
AG_FEATURE_THREE_WAY_CALLING;
1972
connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1974
add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL);
1975
add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL);
1976
add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL);
1977
add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged");
1978
add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged");
1979
add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged");
1980
add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind");
1982
if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
1983
"get_modem_state", modem_state_reply,
1984
NULL, DBUS_TYPE_INVALID) < 0)
1985
error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
1987
generate_flag_file(NONE_FLAG_FILE);
1988
callerid = callerid_from_file();
1990
if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
1991
TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
1992
NULL, NULL, NULL, NULL)) {
1993
error("telephony-maemo6 interface %s init failed on path %s",
1994
TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
1997
DBG("telephony-maemo6 registering %s interface on path %s",
1998
TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
2000
telephony_ready_ind(features, maemo_indicators, response_and_hold,
2002
if (send_method_call("org.freedesktop.Hal",
2003
"/org/freedesktop/Hal/Manager",
2004
"org.freedesktop.Hal.Manager",
2005
"FindDeviceByCapability",
2006
hal_find_device_reply, NULL,
2007
DBUS_TYPE_STRING, &battery_cap,
2008
DBUS_TYPE_INVALID) < 0)
2009
error("Unable to send HAL method call");
2014
static void remove_watch(gpointer data)
2016
g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
2019
void telephony_exit(void)
2023
g_free(net.operator_name);
2024
net.operator_name = NULL;
2026
g_free(last_dialed_number);
2027
last_dialed_number = NULL;
2029
g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
2030
g_slist_free(calls);
2033
g_slist_foreach(pending, (GFunc) dbus_pending_call_cancel, NULL);
2034
g_slist_foreach(pending, (GFunc) dbus_pending_call_unref, NULL);
2035
g_slist_free(pending);
2038
g_slist_foreach(watches, (GFunc) remove_watch, NULL);
2039
g_slist_free(watches);
2042
g_dbus_unregister_interface(connection, TELEPHONY_MAEMO_PATH,
2043
TELEPHONY_MAEMO_INTERFACE);
2045
dbus_connection_unref(connection);