1
2 #ifdef HAVE_CONFIG_H
3 # include <config.h>
4 #endif
5
6 /* TODO: Consider flushing local icons cache after idling.
7 * Icon requests will probably come in batches, f.ex. during menu
8 * browsing.
9 */
10
11 #include <libgen.h>
12 #include <unistd.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15
16 #include <Eet.h>
17 #include <Ecore.h>
18 #include <Ecore_File.h>
19 #include <Ecore_Ipc.h>
20 #include <Ecore_Con.h>
21
22 /* define macros and variable for using the eina logging system */
23 #define EFREET_MODULE_LOG_DOM _efreet_cache_log_dom
24 static int _efreet_cache_log_dom = -1;
25
26 #include "Efreet.h"
27 #include "efreet_private.h"
28 #include "efreet_cache_private.h"
29 #include "../../static_libs/buildsystem/buildsystem.h"
30 #define NON_EXISTING (void *)-1
31
32 typedef struct _Efreet_Old_Cache Efreet_Old_Cache;
33
34 struct _Efreet_Old_Cache
35 {
36 Eina_Hash *hash;
37 Eet_File *ef;
38 };
39
40 static Ecore_Ipc_Server *ipc = NULL;
41 static Ecore_Event_Handler *hnd_add = NULL;
42 static Ecore_Event_Handler *hnd_del = NULL;
43 static Ecore_Event_Handler *hnd_data = NULL;
44
45 static Eina_Lock _lock;
46
47 /**
48 * Data for cache files
49 */
50 static Eet_Data_Descriptor *directory_edd = NULL;
51 static Eet_Data_Descriptor *icon_theme_edd = NULL;
52 static Eet_Data_Descriptor *icon_theme_directory_edd = NULL;
53
54 static Eet_Data_Descriptor *icon_fallback_edd = NULL;
55 static Eet_Data_Descriptor *icon_element_pointer_edd = NULL;
56 static Eet_Data_Descriptor *icon_element_edd = NULL;
57 static Eet_Data_Descriptor *icon_edd = NULL;
58
59 static Eet_File *icon_cache = NULL;
60 static Eet_File *fallback_cache = NULL;
61 static Eet_File *icon_theme_cache = NULL;
62
63 static Eina_Hash *themes = NULL;
64 static Eina_Hash *icons = NULL;
65 static Eina_Hash *fallbacks = NULL;
66
67 static const char *icon_theme_cache_file = NULL;
68
69 static const char *theme_name = NULL;
70
71 static Eet_Data_Descriptor *version_edd = NULL;
72 static Eet_Data_Descriptor *desktop_edd = NULL;
73 static Eet_Data_Descriptor *desktop_action_edd = NULL;
74 static Eet_Data_Descriptor *hash_array_string_edd = NULL;
75 static Eet_Data_Descriptor *array_string_edd = NULL;
76 static Eet_Data_Descriptor *hash_string_edd = NULL;
77
78 static Eina_Hash *desktops = NULL;
79 static Eet_File *desktop_cache = NULL;
80 static const char *desktop_cache_file = NULL;
81
82 static Eina_List *old_desktop_caches = NULL;
83
84 static const char *util_cache_file = NULL;
85 static Eet_File *util_cache = NULL;
86 static Efreet_Cache_Hash *util_cache_hash = NULL;
87 static const char *util_cache_hash_key = NULL;
88 static Efreet_Cache_Array_String *util_cache_names = NULL;
89 static const char *util_cache_names_key = NULL;
90
91 static void efreet_cache_edd_shutdown(void);
92 static void efreet_cache_icon_free(Efreet_Cache_Icon *icon);
93 static void efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon);
94 static void efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme);
95
96 static Eina_Bool efreet_cache_check(Eet_File **ef, const char *path, int major);
97 static void *efreet_cache_close(Eet_File *ef);
98
99 static void icon_cache_update_free(void *data, void *ev);
100
101 static void *hash_array_string_add(void *hash, const char *key, void *data);
102
103 static Eina_Bool disable_cache;
104 static Eina_Bool run_in_tree;
105 static int relaunch_try = 0;
106
107 EAPI int EFREET_EVENT_ICON_CACHE_UPDATE = 0;
108 EAPI int EFREET_EVENT_DESKTOP_CACHE_UPDATE = 0;
109 EAPI int EFREET_EVENT_DESKTOP_CACHE_BUILD = 0;
110
111 #define IPC_HEAD(_type) \
112 Ecore_Ipc_Event_Server_##_type *e = event; \
113 if (e->server != ipc) \
114 return ECORE_CALLBACK_PASS_ON
115
116 static void
_ipc_launch(void)117 _ipc_launch(void)
118 {
119 char buf[PATH_MAX];
120 int num;
121 int try_gap = 10000; // 10ms
122 int tries = 1000; // 1000 * 10ms == 10sec
123 const char *s;
124
125 if (relaunch_try == 0)
126 {
127 ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
128 if (ipc)
129 {
130 relaunch_try++;
131 return;
132 }
133 }
134 relaunch_try--;
135 s = getenv("EFREETD_CONNECT_TRIES");
136 if (s)
137 {
138 num = atoi(s);
139 if (num >= 0) tries = num;
140 }
141 s = getenv("EFREETD_CONNECT_TRY_GAP");
142 if (s)
143 {
144 num = atoi(s);
145 if (num >= 0) try_gap = num;
146 }
147 if (run_in_tree)
148 bs_binary_get(buf, sizeof(buf), "efreet", "efreetd");
149 else
150 snprintf(buf, sizeof(buf), PACKAGE_BIN_DIR "/efreetd");
151 ecore_exe_run(buf, NULL);
152 num = 0;
153 while ((!ipc) && (num < tries))
154 {
155 num++;
156 usleep(try_gap);
157 ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
158 }
159 if (!ipc) ERR("Timeout in trying to start and then connect to efreetd");
160 }
161
162 static Eina_Bool
_cb_server_add(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)163 _cb_server_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
164 {
165 IPC_HEAD(Add);
166 relaunch_try--;
167 return ECORE_CALLBACK_DONE;
168 }
169
170 static Ecore_Timer *reconnect_timer = NULL;
171 static unsigned int reconnect_count = 0;
172
173 static Eina_Bool
_cb_server_reconnect(void * data EINA_UNUSED)174 _cb_server_reconnect(void *data EINA_UNUSED)
175 {
176 if (reconnect_timer) ecore_timer_del(reconnect_timer);
177 reconnect_timer = NULL;
178 reconnect_count++;
179 _ipc_launch();
180 if (ipc)
181 {
182 const char *s;
183 int len = 0;
184
185 s = efreet_language_get();
186 if (s) len = strlen(s);
187 ecore_ipc_server_send(ipc, 1, 0, 0, 0, 0, s, len);
188 efreet_icon_extensions_refresh();
189 }
190 return EINA_FALSE;
191 }
192
193 static Eina_Bool
_cb_server_del(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)194 _cb_server_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
195 {
196 double t;
197 IPC_HEAD(Del);
198 ipc = NULL;
199
200 if (disable_cache) return ECORE_CALLBACK_RENEW;
201 if (reconnect_count > 10)
202 {
203 char *address = ecore_con_local_path_new(EINA_FALSE, "efreetd", 0);
204 reconnect_timer = NULL;
205 ERR("efreetd connection failed 10 times! check for stale socket file at %s", address);
206 free(address);
207 return EINA_FALSE;
208 }
209 // random 0.5 -> 1.0 sec from now
210 t = (((double)((rand() + (int)getpid()) & 0xff) / 255.0) * 0.5) + 0.5;
211 if (reconnect_timer) ecore_timer_del(reconnect_timer);
212 reconnect_timer = ecore_timer_add(t, _cb_server_reconnect, NULL);
213 return ECORE_CALLBACK_DONE;
214 }
215
216 static void
_efreet_cache_reset()217 _efreet_cache_reset()
218 {
219 const char *s;
220 int len = 0;
221
222 if (ipc) ecore_ipc_server_del(ipc);
223 ipc = NULL;
224 if (!disable_cache)
225 ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
226 if (!ipc) return;
227
228 s = efreet_language_get();
229 if (s) len = strlen(s);
230 ecore_ipc_server_send(ipc, 1, 0, 0, 0, 0, s, len);
231 efreet_icon_extensions_refresh();
232 }
233
234 static void
_icon_desktop_cache_update_event_add(int event_type)235 _icon_desktop_cache_update_event_add(int event_type)
236 {
237 Efreet_Event_Cache_Update *ev;
238 Efreet_Old_Cache *d = NULL;
239 Eina_List *l = NULL;
240
241 efreet_cache_desktop_close();
242
243 ev = NEW(Efreet_Event_Cache_Update, 1);
244 if (!ev) return;
245
246 IF_RELEASE(theme_name);
247
248 // Save all old caches
249 d = NEW(Efreet_Old_Cache, 1);
250 if (d)
251 {
252 d->hash = themes;
253 d->ef = icon_theme_cache;
254 l = eina_list_append(l, d);
255 }
256
257 d = NEW(Efreet_Old_Cache, 1);
258 if (d)
259 {
260 d->hash = icons;
261 d->ef = icon_cache;
262 l = eina_list_append(l, d);
263 }
264
265 d = NEW(Efreet_Old_Cache, 1);
266 if (d)
267 {
268 d->hash = fallbacks;
269 d->ef = fallback_cache;
270 l = eina_list_append(l, d);
271 }
272
273 // Create new empty caches
274 themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
275 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
276 fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
277
278 icon_theme_cache = NULL;
279 icon_cache = NULL;
280 fallback_cache = NULL;
281
282 // Send event
283 ecore_event_add(event_type, ev, icon_cache_update_free, l);
284 }
285
286 EAPI void (*_efreet_mime_update_func) (void) = NULL;
287
288 static Eina_Bool
_cb_server_data(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)289 _cb_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
290 {
291 IPC_HEAD(Data);
292 if (e->major == 1) // registration
293 {
294 if (e->minor == 1)
295 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, NULL, NULL, NULL);
296 }
297 else if (e->major == 2) // icon cache update
298 {
299 if (e->minor == 1)
300 _icon_desktop_cache_update_event_add(EFREET_EVENT_ICON_CACHE_UPDATE);
301 else
302 ecore_event_add(EFREET_EVENT_ICON_CACHE_UPDATE, NULL, NULL, NULL);
303 }
304 else if (e->major == 3) // desktop cache update
305 {
306 _icon_desktop_cache_update_event_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE);
307 }
308 else if (e->major == 4) // mime cache update
309 {
310 if (_efreet_mime_update_func) _efreet_mime_update_func();
311 }
312 return ECORE_CALLBACK_DONE;
313 }
314
315 int
efreet_cache_init(void)316 efreet_cache_init(void)
317 {
318 char buf[PATH_MAX];
319
320 _efreet_cache_log_dom = eina_log_domain_register("efreet_cache", EFREET_DEFAULT_LOG_COLOR);
321 if (_efreet_cache_log_dom < 0)
322 return 0;
323
324 if (!eina_lock_new(&_lock))
325 {
326 ERR("Could not create lock");
327 goto error;
328 }
329
330 snprintf(buf, sizeof(buf), "%s/efreet", efreet_cache_home_get());
331 if (!ecore_file_mkpath(buf))
332 {
333 ERR("Failed to create directory '%s'", buf);
334 }
335
336 run_in_tree = !!getenv("EFL_RUN_IN_TREE");
337
338 EFREET_EVENT_ICON_CACHE_UPDATE = ecore_event_type_new();
339 EFREET_EVENT_DESKTOP_CACHE_UPDATE = ecore_event_type_new();
340 EFREET_EVENT_DESKTOP_CACHE_BUILD = ecore_event_type_new();
341
342 themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
343 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
344 fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
345 desktops = eina_hash_string_superfast_new(NULL);
346
347 ecore_ipc_init();
348 // XXX: connect to efreetd
349
350 if (efreet_cache_update)
351 {
352 if (disable_cache)
353 ipc = NULL;
354 else
355 {
356 ipc = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, "efreetd", 0, NULL);
357 if (!ipc) _ipc_launch();
358 }
359 if (ipc)
360 {
361 const char *s;
362 int len = 0;
363
364 hnd_add = ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD,
365 _cb_server_add, NULL);
366 hnd_del = ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL,
367 _cb_server_del, NULL);
368 hnd_data = ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA,
369 _cb_server_data, NULL);
370 s = efreet_language_get();
371 if (s) len = strlen(s);
372 ecore_ipc_server_send(ipc, 1, 0, 0, 0, 0, s, len);
373 }
374 else
375 {
376 Efreet_Event_Cache_Update *ev;
377
378 if (!disable_cache)
379 WRN("Can't contact efreetd daemon for desktop/icon etc. changes");
380 ev = NEW(Efreet_Event_Cache_Update, 1);
381 if (ev)
382 {
383 ev->error = 1;
384 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, ev, NULL, NULL);
385 }
386 }
387 }
388 ecore_fork_reset_callback_add(_efreet_cache_reset, NULL);
389
390 return 1;
391 error:
392 if (themes) eina_hash_free(themes);
393 themes = NULL;
394 if (icons) eina_hash_free(icons);
395 icons = NULL;
396 if (fallbacks) eina_hash_free(fallbacks);
397 fallbacks = NULL;
398 if (desktops) eina_hash_free(desktops);
399 desktops = NULL;
400
401 efreet_cache_edd_shutdown();
402 return 0;
403 }
404
405 void
efreet_cache_shutdown(void)406 efreet_cache_shutdown(void)
407 {
408 Efreet_Old_Cache *d;
409
410 ecore_event_type_flush(EFREET_EVENT_ICON_CACHE_UPDATE,
411 EFREET_EVENT_DESKTOP_CACHE_UPDATE,
412 EFREET_EVENT_DESKTOP_CACHE_BUILD);
413 ecore_fork_reset_callback_del(_efreet_cache_reset, NULL);
414 IF_RELEASE(theme_name);
415
416 icon_cache = efreet_cache_close(icon_cache);
417 icon_theme_cache = efreet_cache_close(icon_theme_cache);
418 fallback_cache = efreet_cache_close(fallback_cache);
419
420 IF_FREE_HASH(themes);
421 IF_FREE_HASH(icons);
422 IF_FREE_HASH(fallbacks);
423
424 IF_FREE_HASH_CB(desktops, EINA_FREE_CB(efreet_cache_desktop_free));
425 desktop_cache = efreet_cache_close(desktop_cache);
426 IF_RELEASE(desktop_cache_file);
427
428 efreet_cache_edd_shutdown();
429 IF_RELEASE(icon_theme_cache_file);
430
431 if (old_desktop_caches)
432 ERR("This application has not properly closed all its desktop references!");
433 EINA_LIST_FREE(old_desktop_caches, d)
434 {
435 eina_hash_free(d->hash);
436 eet_close(d->ef);
437 free(d);
438 }
439
440 IF_RELEASE(util_cache_names_key);
441 efreet_cache_array_string_free(util_cache_names);
442 util_cache_names = NULL;
443
444 IF_RELEASE(util_cache_hash_key);
445 if (util_cache_hash)
446 {
447 eina_hash_free(util_cache_hash->hash);
448 free(util_cache_hash);
449 util_cache_hash = NULL;
450 }
451
452 util_cache = efreet_cache_close(util_cache);
453 IF_RELEASE(util_cache_file);
454
455 if (ipc) ecore_ipc_server_del(ipc);
456 if (hnd_add) ecore_event_handler_del(hnd_add);
457 if (hnd_del) ecore_event_handler_del(hnd_del);
458 if (hnd_data) ecore_event_handler_del(hnd_data);
459
460 ecore_ipc_shutdown();
461
462 ipc = NULL;
463 hnd_add = NULL;
464 hnd_del = NULL;
465 hnd_data = NULL;
466
467 eina_lock_free(&_lock);
468
469 eina_log_domain_unregister(_efreet_cache_log_dom);
470 _efreet_cache_log_dom = -1;
471 }
472
473 /*
474 * Needs EAPI because of helper binaries
475 */
476 EAPI const char *
efreet_icon_cache_file(const char * theme)477 efreet_icon_cache_file(const char *theme)
478 {
479 static char cache_file[PATH_MAX] = { '\0' };
480 const char *cache;
481
482 EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL);
483
484 cache = efreet_cache_home_get();
485
486 snprintf(cache_file, sizeof(cache_file), "%s/efreet/icons_%s_%s.eet", cache, theme, efreet_hostname_get());
487
488 return cache_file;
489 }
490
491 /*
492 * Needs EAPI because of helper binaries
493 */
494 EAPI const char *
efreet_icon_theme_cache_file(void)495 efreet_icon_theme_cache_file(void)
496 {
497 char tmp[PATH_MAX] = { '\0' };
498
499 if (icon_theme_cache_file) return icon_theme_cache_file;
500
501 snprintf(tmp, sizeof(tmp), "%s/efreet/icon_themes_%s.eet",
502 efreet_cache_home_get(), efreet_hostname_get());
503 icon_theme_cache_file = eina_stringshare_add(tmp);
504
505 return icon_theme_cache_file;
506 }
507
508 /*
509 * Needs EAPI because of helper binaries
510 */
511 EAPI const char *
efreet_desktop_util_cache_file(void)512 efreet_desktop_util_cache_file(void)
513 {
514 char tmp[PATH_MAX] = { '\0' };
515 const char *cache_dir, *lang, *country, *modifier;
516
517 if (util_cache_file) return util_cache_file;
518
519 cache_dir = efreet_cache_home_get();
520 lang = efreet_lang_get();
521 country = efreet_lang_country_get();
522 modifier = efreet_lang_modifier_get();
523
524 if (lang && country && modifier)
525 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s@%s.eet", cache_dir, efreet_hostname_get(), lang, country, modifier);
526 else if (lang && country)
527 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s.eet", cache_dir, efreet_hostname_get(), lang, country);
528 else if (lang)
529 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s.eet", cache_dir, efreet_hostname_get(), lang);
530 else
531 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s.eet", cache_dir, efreet_hostname_get());
532
533 util_cache_file = eina_stringshare_add(tmp);
534 return util_cache_file;
535 }
536
537 /*
538 * Needs EAPI because of helper binaries
539 */
540 #define SHSH(n, v) ((((v) << (n)) & 0xffffffff) | ((v) >> (32 - (n))))
541
542 static inline int
int_to_bigendian(int in)543 int_to_bigendian(int in)
544 {
545 static const unsigned char test[4] = { 0x11, 0x22, 0x33, 0x44 };
546 static const unsigned int *test_i = (const unsigned int *)test;
547 if (test_i[0] == 0x44332211) return eina_swap32(in);
548 return in;
549 }
550
551 static void
sha1(unsigned char * data,int size,unsigned char * dst)552 sha1(unsigned char *data, int size, unsigned char *dst)
553 {
554 unsigned int digest[5], word[80], wa, wb, wc, wd, we, t;
555 unsigned char buf[64], *d;
556 int idx, left, i;
557 const unsigned int magic[4] =
558 { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
559
560 idx = 0;
561 digest[0] = 0x67452301; digest[1] = 0xefcdab89; digest[2] = 0x98badcfe;
562 digest[3] = 0x10325476; digest[4] = 0xc3d2e1f0;
563
564 memset(buf, 0, sizeof(buf));
565 for (left = size, d = data; left > 0; left--, d++)
566 {
567 if ((idx == 0) && (left < 64))
568 {
569 memset(buf, 0, 60);
570 buf[60] = (size >> 24) & 0xff;
571 buf[61] = (size >> 16) & 0xff;
572 buf[62] = (size >> 8) & 0xff;
573 buf[63] = (size) & 0xff;
574 }
575 buf[idx] = *d;
576 idx++;
577 if ((idx == 64) || (left == 1))
578 {
579 if ((left == 1) && (idx < 64)) buf[idx] = 0x80;
580 for (i = 0; i < 16; i++)
581 {
582 word[i] = (unsigned int)buf[(i * 4) ] << 24;
583 word[i] |= (unsigned int)buf[(i * 4) + 1] << 16;
584 word[i] |= (unsigned int)buf[(i * 4) + 2] << 8;
585 word[i] |= (unsigned int)buf[(i * 4) + 3];
586 }
587 for (i = 16; i < 80; i++)
588 word[i] = SHSH(1,
589 word[i - 3 ] ^ word[i - 8 ] ^
590 word[i - 14] ^ word[i - 16]);
591 wa = digest[0]; wb = digest[1]; wc = digest[2];
592 wd = digest[3]; we = digest[4];
593 for (i = 0; i < 80; i++)
594 {
595 if (i < 20)
596 t = SHSH(5, wa) + ((wb & wc) | ((~wb) & wd)) +
597 we + word[i] + magic[0];
598 else if (i < 40)
599 t = SHSH(5, wa) + (wb ^ wc ^ wd) +
600 we + word[i] + magic[1];
601 else if (i < 60)
602 t = SHSH(5, wa) + ((wb & wc) | (wb & wd) | (wc & wd)) +
603 we + word[i] + magic[2];
604 else if (i < 80)
605 t = SHSH(5, wa) + (wb ^ wc ^ wd) +
606 we + word[i] + magic[3];
607 we = wd;
608 wd = wc;
609 wc = SHSH(30, wb);
610 wb = wa;
611 wa = t;
612 }
613 digest[0] += wa; digest[1] += wb; digest[2] += wc;
614 digest[3] += wd; digest[4] += we;
615 idx = 0;
616 }
617 }
618 t = int_to_bigendian(digest[0]); digest[0] = t;
619 t = int_to_bigendian(digest[1]); digest[1] = t;
620 t = int_to_bigendian(digest[2]); digest[2] = t;
621 t = int_to_bigendian(digest[3]); digest[3] = t;
622 t = int_to_bigendian(digest[4]); digest[4] = t;
623 memcpy(dst, digest, 5 * 4);
624 }
625
626 EAPI Eina_Bool
efreet_file_cache_fill(const char * file,Efreet_Cache_Check * check)627 efreet_file_cache_fill(const char *file, Efreet_Cache_Check *check)
628 {
629 struct stat st;
630
631 memset(check, 0, sizeof(Efreet_Cache_Check));
632 #ifdef _WIN32
633 if (stat(file, &st) != 0) return EINA_FALSE;
634 #else
635 ssize_t size = 0;
636
637 if (lstat(file, &st) != 0) return EINA_FALSE;
638 if (S_ISLNK(st.st_mode))
639 {
640 char link[PATH_MAX];
641
642 size = readlink(file, link, sizeof(link));
643 if ((size > 0) && ((size_t)size >= sizeof(link))) return EINA_FALSE;
644 if (stat(file, &st) != 0) return EINA_FALSE;
645 }
646 if (size > 0) sha1((unsigned char *)link, size, check->link_sha1);
647 #endif
648 check->uid = st.st_uid;
649 check->gid = st.st_gid;
650 check->size = st.st_size;
651 #ifndef _WIN32
652 check->blocks = st.st_blocks;
653 #else
654 check->blocks = 0;
655 #endif
656 check->mtime = st.st_mtime;
657 check->chtime = st.st_ctime;
658 check->mode = st.st_mode;
659 return EINA_TRUE;
660 }
661
662 EAPI Eina_Bool // true if matches
efreet_file_cache_check(const Efreet_Cache_Check * check1,const Efreet_Cache_Check * check2)663 efreet_file_cache_check(const Efreet_Cache_Check *check1, const Efreet_Cache_Check *check2)
664 {
665 if ((check1->mtime != check2->mtime ) ||
666 (check1->size != check2->size ) ||
667 (check1->chtime != check2->chtime ) ||
668 (check1->blocks != check2->blocks) ||
669 (check1->mode != check2->mode ) ||
670 (check1->uid != check2->uid ) ||
671 (check1->gid != check2->gid ) ||
672 (memcmp(check1->link_sha1, check2->link_sha1, 20) != 0))
673 {
674 return EINA_FALSE;
675 }
676 return EINA_TRUE; // matches
677 }
678
679 EAPI Eet_Data_Descriptor *
efreet_version_edd(void)680 efreet_version_edd(void)
681 {
682 Eet_Data_Descriptor_Class eddc;
683
684 if (version_edd) return version_edd;
685
686 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Version);
687 version_edd = eet_data_descriptor_file_new(&eddc);
688 if (!version_edd) return NULL;
689
690 EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
691 "minor", minor, EET_T_UCHAR);
692 EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
693 "major", major, EET_T_UCHAR);
694
695 return version_edd;
696 }
697
698 /*
699 * Needs EAPI because of helper binaries
700 */
701 EAPI Eet_Data_Descriptor *
efreet_hash_array_string_edd(void)702 efreet_hash_array_string_edd(void)
703 {
704 Eet_Data_Descriptor_Class eddc;
705
706 if (hash_array_string_edd) return hash_array_string_edd;
707
708 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
709 eddc.func.hash_add = hash_array_string_add;
710 hash_array_string_edd = eet_data_descriptor_file_new(&eddc);
711 if (!hash_array_string_edd) return NULL;
712
713 EET_DATA_DESCRIPTOR_ADD_HASH(hash_array_string_edd, Efreet_Cache_Hash,
714 "hash", hash, efreet_array_string_edd());
715
716 return hash_array_string_edd;
717 }
718
719 /*
720 * Needs EAPI because of helper binaries
721 */
722 EAPI Eet_Data_Descriptor *
efreet_hash_string_edd(void)723 efreet_hash_string_edd(void)
724 {
725 Eet_Data_Descriptor_Class eddc;
726
727 if (hash_string_edd) return hash_string_edd;
728
729 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
730 hash_string_edd = eet_data_descriptor_file_new(&eddc);
731 if (!hash_string_edd) return NULL;
732
733 EET_DATA_DESCRIPTOR_ADD_HASH_STRING(hash_string_edd, Efreet_Cache_Hash,
734 "hash", hash);
735
736 return hash_string_edd;
737 }
738
739 /*
740 * Needs EAPI because of helper binaries
741 */
742 EAPI Eet_Data_Descriptor *
efreet_array_string_edd(void)743 efreet_array_string_edd(void)
744 {
745 Eet_Data_Descriptor_Class eddc;
746
747 if (array_string_edd) return array_string_edd;
748
749 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Array_String);
750 array_string_edd = eet_data_descriptor_file_new(&eddc);
751 if (!array_string_edd) return NULL;
752 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(array_string_edd, Efreet_Cache_Array_String,
753 "array", array);
754
755 return array_string_edd;
756 }
757
758 /*
759 * Needs EAPI because of helper binaries
760 */
761 EAPI const char *
efreet_desktop_cache_file(void)762 efreet_desktop_cache_file(void)
763 {
764 char tmp[PATH_MAX] = { '\0' };
765 const char *cache, *lang, *country, *modifier;
766
767 if (desktop_cache_file) return desktop_cache_file;
768
769 cache = efreet_cache_home_get();
770 lang = efreet_lang_get();
771 country = efreet_lang_country_get();
772 modifier = efreet_lang_modifier_get();
773
774 if (lang && country && modifier)
775 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s@%s.eet", cache, efreet_hostname_get(), lang, country, modifier);
776 else if (lang && country)
777 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s.eet", cache, efreet_hostname_get(), lang, country);
778 else if (lang)
779 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s.eet", cache, efreet_hostname_get(), lang);
780 else
781 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s.eet", cache, efreet_hostname_get());
782
783 desktop_cache_file = eina_stringshare_add(tmp);
784 return desktop_cache_file;
785 }
786
787 #define EDD_SHUTDOWN(Edd) \
788 if (Edd) eet_data_descriptor_free(Edd); \
789 Edd = NULL;
790
791 static void
efreet_cache_edd_shutdown(void)792 efreet_cache_edd_shutdown(void)
793 {
794 EDD_SHUTDOWN(version_edd);
795 EDD_SHUTDOWN(desktop_edd);
796 EDD_SHUTDOWN(desktop_action_edd);
797 EDD_SHUTDOWN(hash_array_string_edd);
798 EDD_SHUTDOWN(array_string_edd);
799 EDD_SHUTDOWN(hash_string_edd);
800 EDD_SHUTDOWN(icon_theme_edd);
801 EDD_SHUTDOWN(icon_theme_directory_edd);
802 EDD_SHUTDOWN(directory_edd);
803 EDD_SHUTDOWN(icon_fallback_edd);
804 EDD_SHUTDOWN(icon_element_pointer_edd);
805 EDD_SHUTDOWN(icon_element_edd);
806 EDD_SHUTDOWN(icon_edd);
807 }
808
809 #define EFREET_POINTER_TYPE(Edd_Dest, Edd_Source, Type) \
810 { \
811 typedef struct _Efreet_##Type##_Pointer Efreet_##Type##_Pointer; \
812 struct _Efreet_##Type##_Pointer \
813 { \
814 Efreet_##Type *pointer; \
815 }; \
816 \
817 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_##Type##_Pointer); \
818 Edd_Dest = eet_data_descriptor_file_new(&eddc); \
819 EET_DATA_DESCRIPTOR_ADD_SUB(Edd_Dest, Efreet_##Type##_Pointer, \
820 "pointer", pointer, Edd_Source); \
821 }
822
823 static Eet_Data_Descriptor *
efreet_icon_directory_edd(void)824 efreet_icon_directory_edd(void)
825 {
826 Eet_Data_Descriptor_Class eddc;
827
828 if (directory_edd) return directory_edd;
829
830 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Directory);
831 directory_edd = eet_data_descriptor_file_new(&eddc);
832 if (!directory_edd) return NULL;
833
834 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
835 "check.uid", check.uid, EET_T_LONG_LONG);
836 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
837 "check.gid", check.gid, EET_T_LONG_LONG);
838 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
839 "check.size", check.size, EET_T_LONG_LONG);
840 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
841 "check.blocks", check.blocks, EET_T_LONG_LONG);
842 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
843 "check.mtime", check.mtime, EET_T_LONG_LONG);
844 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
845 "check.chtime", check.chtime, EET_T_LONG_LONG);
846 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
847 "check.mode", check.mode, EET_T_INT);
848 EET_DATA_DESCRIPTOR_ADD_BASIC_ARRAY(directory_edd, Efreet_Cache_Directory,
849 "check.link_sha1", check.link_sha1, EET_T_CHAR);
850
851 return directory_edd;
852 }
853
854 /*
855 * Needs EAPI because of helper binaries
856 */
857 EAPI Eet_Data_Descriptor *
efreet_icon_edd(void)858 efreet_icon_edd(void)
859 {
860 Eet_Data_Descriptor_Class eddc;
861
862 if (icon_edd) return icon_edd;
863
864 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Element);
865 icon_element_edd = eet_data_descriptor_file_new(&eddc);
866 if (!icon_element_edd) return NULL;
867
868 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
869 "type", type, EET_T_USHORT);
870 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
871 "normal", normal, EET_T_USHORT);
872 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
873 "normal", normal, EET_T_USHORT);
874 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
875 "min", min, EET_T_USHORT);
876 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
877 "max", max, EET_T_USHORT);
878 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_element_edd, Efreet_Cache_Icon_Element,
879 "paths", paths);
880
881 EFREET_POINTER_TYPE(icon_element_pointer_edd, icon_element_edd, Cache_Icon_Element);
882
883 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon);
884 icon_edd = eet_data_descriptor_file_new(&eddc);
885 if (!icon_edd) return NULL;
886
887 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_edd, Efreet_Cache_Icon,
888 "theme", theme, EET_T_STRING);
889 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(icon_edd, Efreet_Cache_Icon,
890 "icons", icons, icon_element_pointer_edd);
891
892 return icon_edd;
893 }
894
895 /*
896 * Needs EAPI because of helper binaries
897 */
898 EAPI Eet_Data_Descriptor *
efreet_icon_theme_edd(Eina_Bool cache)899 efreet_icon_theme_edd(Eina_Bool cache)
900 {
901 Eet_Data_Descriptor_Class eddc;
902
903 if (icon_theme_edd) return icon_theme_edd;
904
905 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Icon_Theme_Directory);
906 icon_theme_directory_edd = eet_data_descriptor_file_new(&eddc);
907 if (!icon_theme_directory_edd) return NULL;
908
909 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
910 "name", name, EET_T_STRING);
911 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
912 "context", context, EET_T_UCHAR);
913 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
914 "type", type, EET_T_UCHAR);
915 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
916 "size.normal", size.normal, EET_T_UINT);
917 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
918 "size.min", size.min, EET_T_UINT);
919 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
920 "size.max", size.max, EET_T_UINT);
921 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
922 "size.threshold", size.threshold, EET_T_UINT);
923
924 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Theme);
925 icon_theme_edd = eet_data_descriptor_file_new(&eddc);
926 if (!icon_theme_edd) return NULL;
927
928 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
929 "name.internal", theme.name.internal, EET_T_STRING);
930 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
931 "name.name", theme.name.name, EET_T_STRING);
932 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
933 "comment", theme.comment, EET_T_STRING);
934 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
935 "example_icon", theme.example_icon, EET_T_STRING);
936
937 eet_data_descriptor_element_add(icon_theme_edd, "paths", EET_T_STRING, EET_G_LIST,
938 offsetof(Efreet_Cache_Icon_Theme, theme.paths), 0, NULL, NULL);
939 eet_data_descriptor_element_add(icon_theme_edd, "inherits", EET_T_STRING, EET_G_LIST,
940 offsetof(Efreet_Cache_Icon_Theme, theme.inherits), 0, NULL, NULL);
941 EET_DATA_DESCRIPTOR_ADD_LIST(icon_theme_edd, Efreet_Cache_Icon_Theme,
942 "directories", theme.directories, icon_theme_directory_edd);
943
944 if (cache)
945 {
946 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
947 "check.uid", check.uid, EET_T_LONG_LONG);
948 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
949 "check.gid", check.gid, EET_T_LONG_LONG);
950 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
951 "check.size", check.size, EET_T_LONG_LONG);
952 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
953 "check.blocks", check.blocks, EET_T_LONG_LONG);
954 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
955 "check.mtime", check.mtime, EET_T_LONG_LONG);
956 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
957 "check.chtime", check.chtime, EET_T_LONG_LONG);
958 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
959 "check.mode", check.mode, EET_T_INT);
960 EET_DATA_DESCRIPTOR_ADD_BASIC_ARRAY(icon_theme_edd, Efreet_Cache_Icon_Theme,
961 "check.link_sha1", check.link_sha1, EET_T_CHAR);
962
963 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
964 "path", path, EET_T_STRING);
965
966 EET_DATA_DESCRIPTOR_ADD_HASH(icon_theme_edd, Efreet_Cache_Icon_Theme,
967 "dirs", dirs, efreet_icon_directory_edd());
968 }
969
970 return icon_theme_edd;
971 }
972
973 /*
974 * Needs EAPI because of helper binaries
975 */
976 EAPI Eet_Data_Descriptor *
efreet_icon_fallback_edd(void)977 efreet_icon_fallback_edd(void)
978 {
979 Eet_Data_Descriptor_Class eddc;
980
981 if (icon_fallback_edd) return icon_fallback_edd;
982
983 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Fallback_Icon);
984 icon_fallback_edd = eet_data_descriptor_file_new(&eddc);
985 if (!icon_fallback_edd) return NULL;
986
987 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_fallback_edd,
988 Efreet_Cache_Fallback_Icon, "icons", icons);
989
990 return icon_fallback_edd;
991 }
992
993 /*
994 * Needs EAPI because of helper binaries
995 */
996 EAPI Eet_Data_Descriptor *
efreet_desktop_edd(void)997 efreet_desktop_edd(void)
998 {
999 Eet_Data_Descriptor_Class eddc;
1000
1001 if (desktop_edd) return desktop_edd;
1002
1003 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Desktop_Action);
1004 desktop_action_edd = eet_data_descriptor_file_new(&eddc);
1005 if (!desktop_action_edd) return NULL;
1006
1007 /* Desktop Spec 1.1 */
1008 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "key", key, EET_T_STRING);
1009 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "name", name, EET_T_STRING);
1010 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "icon", icon, EET_T_STRING);
1011 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_action_edd, Efreet_Desktop_Action, "exec", exec, EET_T_STRING);
1012
1013 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Desktop);
1014 desktop_edd = eet_data_descriptor_file_new(&eddc);
1015 if (!desktop_edd) return NULL;
1016
1017 /* Desktop Spec 1.0 */
1018 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "type", desktop.type, EET_T_INT);
1019 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "version", desktop.version, EET_T_STRING);
1020 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "orig_path", desktop.orig_path, EET_T_STRING);
1021 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "load_time", desktop.load_time, EET_T_LONG_LONG);
1022 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "name", desktop.name, EET_T_STRING);
1023 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "generic_name", desktop.generic_name, EET_T_STRING);
1024 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "comment", desktop.comment, EET_T_STRING);
1025 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "icon", desktop.icon, EET_T_STRING);
1026 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "try_exec", desktop.try_exec, EET_T_STRING);
1027 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "exec", desktop.exec, EET_T_STRING);
1028 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "path", desktop.path, EET_T_STRING);
1029 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_wm_class", desktop.startup_wm_class, EET_T_STRING);
1030 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "url", desktop.url, EET_T_STRING);
1031 eet_data_descriptor_element_add(desktop_edd, "only_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.only_show_in), 0, NULL, NULL);
1032 eet_data_descriptor_element_add(desktop_edd, "not_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.not_show_in), 0, NULL, NULL);
1033 eet_data_descriptor_element_add(desktop_edd, "categories", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.categories), 0, NULL, NULL);
1034 eet_data_descriptor_element_add(desktop_edd, "mime_types", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.mime_types), 0, NULL, NULL);
1035 eet_data_descriptor_element_add(desktop_edd, "x", EET_T_STRING, EET_G_HASH, offsetof(Efreet_Cache_Desktop, desktop.x), 0, NULL, NULL);
1036 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "no_display", desktop.no_display, EET_T_UCHAR);
1037 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "hidden", desktop.hidden, EET_T_UCHAR);
1038 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "terminal", desktop.terminal, EET_T_UCHAR);
1039 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_notify", desktop.startup_notify, EET_T_UCHAR);
1040
1041 /* Desktop Spec 1.1 */
1042 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "dbus_activatable", desktop.dbus_activatable, EET_T_UCHAR);
1043 EET_DATA_DESCRIPTOR_ADD_LIST(desktop_edd, Efreet_Cache_Desktop,
1044 "actions", desktop.actions, desktop_action_edd);
1045 eet_data_descriptor_element_add(desktop_edd, "implements", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.implements), 0, NULL, NULL);
1046 eet_data_descriptor_element_add(desktop_edd, "keywords", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.keywords), 0, NULL, NULL);
1047
1048 return desktop_edd;
1049 }
1050
1051 Efreet_Cache_Icon *
efreet_cache_icon_find(Efreet_Icon_Theme * theme,const char * icon)1052 efreet_cache_icon_find(Efreet_Icon_Theme *theme, const char *icon)
1053 {
1054 Efreet_Cache_Icon *cache = NULL;
1055
1056 if (theme_name && strcmp(theme_name, theme->name.internal))
1057 {
1058 /* FIXME: this is bad if people have pointer to this cache, things will go wrong */
1059 INF("theme_name change from '%s' to '%s'", theme_name, theme->name.internal);
1060 IF_RELEASE(theme_name);
1061 icon_cache = efreet_cache_close(icon_cache);
1062 eina_hash_free(icons);
1063 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
1064 }
1065
1066 if (!efreet_cache_check(&icon_cache, efreet_icon_cache_file(theme->name.internal), EFREET_ICON_CACHE_MAJOR)) return NULL;
1067 if (!theme_name)
1068 theme_name = eina_stringshare_add(theme->name.internal);
1069
1070 cache = eina_hash_find(icons, icon);
1071 if (cache == NON_EXISTING) return NULL;
1072 if (cache) return cache;
1073
1074 cache = eet_data_read(icon_cache, efreet_icon_edd(), icon);
1075 if (cache)
1076 eina_hash_add(icons, icon, cache);
1077 else
1078 eina_hash_add(icons, icon, NON_EXISTING);
1079 return cache;
1080 }
1081
1082 Efreet_Cache_Fallback_Icon *
efreet_cache_icon_fallback_find(const char * icon)1083 efreet_cache_icon_fallback_find(const char *icon)
1084 {
1085 Efreet_Cache_Fallback_Icon *cache;
1086
1087 if (!efreet_cache_check(&fallback_cache, efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EFREET_ICON_CACHE_MAJOR)) return NULL;
1088
1089 cache = eina_hash_find(fallbacks, icon);
1090 if (cache == NON_EXISTING) return NULL;
1091 if (cache) return cache;
1092
1093 cache = eet_data_read(fallback_cache, efreet_icon_fallback_edd(), icon);
1094 if (cache)
1095 eina_hash_add(fallbacks, icon, cache);
1096 else
1097 eina_hash_add(fallbacks, icon, NON_EXISTING);
1098 return cache;
1099 }
1100
1101 Efreet_Icon_Theme *
efreet_cache_icon_theme_find(const char * theme)1102 efreet_cache_icon_theme_find(const char *theme)
1103 {
1104 Efreet_Cache_Icon_Theme *cache;
1105
1106 if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
1107
1108 cache = eina_hash_find(themes, theme);
1109 if (cache == NON_EXISTING) return NULL;
1110 if (cache) return &(cache->theme);
1111
1112 cache = eet_data_read(icon_theme_cache, efreet_icon_theme_edd(EINA_FALSE), theme);
1113 if (cache)
1114 {
1115 eina_hash_add(themes, theme, cache);
1116 return &(cache->theme);
1117 }
1118 else
1119 eina_hash_add(themes, theme, NON_EXISTING);
1120 return NULL;
1121 }
1122
1123 static void
efreet_cache_icon_free(Efreet_Cache_Icon * icon)1124 efreet_cache_icon_free(Efreet_Cache_Icon *icon)
1125 {
1126 unsigned int i;
1127
1128 if (!icon) return;
1129 if (icon == NON_EXISTING) return;
1130
1131 for (i = 0; i < icon->icons_count; ++i)
1132 {
1133 free(icon->icons[i]->paths);
1134 free(icon->icons[i]);
1135 }
1136
1137 free(icon->icons);
1138 free(icon);
1139 }
1140
1141 static void
efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon * icon)1142 efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon)
1143 {
1144 if (!icon) return;
1145 if (icon == NON_EXISTING) return;
1146
1147 free(icon->icons);
1148 free(icon);
1149 }
1150
1151 static void
efreet_cache_icon_theme_free(Efreet_Icon_Theme * theme)1152 efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme)
1153 {
1154 void *data;
1155
1156 if (!theme) return;
1157 if (theme == NON_EXISTING) return;
1158
1159 eina_list_free(theme->paths);
1160 eina_list_free(theme->inherits);
1161 EINA_LIST_FREE(theme->directories, data)
1162 free(data);
1163
1164 free(theme);
1165 }
1166
1167 Eina_List *
efreet_cache_icon_theme_list(void)1168 efreet_cache_icon_theme_list(void)
1169 {
1170 Eina_List *ret = NULL;
1171 char **keys;
1172 int i, num;
1173
1174 if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
1175 keys = eet_list(icon_theme_cache, "*", &num);
1176 if (!keys) return NULL;
1177 for (i = 0; i < num; i++)
1178 {
1179 Efreet_Icon_Theme *theme;
1180 if (!strncmp(keys[i], "__efreet", 8)) continue;
1181
1182 theme = eina_hash_find(themes, keys[i]);
1183 if (!theme)
1184 theme = efreet_cache_icon_theme_find(keys[i]);
1185 if (theme && theme != NON_EXISTING)
1186 ret = eina_list_append(ret, theme);
1187 }
1188 free(keys);
1189 return ret;
1190 }
1191
1192 /*
1193 * Needs EAPI because of helper binaries
1194 */
1195 EAPI void
efreet_cache_array_string_free(Efreet_Cache_Array_String * array)1196 efreet_cache_array_string_free(Efreet_Cache_Array_String *array)
1197 {
1198 if (!array) return;
1199 free(array->array);
1200 free(array);
1201 }
1202
1203 Efreet_Desktop *
efreet_cache_desktop_find(const char * file)1204 efreet_cache_desktop_find(const char *file)
1205 {
1206 Efreet_Cache_Desktop *cache = NULL;
1207
1208 eina_lock_take(&_lock);
1209 if (!efreet_cache_check(&desktop_cache, efreet_desktop_cache_file(), EFREET_DESKTOP_CACHE_MAJOR)) goto error;
1210
1211 cache = eina_hash_find(desktops, file);
1212 if (cache == NON_EXISTING) goto error;
1213 if (cache)
1214 {
1215 /* If less than one second since last stat, return desktop */
1216 if ((ecore_time_get() - cache->check_time) < 1)
1217 {
1218 INF("Return without stat %f %f for file '%s'", ecore_time_get(), cache->check_time, file);
1219 eina_lock_release(&_lock);
1220 return &cache->desktop;
1221 }
1222 if (cache->desktop.load_time == ecore_file_mod_time(cache->desktop.orig_path))
1223 {
1224 INF("Return with stat %f %f for file '%s'", ecore_time_get(), cache->check_time, file);
1225 cache->check_time = ecore_time_get();
1226 eina_lock_release(&_lock);
1227 return &cache->desktop;
1228 }
1229
1230 /* We got stale data. The desktop will be free'd eventually as
1231 * users will call efreet_desktop_free */
1232 eina_hash_set(desktops, file, NON_EXISTING);
1233 cache = NULL;
1234 }
1235
1236 cache = eet_data_read(desktop_cache, efreet_desktop_edd(), file);
1237 if (cache)
1238 {
1239 if (cache->desktop.load_time != ecore_file_mod_time(cache->desktop.orig_path))
1240 {
1241 /* Don't return stale data */
1242 INF("We got stale data in the desktop cache for file '%s'", cache->desktop.orig_path);
1243 efreet_cache_desktop_free(&cache->desktop);
1244 eina_hash_set(desktops, file, NON_EXISTING);
1245 }
1246 else
1247 {
1248 cache->desktop.eet = 1;
1249 cache->check_time = ecore_time_get();
1250 eina_hash_set(desktops, cache->desktop.orig_path, cache);
1251 eina_lock_release(&_lock);
1252 return &cache->desktop;
1253 }
1254 }
1255 else
1256 eina_hash_set(desktops, file, NON_EXISTING);
1257 error:
1258 eina_lock_release(&_lock);
1259 return NULL;
1260 }
1261
1262 void
efreet_cache_desktop_free(Efreet_Desktop * desktop)1263 efreet_cache_desktop_free(Efreet_Desktop *desktop)
1264 {
1265 Efreet_Old_Cache *d;
1266 Efreet_Desktop *curr;
1267 Eina_List *l;
1268
1269 if (!desktop ||
1270 desktop == NON_EXISTING ||
1271 !desktop->eet) return;
1272
1273 eina_lock_take(&_lock);
1274 curr = eina_hash_find(desktops, desktop->orig_path);
1275 if (curr == desktop)
1276 {
1277 INF("Found '%s' in current cache, purge", desktop->orig_path);
1278 eina_hash_del_by_key(desktops, desktop->orig_path);
1279 }
1280
1281 EINA_LIST_FOREACH(old_desktop_caches, l, d)
1282 {
1283 curr = eina_hash_find(d->hash, desktop->orig_path);
1284 if (curr == desktop)
1285 {
1286 INF("Found '%s' in old cache, purge", desktop->orig_path);
1287 eina_hash_del_by_key(d->hash, desktop->orig_path);
1288 if (eina_hash_population(d->hash) == 0)
1289 {
1290 INF("Cache empty, close file");
1291 eina_hash_free(d->hash);
1292 eet_close(d->ef);
1293 free(d);
1294 old_desktop_caches = eina_list_remove_list(old_desktop_caches, l);
1295 }
1296 break;
1297 }
1298 }
1299
1300 /* Desktop Spec 1.0 */
1301 eina_list_free(desktop->only_show_in);
1302 eina_list_free(desktop->not_show_in);
1303 eina_list_free(desktop->categories);
1304 eina_list_free(desktop->mime_types);
1305 IF_FREE_HASH(desktop->x);
1306 /* Desktop Spec 1.1 */
1307 eina_list_free(desktop->actions);
1308 eina_list_free(desktop->implements);
1309 eina_list_free(desktop->keywords);
1310
1311 free(desktop);
1312 eina_lock_release(&_lock);
1313 }
1314
1315 void
efreet_cache_desktop_add(Efreet_Desktop * desktop)1316 efreet_cache_desktop_add(Efreet_Desktop *desktop)
1317 {
1318 char *path;
1319
1320 if ((!efreet_cache_update) || (!ipc)) return;
1321 if (!eina_main_loop_is()) return;
1322 /*
1323 * TODO: Call in thread with:
1324 * ecore_thread_main_loop_begin();
1325 * ecore_thread_main_loop_end();
1326 */
1327 path = ecore_file_dir_get(desktop->orig_path);
1328 if (!path) return;
1329 ecore_ipc_server_send(ipc, 2, 0, 0, 0, 0, path, strlen(path));
1330 free(path);
1331 }
1332
1333 void
efreet_cache_icon_exts_add(Eina_List * exts)1334 efreet_cache_icon_exts_add(Eina_List *exts)
1335 {
1336 Eina_List *l;
1337 const char *s;
1338 Eina_Binbuf *buf;
1339 int num = 0;
1340 unsigned char nil[1] = { 0 };
1341
1342 if ((!efreet_cache_update) || (!ipc)) return;
1343 buf = eina_binbuf_new();
1344 if (!buf) return;
1345 EINA_LIST_FOREACH(exts, l, s)
1346 {
1347 if (num > 0) eina_binbuf_append_length(buf, nil, 1);
1348 eina_binbuf_append_length(buf, (unsigned char *)s, strlen(s));
1349 num++;
1350 }
1351 ecore_ipc_server_send(ipc, 5 /* add icon exts */, 0, 0, 0, 0,
1352 eina_binbuf_string_get(buf),
1353 eina_binbuf_length_get(buf));
1354 eina_binbuf_free(buf);
1355 }
1356
1357 void
efreet_cache_icon_dirs_add(Eina_List * dirs)1358 efreet_cache_icon_dirs_add(Eina_List *dirs)
1359 {
1360 Eina_List *l;
1361 const char *s;
1362 Eina_Binbuf *buf;
1363 int num = 0;
1364 unsigned char nil[1] = { 0 };
1365
1366 if ((!efreet_cache_update) || (!ipc)) return;
1367 buf = eina_binbuf_new();
1368 if (!buf) return;
1369 EINA_LIST_FOREACH(dirs, l, s)
1370 {
1371 if (num > 0) eina_binbuf_append_length(buf, nil, 1);
1372 eina_binbuf_append_length(buf, (unsigned char *)s, strlen(s));
1373 num++;
1374 }
1375 ecore_ipc_server_send(ipc, 4 /* add icon dirs */, 0, 0, 0, 0,
1376 eina_binbuf_string_get(buf),
1377 eina_binbuf_length_get(buf));
1378 eina_binbuf_free(buf);
1379 }
1380
1381 void
efreet_cache_desktop_close(void)1382 efreet_cache_desktop_close(void)
1383 {
1384 IF_RELEASE(util_cache_names_key);
1385 IF_RELEASE(util_cache_hash_key);
1386
1387 eina_lock_take(&_lock);
1388 if ((desktop_cache) && (desktop_cache != NON_EXISTING))
1389 {
1390 Efreet_Old_Cache *d = NEW(Efreet_Old_Cache, 1);
1391 if (d)
1392 {
1393 d->hash = desktops;
1394 d->ef = desktop_cache;
1395 old_desktop_caches = eina_list_append(old_desktop_caches, d);
1396 }
1397
1398 desktops = eina_hash_string_superfast_new(NULL);
1399 }
1400 desktop_cache = NULL;
1401 IF_RELEASE(desktop_cache_file);
1402 eina_lock_release(&_lock);
1403
1404 efreet_cache_array_string_free(util_cache_names);
1405 util_cache_names = NULL;
1406
1407 if (util_cache_hash)
1408 {
1409 eina_hash_free(util_cache_hash->hash);
1410 free(util_cache_hash);
1411 util_cache_hash = NULL;
1412 }
1413
1414 util_cache = efreet_cache_close(util_cache);
1415 IF_RELEASE(util_cache_file);
1416 }
1417
1418 void
efreet_cache_desktop_build(void)1419 efreet_cache_desktop_build(void)
1420 {
1421 const char *s;
1422 int len = 0;
1423 if ((!efreet_cache_update) || (!ipc)) return;
1424 s = efreet_language_get();
1425 if (s) len = strlen(s);
1426 ecore_ipc_server_send(ipc, 3 /* build desktop cache */, 0, 0, 0, 0, s, len);
1427 }
1428
1429 static Eina_Bool
efreet_cache_check(Eet_File ** ef,const char * path,int major)1430 efreet_cache_check(Eet_File **ef, const char *path, int major)
1431 {
1432 Efreet_Cache_Version *version;
1433
1434 if (*ef == NON_EXISTING) return EINA_FALSE;
1435 if (*ef) return EINA_TRUE;
1436 if (!*ef)
1437 *ef = eet_open(path, EET_FILE_MODE_READ);
1438 if (!*ef)
1439 {
1440 *ef = NON_EXISTING;
1441 return EINA_FALSE;
1442 }
1443
1444 version = eet_data_read(*ef, efreet_version_edd(), EFREET_CACHE_VERSION);
1445 if ((!version) || (version->major != major))
1446 {
1447 IF_FREE(version);
1448 eet_close(*ef);
1449 *ef = NON_EXISTING;
1450 return EINA_FALSE;
1451 }
1452 free(version);
1453 return EINA_TRUE;
1454 }
1455
1456 static void *
efreet_cache_close(Eet_File * ef)1457 efreet_cache_close(Eet_File *ef)
1458 {
1459 if (ef && ef != NON_EXISTING)
1460 eet_close(ef);
1461 return NULL;
1462 }
1463
1464 Efreet_Cache_Hash *
efreet_cache_util_hash_string(const char * key)1465 efreet_cache_util_hash_string(const char *key)
1466 {
1467 if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
1468 return util_cache_hash;
1469 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1470
1471 if (util_cache_hash)
1472 {
1473 /* free previous util_cache */
1474 IF_RELEASE(util_cache_hash_key);
1475 eina_hash_free(util_cache_hash->hash);
1476 free(util_cache_hash);
1477 }
1478 util_cache_hash_key = eina_stringshare_add(key);
1479 util_cache_hash = eet_data_read(util_cache, efreet_hash_string_edd(), key);
1480 return util_cache_hash;
1481 }
1482
1483 Efreet_Cache_Hash *
efreet_cache_util_hash_array_string(const char * key)1484 efreet_cache_util_hash_array_string(const char *key)
1485 {
1486 if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
1487 return util_cache_hash;
1488 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1489
1490 IF_RELEASE(util_cache_hash_key);
1491 if (util_cache_hash)
1492 {
1493 /* free previous cache */
1494 eina_hash_free(util_cache_hash->hash);
1495 free(util_cache_hash);
1496 }
1497 util_cache_hash_key = eina_stringshare_add(key);
1498 util_cache_hash = eet_data_read(util_cache, efreet_hash_array_string_edd(), key);
1499 return util_cache_hash;
1500 }
1501
1502 Efreet_Cache_Array_String *
efreet_cache_util_names(const char * key)1503 efreet_cache_util_names(const char *key)
1504 {
1505 if (util_cache_names_key && !strcmp(key, util_cache_names_key))
1506 return util_cache_names;
1507 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1508
1509 if (util_cache_names)
1510 {
1511 /* free previous util_cache */
1512 IF_RELEASE(util_cache_names_key);
1513 efreet_cache_array_string_free(util_cache_names);
1514 }
1515 util_cache_names_key = eina_stringshare_add(key);
1516 util_cache_names = eet_data_read(util_cache, efreet_array_string_edd(), key);
1517 return util_cache_names;
1518 }
1519
1520 static void
icon_cache_update_free(void * data,void * ev)1521 icon_cache_update_free(void *data, void *ev)
1522 {
1523 Efreet_Old_Cache *d;
1524 Eina_List *l;
1525
1526 l = data;
1527 EINA_LIST_FREE(l, d)
1528 {
1529 if (d->hash)
1530 eina_hash_free(d->hash);
1531 efreet_cache_close(d->ef);
1532 free(d);
1533 }
1534 free(ev);
1535 }
1536
1537 static void *
hash_array_string_add(void * hash,const char * key,void * data)1538 hash_array_string_add(void *hash, const char *key, void *data)
1539 {
1540 if (!hash)
1541 hash = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
1542 if (!hash)
1543 return NULL;
1544 eina_hash_add(hash, key, data);
1545 return hash;
1546 }
1547
1548 EAPI void
efreet_cache_disable(void)1549 efreet_cache_disable(void)
1550 {
1551 Eina_Bool prev = disable_cache;
1552
1553 disable_cache = EINA_TRUE;
1554
1555 if (_efreet_cache_log_dom < 0) return; // not yet initialized
1556 if (prev == disable_cache) return; // same value
1557 if (ipc)
1558 {
1559 ecore_ipc_server_del(ipc);
1560 ipc = NULL;
1561 }
1562 }
1563
1564 EAPI void
efreet_cache_enable(void)1565 efreet_cache_enable(void)
1566 {
1567 Eina_Bool prev = disable_cache;
1568
1569 disable_cache = EINA_FALSE;
1570
1571 if (_efreet_cache_log_dom < 0) return; // not yet initialized
1572 if (prev == disable_cache) return; // same value
1573 if (!ipc) _ipc_launch();
1574 }
1575