1 #include "e.h"
2 
3 /* local types */
4 typedef struct _E_Fm2_Mime_Handler_Tuple E_Fm2_Mime_Handler_Tuple;
5 struct _E_Fm2_Mime_Handler_Tuple
6 {
7    Eina_List  *list;
8    const char *str;
9 };
10 
11 /* local subsystem functions */
12 static Eina_Bool _e_fm2_mime_handler_glob_match_foreach(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata);
13 static Eina_Bool _e_fm_mime_icon_foreach(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata);
14 
15 static Eina_Hash *icon_map = NULL;
16 static Eina_Hash *_mime_handlers = NULL;
17 static Eina_Hash *_glob_handlers = NULL;
18 
19 /* externally accessible functions */
20 E_API const char *
e_fm_mime_filename_get(const char * fname)21 e_fm_mime_filename_get(const char *fname)
22 {
23    return efreet_mime_globs_type_get(fname);
24 }
25 
26 /* returns:
27  * NULL == don't know
28  * "THUMB" == generate a thumb
29  * "e/icons/fileman/mime/..." == theme icon
30  * "/path/to/file....edj" = explicit icon edje file
31  * "/path/to/file..." = explicit image file to use
32  */
33 E_API const char *
e_fm_mime_icon_get(const char * mime)34 e_fm_mime_icon_get(const char *mime)
35 {
36    char buf[4096], buf2[4096], *val;
37    Eina_List *l = NULL;
38    E_Config_Mime_Icon *mi;
39    size_t len;
40 
41    /* 0.0 clean out hash cache once it has more than 512 entries in it */
42    if (eina_hash_population(icon_map) > 512) e_fm_mime_icon_cache_flush();
43 
44    /* 0. look in mapping cache */
45    val = eina_hash_find(icon_map, mime);
46    if (val) return val;
47 
48    eina_strlcpy(buf2, mime, sizeof(buf2));
49    val = strchr(buf2, '/');
50    if (val) *val = 0;
51 
52    /* 1. look up in mapping to file or thumb (thumb has flag)*/
53    EINA_LIST_FOREACH(e_config->mime_icons, l, mi)
54      {
55         if (e_util_glob_match(mi->mime, mime))
56           {
57              eina_strlcpy(buf, mi->icon, sizeof(buf));
58              goto ok;
59           }
60      }
61 
62    /* 2. look up in ~/.e/e/icons */
63    len = e_user_dir_snprintf(buf, sizeof(buf), "icons/%s.edj", mime);
64    if (len >= sizeof(buf))
65      goto try_e_icon_generic;
66 
67    if (ecore_file_exists(buf)) goto ok;
68    memcpy(buf + len - (sizeof("edj") - 1), "svg", sizeof("svg"));
69    if (ecore_file_exists(buf)) goto ok;
70    memcpy(buf + len - (sizeof("edj") - 1), "png", sizeof("png"));
71    if (ecore_file_exists(buf)) goto ok;
72 
73 try_e_icon_generic:
74    len = e_user_dir_snprintf(buf, sizeof(buf), "icons/%s.edj", buf2);
75    if (len >= sizeof(buf))
76      goto try_theme;
77 
78    if (ecore_file_exists(buf)) goto ok;
79    memcpy(buf + len - (sizeof("edj") - 1), "svg", sizeof("svg"));
80    if (ecore_file_exists(buf)) goto ok;
81    memcpy(buf + len - (sizeof("edj") - 1), "png", sizeof("png"));
82    if (ecore_file_exists(buf)) goto ok;
83 
84    /* 3. look up icon in theme */
85 try_theme:
86    memcpy(buf, "e/icons/fileman/mime/", sizeof("e/icons/fileman/mime/"));
87    eina_strlcpy(buf + sizeof("e/icons/fileman/mime/") - 1, mime,
88                 sizeof(buf) - (sizeof("e/icons/fileman/mime/") - 1));
89    val = (char *)e_theme_edje_file_get("base/theme/fileman", buf);
90    if ((val) && (e_util_edje_collection_exists(val, buf))) goto ok;
91 
92    eina_strlcpy(buf + sizeof("e/icons/fileman/mime/") - 1, buf2,
93                 sizeof(buf) - (sizeof("e/icons/fileman/mime/") - 1));
94    val = (char *)e_theme_edje_file_get("base/theme/fileman", buf);
95    if ((val) && (e_util_edje_collection_exists(val, buf))) goto ok;
96 
97    /* 4. look up icon in PREFIX/share/enlightent/data/icons */
98    len = e_prefix_data_snprintf(buf, sizeof(buf), "data/icons/%s.edj", mime);
99    if (len >= sizeof(buf))
100      goto try_efreet_icon_generic;
101 
102    if (ecore_file_exists(buf)) goto ok;
103    memcpy(buf + len - (sizeof("edj") - 1), "svg", sizeof("svg"));
104    if (ecore_file_exists(buf)) goto ok;
105    memcpy(buf + len - (sizeof("edj") - 1), "png", sizeof("png"));
106    if (ecore_file_exists(buf)) goto ok;
107 
108 try_efreet_icon_generic:
109    len = e_prefix_data_snprintf(buf, sizeof(buf), "data/icons/%s.edj", buf2);
110    if (len >= sizeof(buf))
111      goto try_efreet_icon_generic;
112 
113    if (ecore_file_exists(buf)) goto ok;
114    memcpy(buf + len - (sizeof("edj") - 1), "svg", sizeof("svg"));
115    if (ecore_file_exists(buf)) goto ok;
116    memcpy(buf + len - (sizeof("edj") - 1), "png", sizeof("png"));
117    if (ecore_file_exists(buf)) goto ok;
118 
119    return NULL;
120 
121 ok:
122    val = (char *)eina_stringshare_add(buf);
123    if (!icon_map) icon_map = eina_hash_string_superfast_new(NULL);
124    eina_hash_add(icon_map, mime, val);
125    return val;
126 }
127 
128 E_API void
e_fm_mime_icon_cache_flush(void)129 e_fm_mime_icon_cache_flush(void)
130 {
131    Eina_List *freelist = NULL;
132 
133    eina_hash_foreach(icon_map, _e_fm_mime_icon_foreach, &freelist);
134    E_FREE_LIST(freelist, eina_stringshare_del);
135    eina_hash_free(icon_map);
136    icon_map = NULL;
137 }
138 
139 /* create (allocate), set properties, and return a new mime handler */
140 E_API E_Fm2_Mime_Handler *
e_fm2_mime_handler_new(const char * label,const char * icon_group,void (* action_func)(void * data,Evas_Object * obj,const char * path),void * action_data,int (test_func)(void * data,Evas_Object * obj,const char * path),void * test_data)141 e_fm2_mime_handler_new(const char *label, const char *icon_group, void (*action_func)(void *data, Evas_Object *obj, const char *path), void *action_data, int(test_func) (void *data, Evas_Object * obj, const char *path), void *test_data)
142 {
143    E_Fm2_Mime_Handler *handler;
144 
145    if ((!label) || (!action_func)) return NULL;
146 
147    handler = E_NEW(E_Fm2_Mime_Handler, 1);
148    if (!handler) return NULL;
149 
150    handler->label = eina_stringshare_add(label);
151    handler->icon_group = icon_group ? eina_stringshare_add(icon_group) : NULL;
152    handler->action_func = action_func;
153    handler->action_data = action_data;
154    handler->test_func = test_func;
155    handler->test_data = test_data;
156 
157    return handler;
158 }
159 
160 E_API void
e_fm2_mime_handler_free(E_Fm2_Mime_Handler * handler)161 e_fm2_mime_handler_free(E_Fm2_Mime_Handler *handler)
162 {
163    if (!handler) return;
164 
165    eina_stringshare_del(handler->label);
166    if (handler->icon_group) eina_stringshare_del(handler->icon_group);
167    E_FREE(handler);
168 }
169 
170 /* associate a certain mime type with a handler */
171 E_API Eina_Bool
e_fm2_mime_handler_mime_add(E_Fm2_Mime_Handler * handler,const char * mime)172 e_fm2_mime_handler_mime_add(E_Fm2_Mime_Handler *handler, const char *mime)
173 {
174    Eina_List *handlers = NULL;
175 
176    if ((!handler) || (!mime)) return 0;
177 
178    /* if there's an entry for this mime already, then append to its list */
179    if ((handlers = eina_hash_find(_mime_handlers, mime)))
180      {
181         handlers = eina_list_append(handlers, handler);
182         eina_hash_modify(_mime_handlers, mime, handlers);
183      }
184    else
185      {
186         /* no previous entry for this mime, lets add one */
187         handlers = eina_list_append(handlers, handler);
188         if (!_mime_handlers) _mime_handlers = eina_hash_string_superfast_new(NULL);
189         eina_hash_add(_mime_handlers, mime, handlers);
190      }
191 
192    return 1;
193 }
194 
195 /* associate a certain glob with a handler */
196 E_API Eina_Bool
e_fm2_mime_handler_glob_add(E_Fm2_Mime_Handler * handler,const char * glob_)197 e_fm2_mime_handler_glob_add(E_Fm2_Mime_Handler *handler, const char *glob_)
198 {
199    Eina_List *handlers = NULL;
200 
201    if ((!handler) || (!glob_)) return 0;
202 
203    /* if there's an entry for this glob already, then append to its list */
204    if ((handlers = eina_hash_find(_glob_handlers, glob_)))
205      {
206         handlers = eina_list_append(handlers, handler);
207         eina_hash_modify(_glob_handlers, glob_, handlers);
208      }
209    else
210      {
211         /* no previous entry for this glob, lets add one */
212         handlers = eina_list_append(handlers, handler);
213         if (!_glob_handlers) _glob_handlers = eina_hash_string_superfast_new(NULL);
214         eina_hash_add(_glob_handlers, glob_, handlers);
215      }
216 
217    return 1;
218 }
219 
220 /* delete a certain handler for a certain mime */
221 E_API void
e_fm2_mime_handler_mime_del(E_Fm2_Mime_Handler * handler,const char * mime)222 e_fm2_mime_handler_mime_del(E_Fm2_Mime_Handler *handler, const char *mime)
223 {
224    Eina_List *handlers = NULL;
225 
226    if ((!handler) || (!mime)) return;
227 
228    /* if there's an entry for this mime already, then remove from list */
229    if ((handlers = eina_hash_find(_mime_handlers, mime)))
230      {
231         handlers = eina_list_remove(handlers, handler);
232         if (handlers)
233           eina_hash_modify(_mime_handlers, mime, handlers);
234         else
235           {
236              eina_hash_del(_mime_handlers, mime, handlers);
237              if (!eina_hash_population(_mime_handlers))
238                {
239                   eina_hash_free(_mime_handlers);
240                   _mime_handlers = NULL;
241                }
242           }
243      }
244 }
245 
246 /* delete a certain handler for a certain glob */
247 E_API void
e_fm2_mime_handler_glob_del(E_Fm2_Mime_Handler * handler,const char * glob_)248 e_fm2_mime_handler_glob_del(E_Fm2_Mime_Handler *handler, const char *glob_)
249 {
250    Eina_List *handlers = NULL;
251 
252    if ((!handler) || (!glob_)) return;
253 
254    /* if there's an entry for this glob already, then remove from list */
255    if ((handlers = eina_hash_find(_glob_handlers, glob_)))
256      {
257         handlers = eina_list_remove(handlers, handler);
258         if (handlers)
259           eina_hash_modify(_glob_handlers, glob_, handlers);
260         else
261           {
262              eina_hash_del(_glob_handlers, glob_, handlers);
263              if (!eina_hash_population(_glob_handlers))
264                {
265                   eina_hash_free(_glob_handlers);
266                   _glob_handlers = NULL;
267                }
268           }
269      }
270 }
271 
272 E_API const Eina_List *
e_fm2_mime_handler_mime_handlers_get(const char * mime)273 e_fm2_mime_handler_mime_handlers_get(const char *mime)
274 {
275    if ((!mime) || (!_mime_handlers)) return NULL;
276    return eina_hash_find(_mime_handlers, mime);
277 }
278 
279 /* get the list of glob handlers for a glob.
280    NOTE: the list should be free()'ed */
281 E_API Eina_List *
e_fm2_mime_handler_glob_handlers_get(const char * glob_)282 e_fm2_mime_handler_glob_handlers_get(const char *glob_)
283 {
284    E_Fm2_Mime_Handler_Tuple *tuple = NULL;
285    Eina_List *handlers = NULL;
286 
287    if ((!glob_) || (!_glob_handlers)) return NULL;
288 
289    tuple = E_NEW(E_Fm2_Mime_Handler_Tuple, 1);
290    tuple->list = NULL;
291    tuple->str = glob_;
292    eina_hash_foreach(_glob_handlers, _e_fm2_mime_handler_glob_match_foreach, tuple);
293    handlers = tuple->list;
294    E_FREE(tuple);
295    return handlers;
296 }
297 
298 /* call a certain handler */
299 E_API Eina_Bool
e_fm2_mime_handler_call(E_Fm2_Mime_Handler * handler,Evas_Object * obj,const char * path)300 e_fm2_mime_handler_call(E_Fm2_Mime_Handler *handler, Evas_Object *obj, const char *path)
301 {
302    if ((!handler) || (!obj) || (!path) || (!handler->action_func))
303      return 0;
304 
305    if (handler->test_func)
306      {
307         if (handler->test_func(handler->test_data, obj, path))
308           {
309              handler->action_func(handler->action_data, obj, path);
310              return 1;
311           }
312         else
313           return 0;
314      }
315 
316    handler->action_func(handler->action_data, obj, path);
317    return 1;
318 }
319 
320 /* call all handlers related to a certain mime */
321 E_API void
e_fm2_mime_handler_mime_handlers_call_all(Evas_Object * obj,const char * path,const char * mime)322 e_fm2_mime_handler_mime_handlers_call_all(Evas_Object *obj, const char *path, const char *mime)
323 {
324    const Eina_List *l, *handlers;
325    E_Fm2_Mime_Handler *handler = NULL;
326 
327    if ((!obj) || (!path) || (!mime)) return;
328 
329    handlers = e_fm2_mime_handler_mime_handlers_get(mime);
330    if (!handlers) return;
331 
332    EINA_LIST_FOREACH(handlers, l, handler)
333      {
334         if (!handler) continue;
335 
336         e_fm2_mime_handler_call(handler, obj, path);
337      }
338 }
339 
340 /* call all handlers related to a certain glob */
341 E_API void
e_fm2_mime_handler_glob_handlers_call_all(Evas_Object * obj,const char * path,const char * glob_)342 e_fm2_mime_handler_glob_handlers_call_all(Evas_Object *obj, const char *path, const char *glob_)
343 {
344    Eina_List *handlers = NULL;
345    Eina_List *l = NULL;
346    E_Fm2_Mime_Handler *handler = NULL;
347 
348    if ((!obj) || (!path) || (!glob_)) return;
349 
350    handlers = e_fm2_mime_handler_glob_handlers_get(glob_);
351    if (!handlers) return;
352 
353    EINA_LIST_FOREACH(handlers, l, handler)
354      {
355         if (!handler) continue;
356 
357         e_fm2_mime_handler_call(handler, obj, path);
358      }
359 }
360 
361 /* run a handlers test function */
362 E_API Eina_Bool
e_fm2_mime_handler_test(E_Fm2_Mime_Handler * handler,Evas_Object * obj,const char * path)363 e_fm2_mime_handler_test(E_Fm2_Mime_Handler *handler, Evas_Object *obj, const char *path)
364 {
365    if ((!handler) || (!obj) || (!path)) return 0;
366    if (!handler->test_func) return 1;
367 
368    return handler->test_func(handler->test_data, obj, path);
369 }
370 
371 /* local subsystem functions */
372 /* used to loop a glob hash and determine if the glob handler matches the filename */
373 static Eina_Bool
_e_fm2_mime_handler_glob_match_foreach(const Eina_Hash * hash EINA_UNUSED,const void * key,void * data,void * fdata)374 _e_fm2_mime_handler_glob_match_foreach(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata)
375 {
376    E_Fm2_Mime_Handler_Tuple *tuple;
377    Eina_List *handlers = NULL;
378    Eina_List *l = NULL;
379    void *handler = NULL;
380 
381    tuple = fdata;
382    if (e_util_glob_match(tuple->str, key))
383      {
384         handlers = data;
385         EINA_LIST_FOREACH(handlers, l, handler)
386           {
387              if (handler)
388                tuple->list = eina_list_append(tuple->list, handler);
389           }
390      }
391 
392    return 1;
393 }
394 
395 static Eina_Bool
_e_fm_mime_icon_foreach(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata)396 _e_fm_mime_icon_foreach(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
397 {
398    Eina_List **freelist;
399 
400    freelist = fdata;
401    *freelist = eina_list_append(*freelist, data);
402    return 1;
403 }
404 
405