Adding logic to handle disconnected modems
[profile/ivi/lemolo.git] / messages / 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.messages.Control"
15 #define RC_PATH "/"
16
17 static const char *rc_service = NULL;
18 static OFono_Callback_List_Modem_Node *modem_changed_node = NULL;
19 static DBusMessage *pending_send = NULL;
20
21 static void _send_message(const char *number, const char *message,
22                                 Eina_Bool do_auto)
23 {
24         INF("send '%s' '%s' auto=%d!", number, message, do_auto);
25         gui_activate();
26         gui_send(number, message, do_auto);
27 }
28
29 static void _modem_changed_cb(void *data __UNUSED__)
30 {
31         DBusError err;
32         const char *number, *message;
33         dbus_bool_t do_auto;
34         DBusMessage *reply;
35
36         if (!ofono_voice_is_online() || !pending_send)
37                 return;
38
39         dbus_error_init(&err);
40         dbus_message_get_args(pending_send, &err,
41                                 DBUS_TYPE_STRING, &number,
42                                 DBUS_TYPE_STRING, &message,
43                                 DBUS_TYPE_BOOLEAN, &do_auto, DBUS_TYPE_INVALID);
44
45         if (dbus_error_is_set(&err)) {
46                 ERR("Could not parse message: %s: %s", err.name, err.message);
47                 reply = dbus_message_new_error(pending_send, err.name,
48                                                 err.message);
49                 goto reply_send;
50         }
51
52         _send_message(number, message, do_auto);
53         reply = dbus_message_new_method_return(pending_send);
54 reply_send:
55         e_dbus_message_send(bus_conn, reply, NULL, -1, NULL);
56         dbus_message_unref(pending_send);
57         dbus_message_unref(reply);
58         pending_send = NULL;
59 }
60
61 static DBusMessage *
62 _rc_activate(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
63 {
64         INF("Remotely activated!");
65         gui_activate();
66         return dbus_message_new_method_return(msg);
67 }
68
69 static DBusMessage *
70 _rc_send(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
71 {
72         DBusError err;
73         dbus_bool_t do_auto;
74         const char *number, *message;
75
76         if (!ofono_voice_is_online()) {
77                 if (pending_send)
78                         dbus_message_unref(pending_send);
79                 pending_send = dbus_message_ref(msg);
80                 return NULL;
81         }
82
83         dbus_error_init(&err);
84         dbus_message_get_args(msg, &err,
85                                 DBUS_TYPE_STRING, &number,
86                                 DBUS_TYPE_STRING, &message,
87                                 DBUS_TYPE_BOOLEAN, &do_auto, DBUS_TYPE_INVALID);
88         if (dbus_error_is_set(&err)) {
89                 ERR("Could not parse message: %s: %s", err.name, err.message);
90                 return dbus_message_new_error(msg, err.name, err.message);
91         }
92         _send_message(number, message, do_auto);
93         return dbus_message_new_method_return(msg);
94 }
95
96 static void _rc_object_register(void)
97 {
98         bus_obj = e_dbus_object_add(bus_conn, RC_PATH, NULL);
99         if (!bus_obj) {
100                 CRITICAL("Could not create "RC_PATH" DBus object.");
101                 return;
102         }
103         bus_iface = e_dbus_interface_new(RC_IFACE);
104         e_dbus_object_interface_attach(bus_obj, bus_iface);
105
106 #define IF_ADD(name, par, ret, cb)              \
107         e_dbus_interface_method_add(bus_iface, name, par, ret, cb)
108
109         IF_ADD("Activate", "", "", _rc_activate);
110         IF_ADD("Send", "ssb", "", _rc_send);
111 #undef IF_ADD
112 }
113
114 static void _rc_activate_existing_reply(void *data __UNUSED__,
115                                         DBusMessage *msg __UNUSED__,
116                                         DBusError *err)
117 {
118         if (dbus_error_is_set(err)) {
119                 CRITICAL("Failed to activate existing messages: %s: %s",
120                                 err->name, err->message);
121                 _app_exit_code = EXIT_FAILURE;
122                 ecore_main_loop_quit();
123                 return;
124         }
125
126         INF("Activated the existing messages!");
127         ecore_main_loop_quit();
128 }
129
130 static void _rc_activate_existing(void)
131 {
132         DBusMessage *msg = dbus_message_new_method_call(
133                 rc_service, RC_PATH, RC_IFACE, "Activate");
134         e_dbus_message_send(bus_conn, msg,  _rc_activate_existing_reply,
135                                 -1, NULL);
136         dbus_message_unref(msg);
137 }
138
139 static void _rc_request_name_reply(void *data __UNUSED__, DBusMessage *msg,
140                                         DBusError *err)
141 {
142         DBusError e;
143         dbus_uint32_t t;
144
145         if (!msg) {
146                 if (err)
147                         WRN("%s: %s", err->name, err->message);
148                 else
149                         WRN("No message");
150                 _rc_activate_existing();
151                 return;
152         }
153
154         dbus_error_init(&e);
155         dbus_message_get_args(msg, &e, DBUS_TYPE_UINT32, &t, DBUS_TYPE_INVALID);
156         if (t == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
157                 _rc_object_register();
158                 gui_activate();
159         } else {
160                 WRN("Messages already running! Activate it!");
161                 _rc_activate_existing();
162         }
163 }
164
165 Eina_Bool rc_init(const char *service)
166 {
167         rc_service = service;
168
169         if (!elm_need_e_dbus()) {
170                 CRITICAL("Elementary does not support DBus.");
171                 return EINA_FALSE;
172         }
173
174         INF("Running on Session bus");
175         bus_conn = e_dbus_bus_get(DBUS_BUS_SESSION);
176
177         if (!bus_conn) {
178                 CRITICAL("Could not get DBus Bus");
179                 return EINA_FALSE;
180         }
181
182         e_dbus_request_name(bus_conn, rc_service, DBUS_NAME_FLAG_DO_NOT_QUEUE,
183                                 _rc_request_name_reply, NULL);
184
185         modem_changed_node = ofono_modem_changed_cb_add(_modem_changed_cb,
186                                                         NULL);
187
188         return EINA_TRUE;
189 }
190
191 void rc_shutdown(void)
192 {
193         if (bus_obj)
194                 e_dbus_object_free(bus_obj);
195         if (bus_iface)
196                 e_dbus_interface_unref(bus_iface);
197
198         ofono_modem_changed_cb_del(modem_changed_node);
199
200         if (pending_send)
201                 dbus_message_unref(pending_send);
202
203         bus_conn = NULL;
204 }