update for beta release
[framework/uifw/e17.git] / src / modules / connman / e_mod_main.c
1 #include "e.h"
2 #include "e_mod_main.h"
3
4 /*
5  * STATUS:
6  *
7  *    displays current status, allows connecting and
8  *    disconnecting. needs connman 0.48 or even better from git.
9  *
10  * TODO:
11  *
12  *    MUST:
13  *       1. improve gadget ui
14  *
15  *    GOOD:
16  *       1. imporve mouse over popup ui
17  *       2. nice popup using edje objects as rows, not simple lists (fancy)
18  *       3. "Controls" for detailed information, similar to Mixer app
19  *          it would contain switches to toggle offline and choose
20  *          technologies that are enabled.
21  *
22  *    IDEAS:
23  *       1. create static connections
24  *       2. handle cellular: ask APN, Username and Password, use SetupRequired
25  *       3. handle vpn, bluetooth, wimax
26  *
27  */
28
29 static E_Module *connman_mod = NULL;
30 static char tmpbuf[PATH_MAX]; /* general purpose buffer, just use immediately */
31
32 const char _e_connman_name[] = "connman";
33 const char _e_connman_Name[] = "Connection Manager";
34 int _e_connman_log_dom = -1;
35
36 static const char *e_str_idle = NULL;
37 static const char *e_str_association = NULL;
38 static const char *e_str_configuration = NULL;
39 static const char *e_str_ready = NULL;
40 static const char *e_str_login = NULL;
41 static const char *e_str_online = NULL;
42 static const char *e_str_disconnect = NULL;
43 static const char *e_str_failure = NULL;
44
45 const char *e_str_enabled = NULL;
46 const char *e_str_available = NULL;
47 const char *e_str_connected = NULL;
48 const char *e_str_offline = NULL;
49
50 static void _connman_service_ask_pass_and_connect(E_Connman_Service *service);
51 static void _connman_default_service_changed_delayed(E_Connman_Module_Context *ctxt);
52 static void _connman_gadget_update(E_Connman_Instance *inst);
53 static void _connman_tip_update(E_Connman_Instance *inst);
54
55 const char *
56 e_connman_theme_path(void)
57 {
58 #define TF "/e-module-connman.edj"
59    size_t dirlen;
60
61    dirlen = strlen(connman_mod->dir);
62    if (dirlen >= sizeof(tmpbuf) - sizeof(TF))
63      return NULL;
64
65    memcpy(tmpbuf, connman_mod->dir, dirlen);
66    memcpy(tmpbuf + dirlen, TF, sizeof(TF));
67
68    return tmpbuf;
69 #undef TF
70 }
71
72 static void
73 _connman_toggle_offline_mode_cb(void            *data,
74                                 DBusMessage *msg __UNUSED__,
75                                 DBusError       *error)
76 {
77    E_Connman_Module_Context *ctxt = data;
78
79    if ((!error) || (!dbus_error_is_set(error)))
80      {
81         ctxt->offline_mode_pending = EINA_FALSE;
82         return;
83      }
84
85    _connman_dbus_error_show(_("Cannot toggle system's offline mode."), error);
86    dbus_error_free(error);
87 }
88
89 void
90 _connman_toggle_offline_mode(E_Connman_Module_Context *ctxt)
91 {
92    Eina_Bool offline;
93
94    if ((!ctxt) || (!ctxt->has_manager))
95      {
96         _connman_operation_error_show(_("ConnMan Daemon is not running."));
97         return;
98      }
99
100    if (!e_connman_manager_offline_mode_get(&offline))
101      {
102         _connman_operation_error_show
103           (_("Query system's offline mode."));
104         return;
105      }
106
107    offline = !offline;
108    if (!e_connman_manager_offline_mode_set
109          (offline, _connman_toggle_offline_mode_cb, ctxt))
110      {
111         _connman_operation_error_show
112           (_("Cannot toggle system's offline mode."));
113         return;
114      }
115 }
116
117 static void
118 _connman_cb_toggle_offline_mode(E_Object *obj      __UNUSED__,
119                                 const char *params __UNUSED__)
120 {
121    E_Connman_Module_Context *ctxt;
122
123    if (!connman_mod)
124      return;
125
126    ctxt = connman_mod->data;
127    _connman_toggle_offline_mode(ctxt);
128 }
129
130 struct connman_passphrase_data
131 {
132    void                      (*cb)(void       *data,
133                                    const char *password,
134                                    const char *service_path);
135    void                     *data;
136    const char               *service_path;
137    char                     *passphrase;
138    E_Connman_Module_Context *ctxt;
139    E_Dialog                 *dia;
140    Evas_Object              *entry;
141    Eina_Bool                 canceled;
142    int                       cleartext;
143 };
144
145 #if 0 // NOT WORKING, e_widget_entry_password_set() changes stops editing!!!
146 static void
147 _connman_passphrase_ask_cleartext_changed(void        *data,
148                                           Evas_Object *obj,
149                                           void *event  __UNUSED__)
150 {
151    struct connman_passphrase_data *d = data;
152    e_widget_entry_password_set(d->entry, !e_widget_check_checked_get(obj));
153    e_widget_entry_readonly_set(d->entry, 0);
154    e_widget_focus_set(d->entry, 1);
155 }
156
157 #endif
158
159 static void
160 _connman_passphrase_ask_ok(void     *data,
161                            E_Dialog *dia)
162 {
163    struct connman_passphrase_data *d = data;
164    d->canceled = EINA_FALSE;
165    e_object_del(E_OBJECT(dia));
166 }
167
168 static void
169 _connman_passphrase_ask_cancel(void     *data,
170                                E_Dialog *dia)
171 {
172    struct connman_passphrase_data *d = data;
173    d->canceled = EINA_TRUE;
174    e_object_del(E_OBJECT(dia));
175 }
176
177 static void
178 _connman_passphrase_ask_del(void *data)
179 {
180    E_Dialog *dia = data;
181    struct connman_passphrase_data *d = e_object_data_get(E_OBJECT(dia));
182
183    if (d->canceled)
184      {
185         free(d->passphrase);
186         d->passphrase = NULL;
187      }
188
189    d->cb(d->data, d->passphrase, d->service_path);
190
191    eina_stringshare_del(d->service_path);
192    free(d->passphrase);
193    E_FREE(d);
194 }
195
196 static void
197 _connman_passphrase_ask_key_down(void          *data,
198                                  Evas *e        __UNUSED__,
199                                  Evas_Object *o __UNUSED__,
200                                  void          *event)
201 {
202    Evas_Event_Key_Down *ev = event;
203    struct connman_passphrase_data *d = data;
204
205    if (strcmp(ev->keyname, "Return") == 0)
206      _connman_passphrase_ask_ok(d, d->dia);
207    else if (strcmp(ev->keyname, "Escape") == 0)
208      _connman_passphrase_ask_cancel(d, d->dia);
209 }
210
211 static void
212 _connman_passphrase_ask(E_Connman_Service                       *service,
213                         void                                     (*cb)(void *data,
214                                                      const char *password,
215                                                      const char *service_path),
216                         const void                              *data)
217 {
218    struct connman_passphrase_data *d;
219    Evas_Object *list, *o;
220    Evas *evas;
221    char buf[512];
222    const char *passphrase;
223    int mw, mh;
224
225    if (!cb)
226      return;
227    if (!service)
228      {
229         cb((void *)data, NULL, NULL);
230         return;
231      }
232
233    d = E_NEW(struct connman_passphrase_data, 1);
234    if (!d)
235      {
236         cb((void *)data, NULL, NULL);
237         return;
238      }
239    d->cb = cb;
240    d->data = (void *)data;
241    d->service_path = eina_stringshare_add(service->path);
242    d->ctxt = service->ctxt;
243    d->canceled = EINA_TRUE; /* closing the dialog defaults to cancel */
244    d->dia = e_dialog_new(NULL, "E", "connman_ask_passphrase");
245
246    e_dialog_title_set(d->dia, _("ConnMan needs your passphrase"));
247    e_dialog_icon_set(d->dia, "dialog-ask", 64);
248    e_dialog_border_icon_set(d->dia, "dialog-ask");
249
250    evas = d->dia->win->evas;
251
252    list = e_widget_list_add(evas, 0, 0);
253
254    o = edje_object_add(evas);
255    e_theme_edje_object_set(o, "base/theme/dialog",
256                            "e/widgets/dialog/text");
257    snprintf(buf, sizeof(buf),
258             _("Connection Manager needs your passphrase for <br>"
259               "the service <hilight>%s</hilight>"),
260             service->name);
261    edje_object_part_text_set(o, "e.textblock.message", buf);
262    edje_object_size_min_calc(o, &mw, &mh);
263    evas_object_size_hint_min_set(o, mw, mh);
264    evas_object_resize(o, mw, mh);
265    evas_object_show(o);
266    e_widget_list_object_append(list, o, 1, 1, 0.5);
267
268    if (!e_connman_service_passphrase_get(service->element, &passphrase))
269      passphrase = NULL;
270    if (passphrase && passphrase[0])
271      d->passphrase = strdup(passphrase);
272    else
273      d->passphrase = NULL;
274
275    d->entry = o = e_widget_entry_add(evas, &d->passphrase, NULL, NULL, NULL);
276    e_widget_entry_password_set(o, 0);
277    evas_object_show(o);
278    e_widget_list_object_append(list, o, 1, 0, 0.0);
279
280 #if 0 // NOT WORKING, e_widget_entry_password_set() changes stops editing!!!
281    d->cleartext = 1;
282    o = e_widget_check_add(evas, _("Show passphrase as clear text"),
283                           &d->cleartext);
284    evas_object_smart_callback_add
285      (o, "changed", _connman_passphrase_ask_cleartext_changed, d);
286    evas_object_show(o);
287    e_widget_list_object_append(list, o, 1, 0, 0.0);
288 #endif
289
290    e_widget_size_min_get(list, &mw, &mh);
291    if (mw < 200)
292      mw = 200;
293    if (mh < 60)
294      mh = 60;
295    e_dialog_content_set(d->dia, list, mw, mh);
296
297    e_dialog_button_add
298      (d->dia, _("Ok"), NULL, _connman_passphrase_ask_ok, d);
299    e_dialog_button_add
300      (d->dia, _("Cancel"), NULL, _connman_passphrase_ask_cancel, d);
301
302    evas_object_event_callback_add
303      (d->dia->bg_object, EVAS_CALLBACK_KEY_DOWN,
304      _connman_passphrase_ask_key_down, d);
305
306    e_object_del_attach_func_set
307      (E_OBJECT(d->dia), _connman_passphrase_ask_del);
308    e_object_data_set(E_OBJECT(d->dia), d);
309
310    e_dialog_button_focus_num(d->dia, 0);
311    e_widget_focus_set(d->entry, 1);
312
313    e_win_centered_set(d->dia->win, 1);
314    e_dialog_show(d->dia);
315 }
316
317 static void
318 _connman_service_free(E_Connman_Service *service)
319 {
320    eina_stringshare_del(service->path);
321    eina_stringshare_del(service->name);
322    eina_stringshare_del(service->type);
323    eina_stringshare_del(service->mode);
324    eina_stringshare_del(service->state);
325    eina_stringshare_del(service->error);
326    eina_stringshare_del(service->security);
327    eina_stringshare_del(service->ipv4_method);
328    eina_stringshare_del(service->ipv4_address);
329    eina_stringshare_del(service->ipv4_netmask);
330
331    E_FREE(service);
332 }
333
334 static const char *
335 _connman_service_security_find(const E_Connman_Element *element)
336 {
337    const char **security;
338    unsigned int count;
339
340    if (!e_connman_service_security_get(element, &count, &security))
341      return NULL;
342    if ((!security) || (count < 1))
343      return NULL;
344    return security[0];
345 }
346
347 static void
348 _connman_service_changed(void                    *data,
349                          const E_Connman_Element *element)
350 {
351    E_Connman_Service *service = data;
352    const char *str;
353    unsigned char u8;
354    Eina_Bool b;
355
356 #define GSTR(name_, getter)   \
357   str = NULL;                 \
358   if (!getter(element, &str)) \
359     str = NULL;               \
360   eina_stringshare_replace(&service->name_, str)
361
362    GSTR(name, e_connman_service_name_get);
363    GSTR(type, e_connman_service_type_get);
364    GSTR(state, e_connman_service_state_get);
365    GSTR(error, e_connman_service_error_get);
366    GSTR(ipv4_method, e_connman_service_ipv4_configuration_method_get);
367
368    str = _connman_service_security_find(element);
369    eina_stringshare_replace(&service->security, str);
370
371    if (service->ipv4_method && strcmp(service->ipv4_method, "dhcp") == 0)
372      {
373         GSTR(ipv4_address, e_connman_service_ipv4_address_get);
374         GSTR(ipv4_netmask, e_connman_service_ipv4_netmask_get);
375      }
376    else
377      {
378         GSTR(ipv4_address,
379              e_connman_service_ipv4_configuration_address_get);
380         GSTR(ipv4_netmask,
381              e_connman_service_ipv4_configuration_netmask_get);
382      }
383 #undef GSTR
384
385    if ((service->state != e_str_failure) && (service->error))
386      eina_stringshare_replace(&service->error, NULL);
387
388    if (!e_connman_service_strength_get(element, &u8))
389      u8 = 0;
390    service->strength = u8;
391
392 #define GBOOL(name_, getter) \
393   b = EINA_FALSE;            \
394   if (!getter(element, &b))  \
395     b = EINA_FALSE;          \
396   service->name_ = b
397
398    GBOOL(favorite, e_connman_service_favorite_get);
399    GBOOL(auto_connect, e_connman_service_auto_connect_get);
400    GBOOL(pass_required, e_connman_service_passphrase_required_get);
401 #undef GBOOL
402
403    if ((service->ctxt->default_service == service) ||
404        (!service->ctxt->default_service))
405      _connman_default_service_changed_delayed(service->ctxt);
406    else
407      DBG("Do not request for delayed changed as this is not the default.");
408 }
409
410 static void
411 _connman_service_freed(void *data)
412 {
413    E_Connman_Service *service = data;
414    E_Connman_Module_Context *ctxt = service->ctxt;
415
416    ctxt->services = eina_inlist_remove
417        (ctxt->services, EINA_INLIST_GET(service));
418
419    _connman_service_free(service);
420
421    if (ctxt->default_service == service)
422      {
423         ctxt->default_service = NULL;
424         _connman_default_service_changed_delayed(ctxt);
425      }
426 }
427
428 static E_Connman_Service *
429 _connman_service_new(E_Connman_Module_Context *ctxt,
430                      E_Connman_Element        *element)
431 {
432    E_Connman_Service *service;
433    const char *str;
434    unsigned char u8;
435    Eina_Bool b;
436
437    if (!element)
438      return NULL;
439
440    service = E_NEW(E_Connman_Service, 1);
441    if (!service)
442      return NULL;
443
444    service->ctxt = ctxt;
445    service->element = element;
446    service->path = eina_stringshare_add(element->path);
447
448 #define GSTR(name_, getter)   \
449   str = NULL;                 \
450   if (!getter(element, &str)) \
451     str = NULL;               \
452   service->name_ = eina_stringshare_add(str)
453
454    GSTR(name, e_connman_service_name_get);
455    GSTR(type, e_connman_service_type_get);
456    GSTR(state, e_connman_service_state_get);
457    GSTR(error, e_connman_service_error_get);
458    GSTR(ipv4_method, e_connman_service_ipv4_method_get);
459    GSTR(ipv4_address, e_connman_service_ipv4_address_get);
460    GSTR(ipv4_netmask, e_connman_service_ipv4_netmask_get);
461 #undef GSTR
462
463    str = _connman_service_security_find(element);
464    eina_stringshare_replace(&service->security, str);
465
466    if ((service->state != e_str_failure) && (service->error))
467      eina_stringshare_replace(&service->error, NULL);
468
469    if (!e_connman_service_strength_get(element, &u8))
470      u8 = 0;
471    service->strength = u8;
472
473 #define GBOOL(name_, getter) \
474   b = EINA_FALSE;            \
475   if (!getter(element, &b))  \
476     b = EINA_FALSE;          \
477   service->name_ = b
478
479    GBOOL(favorite, e_connman_service_favorite_get);
480    GBOOL(auto_connect, e_connman_service_auto_connect_get);
481    GBOOL(pass_required, e_connman_service_passphrase_required_get);
482 #undef GBOOL
483
484    e_connman_element_listener_add
485      (element, _connman_service_changed, service,
486      _connman_service_freed);
487
488    return service;
489 }
490
491 #define GSTR(name_, getter)   \
492   str = NULL;                 \
493   if (!getter(element, &str)) \
494     str = NULL;               \
495   eina_stringshare_replace(&t->name_, str)
496
497 static void
498 _connman_technology_free(E_Connman_Technology *t)
499 {
500    eina_stringshare_del(t->path);
501    eina_stringshare_del(t->name);
502    eina_stringshare_del(t->type);
503    eina_stringshare_del(t->state);
504
505    E_FREE(t);
506 }
507
508 static void
509 _connman_technology_changed(void                    *data,
510                             const E_Connman_Element *element)
511 {
512    E_Connman_Technology *t = data;
513    const char *str;
514
515    GSTR(name, e_connman_technology_name_get);
516    GSTR(type, e_connman_technology_type_get);
517    GSTR(state, e_connman_technology_state_get);
518 }
519
520 static void
521 _connman_technology_freed(void *data)
522 {
523    E_Connman_Technology *t = data;
524    E_Connman_Module_Context *ctxt = t->ctxt;
525
526    ctxt->technologies = eina_inlist_remove
527        (ctxt->technologies, EINA_INLIST_GET(t));
528
529    _connman_technology_free(t);
530 }
531
532 static E_Connman_Technology *
533 _connman_technology_new(E_Connman_Module_Context *ctxt,
534                         E_Connman_Element        *element)
535 {
536    E_Connman_Technology *t;
537    const char *str;
538
539    if (!element)
540      return NULL;
541
542    t = E_NEW(E_Connman_Technology, 1);
543    if (!t)
544      return NULL;
545
546    t->ctxt = ctxt;
547    t->element = element;
548    t->path = eina_stringshare_add(element->path);
549
550    GSTR(name, e_connman_technology_name_get);
551    GSTR(type, e_connman_technology_type_get);
552    GSTR(state, e_connman_technology_state_get);
553
554    e_connman_element_listener_add
555      (element, _connman_technology_changed, t,
556      _connman_technology_freed);
557
558    return t;
559 }
560
561 #undef GSTR
562
563 static void
564 _connman_service_disconnect_cb(void            *data,
565                                DBusMessage *msg __UNUSED__,
566                                DBusError       *error)
567 {
568    E_Connman_Module_Context *ctxt = data;
569
570    if (error && dbus_error_is_set(error))
571      {
572         if ((strcmp(error->name,
573                     "org.moblin.connman.Error.NotConnected") != 0) ||
574             (strcmp(error->name,
575                     "net.connman.Error.NotConnected") != 0))
576           _connman_dbus_error_show(_("Disconnect from network service."),
577                                    error);
578         dbus_error_free(error);
579      }
580
581    _connman_default_service_changed_delayed(ctxt);
582 }
583
584 static void
585 _connman_service_disconnect(E_Connman_Service *service)
586 {
587    if (!e_connman_service_disconnect
588          (service->element, _connman_service_disconnect_cb, service->ctxt))
589      _connman_operation_error_show(_("Disconnect from network service."));
590 }
591
592 struct connman_service_connect_data
593 {
594    const char               *service_path;
595    E_Connman_Module_Context *ctxt;
596 };
597
598 static void
599 _connman_service_connect_cb(void            *data,
600                             DBusMessage *msg __UNUSED__,
601                             DBusError       *error)
602 {
603    struct connman_service_connect_data *d = data;
604
605    if (error && dbus_error_is_set(error))
606      {
607         char *password_needed[] = {
608           "org.moblin.connman.Error.PassphraseRequired",
609           "org.moblin.connman.Error.Failed",
610           "net.connman.Error.PassphraseRequired",
611           "net.connman.Error.Failed",
612           NULL
613         };
614         char *dont_display_error[] = {
615           "org.moblin.connman.Error.AlreadyConnected",
616           "net.connman.Error.AlreadyConnected",
617           "net.connman.Error.OperationAborted",
618           NULL
619         };
620         int i;
621
622         for (i = 0; password_needed[i]; ++i)
623           if (strcmp(error->name, password_needed[i]) == 0)
624             {
625                /* TODO: cellular might ask for SetupRequired to enter APN,
626                 * username and password
627                 */
628                E_Connman_Service *service;
629
630                service = _connman_ctxt_find_service_stringshare
631                    (d->ctxt, d->service_path);
632                if (!service)
633                  _connman_operation_error_show
634                    (_("Service does not exist anymore"));
635                else if (strcmp(service->type, "wifi") == 0)
636                  {
637                     _connman_service_disconnect(service);
638                     _connman_service_ask_pass_and_connect(service);
639                  }
640                else
641                  /* TODO: cellular might ask for user and pass */
642                  _connman_dbus_error_show(_("Connect to network service."),
643                                           error);
644                break;
645             }
646
647         if (password_needed[i] == NULL)
648           {
649              for (i = 0; dont_display_error[i]; ++i)
650                if (strcmp(error->name, dont_display_error[i]) == 0)
651                  break;
652
653              if (dont_display_error[i] == NULL)
654                _connman_dbus_error_show(_("Connect to network service."), error);
655           }
656
657         dbus_error_free(error);
658      }
659
660    _connman_default_service_changed_delayed(d->ctxt);
661    eina_stringshare_del(d->service_path);
662    E_FREE(d);
663 }
664
665 static void
666 _connman_service_connect(E_Connman_Service *service)
667 {
668    struct connman_service_connect_data *d;
669
670    d = E_NEW(struct connman_service_connect_data, 1);
671    if (!d)
672      return;
673
674    d->service_path = eina_stringshare_ref(service->path);
675    d->ctxt = service->ctxt;
676
677    if (!e_connman_service_connect
678          (service->element, _connman_service_connect_cb, d))
679      {
680         eina_stringshare_del(d->service_path);
681         E_FREE(d);
682         _connman_operation_error_show(_("Connect to network service."));
683      }
684 }
685
686 struct connman_service_ask_pass_data
687 {
688    const char               *service_path;
689    E_Connman_Module_Context *ctxt;
690 };
691
692 static void
693 _connman_service_ask_pass_and_connect__set_cb(void            *data,
694                                               DBusMessage *msg __UNUSED__,
695                                               DBusError       *error)
696 {
697    struct connman_service_ask_pass_data *d = data;
698    E_Connman_Service *service;
699
700    service = _connman_ctxt_find_service_stringshare(d->ctxt, d->service_path);
701    if (!service)
702      {
703         _connman_operation_error_show(_("Service does not exist anymore"));
704         goto end;
705      }
706
707    if ((!error) || (!dbus_error_is_set(error)))
708      _connman_service_connect(service);
709
710 end:
711    if ((error) && (dbus_error_is_set(error)))
712      dbus_error_free(error);
713    eina_stringshare_del(d->service_path);
714    E_FREE(d);
715 }
716
717 static void
718 _connman_service_ask_pass_and_connect__ask_cb(void       *data,
719                                               const char *passphrase,
720                                               const char *service_path)
721 {
722    E_Connman_Module_Context *ctxt = data;
723    E_Connman_Service *service;
724    struct connman_service_ask_pass_data *d;
725
726    service = _connman_ctxt_find_service_stringshare(ctxt, service_path);
727    if (!service)
728      {
729         _connman_operation_error_show(_("Service does not exist anymore"));
730         return;
731      }
732
733    if (!passphrase)
734      {
735         _connman_service_disconnect(service);
736         return;
737      }
738
739    d = E_NEW(struct connman_service_ask_pass_data, 1);
740    if (!d)
741      return;
742    d->service_path = eina_stringshare_ref(service_path);
743    d->ctxt = ctxt;
744
745    if (!e_connman_service_passphrase_set
746          (service->element, passphrase,
747          _connman_service_ask_pass_and_connect__set_cb, d))
748      {
749         eina_stringshare_del(d->service_path);
750         E_FREE(d);
751         _connman_operation_error_show(_("Could not set service's passphrase"));
752         return;
753      }
754 }
755
756 static void
757 _connman_service_ask_pass_and_connect(E_Connman_Service *service)
758 {
759    _connman_passphrase_ask
760      (service, _connman_service_ask_pass_and_connect__ask_cb, service->ctxt);
761 }
762
763 static void
764 _connman_services_free(E_Connman_Module_Context *ctxt)
765 {
766    while (ctxt->services)
767      {
768         E_Connman_Service *service = (E_Connman_Service *)ctxt->services;
769         e_connman_element_listener_del
770           (service->element, _connman_service_changed, service);
771         /* no need for free or unlink, since listener_del() calls
772          * _connman_service_freed()
773          */
774         //ctxt->services = eina_inlist_remove(ctxt->services, ctxt->services);
775         //_connman_service_free(service);
776      }
777 }
778
779 static inline Eina_Bool
780 _connman_services_element_exists(const E_Connman_Module_Context *ctxt,
781                                  const E_Connman_Element        *element)
782 {
783    const E_Connman_Service *service;
784
785    EINA_INLIST_FOREACH(ctxt->services, service)
786      if (service->path == element->path)
787        return EINA_TRUE;
788
789    return EINA_FALSE;
790 }
791
792 static inline Eina_Bool
793 _connman_technologies_element_exists(const E_Connman_Module_Context *ctxt,
794                                      const E_Connman_Element        *element)
795 {
796    const E_Connman_Technology *t;
797
798    EINA_INLIST_FOREACH(ctxt->technologies, t)
799      {
800         if (t->path == element->path)
801           return EINA_TRUE;
802      }
803
804    return EINA_FALSE;
805 }
806
807 void
808 _connman_request_scan_cb(void *data       __UNUSED__,
809                          DBusMessage *msg __UNUSED__,
810                          DBusError       *error)
811 {
812    if (error && dbus_error_is_set(error))
813      {
814         ERR("%s method failed with message \'%s\'", error->name, error->message);
815         dbus_error_free(error);
816      }
817
818    return;
819 }
820
821 static void
822 _connman_technologies_load(E_Connman_Module_Context *ctxt)
823 {
824    unsigned int count, i;
825    E_Connman_Element **elements;
826
827    if (!e_connman_manager_technologies_get(&count, &elements))
828      return;
829
830    DBG("Technologies = %d.", count);
831    for (i = 0; i < count; i++)
832      {
833         E_Connman_Element *e = elements[i];
834         E_Connman_Technology *t;
835
836         if ((!e) || _connman_technologies_element_exists(ctxt, e))
837           continue;
838
839         t = _connman_technology_new(ctxt, e);
840         if (!t)
841           continue;
842
843         DBG("Added technology: %s.", t->name);
844         ctxt->technologies = eina_inlist_append
845             (ctxt->technologies, EINA_INLIST_GET(t));
846      }
847
848    if (!e_connman_manager_request_scan("", _connman_request_scan_cb, NULL))
849      ERR("Request scan on all technologies failed.");
850
851    free(elements);
852 }
853
854 static void
855 _connman_services_load(E_Connman_Module_Context *ctxt)
856 {
857    unsigned int i, count;
858    E_Connman_Element **elements;
859
860    if (!e_connman_manager_services_get(&count, &elements))
861      return;
862
863    for (i = 0; i < count; i++)
864      {
865         E_Connman_Element *e = elements[i];
866         E_Connman_Service *service;
867
868         if ((!e) || (_connman_services_element_exists(ctxt, e)))
869           continue;
870
871         service = _connman_service_new(ctxt, e);
872         if (!service)
873           continue;
874
875         DBG("Added service: %s\n", service->name);
876         ctxt->services = eina_inlist_append
877             (ctxt->services, EINA_INLIST_GET(service));
878      }
879
880    /* no need to remove elements, as they remove themselves */
881    free(elements);
882 }
883
884 static void
885 _connman_default_service_changed(E_Connman_Module_Context *ctxt)
886 {
887    E_Connman_Service *itr, *def = NULL;
888    E_Connman_Instance *inst;
889    const Eina_List *l;
890    const char *tech;
891
892    EINA_INLIST_FOREACH(ctxt->services, itr)
893      {
894         if ((itr->state == e_str_ready) ||
895             (itr->state == e_str_login) ||
896             (itr->state == e_str_online))
897           {
898              def = itr;
899              break;
900           }
901         else if ((itr->state == e_str_association) &&
902                  ((!def) || (def && def->state != e_str_configuration)))
903           def = itr;
904         else if (itr->state == e_str_configuration)
905           def = itr;
906      }
907
908    DBG("Default service changed to %p (%s)", def, def ? def->name : "");
909
910    if (!e_connman_manager_technology_default_get(&tech))
911      tech = NULL;
912    if (eina_stringshare_replace(&ctxt->technology, tech))
913      DBG("Manager technology is '%s'", tech);
914
915    if (!e_connman_manager_offline_mode_get(&ctxt->offline_mode))
916      ctxt->offline_mode = EINA_FALSE;
917
918    if ((e_config->mode.offline != ctxt->offline_mode) &&
919        (!ctxt->offline_mode_pending))
920      {
921         e_config->mode.offline = ctxt->offline_mode;
922         e_config_mode_changed();
923         e_config_save_queue();
924      }
925
926    ctxt->default_service = def;
927    EINA_LIST_FOREACH(ctxt->instances, l, inst)
928      _connman_gadget_update(inst);
929 }
930
931 static void
932 _connman_services_reload(E_Connman_Module_Context *ctxt)
933 {
934    _connman_services_load(ctxt);
935    _connman_default_service_changed(ctxt);
936 }
937
938 static Eina_Bool
939 _connman_default_service_changed_delayed_do(void *data)
940 {
941    E_Connman_Module_Context *ctxt = data;
942    DBG("Do delayed change.");
943
944    ctxt->poller.default_service_changed = NULL;
945    _connman_default_service_changed(ctxt);
946    return ECORE_CALLBACK_CANCEL;
947 }
948
949 static void
950 _connman_default_service_changed_delayed(E_Connman_Module_Context *ctxt)
951 {
952    if (!ctxt->has_manager)
953      return;
954    DBG("Request delayed change.");
955    if (ctxt->poller.default_service_changed)
956      ecore_poller_del(ctxt->poller.default_service_changed);
957    ctxt->poller.default_service_changed = ecore_poller_add
958        (ECORE_POLLER_CORE, 1, _connman_default_service_changed_delayed_do, ctxt);
959 }
960
961 static void _connman_popup_del(E_Connman_Instance *inst);
962
963 static Eina_Bool
964 _connman_popup_input_window_mouse_up_cb(void    *data,
965                                         int type __UNUSED__,
966                                         void    *event)
967 {
968    Ecore_Event_Mouse_Button *ev = event;
969    E_Connman_Instance *inst = data;
970
971    if (ev->window != inst->ui.input.win)
972      return ECORE_CALLBACK_PASS_ON;
973
974    _connman_popup_del(inst);
975
976    return ECORE_CALLBACK_PASS_ON;
977 }
978
979 static Eina_Bool
980 _connman_popup_input_window_key_down_cb(void    *data,
981                                         int type __UNUSED__,
982                                         void    *event)
983 {
984    Ecore_Event_Key *ev = event;
985    E_Connman_Instance *inst = data;
986    const char *keysym;
987
988    if (ev->window != inst->ui.input.win)
989      return ECORE_CALLBACK_PASS_ON;
990
991    keysym = ev->key;
992    if (strcmp(keysym, "Escape") == 0)
993      _connman_popup_del(inst);
994
995    return ECORE_CALLBACK_PASS_ON;
996 }
997
998 static void
999 _connman_popup_input_window_destroy(E_Connman_Instance *inst)
1000 {
1001    ecore_x_window_free(inst->ui.input.win);
1002    inst->ui.input.win = 0;
1003
1004    ecore_event_handler_del(inst->ui.input.mouse_up);
1005    inst->ui.input.mouse_up = NULL;
1006
1007    ecore_event_handler_del(inst->ui.input.key_down);
1008    inst->ui.input.key_down = NULL;
1009 }
1010
1011 static void
1012 _connman_popup_input_window_create(E_Connman_Instance *inst)
1013 {
1014    Ecore_X_Window_Configure_Mask mask;
1015    Ecore_X_Window w, popup_w;
1016    E_Manager *man;
1017
1018    man = e_manager_current_get();
1019
1020    w = ecore_x_window_input_new(man->root, 0, 0, man->w, man->h);
1021    mask = (ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE |
1022            ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING);
1023    popup_w = inst->popup->win->evas_win;
1024    ecore_x_window_configure(w, mask, 0, 0, 0, 0, 0, popup_w,
1025                             ECORE_X_WINDOW_STACK_BELOW);
1026    ecore_x_window_show(w);
1027
1028    inst->ui.input.mouse_up =
1029      ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
1030                              _connman_popup_input_window_mouse_up_cb, inst);
1031
1032    inst->ui.input.key_down =
1033      ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
1034                              _connman_popup_input_window_key_down_cb, inst);
1035
1036    inst->ui.input.win = w;
1037 }
1038
1039 static void
1040 _connman_popup_cb_offline_mode_changed(void        *data,
1041                                        Evas_Object *obj)
1042 {
1043    E_Connman_Instance *inst = data;
1044    E_Connman_Module_Context *ctxt = inst->ctxt;
1045    Eina_Bool offline = e_widget_check_checked_get(obj);
1046
1047    if ((!ctxt) || (!ctxt->has_manager))
1048      {
1049         _connman_operation_error_show(_("ConnMan Daemon is not running."));
1050         return;
1051      }
1052
1053    if (!e_connman_manager_offline_mode_set
1054          (offline, _connman_toggle_offline_mode_cb, ctxt))
1055      {
1056         _connman_operation_error_show
1057           (_("Cannot toggle system's offline mode."));
1058         return;
1059      }
1060    ctxt->offline_mode_pending = EINA_TRUE;
1061 }
1062
1063 static void
1064 _connman_popup_cb_controls(void       *data,
1065                            void *data2 __UNUSED__)
1066 {
1067    E_Connman_Instance *inst = data;
1068
1069    if (!inst)
1070      return;
1071    if (inst->popup)
1072      _connman_popup_del(inst);
1073    if (inst->ctxt->conf_dialog)
1074      return;
1075
1076    inst->ctxt->conf_dialog = e_connman_config_dialog_new(NULL, inst->ctxt);
1077 }
1078
1079 static void
1080 _connman_popup_service_selected(void *data)
1081 {
1082    E_Connman_Instance *inst = data;
1083    E_Connman_Module_Context *ctxt = inst->ctxt;
1084    E_Connman_Service *service;
1085
1086    if (inst->first_selection)
1087      {
1088         inst->first_selection = EINA_FALSE;
1089         return;
1090      }
1091
1092    if (!inst->service_path)
1093      return;
1094
1095    service = _connman_ctxt_find_service_stringshare(ctxt, inst->service_path);
1096    if (!service)
1097      return;
1098
1099    _connman_popup_del(inst);
1100
1101    if ((service->state != e_str_idle) &&
1102        (service->state != e_str_disconnect) &&
1103        (service->state != e_str_failure))
1104      _connman_service_disconnect(service);
1105    else if (service->pass_required)
1106      _connman_service_ask_pass_and_connect(service);
1107    else
1108      _connman_service_connect(service);
1109 }
1110
1111 Evas_Object *
1112 _connman_service_new_list_item(Evas              *evas,
1113                                E_Connman_Service *service)
1114 {
1115    Evas_Object *icon;
1116    Edje_Message_Int msg;
1117    char buf[128];
1118
1119    snprintf(buf, sizeof(buf), "e/modules/connman/icon/%s", service->type);
1120    icon = edje_object_add(evas);
1121    e_theme_edje_object_set(icon, "base/theme/modules/connman", buf);
1122
1123    snprintf(buf, sizeof(buf), "e,state,%s", service->state);
1124    edje_object_signal_emit(icon, buf, "e");
1125
1126    if (service->mode)
1127      {
1128         snprintf(buf, sizeof(buf), "e,mode,%s", service->mode);
1129         edje_object_signal_emit(icon, buf, "e");
1130      }
1131
1132    if (service->security)
1133      {
1134         snprintf(buf, sizeof(buf), "e,security,%s", service->security);
1135         edje_object_signal_emit(icon, buf, "e");
1136      }
1137
1138    if (service->favorite)
1139      edje_object_signal_emit(icon, "e,favorite,yes", "e");
1140    else
1141      edje_object_signal_emit(icon, "e,favorite,no", "e");
1142
1143    if (service->auto_connect)
1144      edje_object_signal_emit(icon, "e,auto_connect,yes", "e");
1145    else
1146      edje_object_signal_emit(icon, "e,auto_connect,no", "e");
1147
1148    if (service->pass_required)
1149      edje_object_signal_emit(icon, "e,pass_required,yes", "e");
1150    else
1151      edje_object_signal_emit(icon, "e,pass_required,no", "e");
1152
1153    msg.val = service->strength;
1154    edje_object_message_send(icon, EDJE_MESSAGE_INT, 1, &msg);
1155
1156    return icon;
1157 }
1158
1159 static void
1160 _connman_popup_update(E_Connman_Instance *inst)
1161 {
1162    Evas_Object *list = inst->ui.list;
1163    E_Connman_Service *service;
1164    const char *default_path;
1165    Evas *evas = evas_object_evas_get(list);
1166    int i, selected;
1167
1168    default_path = inst->ctxt->default_service ?
1169      inst->ctxt->default_service->path : NULL;
1170
1171    /* TODO: replace this with a scroller + list of edje
1172     * objects that are more full of features
1173     */
1174    e_widget_ilist_freeze(list);
1175    e_widget_ilist_clear(list);
1176    i = 0;
1177    selected = -1;
1178    EINA_INLIST_FOREACH(inst->ctxt->services, service)
1179      {
1180         Evas_Object *icon;
1181
1182         if (service->path == default_path)
1183           selected = i;
1184         i++;
1185
1186         icon = _connman_service_new_list_item(evas, service);
1187
1188         e_widget_ilist_append
1189           (list, icon, service->name, _connman_popup_service_selected,
1190           inst, service->path);
1191      }
1192
1193    if (selected >= 0)
1194      {
1195         inst->first_selection = EINA_TRUE;
1196         e_widget_ilist_selected_set(list, selected);
1197      }
1198    else
1199      inst->first_selection = EINA_FALSE;
1200
1201    e_widget_ilist_thaw(list);
1202    e_widget_ilist_go(list);
1203
1204    e_widget_check_checked_set(inst->ui.offline_mode, inst->ctxt->offline_mode);
1205 }
1206
1207 static void
1208 _connman_popup_del(E_Connman_Instance *inst)
1209 {
1210    eina_stringshare_replace(&inst->service_path, NULL);
1211    _connman_popup_input_window_destroy(inst);
1212    e_object_del(E_OBJECT(inst->popup));
1213    inst->popup = NULL;
1214 }
1215
1216 static void
1217 _connman_popup_new(E_Connman_Instance *inst)
1218 {
1219    E_Connman_Module_Context *ctxt = inst->ctxt;
1220    Evas *evas;
1221    Evas_Coord mw, mh;
1222
1223    if (inst->popup)
1224      {
1225         e_gadcon_popup_show(inst->popup);
1226         return;
1227      }
1228
1229    inst->popup = e_gadcon_popup_new(inst->gcc);
1230    evas = inst->popup->win->evas;
1231
1232    inst->ui.table = e_widget_table_add(evas, 0);
1233
1234    if (ctxt->default_service)
1235      eina_stringshare_replace(&inst->service_path, ctxt->default_service->path);
1236
1237    // TODO: get this size from edj
1238    inst->ui.list = e_widget_ilist_add(evas, 32, 32, &inst->service_path);
1239    e_widget_size_min_set(inst->ui.list, 180, 100);
1240    e_widget_table_object_append(inst->ui.table, inst->ui.list,
1241                                 0, 0, 1, 5, 1, 1, 1, 1);
1242
1243    inst->offline_mode = ctxt->offline_mode;
1244    inst->ui.offline_mode = e_widget_check_add
1245        (evas, _("Offline mode"), &inst->offline_mode);
1246
1247    evas_object_show(inst->ui.offline_mode);
1248    e_widget_table_object_append(inst->ui.table, inst->ui.offline_mode,
1249                                 0, 5, 1, 1, 1, 1, 1, 0);
1250    e_widget_on_change_hook_set
1251      (inst->ui.offline_mode, _connman_popup_cb_offline_mode_changed, inst);
1252
1253    inst->ui.button = e_widget_button_add
1254        (evas, _("Controls"), NULL,
1255        _connman_popup_cb_controls, inst, NULL);
1256    e_widget_table_object_append(inst->ui.table, inst->ui.button,
1257                                 0, 6, 1, 1, 1, 1, 1, 0);
1258
1259    _connman_popup_update(inst);
1260
1261    e_widget_size_min_get(inst->ui.table, &mw, &mh);
1262    if (mh < 200) mh = 200;
1263    if (mw < 200) mw = 200;
1264    e_widget_size_min_set(inst->ui.table, mw, mh);
1265
1266    e_gadcon_popup_content_set(inst->popup, inst->ui.table);
1267    e_gadcon_popup_show(inst->popup);
1268    _connman_popup_input_window_create(inst);
1269 }
1270
1271 static void
1272 _connman_menu_cb_post(void        *data,
1273                       E_Menu *menu __UNUSED__)
1274 {
1275    E_Connman_Instance *inst = data;
1276    if ((!inst) || (!inst->menu))
1277      return;
1278    if (inst->menu)
1279      {
1280         e_object_del(E_OBJECT(inst->menu));
1281         inst->menu = NULL;
1282      }
1283 }
1284
1285 static void
1286 _connman_menu_cb_cfg(void           *data,
1287                      E_Menu *menu    __UNUSED__,
1288                      E_Menu_Item *mi __UNUSED__)
1289 {
1290    E_Connman_Instance *inst = data;
1291
1292    if (!inst)
1293      return;
1294    if (inst->popup)
1295      _connman_popup_del(inst);
1296    if (inst->ctxt->conf_dialog)
1297      return;
1298
1299    inst->ctxt->conf_dialog = e_connman_config_dialog_new(NULL, inst->ctxt);
1300 }
1301
1302 static void
1303 _connman_menu_new(E_Connman_Instance    *inst,
1304                   Evas_Event_Mouse_Down *ev)
1305 {
1306    E_Zone *zone;
1307    E_Menu *m;
1308    E_Menu_Item *mi;
1309    int x, y;
1310
1311    zone = e_util_zone_current_get(e_manager_current_get());
1312
1313    m = e_menu_new();
1314    mi = e_menu_item_new(m);
1315    e_menu_item_label_set(mi, _("Settings"));
1316    e_util_menu_item_theme_icon_set(mi, "configure");
1317    e_menu_item_callback_set(mi, _connman_menu_cb_cfg, inst);
1318
1319    m = e_gadcon_client_util_menu_items_append(inst->gcc, m, 0);
1320    e_menu_post_deactivate_callback_set(m, _connman_menu_cb_post, inst);
1321    inst->menu = m;
1322    e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, NULL, NULL);
1323    e_menu_activate_mouse(m, zone, x + ev->output.x, y + ev->output.y,
1324                          1, 1, E_MENU_POP_DIRECTION_AUTO, ev->timestamp);
1325    evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button,
1326                             EVAS_BUTTON_NONE, ev->timestamp, NULL);
1327 }
1328
1329 static void
1330 _connman_tip_new(E_Connman_Instance *inst)
1331 {
1332    Evas *e;
1333
1334    inst->tip = e_gadcon_popup_new(inst->gcc);
1335    if (!inst->tip) return;
1336
1337    e = inst->tip->win->evas;
1338
1339    inst->o_tip = edje_object_add(e);
1340    e_theme_edje_object_set(inst->o_tip, "base/theme/modules/connman/tip",
1341                            "e/modules/connman/tip");
1342
1343    _connman_tip_update(inst);
1344
1345    e_gadcon_popup_content_set(inst->tip, inst->o_tip);
1346    e_gadcon_popup_show(inst->tip);
1347 }
1348
1349 static void
1350 _connman_tip_del(E_Connman_Instance *inst)
1351 {
1352    evas_object_del(inst->o_tip);
1353    e_object_del(E_OBJECT(inst->tip));
1354    inst->tip = NULL;
1355    inst->o_tip = NULL;
1356 }
1357
1358 static void
1359 _connman_cb_mouse_down(void            *data,
1360                        Evas *evas       __UNUSED__,
1361                        Evas_Object *obj __UNUSED__,
1362                        void            *event)
1363 {
1364    E_Connman_Instance *inst;
1365    Evas_Event_Mouse_Down *ev;
1366
1367    inst = data;
1368    if (!inst)
1369      return;
1370
1371    ev = event;
1372    if (ev->button == 1)
1373      {
1374         if (!inst->popup)
1375           _connman_popup_new(inst);
1376         else
1377           _connman_popup_del(inst);
1378      }
1379    else if (ev->button == 2)
1380      _connman_toggle_offline_mode(inst->ctxt);
1381    else if ((ev->button == 3) && (!inst->menu))
1382      _connman_menu_new(inst, ev);
1383 }
1384
1385 static void
1386 _connman_cb_mouse_in(void            *data,
1387                      Evas *evas       __UNUSED__,
1388                      Evas_Object *obj __UNUSED__,
1389                      void *event      __UNUSED__)
1390 {
1391    E_Connman_Instance *inst = data;
1392
1393    if (inst->tip)
1394      return;
1395
1396    _connman_tip_new(inst);
1397 }
1398
1399 static void
1400 _connman_cb_mouse_out(void            *data,
1401                       Evas *evas       __UNUSED__,
1402                       Evas_Object *obj __UNUSED__,
1403                       void *event      __UNUSED__)
1404 {
1405    E_Connman_Instance *inst = data;
1406
1407    if (!inst->tip)
1408      return;
1409
1410    _connman_tip_del(inst);
1411 }
1412
1413 static void
1414 _connman_edje_view_update(E_Connman_Instance *inst,
1415                           Evas_Object        *o)
1416 {
1417    E_Connman_Module_Context *ctxt = inst->ctxt;
1418    const E_Connman_Service *service;
1419    Edje_Message_Int msg;
1420    char buf[128];
1421
1422    if (!ctxt->has_manager)
1423      {
1424         edje_object_signal_emit(o, "e,unavailable", "e");
1425         edje_object_part_text_set(o, "e.text.name", _("No ConnMan"));
1426         edje_object_part_text_set(o, "e.text.error",
1427                                   _("No ConnMan server found."));
1428         edje_object_signal_emit(o, "e,changed,connected,no", "e");
1429         edje_object_part_text_set(o, "e.text.offline_mode", "");
1430         edje_object_signal_emit(o, "e,changed,offline_mode,no", "e");
1431         return;
1432      }
1433
1434    edje_object_signal_emit(o, "e,available", "e");
1435
1436    if (ctxt->offline_mode)
1437      {
1438         edje_object_signal_emit(o, "e,changed,offline_mode,yes", "e");
1439         edje_object_part_text_set(o, "e.text.offline_mode",
1440                                   _("Offline mode: all radios are turned off"));
1441      }
1442    else
1443      {
1444         edje_object_signal_emit(o, "e,changed,offline_mode,no", "e");
1445         edje_object_part_text_set(o, "e.text.offline_mode", "");
1446      }
1447
1448    if (ctxt->technology && ctxt->technology[0])
1449      {
1450         edje_object_part_text_set(o, "e.text.technology",
1451                                   ctxt->technology);
1452         snprintf(buf, sizeof(buf), "e,changed,technology,%s",
1453                  ctxt->technology);
1454         edje_object_signal_emit(o, buf, "e");
1455      }
1456    else if (!ctxt->default_service)
1457      {
1458         edje_object_part_text_set(o, "e.text.technology", "");
1459         edje_object_signal_emit(o, "e,changed,technology,none", "e");
1460      }
1461
1462    service = ctxt->default_service;
1463    if (!service)
1464      {
1465         edje_object_part_text_set(o, "e.text.name", _("No Connection"));
1466         edje_object_signal_emit(o, "e,changed,service,none", "e");
1467         edje_object_signal_emit(o, "e,changed,connected,no", "e");
1468
1469         edje_object_part_text_set(o, "e.text.error", _("Not connected"));
1470         edje_object_signal_emit(o, "e,changed,error,no", "e");
1471
1472         edje_object_part_text_set(o, "e.text.state", _("disconnect"));
1473         edje_object_signal_emit(o, "e,changed,state,disconnect", "e");
1474
1475         edje_object_signal_emit(o, "e,changed,mode,no", "e");
1476
1477         edje_object_signal_emit(o, "e,changed,mode,none", "e");
1478         edje_object_signal_emit(o, "e,changed,security,none", "e");
1479
1480         edje_object_part_text_set(o, "e.text.ipv4_address", "");
1481         edje_object_signal_emit(o, "e,changed,ipv4_address,no", "e");
1482
1483         edje_object_signal_emit(o, "e,changed,favorite,no", "e");
1484         edje_object_signal_emit(o, "e,changed,auto_connect,no", "e");
1485         edje_object_signal_emit(o, "e,changed,pass_required,no", "e");
1486
1487         return;
1488      }
1489
1490    edje_object_signal_emit(o, "e,changed,connected,yes", "e");
1491
1492    if (service->name)
1493      edje_object_part_text_set(o, "e.text.name", service->name);
1494    else
1495      edje_object_part_text_set(o, "e.text.name", _("Unknown Name"));
1496
1497    if (service->error)
1498      {
1499         edje_object_part_text_set(o, "e.text.error", service->error);
1500         edje_object_signal_emit(o, "e,changed,error,yes", "e");
1501      }
1502    else
1503      {
1504         edje_object_part_text_set(o, "e.text.error", _("No error"));
1505         edje_object_signal_emit(o, "e,changed,error,no", "e");
1506      }
1507
1508    snprintf(buf, sizeof(buf), "e,changed,service,%s", service->type);
1509    edje_object_signal_emit(o, buf, "e");
1510
1511    if (!ctxt->technology)
1512      {
1513         edje_object_part_text_set(o, "e.text.technology", service->type);
1514         snprintf(buf, sizeof(buf), "e,changed,technology,%s", service->type);
1515         edje_object_signal_emit(o, buf, "e");
1516      }
1517
1518    snprintf(buf, sizeof(buf), "e,changed,state,%s", service->state);
1519    edje_object_signal_emit(o, buf, "e");
1520    edje_object_part_text_set(o, "e.text.state", _(service->state));
1521
1522    if (service->mode)
1523      {
1524         snprintf(buf, sizeof(buf), "e,changed,mode,%s", service->mode);
1525         edje_object_signal_emit(o, buf, "e");
1526      }
1527    else
1528      edje_object_signal_emit(o, "e,changed,mode,none", "e");
1529
1530    if (service->security)
1531      {
1532         snprintf(buf, sizeof(buf), "e,changed,security,%s", service->security);
1533         edje_object_signal_emit(o, buf, "e");
1534      }
1535    else
1536      edje_object_signal_emit(o, "e,changed,security,none", "e");
1537
1538    if (service->ipv4_address)
1539      {
1540         edje_object_part_text_set(o, "e.text.ipv4_address", service->ipv4_address);
1541         edje_object_signal_emit(o, "e,changed,ipv4_address,yes", "e");
1542      }
1543    else
1544      {
1545         edje_object_part_text_set(o, "e.text.ipv4_address", "");
1546         edje_object_signal_emit(o, "e,changed,ipv4_address,no", "e");
1547      }
1548
1549    if (service->favorite)
1550      edje_object_signal_emit(o, "e,changed,favorite,yes", "e");
1551    else
1552      edje_object_signal_emit(o, "e,changed,favorite,no", "e");
1553
1554    if (service->auto_connect)
1555      edje_object_signal_emit(o, "e,changed,auto_connect,yes", "e");
1556    else
1557      edje_object_signal_emit(o, "e,changed,auto_connect,no", "e");
1558
1559    if (service->pass_required)
1560      edje_object_signal_emit(o, "e,changed,pass_required,yes", "e");
1561    else
1562      edje_object_signal_emit(o, "e,changed,pass_required,no", "e");
1563
1564    msg.val = service->strength;
1565    edje_object_message_send(o, EDJE_MESSAGE_INT, 1, &msg);
1566 }
1567
1568 static void
1569 _connman_tip_update(E_Connman_Instance *inst)
1570 {
1571    _connman_edje_view_update(inst, inst->o_tip);
1572 }
1573
1574 static void
1575 _connman_gadget_update(E_Connman_Instance *inst)
1576 {
1577    E_Connman_Module_Context *ctxt = inst->ctxt;
1578
1579    if (!ctxt->has_manager && inst->popup)
1580      _connman_popup_del(inst);
1581
1582    if (inst->popup)
1583      _connman_popup_update(inst);
1584    if (inst->tip)
1585      _connman_tip_update(inst);
1586
1587    _connman_edje_view_update(inst, inst->ui.gadget);
1588 }
1589
1590 /* Gadcon Api Functions */
1591
1592 static E_Gadcon_Client *
1593 _gc_init(E_Gadcon   *gc,
1594          const char *name,
1595          const char *id,
1596          const char *style)
1597 {
1598    E_Connman_Instance *inst;
1599    E_Connman_Module_Context *ctxt;
1600
1601    if (!connman_mod)
1602      return NULL;
1603
1604    ctxt = connman_mod->data;
1605
1606    inst = E_NEW(E_Connman_Instance, 1);
1607    inst->ctxt = ctxt;
1608    inst->ui.gadget = edje_object_add(gc->evas);
1609    e_theme_edje_object_set(inst->ui.gadget, "base/theme/modules/connman",
1610                            "e/modules/connman/main");
1611
1612    inst->gcc = e_gadcon_client_new(gc, name, id, style, inst->ui.gadget);
1613    inst->gcc->data = inst;
1614
1615    evas_object_event_callback_add
1616      (inst->ui.gadget, EVAS_CALLBACK_MOUSE_DOWN, _connman_cb_mouse_down, inst);
1617    evas_object_event_callback_add
1618      (inst->ui.gadget, EVAS_CALLBACK_MOUSE_IN, _connman_cb_mouse_in, inst);
1619    evas_object_event_callback_add
1620      (inst->ui.gadget, EVAS_CALLBACK_MOUSE_OUT, _connman_cb_mouse_out, inst);
1621
1622    _connman_gadget_update(inst);
1623
1624    ctxt->instances = eina_list_append(ctxt->instances, inst);
1625
1626    return inst->gcc;
1627 }
1628
1629 static void
1630 _gc_shutdown(E_Gadcon_Client *gcc)
1631 {
1632    E_Connman_Module_Context *ctxt;
1633    E_Connman_Instance *inst;
1634
1635    if (!connman_mod)
1636      return;
1637
1638    ctxt = connman_mod->data;
1639    if (!ctxt)
1640      return;
1641
1642    inst = gcc->data;
1643    if (!inst)
1644      return;
1645
1646    if (inst->menu)
1647      {
1648         e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL);
1649         e_object_del(E_OBJECT(inst->menu));
1650      }
1651    evas_object_del(inst->ui.gadget);
1652
1653    ctxt->instances = eina_list_remove(ctxt->instances, inst);
1654
1655    E_FREE(inst);
1656 }
1657
1658 static void
1659 _gc_orient(E_Gadcon_Client       *gcc,
1660            E_Gadcon_Orient orient __UNUSED__)
1661 {
1662    e_gadcon_client_aspect_set(gcc, 16, 16);
1663    e_gadcon_client_min_size_set(gcc, 16, 16);
1664 }
1665
1666 static const char *
1667 _gc_label(E_Gadcon_Client_Class *client_class __UNUSED__)
1668 {
1669    return _(_e_connman_Name);
1670 }
1671
1672 static Evas_Object *
1673 _gc_icon(E_Gadcon_Client_Class *client_class __UNUSED__,
1674          Evas                               *evas)
1675 {
1676    Evas_Object *o;
1677
1678    o = edje_object_add(evas);
1679    edje_object_file_set(o, e_connman_theme_path(), "icon");
1680    return o;
1681 }
1682
1683 static const char *
1684 _gc_id_new(E_Gadcon_Client_Class *client_class __UNUSED__)
1685 {
1686    E_Connman_Module_Context *ctxt;
1687    Eina_List *instances;
1688
1689    if (!connman_mod)
1690      return NULL;
1691
1692    ctxt = connman_mod->data;
1693    if (!ctxt)
1694      return NULL;
1695
1696    instances = ctxt->instances;
1697    snprintf(tmpbuf, sizeof(tmpbuf), "connman.%d", eina_list_count(instances));
1698    return tmpbuf;
1699 }
1700
1701 static const E_Gadcon_Client_Class _gc_class =
1702 {
1703    GADCON_CLIENT_CLASS_VERSION, _e_connman_name,
1704    {
1705       _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL,
1706       e_gadcon_site_is_not_toolbar
1707    },
1708    E_GADCON_CLIENT_STYLE_PLAIN
1709 };
1710
1711 EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, _e_connman_Name};
1712
1713 static const char _act_toggle_offline_mode[] = "toggle_offline_mode";
1714 static const char _lbl_toggle_offline_mode[] = "Toggle Offline Mode";
1715
1716 static void
1717 _connman_actions_register(E_Connman_Module_Context *ctxt)
1718 {
1719    ctxt->actions.toggle_offline_mode = e_action_add(_act_toggle_offline_mode);
1720    if (ctxt->actions.toggle_offline_mode)
1721      {
1722         ctxt->actions.toggle_offline_mode->func.go =
1723           _connman_cb_toggle_offline_mode;
1724         e_action_predef_name_set
1725           (_(_e_connman_Name), _(_lbl_toggle_offline_mode), _act_toggle_offline_mode,
1726           NULL, NULL, 0);
1727      }
1728 }
1729
1730 static void
1731 _connman_actions_unregister(E_Connman_Module_Context *ctxt)
1732 {
1733    if (ctxt->actions.toggle_offline_mode)
1734      {
1735         e_action_predef_name_del(_(_e_connman_Name), _(_lbl_toggle_offline_mode));
1736         e_action_del(_act_toggle_offline_mode);
1737      }
1738 }
1739
1740 static Eina_Bool
1741 _connman_manager_changed_do(void *data)
1742 {
1743    E_Connman_Module_Context *ctxt = data;
1744
1745    _connman_technologies_load(ctxt);
1746    _connman_services_reload(ctxt);
1747
1748    ctxt->poller.manager_changed = NULL;
1749    return ECORE_CALLBACK_CANCEL;
1750 }
1751
1752 static void
1753 _connman_manager_changed(void                            *data,
1754                          const E_Connman_Element *element __UNUSED__)
1755 {
1756    E_Connman_Module_Context *ctxt = data;
1757    if (ctxt->poller.manager_changed)
1758      ecore_poller_del(ctxt->poller.manager_changed);
1759    ctxt->poller.manager_changed = ecore_poller_add
1760        (ECORE_POLLER_CORE, 1, _connman_manager_changed_do, ctxt);
1761 }
1762
1763 static Eina_Bool
1764 _connman_event_manager_in(void       *data,
1765                           int type    __UNUSED__,
1766                           void *event __UNUSED__)
1767 {
1768    E_Connman_Module_Context *ctxt = data;
1769    E_Connman_Element *element;
1770
1771    ctxt->has_manager = EINA_TRUE;
1772
1773    element = e_connman_manager_get();
1774    e_connman_element_listener_add
1775      (element, _connman_manager_changed, ctxt, NULL);
1776
1777    _connman_services_reload(ctxt);
1778
1779    return ECORE_CALLBACK_PASS_ON;
1780 }
1781
1782 static Eina_Bool
1783 _connman_event_manager_out(void       *data,
1784                            int type    __UNUSED__,
1785                            void *event __UNUSED__)
1786 {
1787    E_Connman_Module_Context *ctxt = data;
1788
1789    ctxt->has_manager = EINA_FALSE;
1790    eina_stringshare_replace(&ctxt->technology, NULL);
1791
1792    _connman_services_free(ctxt);
1793    _connman_default_service_changed(ctxt);
1794
1795    return ECORE_CALLBACK_PASS_ON;
1796 }
1797
1798 static Eina_Bool
1799 _connman_event_mode_changed(void       *data,
1800                             int type    __UNUSED__,
1801                             void *event __UNUSED__)
1802 {
1803    E_Connman_Module_Context *ctxt = data;
1804    if ((ctxt->offline_mode == e_config->mode.offline) ||
1805        (!ctxt->has_manager))
1806      return ECORE_CALLBACK_PASS_ON;
1807    if (!ctxt->offline_mode_pending)
1808      {
1809         if (!e_connman_manager_offline_mode_set(e_config->mode.offline,
1810                                                 _connman_toggle_offline_mode_cb, ctxt))
1811           _connman_operation_error_show(_("Cannot toggle system's offline mode."));
1812      }
1813    else
1814      ctxt->offline_mode_pending = EINA_FALSE;
1815
1816    return ECORE_CALLBACK_PASS_ON;
1817 }
1818
1819 static E_Config_Dialog *
1820 _connman_config(E_Container       *con,
1821                 const char *params __UNUSED__)
1822 {
1823    E_Connman_Module_Context *ctxt;
1824
1825    if (!connman_mod)
1826      return NULL;
1827
1828    ctxt = connman_mod->data;
1829    if (!ctxt)
1830      return NULL;
1831
1832    if (!ctxt->conf_dialog)
1833      ctxt->conf_dialog = e_connman_config_dialog_new(con, ctxt);
1834
1835    return ctxt->conf_dialog;
1836 }
1837
1838 static const char _reg_cat[] = "extensions";
1839 static const char _reg_item[] = "extensions/connman";
1840
1841 static void
1842 _connman_configure_registry_register(void)
1843 {
1844    e_configure_registry_category_add(_reg_cat, 90, _("Extensions"), NULL,
1845                                      "preferences-extensions");
1846    e_configure_registry_item_add(_reg_item, 110, _(_e_connman_Name), NULL,
1847                                  e_connman_theme_path(),
1848                                  _connman_config);
1849 }
1850
1851 static void
1852 _connman_configure_registry_unregister(void)
1853 {
1854    e_configure_registry_item_del(_reg_item);
1855    e_configure_registry_category_del(_reg_cat);
1856 }
1857
1858 static void
1859 _connman_events_register(E_Connman_Module_Context *ctxt)
1860 {
1861    ctxt->event.manager_in = ecore_event_handler_add
1862        (E_CONNMAN_EVENT_MANAGER_IN, _connman_event_manager_in, ctxt);
1863    ctxt->event.manager_out = ecore_event_handler_add
1864        (E_CONNMAN_EVENT_MANAGER_OUT, _connman_event_manager_out, ctxt);
1865    ctxt->event.mode_changed = ecore_event_handler_add
1866        (E_EVENT_CONFIG_MODE_CHANGED, _connman_event_mode_changed, ctxt);
1867 }
1868
1869 static void
1870 _connman_events_unregister(E_Connman_Module_Context *ctxt)
1871 {
1872    if (ctxt->event.manager_in)
1873      ecore_event_handler_del(ctxt->event.manager_in);
1874    if (ctxt->event.manager_out)
1875      ecore_event_handler_del(ctxt->event.manager_out);
1876    if (ctxt->event.mode_changed)
1877      ecore_event_handler_del(ctxt->event.mode_changed);
1878 }
1879
1880 static inline void
1881 _connman_status_stringshare_init(void)
1882 {
1883    e_str_idle = eina_stringshare_add(N_("idle"));
1884    e_str_association = eina_stringshare_add(N_("association"));
1885    e_str_configuration = eina_stringshare_add(N_("configuration"));
1886    e_str_ready = eina_stringshare_add(N_("ready"));
1887    e_str_login = eina_stringshare_add(N_("login"));
1888    e_str_online = eina_stringshare_add(N_("online"));
1889    e_str_disconnect = eina_stringshare_add(N_("disconnect"));
1890    e_str_failure = eina_stringshare_add(N_("failure"));
1891    e_str_enabled = eina_stringshare_add(N_("enabled"));
1892    e_str_available = eina_stringshare_add(N_("available"));
1893    e_str_connected = eina_stringshare_add(N_("connected"));
1894    e_str_offline = eina_stringshare_add(N_("offline"));
1895 }
1896
1897 static inline void
1898 _connman_status_stringshare_del(void)
1899 {
1900    eina_stringshare_replace(&e_str_idle, NULL);
1901    eina_stringshare_replace(&e_str_association, NULL);
1902    eina_stringshare_replace(&e_str_configuration, NULL);
1903    eina_stringshare_replace(&e_str_ready, NULL);
1904    eina_stringshare_replace(&e_str_login, NULL);
1905    eina_stringshare_replace(&e_str_online, NULL);
1906    eina_stringshare_replace(&e_str_disconnect, NULL);
1907    eina_stringshare_replace(&e_str_failure, NULL);
1908    eina_stringshare_replace(&e_str_enabled, NULL);
1909    eina_stringshare_replace(&e_str_available, NULL);
1910    eina_stringshare_replace(&e_str_connected, NULL);
1911    eina_stringshare_replace(&e_str_offline, NULL);
1912 }
1913
1914 EAPI void *
1915 e_modapi_init(E_Module *m)
1916 {
1917    E_Connman_Module_Context *ctxt;
1918    E_DBus_Connection *c;
1919
1920    _connman_status_stringshare_init();
1921
1922    c = e_dbus_bus_get(DBUS_BUS_SYSTEM);
1923    if (!c)
1924      goto error_dbus_bus_get;
1925    if (!e_connman_system_init(c))
1926      goto error_connman_system_init;
1927
1928    ctxt = E_NEW(E_Connman_Module_Context, 1);
1929    if (!ctxt)
1930      goto error_connman_context;
1931
1932    ctxt->services = NULL;
1933    ctxt->technologies = NULL;
1934    ctxt->conf_dialog = NULL;
1935    connman_mod = m;
1936
1937    if (_e_connman_log_dom < 0)
1938      {
1939         _e_connman_log_dom = eina_log_domain_register("econnman", EINA_COLOR_ORANGE);
1940         if (_e_connman_log_dom < 0)
1941           {
1942              EINA_LOG_CRIT("could not register logging domain econnman");
1943              goto error_log_domain;
1944           }
1945      }
1946
1947    _connman_configure_registry_register();
1948    _connman_actions_register(ctxt);
1949    e_gadcon_provider_register(&_gc_class);
1950
1951    _connman_events_register(ctxt);
1952
1953    return ctxt;
1954
1955 error_log_domain:
1956    _e_connman_log_dom = -1;
1957    connman_mod = NULL;
1958    E_FREE(ctxt);
1959 error_connman_context:
1960    e_connman_system_shutdown();
1961 error_connman_system_init:
1962 error_dbus_bus_get:
1963    _connman_status_stringshare_del();
1964    return NULL;
1965 }
1966
1967 static void
1968 _connman_instances_free(E_Connman_Module_Context *ctxt)
1969 {
1970    while (ctxt->instances)
1971      {
1972         E_Connman_Instance *inst;
1973
1974         inst = ctxt->instances->data;
1975
1976         if (inst->popup)
1977           _connman_popup_del(inst);
1978         if (inst->tip)
1979           _connman_tip_del(inst);
1980
1981         e_object_del(E_OBJECT(inst->gcc));
1982      }
1983 }
1984
1985 EAPI int
1986 e_modapi_shutdown(E_Module *m)
1987 {
1988    E_Connman_Module_Context *ctxt;
1989    E_Connman_Element *element;
1990
1991    ctxt = m->data;
1992    if (!ctxt)
1993      return 0;
1994
1995    element = e_connman_manager_get();
1996    e_connman_element_listener_del
1997      (element, _connman_manager_changed, ctxt);
1998
1999    _connman_events_unregister(ctxt);
2000
2001    _connman_instances_free(ctxt);
2002    _connman_services_free(ctxt);
2003
2004    _connman_configure_registry_unregister();
2005    _connman_actions_unregister(ctxt);
2006    e_gadcon_provider_unregister(&_gc_class);
2007
2008    if (ctxt->poller.default_service_changed)
2009      ecore_poller_del(ctxt->poller.default_service_changed);
2010    if (ctxt->poller.manager_changed)
2011      ecore_poller_del(ctxt->poller.manager_changed);
2012
2013    E_FREE(ctxt);
2014    connman_mod = NULL;
2015
2016    e_connman_system_shutdown();
2017
2018    _connman_status_stringshare_del();
2019    return 1;
2020 }
2021
2022 EAPI int
2023 e_modapi_save(E_Module *m)
2024 {
2025    E_Connman_Module_Context *ctxt;
2026
2027    ctxt = m->data;
2028    if (!ctxt)
2029      return 0;
2030    return 1;
2031 }
2032