Fixes TC-1775 - dbus command fails
[profile/ivi/lemolo.git] / dialer / rc.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <Elementary.h>
5 #include <Eldbus.h>
6
7 #ifdef HAVE_NOTIFICATION
8 #include <appsvc.h>
9 #include <notification.h>
10 #endif
11
12 #include "log.h"
13 #include "gui.h"
14 #include "ofono.h"
15
16 static Eldbus_Connection *bus_conn = NULL;
17 static Eldbus_Service_Interface *bus_iface = NULL;
18
19 #define RC_IFACE "org.tizen.dialer.Control"
20 #define RC_PATH "/"
21 #define RC_SIG_CALL_ADDED "AddedCall"
22 #define RC_SIG_CALL_REMOVED "RemovedCall"
23
24 enum {
25    RC_SIGNAL_CALL_ADDED,
26    RC_SIGNAL_CALL_REMOVED
27 };
28
29 static const char *rc_service = NULL;
30 static OFono_Callback_List_Modem_Node *modem_changed_node = NULL;
31 static OFono_Callback_List_Call_Node *call_added = NULL;
32 static OFono_Callback_List_Call_Node *call_removed = NULL;
33 static OFono_Callback_List_Call_Node *call_changed = NULL;
34 static Eldbus_Message *pending_dial = NULL;
35 static OFono_Call *waiting = NULL;
36
37 static void _dial_number(const char *number, Eina_Bool do_auto)
38 {
39         INF("dial '%s' auto=%d!", number, do_auto);
40         gui_activate();
41         gui_call_exit();
42         gui_number_set(number, do_auto);
43 }
44
45 static void _modem_changed_cb(void *data __UNUSED__)
46 {
47         const char *number;
48         Eina_Bool do_auto;
49         Eldbus_Message *reply;
50
51         if (!ofono_voice_is_online() || !pending_dial)
52                 return;
53
54         if (!eldbus_message_arguments_get(pending_dial, "sb", &number, &do_auto)) {
55                 ERR("Could not pending dial arguments");
56                 reply = eldbus_message_error_new(pending_dial, "Pending dial", "Invalid argument");
57                 goto reply_send;
58         }
59
60         _dial_number(number, do_auto);
61         reply = eldbus_message_method_return_new(pending_dial);
62 reply_send:
63         eldbus_connection_send(bus_conn, reply, NULL, NULL, -1);
64         eldbus_message_unref(pending_dial);
65         pending_dial = NULL;
66 }
67
68 static Eldbus_Message *
69 _rc_activate(Eldbus_Object *obj __UNUSED__, Eldbus_Message *msg)
70 {
71         INF("Remotely activated!");
72         gui_activate();
73         return eldbus_message_method_return_new(msg);
74 }
75
76 static Eldbus_Message *
77 _rc_dial(Eldbus_Object *obj __UNUSED__, Eldbus_Message *msg)
78 {
79         Eina_Bool do_auto;
80         const char *number;
81
82         if (!ofono_voice_is_online()) {
83                 if (pending_dial)
84                         eldbus_message_unref(pending_dial);
85                 pending_dial = eldbus_message_ref(msg);
86                 return NULL;
87         }
88
89         if (!eldbus_message_arguments_get(msg, "sb", &number, &do_auto)) {
90                 ERR("Could not get rc dial arguments");
91                 return eldbus_message_error_new(msg, "RC dial", "Invalid argument");
92         }
93
94         _dial_number(number, do_auto);
95         return eldbus_message_method_return_new(msg);
96 }
97
98 static Eldbus_Message *_rc_hangup_call(Eldbus_Object *obj __UNUSED__,
99                                                 Eldbus_Message *msg)
100 {
101         if (!waiting) {
102                 return eldbus_message_error_new(msg,
103                                         "org.tizen.dialer.error.NotAvailable",
104                                         "No calls available");
105         }
106
107         ofono_call_hangup(waiting, NULL, NULL);
108
109         return eldbus_message_method_return_new(msg);
110 }
111
112 static Eldbus_Message *_rc_answer_call(Eldbus_Object *obj __UNUSED__,
113                                                 Eldbus_Message *msg)
114 {
115         OFono_Call_State state;
116
117         if (!waiting) {
118                 return eldbus_message_error_new(msg,
119                                         "org.tizen.dialer.error.NotAvailable",
120                                         "No calls available");
121         }
122
123         state = ofono_call_state_get(waiting);
124         if (state == OFONO_CALL_STATE_INCOMING)
125                 ofono_call_answer(waiting, NULL, NULL);
126         else if (state == OFONO_CALL_STATE_WAITING)
127                 ofono_hold_and_answer(NULL, NULL);
128
129         return eldbus_message_method_return_new(msg);
130 }
131
132 static void _new_call_sig_emit(OFono_Call *call)
133 {
134         Eldbus_Message *msg;
135         const char *line_id, *name = "", *type = "", *img = "";
136         Contact_Info *c_info;
137
138         line_id = ofono_call_line_id_get(call);
139         c_info = gui_contact_search(line_id, &type);
140
141         if (c_info) {
142                 name = contact_info_full_name_get(c_info);
143                 img = contact_info_picture_get(c_info);
144                 if (!img)
145                         img = "";
146         }
147
148         msg = eldbus_service_signal_new(bus_iface, RC_SIGNAL_CALL_ADDED);
149         EINA_SAFETY_ON_NULL_RETURN(msg);
150
151         eldbus_message_arguments_append(msg,"ssss", img, line_id, name, type);
152         eldbus_service_signal_send(bus_iface, msg);
153 }
154
155 #ifdef HAVE_NOTIFICATION
156 static void _system_notification_emit(OFono_Call *call)
157 {
158         const char *line_id, *type="", *content = "";
159         const char *title = "Incoming call";
160         Contact_Info *c_info;
161         notification_h noti = NULL;
162         notification_error_e noti_err = NOTIFICATION_ERROR_NONE;
163
164         noti = notification_new(NOTIFICATION_TYPE_NOTI,
165                                 NOTIFICATION_GROUP_ID_NONE,
166                                 NOTIFICATION_PRIV_ID_NONE);
167         if (noti == NULL) {
168                 ERR("Failed to create notification");
169                 return;
170         }
171
172         noti_err = notification_set_pkgname(noti, "org.tizen.dialer");
173         if (noti_err != NOTIFICATION_ERROR_NONE) {
174                 ERR("Failed to set pkgname: %d", noti_err);
175                 return;
176         }
177
178         noti_err = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_TITLE,
179                                         title,
180                                         NULL,
181                                         NOTIFICATION_VARIABLE_TYPE_NONE);
182         if (noti_err != NOTIFICATION_ERROR_NONE) {
183                 ERR("Failed to set notification title: %d", noti_err);
184                 return;
185         }
186
187         line_id = ofono_call_line_id_get(call);
188         c_info = gui_contact_search(line_id, &type);
189
190         if (c_info) {
191                 content = contact_info_full_name_get(c_info);
192         } else {
193                 content = line_id;
194         }
195
196         noti_err = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT,
197                                         content,
198                                         NULL,
199                                         NOTIFICATION_VARIABLE_TYPE_NONE);
200         if (noti_err != NOTIFICATION_ERROR_NONE) {
201                 ERR("Failed to set notification content: %d", noti_err);
202                 return;
203         }
204
205         bundle *b = NULL;
206         b = bundle_create();
207         appsvc_set_pkgname(b, "org.tizen.dialer");
208         noti_err = notification_set_execute_option(noti, NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, "Launch", NULL, b);
209         if (noti_err != NOTIFICATION_ERROR_NONE) {
210                 ERR("Failed to set notification execute option: %d", noti_err);
211                 return;
212         }
213
214         noti_err = notification_insert(noti, NULL);
215         if (noti_err != NOTIFICATION_ERROR_NONE) {
216                 ERR("Failed to send notification: %d", noti_err);
217                 return;
218         }
219         DBG("Sent notification: %s : %s", title, content);
220
221         noti_err = notification_free(noti);
222         if (noti_err != NOTIFICATION_ERROR_NONE) {
223                 ERR("Failed to free notification: %d", noti_err);
224                 return;
225         }
226 }
227 #endif
228
229 static Eldbus_Message *_rc_waiting_call_get(Eldbus_Object *obj __UNUSED__,
230                                                 Eldbus_Message *msg)
231 {
232         Eldbus_Message *ret;
233         const char *line_id, *name = "", *type = "", *img = "";
234         Contact_Info *c_info;
235
236
237         if (!waiting) {
238                 return eldbus_message_error_new(msg,
239                                         "org.tizen.dialer.error.NotAvailable",
240                                         "No calls available");
241         }
242
243         line_id = ofono_call_line_id_get(waiting);
244         c_info = gui_contact_search(line_id, &type);
245
246         if (c_info) {
247                 name = contact_info_full_name_get(c_info);
248                 img = contact_info_picture_get(c_info);
249                 if (!img)
250                         img = "";
251         }
252
253         ret = eldbus_message_method_return_new(msg);
254         eldbus_message_arguments_append(msg,"ssss", img, line_id, name, type);
255
256         return ret;
257 }
258
259 static const Eldbus_Method rc_methods[] = {
260         { "Activate", NULL, NULL, _rc_activate, },
261         { "Dial", ELDBUS_ARGS(
262                 {"s", "number"},
263                 {"b", "do_auto"}), NULL, _rc_dial },
264         { "HangupCall", NULL, NULL, _rc_hangup_call, },
265         { "AnswerCall", NULL, NULL, _rc_answer_call, },
266         { "GetAvailableCall", NULL, ELDBUS_ARGS(
267                 {"s", "img"},
268                 {"s", "line_id"},
269                 {"s", "name"},
270                 {"s", "type"}), _rc_waiting_call_get, ELDBUS_METHOD_FLAG_DEPRECATED },
271         { }
272 };
273
274 static const Eldbus_Signal rc_signals[] = {
275    [RC_SIGNAL_CALL_ADDED] = { "AddedCall", ELDBUS_ARGS(
276                 {"s", "img"},
277                 {"s", "line_id"},
278                 {"s", "name"},
279                 {"s", "type"}), 0},
280    [RC_SIGNAL_CALL_REMOVED] = { "RemovedCall", NULL, 0 },
281    { NULL}
282 };
283
284 static const Eldbus_Service_Interface_Desc rc_iface_desc = {
285    RC_IFACE, rc_methods, rc_signals, NULL, NULL, NULL
286 };
287
288 static void _rc_object_register(void)
289 {
290         bus_iface = eldbus_service_interface_register(bus_conn, RC_PATH, &rc_iface_desc);
291 }
292
293 static void _rc_activate_existing_reply(void *data __UNUSED__, const Eldbus_Message *msg,
294                                                 Eldbus_Pending *pending __UNUSED__)
295 {
296         const char *err_name, *err_message;
297
298         EINA_SAFETY_ON_NULL_RETURN(msg);
299
300         if (eldbus_message_error_get(msg, &err_name, &err_message)) {
301                 ERR("Failed to activate existing dialer: %s: %s", err_name, err_message);
302                 _app_exit_code = EXIT_FAILURE;
303                 ecore_main_loop_quit();
304                 return;
305         }
306
307         INF("Activated the existing dialer!");
308         ecore_main_loop_quit();
309 }
310
311 static void _rc_activate_existing(void)
312 {
313         Eldbus_Message *msg = eldbus_message_method_call_new(
314                 rc_service, RC_PATH, RC_IFACE, "Activate");
315         eldbus_connection_send(bus_conn, msg, _rc_activate_existing_reply, NULL, -1);
316 }
317
318 static void _rc_request_name_reply(void *data __UNUSED__, Eldbus_Message *msg,
319                                                 Eldbus_Pending *pending __UNUSED__)
320 {
321         int t;
322         const char *err_name, *err_message;
323
324         EINA_SAFETY_ON_NULL_RETURN(msg);
325
326         if (eldbus_message_error_get(msg, &err_name, &err_message)) {
327                 ERR("Failed to request name: %s: %s", err_name, err_message);
328                 return;
329         }
330
331         if (!eldbus_message_arguments_get(msg, "u", &t)) {
332                 ERR("Could not get request name arguments");
333                 _rc_activate_existing();
334                 return;
335         }
336
337         if (t == ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER) {
338                 _rc_object_register();
339                 gui_activate();
340         } else {
341                 WRN("Dialer already running! Activate it!");
342                 _rc_activate_existing();
343         }
344 }
345
346 static void _removed_signal_send(void)
347 {
348         Eldbus_Message *msg;
349
350         msg = eldbus_service_signal_new(bus_iface, RC_SIGNAL_CALL_REMOVED);
351         EINA_SAFETY_ON_NULL_RETURN(msg);
352
353         eldbus_service_signal_send(bus_iface, msg);
354 }
355
356 static void _rc_call_added_cb(void *data __UNUSED__, OFono_Call *call)
357 {
358         OFono_Call_State state = ofono_call_state_get(call);
359
360         if (state != OFONO_CALL_STATE_INCOMING &&
361                 state != OFONO_CALL_STATE_WAITING)
362                 return;
363
364         if (waiting)
365                 _removed_signal_send();
366
367         waiting = call;
368         _new_call_sig_emit(call);
369
370 #ifdef HAVE_NOTIFICATION
371         _system_notification_emit(call);
372 #endif
373 }
374
375 static void _rc_call_removed_cb(void *data __UNUSED__, OFono_Call *call)
376 {
377         if (waiting != call)
378                 return;
379         _removed_signal_send();
380         waiting = NULL;
381 }
382
383 static void _rc_call_changed_cb(void *data __UNUSED__, OFono_Call *call)
384 {
385         OFono_Call_State state;
386
387         if (waiting != call)
388                 return;
389
390         state = ofono_call_state_get(call);
391         if (state == OFONO_CALL_STATE_INCOMING ||
392                 state == OFONO_CALL_STATE_WAITING)
393                 return;
394
395         _removed_signal_send();
396         waiting = NULL;
397 }
398
399 Eina_Bool rc_init(const char *service)
400 {
401         rc_service = service;
402
403         if (!elm_need_eldbus()) {
404                 CRITICAL("Elementary does not support DBus.");
405                 return EINA_FALSE;
406         }
407
408         INF("Running on Session bus");
409         bus_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
410
411         if (!bus_conn) {
412                 CRITICAL("Could not get DBus Bus");
413                 return EINA_FALSE;
414         }
415
416         eldbus_name_request(bus_conn, rc_service, ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
417                                 _rc_request_name_reply, NULL);
418
419         modem_changed_node = ofono_modem_changed_cb_add(_modem_changed_cb,
420                                                         NULL);
421
422         call_added = ofono_call_added_cb_add(_rc_call_added_cb, NULL);
423         call_removed = ofono_call_removed_cb_add(_rc_call_removed_cb, NULL);
424         call_changed = ofono_call_changed_cb_add(_rc_call_changed_cb, NULL);
425
426         return EINA_TRUE;
427 }
428
429 void rc_shutdown(void)
430 {
431         if (bus_iface)
432                 eldbus_service_interface_unregister(bus_iface);
433
434         ofono_modem_changed_cb_del(modem_changed_node);
435         ofono_call_added_cb_del(call_added);
436         ofono_call_removed_cb_del(call_removed);
437         ofono_call_changed_cb_del(call_changed);
438
439         if (pending_dial)
440                 eldbus_message_unref(pending_dial);
441
442         bus_conn = NULL;
443 }