Tizen 2.1 release
[platform/core/uifw/e17.git] / src / modules / fileman / e_mod_dbus.c
1 #include "e.h"
2 #include "e_mod_main.h"
3 #include "e_mod_dbus.h"
4
5 static const char E_FILEMAN_BUS_NAME[] = "org.enlightenment.FileManager";
6 static const char E_FILEMAN_INTERFACE[] = "org.enlightenment.FileManager";
7 static const char E_FILEMAN_ERROR[] = "org.enlightenment.FileManager.Error";
8 static const char E_FILEMAN_PATH[] = "/org/enlightenment/FileManager";
9
10 typedef struct _E_Fileman_DBus_Daemon E_Fileman_DBus_Daemon;
11 struct _E_Fileman_DBus_Daemon
12 {
13    E_DBus_Connection *conn;
14    E_DBus_Interface  *iface;
15    E_DBus_Object     *obj;
16
17    struct
18    {
19       DBusPendingCall *request_name;
20    } pending;
21 };
22
23 static DBusMessage *
24 _e_fileman_dbus_daemon_error(DBusMessage *message,
25                              const char  *msg)
26 {
27    return dbus_message_new_error(message, E_FILEMAN_ERROR, msg);
28 }
29
30 static void
31 _e_fileman_dbus_daemon_object_init(E_Fileman_DBus_Daemon *d)
32 {
33    if (d->obj) return;
34
35    d->obj = e_dbus_object_add(d->conn, E_FILEMAN_PATH, d);
36    if (!d->obj)
37      {
38         fprintf(stderr, "ERROR: cannot add object to %s\n", E_FILEMAN_PATH);
39         return;
40      }
41
42    e_dbus_object_interface_attach(d->obj, d->iface);
43 }
44
45 static void
46 _e_fileman_dbus_daemon_free(E_Fileman_DBus_Daemon *d)
47 {
48    if (d->pending.request_name)
49      dbus_pending_call_cancel(d->pending.request_name);
50
51    if (d->obj)
52      {
53         e_dbus_object_interface_detach(d->obj, d->iface);
54         e_dbus_object_free(d->obj);
55      }
56
57    if (d->iface)
58      e_dbus_interface_unref(d->iface);
59
60    if (d->conn)
61      e_dbus_connection_close(d->conn);
62
63    free(d);
64 }
65
66 static DBusMessage *
67 _e_fileman_dbus_daemon_open_directory_cb(E_DBus_Object *obj __UNUSED__,
68                                          DBusMessage       *message)
69 {
70    DBusMessageIter itr;
71    const char *directory = NULL, *p;
72    char *dev, *to_free = NULL;
73    E_Zone *zone;
74
75    dbus_message_iter_init(message, &itr);
76    dbus_message_iter_get_basic(&itr, &directory);
77
78    if ((!directory) || (directory[0] == '\0'))
79      return _e_fileman_dbus_daemon_error(message, "no directory provided.");
80
81    zone = e_util_zone_current_get(e_manager_current_get());
82    if (!zone)
83      return _e_fileman_dbus_daemon_error(message, "could not find a zone.");
84
85    if (strstr(directory, "://"))
86      {
87         Efreet_Uri *uri = efreet_uri_decode(directory);
88
89         directory = NULL;
90         if (uri)
91           {
92              if ((uri->protocol) && (strcmp(uri->protocol, "file") == 0))
93                directory = to_free = strdup(uri->path);
94              efreet_uri_free(uri);
95           }
96
97         if (!directory)
98           return _e_fileman_dbus_daemon_error(message, "unsupported protocol");
99      }
100
101    p = strchr(directory, '/');
102    if (p)
103      {
104         int len = p - directory + 1;
105
106         dev = malloc(len + 1);
107         if (!dev)
108           {
109              free(to_free);
110              return _e_fileman_dbus_daemon_error(message,
111                                                  "could not allocate memory.");
112           }
113
114         memcpy(dev, directory, len);
115         dev[len] = '\0';
116
117         if ((dev[0] != '/') && (dev[0] != '~'))
118           dev[len - 1] = '\0';  /* remove trailing '/' */
119
120         directory += p - directory;
121      }
122    else
123      {
124         dev = strdup(directory);
125         directory = "/";
126      }
127
128    e_fwin_new(zone->container, dev, directory);
129    free(dev);
130    free(to_free);
131    return dbus_message_new_method_return(message);
132 }
133
134 static Eina_Bool
135 _mime_shell_script_check(const char *mime)
136 {
137    static const struct sh_script_map {
138       const char *str;
139       size_t len;
140    } options[] = {
141 #define O(x) {x, sizeof(x) - 1}
142      O("application/x-sh"),
143      O("application/x-shellscript"),
144      O("text/x-sh"),
145 #undef O
146      {NULL, 0}
147    };
148    const struct sh_script_map *itr;
149    size_t mimelen = strlen(mime);
150
151    for (itr = options; itr->str != NULL; itr++)
152      if ((mimelen == itr->len) && (memcmp(mime, itr->str, mimelen) == 0))
153        return EINA_TRUE;
154
155    return EINA_FALSE;
156 }
157
158 static DBusMessage *
159 _e_fileman_dbus_daemon_open_file_cb(E_DBus_Object *obj __UNUSED__,
160                                     DBusMessage       *message)
161 {
162    DBusMessageIter itr;
163    Eina_List *handlers;
164    const char *param_file = NULL, *mime, *errmsg = "unknow error";
165    char *real_file, *to_free = NULL;
166    E_Zone *zone;
167
168    dbus_message_iter_init(message, &itr);
169    dbus_message_iter_get_basic(&itr, &param_file);
170
171    if ((!param_file) || (param_file[0] == '\0'))
172      return _e_fileman_dbus_daemon_error(message, "no file provided.");
173
174    zone = e_util_zone_current_get(e_manager_current_get());
175    if (!zone)
176      return _e_fileman_dbus_daemon_error(message, "could not find a zone.");
177
178    if (!strstr(param_file, "://"))
179      {
180         real_file = ecore_file_realpath(param_file);
181         if (!real_file)
182           {
183              errmsg = "couldn't get realpath for file.";
184              goto error;
185           }
186      }
187    else
188      {
189         Efreet_Uri *uri = efreet_uri_decode(param_file);
190
191         real_file = NULL;
192         if (uri)
193           {
194              if ((uri->protocol) && (strcmp(uri->protocol, "file") == 0))
195                {
196                   real_file = ecore_file_realpath(uri->path);
197                   param_file = to_free = strdup(uri->path);
198                }
199              efreet_uri_free(uri);
200           }
201
202         if (!real_file)
203           {
204              errmsg = "unsupported protocol";
205              goto error;
206           }
207      }
208
209    mime = efreet_mime_type_get(real_file);
210    if (!mime)
211      {
212         errmsg = "couldn't find mime-type";
213         goto error;
214      }
215
216    if (strcmp(mime, "application/x-desktop") == 0)
217      {
218         Efreet_Desktop *desktop = efreet_desktop_new(real_file);
219         if (!desktop)
220           {
221              errmsg = "couldn't open desktop file";
222              goto error;
223           }
224
225         e_exec(zone, desktop, NULL, NULL, NULL);
226         efreet_desktop_free(desktop);
227         goto end;
228      }
229    else if ((strcmp(mime, "application/x-executable") == 0) ||
230             ecore_file_can_exec(param_file))
231      {
232         e_exec(zone, NULL, param_file, NULL, NULL);
233         goto end;
234      }
235    else if (_mime_shell_script_check(mime))
236      {
237         Eina_Strbuf *b = eina_strbuf_new();
238         const char *shell = getenv("SHELL");
239         if (!shell)
240           {
241              uid_t uid = getuid();
242              struct passwd *pw = getpwuid(uid);
243              if (pw) shell = pw->pw_shell;
244           }
245         if (!shell) shell = "/bin/sh";
246         eina_strbuf_append_printf(b, "%s %s %s",
247                                   e_config->exebuf_term_cmd,
248                                   shell,
249                                   param_file);
250         e_exec(zone, NULL, eina_strbuf_string_get(b), NULL, NULL);
251         eina_strbuf_free(b);
252         goto end;
253      }
254
255    handlers = efreet_util_desktop_mime_list(mime);
256    if (!handlers)
257      {
258         errmsg = "no handlers for given file";
259         goto end;
260      }
261    else
262      {
263         Efreet_Desktop *desktop = handlers->data;
264         Eina_List *files = eina_list_append(NULL, param_file);
265
266         e_exec(zone, desktop, NULL, files, NULL);
267         eina_list_free(files);
268
269         EINA_LIST_FREE(handlers, desktop)
270           efreet_desktop_free(desktop);
271      }
272
273  end:
274    free(real_file);
275    free(to_free);
276    return dbus_message_new_method_return(message);
277
278  error:
279    free(real_file);
280    free(to_free);
281    return _e_fileman_dbus_daemon_error(message, errmsg);
282 }
283
284 static void
285 _e_fileman_dbus_daemon_request_name_cb(void        *data,
286                                        DBusMessage *msg,
287                                        DBusError   *err)
288 {
289    E_Fileman_DBus_Daemon *d = data;
290    dbus_uint32_t ret;
291    DBusError new_err;
292
293    d->pending.request_name = NULL;
294
295    if (dbus_error_is_set(err))
296      {
297         fprintf(stderr, "ERROR: FILEMAN: RequestName failed: %s\n",
298                 err->message);
299         dbus_error_free(err);
300         return;
301      }
302
303    dbus_error_init(&new_err);
304    dbus_message_get_args(msg, &new_err, DBUS_TYPE_UINT32, &ret,
305                          DBUS_TYPE_INVALID);
306
307    if (dbus_error_is_set(&new_err))
308      {
309         fprintf(stderr,
310                 "ERROR: FILEMAN: could not get arguments of RequestName: %s\n",
311                 new_err.message);
312         dbus_error_free(&new_err);
313         return;
314      }
315
316    switch (ret)
317      {
318       case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
319       case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
320         _e_fileman_dbus_daemon_object_init(d);
321         break;
322
323       case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
324         //XXX mark daemon as queued?
325         break;
326
327       case DBUS_REQUEST_NAME_REPLY_EXISTS:
328         //XXX exit?
329         break;
330      }
331 }
332
333 static E_Fileman_DBus_Daemon *
334 _e_fileman_dbus_daemon_new(void)
335 {
336    const struct
337    {
338       const char      *method;
339       const char      *signature;
340       const char      *ret_signature;
341       E_DBus_Method_Cb func;
342    } *itr, desc[] = {
343       {"OpenDirectory", "s", "", _e_fileman_dbus_daemon_open_directory_cb},
344       {"OpenFile", "s", "", _e_fileman_dbus_daemon_open_file_cb},
345       {NULL, NULL, NULL, NULL}
346    };
347    E_Fileman_DBus_Daemon *d;
348
349    d = calloc(1, sizeof(*d));
350    if (!d)
351      {
352         perror("ERROR: FILEMAN: cannot allocate fileman dbus daemon memory.");
353         return NULL;
354      }
355
356    d->conn = e_dbus_bus_get(DBUS_BUS_SESSION);
357    if (!d->conn)
358      goto error;
359
360    d->iface = e_dbus_interface_new(E_FILEMAN_INTERFACE);
361    if (!d->iface)
362      goto error;
363
364    d->pending.request_name = e_dbus_request_name
365        (d->conn, E_FILEMAN_BUS_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING,
366        _e_fileman_dbus_daemon_request_name_cb, d);
367    if (!d->pending.request_name)
368      goto error;
369
370    for (itr = desc; itr->method; itr++)
371      e_dbus_interface_method_add
372        (d->iface, itr->method, itr->signature, itr->ret_signature, itr->func);
373
374    return d;
375
376 error:
377    fprintf(stderr, "ERROR: FILEMAN: failed to create daemon at %p\n", d);
378    _e_fileman_dbus_daemon_free(d);
379    return NULL;
380 }
381
382 static E_Fileman_DBus_Daemon *_daemon = NULL;
383
384 void
385 e_fileman_dbus_init(void)
386 {
387    if (_daemon)
388      return;
389
390    e_dbus_init();
391    _daemon = _e_fileman_dbus_daemon_new();
392 }
393
394 void
395 e_fileman_dbus_shutdown(void)
396 {
397    if (!_daemon)
398      return;
399
400    _e_fileman_dbus_daemon_free(_daemon);
401    _daemon = NULL;
402    e_dbus_shutdown();
403 }
404