Port to Tizen 2.0alpha with the exception of contacts handling
[profile/ivi/lemolo.git] / dialer / rc.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <Elementary.h>
5
6 #include "log.h"
7 #include "gui.h"
8 #include "ofono.h"
9
10 static E_DBus_Connection *bus_conn = NULL;
11 static E_DBus_Object *bus_obj = NULL;
12 static E_DBus_Interface *bus_iface = NULL;
13
14 #define RC_IFACE "org.tizen.dialer.Control"
15 #define RC_PATH "/"
16 #define RC_SIG_CALL_ADDED "AddedCall"
17 #define RC_SIG_CALL_REMOVED "RemovedCall"
18
19 static const char *rc_service = NULL;
20 static OFono_Callback_List_Modem_Node *modem_changed_node = NULL;
21 static OFono_Callback_List_Call_Node *call_added = NULL;
22 static OFono_Callback_List_Call_Node *call_removed = NULL;
23 static OFono_Callback_List_Call_Node *call_changed = NULL;
24 static DBusMessage *pending_dial = NULL;
25 static OFono_Call *waiting = NULL;
26
27 static void _dial_number(const char *number, Eina_Bool do_auto)
28 {
29         INF("dial '%s' auto=%d!", number, do_auto);
30         gui_activate();
31         gui_call_exit();
32         gui_number_set(number, do_auto);
33 }
34
35 static void _modem_changed_cb(void *data __UNUSED__)
36 {
37         DBusError err;
38         const char *number;
39         dbus_bool_t do_auto;
40         DBusMessage *reply;
41
42         if (!ofono_voice_is_online() || !pending_dial)
43                 return;
44
45         dbus_error_init(&err);
46         dbus_message_get_args(pending_dial, &err, DBUS_TYPE_STRING, &number,
47                                 DBUS_TYPE_BOOLEAN, &do_auto, DBUS_TYPE_INVALID);
48
49         if (dbus_error_is_set(&err)) {
50                 ERR("Could not parse message: %s: %s", err.name, err.message);
51                 reply = dbus_message_new_error(pending_dial, err.name,
52                                                 err.message);
53                 goto reply_send;
54         }
55
56         _dial_number(number, do_auto);
57         reply = dbus_message_new_method_return(pending_dial);
58 reply_send:
59         e_dbus_message_send(bus_conn, reply, NULL, -1, NULL);
60         dbus_message_unref(pending_dial);
61         dbus_message_unref(reply);
62         pending_dial = NULL;
63 }
64
65 static DBusMessage *
66 _rc_activate(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
67 {
68         INF("Remotely activated!");
69         gui_activate();
70         return dbus_message_new_method_return(msg);
71 }
72
73 static DBusMessage *
74 _rc_dial(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
75 {
76         DBusError err;
77         dbus_bool_t do_auto;
78         const char *number;
79
80         if (!ofono_voice_is_online()) {
81                 if (pending_dial)
82                         dbus_message_unref(pending_dial);
83                 pending_dial = dbus_message_ref(msg);
84                 return NULL;
85         }
86
87         dbus_error_init(&err);
88         dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &number,
89                                 DBUS_TYPE_BOOLEAN, &do_auto, DBUS_TYPE_INVALID);
90         if (dbus_error_is_set(&err)) {
91                 ERR("Could not parse message: %s: %s", err.name, err.message);
92                 return dbus_message_new_error(msg, err.name, err.message);
93         }
94         _dial_number(number, do_auto);
95         return dbus_message_new_method_return(msg);
96 }
97
98 static DBusMessage *_rc_hangup_call(E_DBus_Object *obj __UNUSED__,
99                                                 DBusMessage *msg)
100 {
101         if (!waiting) {
102                 return dbus_message_new_error(msg,
103                                         "org.tizen.dialer.error.NotAvailable",
104                                         "No calls available");
105         }
106
107         ofono_call_hangup(waiting, NULL, NULL);
108
109         return dbus_message_new_method_return(msg);
110 }
111
112 static DBusMessage *_rc_answer_call(E_DBus_Object *obj __UNUSED__,
113                                                 DBusMessage *msg)
114 {
115         OFono_Call_State state;
116
117         if (!waiting) {
118                 return dbus_message_new_error(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 dbus_message_new_method_return(msg);
130 }
131
132 static void _rc_signal_reply(void *data __UNUSED__,
133                                         DBusMessage *msg __UNUSED__,
134                                         DBusError *err)
135 {
136         if (dbus_error_is_set(err)) {
137                 CRITICAL("Failed to send a signal: %s: %s",
138                                 err->name, err->message);
139                 return;
140         }
141
142         DBG("Signal was sent successfully");
143 }
144
145 static void _new_call_sig_emit(OFono_Call *call)
146 {
147         DBusMessage *msg;
148         const char *line_id, *name = "", *type = "", *img = "";
149         Contact_Info *c_info;
150
151         line_id = ofono_call_line_id_get(call);
152         c_info = gui_contact_search(line_id, &type);
153
154         if (c_info) {
155                 name = contact_info_full_name_get(c_info);
156                 img = contact_info_picture_get(c_info);
157                 if (!img)
158                         img = "";
159         }
160
161         msg = dbus_message_new_signal(RC_PATH, RC_IFACE, RC_SIG_CALL_ADDED);
162         EINA_SAFETY_ON_NULL_RETURN(msg);
163
164         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &img,
165                                         DBUS_TYPE_STRING, &line_id,
166                                         DBUS_TYPE_STRING, &name,
167                                         DBUS_TYPE_STRING, &type,
168                                         DBUS_TYPE_INVALID)) {
169                 ERR("Could not append msg args.");
170                 goto err_args;
171         }
172
173         e_dbus_message_send(bus_conn, msg, _rc_signal_reply, -1, NULL);
174 err_args:
175         dbus_message_unref(msg);
176 }
177
178 static DBusMessage *_rc_waiting_call_get(E_DBus_Object *obj __UNUSED__,
179                                                 DBusMessage *msg)
180 {
181         DBusMessage *ret;
182         const char *line_id, *name = "", *type = "", *img = "";
183         Contact_Info *c_info;
184
185
186         if (!waiting) {
187                 return dbus_message_new_error(msg,
188                                         "org.tizen.dialer.error.NotAvailable",
189                                         "No calls available");
190         }
191
192         line_id = ofono_call_line_id_get(waiting);
193         c_info = gui_contact_search(line_id, &type);
194
195         if (c_info) {
196                 name = contact_info_full_name_get(c_info);
197                 img = contact_info_picture_get(c_info);
198                 if (!img)
199                         img = "";
200         }
201
202         ret = dbus_message_new_method_return(msg);
203         EINA_SAFETY_ON_NULL_GOTO(ret, err_ret);
204
205         if (!dbus_message_append_args(ret, DBUS_TYPE_STRING, &img,
206                                         DBUS_TYPE_STRING, &line_id,
207                                         DBUS_TYPE_STRING, &name,
208                                         DBUS_TYPE_STRING, &type,
209                                         DBUS_TYPE_INVALID)) {
210                 ERR("Could not append msg args.");
211                 goto err_args;
212         }
213
214         return ret;
215
216 err_args:
217         dbus_message_unref(ret);
218
219 err_ret:
220         return dbus_message_new_error(msg,
221                                         "org.tizen.dialer.error.Error",
222                                         "Could not create a reply");
223 }
224
225 static void _rc_object_register(void)
226 {
227         bus_obj = e_dbus_object_add(bus_conn, RC_PATH, NULL);
228         if (!bus_obj) {
229                 CRITICAL("Could not create "RC_PATH" DBus object.");
230                 return;
231         }
232         bus_iface = e_dbus_interface_new(RC_IFACE);
233         e_dbus_object_interface_attach(bus_obj, bus_iface);
234
235 #define IF_ADD(name, par, ret, cb)              \
236         e_dbus_interface_method_add(bus_iface, name, par, ret, cb)
237
238         IF_ADD("Activate", "", "", _rc_activate);
239         IF_ADD("Dial", "sb", "", _rc_dial);
240         IF_ADD("HangupCall", "", "", _rc_hangup_call);
241         IF_ADD("AnswerCall", "", "", _rc_answer_call);
242         IF_ADD("GetAvailableCall", "", "ssss", _rc_waiting_call_get);
243 #undef IF_ADD
244
245         e_dbus_interface_signal_add(bus_iface, RC_SIG_CALL_ADDED,
246                                         "ssss");
247         e_dbus_interface_signal_add(bus_iface, RC_SIG_CALL_REMOVED,
248                                         "");
249 }
250
251 static void _rc_activate_existing_reply(void *data __UNUSED__,
252                                         DBusMessage *msg __UNUSED__,
253                                         DBusError *err)
254 {
255         if (dbus_error_is_set(err)) {
256                 CRITICAL("Failed to activate existing dialer: %s: %s",
257                                 err->name, err->message);
258                 _app_exit_code = EXIT_FAILURE;
259                 ecore_main_loop_quit();
260                 return;
261         }
262
263         INF("Activated the existing dialer!");
264         ecore_main_loop_quit();
265 }
266
267 static void _rc_activate_existing(void)
268 {
269         DBusMessage *msg = dbus_message_new_method_call(
270                 rc_service, RC_PATH, RC_IFACE, "Activate");
271         e_dbus_message_send(bus_conn, msg,  _rc_activate_existing_reply,
272                                 -1, NULL);
273         dbus_message_unref(msg);
274 }
275
276 static void _rc_request_name_reply(void *data __UNUSED__, DBusMessage *msg,
277                                         DBusError *err)
278 {
279         DBusError e;
280         dbus_uint32_t t;
281
282         if (!msg) {
283                 if (err)
284                         WRN("%s: %s", err->name, err->message);
285                 else
286                         WRN("No message");
287                 _rc_activate_existing();
288                 return;
289         }
290
291         dbus_error_init(&e);
292         dbus_message_get_args(msg, &e, DBUS_TYPE_UINT32, &t, DBUS_TYPE_INVALID);
293         if (t == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
294                 _rc_object_register();
295                 gui_activate();
296         } else {
297                 WRN("Dialer already running! Activate it!");
298                 _rc_activate_existing();
299         }
300 }
301
302 static void _removed_signal_send(void)
303 {
304         DBusMessage *msg;
305
306         msg = dbus_message_new_signal(RC_PATH, RC_IFACE, RC_SIG_CALL_REMOVED);
307         EINA_SAFETY_ON_NULL_RETURN(msg);
308
309         e_dbus_message_send(bus_conn, msg, _rc_signal_reply, -1, NULL);
310
311         dbus_message_unref(msg);
312 }
313
314 static void _rc_call_added_cb(void *data __UNUSED__, OFono_Call *call)
315 {
316         OFono_Call_State state = ofono_call_state_get(call);
317
318         if (state != OFONO_CALL_STATE_INCOMING &&
319                 state != OFONO_CALL_STATE_WAITING)
320                 return;
321
322         if (waiting)
323                 _removed_signal_send();
324
325         waiting = call;
326         _new_call_sig_emit(call);
327
328 }
329
330 static void _rc_call_removed_cb(void *data __UNUSED__, OFono_Call *call)
331 {
332         if (waiting != call)
333                 return;
334         _removed_signal_send();
335         waiting = NULL;
336 }
337
338 static void _rc_call_changed_cb(void *data __UNUSED__, OFono_Call *call)
339 {
340         OFono_Call_State state;
341
342         if (waiting != call)
343                 return;
344
345         state = ofono_call_state_get(call);
346         if (state == OFONO_CALL_STATE_INCOMING ||
347                 state == OFONO_CALL_STATE_WAITING)
348                 return;
349
350         _removed_signal_send();
351         waiting = NULL;
352 }
353
354 Eina_Bool rc_init(const char *service)
355 {
356         rc_service = service;
357
358         if (!elm_need_e_dbus()) {
359                 CRITICAL("Elementary does not support DBus.");
360                 return EINA_FALSE;
361         }
362
363 #ifdef HAVE_TIZEN
364         /* NOTE: Tizen is stupid and does not have a session bus.  at
365          * least not for user "app". Moreover the dialer is started by
366          * user "root" :-(
367          */
368         INF("Running on System bus");
369         bus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
370 #else
371         INF("Running on Session bus");
372         bus_conn = e_dbus_bus_get(DBUS_BUS_SESSION);
373 #endif
374         if (!bus_conn) {
375                 CRITICAL("Could not get DBus Bus");
376                 return EINA_FALSE;
377         }
378
379         e_dbus_request_name(bus_conn, rc_service, DBUS_NAME_FLAG_DO_NOT_QUEUE,
380                                 _rc_request_name_reply, NULL);
381
382         modem_changed_node = ofono_modem_changed_cb_add(_modem_changed_cb,
383                                                         NULL);
384
385         call_added = ofono_call_added_cb_add(_rc_call_added_cb, NULL);
386         call_removed = ofono_call_removed_cb_add(_rc_call_removed_cb, NULL);
387         call_changed = ofono_call_changed_cb_add(_rc_call_changed_cb, NULL);
388
389         return EINA_TRUE;
390 }
391
392 void rc_shutdown(void)
393 {
394         if (bus_obj)
395                 e_dbus_object_free(bus_obj);
396         if (bus_iface)
397                 e_dbus_interface_unref(bus_iface);
398
399         ofono_modem_changed_cb_del(modem_changed_node);
400         ofono_call_added_cb_del(call_added);
401         ofono_call_removed_cb_del(call_removed);
402         ofono_call_changed_cb_del(call_changed);
403
404         if (pending_dial)
405                 dbus_message_unref(pending_dial);
406
407         bus_conn = NULL;
408 }