e_entry -> elm_entry conversion
[platform/upstream/enlightenment.git] / src / modules / connman / agent.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <stdbool.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "e.h"
10 #include "E_Connman.h"
11 #include "e_mod_main.h"
12 #define AGENT_IFACE "net.connman.Agent"
13 #define AGENT_KEY "agent"
14
15 typedef struct _E_Connman_Agent_Input E_Connman_Agent_Input;
16
17 struct Connman_Field
18 {
19    const char *name;
20
21    const char *type;
22    const char *requirement;
23    const char *value;
24    Eina_Array *alternates;
25 };
26
27 struct _E_Connman_Agent_Input
28 {
29    char *key;
30    char *value;
31    int show_password;
32 };
33
34 struct _E_Connman_Agent
35 {
36    E_Dialog *dialog;
37    Eldbus_Service_Interface *iface;
38    Eldbus_Message *msg;
39    Eldbus_Connection *conn;
40    Eina_Bool canceled:1;
41 };
42
43 static void
44 _dict_append_basic(Eldbus_Message_Iter *array, const char *key, void *val)
45 {
46    Eldbus_Message_Iter *dict, *variant;
47
48    eldbus_message_iter_arguments_append(array, "{sv}", &dict);
49    eldbus_message_iter_basic_append(dict, 's', key);
50    variant = eldbus_message_iter_container_new(dict, 'v', "s");
51    eldbus_message_iter_basic_append(variant, 's', val ?: "");
52    eldbus_message_iter_container_close(dict, variant);
53    eldbus_message_iter_container_close(array, dict);
54 }
55
56 static void
57 _dialog_ok_cb(void *data, E_Dialog *dialog)
58 {
59    E_Connman_Agent *agent = data;
60    E_Connman_Agent_Input *input;
61    Evas_Object *toolbook, *list;
62    Eldbus_Message_Iter *iter, *array;
63    Eina_List *input_list, *l;
64    Eldbus_Message *reply;
65
66    toolbook = agent->dialog->content_object;
67
68    /* fugly - no toolbook page get */
69    list = evas_object_data_get(toolbook, "mandatory");
70    if ((!list) || (!evas_object_visible_get(list)))
71      {
72         list = evas_object_data_get(toolbook, "alternate");
73         if ((!list) || (!evas_object_visible_get(list)))
74           {
75              ERR("Couldn't get user input.");
76              e_object_del(E_OBJECT(dialog));
77              return;
78           }
79      }
80
81    agent->canceled = EINA_FALSE;
82    input_list = evas_object_data_get(list, "input_list");
83
84    reply = eldbus_message_method_return_new(agent->msg);
85    iter = eldbus_message_iter_get(reply);
86    eldbus_message_iter_arguments_append(iter, "a{sv}", &array);
87
88    EINA_LIST_FOREACH(input_list, l, input)
89      _dict_append_basic(array, input->key, input->value);
90    eldbus_message_iter_container_close(iter, array);
91
92    eldbus_connection_send(agent->conn, reply, NULL, NULL, -1);
93
94    e_object_del(E_OBJECT(dialog));
95 }
96
97 static void
98 _dialog_cancel_cb(void *data, E_Dialog *dialog)
99 {
100    E_Connman_Agent *agent = data;
101    agent->canceled = EINA_TRUE;
102    e_object_del(E_OBJECT(dialog));
103 }
104
105 static void
106 _dialog_key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__,
107                     void *event)
108 {
109    Evas_Event_Key_Down *ev = event;
110    E_Connman_Agent *agent = data;
111
112    if (!strcmp(ev->key, "Return"))
113      _dialog_ok_cb(agent, agent->dialog);
114    else if (strcmp(ev->key, "Escape") == 0)
115      _dialog_cancel_cb(agent, agent->dialog);
116 }
117
118 static void
119 _dialog_cancel(E_Connman_Agent *agent)
120 {
121    Eldbus_Message *reply;
122
123    reply = eldbus_message_error_new(agent->msg,
124                                   "net.connman.Agent.Error.Canceled",
125                                   "User canceled dialog");
126    eldbus_connection_send(agent->conn, reply, NULL, NULL, -1);
127 }
128
129 static void
130 _dialog_del_cb(void *data)
131 {
132    E_Dialog *dialog = data;
133    E_Connman_Agent *agent = e_object_data_get(E_OBJECT(dialog));
134
135    if (agent->canceled)
136      _dialog_cancel(agent);
137
138    // FIXME need to mark cs->pending_connect = NULL;
139    eldbus_message_unref(agent->msg);
140    agent->dialog = NULL;
141 }
142
143 static void
144 _page_del(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
145 {
146    E_Connman_Agent_Input *input;
147    Eina_List *input_list;
148
149    input_list = evas_object_data_get(obj, "input_list");
150    EINA_LIST_FREE(input_list, input)
151      {
152         free(input->key);
153         free(input);
154      }
155 }
156
157 static void
158 _show_password_cb(void *data, Evas_Object *obj, void *event  __UNUSED__)
159 {
160    Evas_Object *entry = data;
161    int hidden;
162
163    hidden = !e_widget_check_checked_get(obj);
164    e_widget_entry_password_set(entry, hidden);
165 }
166
167 static void
168 _dialog_field_add(E_Connman_Agent *agent, struct Connman_Field *field)
169 {
170    Evas_Object *toolbook, *list, *framelist, *entry, *check;
171    E_Connman_Agent_Input *input;
172    Eina_List *input_list;
173    Eina_Bool mandatory;
174    char header[64];
175    Evas *evas;
176
177    evas = evas_object_evas_get(agent->dialog->win);
178    toolbook = agent->dialog->content_object;
179    mandatory = !strcmp(field->requirement, "mandatory");
180
181    if ((!mandatory) && (strcmp(field->requirement, "alternate")))
182      {
183         WRN("Field not handled: %s %s", field->name, field->type);
184         return;
185      }
186
187    input = E_NEW(E_Connman_Agent_Input, 1);
188    input->key = strdup(field->name);
189    entry = e_widget_entry_add(agent->dialog->win, &(input->value), NULL, NULL, NULL);
190    evas_object_show(entry);
191
192    list = evas_object_data_get(toolbook, field->requirement);
193    if (!list)
194      {
195         list = e_widget_list_add(evas, 0, 0);
196         e_widget_toolbook_page_append(toolbook, NULL, field->name,
197                                       list, 1, 1, 1, 1, 0.5, 0.0);
198         evas_object_data_set(toolbook, field->requirement, list);
199
200         e_widget_toolbook_page_show(toolbook, 0);
201         evas_object_event_callback_add(list, EVAS_CALLBACK_DEL,
202                                        _page_del, NULL);
203
204         if (mandatory)
205           e_widget_focus_set(entry, 1);
206      }
207
208    input_list = evas_object_data_get(list, "input_list");
209    input_list = eina_list_append(input_list, input);
210    evas_object_data_set(list, "input_list", input_list);
211
212    snprintf(header, sizeof(header), "%s required to access network:",
213             field->name);
214    framelist = e_widget_framelist_add(evas, header, 0);
215    evas_object_show(framelist);
216    e_widget_list_object_append(list, framelist, 1, 1, 0.5);
217
218    e_widget_framelist_object_append(framelist, entry);
219
220    if ((!strcmp(field->name, "Passphrase")) ||
221        (!strcmp(field->name, "Password")))
222      {
223         e_widget_entry_password_set(entry, 1);
224
225         check = e_widget_check_add(evas, _("Show password"),
226                                    &(input->show_password));
227         evas_object_show(check);
228         e_widget_framelist_object_append(framelist, check);
229
230         evas_object_smart_callback_add(check, "changed", _show_password_cb,
231                                        entry);
232      }
233 }
234
235 static E_Dialog *
236 _dialog_new(E_Connman_Agent *agent)
237 {
238    Evas_Object *toolbook;
239    E_Dialog *dialog;
240    Evas *evas;
241    int mw, mh;
242
243    dialog = e_dialog_new(NULL, "E", "connman_request_input");
244    if (!dialog)
245      return NULL;
246
247    e_dialog_title_set(dialog, _("Input requested"));
248    e_dialog_border_icon_set(dialog, "dialog-ask");
249
250    e_dialog_button_add(dialog, _("Ok"), NULL, _dialog_ok_cb, agent);
251    e_dialog_button_add(dialog, _("Cancel"), NULL, _dialog_cancel_cb, agent);
252    agent->canceled = EINA_TRUE; /* if win is closed it works like cancel */
253
254    evas = evas_object_evas_get(dialog->win);
255
256    toolbook = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale);
257    evas_object_show(toolbook);
258
259    e_widget_size_min_get(toolbook, &mw, &mh);
260    /* is it a hack ? */
261    if (mw < 260)
262      mw = 260;
263    if (mh < 130)
264      mh = 130;
265    e_dialog_content_set(dialog, toolbook, mw, mh);
266    e_dialog_show(dialog);
267
268    evas_object_event_callback_add(dialog->bg_object, EVAS_CALLBACK_KEY_DOWN,
269                                   _dialog_key_down_cb, agent);
270
271    e_object_del_attach_func_set(E_OBJECT(dialog), _dialog_del_cb);
272    e_object_data_set(E_OBJECT(dialog), agent);
273
274    e_dialog_button_focus_num(dialog, 0);
275    elm_win_center(dialog->win, 1, 1);
276
277    return dialog;
278 }
279
280 static Eldbus_Message *
281 _agent_release(const Eldbus_Service_Interface *iface,
282                const Eldbus_Message *msg)
283 {
284    E_Connman_Agent *agent;
285    Eldbus_Message *reply;
286
287    DBG("Agent released");
288
289    reply = eldbus_message_method_return_new(msg);
290
291    agent = eldbus_service_object_data_get(iface, AGENT_KEY);
292    EINA_SAFETY_ON_FALSE_RETURN_VAL(agent, reply);
293
294    if (agent->dialog)
295      e_object_del(E_OBJECT(agent->dialog));
296
297    return reply;
298 }
299
300 static Eldbus_Message *
301 _agent_report_error(const Eldbus_Service_Interface *iface EINA_UNUSED,
302                     const Eldbus_Message *msg EINA_UNUSED)
303 {
304    return NULL;
305 }
306
307 static Eldbus_Message *
308 _agent_request_browser(const Eldbus_Service_Interface *iface EINA_UNUSED,
309                        const Eldbus_Message *msg EINA_UNUSED)
310 {
311    return NULL;
312 }
313
314 static Eina_Bool
315 _parse_field_value(struct Connman_Field *field, const char *key,
316                    Eldbus_Message_Iter *value, const char *signature)
317 {
318    if (!strcmp(key, "Type"))
319      {
320         EINA_SAFETY_ON_FALSE_RETURN_VAL(signature[0] == 's', EINA_FALSE);
321         eldbus_message_iter_basic_get(value, &field->type);
322         return EINA_TRUE;
323      }
324
325    if (!strcmp(key, "Requirement"))
326      {
327         EINA_SAFETY_ON_FALSE_RETURN_VAL(signature[0] == 's', EINA_FALSE);
328         eldbus_message_iter_basic_get(value, &field->requirement);
329         return EINA_TRUE;
330      }
331
332    if (!strcmp(key, "Alternates"))
333      {
334         EINA_SAFETY_ON_FALSE_RETURN_VAL(signature[0] == 'a', EINA_FALSE);
335         /* ignore alternates */
336         return EINA_TRUE;
337      }
338
339    if (!strcmp(key, "Value"))
340      {
341         EINA_SAFETY_ON_FALSE_RETURN_VAL(signature[0] == 's', EINA_FALSE);
342         eldbus_message_iter_basic_get(value, &field->value);
343         return EINA_TRUE;
344      }
345
346    DBG("Ignored unknown argument: %s", key);
347    return EINA_FALSE;
348 }
349
350 static Eina_Bool
351 _parse_field(struct Connman_Field *field, Eldbus_Message_Iter *value,
352              const char *signature EINA_UNUSED)
353 {
354    Eldbus_Message_Iter *array, *dict;
355
356    eldbus_message_iter_arguments_get(value, "a{sv}", &array);
357    EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
358
359    while (eldbus_message_iter_get_and_next(array, 'e', &dict))
360      {
361         Eldbus_Message_Iter *var;
362         const char *key;
363         char *sig2;
364
365         if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &var))
366           return EINA_FALSE;
367         sig2 = eldbus_message_iter_signature_get(var);
368         if (!sig2)
369           return EINA_FALSE;
370
371         if (!_parse_field_value(field, key, var, sig2))
372           {
373              free(sig2);
374              return EINA_FALSE;
375           }
376         free(sig2);
377      }
378
379    return EINA_TRUE;
380 }
381
382 static Eldbus_Message *
383 _agent_request_input(const Eldbus_Service_Interface *iface,
384                      const Eldbus_Message *msg)
385 {
386    E_Connman_Module_Context *ctxt = connman_mod->data;
387    const Eina_List *l;
388    E_Connman_Instance *inst;
389    Eldbus_Message_Iter *array, *dict;
390    E_Connman_Agent *agent;
391    const char *path;
392
393    agent = eldbus_service_object_data_get(iface, AGENT_KEY);
394
395    /* Discard previous requests */
396    // if msg is the current agent msg? eek.
397    if (agent->msg == msg) return NULL;
398
399    if (agent->msg)
400      eldbus_message_unref(agent->msg);
401    agent->msg = eldbus_message_ref((Eldbus_Message *)msg);
402
403    EINA_LIST_FOREACH(ctxt->instances, l, inst)
404      econnman_popup_del(inst);
405
406    if (agent->dialog)
407      e_object_del(E_OBJECT(agent->dialog));
408    agent->dialog = _dialog_new(agent);
409    EINA_SAFETY_ON_NULL_GOTO(agent->dialog, err);
410
411    if (!eldbus_message_arguments_get(msg, "oa{sv}", &path, &array))
412      goto err;
413
414    while (eldbus_message_iter_get_and_next(array, 'e', &dict))
415      {
416         Eldbus_Message_Iter *var;
417         char *signature;
418         struct Connman_Field field = { NULL, NULL, NULL, NULL, NULL };
419
420         if (!eldbus_message_iter_arguments_get(dict, "sv", &field.name, &var))
421           goto err;
422         signature = eldbus_message_iter_signature_get(var);
423         if (!signature) goto err;
424
425         if (!_parse_field(&field, var, signature))
426           {
427              free(signature);
428              goto err;
429           }
430         free(signature);
431
432         DBG("AGENT Got field:\n"
433             "\tName: %s\n"
434             "\tType: %s\n"
435             "\tRequirement: %s\n"
436             "\tAlternates: (omit array)\n"
437             "\tValue: %s",
438             field.name, field.type, field.requirement, field.value);
439
440         _dialog_field_add(agent, &field);
441      }
442
443    return NULL;
444
445 err:
446    eldbus_message_unref((Eldbus_Message *)msg);
447    agent->msg = NULL;
448    WRN("Failed to parse msg");
449    return eldbus_message_method_return_new(msg);
450 }
451
452 static Eldbus_Message *
453 _agent_cancel(const Eldbus_Service_Interface *iface,
454               const Eldbus_Message *msg)
455 {
456    E_Connman_Agent *agent;
457    Eldbus_Message *reply = eldbus_message_method_return_new(msg);
458
459    DBG("Agent canceled");
460
461    agent = eldbus_service_object_data_get(iface, AGENT_KEY);
462    EINA_SAFETY_ON_FALSE_RETURN_VAL(agent, reply);
463
464    if (agent->dialog)
465      e_object_del(E_OBJECT(agent->dialog));
466
467    return reply;
468 }
469
470 static const Eldbus_Method methods[] = {
471    { "Release", NULL, NULL, _agent_release, 0 },
472    {
473     "ReportError", ELDBUS_ARGS({"o", "service"}, {"s", "error"}), NULL,
474     _agent_report_error, 0
475    },
476    {
477     "RequestBrowser", ELDBUS_ARGS({"o", "service"}, {"s", "url"}), NULL,
478      _agent_request_browser, 0
479    },
480    {
481     "RequestInput", ELDBUS_ARGS({"o", "service"}, {"a{sv}", "fields"}),
482     ELDBUS_ARGS({"a{sv}", ""}), _agent_request_input, 0
483    },
484    { "Cancel", NULL, NULL, _agent_cancel, 0 },
485    { NULL, NULL, NULL, NULL, 0 }
486 };
487
488 static const Eldbus_Service_Interface_Desc desc = {
489    AGENT_IFACE, methods, NULL, NULL, NULL, NULL
490 };
491
492 E_Connman_Agent *
493 econnman_agent_new(Eldbus_Connection *eldbus_conn)
494 {
495    Eldbus_Service_Interface *iface;
496    E_Connman_Agent *agent;
497
498    agent = E_NEW(E_Connman_Agent, 1);
499    EINA_SAFETY_ON_NULL_RETURN_VAL(agent, NULL);
500
501    iface = eldbus_service_interface_register(eldbus_conn, AGENT_PATH, &desc);
502    if (!iface)
503      {
504         ERR("Failed to create eldbus interface");
505         free(agent);
506         return NULL;
507      }
508    eldbus_service_object_data_set(iface, AGENT_KEY, agent);
509
510    agent->iface = iface;
511    agent->conn = eldbus_conn;
512
513    return agent;
514 }
515
516 void
517 econnman_agent_del(E_Connman_Agent *agent)
518 {
519    EINA_SAFETY_ON_NULL_RETURN(agent);
520    eldbus_service_object_unregister(agent->iface);
521    free(agent);
522 }