1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #ifdef _WIN32
6 # include <evil_private.h> /* setenv */
7 #endif
8 
9 #include <Ecore.h>
10 #include <Ecore_Ipc.h>
11 
12 #include "efreetd.h"
13 #include "efreetd_cache.h"
14 
15 extern FILE *efreetd_log_file;
16 
17 static int init = 0;
18 static Ecore_Ipc_Server *ipc = NULL;
19 static Ecore_Event_Handler *hnd_add = NULL;
20 static Ecore_Event_Handler *hnd_del = NULL;
21 static Ecore_Event_Handler *hnd_data = NULL;
22 static int clients = 0;
23 static Ecore_Timer *quit_timer_start = NULL;
24 static Ecore_Timer *quit_timer = NULL;
25 
26 static Eina_Bool
_cb_quit_timer(void * data EINA_UNUSED)27 _cb_quit_timer(void *data EINA_UNUSED)
28 {
29    quit_timer = NULL;
30    quit();
31    return EINA_FALSE;
32 }
33 
34 static Eina_Bool
_cb_quit_timer_start(void * data EINA_UNUSED)35 _cb_quit_timer_start(void *data EINA_UNUSED)
36 {
37    quit_timer_start = NULL;
38    if (quit_timer) ecore_timer_del(quit_timer);
39    quit_timer = ecore_timer_add(10.0, _cb_quit_timer, NULL);
40    return EINA_FALSE;
41 }
42 
43 static void
_broadcast(Ecore_Ipc_Server * svr,int major,int minor,void * data,int size)44 _broadcast(Ecore_Ipc_Server *svr, int major, int minor, void *data, int size)
45 {
46    Eina_List *ipc_clients = ecore_ipc_server_clients_get(svr);
47    Eina_List *l;
48    Ecore_Ipc_Client *cl;
49 
50    EINA_LIST_FOREACH(ipc_clients, l, cl)
51      {
52         fprintf(efreetd_log_file, "[%09.3f] Client broadcast %i.%i\n", ecore_time_get(), major, minor);
53         fflush(efreetd_log_file);
54         ecore_ipc_client_send(cl, major, minor, 0, 0, 0, data, size);
55      }
56 }
57 
58 static char *
_parse_str(void * data,int size)59 _parse_str(void *data, int size)
60 {
61    char *str = malloc(size + 1);
62    if (!str) return NULL;
63    memcpy(str, data, size);
64    str[size] = 0;
65    return str;
66 }
67 
68 static Eina_List *
_parse_strs(void * data,int size)69 _parse_strs(void *data, int size)
70 {
71    Eina_List *list = NULL;
72    char *p, *p0 = NULL, *p1 = NULL, *e = (char *)data + size;
73 
74    for (p = data; p < e; p++)
75      {
76         if (!p0)
77           {
78              if (*p)
79                {
80                   p0 = p;
81                   p1 = e;
82                }
83           }
84         if ((!*p) && (p0))
85           {
86              p1 = strdup(p0);
87              if (p1) list = eina_list_append(list, p1);
88              p0 = NULL;
89           }
90      }
91    if (p0)
92      {
93         p = malloc(p1 - p0 + 1);
94         if (p)
95           {
96              memcpy(p, p0, p1 - p0);
97              p[p1 - p0] = 0;
98              list = eina_list_append(list, p);
99           }
100      }
101    return list;
102 }
103 
104 #define IPC_HEAD(_type) \
105    Ecore_Ipc_Event_Client_##_type *e = event; \
106    if (ecore_ipc_client_server_get(e->client) != ipc) \
107      return ECORE_CALLBACK_PASS_ON
108 
109 static Eina_Bool
_cb_client_add(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)110 _cb_client_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
111 {
112    IPC_HEAD(Add);
113    if (quit_timer)
114      {
115         ecore_timer_del(quit_timer);
116         quit_timer = NULL;
117      }
118    if (quit_timer_start)
119      {
120         ecore_timer_del(quit_timer_start);
121         quit_timer_start = NULL;
122      }
123    clients++;
124    fprintf(efreetd_log_file, "[%09.3f] Add client (count=%i)\n", ecore_time_get(),
125            clients);
126    fflush(efreetd_log_file);
127    return ECORE_CALLBACK_DONE;
128 }
129 
130 static Eina_Bool
_cb_client_del(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)131 _cb_client_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
132 {
133    IPC_HEAD(Del);
134    clients--;
135    fprintf(efreetd_log_file, "[%09.3f] Del client (count=%i)\n", ecore_time_get(),
136            clients);
137    fflush(efreetd_log_file);
138    if (clients == 0)
139      {
140         if (quit_timer) ecore_timer_del(quit_timer);
141         quit_timer = ecore_timer_add(2.0, _cb_quit_timer, NULL);
142      }
143    return ECORE_CALLBACK_DONE;
144 }
145 
146 static Eina_Bool
_cb_client_data(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)147 _cb_client_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
148 {
149    Eina_List *strs;
150    char *s;
151    IPC_HEAD(Data);
152    if (e->major == 1) // register lang
153      { // input: str -> lang
154         fprintf(efreetd_log_file, "[%09.3f] Client register lang\n", ecore_time_get());
155         fflush(efreetd_log_file);
156         if ((s = _parse_str(e->data, e->size)))
157           {
158              setenv("LANG", s, 1);
159              free(s);
160           }
161         // return if desktop cache exists (bool as minor)
162         ecore_ipc_client_send(e->client, 1 /* register reply */,
163                               cache_desktop_exists(), 0, 0, 0, NULL, 0);
164      }
165    else if (e->major == 2) // add desktop dirs
166      { // input: array of str -> dirs
167         fprintf(efreetd_log_file, "[%09.3f] Client add desktop dirs\n", ecore_time_get());
168         fflush(efreetd_log_file);
169         strs = _parse_strs(e->data, e->size);
170         EINA_LIST_FREE(strs, s)
171           {
172              cache_desktop_dir_add(s);
173              free(s);
174           }
175      }
176    else if (e->major == 3) // build desktop cache
177      { // input: str -> lang
178         fprintf(efreetd_log_file, "[%09.3f] Client update desktop cache\n", ecore_time_get());
179         fflush(efreetd_log_file);
180         if ((s = _parse_str(e->data, e->size)))
181           {
182              setenv("LANG", s, 1);
183              free(s);
184           }
185         cache_desktop_update();
186      }
187    else if (e->major == 4) // add icon dirs
188      { // input: array of str -> dirs
189         fprintf(efreetd_log_file, "[%09.3f] Client add icon dirs\n", ecore_time_get());
190         fflush(efreetd_log_file);
191         strs = _parse_strs(e->data, e->size);
192         EINA_LIST_FREE(strs, s)
193           {
194              cache_icon_dir_add(s);
195              free(s);
196           }
197      }
198    else if (e->major == 5) // add icon exts
199      { // input: array of str -> exts
200         fprintf(efreetd_log_file, "[%09.3f] Client add icon exts\n", ecore_time_get());
201         fflush(efreetd_log_file);
202         strs = _parse_strs(e->data, e->size);
203         EINA_LIST_FREE(strs, s)
204           {
205              cache_icon_ext_add(s);
206              free(s);
207           }
208      }
209    return ECORE_CALLBACK_DONE;
210 }
211 
212 ///////////////////////////////////////////////////////////////////////////
213 
214 void
send_signal_icon_cache_update(Eina_Bool update)215 send_signal_icon_cache_update(Eina_Bool update)
216 {
217    _broadcast(ipc, 2 /* icon cache update */, update, NULL, 0);
218 }
219 
220 void
send_signal_desktop_cache_update(Eina_Bool update)221 send_signal_desktop_cache_update(Eina_Bool update)
222 {
223    _broadcast(ipc, 3 /* desktop cache update */, update, NULL, 0);
224 }
225 
226 void
send_signal_desktop_cache_build(void)227 send_signal_desktop_cache_build(void)
228 {
229    _broadcast(ipc, 1 /* desktop cache build */, 1, NULL, 0);
230 }
231 
232 void
send_signal_mime_cache_build(void)233 send_signal_mime_cache_build(void)
234 {
235    _broadcast(ipc, 4 /* mime cache build */, 1, NULL, 0);
236 }
237 
238 Eina_Bool
ipc_init(void)239 ipc_init(void)
240 {
241    if (init > 0) return EINA_TRUE;
242    if (!ecore_ipc_init()) return EINA_FALSE;
243    ipc = ecore_ipc_server_add(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
244    if (!ipc)
245      {
246         ecore_ipc_shutdown();
247         return EINA_FALSE;
248      }
249    quit_timer_start = ecore_timer_add(10.0, _cb_quit_timer_start, NULL);
250    hnd_add = ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_ADD,
251                                      _cb_client_add, NULL);
252    hnd_del = ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DEL,
253                                      _cb_client_del, NULL);
254    hnd_data = ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA,
255                                       _cb_client_data, NULL);
256    init++;
257    return EINA_TRUE;
258 }
259 
260 Eina_Bool
ipc_shutdown(void)261 ipc_shutdown(void)
262 {
263    if (init <= 0) return EINA_TRUE;
264    init--;
265    if (init > 0) return EINA_TRUE;
266    if (quit_timer) ecore_timer_del(quit_timer);
267    if (quit_timer_start) ecore_timer_del(quit_timer_start);
268    quit_timer = NULL;
269    quit_timer_start = NULL;
270    ecore_ipc_server_del(ipc);
271    ecore_event_handler_del(hnd_add);
272    ecore_event_handler_del(hnd_del);
273    ecore_event_handler_del(hnd_data);
274    ipc = NULL;
275    hnd_add = NULL;
276    hnd_del = NULL;
277    hnd_data = NULL;
278    ecore_ipc_shutdown();
279    return EINA_TRUE;
280 }
281 
282