update for beta release
[framework/uifw/e17.git] / src / bin / e_fm / e_fm_main_udisks.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_Ukit.h>
50
51 #include "e_fm_main.h"
52 #include "e_fm_main_udisks.h"
53
54 #include "e_fm_shared_codec.h"
55 #include "e_fm_shared_device.h"
56 #include "e_fm_ipc.h"
57 #include "e_fm_device.h"
58
59 static E_DBus_Signal_Handler *_udisks_poll = NULL;
60 static E_DBus_Connection *_e_fm_main_udisks_conn = NULL;
61 static Eina_List *_e_stores = NULL;
62 static Eina_List *_e_vols = NULL;
63
64 static void _e_fm_main_udisks_cb_dev_all(void *user_data __UNUSED__,
65                              E_Ukit_String_List_Return *ret,
66                              DBusError      *error);
67 static void _e_fm_main_udisks_cb_dev_verify(const char *udi,
68                                             E_Ukit_Property *ret,
69                                             DBusError      *error);
70 static void _e_fm_main_udisks_cb_dev_add_verify(const char *udi,
71                              E_Ukit_Property *ret,
72                              DBusError      *error);
73 static void _e_fm_main_udisks_cb_dev_add(void        *data,
74                                          DBusMessage *msg);
75 static void _e_fm_main_udisks_cb_dev_del(void        *data,
76                                          DBusMessage *msg);
77 static void _e_fm_main_udisks_cb_dev_chg(void        *data,
78                                          DBusMessage *msg);
79 static void _e_fm_main_udisks_cb_prop_modified(E_Volume    *v,
80                                    DBusMessage *msg);
81 static void _e_fm_main_udisks_cb_store_prop(E_Storage *s,
82                                 E_Ukit_Properties *ret,
83                                 DBusError *error);
84 static void _e_fm_main_udisks_cb_vol_prop(E_Volume      *v,
85                               E_Ukit_Properties      *ret,
86                               DBusError *error);
87 static void _e_fm_main_udisks_cb_vol_mounted(E_Volume               *v,
88                                  DBusError          *error);
89 static void _e_fm_main_udisks_cb_vol_unmounted(E_Volume               *v,
90                                    DBusError          *error);
91 static void _e_fm_main_udisks_cb_vol_unmounted_before_eject(E_Volume      *v,
92                                                 void      *method_return __UNUSED__,
93                                                 DBusError *error);
94
95 static Eina_Bool _e_fm_main_udisks_cb_vol_ejecting_after_unmount(E_Volume *v);
96 static void      _e_fm_main_udisks_cb_vol_ejected(E_Volume               *v,
97                                  void *method_return __UNUSED__,
98                                  DBusError          *error);
99 static int _e_fm_main_udisks_format_error_msg(char     **buf,
100                                               E_Volume  *v,
101                                               DBusError *error);
102 static void _e_fm_main_udisks_test(void        *data,
103                                    DBusMessage *msg,
104                                    DBusError   *error);
105 static void _e_fm_main_udisks_poll(void        *data,
106                                    DBusMessage *msg);
107
108 static Eina_Bool _e_fm_main_udisks_vol_mount_timeout(E_Volume *v);
109 static Eina_Bool _e_fm_main_udisks_vol_unmount_timeout(E_Volume *v);
110 static Eina_Bool _e_fm_main_udisks_vol_eject_timeout(E_Volume *v);
111
112 static void
113 _e_fm_main_udisks_poll(void *data   __UNUSED__,
114                        DBusMessage *msg)
115 {
116    DBusError err;
117    const char *name, *from, *to;
118
119    dbus_error_init(&err);
120    if (!dbus_message_get_args(msg, &err,
121                               DBUS_TYPE_STRING, &name,
122                               DBUS_TYPE_STRING, &from,
123                               DBUS_TYPE_STRING, &to,
124                               DBUS_TYPE_INVALID))
125      dbus_error_free(&err);
126
127    //printf("name: %s\nfrom: %s\nto: %s\n", name, from, to);
128    if ((name) && !strcmp(name, E_UDISKS_BUS))
129      _e_fm_main_udisks_test(NULL, NULL, NULL);
130 }
131
132 static void
133 _e_fm_main_udisks_test(void *data       __UNUSED__,
134                        DBusMessage *msg __UNUSED__,
135                        DBusError       *error)
136 {
137    if ((error) && (dbus_error_is_set(error)))
138      {
139         dbus_error_free(error);
140         _e_fm_main_udisks_catch(EINA_FALSE);
141         return;
142      }
143    if (_udisks_poll)
144      e_dbus_signal_handler_del(_e_fm_main_udisks_conn, _udisks_poll);
145
146    e_udisks_get_all_devices(_e_fm_main_udisks_conn, (E_DBus_Callback_Func)_e_fm_main_udisks_cb_dev_all, NULL);
147
148    e_dbus_signal_handler_add(_e_fm_main_udisks_conn, E_UDISKS_BUS,
149                              E_UDISKS_PATH,
150                              E_UDISKS_BUS,
151                              "DeviceAdded", (E_DBus_Signal_Cb)_e_fm_main_udisks_cb_dev_add, NULL);
152    e_dbus_signal_handler_add(_e_fm_main_udisks_conn, E_UDISKS_BUS,
153                              E_UDISKS_PATH,
154                              E_UDISKS_BUS,
155                              "DeviceRemoved", (E_DBus_Signal_Cb)_e_fm_main_udisks_cb_dev_del, NULL);
156    e_dbus_signal_handler_add(_e_fm_main_udisks_conn, E_UDISKS_BUS,
157                              E_UDISKS_PATH,
158                              E_UDISKS_BUS,
159                              "DeviceChanged", (E_DBus_Signal_Cb)_e_fm_main_udisks_cb_dev_chg, NULL);
160    _e_fm_main_udisks_catch(EINA_TRUE); /* signal usage of udisks for mounting */
161 }
162
163 static void
164 _e_fm_main_udisks_cb_dev_all(void *user_data __UNUSED__,
165                              E_Ukit_String_List_Return *ret,
166                              DBusError      *error)
167 {
168    Eina_List *l;
169    const char *udi;
170
171    if (!ret || !ret->strings) return;
172
173    if (dbus_error_is_set(error))
174      {
175         dbus_error_free(error);
176         return;
177      }
178
179    EINA_LIST_FOREACH(ret->strings, l, udi)
180      {
181         printf("DB INIT DEV+: %s\n", udi);
182           e_udisks_get_property(_e_fm_main_udisks_conn, udi, "IdUsage",
183                                 (E_DBus_Callback_Func)_e_fm_main_udisks_cb_dev_verify, (void*)eina_stringshare_add(udi));
184      }
185 }
186
187
188 static void
189 _e_fm_main_udisks_cb_dev_verify(const char *udi,
190                              E_Ukit_Property *ret,
191                              DBusError      *error)
192 {
193    if (!ret) return;
194
195    if (dbus_error_is_set(error))
196      {
197         dbus_error_free(error);
198         return;
199      }
200
201    if ((!ret->val.s) || (!ret->val.s[0])) /* storage */
202      _e_fm_main_udisks_storage_add(udi);
203    else if (!strcmp(ret->val.s, "filesystem"))
204      {
205         printf("DB VOL+: %s\n", udi);
206           _e_fm_main_udisks_volume_add(udi, EINA_TRUE);
207      }
208    //eina_stringshare_del(udi);
209 }
210
211 static void
212 _e_fm_main_udisks_cb_dev_add_verify(const char *udi,
213                              E_Ukit_Property *ret,
214                              DBusError      *error)
215 {
216    if (!ret) return;
217
218    if (dbus_error_is_set(error))
219      {
220         dbus_error_free(error);
221         return;
222      }
223
224    if ((!ret->val.s) || (!ret->val.s[0])) /* storage */
225      _e_fm_main_udisks_storage_add(udi);
226    else if (!strcmp(ret->val.s, "filesystem"))
227      {
228         printf("DB VOL+: %s\n", udi);
229           _e_fm_main_udisks_volume_add(udi, EINA_FALSE);
230      }
231    //eina_stringshare_del(udi);
232 }
233
234 static void
235 _e_fm_main_udisks_cb_dev_add(void *data   __UNUSED__,
236                              DBusMessage *msg)
237 {
238    DBusError err;
239    char *udi = NULL;
240
241    dbus_error_init(&err);
242    dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH, &udi, DBUS_TYPE_INVALID);
243    if (!udi) return;
244    e_udisks_get_property(_e_fm_main_udisks_conn, udi, "IdUsage",
245                          (E_DBus_Callback_Func)_e_fm_main_udisks_cb_dev_add_verify, (void*)eina_stringshare_add(udi));
246 }
247
248 static void
249 _e_fm_main_udisks_cb_dev_del(void *data   __UNUSED__,
250                              DBusMessage *msg)
251 {
252    DBusError err;
253    char *udi;
254    E_Volume *v;
255
256    dbus_error_init(&err);
257
258    dbus_message_get_args(msg,
259                          &err, DBUS_TYPE_OBJECT_PATH,
260                          &udi, DBUS_TYPE_INVALID);
261    printf("DB DEV-: %s\n", udi);
262    if ((v = _e_fm_main_udisks_volume_find(udi)))
263      {
264         if (v->optype == E_VOLUME_OP_TYPE_EJECT)
265           _e_fm_main_udisks_cb_vol_ejected(v, msg, &err);  
266      }
267    _e_fm_main_udisks_volume_del(udi);
268    _e_fm_main_udisks_storage_del(udi);
269 }
270
271 static void
272 _e_fm_main_udisks_cb_dev_chg(void *data   __UNUSED__,
273                              DBusMessage *msg)
274 {
275    DBusError err;
276    char *udi;
277
278    dbus_error_init(&err);
279
280    dbus_message_get_args(msg, &err,
281                          DBUS_TYPE_OBJECT_PATH, &udi,
282                          DBUS_TYPE_INVALID);
283
284         printf("DB STORE CAP+: %s\n", udi);
285    e_udisks_get_property(_e_fm_main_udisks_conn, udi, "IdUsage",
286                          (E_DBus_Callback_Func)_e_fm_main_udisks_cb_dev_add_verify, (void*)eina_stringshare_add(udi));
287 }
288
289 static void
290 _e_fm_main_udisks_cb_prop_modified(E_Volume    *v,
291                                    DBusMessage *msg)
292 {
293    if (!v) return;
294
295    if (dbus_message_get_error_name(msg))
296      {
297         printf("DBUS ERROR: %s\n", dbus_message_get_error_name(msg));
298         return;
299      }
300    e_udisks_get_all_properties(_e_fm_main_udisks_conn, v->udi,
301                                       (E_DBus_Callback_Func)_e_fm_main_udisks_cb_vol_prop, v);
302 }
303
304 static void
305 _e_fm_main_udisks_cb_store_prop(E_Storage *s,
306                                 E_Ukit_Properties *ret,
307                                 DBusError *error)
308 {
309    const char *str;
310    int err = 0;
311
312    if (!ret) goto error;
313
314    if (dbus_error_is_set(error))
315      {
316         dbus_error_free(error);
317         goto error;
318      }
319
320    s->bus = e_ukit_property_string_get(ret, "DriveConnectionInterface", &err);
321    if (err) goto error;
322    s->bus = eina_stringshare_add(s->bus);
323    {
324       const Eina_List *l;
325
326       l = e_ukit_property_strlist_get(ret, "DriveMediaCompatibility", &err);
327       if (err) goto error;
328       if (l) s->drive_type = eina_stringshare_add(l->data);
329    }
330    s->model = e_ukit_property_string_get(ret, "DriveModel", &err);
331    if (err) goto error;
332    s->model = eina_stringshare_add(s->model);
333    s->vendor = e_ukit_property_string_get(ret, "DriveVendor", &err);
334    if (err) goto error;
335    s->vendor = eina_stringshare_add(s->vendor);
336    s->serial = e_ukit_property_string_get(ret, "DriveSerial", &err);
337 //   if (err) goto error;
338    if (err) printf("Error getting serial for %s\n", s->udi);
339    s->serial = eina_stringshare_add(s->serial);
340
341    s->removable = e_ukit_property_bool_get(ret, "DeviceIsRemovable", &err);
342    s->system_internal = e_ukit_property_bool_get(ret, "DeviceIsSystemInternal", &err);
343    if (s->system_internal) goto error; /* only track non internal */
344    str = e_ukit_property_string_get(ret, "IdUsage", &err);
345    /* if not of filesystem usage type - skip it  - testing on ubuntu 10.04 */
346    if (!((str) && (!strcmp(str, "filesystem")))) goto error;
347    /* force it to be removable if it passed the above tests */
348    s->removable = EINA_TRUE;
349    
350 // ubuntu 10.04 - only dvd is reported as removable. usb storage and mmcblk
351 // is not - but its not "system internal".   
352 //   if (!s->removable) goto error; /* only track removable media */
353    s->media_available = e_ukit_property_bool_get(ret, "DeviceIsMediaAvailable", &err);
354    s->media_size = e_ukit_property_uint64_get(ret, "DeviceSize", &err);
355
356    s->requires_eject = e_ukit_property_bool_get(ret, "DriveIsMediaEjectable", &err);
357    s->hotpluggable = e_ukit_property_bool_get(ret, "DriveCanDetach", &err);
358    s->media_check_enabled = !e_ukit_property_bool_get(ret, "DeviceIsMediaChangeDetectionInhibited", &err);
359
360    s->icon.drive = e_ukit_property_string_get(ret, "DevicePresentationIconName", &err);
361    if (s->icon.drive && s->icon.drive[0]) s->icon.drive = eina_stringshare_add(s->icon.drive);
362    else s->icon.drive = NULL;
363    s->icon.volume = e_ukit_property_string_get(ret, "DevicePresentationIconName", &err);
364    if (s->icon.volume && s->icon.volume[0]) s->icon.volume = eina_stringshare_add(s->icon.volume);
365    else s->icon.volume = NULL;
366
367 //   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);
368    s->validated = EINA_TRUE;
369    {
370       void *msg_data;
371       int msg_size;
372
373       msg_data = _e_fm_shared_codec_storage_encode(s, &msg_size);
374       if (msg_data)
375         {
376            ecore_ipc_server_send(_e_fm_ipc_server,
377                                  6 /*E_IPC_DOMAIN_FM*/,
378                                  E_FM_OP_STORAGE_ADD,
379                                  0, 0, 0, msg_data, msg_size);
380            free(msg_data);
381         }
382    }
383    return;
384
385 error:
386 //   printf("ERR %s\n", s->udi);
387    _e_fm_main_udisks_storage_del(s->udi);
388 }
389
390 static void
391 _e_fm_main_udisks_cb_vol_prop(E_Volume      *v,
392                               E_Ukit_Properties      *ret,
393                               DBusError *error)
394 {
395    E_Storage *s = NULL;
396    int err = 0;
397    const char *str = NULL;
398
399    if ((!v) || (!ret)) goto error;
400
401    if (dbus_error_is_set(error))
402      {
403         dbus_error_free(error);
404         goto error;
405      }
406
407    if (e_ukit_property_bool_get(ret, "DeviceIsSystemInternal", &err) || err) goto error;
408
409    /* skip volumes with volume.ignore set */
410    if (e_ukit_property_bool_get(ret, "DeviceIsMediaChangeDetectionInhibited", &err) || err)
411      goto error;
412
413    /* skip volumes that aren't filesystems */
414    str = e_ukit_property_string_get(ret, "IdUsage", &err);
415    if (err || !str) goto error;
416    if (strcmp(str, "filesystem"))
417      {
418         if (strcmp(str, "crypto"))
419           v->encrypted = e_ukit_property_bool_get(ret, "DeviceIsLuks", &err);
420
421         if (!v->encrypted)
422           goto error;
423      }
424    str = NULL;
425
426    v->uuid = e_ukit_property_string_get(ret, "IdUuid", &err);
427    if (err) goto error;
428    v->uuid = eina_stringshare_add(v->uuid);
429
430    v->label = e_ukit_property_string_get(ret, "IdLabel", &err);
431    if (!v->label) v->label = e_ukit_property_string_get(ret, "DeviceFile", &err); /* avoid having blank labels */
432    if (!v->label) v->label = v->uuid; /* last resort */
433    v->label = eina_stringshare_add(v->label);
434
435    if (!v->encrypted)
436      {
437         const Eina_List *l;   
438
439         l = e_ukit_property_strlist_get(ret, "DeviceMountPaths", &err);
440         if (err) goto error;
441         if (l) v->mount_point = eina_stringshare_add(l->data);
442
443         v->fstype = e_ukit_property_string_get(ret, "IdType", &err);
444         v->fstype = eina_stringshare_add(v->fstype);
445
446         v->size = e_ukit_property_uint64_get(ret, "DeviceSize", &err);
447
448         v->mounted = e_ukit_property_bool_get(ret, "DeviceIsMounted", &err);
449         if (err) goto error;
450      }
451    else
452      v->unlocked = e_ukit_property_bool_get(ret, "DeviceIsLuksCleartext", &err);
453
454    v->partition = e_ukit_property_bool_get(ret, "DeviceIsPartition", &err);
455    if (err) goto error;
456
457    if (v->partition)
458      {
459         v->partition_number = e_ukit_property_int_get(ret, "PartitionNumber", NULL);
460         v->partition_label = e_ukit_property_string_get(ret, "PartitionLabel", NULL);
461         v->partition_label = eina_stringshare_add(v->partition_label);
462      }
463
464    if (v->unlocked)
465      {
466         const char *enc;
467         E_Volume *venc;
468
469         enc = e_ukit_property_string_get(ret, "LuksCleartextSlave", &err);
470         venc = _e_fm_main_udisks_volume_find(enc);
471         v->parent = venc->parent;
472         v->storage = venc->storage;
473         v->storage->volumes = eina_list_append(v->storage->volumes, v);
474      }
475    else
476      {
477         v->parent = e_ukit_property_string_get(ret, "PartitionSlave", &err);
478           
479         if (!err)
480           {
481              if (v->parent)
482                {
483                   s = e_storage_find(v->parent);
484                   if (s)
485                     {
486                        v->storage = s;
487                        if (!eina_list_data_find_list(s->volumes, v))
488                          s->volumes = eina_list_append(s->volumes, v);
489                     }
490                }
491              else
492                {
493                   v->storage = _e_fm_main_udisks_storage_add(v->udi); /* disk is both storage and volume */
494                   if (v->storage) v->storage->volumes = eina_list_append(v->storage->volumes, v);
495                   v->parent = v->udi;
496                }
497           }
498      }
499    v->parent = eina_stringshare_add(v->parent);
500
501    switch (v->optype)
502      {
503       case E_VOLUME_OP_TYPE_MOUNT:
504         _e_fm_main_udisks_cb_vol_mounted(v, error);
505         return;
506       case E_VOLUME_OP_TYPE_UNMOUNT:
507         _e_fm_main_udisks_cb_vol_unmounted(v, error);
508         return;
509       case E_VOLUME_OP_TYPE_EJECT:
510         _e_fm_main_udisks_cb_vol_unmounted_before_eject(v, NULL, error);
511         return;
512       default:
513         break;
514      }
515
516 //   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);
517 //   if (s) printf("  for storage: %s\n", s->udi);
518 //   else printf("  storage unknown\n");
519    v->validated = EINA_TRUE;
520    {
521       void *msg_data;
522       int msg_size;
523
524       msg_data = _e_fm_shared_codec_volume_encode(v, &msg_size);
525       if (msg_data)
526         {
527            ecore_ipc_server_send(_e_fm_ipc_server,
528                                  6 /*E_IPC_DOMAIN_FM*/,
529                                  E_FM_OP_VOLUME_ADD,
530                                  0, 0, 0, msg_data, msg_size);
531            free(msg_data);
532         }
533    }
534    return;
535
536 error:
537    if (v) _e_fm_main_udisks_volume_del(v->udi);
538    return;
539 }
540
541 static int
542 _e_fm_main_udisks_format_error_msg(char     **buf,
543                                    E_Volume  *v,
544                                    DBusError *error)
545 {
546    int size, vu, vm, en;
547    char *tmp;
548
549    vu = strlen(v->udi) + 1;
550    vm = strlen(v->mount_point) + 1;
551    en = strlen(error->name) + 1;
552    size = vu + vm + en + strlen(error->message) + 1;
553    tmp = *buf = malloc(size);
554
555    strcpy(tmp, v->udi);
556    tmp += vu;
557    strcpy(tmp, v->mount_point);
558    tmp += vm;
559    strcpy(tmp, error->name);
560    tmp += en;
561    strcpy(tmp, error->message);
562
563    return size;
564 }
565
566 static Eina_Bool
567 _e_fm_main_udisks_vol_mount_timeout(E_Volume *v)
568 {
569    DBusError error;
570    char *buf;
571    int size;
572
573    v->guard = NULL;
574    dbus_pending_call_cancel(v->op);
575    v->op = NULL;
576    v->optype = E_VOLUME_OP_TYPE_NONE;
577    error.name = "org.enlightenment.fm2.MountTimeout";
578    error.message = "Unable to mount the volume with specified time-out.";
579    size = _e_fm_main_udisks_format_error_msg(&buf, v, &error);
580    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_MOUNT_ERROR,
581                          0, 0, 0, buf, size);
582    free(buf);
583
584    return ECORE_CALLBACK_CANCEL;
585 }
586
587 static void
588 _e_fm_main_udisks_cb_vol_mounted(E_Volume               *v,
589                                  DBusError          *error)
590 {
591    char *buf;
592    int size;
593
594    if (v->guard)
595      {
596         ecore_timer_del(v->guard);
597         v->guard = NULL;
598      }
599
600    if (error && dbus_error_is_set(error))
601      {
602         size = _e_fm_main_udisks_format_error_msg(&buf, v, error);
603         ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_MOUNT_ERROR,
604                               0, 0, 0, buf, size);
605         dbus_error_free(error);
606         free(buf);
607         v->optype = E_VOLUME_OP_TYPE_NONE;
608         return;
609      }
610    if (!v->mount_point) return; /* come back later */
611
612    v->optype = E_VOLUME_OP_TYPE_NONE;
613    v->op = NULL;
614    v->mounted = EINA_TRUE;
615 //   printf("MOUNT: %s from %s\n", v->udi, v->mount_point);
616    size = strlen(v->udi) + 1 + strlen(v->mount_point) + 1;
617    buf = alloca(size);
618    strcpy(buf, v->udi);
619    strcpy(buf + strlen(buf) + 1, v->mount_point);
620    ecore_ipc_server_send(_e_fm_ipc_server,
621                          6 /*E_IPC_DOMAIN_FM*/,
622                          E_FM_OP_MOUNT_DONE,
623                          0, 0, 0, buf, size);
624 }
625
626 static Eina_Bool
627 _e_fm_main_udisks_vol_unmount_timeout(E_Volume *v)
628 {
629    DBusError error;
630    char *buf;
631    int size;
632
633    v->guard = NULL;
634    dbus_pending_call_cancel(v->op);
635    v->op = NULL;
636    v->optype = E_VOLUME_OP_TYPE_NONE;
637    error.name = "org.enlightenment.fm2.UnmountTimeout";
638    error.message = "Unable to unmount the volume with specified time-out.";
639    size = _e_fm_main_udisks_format_error_msg(&buf, v, &error);
640    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_UNMOUNT_ERROR,
641                          0, 0, 0, buf, size);
642    free(buf);
643
644    return ECORE_CALLBACK_CANCEL;
645 }
646
647 static void
648 _e_fm_main_udisks_cb_vol_unmounted(E_Volume               *v,
649                                    DBusError          *error)
650 {
651    char *buf;
652    int size;
653
654    if (v->guard)
655      {
656         ecore_timer_del(v->guard);
657         v->guard = NULL;
658      }
659
660    if (v->optype != E_VOLUME_OP_TYPE_EJECT)
661      {
662         v->optype = E_VOLUME_OP_TYPE_NONE;
663         v->op = NULL;
664      }
665    if (dbus_error_is_set(error))
666      {
667         size = _e_fm_main_udisks_format_error_msg(&buf, v, error);
668         ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_UNMOUNT_ERROR,
669                               0, 0, 0, buf, size);
670         dbus_error_free(error);
671         free(buf);
672         return;
673      }
674
675    v->mounted = EINA_FALSE;
676 //   printf("UNMOUNT: %s from %s\n", v->udi, v->mount_point);
677    size = strlen(v->udi) + 1 + strlen(v->mount_point) + 1;
678    buf = alloca(size);
679    strcpy(buf, v->udi);
680    strcpy(buf + strlen(buf) + 1, v->mount_point);
681    ecore_ipc_server_send(_e_fm_ipc_server,
682                          6 /*E_IPC_DOMAIN_FM*/,
683                          E_FM_OP_UNMOUNT_DONE,
684                          0, 0, 0, buf, size);
685 }
686
687 static Eina_Bool
688 _e_fm_main_udisks_vol_eject_timeout(E_Volume *v)
689 {
690    DBusError error;
691    char *buf;
692    int size;
693
694    v->guard = NULL;
695    dbus_pending_call_cancel(v->op);
696    v->op = NULL;
697    v->optype = E_VOLUME_OP_TYPE_NONE;
698    error.name = "org.enlightenment.fm2.EjectTimeout";
699    error.message = "Unable to eject the media with specified time-out.";
700    size = _e_fm_main_udisks_format_error_msg(&buf, v, &error);
701    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_EJECT_ERROR,
702                          0, 0, 0, buf, size);
703    free(buf);
704
705    return ECORE_CALLBACK_CANCEL;
706 }
707
708 static Eina_Bool
709 _e_fm_main_udisks_cb_vol_ejecting_after_unmount(E_Volume *v)
710 {
711    v->guard = ecore_timer_add(E_FM_EJECT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_eject_timeout, v);
712    v->op = e_udisks_volume_eject(_e_fm_main_udisks_conn, v->udi, NULL);
713
714    return ECORE_CALLBACK_CANCEL;
715 }
716
717 static void
718 _e_fm_main_udisks_cb_vol_unmounted_before_eject(E_Volume      *v,
719                                                 void      *method_return __UNUSED__,
720                                                 DBusError *error)
721 {
722    Eina_Bool err;
723
724    err = !!dbus_error_is_set(error);
725    _e_fm_main_udisks_cb_vol_unmounted(v, error);
726
727    // delay is required for all message handlers were executed after unmount
728    if (!err)
729      ecore_timer_add(1.0, (Ecore_Task_Cb)_e_fm_main_udisks_cb_vol_ejecting_after_unmount, v);
730 }
731
732 static void
733 _e_fm_main_udisks_cb_vol_ejected(E_Volume               *v,
734                                  void *method_return __UNUSED__,
735                                  DBusError          *error)
736 {
737    char *buf;
738    int size;
739
740    if (v->guard)
741      {
742         ecore_timer_del(v->guard);
743         v->guard = NULL;
744      }
745
746    v->optype = E_VOLUME_OP_TYPE_NONE;
747    v->op = NULL;
748    if (dbus_error_is_set(error))
749      {
750         size = _e_fm_main_udisks_format_error_msg(&buf, v, error);
751         ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_EJECT_ERROR,
752                               0, 0, 0, buf, size);
753         dbus_error_free(error);
754         free(buf);
755         return;
756      }
757
758    size = strlen(v->udi) + 1;
759    buf = alloca(size);
760    strcpy(buf, v->udi);
761    ecore_ipc_server_send(_e_fm_ipc_server,
762                          6 /*E_IPC_DOMAIN_FM*/,
763                          E_FM_OP_EJECT_DONE,
764                          0, 0, 0, buf, size);
765 }
766
767 E_Volume *
768 _e_fm_main_udisks_volume_add(const char *udi,
769                              Eina_Bool   first_time)
770 {
771    E_Volume *v;
772
773    if (!udi) return NULL;
774    if (e_volume_find(udi)) return NULL;
775    v = calloc(1, sizeof(E_Volume));
776    if (!v) return NULL;
777 //   printf("VOL+ %s\n", udi);
778    v->efm_mode = EFM_MODE_USING_UDISKS_MOUNT;
779    v->udi = eina_stringshare_add(udi);
780    v->icon = NULL;
781    v->first_time = first_time;
782    _e_vols = eina_list_append(_e_vols, v);
783    e_udisks_get_all_properties(_e_fm_main_udisks_conn, v->udi,
784                                       (E_DBus_Callback_Func)_e_fm_main_udisks_cb_vol_prop, v);
785    v->prop_handler = e_dbus_signal_handler_add(_e_fm_main_udisks_conn,
786                                                E_UDISKS_BUS,
787                                                udi,
788                                                E_UDISKS_INTERFACE,
789                                                "Changed",
790                                                (E_DBus_Signal_Cb)_e_fm_main_udisks_cb_prop_modified, v);
791    v->guard = NULL;
792
793    return v;
794 }
795
796 void
797 _e_fm_main_udisks_volume_del(const char *udi)
798 {
799    E_Volume *v;
800
801    v = e_volume_find(udi);
802    if (!v) return;
803    if (v->guard)
804      {
805         ecore_timer_del(v->guard);
806         v->guard = NULL;
807      }
808    if (v->prop_handler) e_dbus_signal_handler_del(_e_fm_main_udisks_conn, v->prop_handler);
809    if (v->validated)
810      {
811         //      printf("--VOL %s\n", v->udi);
812         /* FIXME: send event of storage volume (disk) removed */
813            ecore_ipc_server_send(_e_fm_ipc_server,
814                                  6 /*E_IPC_DOMAIN_FM*/,
815                                  E_FM_OP_VOLUME_DEL,
816                                  0, 0, 0, v->udi, eina_stringshare_strlen(v->udi) + 1);
817      }
818    _e_vols = eina_list_remove(_e_vols, v);
819    _e_fm_shared_device_volume_free(v);
820 }
821
822 E_Volume *
823 _e_fm_main_udisks_volume_find(const char *udi)
824 {
825    Eina_List *l;
826    E_Volume *v;
827
828    if (!udi) return NULL;
829    EINA_LIST_FOREACH(_e_vols, l, v)
830      {
831         if (!v->udi) continue;
832         if (!strcmp(udi, v->udi)) return v;
833      }
834    return NULL;
835 }
836
837 void
838 _e_fm_main_udisks_volume_eject(E_Volume *v)
839 {
840    if (!v || v->guard) return;
841    if (v->mounted)
842      {
843         v->guard = ecore_timer_add(E_FM_UNMOUNT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_unmount_timeout, v);
844         v->op = e_udisks_volume_unmount(_e_fm_main_udisks_conn, v->udi, NULL);
845      }
846    else
847      {
848         v->guard = ecore_timer_add(E_FM_EJECT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_eject_timeout, v);
849         v->op = e_udisks_volume_eject(_e_fm_main_udisks_conn, v->udi, NULL);
850      }
851    v->optype = E_VOLUME_OP_TYPE_EJECT;
852 }
853
854 void
855 _e_fm_main_udisks_volume_unmount(E_Volume *v)
856 {
857 //   printf("unmount %s %s\n", v->udi, v->mount_point);
858      if (!v || v->guard) return;
859
860      v->guard = ecore_timer_add(E_FM_UNMOUNT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_unmount_timeout, v);
861      v->op = e_udisks_volume_unmount(_e_fm_main_udisks_conn, v->udi, NULL);
862      v->optype = E_VOLUME_OP_TYPE_UNMOUNT;
863 }
864
865 void
866 _e_fm_main_udisks_volume_mount(E_Volume *v)
867 {
868    char buf[256];
869    char buf2[256];
870    Eina_List *opt = NULL;
871
872    if ((!v) || (v->guard))
873      return;
874
875 //   printf("mount %s %s [fs type = %s]\n", v->udi, v->mount_point, v->fstype);
876
877    // for vfat and ntfs we want the uid mapped to the user mounting, if we can
878    if ((!strcmp(v->fstype, "vfat")) ||
879        (!strcmp(v->fstype, "ntfs"))
880        )
881      {
882         snprintf(buf, sizeof(buf), "uid=%i", (int)getuid());
883         opt = eina_list_append(opt, buf);
884      }
885
886    // force utf8 as the encoding - e only likes/handles utf8. its the
887    // pseudo-standard these days anyway for "linux" for intl text to work
888    // everywhere. problem is some fs's use differing options
889    if ((!strcmp(v->fstype, "vfat")) ||
890        (!strcmp(v->fstype, "ntfs")) ||
891        (!strcmp(v->fstype, "iso9660"))
892        )
893      {
894         snprintf(buf2, sizeof(buf2), "utf8");
895         opt = eina_list_append(opt, buf2);
896      }
897    else if ((!strcmp(v->fstype, "fat")) ||
898             (!strcmp(v->fstype, "jfs")) ||
899             (!strcmp(v->fstype, "udf"))
900             )
901      {
902         snprintf(buf2, sizeof(buf2), "iocharset=utf8");
903         opt = eina_list_append(opt, buf2);
904      }
905
906    v->guard = ecore_timer_add(E_FM_MOUNT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_mount_timeout, v);
907 // on ubuntu 10.04 if we request mount with opt - it fails. unknown why right
908 // now, but lets try without and maybe we need to try 2 mounts - one with
909 // opts and one without?   
910 //   v->op = e_udisks_volume_mount(_e_fm_main_udisks_conn, v->udi,
911 //                                        v->fstype, opt);
912    v->op = e_udisks_volume_mount(_e_fm_main_udisks_conn, v->udi,
913                                         v->fstype, NULL);
914    eina_list_free(opt);
915    v->optype = E_VOLUME_OP_TYPE_MOUNT;
916 }
917
918 void
919 _e_fm_main_udisks_init(void)
920 {
921    DBusMessage *msg;
922
923    e_dbus_init();
924    e_ukit_init();
925    _e_fm_main_udisks_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
926    if (!_e_fm_main_udisks_conn) return;
927    if (!_udisks_poll)
928      _udisks_poll = e_dbus_signal_handler_add(_e_fm_main_udisks_conn,
929                                               E_DBUS_FDO_BUS, E_DBUS_FDO_PATH,
930                                               E_DBUS_FDO_INTERFACE,
931                                               "NameOwnerChanged", _e_fm_main_udisks_poll, NULL);
932
933    e_dbus_get_name_owner(_e_fm_main_udisks_conn, E_UDISKS_BUS, _e_fm_main_udisks_test, NULL); /* test for already running udisks */
934    msg = dbus_message_new_method_call(E_UDISKS_BUS, E_UDISKS_PATH, E_UDISKS_BUS, "suuuuuup");
935    e_dbus_method_call_send(_e_fm_main_udisks_conn, msg, NULL, (E_DBus_Callback_Func)_e_fm_main_udisks_test, NULL, -1, NULL); /* test for not running udisks */
936    dbus_message_unref(msg);
937 }
938
939 void
940 _e_fm_main_udisks_shutdown(void)
941 {
942    if (_e_fm_main_udisks_conn)
943      e_dbus_connection_close(_e_fm_main_udisks_conn);
944    e_ukit_shutdown();
945    e_dbus_shutdown();
946 }
947
948 E_Storage *
949 _e_fm_main_udisks_storage_add(const char *udi)
950 {
951    E_Storage *s;
952
953    if (!udi) return NULL;
954    if (e_storage_find(udi)) return NULL;
955    s = calloc(1, sizeof(E_Storage));
956    if (!s) return NULL;
957    s->udi = eina_stringshare_add(udi);
958    _e_stores = eina_list_append(_e_stores, s);
959    e_udisks_get_all_properties(_e_fm_main_udisks_conn, s->udi,
960                                       (E_DBus_Callback_Func)_e_fm_main_udisks_cb_store_prop, s);
961    return s;
962 }
963
964 void
965 _e_fm_main_udisks_storage_del(const char *udi)
966 {
967    E_Storage *s;
968
969    s = e_storage_find(udi);
970    if (!s) return;
971    if (s->validated)
972      {
973 //        printf("--STO %s\n", s->udi);
974           ecore_ipc_server_send(_e_fm_ipc_server,
975                                 6 /*E_IPC_DOMAIN_FM*/,
976                                 E_FM_OP_STORAGE_DEL,
977                                 0, 0, 0, s->udi, strlen(s->udi) + 1);
978      }
979    _e_stores = eina_list_remove(_e_stores, s);
980    _e_fm_shared_device_storage_free(s);
981 }
982
983 E_Storage *
984 _e_fm_main_udisks_storage_find(const char *udi)
985 {
986    Eina_List *l;
987    E_Storage *s;
988
989    EINA_LIST_FOREACH(_e_stores, l, s)
990      {
991         if (!strcmp(udi, s->udi)) return s;
992      }
993    return NULL;
994 }
995