Merge from TIZEN 2.3
[platform/core/uifw/e17.git] / src / bin / e_fm_device.c
1 #include "e_fm_device.h"
2 #include "e_fm_shared_codec.h"
3 #include "e_fm_shared_device.h"
4
5 static void _e_fm2_volume_write(E_Volume *v) EINA_ARG_NONNULL(1);
6 static void _e_fm2_volume_erase(E_Volume *v) EINA_ARG_NONNULL(1);
7 static void _e_fm2_device_mount_free(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
8 static void _e_fm2_device_mount_ok(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
9 static void _e_fm2_device_mount_fail(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
10 static void _e_fm2_device_unmount_ok(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
11 static void _e_fm2_device_unmount_fail(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
12
13 static Eina_List *_e_stores = NULL;
14 static Eina_List *_e_vols = NULL;
15
16 static void
17 _e_fm2_device_volume_setup(E_Volume *v)
18 {
19    char label[1024] = {0};
20    char *size = NULL;
21    const char *icon = NULL;
22    /* unsigned long long sz; */
23
24    /* Compute the size in a readable form */
25    if (v->size)
26      size = e_util_size_string_get(v->size);
27
28    /* Choose the label */
29    if ((v->label) && (v->label[0]))
30      {}
31    else if ((v->partition_label) && (v->partition_label[0]))
32      snprintf(label, sizeof(label) - 1, "%s", v->partition_label);
33    else if (((v->storage->vendor) && (v->storage->vendor[0])) &&
34             ((v->storage->model) && (v->storage->model[0])))
35      {
36         if (size && (size[0] != '\0'))
37           snprintf(label, sizeof(label) - 1, _("%s %s—%s"), v->storage->vendor, v->storage->model, size);
38         else
39           snprintf(label, sizeof(label) - 1, "%s %s", v->storage->vendor, v->storage->model);
40      }
41    else if ((v->storage->model) && (v->storage->model[0]))
42      {
43         if (size && (size[0] != '\0'))
44           snprintf(label, sizeof(label) - 1, _("%s—%s"), v->storage->model, size);
45         else
46           snprintf(label, sizeof(label) - 1, "%s", v->storage->model);
47      }
48    else if ((v->storage->vendor) && (v->storage->vendor[0]))
49      {
50         if (size && (size[0] != '\0'))
51           snprintf(label, sizeof(label) - 1, _("%s—%s"), v->storage->vendor, size);
52         else
53           snprintf(label, sizeof(label) - 1, "%s", v->storage->vendor);
54      }
55    else if (v->storage->drive_type && (!strcmp(v->storage->drive_type, "sd_mmc")))
56      snprintf(label, sizeof(label) - 1, _("Flash Card—%s"), size);
57    else
58      snprintf(label, sizeof(label), _("Unknown Volume"));
59
60    if (label[0]) eina_stringshare_replace(&v->label, label);
61
62    /* Choose the icon */
63    /* http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html */
64    if (v->storage->icon.volume)
65      icon = v->storage->icon.volume;
66    else
67      {
68         if ((!v->storage->drive_type) || (!strcmp(v->storage->drive_type, "disk")) || (!strcmp(v->storage->drive_type, "partition")))
69           {
70              if (v->storage->removable == 0)
71                icon = "drive-harddisk";
72              else
73                icon = "drive-removable-media";
74           }
75         else if ((!strcmp(v->storage->drive_type, "cdrom")) || (!strncmp(v->storage->drive_type, "optical", 7)))
76           icon = "drive-optical";
77         else if (!strncmp(v->storage->drive_type, "floppy", 6))
78           icon = "media-floppy";
79         else if (!strcmp(v->storage->drive_type, "tape"))
80           icon = "media-tape";
81         else if (!strcmp(v->storage->drive_type, "compact_flash")
82                  || !strcmp(v->storage->drive_type, "memory_stick")
83                  || !strcmp(v->storage->drive_type, "smart_media")
84                  || !strcmp(v->storage->drive_type, "sd_mmc")
85                  || !strncmp(v->storage->drive_type, "flash", 5))
86           icon = "media-flash";
87      }
88    if (icon) eina_stringshare_replace(&v->icon, icon);
89
90    if ((!v->mount_point) ||
91        // filter out these mountouts - hack hack
92        (strcmp(v->mount_point, "/") &&
93         strcmp(v->mount_point, "/home") &&
94         strcmp(v->mount_point, "/tmp")))
95      _e_fm2_volume_write(v);
96
97    E_FREE(size);
98 }
99
100 EAPI void
101 e_fm2_device_storage_add(E_Storage *s)
102 {
103    Eina_List *l;
104    E_Volume *v;
105
106    if (e_fm2_device_storage_find(s->udi)) return;
107
108    s->validated = EINA_TRUE;
109    _e_stores = eina_list_append(_e_stores, s);
110 /*
111    printf("STO+\n"
112           "  udi: %s\n"
113           "  bus: %s\n"
114           "  drive_type: %s\n"
115           "  model: %s\n"
116           "  vendor: %s\n"
117           "  serial: %s\n"
118           "  removable: %i\n"
119           "  media_available: %i\n"
120           "  media_size: %lli\n"
121           "  requires_eject: %i\n"
122           "  hotpluggable: %i\n"
123           "  media_check_enabled: %i\n"
124           "  icon.drive: %s\n"
125           "  icon.volume: %s\n\n"
126           ,
127           s->udi,
128           s->bus,
129           s->drive_type,
130           s->model,
131           s->vendor,
132           s->serial,
133           s->removable,
134           s->media_available,
135           s->media_size,
136           s->requires_eject,
137           s->hotpluggable,
138           s->media_check_enabled,
139           s->icon.drive,
140           s->icon.volume);
141  */
142    if ((s->removable == 0) &&
143        (s->media_available == 0) &&
144        (s->media_size == 0) &&
145        (s->requires_eject == 0) &&
146        (s->hotpluggable == 0) &&
147        (s->media_check_enabled == 0))
148      {
149 //      printf("      Ignore this storage\n");
150      }
151    else
152      {
153         s->trackable = EINA_TRUE;
154      }
155
156    EINA_LIST_FOREACH(_e_vols, l, v) /* catch volumes which were added before their storage */
157      {
158         if ((!v->storage) && (s->udi == v->parent))
159           {
160              v->storage = s;
161              _e_fm2_device_volume_setup(v);
162           }
163      }
164 }
165
166 EAPI void
167 e_fm2_device_storage_del(E_Storage *s)
168 {
169 //   printf("STO- %s\n", s->udi);
170      _e_stores = eina_list_remove(_e_stores, s);
171      _e_fm_shared_device_storage_free(s);
172 }
173
174 EAPI E_Storage *
175 e_fm2_device_storage_find(const char *udi)
176 {
177    Eina_List *l;
178    E_Storage *s;
179
180    if (!udi) return NULL;
181    EINA_LIST_FOREACH(_e_stores, l, s)
182      {
183         if (!strcmp(udi, s->udi)) return s;
184      }
185    return NULL;
186 }
187
188
189 EAPI void
190 e_fm2_device_volume_add(E_Volume *v)
191 {
192    E_Storage *s;
193
194    if (e_fm2_device_volume_find(v->udi)) return;
195
196    v->validated = EINA_TRUE;
197    _e_vols = eina_list_append(_e_vols, v);
198 /*
199    printf("VOL+\n"
200           "  udi: %s\n"
201           "  uuid: %s\n"
202           "  fstype: %s\n"
203           "  size: %llu\n"
204           "  label: %s\n"
205           "  partition: %d\n"
206           "  partition_number: %d\n"
207           "  partition_label: %s\n"
208           "  mounted: %d\n"
209           "  mount_point: %s\n"
210           "  parent: %s\n"
211           ,
212           v->udi,
213           v->uuid,
214           v->fstype,
215           v->size,
216           v->label,
217           v->partition,
218           v->partition_number,
219           v->partition ? v->partition_label : "(not a partition)",
220           v->mounted,
221           v->mount_point,
222           v->parent);
223  */
224 /* Check mount point */
225    if ((v->efm_mode == EFM_MODE_USING_HAL_MOUNT) &&
226        ((!v->mount_point) || (!v->mount_point[0])))
227      {
228         eina_stringshare_del(v->mount_point);
229         v->mount_point = NULL;
230         v->mount_point = e_fm2_device_volume_mountpoint_get(v);
231         if ((!v->mount_point) || (!v->mount_point[0]))
232           {
233              char buf[PATH_MAX];
234              const char *id;
235
236              if (v->mount_point) eina_stringshare_del(v->mount_point);
237              v->mount_point = NULL;
238              id = "disk";
239              if ((v->uuid) && (v->uuid[0])) id = v->uuid;
240              if (ecore_file_is_dir("/media"))
241                snprintf(buf, sizeof(buf), "/media/%s", id);
242              else if (ecore_file_is_dir("/mnt"))
243                snprintf(buf, sizeof(buf), "/mnt/%s", id);
244              else if (ecore_file_is_dir("/tmp"))
245                snprintf(buf, sizeof(buf), "/tmp/%s", id);
246              else
247                buf[0] = 0;
248              v->mount_point = eina_stringshare_add(buf);
249           }
250      }
251
252    /* Search parent storage */
253    if ((s = e_fm2_device_storage_find(v->parent)))
254      {
255         v->storage = s;
256         s->volumes = eina_list_append(s->volumes, v);
257      }
258
259    if (v->storage) _e_fm2_device_volume_setup(v);
260
261 }
262
263 EAPI void
264 e_fm2_device_volume_del(E_Volume *v)
265 {
266    E_Fm2_Mount *m;
267
268 //   printf("VOL- %s\n", v->udi);
269    _e_vols = eina_list_remove(_e_vols, v);
270    _e_fm2_volume_erase(v);
271    if (v->storage)
272      {
273         v->storage->volumes = eina_list_remove(v->storage->volumes, v);
274         v->storage = NULL;
275      }
276    EINA_LIST_FREE(v->mounts, m)
277      {
278         _e_fm2_device_unmount_ok(m);
279         _e_fm2_device_mount_free(m);
280      }
281    _e_fm_shared_device_volume_free(v);
282 }
283
284 static void
285 _e_fm2_volume_write(E_Volume *v)
286 {
287    char buf[PATH_MAX], buf2[PATH_MAX];
288    FILE *f;
289    const char *id;
290
291    if (!v->storage) return;
292    id = ecore_file_file_get(v->storage->udi);
293    e_user_dir_snprintf(buf, sizeof(buf), "fileman/favorites/|%s_%d.desktop",
294                        id, v->partition_number);
295
296    f = fopen(buf, "w");
297    if (f)
298      {
299         fprintf(f,
300                 "[Desktop Entry]\n"
301                 "Encoding=UTF-8\n"
302                 "Type=Link\n"
303                 "X-Enlightenment-Type=Removable\n"
304                 "X-Enlightenment-Removable-State=Full\n"
305                 "Name=%s\n"
306                 "Icon=%s\n"
307                 "Comment=%s\n"
308                 "URL=file:/%s\n"
309                 ,
310                 v->label,
311                 v->icon,
312                 _("Removable Device"),
313                 v->udi);
314         fclose(f);
315
316         if (e_config->device_desktop)
317           {
318              e_user_homedir_snprintf(buf2, sizeof(buf2),
319                                      "%s/|%s_%d.desktop",
320                                      _("Desktop"), id, v->partition_number);
321              ecore_file_symlink(buf, buf2);
322           }
323
324         /* FIXME: manipulate icon directly */
325         _e_fm2_file_force_update(buf);
326         _e_fm2_file_force_update(buf2);
327      }
328 }
329
330 static void
331 _e_fm2_volume_erase(E_Volume *v)
332 {
333    char buf[PATH_MAX] = {0};
334    const char *id;
335
336    if (!v->storage) return;
337    id = ecore_file_file_get(v->storage->udi);
338    if (e_config->device_desktop)
339      {
340         e_user_homedir_snprintf(buf, sizeof(buf), "%s/|%s_%d.desktop",
341                            _("Desktop"), id, v->partition_number);
342         ecore_file_unlink(buf);
343         _e_fm2_file_force_update(buf);
344      }
345    e_user_dir_snprintf(buf, sizeof(buf),
346                        "fileman/favorites/|%s_%d.desktop",
347                        id, v->partition_number);
348    ecore_file_unlink(buf);
349    _e_fm2_file_force_update(buf);
350 }
351
352 EAPI E_Volume *
353 e_fm2_device_volume_find(const char *udi)
354 {
355    Eina_List *l;
356    E_Volume *v;
357
358    if (!udi) return NULL;
359
360    EINA_LIST_FOREACH(_e_vols, l, v)
361      {
362         if (!v->udi) continue;
363         if (!strcmp(udi, v->udi)) return v;
364      }
365
366    return NULL;
367 }
368
369 EAPI E_Volume *
370 e_fm2_device_volume_find_fast(const char *udi)
371 {
372    Eina_List *l;
373    E_Volume *v;
374
375    if (!udi) return NULL;
376
377    EINA_LIST_FOREACH(_e_vols, l, v)
378      if (udi == v->udi) return v;
379
380    return NULL;
381 }
382
383 EAPI const char *
384 e_fm2_device_volume_mountpoint_get(E_Volume *v)
385 {
386    char buf[PATH_MAX] = {0};
387
388    if (!v) return NULL;
389    if (v->mount_point)
390      {
391         //      printf("GET MOUNTPOINT = %s\n", v->mount_point);
392           return eina_stringshare_add(v->mount_point);
393      }
394    else if (v->efm_mode != EFM_MODE_USING_HAL_MOUNT)
395      return NULL;
396
397    if (v->label && v->label[0] != '\0')
398      snprintf(buf, sizeof(buf) - 1, "/media/%s", v->label);
399    else if (v->uuid && v->uuid[0] != '\0')
400      snprintf(buf, sizeof(buf) - 1, "/media/%s", v->uuid);
401    else if ((v->storage) && (v->storage->serial) && v->storage->serial[0] != '\0')
402      snprintf(buf, sizeof(buf) - 1, "/media/%s", v->storage->serial);
403    else
404      {
405         static int mount_count = 1;
406         snprintf(buf, sizeof(buf) - 1, "/media/unknown-%i", mount_count++);
407      }
408 //   printf("GET MOUNTPOINT = %s\n", buf);
409    return eina_stringshare_add(buf);
410 }
411
412 EAPI void
413 e_fm2_device_mount_add(E_Volume   *v,
414                        const char *mountpoint)
415 {
416    Eina_List *l;
417    E_Fm2_Mount *m;
418
419    v->mounted = EINA_TRUE;
420    if (mountpoint && (mountpoint[0]))
421      eina_stringshare_replace(&v->mount_point, mountpoint);
422
423    EINA_LIST_FOREACH(v->mounts, l, m)
424      _e_fm2_device_mount_ok(m);
425
426 //   printf("MOUNT %s %s\n", v->udi, v->mount_point);
427 }
428
429 EAPI void
430 e_fm2_device_mount_del(E_Volume *v)
431 {
432    E_Fm2_Mount *m;
433
434    v->mounted = EINA_FALSE;
435    if (v->mount_point)
436      {
437         eina_stringshare_del(v->mount_point);
438         v->mount_point = NULL;
439      }
440
441    EINA_LIST_FREE(v->mounts, m)
442      {
443         _e_fm2_device_unmount_ok(m);
444         _e_fm2_device_mount_free(m);
445      }
446 }
447
448 EAPI void
449 _e_fm2_device_mount_free(E_Fm2_Mount *m)
450 {
451    if (!m) return;
452
453    if (m->udi) eina_stringshare_del(m->udi);
454    if (m->mount_point) eina_stringshare_del(m->mount_point);
455
456    free(m);
457 }
458
459 EAPI E_Fm2_Mount *
460 e_fm2_device_mount_find(const char *path)
461 {
462    Eina_List *l;
463    E_Volume *v;
464
465    if (!path) return NULL;
466
467    EINA_LIST_FOREACH(_e_vols, l, v)
468      {
469         if (v->mounted
470             && v->mount_point
471             && !strncmp(path, v->mount_point, strlen(v->mount_point))
472             && v->mounts)
473           return eina_list_data_get(v->mounts);
474      }
475    return NULL;
476 }
477
478 EAPI E_Fm2_Mount *
479 e_fm2_device_mount(E_Volume *v,
480                    Ecore_Cb  mount_ok,
481                    Ecore_Cb  mount_fail,
482                    Ecore_Cb  unmount_ok,
483                    Ecore_Cb  unmount_fail,
484                    void     *data)
485 {
486    E_Fm2_Mount *m;
487
488    if (!v) return NULL;
489
490    m = calloc(1, sizeof(E_Fm2_Mount));
491    if (!m) return NULL;
492    m->udi = eina_stringshare_add(v->udi);
493    m->mount_ok = mount_ok;
494    m->mount_fail = mount_fail;
495    m->unmount_ok = unmount_ok;
496    m->unmount_fail = unmount_fail;
497    m->data = data;
498    m->volume = v;
499    m->mounted = v->mounted;
500
501    v->mounts = eina_list_prepend(v->mounts, m);
502
503
504    if (!v->mounted)
505      {
506         //printf("BEGIN MOUNT %p '%s'\n", m, v->mount_point);
507         v->auto_unmount = EINA_TRUE;
508         _e_fm2_client_mount(v->udi, v->mount_point);
509      }
510    else
511      {
512         v->auto_unmount = EINA_FALSE;
513         m->mount_point = eina_stringshare_add(v->mount_point);
514      }
515
516    return m;
517 }
518
519 EAPI void
520 e_fm2_device_mount_fail(E_Volume *v)
521 {
522    E_Fm2_Mount *m;
523
524    v->mounted = EINA_FALSE;
525    if (v->mount_point)
526      {
527         eina_stringshare_del(v->mount_point);
528         v->mount_point = NULL;
529      }
530
531    EINA_LIST_FREE(v->mounts, m)
532      {
533         _e_fm2_device_mount_fail(m);
534         _e_fm2_device_mount_free(m);
535      }
536 }
537
538 EAPI void
539 e_fm2_device_unmount(E_Fm2_Mount *m)
540 {
541    E_Volume *v;
542
543    if (!(v = m->volume)) return;
544    v->mounts = eina_list_remove(v->mounts, m);
545    _e_fm2_device_mount_free(m);
546
547    if (v->auto_unmount && v->mounted && !eina_list_count(v->mounts))
548      {
549         //printf("BEGIN UNMOUNT %p '%s'\n", m, v->udi);
550         _e_fm2_client_unmount(v->udi);
551      }
552 }
553
554 EAPI void
555 e_fm2_device_unmount_fail(E_Volume *v)
556 {
557    Eina_List *l;
558    E_Fm2_Mount *m;
559
560    v->mounted = EINA_TRUE;
561
562    EINA_LIST_FOREACH(v->mounts, l, m)
563      _e_fm2_device_unmount_fail(m);
564 }
565
566 static void
567 _e_fm2_device_mount_ok(E_Fm2_Mount *m)
568 {
569    if (m->mounted) return;
570    m->mounted = EINA_TRUE;
571    if (m->volume)
572      m->mount_point = eina_stringshare_add(m->volume->mount_point);
573    if (m->mount_ok)
574      m->mount_ok(m->data);
575    //printf("MOUNT OK '%s'\n", m->mount_point);
576 }
577
578 static void
579 _e_fm2_device_mount_fail(E_Fm2_Mount *m)
580 {
581    //printf("MOUNT FAIL '%s'\n", m->mount_point);
582    m->mounted = EINA_FALSE;
583    if (m->mount_point)
584      {
585         eina_stringshare_del(m->mount_point);
586         m->mount_point = NULL;
587      }
588    if (m->mount_fail)
589      m->mount_fail(m->data);
590 }
591
592 static void
593 _e_fm2_device_unmount_ok(E_Fm2_Mount *m)
594 {
595    if (!m->mounted) return;
596    m->mounted = EINA_FALSE;
597    if (m->mount_point)
598      {
599         eina_stringshare_del(m->mount_point);
600         m->mount_point = NULL;
601      }
602    if (m->unmount_ok)
603      m->unmount_ok(m->data);
604 }
605
606 static void
607 _e_fm2_device_unmount_fail(E_Fm2_Mount *m)
608 {
609    if (m->mounted) return;
610    m->mounted = EINA_TRUE;
611    if (m->unmount_fail)
612      m->unmount_fail(m->data);
613 }
614
615 EAPI void
616 e_fm2_device_show_desktop_icons(void)
617 {
618    Eina_List *l;
619    E_Volume *v;
620    char buf[PATH_MAX] = {0};
621    char buf2[PATH_MAX] = {0};
622    const char *id;
623
624    EINA_LIST_FOREACH(_e_vols, l, v)
625      {
626         if (!v) continue;
627         if (!v->storage) continue;
628
629         id = ecore_file_file_get(v->storage->udi);
630
631         e_user_dir_snprintf(buf, sizeof(buf),
632                             "fileman/favorites/|%s_%d.desktop",
633                             id, v->partition_number);
634
635         e_user_homedir_snprintf(buf2, sizeof(buf2),
636                                 "%s/|%s_%d.desktop",
637                                 _("Desktop"), id, v->partition_number);
638
639         if (ecore_file_exists(buf) && !ecore_file_exists(buf2))
640           {
641              ecore_file_symlink(buf, buf2);
642              _e_fm2_file_force_update(buf2);
643           }
644      }
645 }
646
647 EAPI void
648 e_fm2_device_hide_desktop_icons(void)
649 {
650    Eina_List *l;
651    E_Volume *v;
652    char buf[PATH_MAX] = {0};
653    const char *id;
654
655    EINA_LIST_FOREACH(_e_vols, l, v)
656      {
657         if (!v) continue;
658         if (!v->storage) continue;
659
660         id = ecore_file_file_get(v->storage->udi);
661
662         e_user_homedir_snprintf(buf, sizeof(buf),
663                                 "%s/|%s_%d.desktop",
664                                 _("Desktop"), id, v->partition_number);
665
666         if (ecore_file_exists(buf))
667           {
668              ecore_file_unlink(buf);
669              _e_fm2_file_force_update(buf);
670           }
671      }
672 }
673
674 EAPI Eina_List *
675 e_fm2_device_volume_list_get(void)
676 {
677    return _e_vols;
678 }