1 #include "e_mod_main.h"
2 #include "md5.h"
3
4 #define MAX_FUZZ 100
5 #define MAX_WORDS 5
6
7 static const char *home_dir = NULL;
8 static int home_dir_len;
9 static char dir_buf[1024];
10 static char thumb_buf[4096];
11
12 void
evry_util_file_detail_set(Evry_Item_File * file)13 evry_util_file_detail_set(Evry_Item_File *file)
14 {
15 char *dir = NULL;
16 const char *tmp;
17
18 if (EVRY_ITEM(file)->detail)
19 return;
20
21 if (!home_dir)
22 {
23 home_dir = e_user_homedir_get();
24 home_dir_len = strlen(home_dir);
25 }
26
27 dir = ecore_file_dir_get(file->path);
28 if (!dir || !home_dir) return;
29
30 if (!strncmp(dir, home_dir, home_dir_len))
31 {
32 tmp = dir + home_dir_len;
33
34 if (*(tmp) == '\0')
35 snprintf(dir_buf, sizeof(dir_buf), "~%s", tmp);
36 else
37 snprintf(dir_buf, sizeof(dir_buf), "~%s/", tmp);
38
39 EVRY_ITEM(file)->detail = eina_stringshare_add(dir_buf);
40 }
41 else
42 {
43 if (!strncmp(dir, "//", 2))
44 EVRY_ITEM(file)->detail = eina_stringshare_add(dir + 1);
45 else
46 EVRY_ITEM(file)->detail = eina_stringshare_add(dir);
47 }
48
49 E_FREE(dir);
50 }
51
52 static inline Eina_Unicode
_evry_utf8_next(const char * buf,int * iindex)53 _evry_utf8_next(const char *buf, int *iindex)
54 {
55 Eina_Unicode u = eina_unicode_utf8_next_get(buf, iindex);
56 if ((!u) || ((u >= 0xdc80) && (u <= 0xdcff))) return 0;
57 return u;
58 }
59
60 int
evry_fuzzy_match(const char * str,const char * match)61 evry_fuzzy_match(const char *str, const char *match)
62 {
63 const char *p, *m, *next;
64 int sum = 0;
65
66 unsigned int last = 0;
67 unsigned int offset = 0;
68 unsigned int min = 0;
69 unsigned char first = 0;
70 /* ignore punctuation */
71 unsigned char ip = 1;
72
73 unsigned int cnt = 0;
74 /* words in match */
75 unsigned int m_num = 0;
76 unsigned int m_cnt = 0;
77 unsigned int m_min[MAX_WORDS];
78 unsigned int m_len = 0;
79 unsigned int s_len = 0;
80
81 if (!match || !str || !match[0] || !str[0])
82 return 0;
83
84 /* remove white spaces at the beginning */
85 for (; (*match != 0) && isspace(*match); match++) ;
86 for (; (*str != 0) && isspace(*str); str++) ;
87
88 /* count words in match */
89 for (m = match; (*m != 0) && (m_num < MAX_WORDS); )
90 {
91 for (; (*m != 0) && !isspace(*m); m++) ;
92 for (; (*m != 0) && isspace(*m); m++) ;
93 m_min[m_num++] = MAX_FUZZ;
94 }
95 for (m = match; ip && (*m != 0); m++)
96 if (ip && ispunct(*m)) ip = 0;
97
98 m_len = strlen(match);
99 s_len = strlen(str);
100
101 /* with less than 3 chars match must be a prefix */
102 if (m_len < 3) m_len = 0;
103
104 next = str;
105 m = match;
106
107 while ((m_cnt < m_num) && (*next != 0))
108 {
109 int ii;
110
111 /* reset match */
112 if (m_cnt == 0) m = match;
113
114 /* end of matching */
115 if (*m == 0) break;
116
117 offset = 0;
118 last = 0;
119 min = 1;
120 first = 0;
121 /* m_len = 0; */
122
123 /* match current word of string against current match */
124 for (p = next; *next != 0; p++)
125 {
126 /* new word of string begins */
127 if ((*p == 0) || isspace(*p) || (ip && ispunct(*p)))
128 {
129 if (m_cnt < m_num - 1)
130 {
131 /* test next match */
132 for (; (*m != 0) && !isspace(*m); m++) ;
133 for (; (*m != 0) && isspace(*m); m++) ;
134 m_cnt++;
135 break;
136 }
137 else
138 {
139 ii = 0;
140 /* go to next word */
141 for (; (*p != 0) && ((isspace(*p) || (ip && ispunct(*p)))); p += ii)
142 {
143 ii = 0;
144 if (!_evry_utf8_next(p, &ii)) break;
145 }
146 cnt++;
147 next = p;
148 m_cnt = 0;
149 break;
150 }
151 }
152
153 /* current char matches? */
154 if (tolower(*p) != tolower(*m))
155 {
156 if (!first)
157 offset += 1;
158 else
159 offset += 3;
160
161 /* m_len++; */
162
163 if (offset <= m_len * 3)
164 continue;
165 }
166
167 if (min < MAX_FUZZ && offset <= m_len * 3)
168 {
169 /* first offset of match in word */
170 if (!first)
171 {
172 first = 1;
173 last = offset;
174 }
175
176 min += offset + (offset - last) * 5;
177 last = offset;
178
179 /* try next char of match */
180 ii = 0;
181 if (!_evry_utf8_next(m, &ii)) continue;
182 m += ii;
183 if (*m != 0 && !isspace(*m))
184 continue;
185
186 /* end of match: store min weight of match */
187 min += (cnt - m_cnt) > 0 ? (cnt - m_cnt) : 0;
188
189 if (min < m_min[m_cnt])
190 m_min[m_cnt] = min;
191 }
192 else
193 {
194 ii = 0;
195 /* go to next match */
196 for (; (m[0] && m[ii]) && !isspace(*m); m += ii)
197 {
198 ii = 0;
199 if (!_evry_utf8_next(m, &ii)) break;
200 }
201 }
202
203 if (m_cnt < m_num - 1)
204 {
205 ii = 0;
206 /* test next match */
207 for (; (m[0] && m[ii]) && !isspace(*m); m += ii)
208 {
209 ii = 0;
210 if (!_evry_utf8_next(m, &ii)) break;
211 }
212 m_cnt++;
213 break;
214 }
215 else if (*p != 0)
216 {
217 ii = 0;
218 /* go to next word */
219 for (; (p[0] && (s_len - (p - str) >= (unsigned int)ii)) &&
220 !((isspace(*p) || (ip && ispunct(*p))));
221 p += ii)
222 {
223 if (!_evry_utf8_next(p, &ii)) break;
224 }
225 ii = 0;
226 for (; (p[0] && (s_len - (p - str) >= (unsigned int)ii)) &&
227 ((isspace(*p) || (ip && ispunct(*p))));
228 p += ii)
229 {
230 if (!_evry_utf8_next(p, &ii)) break;
231 }
232 cnt++;
233 next = p;
234 m_cnt = 0;
235 break;
236 }
237 else
238 {
239 next = p;
240 break;
241 }
242 }
243 }
244
245 for (m_cnt = 0; m_cnt < m_num; m_cnt++)
246 {
247 sum += m_min[m_cnt];
248
249 if (sum >= MAX_FUZZ)
250 {
251 sum = 0;
252 break;
253 }
254 }
255
256 if (sum > 0)
257 {
258 /* exact match ? */
259 if (strcmp(match, str))
260 sum += 10;
261 }
262
263 return sum;
264 }
265
266 static int
_evry_fuzzy_match_sort_cb(const void * data1,const void * data2)267 _evry_fuzzy_match_sort_cb(const void *data1, const void *data2)
268 {
269 const Evry_Item *it1 = data1;
270 const Evry_Item *it2 = data2;
271
272 if (it1->priority - it2->priority)
273 return it1->priority - it2->priority;
274
275 if (it1->fuzzy_match || it2->fuzzy_match)
276 {
277 if (it1->fuzzy_match && !it2->fuzzy_match)
278 return -1;
279
280 if (!it1->fuzzy_match && it2->fuzzy_match)
281 return 1;
282
283 if (it1->fuzzy_match - it2->fuzzy_match)
284 return it1->fuzzy_match - it2->fuzzy_match;
285 }
286
287 return 0;
288 }
289
290 Eina_List *
evry_fuzzy_match_sort(Eina_List * items)291 evry_fuzzy_match_sort(Eina_List *items)
292 {
293 return eina_list_sort(items, -1, _evry_fuzzy_match_sort_cb);
294 }
295
296 static int _sort_flags = 0;
297
298 static int
_evry_items_sort_func(const void * data1,const void * data2)299 _evry_items_sort_func(const void *data1, const void *data2)
300 {
301 const Evry_Item *it1 = data1;
302 const Evry_Item *it2 = data2;
303
304 /* if (!((!_sort_flags) &&
305 * (it1->type == EVRY_TYPE_ACTION) &&
306 * (it2->type == EVRY_TYPE_ACTION)))
307 * { */
308 /* only sort actions when there is input otherwise show default order */
309
310 if (((it1->type == EVRY_TYPE_ACTION) || (it1->subtype == EVRY_TYPE_ACTION)) &&
311 ((it2->type == EVRY_TYPE_ACTION) || (it2->subtype == EVRY_TYPE_ACTION)))
312 {
313 const Evry_Action *act1 = data1;
314 const Evry_Action *act2 = data2;
315
316 /* sort actions that match the specific type before
317 those matching general type */
318 if (act1->it1.item && act2->it1.item)
319 {
320 if ((act1->it1.type == act1->it1.item->type) &&
321 (act2->it1.type != act2->it1.item->type))
322 return -1;
323
324 if ((act1->it1.type != act1->it1.item->type) &&
325 (act2->it1.type == act2->it1.item->type))
326 return 1;
327 }
328
329 /* sort context specific actions before
330 general actions */
331 if (act1->remember_context)
332 {
333 if (!act2->remember_context)
334 return -1;
335 }
336 else
337 {
338 if (act2->remember_context)
339 return 1;
340 }
341 }
342 /* } */
343
344 if (_sort_flags)
345 {
346 /* when there is no input sort items with higher
347 * plugin priority first */
348 if (it1->type != EVRY_TYPE_ACTION &&
349 it2->type != EVRY_TYPE_ACTION)
350 {
351 int prio1 = it1->plugin->config->priority;
352 int prio2 = it2->plugin->config->priority;
353
354 if (prio1 - prio2)
355 return prio1 - prio2;
356 }
357 }
358
359 /* sort items which match input or which
360 match much better first */
361 if (it1->fuzzy_match > 0 || it2->fuzzy_match > 0)
362 {
363 if (it2->fuzzy_match <= 0)
364 return -1;
365
366 if (it1->fuzzy_match <= 0)
367 return 1;
368
369 if (abs (it1->fuzzy_match - it2->fuzzy_match) > 5)
370 return it1->fuzzy_match - it2->fuzzy_match;
371 }
372
373 /* sort recently/most frequently used items first */
374 if (it1->usage > 0.0 || it2->usage > 0.0)
375 {
376 return it1->usage > it2->usage ? -1 : 1;
377 }
378
379 /* sort items which match input better first */
380 if (it1->fuzzy_match > 0 || it2->fuzzy_match > 0)
381 {
382 if (it1->fuzzy_match - it2->fuzzy_match)
383 return it1->fuzzy_match - it2->fuzzy_match;
384 }
385
386 /* sort itemswith higher priority first */
387 if ((it1->plugin == it2->plugin) &&
388 (it1->priority - it2->priority))
389 return it1->priority - it2->priority;
390
391 /* sort items with higher plugin priority first */
392 if (it1->type != EVRY_TYPE_ACTION &&
393 it2->type != EVRY_TYPE_ACTION)
394 {
395 int prio1 = it1->plugin->config->priority;
396 int prio2 = it2->plugin->config->priority;
397
398 if (prio1 - prio2)
399 return prio1 - prio2;
400 }
401
402 /* user has a broken system: -╯□)╯︵-┻━┻ */
403 if ((!it1->label) || (!it2->label)) return -1;
404 return strcasecmp(it1->label, it2->label);
405 }
406
407 void
evry_util_items_sort(Eina_List ** items,int flags)408 evry_util_items_sort(Eina_List **items, int flags)
409 {
410 _sort_flags = flags;
411 *items = eina_list_sort(*items, -1, _evry_items_sort_func);
412 _sort_flags = 0;
413 }
414
415 int
evry_util_plugin_items_add(Evry_Plugin * p,Eina_List * items,const char * input,int match_detail,int set_usage)416 evry_util_plugin_items_add(Evry_Plugin *p, Eina_List *items, const char *input,
417 int match_detail, int set_usage)
418 {
419 Eina_List *l;
420 Evry_Item *it;
421 int match = 0;
422
423 EINA_LIST_FOREACH (items, l, it)
424 {
425 it->fuzzy_match = 0;
426
427 if (set_usage)
428 evry_history_item_usage_set(it, input, NULL);
429
430 if (!input)
431 {
432 p->items = eina_list_append(p->items, it);
433 continue;
434 }
435
436 it->fuzzy_match = evry_fuzzy_match(it->label, input);
437
438 if (match_detail)
439 {
440 match = evry_fuzzy_match(it->detail, input);
441
442 if (!(it->fuzzy_match) || (match && (match < it->fuzzy_match)))
443 it->fuzzy_match = match;
444 }
445
446 if (it->fuzzy_match)
447 p->items = eina_list_append(p->items, it);
448 }
449
450 p->items = eina_list_sort(p->items, -1, _evry_items_sort_func);
451
452 return !!(p->items);
453 }
454
455 Evas_Object *
evry_icon_theme_get(const char * icon,Evas * e)456 evry_icon_theme_get(const char *icon, Evas *e)
457 {
458 Evas_Object *o = NULL;
459
460 if (!icon)
461 return NULL;
462
463 o = e_icon_add(e);
464 e_icon_scale_size_set(o, 128);
465 e_icon_preload_set(o, 1);
466
467 if (icon[0] == '/')
468 {
469 e_icon_file_set(o, icon);
470 }
471 else if (!e_util_icon_theme_set(o, icon))
472 {
473 char grp[1024];
474
475 snprintf(grp, sizeof(grp), "fileman/mime/%s", icon);
476 if (!e_util_icon_theme_set(o, grp))
477 {
478 evas_object_del(o);
479 o = NULL;
480 }
481 }
482
483 return o;
484 }
485
486 Evas_Object *
evry_util_icon_get(Evry_Item * it,Evas * e)487 evry_util_icon_get(Evry_Item *it, Evas *e)
488 {
489 Evas_Object *o = NULL;
490
491 if (it->icon_get)
492 {
493 o = it->icon_get(it, e);
494 if (o) return o;
495 }
496
497 if ((it->icon) && (it->icon[0] == '/'))
498 {
499 o = evry_icon_theme_get(it->icon, e);
500 if (o) return o;
501 }
502
503 if (CHECK_TYPE(it, EVRY_TYPE_FILE))
504 {
505 const char *icon;
506 char *sum;
507
508 GET_FILE(file, it);
509
510 if (it->browseable)
511 {
512 o = evry_icon_theme_get("folder", e);
513 if (o) return o;
514 }
515
516 if ((!it->icon) && (file->mime) &&
517 ( /*(!strncmp(file->mime, "image/", 6)) || */
518 (!strncmp(file->mime, "video/", 6)) ||
519 (!strncmp(file->mime, "application/pdf", 15))) &&
520 (evry_file_url_get(file)))
521 {
522 sum = evry_util_md5_sum(file->url);
523
524 snprintf(thumb_buf, sizeof(thumb_buf),
525 "%s/.thumbnails/normal/%s.png",
526 e_user_homedir_get(), sum);
527 free(sum);
528
529 if ((o = evry_icon_theme_get(thumb_buf, e)))
530 {
531 it->icon = eina_stringshare_add(thumb_buf);
532 return o;
533 }
534 }
535
536 if ((!it->icon) && (file->mime))
537 {
538 icon = efreet_mime_type_icon_get(file->mime, e_config->icon_theme, 128);
539 /* XXX can do _ref ?*/
540 if ((o = evry_icon_theme_get(icon, e)) || (o = evry_icon_theme_get(file->mime, e)))
541 {
542 /* it->icon = eina_stringshare_add(icon); */
543 return o;
544 }
545 }
546
547 if ((icon = efreet_mime_type_icon_get("unknown", e_config->icon_theme, 128)))
548 it->icon = eina_stringshare_add(icon);
549 else
550 it->icon = eina_stringshare_add("");
551 }
552
553 if (CHECK_TYPE(it, EVRY_TYPE_APP))
554 {
555 GET_APP(app, it);
556
557 o = e_util_desktop_icon_add(app->desktop, 128, e);
558 if (o) return o;
559
560 o = evry_icon_theme_get("system-run", e);
561 if (o) return o;
562 }
563
564 if (it->icon)
565 {
566 o = evry_icon_theme_get(it->icon, e);
567 if (o) return o;
568 }
569
570 if (it->browseable)
571 {
572 o = evry_icon_theme_get("folder", e);
573 if (o) return o;
574 }
575
576 o = evry_icon_theme_get("unknown", e);
577 return o;
578 }
579
580 int
evry_util_exec_app(const Evry_Item * it_app,const Evry_Item * it_file)581 evry_util_exec_app(const Evry_Item *it_app, const Evry_Item *it_file)
582 {
583 E_Zone *zone;
584 Eina_List *files = NULL;
585 char *exe = NULL;
586 char *tmp = NULL;
587
588 if (!it_app) return 0;
589 GET_APP(app, it_app);
590 GET_FILE(file, it_file);
591
592 zone = e_zone_current_get();
593
594 if (app->desktop)
595 {
596 if (file && evry_file_path_get(file))
597 {
598 Eina_List *l;
599 char *mime;
600 int open_folder = 0;
601
602 /* when the file is no a directory and the app
603 opens folders, pass only the dir */
604 if (!IS_BROWSEABLE(file))
605 {
606 EINA_LIST_FOREACH (app->desktop->mime_types, l, mime)
607 {
608 if (!mime)
609 continue;
610
611 if (!strcmp(mime, "x-directory/normal"))
612 open_folder = 1;
613
614 if (file->mime && !strcmp(mime, file->mime))
615 {
616 open_folder = 0;
617 break;
618 }
619 }
620 }
621
622 if (open_folder)
623 {
624 tmp = ecore_file_dir_get(file->path);
625 files = eina_list_append(files, tmp);
626 }
627 else
628 {
629 files = eina_list_append(files, file->path);
630 }
631
632 e_exec(zone, app->desktop, NULL, files, NULL);
633
634 if (file && file->mime && !open_folder)
635 e_exehist_mime_desktop_add(file->mime, app->desktop);
636
637 if (files)
638 eina_list_free(files);
639
640 E_FREE(tmp);
641 }
642 else if (app->file)
643 {
644 files = eina_list_append(files, app->file);
645 e_exec(zone, app->desktop, NULL, files, NULL);
646 eina_list_free(files);
647 }
648 else
649 {
650 e_exec(zone, app->desktop, NULL, NULL, NULL);
651 }
652 }
653 else if (app->file)
654 {
655 if (file && evry_file_path_get(file))
656 {
657 int len;
658 len = strlen(app->file) + strlen(file->path) + 4;
659 exe = malloc(len);
660 snprintf(exe, len, "%s \'%s\'", app->file, file->path);
661 e_exec(zone, NULL, exe, NULL, NULL);
662 E_FREE(exe);
663 }
664 else
665 {
666 exe = (char *)app->file;
667 e_exec(zone, NULL, exe, NULL, NULL);
668 }
669 }
670
671 return 1;
672 }
673
674 /* taken from curl:
675 *
676 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et
677 * al.
678 *
679 * Unescapes the given URL escaped string of given length. Returns a
680 * pointer to a malloced string with length given in *olen.
681 * If length == 0, the length is assumed to be strlen(string).
682 * If olen == NULL, no output length is stored.
683 */
684 #define ISXDIGIT(x) (isxdigit((int)((unsigned char)x)))
685
686 char *
evry_util_url_unescape(const char * string,int length)687 evry_util_url_unescape(const char *string, int length)
688 {
689 int alloc = (length ? length : (int)strlen(string)) + 1;
690 char *ns = malloc(alloc);
691 unsigned char in;
692 int strindex = 0;
693 unsigned long hex;
694
695 if ( !ns )
696 return NULL;
697
698 while (--alloc > 0)
699 {
700 in = *string;
701 if (('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2]))
702 {
703 /* this is two hexadecimal digits following a '%' */
704 char hexstr[3];
705 char *ptr;
706 hexstr[0] = string[1];
707 hexstr[1] = string[2];
708 hexstr[2] = 0;
709
710 hex = strtoul(hexstr, &ptr, 16);
711 in = (unsigned char)(hex & (unsigned long)0xFF);
712 // in = ultouc(hex); /* this long is never bigger than 255 anyway */
713
714 string += 2;
715 alloc -= 2;
716 }
717
718 ns[strindex++] = in;
719 string++;
720 }
721 ns[strindex] = 0; /* terminate it */
722
723 return ns;
724 }
725
726 #undef ISXDIGIT
727
728 static Eina_Bool
_isalnum(unsigned char in)729 _isalnum(unsigned char in)
730 {
731 switch (in)
732 {
733 case '0':
734 case '1':
735 case '2':
736 case '3':
737 case '4':
738 case '5':
739 case '6':
740 case '7':
741 case '8':
742 case '9':
743 case 'a':
744 case 'b':
745 case 'c':
746 case 'd':
747 case 'e':
748 case 'f':
749 case 'g':
750 case 'h':
751 case 'i':
752 case 'j':
753 case 'k':
754 case 'l':
755 case 'm':
756 case 'n':
757 case 'o':
758 case 'p':
759 case 'q':
760 case 'r':
761 case 's':
762 case 't':
763 case 'u':
764 case 'v':
765 case 'w':
766 case 'x':
767 case 'y':
768 case 'z':
769 case 'A':
770 case 'B':
771 case 'C':
772 case 'D':
773 case 'E':
774 case 'F':
775 case 'G':
776 case 'H':
777 case 'I':
778 case 'J':
779 case 'K':
780 case 'L':
781 case 'M':
782 case 'N':
783 case 'O':
784 case 'P':
785 case 'Q':
786 case 'R':
787 case 'S':
788 case 'T':
789 case 'U':
790 case 'V':
791 case 'W':
792 case 'X':
793 case 'Y':
794 case 'Z':
795 return EINA_TRUE;
796
797 default:
798 break;
799 }
800 return EINA_FALSE;
801 }
802
803 char *
evry_util_url_escape(const char * string,int inlength)804 evry_util_url_escape(const char *string, int inlength)
805 {
806 size_t alloc = (inlength ? (size_t)inlength : strlen(string)) + 1;
807 char *ns;
808 char *testing_ptr = NULL;
809 unsigned char in; /* we need to treat the characters unsigned */
810 size_t newlen = alloc;
811 int strindex = 0;
812 size_t length;
813
814 ns = malloc(alloc);
815 if (!ns)
816 return NULL;
817
818 length = alloc - 1;
819 while (length--)
820 {
821 in = *string;
822
823 if (_isalnum(in))
824 {
825 /* just copy this */
826 ns[strindex++] = in;
827 }
828 else {
829 /* encode it */
830 newlen += 2; /* the size grows with two, since this'll become a %XX */
831 if (newlen > alloc)
832 {
833 alloc *= 2;
834 testing_ptr = realloc(ns, alloc);
835 if (!testing_ptr)
836 {
837 free(ns);
838 return NULL;
839 }
840 else
841 {
842 ns = testing_ptr;
843 }
844 }
845
846 snprintf(&ns[strindex], 4, "%%%02X", in);
847
848 strindex += 3;
849 }
850 string++;
851 }
852 ns[strindex] = 0; /* terminate it */
853 return ns;
854 }
855
856 const char *
evry_file_path_get(Evry_Item_File * file)857 evry_file_path_get(Evry_Item_File *file)
858 {
859 const char *tmp;
860 char *path;
861
862 if (file->path)
863 return file->path;
864
865 if (!file->url)
866 return NULL;
867
868 if (!strncmp(file->url, "file://", 7))
869 tmp = file->url + 7;
870 else return NULL;
871
872 if (!(path = evry_util_url_unescape(tmp, 0)))
873 return NULL;
874
875 file->path = eina_stringshare_add(path);
876
877 E_FREE(path);
878
879 return file->path;
880 }
881
882 const char *
evry_file_url_get(Evry_Item_File * file)883 evry_file_url_get(Evry_Item_File *file)
884 {
885 char dest[PATH_MAX * 3 + 7];
886 const char *p;
887 int i;
888
889 if (file->url)
890 return file->url;
891
892 if (!file->path)
893 return NULL;
894
895 memset(dest, 0, sizeof(dest));
896
897 snprintf(dest, 8, "file://");
898
899 /* Most app doesn't handle the hostname in the uri so it's put to NULL */
900 for (i = 7, p = file->path; *p != '\0'; p++, i++)
901 {
902 if (isalnum(*p) || strchr("/$-_.+!*'()", *p))
903 dest[i] = *p;
904 else
905 {
906 snprintf(&(dest[i]), 4, "%%%02X", (unsigned char)*p);
907 i += 2;
908 }
909 }
910
911 file->url = eina_stringshare_add(dest);
912
913 return file->url;
914 }
915
916 static void
_cb_free_item_changed(void * data EINA_UNUSED,void * event)917 _cb_free_item_changed(void *data EINA_UNUSED, void *event)
918 {
919 Evry_Event_Item_Changed *ev = event;
920
921 evry_item_free(ev->item);
922 E_FREE(ev);
923 }
924
925 void
evry_item_changed(Evry_Item * it,int icon,int selected)926 evry_item_changed(Evry_Item *it, int icon, int selected)
927 {
928 Evry_Event_Item_Changed *ev;
929 ev = E_NEW(Evry_Event_Item_Changed, 1);
930 ev->item = it;
931 ev->changed_selection = selected;
932 ev->changed_icon = icon;
933 evry_item_ref(it);
934 ecore_event_add(_evry_events[EVRY_EVENT_ITEM_CHANGED], ev, _cb_free_item_changed, NULL);
935 }
936
937 static char thumb_buf[4096];
938 static const char hex[] = "0123456789abcdef";
939
940 char *
evry_util_md5_sum(const char * str)941 evry_util_md5_sum(const char *str)
942 {
943 MD5_CTX ctx;
944 unsigned char hash[MD5_HASHBYTES];
945 int n;
946 char md5out[(2 * MD5_HASHBYTES) + 1];
947 MD5Init (&ctx);
948 MD5Update (&ctx, (unsigned char const *)str,
949 (unsigned)strlen (str));
950 MD5Final (hash, &ctx);
951
952 for (n = 0; n < MD5_HASHBYTES; n++)
953 {
954 md5out[2 * n] = hex[hash[n] >> 4];
955 md5out[2 * n + 1] = hex[hash[n] & 0x0f];
956 }
957 md5out[2 * n] = '\0';
958
959 return strdup(md5out);
960 }
961
962