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_exehist.c
1 #include "e.h"
2 #include <libgen.h>
3
4 EAPI int E_EVENT_EXEHIST_UPDATE = 0;
5
6 /* local subsystem functions */
7 typedef struct _E_Exehist E_Exehist;
8 typedef struct _E_Exehist_Item E_Exehist_Item;
9
10 struct _E_Exehist
11 {
12    Eina_List *history;
13    Eina_List *mimes;
14 };
15
16 struct _E_Exehist_Item
17 {
18    const char   *exe;
19    const char   *normalized_exe;
20    const char   *launch_method;
21    double        exetime;
22    unsigned int  count;
23 };
24
25 static void _e_exehist_unload_queue(void);
26 static void _e_exehist_load(void);
27 static void _e_exehist_clear(void);
28 static void _e_exehist_unload(void);
29 static void _e_exehist_limit(void);
30 static const char *_e_exehist_normalize_exe(const char *exe);
31 static void _e_exehist_cb_unload(void *data);
32 static int  _e_exehist_sort_exe_cb(const void *d1, const void *d2);
33 static int  _e_exehist_sort_pop_cb(const void *d1, const void *d2);
34
35 /* local subsystem globals */
36 static E_Config_DD *_e_exehist_config_edd = NULL;
37 static E_Config_DD *_e_exehist_config_item_edd = NULL;
38 static E_Exehist *_e_exehist = NULL;
39 static E_Powersave_Deferred_Action *_e_exehist_unload_defer = NULL;
40 static int _e_exehist_changes = 0;
41
42 /* externally accessible functions */
43 EINTERN int
44 e_exehist_init(void)
45 {
46    _e_exehist_config_item_edd = E_CONFIG_DD_NEW("E_Exehist_Item", E_Exehist_Item);
47 #undef T
48 #undef D
49 #define T E_Exehist_Item
50 #define D _e_exehist_config_item_edd
51    E_CONFIG_VAL(D, T, exe, STR);
52    E_CONFIG_VAL(D, T, normalized_exe, STR);
53    E_CONFIG_VAL(D, T, launch_method, STR);
54    E_CONFIG_VAL(D, T, exetime, DOUBLE);
55
56    _e_exehist_config_edd = E_CONFIG_DD_NEW("E_Exehist", E_Exehist);
57 #undef T
58 #undef D
59 #define T E_Exehist
60 #define D _e_exehist_config_edd
61    E_CONFIG_LIST(D, T, history, _e_exehist_config_item_edd);
62    E_CONFIG_LIST(D, T, mimes, _e_exehist_config_item_edd);
63
64    E_EVENT_EXEHIST_UPDATE = ecore_event_type_new();
65
66    return 1;
67 }
68
69 EINTERN int
70 e_exehist_shutdown(void)
71 {
72    if (_e_exehist_unload_defer)
73      {
74         e_powersave_deferred_action_del(_e_exehist_unload_defer);
75         _e_exehist_unload_defer = NULL;
76      }
77    _e_exehist_cb_unload(NULL);
78    E_CONFIG_DD_FREE(_e_exehist_config_item_edd);
79    E_CONFIG_DD_FREE(_e_exehist_config_edd);
80    return 1;
81 }
82
83 EAPI void
84 e_exehist_add(const char *launch_method, const char *exe)
85 {
86    E_Exehist_Item *ei;
87
88    _e_exehist_load();
89    if (!_e_exehist) return;
90    ei = E_NEW(E_Exehist_Item, 1);
91    if (!ei)
92      {
93         _e_exehist_unload_queue();
94         return;
95      }
96    ei->launch_method = eina_stringshare_add(launch_method);
97    ei->exe = eina_stringshare_add(exe);
98    ei->normalized_exe = _e_exehist_normalize_exe(exe);
99    ei->exetime = ecore_time_unix_get();
100    _e_exehist->history = eina_list_append(_e_exehist->history, ei);
101    _e_exehist_limit();
102    _e_exehist_changes++;
103    ecore_event_add(E_EVENT_EXEHIST_UPDATE, NULL, NULL, NULL);
104    _e_exehist_unload_queue();
105 }
106
107 EAPI void
108 e_exehist_del(const char *exe)
109 {
110    E_Exehist_Item *ei;
111    Eina_List *l;
112    Eina_Bool ok = EINA_FALSE;
113
114    _e_exehist_load();
115    if (!_e_exehist) return;
116    EINA_LIST_FOREACH(_e_exehist->history, l, ei)
117      {
118         if ((ei->exe) && (!strcmp(exe, ei->exe)))
119           {
120              eina_stringshare_del(ei->exe);
121              eina_stringshare_del(ei->normalized_exe);
122              eina_stringshare_del(ei->launch_method);
123              free(ei);
124              _e_exehist->history = eina_list_remove_list(_e_exehist->history,
125                                                          l);
126              _e_exehist_changes++;
127              _e_exehist_unload_queue();
128              ok = EINA_TRUE;
129           }
130      }
131    if (ok)
132      ecore_event_add(E_EVENT_EXEHIST_UPDATE, NULL, NULL, NULL);
133 }
134
135 EAPI void
136 e_exehist_clear(void)
137 {
138    _e_exehist_load();
139    if (!_e_exehist) return;
140    _e_exehist_clear();
141    _e_exehist_changes++;
142    ecore_event_add(E_EVENT_EXEHIST_UPDATE, NULL, NULL, NULL);
143    _e_exehist_unload_queue();
144 }
145
146 EAPI int
147 e_exehist_popularity_get(const char *exe)
148 {
149    Eina_List *l;
150    E_Exehist_Item *ei;
151    const char *normal;
152    int count = 0;
153
154    _e_exehist_load();
155    if (!_e_exehist) return 0;
156    normal = _e_exehist_normalize_exe(exe);
157    if (!normal) return 0;
158    EINA_LIST_FOREACH(_e_exehist->history, l, ei)
159      {
160         if ((ei->normalized_exe) && (!strcmp(normal, ei->normalized_exe)))
161           count++;
162      }
163    eina_stringshare_del(normal);
164    _e_exehist_unload_queue();
165    return count;
166 }
167
168 EAPI double
169 e_exehist_newest_run_get(const char *exe)
170 {
171    Eina_List *l;
172    E_Exehist_Item *ei;
173    const char *normal;
174
175    _e_exehist_load();
176    if (!_e_exehist) return 0.0;
177    normal = _e_exehist_normalize_exe(exe);
178    if (!normal) return 0.0;
179    EINA_LIST_REVERSE_FOREACH(_e_exehist->history, l, ei)
180      {
181         if ((ei->normalized_exe) && (!strcmp(normal, ei->normalized_exe)))
182           {
183              eina_stringshare_del(normal);
184              _e_exehist_unload_queue();
185              return ei->exetime;
186           }
187      }
188    eina_stringshare_del(normal);
189    _e_exehist_unload_queue();
190    return 0.0;
191 }
192
193 EAPI Eina_List *
194 e_exehist_list_get(void)
195 {
196    return e_exehist_sorted_list_get(E_EXEHIST_SORT_BY_DATE, 0);
197 }
198
199 EAPI Eina_List *
200 e_exehist_sorted_list_get(E_Exehist_Sort sort_type, int max)
201 {
202    Eina_List *list = NULL, *pop = NULL, *l = NULL, *m;
203    Eina_Iterator *iter;
204    E_Exehist_Item *ei;
205    int count = 1;
206    E_Exehist_Item *prev = NULL;
207
208    if (!max) max = 20;
209    _e_exehist_load();
210    switch(sort_type)
211      {
212       case E_EXEHIST_SORT_BY_EXE:
213       case E_EXEHIST_SORT_BY_POPULARITY:
214          l = eina_list_clone(_e_exehist->history);
215          l = eina_list_sort(l, 0, _e_exehist_sort_exe_cb);
216          iter = eina_list_iterator_new(l);
217          break;
218       default:
219          iter = eina_list_iterator_reversed_new(_e_exehist->history);
220          break;
221      }
222    EINA_ITERATOR_FOREACH(iter, ei)
223      {
224         int bad = 0;
225
226         if (!(ei->normalized_exe)) continue;
227         if (sort_type == E_EXEHIST_SORT_BY_POPULARITY)
228           {
229              if (!prev || (strcmp(prev->normalized_exe, ei->normalized_exe)))
230                {
231                   prev = ei;
232                   pop = eina_list_append(pop, ei);
233                }
234              prev->count++;
235           }
236         else
237           {
238              const char *exe;
239
240              EINA_LIST_FOREACH(list, m, exe)
241                {
242                   if (!exe) continue;
243                   if (!strcmp(exe, ei->exe))
244                     {
245                        bad = 1;
246                        break;
247                     }
248                }
249              if (!(bad))
250                {
251                   list = eina_list_append(list, ei->exe);
252                   count++;
253                }
254           }
255         if (count > max) break;
256      }
257    if (sort_type == E_EXEHIST_SORT_BY_POPULARITY)
258      {
259         count = 1;
260         pop = eina_list_sort(pop, 0, _e_exehist_sort_pop_cb);
261         EINA_LIST_FOREACH(pop, l, prev)
262           {
263              list = eina_list_append(list, prev->exe);
264              count++;
265              if (count > max) break;
266           }
267         eina_list_free(pop);
268      }
269    eina_list_free(l);
270    eina_iterator_free(iter);
271    _e_exehist_unload_queue();
272    return list;
273 }
274
275 EAPI void
276 e_exehist_mime_desktop_add(const char *mime, Efreet_Desktop *desktop)
277 {
278    const char *f;
279    E_Exehist_Item *ei;
280    Eina_List *l;
281    char buf[PATH_MAX];
282    Efreet_Ini *ini;
283
284    if ((!mime) || (!desktop)) return;
285    if (!desktop->orig_path) return;
286    _e_exehist_load();
287    if (!_e_exehist) return;
288
289    f = efreet_util_path_to_file_id(desktop->orig_path);
290    if (!f) return;
291    
292    snprintf(buf, sizeof(buf), "%s/applications/defaults.list",
293             efreet_data_home_get());
294    ini = efreet_ini_new(buf);
295    fprintf(stderr, "try open %s = %p\n", buf, ini);
296    if (ini)
297      {
298         fprintf(stderr, "SAVE mime %s with %s\n", mime, desktop->orig_path);
299         if (!efreet_ini_section_set(ini, "Default Applications"))
300           {
301              efreet_ini_section_add(ini, "Default Applications");
302              efreet_ini_section_set(ini, "Default Applications");
303           }
304         if (desktop->orig_path)
305           efreet_ini_string_set(ini, mime, ecore_file_file_get(desktop->orig_path));
306         efreet_ini_save(ini, buf);
307         efreet_ini_free(ini);
308      }
309    
310    EINA_LIST_FOREACH(_e_exehist->mimes, l, ei)
311      {
312         if ((ei->launch_method) && (!strcmp(mime, ei->launch_method)))
313           {
314              if ((ei->exe) && (!strcmp(f, ei->exe)))
315                {
316                   _e_exehist_unload_queue();
317                   return;
318                }
319              if (ei->exe) eina_stringshare_del(ei->exe);
320              if (ei->launch_method) eina_stringshare_del(ei->launch_method);
321              free(ei);
322              _e_exehist->mimes = eina_list_remove_list(_e_exehist->mimes, l);
323              _e_exehist_changes++;
324              break;
325           }
326      }
327    ei = E_NEW(E_Exehist_Item, 1);
328    if (!ei)
329      {
330         _e_exehist_unload_queue();
331         return;
332      }
333    ei->launch_method = eina_stringshare_add(mime);
334    ei->exe = eina_stringshare_add(f);
335    ei->exetime = ecore_time_unix_get();
336    _e_exehist->mimes = eina_list_append(_e_exehist->mimes, ei);
337    _e_exehist_limit();
338    _e_exehist_changes++;
339    _e_exehist_unload_queue();
340 }
341
342 EAPI Efreet_Desktop *
343 e_exehist_mime_desktop_get(const char *mime)
344 {
345    Efreet_Desktop *desktop;
346    E_Exehist_Item *ei;
347    Eina_List *l;
348
349    fprintf(stderr, "e_exehist_mime_desktop_get(%s)\n", mime);
350    if (!mime) return NULL;
351    _e_exehist_load();
352    fprintf(stderr, "x\n");
353    if (!_e_exehist) return NULL;
354    EINA_LIST_FOREACH(_e_exehist->mimes, l, ei)
355      {
356         fprintf(stderr, "look for %s == %s\n", mime, ei->launch_method);
357         if ((ei->launch_method) && (!strcmp(mime, ei->launch_method)))
358           {
359              desktop = NULL;
360              if (ei->exe) desktop = efreet_util_desktop_file_id_find(ei->exe);
361              fprintf(stderr, "  desk = %p\n", desktop);
362              if (desktop)
363                {
364                   _e_exehist_unload_queue();
365                   return desktop;
366                }
367           }
368      }
369    _e_exehist_unload_queue();
370    return NULL;
371 }
372
373 /* local subsystem functions */
374 static void
375 _e_exehist_unload_queue(void)
376 {
377    if (_e_exehist_unload_defer)
378      e_powersave_deferred_action_del(_e_exehist_unload_defer);
379    _e_exehist_unload_defer =
380      e_powersave_deferred_action_add(_e_exehist_cb_unload, NULL);
381 }
382
383 static void
384 _e_exehist_load(void)
385 {
386    if (!_e_exehist)
387      _e_exehist = e_config_domain_load("exehist", _e_exehist_config_edd);
388    if (!_e_exehist)
389      _e_exehist = E_NEW(E_Exehist, 1);
390 }
391
392 static void
393 _e_exehist_clear(void)
394 {
395    if (_e_exehist)
396      {
397         E_Exehist_Item *ei;
398         EINA_LIST_FREE(_e_exehist->history, ei)
399           {
400              eina_stringshare_del(ei->exe);
401              eina_stringshare_del(ei->normalized_exe);
402              eina_stringshare_del(ei->launch_method);
403              free(ei);
404           }
405         EINA_LIST_FREE(_e_exehist->mimes, ei)
406           {
407              eina_stringshare_del(ei->exe);
408              eina_stringshare_del(ei->launch_method);
409              free(ei);
410           }
411      }
412 }
413
414 static void
415 _e_exehist_unload(void)
416 {
417    _e_exehist_clear();
418    E_FREE(_e_exehist);
419 }
420
421 static void
422 _e_exehist_limit(void)
423 {
424    /* go from first item in hist on and either delete all items before a
425     * specific timestamp, or if the list count > limit then delete items
426     *
427     * for now - limit to 500
428     */
429    if (_e_exehist)
430      {
431         while (eina_list_count(_e_exehist->history) > 500)
432           {
433              E_Exehist_Item *ei;
434
435              ei = eina_list_data_get(_e_exehist->history);
436              eina_stringshare_del(ei->exe);
437              eina_stringshare_del(ei->normalized_exe);
438              eina_stringshare_del(ei->launch_method);
439              free(ei);
440              _e_exehist->history = eina_list_remove_list(_e_exehist->history, _e_exehist->history);
441           }
442         while (eina_list_count(_e_exehist->mimes) > 500)
443           {
444              E_Exehist_Item *ei;
445
446              ei = eina_list_data_get(_e_exehist->mimes);
447              eina_stringshare_del(ei->exe);
448              eina_stringshare_del(ei->launch_method);
449              free(ei);
450              _e_exehist->mimes = eina_list_remove_list(_e_exehist->mimes, _e_exehist->mimes);
451           }
452      }
453 }
454
455 static const char *
456 _e_exehist_normalize_exe(const char *exe)
457 {
458    char *base, *buf, *cp, *space = NULL;
459    const char *ret;
460    Eina_Bool flag = EINA_FALSE;
461
462    buf = strdup(exe);
463    base = basename(buf);
464    if ((base[0] == '.') && (base[1] == '\0'))
465      {
466         free(buf);
467         return NULL;
468      }
469
470    cp = base;
471    while (*cp)
472      {
473         if (isspace(*cp))
474           {
475              if (!space) space = cp;
476              if (flag) flag = EINA_FALSE;
477           }
478         else if (!flag)
479           {
480              /* usually a variable in the desktop exe field */
481              if (space && *cp == '%')
482                flag = EINA_TRUE;
483              else
484                {
485                   char lower = tolower(*cp);
486
487                   space = NULL;
488                   if (lower != *cp) *cp = lower;
489                }
490           }
491         cp++;
492      }
493
494    if (space) *space = '\0';
495
496    ret = eina_stringshare_add(base);
497    free(buf);
498
499    return ret;
500 }
501
502 static void
503 _e_exehist_cb_unload(void *data __UNUSED__)
504 {
505    if (_e_exehist_changes)
506      {
507         e_config_domain_save("exehist", _e_exehist_config_edd, _e_exehist);
508         _e_exehist_changes = 0;
509      }
510    _e_exehist_unload();
511    _e_exehist_unload_defer = NULL;
512 }
513
514 static int
515 _e_exehist_sort_exe_cb(const void *d1, const void *d2)
516 {
517    const E_Exehist_Item *ei1, *ei2;
518
519    ei1 = d1;
520    ei2 = d2;
521
522    if ((!ei1) || (!ei1->normalized_exe)) return 1;
523    if ((!ei2) || (!ei2->normalized_exe)) return -1;
524
525    return strcmp(ei1->normalized_exe, ei2->normalized_exe);
526 }
527
528 static int
529 _e_exehist_sort_pop_cb(const void *d1, const void *d2)
530 {
531    const E_Exehist_Item *ei1, *ei2;
532
533    if (!(ei1 = d1)) return 1;
534    if (!(ei2 = d2)) return -1;
535
536    return ei2->count - ei1->count;
537 }