Add a task to copy configuration files to user's HOME dir from data dir for multi...
[platform/core/uifw/e17.git] / src / bin / e_fm_mime.c
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 __UNUSED__, const void *key, void *data, void *fdata);
13 static Eina_Bool _e_fm_mime_icon_foreach(const Eina_Hash *hash __UNUSED__, const void *key __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 EAPI const char *
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 EAPI const char *
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/") - 1);
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 EAPI 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 EAPI 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 {
142    E_Fm2_Mime_Handler *handler;
143
144    if ((!label) || (!action_func)) return NULL;
145
146    handler = E_NEW(E_Fm2_Mime_Handler, 1);
147    if (!handler) return NULL;
148
149    handler->label = eina_stringshare_add(label);
150    handler->icon_group = icon_group ? eina_stringshare_add(icon_group) : NULL;
151    handler->action_func = action_func;
152    handler->action_data = action_data;
153    handler->test_func = test_func;
154    handler->test_data = test_data;
155
156    return handler;
157 }
158
159 EAPI void
160 e_fm2_mime_handler_free(E_Fm2_Mime_Handler *handler)
161 {
162    if (!handler) return;
163
164    eina_stringshare_del(handler->label);
165    if (handler->icon_group) eina_stringshare_del(handler->icon_group);
166    E_FREE(handler);
167 }
168
169 /* associate a certain mime type with a handler */
170 EAPI Eina_Bool
171 e_fm2_mime_handler_mime_add(E_Fm2_Mime_Handler *handler, const char *mime)
172 {
173    Eina_List *handlers = NULL;
174
175    if ((!handler) || (!mime)) return 0;
176
177    /* if there's an entry for this mime already, then append to its list */
178    if ((handlers = eina_hash_find(_mime_handlers, mime)))
179      {
180         handlers = eina_list_append(handlers, handler);
181         eina_hash_modify(_mime_handlers, mime, handlers);
182      }
183    else
184      {
185         /* no previous entry for this mime, lets add one */
186         handlers = eina_list_append(handlers, handler);
187         if (!_mime_handlers) _mime_handlers = eina_hash_string_superfast_new(NULL);
188         eina_hash_add(_mime_handlers, mime, handlers);
189      }
190
191    return 1;
192 }
193
194 /* associate a certain glob with a handler */
195 EAPI Eina_Bool
196 e_fm2_mime_handler_glob_add(E_Fm2_Mime_Handler *handler, const char *glob_)
197 {
198    Eina_List *handlers = NULL;
199
200    if ((!handler) || (!glob_)) return 0;
201
202    /* if there's an entry for this glob already, then append to its list */
203    if ((handlers = eina_hash_find(_glob_handlers, glob_)))
204      {
205         handlers = eina_list_append(handlers, handler);
206         eina_hash_modify(_glob_handlers, glob_, handlers);
207      }
208    else
209      {
210         /* no previous entry for this glob, lets add one */
211         handlers = eina_list_append(handlers, handler);
212         if (!_glob_handlers) _glob_handlers = eina_hash_string_superfast_new(NULL);
213         eina_hash_add(_glob_handlers, glob_, handlers);
214      }
215
216    return 1;
217 }
218
219 /* delete a certain handler for a certain mime */
220 EAPI void
221 e_fm2_mime_handler_mime_del(E_Fm2_Mime_Handler *handler, const char *mime)
222 {
223    Eina_List *handlers = NULL;
224
225    if ((!handler) || (!mime)) return;
226
227    /* if there's an entry for this mime already, then remove from list */
228    if ((handlers = eina_hash_find(_mime_handlers, mime)))
229      {
230         handlers = eina_list_remove(handlers, handler);
231         if (handlers)
232           eina_hash_modify(_mime_handlers, mime, handlers);
233         else
234           {
235              eina_hash_del(_mime_handlers, mime, handlers);
236              if (!eina_hash_population(_mime_handlers))
237                {
238                   eina_hash_free(_mime_handlers);
239                   _mime_handlers = NULL;
240                }
241           }
242      }
243 }
244
245 /* delete a certain handler for a certain glob */
246 EAPI void
247 e_fm2_mime_handler_glob_del(E_Fm2_Mime_Handler *handler, const char *glob_)
248 {
249    Eina_List *handlers = NULL;
250
251    if ((!handler) || (!glob_)) return;
252
253    /* if there's an entry for this glob already, then remove from list */
254    if ((handlers = eina_hash_find(_glob_handlers, glob_)))
255      {
256         handlers = eina_list_remove(handlers, handler);
257         if (handlers)
258           eina_hash_modify(_glob_handlers, glob_, handlers);
259         else
260           {
261              eina_hash_del(_glob_handlers, glob_, handlers);
262              if (!eina_hash_population(_glob_handlers))
263                {
264                   eina_hash_free(_glob_handlers);
265                   _glob_handlers = NULL;
266                }
267           }
268      }
269 }
270
271 EAPI const Eina_List *
272 e_fm2_mime_handler_mime_handlers_get(const char *mime)
273 {
274    if ((!mime) || (!_mime_handlers)) return NULL;
275    return eina_hash_find(_mime_handlers, mime);
276 }
277
278 /* get the list of glob handlers for a glob.
279    NOTE: the list should be free()'ed */
280 EAPI Eina_List *
281 e_fm2_mime_handler_glob_handlers_get(const char *glob_)
282 {
283    E_Fm2_Mime_Handler_Tuple *tuple = NULL;
284    Eina_List *handlers = NULL;
285
286    if ((!glob_) || (!_glob_handlers)) return NULL;
287
288    tuple = E_NEW(E_Fm2_Mime_Handler_Tuple, 1);
289    tuple->list = NULL;
290    tuple->str = glob_;
291    eina_hash_foreach(_glob_handlers, _e_fm2_mime_handler_glob_match_foreach, tuple);
292    handlers = tuple->list;
293    E_FREE(tuple);
294    return handlers;
295 }
296
297 /* call a certain handler */
298 EAPI Eina_Bool
299 e_fm2_mime_handler_call(E_Fm2_Mime_Handler *handler, Evas_Object *obj, const char *path)
300 {
301    if ((!handler) || (!obj) || (!path) || (!handler->action_func))
302      return 0;
303
304    if (handler->test_func)
305      {
306         if (handler->test_func(handler->test_data, obj, path))
307           {
308              handler->action_func(handler->action_data, obj, path);
309              return 1;
310           }
311         else
312           return 0;
313      }
314
315    handler->action_func(handler->action_data, obj, path);
316    return 1;
317 }
318
319 /* call all handlers related to a certain mime */
320 EAPI void
321 e_fm2_mime_handler_mime_handlers_call_all(Evas_Object *obj, const char *path, const char *mime)
322 {
323    const Eina_List *l, *handlers;
324    E_Fm2_Mime_Handler *handler = NULL;
325
326    if ((!obj) || (!path) || (!mime)) return;
327
328    handlers = e_fm2_mime_handler_mime_handlers_get(mime);
329    if (!handlers) return;
330
331    EINA_LIST_FOREACH(handlers, l, handler)
332      {
333         if (!handler) continue;
334
335         e_fm2_mime_handler_call(handler, obj, path);
336      }
337 }
338
339 /* call all handlers related to a certain glob */
340 EAPI void
341 e_fm2_mime_handler_glob_handlers_call_all(Evas_Object *obj, const char *path, const char *glob_)
342 {
343    Eina_List *handlers = NULL;
344    Eina_List *l = NULL;
345    E_Fm2_Mime_Handler *handler = NULL;
346
347    if ((!obj) || (!path) || (!glob_)) return;
348
349    handlers = e_fm2_mime_handler_glob_handlers_get(glob_);
350    if (!handlers) return;
351
352    EINA_LIST_FOREACH(handlers, l, handler)
353      {
354         if (!handler) continue;
355
356         e_fm2_mime_handler_call(handler, obj, path);
357      }
358 }
359
360 /* run a handlers test function */
361 EAPI Eina_Bool
362 e_fm2_mime_handler_test(E_Fm2_Mime_Handler *handler, Evas_Object *obj, const char *path)
363 {
364    if ((!handler) || (!obj) || (!path)) return 0;
365    if (!handler->test_func) return 1;
366
367    return handler->test_func(handler->test_data, obj, path);
368 }
369
370 /* local subsystem functions */
371 /* used to loop a glob hash and determine if the glob handler matches the filename */
372 static Eina_Bool
373 _e_fm2_mime_handler_glob_match_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata)
374 {
375    E_Fm2_Mime_Handler_Tuple *tuple;
376    Eina_List *handlers = NULL;
377    Eina_List *l = NULL;
378    void *handler = NULL;
379
380    tuple = fdata;
381    if (e_util_glob_match(tuple->str, key))
382      {
383         handlers = data;
384         EINA_LIST_FOREACH(handlers, l, handler)
385           {
386              if (handler)
387                tuple->list = eina_list_append(tuple->list, handler);
388           }
389      }
390
391    return 1;
392 }
393
394 static Eina_Bool
395 _e_fm_mime_icon_foreach(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
396 {
397    Eina_List **freelist;
398
399    freelist = fdata;
400    *freelist = eina_list_append(*freelist, data);
401    return 1;
402 }
403