summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric Bail <cedric.bail@free.fr>2014-03-03 06:11:49 -0300
committerCedric Bail <cedric.bail@free.fr>2014-03-03 06:11:49 -0300
commitfa33725fddf743286da4a18731b78505d93ac831 (patch)
tree613c10f089856938c614d5447a8fb42084ffc3a8
parent28fcabc8604a41d53a2efc9bd2ad90ffc562f4a7 (diff)
control: beginning integration of ssh into terminology.devs/cedric/ssh
-rw-r--r--configure.ac11
-rw-r--r--src/bin/Makefile.am5
-rw-r--r--src/bin/controls.c21
-rw-r--r--src/bin/main.c2
-rw-r--r--src/bin/options.c1
-rw-r--r--src/bin/options_ssh.c408
-rw-r--r--src/bin/options_ssh.h14
7 files changed, 458 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index 55e5b5b..35cd2bf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,6 +53,16 @@ PKG_CHECK_MODULES([ELDBUS],
53 [have_eldbus="no"] 53 [have_eldbus="no"]
54 ) 54 )
55 55
56PKG_CHECK_MODULES([AVAHI],
57 [avahi-client ecore-avahi],
58 [
59 AC_DEFINE(HAVE_AVAHI, 1, [Avahi support])
60 have_avahi="yes"
61 ],
62 [
63 have_avahi="no"
64 ])
65
56AC_CHECK_FUNCS(mkstemps) 66AC_CHECK_FUNCS(mkstemps)
57 67
58EFL_WITH_BIN([edje], [edje-cc], [edje_cc]) 68EFL_WITH_BIN([edje], [edje-cc], [edje_cc])
@@ -114,4 +124,5 @@ echo " prefix...................: $prefix"
114echo 124echo
115echo "Features:" 125echo "Features:"
116echo " dbus................: $have_eldbus" 126echo " dbus................: $have_eldbus"
127echo " avahi...............: $have_avahi"
117echo 128echo
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index 46ba0e9..f7a34ae 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -5,9 +5,9 @@ bin_PROGRAMS = terminology tybg tyalpha typop tyq tycat tyls
5 5
6terminology_CPPFLAGS = -I. \ 6terminology_CPPFLAGS = -I. \
7-DPACKAGE_BIN_DIR=\"$(bindir)\" -DPACKAGE_LIB_DIR=\"$(libdir)\" \ 7-DPACKAGE_BIN_DIR=\"$(bindir)\" -DPACKAGE_LIB_DIR=\"$(libdir)\" \
8-DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" @TERMINOLOGY_CFLAGS@ 8-DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" @TERMINOLOGY_CFLAGS@ @AVAHI_CFLAGS@
9 9
10terminology_LDADD = @TERMINOLOGY_LIBS@ @ELDBUS_LIBS@ 10terminology_LDADD = @TERMINOLOGY_LIBS@ @ELDBUS_LIBS@ @AVAHI_LIBS@
11 11
12terminology_SOURCES = \ 12terminology_SOURCES = \
13private.h \ 13private.h \
@@ -20,6 +20,7 @@ keyin.c keyin.h \
20main.c main.h \ 20main.c main.h \
21media.c media.h \ 21media.c media.h \
22options.c options.h \ 22options.c options.h \
23options_ssh.h options_ssh.c \
23options_font.c options_font.h \ 24options_font.c options_font.h \
24options_theme.c options_theme.h \ 25options_theme.c options_theme.h \
25options_themepv.c options_themepv.h \ 26options_themepv.c options_themepv.h \
diff --git a/src/bin/controls.c b/src/bin/controls.c
index 3fb8658..25ab897 100644
--- a/src/bin/controls.c
+++ b/src/bin/controls.c
@@ -8,7 +8,7 @@
8#include "main.h" 8#include "main.h"
9 9
10static Evas_Object *ct_frame = NULL, *ct_boxh = NULL, *ct_box = NULL; 10static Evas_Object *ct_frame = NULL, *ct_boxh = NULL, *ct_box = NULL;
11static Evas_Object *ct_box2 = NULL, *ct_over = NULL; 11static Evas_Object *ct_box2 = NULL, *ct_boxssh = NULL, *ct_over = NULL;
12static Eina_Bool ct_out = EINA_FALSE; 12static Eina_Bool ct_out = EINA_FALSE;
13static Ecore_Timer *ct_del_timer = NULL; 13static Ecore_Timer *ct_del_timer = NULL;
14static Evas_Object *ct_win = NULL, *ct_bg = NULL, *ct_term = NULL; 14static Evas_Object *ct_win = NULL, *ct_bg = NULL, *ct_term = NULL;
@@ -240,9 +240,13 @@ controls_toggle(Evas_Object *win, Evas_Object *bg, Evas_Object *term,
240 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); 240 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
241 elm_object_text_set(o, "Controls"); 241 elm_object_text_set(o, "Controls");
242 242
243 ct_boxssh = o = elm_box_add(win);
244 elm_object_content_set(ct_frame, o);
245 evas_object_show(o);
246
243 ct_boxh = o = elm_box_add(win); 247 ct_boxh = o = elm_box_add(win);
244 elm_box_horizontal_set(o, EINA_TRUE); 248 elm_box_horizontal_set(o, EINA_TRUE);
245 elm_object_content_set(ct_frame, o); 249 elm_box_pack_end(ct_boxssh, o);
246 evas_object_show(o); 250 evas_object_show(o);
247 251
248 ct_box2 = o = elm_box_add(win); 252 ct_box2 = o = elm_box_add(win);
@@ -293,6 +297,19 @@ controls_toggle(Evas_Object *win, Evas_Object *bg, Evas_Object *term,
293 o = _button_add(win, "About", "about", _cb_ct_about, NULL); 297 o = _button_add(win, "About", "about", _cb_ct_about, NULL);
294 elm_box_pack_end(ct_box, o); 298 elm_box_pack_end(ct_box, o);
295 299
300 o = _sep_add_h(win);
301 elm_box_pack_end(ct_boxssh, o);
302
303 o = elm_genlist_add(win);
304 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
305 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
306 evas_object_size_hint_request_set(o, 64, 64);
307 elm_genlist_mode_set(o, ELM_LIST_COMPRESS);
308 elm_genlist_homogeneous_set(o, EINA_TRUE);
309 elm_box_pack_end(ct_boxssh, o);
310 evas_object_show(o);
311 options_genlist_add(o);
312
296 evas_object_event_callback_add(ct_frame, EVAS_CALLBACK_DEL, 313 evas_object_event_callback_add(ct_frame, EVAS_CALLBACK_DEL,
297 _cb_frame_del, NULL); 314 _cb_frame_del, NULL);
298 315
diff --git a/src/bin/main.c b/src/bin/main.c
index 9ccb4a0..7eb8a25 100644
--- a/src/bin/main.c
+++ b/src/bin/main.c
@@ -2704,6 +2704,7 @@ elm_main(int argc, char **argv)
2704 elm_app_info_set(elm_main, "terminology", "themes/default.edj"); 2704 elm_app_info_set(elm_main, "terminology", "themes/default.edj");
2705 2705
2706 config_init(); 2706 config_init();
2707 options_ssh_init();
2707 2708
2708 main_config = config_load("config"); 2709 main_config = config_load("config");
2709 2710
@@ -3058,6 +3059,7 @@ remote:
3058 termpty_shutdown(); 3059 termpty_shutdown();
3059 3060
3060 config_del(main_config); 3061 config_del(main_config);
3062 options_ssh_shutdown();
3061 config_shutdown(); 3063 config_shutdown();
3062 eina_log_domain_unregister(_log_domain); 3064 eina_log_domain_unregister(_log_domain);
3063 _log_domain = -1; 3065 _log_domain = -1;
diff --git a/src/bin/options.c b/src/bin/options.c
index 6eea718..1ccb022 100644
--- a/src/bin/options.c
+++ b/src/bin/options.c
@@ -10,6 +10,7 @@
10#include "options_behavior.h" 10#include "options_behavior.h"
11#include "options_keys.h" 11#include "options_keys.h"
12#include "options_helpers.h" 12#include "options_helpers.h"
13#include "options_ssh.h"
13#include "config.h" 14#include "config.h"
14#include "termio.h" 15#include "termio.h"
15 16
diff --git a/src/bin/options_ssh.c b/src/bin/options_ssh.c
new file mode 100644
index 0000000..c821182
--- /dev/null
+++ b/src/bin/options_ssh.c
@@ -0,0 +1,408 @@
1#include "private.h"
2
3#include <Elementary.h>
4
5#ifdef HAVE_AVAHI
6# include <Ecore_Avahi.h>
7# include <avahi-client/client.h>
8# include <avahi-client/lookup.h>
9# include <avahi-common/error.h>
10#endif
11
12#include "options_ssh.h"
13
14#define FREE_CLEAN(h, cb) do { if (h) cb(h); h = NULL; } while (0);
15
16typedef struct _SSH_Genlist SSH_Genlist;
17struct _SSH_Genlist
18{
19 Evas_Object *gl;
20 Elm_Object_Item *announced_servers;
21 Elm_Object_Item *ww_servers;
22 Eina_List *items;
23};
24
25struct _SSH_Server
26{
27 const char *domain;
28 const char *name;
29 const char *ip;
30 unsigned int port;
31
32 unsigned char announced : 1;
33};
34
35static Eina_List *announced_servers = NULL;
36static Eina_List *ww_servers = NULL;
37static Eina_List *genlists = NULL;
38
39static Elm_Genlist_Item_Class *itc_group = NULL;
40static Elm_Genlist_Item_Class *itc = NULL;
41
42static void
43_option_genlist_ssh_add(SSH_Genlist *genlist, unsigned char announced, const SSH_Server *server)
44{
45 Elm_Object_Item *parent;
46 Elm_Object_Item *it;
47
48 if (announced)
49 {
50 if (!genlist->announced_servers)
51 {
52 genlist->announced_servers = elm_genlist_item_append(genlist->gl, itc_group,
53 (void *)(uintptr_t)1 /* item data */,
54 NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
55 elm_genlist_item_select_mode_set(genlist->announced_servers, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
56 }
57 parent = genlist->announced_servers;
58 }
59 else
60 {
61 if (!genlist->ww_servers)
62 {
63 genlist->ww_servers = elm_genlist_item_append(genlist->gl, itc_group, NULL,
64 NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
65 elm_genlist_item_select_mode_set(genlist->ww_servers, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
66 }
67 parent = genlist->ww_servers;
68 }
69
70 it = elm_genlist_item_append(genlist->gl, itc, server /* item data */,
71 parent /* parent */,
72 ELM_GENLIST_ITEM_NONE,
73 NULL /* func */, // FIXME: there should the action come
74 NULL);
75
76 genlist->items = eina_list_append(genlist->items, it);
77}
78
79static void
80_option_genlist_ssh_del(SSH_Genlist *genlist, const SSH_Server *server)
81{
82 Elm_Object_Item *it;
83 Eina_List *l, *ll;
84
85 EINA_LIST_FOREACH_SAFE(genlist->items, l, ll, it)
86 if (elm_object_item_data_get(it) == server)
87 {
88 elm_object_item_del(it);
89 genlist->items = eina_list_remove_list(genlist->items, l);
90 }
91}
92
93void
94options_ssh_server_add(unsigned char announced, const char *domain, const char *name, const char *ip, unsigned int port)
95{
96 SSH_Server *srv;
97 SSH_Genlist *genlist;
98 Eina_List* l;
99
100 srv = calloc(1, sizeof (SSH_Server));
101 if (!srv) return ;
102
103 srv->domain = eina_stringshare_add(domain);
104 srv->name = eina_stringshare_add(name);
105 srv->ip = eina_stringshare_add(ip);
106 srv->port = port;
107 srv->announced = announced;
108
109 INF("Avahi discovered new host '%s' (%s:%i) from domain '%s'.",
110 name, ip, port, domain);
111
112 if (announced)
113 announced_servers = eina_list_append(announced_servers, srv);
114 else
115 ww_servers = eina_list_append(ww_servers, srv);
116
117 EINA_LIST_FOREACH(genlists, l, genlist)
118 _option_genlist_ssh_add(genlist, announced, srv);
119}
120
121void
122options_ssh_server_data_del(SSH_Server *server)
123{
124 SSH_Genlist *genlist;
125 Eina_List *l;
126
127 INF("Avahi discovered host disapeared '%s' (%s:%i) from domain '%s'.",
128 server->name, server->ip, server->port, server->domain);
129
130 EINA_LIST_FOREACH(genlists, l, genlist)
131 _option_genlist_ssh_del(genlist, server);
132
133 eina_stringshare_del(server->name);
134 eina_stringshare_del(server->domain);
135 eina_stringshare_del(server->ip);
136
137 if (server->announced)
138 announced_servers = eina_list_remove(announced_servers, server);
139 else
140 ww_servers = eina_list_remove(ww_servers, server);
141
142 free(server);
143}
144
145void
146options_ssh_server_del(unsigned char announced, const char *domain, const char *name)
147{
148 SSH_Server *srv;
149 Eina_List *l;
150
151 domain = eina_stringshare_add(domain);
152 name = eina_stringshare_add(name);
153
154 l = announced ? announced_servers : ww_servers;
155
156 EINA_LIST_FOREACH(l, l, srv)
157 if (srv->name == name &&
158 srv->domain == domain)
159 {
160 options_ssh_server_data_del(srv);
161 break;
162 }
163
164 eina_stringshare_del(domain);
165 eina_stringshare_del(name);
166}
167
168static Eina_Bool
169_options_genlist_death(void *data, Eo *obj EINA_UNUSED,
170 const Eo_Event_Description *desc EINA_UNUSED,
171 void *event_info EINA_UNUSED)
172{
173 SSH_Genlist *genlist = data;
174
175 eina_list_free(genlist->items);
176 free(genlist);
177
178 return EINA_TRUE;
179}
180
181void
182options_genlist_add(Evas_Object *gl)
183{
184 SSH_Genlist *genlist;
185 SSH_Server *srv;
186 Eina_List *l;
187
188 genlist = calloc(1, sizeof(SSH_Genlist));
189 if (!genlist) return ;
190
191 genlist->gl = gl;
192
193 EINA_LIST_FOREACH(announced_servers, l, srv)
194 _option_genlist_ssh_add(genlist, 1, srv);
195 EINA_LIST_FOREACH(ww_servers, l, srv)
196 _option_genlist_ssh_add(genlist, 0, srv);
197
198 eo_do(gl, eo_event_callback_add(EO_EV_DEL, _options_genlist_death, genlist));
199}
200
201static char *
202gl_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
203{
204 SSH_Server *srv = data;
205 Eina_Strbuf *buf;
206 char *r;
207
208 buf = eina_strbuf_new();
209
210 if (srv->port != 22)
211 eina_strbuf_append_printf(buf, "%s:%i", srv->name, srv->port);
212 else
213 eina_strbuf_append_printf(buf, "%s", srv->name);
214
215 r = eina_strbuf_string_steal(buf);
216 eina_strbuf_free(buf);
217
218 return r;
219}
220
221static char *
222gl_group_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
223{
224 if (data) return strdup("Announced server");
225 return strdup("World wide server");
226}
227
228#ifdef HAVE_AVAHI
229static Ecore_Avahi *context = NULL;
230static AvahiClient *client = NULL;
231static AvahiServiceBrowser *sb = NULL;
232static int error = 0;
233
234// FIXME: Check what it does
235static void
236_resolve_callback(AvahiServiceResolver *r,
237 AvahiIfIndex interface EINA_UNUSED,
238 AvahiProtocol protocol EINA_UNUSED,
239 AvahiResolverEvent event,
240 const char *name,
241 const char *type,
242 const char *domain,
243 const char *host_name EINA_UNUSED,
244 const AvahiAddress *address,
245 uint16_t port,
246 AvahiStringList *txt EINA_UNUSED,
247 AvahiLookupResultFlags flags EINA_UNUSED,
248 void* userdata EINA_UNUSED)
249{
250 /* Called whenever a service has been resolved successfully or timed out */
251 switch (event)
252 {
253 case AVAHI_RESOLVER_FAILURE:
254 ERR("Avahi failed to resolve service '%s' of type '%s' in domain '%s': %s\n",
255 name, type, domain,
256 avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
257 break;
258
259 case AVAHI_RESOLVER_FOUND:
260 {
261 char a[AVAHI_ADDRESS_STR_MAX];
262
263 avahi_address_snprint(a, sizeof(a), address);
264 options_ssh_server_add(1, domain, name, a, port);
265 }
266 }
267
268 avahi_service_resolver_free(r);
269}
270
271static void
272_browse_callback(AvahiServiceBrowser *b EINA_UNUSED,
273 AvahiIfIndex interface,
274 AvahiProtocol protocol,
275 AvahiBrowserEvent event,
276 const char *name,
277 const char *type,
278 const char *domain,
279 AvahiLookupResultFlags flags EINA_UNUSED,
280 void* userdata)
281{
282 AvahiClient *c = userdata;
283
284 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
285 switch (event)
286 {
287 case AVAHI_BROWSER_FAILURE:
288 // FIXME: What to do in case of failure ? Schedule another browser ?
289 break;
290
291 case AVAHI_BROWSER_NEW:
292 /* We ignore the returned resolver object. In the callback
293 function we free it. If the server is terminated before
294 the callback function is called the server will free
295 the resolver for us. */
296
297 avahi_service_resolver_new(c, interface,
298 protocol, name, type, domain,
299 AVAHI_PROTO_UNSPEC, 0, _resolve_callback, c);
300
301 break;
302
303 case AVAHI_BROWSER_REMOVE:
304 options_ssh_server_del(1, domain, name);
305 break;
306
307 case AVAHI_BROWSER_ALL_FOR_NOW:
308 case AVAHI_BROWSER_CACHE_EXHAUSTED:
309 /* Nothing to do in our case */
310 break;
311 }
312}
313
314static void
315_client_callback(AvahiClient *c, AvahiClientState state, void * userdata EINA_UNUSED)
316{
317 switch (state)
318 {
319 case AVAHI_CLIENT_S_REGISTERING:
320 case AVAHI_CLIENT_S_COLLISION:
321 case AVAHI_CLIENT_S_RUNNING:
322 if (!sb)
323 {
324 sb = avahi_service_browser_new(c, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ssh._tcp", NULL, 0, _browse_callback, c);
325 if (!sb)
326 {
327 WRN("Failed to setup an Avahi Service Browser.");
328 return ;
329 }
330 }
331 break;
332
333 case AVAHI_CLIENT_FAILURE:
334 WRN("Server connection failure: %s.", avahi_strerror(avahi_client_errno(c)));
335 if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED)
336 {
337 FREE_CLEAN(sb, avahi_service_browser_free);
338 FREE_CLEAN(client, avahi_client_free);
339
340 client = avahi_client_new(ecore_avahi_poll_get(context), AVAHI_CLIENT_NO_FAIL, _client_callback, NULL, &error);
341 if (!client)
342 {
343 WRN("Unable to setup an AvahiClient context.");
344 return ;
345 }
346 break;
347 }
348
349 case AVAHI_CLIENT_CONNECTING:
350 FREE_CLEAN(sb, avahi_service_browser_free);
351 break;
352 }
353}
354#endif
355
356void
357options_ssh_init(void)
358{
359 if (!itc)
360 {
361 itc = elm_genlist_item_class_new();
362 itc->item_style = "default";
363 itc->func.text_get = gl_text_get;
364 itc->func.content_get = NULL;
365 itc->func.state_get = NULL;
366 itc->func.del = NULL;
367 }
368 if (!itc_group)
369 {
370 itc_group = elm_genlist_item_class_new();
371 itc_group->item_style = "group_index";
372 itc_group->func.text_get = gl_group_get;
373 itc_group->func.content_get = NULL;
374 itc_group->func.state_get = NULL;
375 itc_group->func.del = NULL;
376 }
377
378#ifdef HAVE_AVAHI
379 if (context) return ;
380
381 context = ecore_avahi_add();
382 if (!context)
383 {
384 WRN("Unable to setup an Ecore_Avahi context.");
385 return ;
386 }
387
388 client = avahi_client_new(ecore_avahi_poll_get(context), AVAHI_CLIENT_NO_FAIL, _client_callback, NULL, &error);
389 if (!client)
390 {
391 WRN("Unable to setup an AvahiClient context.");
392 options_ssh_shutdown();
393 return ;
394 }
395#endif
396}
397
398void
399options_ssh_shutdown(void)
400{
401 FREE_CLEAN(itc, elm_genlist_item_class_free);
402 FREE_CLEAN(itc_group, elm_genlist_item_class_free);
403#ifdef HAVE_AVAHI
404 FREE_CLEAN(sb, avahi_service_browser_free);
405 FREE_CLEAN(client, avahi_client_free);
406 FREE_CLEAN(context, ecore_avahi_del);
407#endif
408}
diff --git a/src/bin/options_ssh.h b/src/bin/options_ssh.h
new file mode 100644
index 0000000..c4fab02
--- /dev/null
+++ b/src/bin/options_ssh.h
@@ -0,0 +1,14 @@
1#ifndef _OPTIONS_SSH_H__
2#define _OPTIONS_SSH_H__
3
4typedef struct _SSH_Server SSH_Server;
5
6void options_ssh_server_add(unsigned char local, const char *domain, const char *name, const char *ip, unsigned int port);
7void options_ssh_server_data_del(SSH_Server *server);
8void options_ssh_server_del(unsigned char local, const char *domain, const char *name);
9void options_genlist_add(Evas_Object *gl);
10
11void options_ssh_init(void);
12void options_ssh_shutdown(void);
13
14#endif