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