Tizen 2.1 release
[platform/core/uifw/e17.git] / src / bin / e_fm / e_fm_main_hal.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #ifdef HAVE_ALLOCA_H
6 # include <alloca.h>
7 #elif defined __GNUC__
8 # define alloca __builtin_alloca
9 #elif defined _AIX
10 # define alloca __alloca
11 #elif defined _MSC_VER
12 # include <malloc.h>
13 # define alloca _alloca
14 #else
15 # include <stddef.h>
16 # ifdef  __cplusplus
17 extern "C"
18 # endif
19 void *alloca(size_t);
20 #endif
21
22 #ifdef __linux__
23 #include <features.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <sys/param.h>
33 #include <utime.h>
34 #include <math.h>
35 #include <fnmatch.h>
36 #include <limits.h>
37 #include <ctype.h>
38 #include <time.h>
39 #include <dirent.h>
40 #include <pwd.h>
41 #include <glob.h>
42 #include <errno.h>
43 #include <signal.h>
44 #include <Ecore.h>
45 #include <Ecore_Ipc.h>
46 #include <Ecore_File.h>
47 #include <Eet.h>
48 #include <E_DBus.h>
49 #include <E_Hal.h>
50
51 #include "e_fm_shared_device.h"
52 #include "e_fm_shared_codec.h"
53 #include "e_fm_ipc.h"
54 #include "e_fm_device.h"
55
56 #include "e_fm_main_hal.h"
57 #ifdef HAVE_UDISKS_MOUNT
58 # include "e_fm_main_udisks.h"
59 #endif
60
61 #include "e_fm_main.h"
62
63 static E_DBus_Signal_Handler *_hal_poll = NULL;
64 static E_DBus_Connection *_e_fm_main_hal_conn = NULL;
65 static Eina_List *_e_stores = NULL;
66
67 static void _e_fm_main_hal_cb_dev_all(void      *user_data,
68                                       void      *reply_data,
69                                       DBusError *error);
70 static void _e_fm_main_hal_cb_dev_store(void      *user_data,
71                                         void      *reply_data,
72                                         DBusError *error);
73 static void _e_fm_main_hal_cb_dev_vol(void      *user_data,
74                                       void      *reply_data,
75                                       DBusError *error);
76 static void _e_fm_main_hal_cb_store_is(void      *user_data,
77                                        void      *reply_data,
78                                        DBusError *error);
79 static void _e_fm_main_hal_cb_vol_is(void      *user_data,
80                                      void      *reply_data,
81                                      DBusError *error);
82 static void _e_fm_main_hal_cb_dev_add(void        *data,
83                                       DBusMessage *msg);
84 static void _e_fm_main_hal_cb_dev_del(void        *data,
85                                       DBusMessage *msg);
86 static void _e_fm_main_hal_cb_cap_add(void        *data,
87                                       DBusMessage *msg);
88 static void _e_fm_main_hal_cb_prop_modified(void        *data,
89                                             DBusMessage *msg);
90 static void _e_fm_main_hal_cb_store_prop(void      *data,
91                                          void      *reply_data,
92                                          DBusError *error);
93 static void _e_fm_main_hal_cb_vol_prop(void      *data,
94                                        void      *reply_data,
95                                        DBusError *error);
96 static void _e_fm_main_hal_cb_vol_prop_mount_modified(void      *data,
97                                                       void      *reply_data,
98                                                       DBusError *error);
99 static void _e_fm_main_hal_cb_vol_mounted(void      *user_data,
100                                           void      *method_return,
101                                           DBusError *error);
102 static void _e_fm_main_hal_cb_vol_unmounted(void      *user_data,
103                                             void      *method_return,
104                                             DBusError *error);
105 static void _e_fm_main_hal_cb_vol_unmounted_before_eject(void      *user_data,
106                                                          void      *method_return,
107                                                          DBusError *error);
108
109 static Eina_Bool _e_fm_main_hal_vb_vol_ejecting_after_unmount(void *data);
110 static void      _e_fm_main_hal_cb_vol_ejected(void      *user_data,
111                                                void      *method_return,
112                                                DBusError *error);
113 static int _e_fm_main_hal_format_error_msg(char     **buf,
114                                            E_Volume  *v,
115                                            DBusError *error);
116 static void _e_fm_main_hal_test(void        *data,
117                                 DBusMessage *msg,
118                                 DBusError   *error);
119 static void _e_fm_main_hal_poll(void        *data,
120                                 DBusMessage *msg);
121
122 static Eina_Bool _e_fm_main_hal_vol_mount_timeout(void *data);
123 static Eina_Bool _e_fm_main_hal_vol_unmount_timeout(void *data);
124 static Eina_Bool _e_fm_main_hal_vol_eject_timeout(void *data);
125
126 static void
127 _e_fm_main_hal_poll(void *data   __UNUSED__,
128                     DBusMessage *msg)
129 {
130    DBusError err;
131    const char *name, *from, *to;
132
133    dbus_error_init(&err);
134    if (!dbus_message_get_args(msg, &err,
135                               DBUS_TYPE_STRING, &name,
136                               DBUS_TYPE_STRING, &from,
137                               DBUS_TYPE_STRING, &to,
138                               DBUS_TYPE_INVALID))
139      dbus_error_free(&err);
140
141    //printf("name: %s\nfrom: %s\nto: %s\n", name, from, to);
142    if ((name) && !strcmp(name, E_HAL_SENDER))
143      _e_fm_main_hal_test(NULL, NULL, NULL);
144 }
145
146 static void
147 _e_fm_main_hal_test(void *data       __UNUSED__,
148                     DBusMessage *msg __UNUSED__,
149                     DBusError       *error)
150 {
151    if ((error) && (dbus_error_is_set(error)))
152      {
153         dbus_error_free(error);
154         if (!_hal_poll)
155           _hal_poll = e_dbus_signal_handler_add(_e_fm_main_hal_conn,
156                                                 E_DBUS_FDO_BUS, E_DBUS_FDO_PATH,
157                                                 E_DBUS_FDO_INTERFACE,
158                                                 "NameOwnerChanged", _e_fm_main_hal_poll, NULL);
159 #ifdef HAVE_UDISKS_MOUNT
160         _e_fm_main_udisks_init(); /* check for udisks while listening for hal */
161 #else
162         _e_fm_main_hal_catch(EINA_FALSE);
163 #endif
164         return;
165      }
166    if (_hal_poll)
167      e_dbus_signal_handler_del(_e_fm_main_hal_conn, _hal_poll);
168
169    e_hal_manager_get_all_devices(_e_fm_main_hal_conn, _e_fm_main_hal_cb_dev_all, NULL);
170    e_hal_manager_find_device_by_capability(_e_fm_main_hal_conn, "storage",
171                                            _e_fm_main_hal_cb_dev_store, NULL);
172    e_hal_manager_find_device_by_capability(_e_fm_main_hal_conn, "volume",
173                                            _e_fm_main_hal_cb_dev_vol, NULL);
174
175    e_dbus_signal_handler_add(_e_fm_main_hal_conn, E_HAL_SENDER,
176                              E_HAL_MANAGER_PATH,
177                              E_HAL_MANAGER_INTERFACE,
178                              "DeviceAdded", _e_fm_main_hal_cb_dev_add, NULL);
179    e_dbus_signal_handler_add(_e_fm_main_hal_conn, E_HAL_SENDER,
180                              E_HAL_MANAGER_PATH,
181                              E_HAL_MANAGER_INTERFACE,
182                              "DeviceRemoved", _e_fm_main_hal_cb_dev_del, NULL);
183    e_dbus_signal_handler_add(_e_fm_main_hal_conn, E_HAL_SENDER,
184                              E_HAL_MANAGER_PATH,
185                              E_HAL_MANAGER_INTERFACE,
186                              "NewCapability", _e_fm_main_hal_cb_cap_add, NULL);
187    _e_fm_main_hal_catch(EINA_TRUE); /* signal usage of HAL for mounting */
188 }
189
190 static void
191 _e_fm_main_hal_cb_dev_all(void *user_data __UNUSED__,
192                           void           *reply_data,
193                           DBusError      *error)
194 {
195    E_Hal_Manager_Get_All_Devices_Return *ret = reply_data;
196    Eina_List *l;
197    char *udi;
198
199    if (!ret || !ret->strings) return;
200
201    if (dbus_error_is_set(error))
202      {
203         dbus_error_free(error);
204         return;
205      }
206
207    EINA_LIST_FOREACH(ret->strings, l, udi)
208      {
209 //      printf("DB INIT DEV+: %s\n", udi);
210           e_hal_device_query_capability(_e_fm_main_hal_conn, udi, "storage",
211                                         _e_fm_main_hal_cb_store_is, (void *)eina_stringshare_add(udi));
212           e_hal_device_query_capability(_e_fm_main_hal_conn, udi, "volume",
213                                         _e_fm_main_hal_cb_vol_is, (void *)eina_stringshare_add(udi));
214      }
215 }
216
217 static void
218 _e_fm_main_hal_cb_dev_store(void *user_data __UNUSED__,
219                             void           *reply_data,
220                             DBusError      *error)
221 {
222    E_Hal_Manager_Find_Device_By_Capability_Return *ret = reply_data;
223    Eina_List *l;
224    char *device;
225
226    if (!ret || !ret->strings) return;
227
228    if (dbus_error_is_set(error))
229      {
230         dbus_error_free(error);
231         return;
232      }
233
234    EINA_LIST_FOREACH(ret->strings, l, device)
235      {
236 //      printf("DB STORE+: %s\n", device);
237           _e_fm_main_hal_storage_add(device);
238      }
239 }
240
241 static void
242 _e_fm_main_hal_cb_dev_vol(void *user_data __UNUSED__,
243                           void           *reply_data,
244                           DBusError      *error)
245 {
246    E_Hal_Manager_Find_Device_By_Capability_Return *ret = reply_data;
247    Eina_List *l;
248    char *device;
249
250    if (!ret || !ret->strings) return;
251
252    if (dbus_error_is_set(error))
253      {
254         dbus_error_free(error);
255         return;
256      }
257
258    EINA_LIST_FOREACH(ret->strings, l, device)
259      {
260 //      printf("DB VOL+: %s\n", device);
261           _e_fm_main_hal_volume_add(device, 1);
262      }
263 }
264
265 static void
266 _e_fm_main_hal_cb_store_is(void      *user_data,
267                            void      *reply_data,
268                            DBusError *error)
269 {
270    char *udi = user_data;
271    E_Hal_Device_Query_Capability_Return *ret = reply_data;
272
273    if (dbus_error_is_set(error))
274      {
275         dbus_error_free(error);
276         goto error;
277      }
278
279    if (ret && ret->boolean)
280      {
281 //      printf("DB STORE IS+: %s\n", udi);
282           _e_fm_main_hal_storage_add(udi);
283      }
284
285 error:
286    eina_stringshare_del(udi);
287 }
288
289 static void
290 _e_fm_main_hal_cb_vol_is(void      *user_data,
291                          void      *reply_data,
292                          DBusError *error)
293 {
294    char *udi = user_data;
295    E_Hal_Device_Query_Capability_Return *ret = reply_data;
296
297    if (dbus_error_is_set(error))
298      {
299         dbus_error_free(error);
300         goto error;
301      }
302
303    if (ret && ret->boolean)
304      {
305 //      printf("DB VOL IS+: %s\n", udi);
306           _e_fm_main_hal_volume_add(udi, 0);
307      }
308
309 error:
310    eina_stringshare_del(udi);
311 }
312
313 static void
314 _e_fm_main_hal_cb_dev_add(void *data   __UNUSED__,
315                           DBusMessage *msg)
316 {
317    DBusError err;
318    char *udi = NULL;
319
320    dbus_error_init(&err);
321    dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &udi, DBUS_TYPE_INVALID);
322    if (!udi) return;
323    e_hal_device_query_capability(_e_fm_main_hal_conn, udi, "storage",
324                                  _e_fm_main_hal_cb_store_is, (void *)eina_stringshare_add(udi));
325    e_hal_device_query_capability(_e_fm_main_hal_conn, udi, "volume",
326                                  _e_fm_main_hal_cb_vol_is, (void *)eina_stringshare_add(udi));
327 }
328
329 static void
330 _e_fm_main_hal_cb_dev_del(void *data   __UNUSED__,
331                           DBusMessage *msg)
332 {
333    DBusError err;
334    char *udi;
335
336    dbus_error_init(&err);
337
338    dbus_message_get_args(msg,
339                          &err, DBUS_TYPE_STRING,
340                          &udi, DBUS_TYPE_INVALID);
341 //   printf("DB DEV-: %s\n", udi);
342    _e_fm_main_hal_storage_del(udi);
343    _e_fm_main_hal_volume_del(udi);
344 }
345
346 static void
347 _e_fm_main_hal_cb_cap_add(void *data   __UNUSED__,
348                           DBusMessage *msg)
349 {
350    DBusError err;
351    char *udi, *capability;
352
353    dbus_error_init(&err);
354
355    dbus_message_get_args(msg,
356                          &err, DBUS_TYPE_STRING,
357                          &udi, DBUS_TYPE_STRING,
358                          &capability, DBUS_TYPE_INVALID);
359    if (!strcmp(capability, "storage"))
360      {
361 //        printf("DB STORE CAP+: %s\n", udi);
362           _e_fm_main_hal_storage_add(udi);
363      }
364 }
365
366 static void
367 _e_fm_main_hal_cb_prop_modified(void        *data,
368                                 DBusMessage *msg)
369 {
370    E_Volume *v;
371    DBusMessageIter iter, sub, subsub;
372    struct
373    {
374       const char *name;
375       int         added;
376       int         removed;
377    } prop;
378    int num_changes = 0, i;
379
380    if (!(v = data)) return;
381
382    if (dbus_message_get_error_name(msg))
383      {
384         printf("DBUS ERROR: %s\n", dbus_message_get_error_name(msg));
385         return;
386      }
387    if (!dbus_message_iter_init(msg, &iter)) return;
388
389    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) return;
390    dbus_message_iter_get_basic(&iter, &num_changes);
391    if (num_changes == 0) return;
392
393    dbus_message_iter_next(&iter);
394    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) return;
395    dbus_message_iter_recurse(&iter, &sub);
396
397    for (i = 0; i < num_changes; i++, dbus_message_iter_next(&sub))
398      {
399         dbus_message_iter_recurse(&sub, &subsub);
400
401         if (dbus_message_iter_get_arg_type(&subsub) != DBUS_TYPE_STRING) break;
402         dbus_message_iter_get_basic(&subsub, &(prop.name));
403         if (!strcmp(prop.name, "volume.mount_point"))
404           {
405              e_hal_device_get_all_properties(_e_fm_main_hal_conn, v->udi,
406                                              _e_fm_main_hal_cb_vol_prop_mount_modified,
407                                              v);
408              return;
409           }
410
411         dbus_message_iter_next(&subsub);
412         dbus_message_iter_next(&subsub);
413      }
414 }
415
416 static void
417 _e_fm_main_hal_cb_store_prop(void      *data,
418                              void      *reply_data,
419                              DBusError *error)
420 {
421    E_Storage *s = data;
422    E_Hal_Properties *ret = reply_data;
423    int err = 0;
424
425    if (!ret) goto error;
426
427    if (dbus_error_is_set(error))
428      {
429         dbus_error_free(error);
430         goto error;
431      }
432
433    s->bus = e_hal_property_string_get(ret, "storage.bus", &err);
434    if (err) goto error;
435    s->bus = eina_stringshare_add(s->bus);
436    s->drive_type = e_hal_property_string_get(ret, "storage.drive_type", &err);
437    if (err) goto error;
438    s->drive_type = eina_stringshare_add(s->drive_type);
439    s->model = e_hal_property_string_get(ret, "storage.model", &err);
440    if (err) goto error;
441    s->model = eina_stringshare_add(s->model);
442    s->vendor = e_hal_property_string_get(ret, "storage.vendor", &err);
443    if (err) goto error;
444    s->vendor = eina_stringshare_add(s->vendor);
445    s->serial = e_hal_property_string_get(ret, "storage.serial", &err);
446 //   if (err) goto error;
447    if (err) printf("Error getting serial for %s\n", s->udi);
448    s->serial = eina_stringshare_add(s->serial);
449
450    s->removable = e_hal_property_bool_get(ret, "storage.removable", &err);
451
452    if (s->removable)
453      {
454         s->media_available = e_hal_property_bool_get(ret, "storage.removable.media_available", &err);
455         s->media_size = e_hal_property_uint64_get(ret, "storage.removable.media_size", &err);
456      }
457
458    s->requires_eject = e_hal_property_bool_get(ret, "storage.requires_eject", &err);
459    s->hotpluggable = e_hal_property_bool_get(ret, "storage.hotpluggable", &err);
460    s->media_check_enabled = e_hal_property_bool_get(ret, "storage.media_check_enabled", &err);
461
462    s->icon.drive = e_hal_property_string_get(ret, "storage.icon.drive", &err);
463    s->icon.drive = eina_stringshare_add(s->icon.drive);
464    s->icon.volume = e_hal_property_string_get(ret, "storage.icon.volume", &err);
465    s->icon.volume = eina_stringshare_add(s->icon.volume);
466
467 //   printf("++STO:\n  udi: %s\n  bus: %s\n  drive_type: %s\n  model: %s\n  vendor: %s\n  serial: %s\n  icon.drive: %s\n  icon.volume: %s\n\n", s->udi, s->bus, s->drive_type, s->model, s->vendor, s->serial, s->icon.drive, s->icon.volume);
468    s->validated = EINA_TRUE;
469    {
470       void *msg_data;
471       int msg_size;
472
473       msg_data = _e_fm_shared_codec_storage_encode(s, &msg_size);
474       if (msg_data)
475         {
476            ecore_ipc_server_send(_e_fm_ipc_server,
477                                  6 /*E_IPC_DOMAIN_FM*/,
478                                  E_FM_OP_STORAGE_ADD,
479                                  0, 0, 0, msg_data, msg_size);
480            free(msg_data);
481         }
482    }
483    return;
484
485 error:
486 //   printf("ERR %s\n", s->udi);
487    _e_fm_main_hal_storage_del(s->udi);
488 }
489
490 static void
491 _e_fm_main_hal_cb_vol_prop(void      *data,
492                            void      *reply_data,
493                            DBusError *error)
494 {
495    E_Volume *v = data;
496    E_Storage *s = NULL;
497    E_Hal_Device_Get_All_Properties_Return *ret = reply_data;
498    int err = 0;
499    const char *str = NULL;
500
501    if (!ret) goto error;
502    if (dbus_error_is_set(error))
503      {
504         dbus_error_free(error);
505         goto error;
506      }
507
508    /* skip volumes with volume.ignore set */
509    if (e_hal_property_bool_get(ret, "volume.ignore", &err) || err)
510      goto error;
511
512    /* skip volumes that aren't filesystems */
513    str = e_hal_property_string_get(ret, "volume.fsusage", &err);
514    if (err || !str) goto error;
515    if (strcmp(str, "filesystem")) goto error;
516    str = NULL;
517
518    v->uuid = e_hal_property_string_get(ret, "volume.uuid", &err);
519    if (err) goto error;
520    v->uuid = eina_stringshare_add(v->uuid);
521
522    v->label = e_hal_property_string_get(ret, "volume.label", &err);
523 //   if (err) goto error;
524    v->label = eina_stringshare_add(v->label);
525
526    v->fstype = e_hal_property_string_get(ret, "volume.fstype", &err);
527 //   if (err) goto error;
528    v->fstype = eina_stringshare_add(v->fstype);
529
530    v->size = e_hal_property_uint64_get(ret, "volume.size", &err);
531
532    v->mounted = e_hal_property_bool_get(ret, "volume.is_mounted", &err);
533    if (err) goto error;
534
535    v->partition = e_hal_property_bool_get(ret, "volume.is_partition", &err);
536    if (err) goto error;
537
538    v->mount_point = e_hal_property_string_get(ret, "volume.mount_point", &err);
539    if (err) goto error;
540    v->mount_point = eina_stringshare_add(v->mount_point);
541
542    if (v->partition)
543      {
544         v->partition_number = e_hal_property_int_get(ret, "volume.partition.number", NULL);
545         v->partition_label = e_hal_property_string_get(ret, "volume.partition.label", NULL);
546         v->partition_label = eina_stringshare_add(v->partition_label);
547      }
548
549    v->parent = e_hal_property_string_get(ret, "info.parent", &err);
550    if ((!err) && (v->parent))
551      {
552         s = e_storage_find(v->parent);
553         if (s)
554           {
555              v->storage = s;
556              s->volumes = eina_list_append(s->volumes, v);
557           }
558      }
559    v->parent = eina_stringshare_add(v->parent);
560
561 //   printf("++VOL:\n  udi: %s\n  uuid: %s\n  fstype: %s\n  size: %llu\n label: %s\n  partition: %d\n  partition_number: %d\n partition_label: %s\n  mounted: %d\n  mount_point: %s\n", v->udi, v->uuid, v->fstype, v->size, v->label, v->partition, v->partition_number, v->partition ? v->partition_label : "(not a partition)", v->mounted, v->mount_point);
562 //   if (s) printf("  for storage: %s\n", s->udi);
563 //   else printf("  storage unknown\n");
564    v->validated = EINA_TRUE;
565    {
566       void *msg_data;
567       int msg_size;
568
569       msg_data = _e_fm_shared_codec_volume_encode(v, &msg_size);
570       if (msg_data)
571         {
572            ecore_ipc_server_send(_e_fm_ipc_server,
573                                  6 /*E_IPC_DOMAIN_FM*/,
574                                  E_FM_OP_VOLUME_ADD,
575                                  0, 0, 0, msg_data, msg_size);
576            free(msg_data);
577         }
578    }
579    return;
580
581 error:
582    _e_fm_main_hal_volume_del(v->udi);
583    return;
584 }
585
586 static int
587 _e_fm_main_hal_format_error_msg(char     **buf,
588                                 E_Volume  *v,
589                                 DBusError *error)
590 {
591    int size, vu, vm, en;
592    char *tmp;
593
594    vu = strlen(v->udi) + 1;
595    vm = strlen(v->mount_point) + 1;
596    en = strlen(error->name) + 1;
597    size = vu + vm + en + strlen(error->message) + 1;
598    tmp = *buf = malloc(size);
599
600    strcpy(tmp, v->udi);
601    tmp += vu;
602    strcpy(tmp, v->mount_point);
603    tmp += vm;
604    strcpy(tmp, error->name);
605    tmp += en;
606    strcpy(tmp, error->message);
607
608    return size;
609 }
610
611 static void
612 _e_fm_main_hal_cb_vol_prop_mount_modified(void      *data,
613                                           void      *reply_data,
614                                           DBusError *error)
615 {
616    E_Volume *v = data;
617    E_Hal_Device_Get_All_Properties_Return *ret = reply_data;
618    int err = 0;
619
620    if (!ret) return;
621    if (dbus_error_is_set(error))
622      {
623         char *buf;
624         int size;
625
626         size = _e_fm_main_hal_format_error_msg(&buf, v, error);
627         if (v->mounted)
628           ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_UNMOUNT_ERROR,
629                                 0, 0, 0, buf, size);
630         else
631           ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_MOUNT_ERROR,
632                                 0, 0, 0, buf, size);
633         dbus_error_free(error);
634         free(buf);
635         return;
636      }
637
638    v->mounted = e_hal_property_bool_get(ret, "volume.is_mounted", &err);
639    if (err) printf("HAL Error : can't get volume.is_mounted property");
640
641    if (v->mount_point) eina_stringshare_del(v->mount_point);
642    v->mount_point = e_hal_property_string_get(ret, "volume.mount_point", &err);
643    if (err) printf("HAL Error : can't get volume.is_mount_point property");
644    v->mount_point = eina_stringshare_add(v->mount_point);
645
646 //   printf("**VOL udi: %s mount_point: %s mounted: %d\n", v->udi, v->mount_point, v->mounted);
647    {
648       char *buf;
649       int size;
650
651       size = strlen(v->udi) + 1 + strlen(v->mount_point) + 1;
652       buf = alloca(size);
653       strcpy(buf, v->udi);
654       strcpy(buf + strlen(buf) + 1, v->mount_point);
655       if (v->mounted)
656         ecore_ipc_server_send(_e_fm_ipc_server,
657                               6 /*E_IPC_DOMAIN_FM*/,
658                               E_FM_OP_MOUNT_DONE,
659                               0, 0, 0, buf, size);
660       else
661         ecore_ipc_server_send(_e_fm_ipc_server,
662                               6 /*E_IPC_DOMAIN_FM*/,
663                               E_FM_OP_UNMOUNT_DONE,
664                               0, 0, 0, buf, size);
665    }
666    return;
667 }
668
669 static Eina_Bool
670 _e_fm_main_hal_vol_mount_timeout(void *data)
671 {
672    E_Volume *v = data;
673    DBusError error;
674    char *buf;
675    int size;
676
677    v->guard = NULL;
678    dbus_pending_call_cancel(v->op);
679    error.name = "org.enlightenment.fm2.MountTimeout";
680    error.message = "Unable to mount the volume with specified time-out.";
681    size = _e_fm_main_hal_format_error_msg(&buf, v, &error);
682    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_MOUNT_ERROR,
683                          0, 0, 0, buf, size);
684    free(buf);
685
686    return ECORE_CALLBACK_CANCEL;
687 }
688
689 static void
690 _e_fm_main_hal_cb_vol_mounted(void               *user_data,
691                               void *method_return __UNUSED__,
692                               DBusError          *error)
693 {
694    E_Volume *v = user_data;
695    char *buf;
696    int size;
697
698    if (v->guard)
699      {
700         ecore_timer_del(v->guard);
701         v->guard = NULL;
702      }
703
704    if (dbus_error_is_set(error))
705      {
706         size = _e_fm_main_hal_format_error_msg(&buf, v, error);
707         ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_MOUNT_ERROR,
708                               0, 0, 0, buf, size);
709         dbus_error_free(error);
710         free(buf);
711         return;
712      }
713
714 #if 0
715    v->mounted = EINA_TRUE;
716 //   printf("MOUNT: %s from %s\n", v->udi, v->mount_point);
717    size = strlen(v->udi) + 1 + strlen(v->mount_point) + 1;
718    buf = alloca(size);
719    strcpy(buf, v->udi);
720    strcpy(buf + strlen(buf) + 1, v->mount_point);
721    ecore_ipc_server_send(_e_fm_ipc_server,
722                          6 /*E_IPC_DOMAIN_FM*/,
723                          E_FM_OP_MOUNT_DONE,
724                          0, 0, 0, buf, size);
725 #endif
726 }
727
728 static Eina_Bool
729 _e_fm_main_hal_vol_unmount_timeout(void *data)
730 {
731    E_Volume *v = data;
732    DBusError error;
733    char *buf;
734    int size;
735
736    v->guard = NULL;
737    dbus_pending_call_cancel(v->op);
738    error.name = "org.enlightenment.fm2.UnmountTimeout";
739    error.message = "Unable to unmount the volume with specified time-out.";
740    size = _e_fm_main_hal_format_error_msg(&buf, v, &error);
741    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_UNMOUNT_ERROR,
742                          0, 0, 0, buf, size);
743    free(buf);
744
745    return ECORE_CALLBACK_CANCEL;
746 }
747
748 static void
749 _e_fm_main_hal_cb_vol_unmounted(void               *user_data,
750                                 void *method_return __UNUSED__,
751                                 DBusError          *error)
752 {
753    E_Volume *v = user_data;
754    char *buf;
755    int size;
756
757    if (v->guard)
758      {
759         ecore_timer_del(v->guard);
760         v->guard = NULL;
761      }
762
763    if (dbus_error_is_set(error))
764      {
765         size = _e_fm_main_hal_format_error_msg(&buf, v, error);
766         ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_UNMOUNT_ERROR,
767                               0, 0, 0, buf, size);
768         dbus_error_free(error);
769         free(buf);
770         return;
771      }
772
773 #if 0
774    v->mounted = EINA_FALSE;
775 //   printf("UNMOUNT: %s from %s\n", v->udi, v->mount_point);
776    size = strlen(v->udi) + 1 + strlen(v->mount_point) + 1;
777    buf = alloca(size);
778    strcpy(buf, v->udi);
779    strcpy(buf + strlen(buf) + 1, v->mount_point);
780    ecore_ipc_server_send(_e_fm_ipc_server,
781                          6 /*E_IPC_DOMAIN_FM*/,
782                          E_FM_OP_UNMOUNT_DONE,
783                          0, 0, 0, buf, size);
784 #endif
785 }
786
787 static Eina_Bool
788 _e_fm_main_hal_vol_eject_timeout(void *data)
789 {
790    E_Volume *v = data;
791    DBusError error;
792    char *buf;
793    int size;
794
795    v->guard = NULL;
796    dbus_pending_call_cancel(v->op);
797    error.name = "org.enlightenment.fm2.EjectTimeout";
798    error.message = "Unable to eject the media with specified time-out.";
799    size = _e_fm_main_hal_format_error_msg(&buf, v, &error);
800    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_EJECT_ERROR,
801                          0, 0, 0, buf, size);
802    free(buf);
803
804    return ECORE_CALLBACK_CANCEL;
805 }
806
807 static Eina_Bool
808 _e_fm_main_hal_vb_vol_ejecting_after_unmount(void *data)
809 {
810    E_Volume *v = data;
811
812    v->guard = ecore_timer_add(E_FM_EJECT_TIMEOUT, _e_fm_main_hal_vol_eject_timeout, v);
813    v->op = e_hal_device_volume_eject(_e_fm_main_hal_conn, v->udi, NULL,
814                                      _e_fm_main_hal_cb_vol_ejected, v);
815
816    return ECORE_CALLBACK_CANCEL;
817 }
818
819 static void
820 _e_fm_main_hal_cb_vol_unmounted_before_eject(void      *user_data,
821                                              void      *method_return,
822                                              DBusError *error)
823 {
824    E_Volume *v = user_data;
825    char err;
826
827    err = dbus_error_is_set(error) ? 1 : 0;
828    _e_fm_main_hal_cb_vol_unmounted(user_data, method_return, error);
829
830    // delay is required for all message handlers were executed after unmount
831    if (!err)
832      ecore_timer_add(1.0, _e_fm_main_hal_vb_vol_ejecting_after_unmount, v);
833 }
834
835 static void
836 _e_fm_main_hal_cb_vol_ejected(void               *user_data,
837                               void *method_return __UNUSED__,
838                               DBusError          *error)
839 {
840    E_Volume *v = user_data;
841    char *buf;
842    int size;
843
844    if (v->guard)
845      {
846         ecore_timer_del(v->guard);
847         v->guard = NULL;
848      }
849
850    if (dbus_error_is_set(error))
851      {
852         size = _e_fm_main_hal_format_error_msg(&buf, v, error);
853         ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_EJECT_ERROR,
854                               0, 0, 0, buf, size);
855         dbus_error_free(error);
856         free(buf);
857         return;
858      }
859
860    size = strlen(v->udi) + 1;
861    buf = alloca(size);
862    strcpy(buf, v->udi);
863    ecore_ipc_server_send(_e_fm_ipc_server,
864                          6 /*E_IPC_DOMAIN_FM*/,
865                          E_FM_OP_EJECT_DONE,
866                          0, 0, 0, buf, size);
867 }
868
869 static Eina_List *_e_vols = NULL;
870
871 E_Volume *
872 _e_fm_main_hal_volume_add(const char *udi,
873                           Eina_Bool   first_time)
874 {
875    E_Volume *v;
876
877    if (!udi) return NULL;
878    if (e_volume_find(udi)) return NULL;
879    v = calloc(1, sizeof(E_Volume));
880    if (!v) return NULL;
881 //   printf("VOL+ %s\n", udi);
882    v->udi = eina_stringshare_add(udi);
883    v->efm_mode = EFM_MODE_USING_HAL_MOUNT;
884    v->icon = NULL;
885    v->first_time = first_time;
886    _e_vols = eina_list_append(_e_vols, v);
887    e_hal_device_get_all_properties(_e_fm_main_hal_conn, v->udi,
888                                    _e_fm_main_hal_cb_vol_prop, v);
889    v->prop_handler = e_dbus_signal_handler_add(_e_fm_main_hal_conn,
890                                                E_HAL_SENDER,
891                                                udi,
892                                                E_HAL_DEVICE_INTERFACE,
893                                                "PropertyModified",
894                                                _e_fm_main_hal_cb_prop_modified, v);
895    v->guard = NULL;
896
897    return v;
898 }
899
900 void
901 _e_fm_main_hal_volume_del(const char *udi)
902 {
903    E_Volume *v;
904
905    v = e_volume_find(udi);
906    if (!v) return;
907    if (v->guard)
908      {
909         ecore_timer_del(v->guard);
910         v->guard = NULL;
911      }
912    if (v->prop_handler) e_dbus_signal_handler_del(_e_fm_main_hal_conn, v->prop_handler);
913    if (v->validated)
914      {
915         //      printf("--VOL %s\n", v->udi);
916         /* FIXME: send event of storage volume (disk) removed */
917            ecore_ipc_server_send(_e_fm_ipc_server,
918                                  6 /*E_IPC_DOMAIN_FM*/,
919                                  E_FM_OP_VOLUME_DEL,
920                                  0, 0, 0, v->udi, eina_stringshare_strlen(v->udi) + 1);
921      }
922    _e_vols = eina_list_remove(_e_vols, v);
923    _e_fm_shared_device_volume_free(v);
924 }
925
926 E_Volume *
927 _e_fm_main_hal_volume_find(const char *udi)
928 {
929    Eina_List *l;
930    E_Volume *v;
931
932    if (!udi) return NULL;
933    EINA_LIST_FOREACH(_e_vols, l, v)
934      {
935         if (!v->udi) continue;
936         if (!strcmp(udi, v->udi)) return v;
937      }
938    return NULL;
939 }
940
941 void
942 _e_fm_main_hal_volume_eject(E_Volume *v)
943 {
944    if (!v || v->guard) return;
945    if (v->mounted)
946      {
947         v->guard = ecore_timer_add(E_FM_UNMOUNT_TIMEOUT, _e_fm_main_hal_vol_unmount_timeout, v);
948         v->op = e_hal_device_volume_unmount(_e_fm_main_hal_conn, v->udi, NULL,
949                                             _e_fm_main_hal_cb_vol_unmounted_before_eject, v);
950      }
951    else
952      {
953         v->guard = ecore_timer_add(E_FM_EJECT_TIMEOUT, _e_fm_main_hal_vol_eject_timeout, v);
954         v->op = e_hal_device_volume_eject(_e_fm_main_hal_conn, v->udi, NULL,
955                                           _e_fm_main_hal_cb_vol_ejected, v);
956      }
957 }
958
959 void
960 _e_fm_main_hal_volume_unmount(E_Volume *v)
961 {
962 //   printf("unmount %s %s\n", v->udi, v->mount_point);
963      if (!v || v->guard) return;
964
965      v->guard = ecore_timer_add(E_FM_UNMOUNT_TIMEOUT, _e_fm_main_hal_vol_unmount_timeout, v);
966      v->op = e_hal_device_volume_unmount(_e_fm_main_hal_conn, v->udi, NULL,
967                                          _e_fm_main_hal_cb_vol_unmounted, v);
968 }
969
970 void
971 _e_fm_main_hal_volume_mount(E_Volume *v)
972 {
973    char buf[256];
974    char buf2[256];
975    const char *mount_point;
976    Eina_List *opt = NULL;
977
978    if ((!v) || (v->guard) || (!v->mount_point) ||
979        (strncmp(v->mount_point, "/media/", 7)))
980      return;
981
982    mount_point = v->mount_point + 7;
983 //   printf("mount %s %s [fs type = %s]\n", v->udi, v->mount_point, v->fstype);
984
985    // for vfat and ntfs we want the uid mapped to the user mounting, if we can
986    if ((!strcmp(v->fstype, "vfat")) ||
987        (!strcmp(v->fstype, "ntfs"))
988        )
989      {
990         snprintf(buf, sizeof(buf), "uid=%i", (int)getuid());
991         opt = eina_list_append(opt, buf);
992      }
993
994    // force utf8 as the encoding - e only likes/handles utf8. its the
995    // pseudo-standard these days anyway for "linux" for intl text to work
996    // everywhere. problem is some fs's use differing options
997    if ((!strcmp(v->fstype, "vfat")) ||
998        (!strcmp(v->fstype, "ntfs")) ||
999        (!strcmp(v->fstype, "iso9660"))
1000        )
1001      {
1002         snprintf(buf2, sizeof(buf2), "utf8");
1003         opt = eina_list_append(opt, buf2);
1004      }
1005    else if ((!strcmp(v->fstype, "fat")) ||
1006             (!strcmp(v->fstype, "jfs")) ||
1007             (!strcmp(v->fstype, "udf"))
1008             )
1009      {
1010         snprintf(buf2, sizeof(buf2), "iocharset=utf8");
1011         opt = eina_list_append(opt, buf2);
1012      }
1013
1014    v->guard = ecore_timer_add(E_FM_MOUNT_TIMEOUT,
1015                               _e_fm_main_hal_vol_mount_timeout, v);
1016    v->op = e_hal_device_volume_mount(_e_fm_main_hal_conn, v->udi, mount_point,
1017                                      v->fstype, opt,
1018                                      _e_fm_main_hal_cb_vol_mounted, v);
1019    eina_list_free(opt);
1020 }
1021
1022 void
1023 _e_fm_main_hal_init(void)
1024 {
1025    e_dbus_init();
1026    e_hal_init();
1027    _e_fm_main_hal_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
1028    /* previously, this assumed that if dbus was running, hal was running. */
1029    if (_e_fm_main_hal_conn)
1030      e_dbus_get_name_owner(_e_fm_main_hal_conn, E_HAL_SENDER, _e_fm_main_hal_test, NULL);
1031 }
1032
1033 void
1034 _e_fm_main_hal_shutdown(void)
1035 {
1036    if (_e_fm_main_hal_conn)
1037      e_dbus_connection_close(_e_fm_main_hal_conn);
1038    e_hal_shutdown();
1039    e_dbus_shutdown();
1040 }
1041
1042 E_Storage *
1043 _e_fm_main_hal_storage_add(const char *udi)
1044 {
1045    E_Storage *s;
1046
1047    if (!udi) return NULL;
1048    if (e_storage_find(udi)) return NULL;
1049    s = calloc(1, sizeof(E_Storage));
1050    if (!s) return NULL;
1051    s->udi = eina_stringshare_add(udi);
1052    _e_stores = eina_list_append(_e_stores, s);
1053    e_hal_device_get_all_properties(_e_fm_main_hal_conn, s->udi,
1054                                    _e_fm_main_hal_cb_store_prop, s);
1055    return s;
1056 }
1057
1058 void
1059 _e_fm_main_hal_storage_del(const char *udi)
1060 {
1061    E_Storage *s;
1062
1063    s = e_storage_find(udi);
1064    if (!s) return;
1065    if (s->validated)
1066      {
1067         //      printf("--STO %s\n", s->udi);
1068           ecore_ipc_server_send(_e_fm_ipc_server,
1069                                 6 /*E_IPC_DOMAIN_FM*/,
1070                                 E_FM_OP_STORAGE_DEL,
1071                                 0, 0, 0, s->udi, strlen(s->udi) + 1);
1072      }
1073    _e_stores = eina_list_remove(_e_stores, s);
1074    _e_fm_shared_device_storage_free(s);
1075 }
1076
1077 E_Storage *
1078 _e_fm_main_hal_storage_find(const char *udi)
1079 {
1080    Eina_List *l;
1081    E_Storage *s;
1082
1083    EINA_LIST_FOREACH(_e_stores, l, s)
1084      {
1085         if (!strcmp(udi, s->udi)) return s;
1086      }
1087    return NULL;
1088 }