[WM_ROT] support for rotating prediction window without virtual keyboard
[platform/core/uifw/e17.git] / src / bin / e_open.c
1 # ifdef HAVE_CONFIG_H
2 #  include "config.h"
3 # endif
4
5 #include <Ecore_Getopt.h>
6 #include <Efreet.h>
7 #include <Efreet_Mime.h>
8 #include <unistd.h>
9 #include <ctype.h>
10
11 static const char *
12 xdg_defaults_get(const char *path, const char *mime)
13 {
14    Efreet_Ini *ini;
15    const char *str;
16
17    if (access(path, R_OK) != 0)
18      return NULL;
19
20    ini = efreet_ini_new(path);
21    if (!ini)
22      return NULL;
23
24    efreet_ini_section_set(ini, "Default Applications");
25    str = eina_stringshare_add(efreet_ini_string_get(ini, mime));
26    efreet_ini_free(ini);
27
28    return str;
29 }
30
31 static Efreet_Desktop *
32 xdg_desktop_from_string_list(const char *strlist)
33 {
34    Efreet_Desktop *desktop = NULL;
35    char **array = eina_str_split(strlist, ";", 0);
36    unsigned int i;
37
38    if (!array)
39      return NULL;
40
41    for (i = 0; array[i] != NULL; i++)
42      {
43         const char *name = array[i];
44         if (name[0] == '/')
45           desktop = efreet_desktop_new(name);
46         else
47           desktop = efreet_util_desktop_file_id_find(name);
48
49         if (desktop)
50           {
51              if (desktop->exec) break;
52              else
53                {
54                   efreet_desktop_free(desktop);
55                   desktop = NULL;
56                }
57           }
58      }
59
60    free(array[0]);
61    free(array);
62
63    return desktop;
64 }
65
66 static Efreet_Desktop *
67 desktop_first_free_others(Eina_List *lst)
68 {
69    Efreet_Desktop *desktop, *d;
70    if (!lst)
71      return NULL;
72
73    desktop = lst->data;
74    efreet_desktop_ref(desktop);
75
76    EINA_LIST_FREE(lst, d)
77      efreet_desktop_free(d);
78
79    return desktop;
80 }
81
82 static Efreet_Desktop *
83 handler_find(const char *mime)
84 {
85    Efreet_Desktop *desktop = NULL;
86    char path[PATH_MAX];
87    const char *name;
88
89    snprintf(path, sizeof(path), "%s/applications/defaults.list",
90             efreet_data_home_get());
91    name = xdg_defaults_get(path, mime);
92    if (!name)
93      {
94         const Eina_List *n, *dirs = efreet_data_dirs_get();
95         const char *d;
96         EINA_LIST_FOREACH(dirs, n, d)
97           {
98              snprintf(path, sizeof(path), "%s/applications/defaults.list", d);
99              name = xdg_defaults_get(path, mime);
100              if (name)
101                break;
102           }
103      }
104
105    if (name)
106      {
107         desktop = xdg_desktop_from_string_list(name);
108         eina_stringshare_del(name);
109      }
110
111    if (!desktop)
112      desktop = desktop_first_free_others(efreet_util_desktop_mime_list(mime));
113
114    return desktop;
115 }
116
117 static void *
118 get_command(void *data, Efreet_Desktop *desktop __UNUSED__, char *command, int remaining __UNUSED__)
119 {
120    Eina_List **p_cmd = data;
121    *p_cmd = eina_list_append(*p_cmd, command);
122    return NULL;
123 }
124
125 static char **
126 mime_open(const char *mime, const char * const *argv, int argc)
127 {
128    Efreet_Desktop *desktop = handler_find(mime);
129    Eina_List *files = NULL;
130    Eina_List *cmds = NULL;
131    char **ret;
132
133    if (!desktop)
134      return NULL;
135
136    for (; argc > 0; argc--, argv++)
137      files = eina_list_append(files, *argv);
138
139    efreet_desktop_command_get(desktop, files, get_command, &cmds);
140
141    if (!cmds) ret = NULL;
142    else
143      {
144         char *c;
145
146         ret = calloc(eina_list_count(cmds) + 1, sizeof(char *));
147         if (ret)
148           {
149              unsigned int i = 0;
150              EINA_LIST_FREE(cmds, c)
151                {
152                   ret[i] = c; /* was strdup by efreet_desktop_command_get() */
153                   i++;
154                }
155              ret[i] = NULL;
156           }
157         else
158           {
159              EINA_LIST_FREE(cmds, c)
160                free(c);
161           }
162      }
163
164    eina_list_free(files);
165
166    return ret;
167 }
168
169 static void
170 append_single_quote_escaped(Eina_Strbuf *b, const char *str)
171 {
172    const char *itr = str;
173    for (; *itr != '\0'; itr++)
174      {
175         if (*itr != '\'')
176           eina_strbuf_append_char(b, *itr);
177         else
178           eina_strbuf_append(b, "\\'");
179      }
180 }
181
182 static char **
183 single_command_open(const char *command, const char * const *argv, int argc)
184 {
185    char **ret = calloc(2, sizeof(char *));
186    Eina_Strbuf *b;
187    int i;
188
189    if (!ret)
190      return NULL;
191
192    b = eina_strbuf_new();
193    if (!b)
194      {
195         free(ret);
196         return NULL;
197      }
198    eina_strbuf_append(b, command);
199
200    for (i = 0; i < argc; i++)
201      {
202         Eina_Bool has_space = EINA_FALSE;
203         int s_idx_sq = -1, s_idx_dq = -1;
204         int l_idx_sq = -1, l_idx_dq = -1;
205         int idx;
206         const char *itr;
207
208         for (idx = 0, itr = argv[i]; *itr != '\0'; itr++, idx++)
209           {
210              if ((!has_space) && (isspace(*itr)))
211                has_space = EINA_TRUE;
212
213              if (*itr == '\'')
214                {
215                   l_idx_sq = idx;
216                   if (s_idx_sq < 0)
217                     s_idx_sq = idx;
218                }
219
220              if (*itr == '\'')
221                {
222                   l_idx_dq = idx;
223                   if (s_idx_dq < 0)
224                     s_idx_dq = idx;
225                }
226           }
227         idx--;
228
229         eina_strbuf_append_char(b, ' ');
230         if ((!has_space) ||
231             ((s_idx_sq == 0) && (l_idx_sq == idx)) ||
232             ((s_idx_dq == 0) && (l_idx_dq == idx)))
233           eina_strbuf_append(b, argv[i]);
234         else
235           {
236              char c;
237              if ((s_idx_sq >= 0) && (s_idx_dq < 0))
238                c = '"';
239              else if ((s_idx_sq < 0) && (s_idx_dq >= 0))
240                c = '\'';
241              else
242                c = 0;
243
244              if (c)
245                {
246                   eina_strbuf_append_char(b, c);
247                   eina_strbuf_append(b, argv[i]);
248                   eina_strbuf_append_char(b, c);
249                }
250              else
251                {
252                   eina_strbuf_append_char(b, '\'');
253                   append_single_quote_escaped(b, argv[i]);
254                   eina_strbuf_append_char(b, '\'');
255                }
256           }
257      }
258
259    ret[0] = eina_strbuf_string_steal(b);
260    eina_strbuf_free(b);
261
262    return ret;
263 }
264
265 static Efreet_Desktop *
266 _terminal_get(const char *defaults_list)
267 {
268    Efreet_Desktop *tdesktop = NULL;
269    Efreet_Ini *ini;
270    const char *s;
271    
272    ini = efreet_ini_new(defaults_list);
273    if ((ini) && (ini->data) &&
274        (efreet_ini_section_set(ini, "Default Applications")) &&
275        (ini->section))
276      {
277         s = efreet_ini_string_get(ini, "x-scheme-handler/terminal");
278         if (s) tdesktop = efreet_util_desktop_file_id_find(s);
279      }
280    if (ini) efreet_ini_free(ini);
281    return tdesktop;
282 }
283
284 static char **
285 terminal_open(void)
286 {
287    const char *terms[] =
288      {
289         "terminology.desktop",
290         "xterm.desktop",
291         "rxvt.desktop",
292         "gnome-terimnal.desktop",
293         "konsole.desktop",
294         NULL
295      };
296    const char *s;
297    char buf[PATH_MAX], **ret;
298    Efreet_Desktop *tdesktop = NULL, *td;
299    Eina_List *l;
300    int i;
301    
302    s = efreet_data_home_get();
303    if (s)
304      {
305         snprintf(buf, sizeof(buf), "%s/applications/defaults.list", s);
306         tdesktop = _terminal_get(buf);
307      }
308    if (tdesktop) goto have_desktop;
309    EINA_LIST_FOREACH(efreet_data_dirs_get(), l, s)
310      {
311         snprintf(buf, sizeof(buf), "%s/applications/defaults.list", s);
312         tdesktop = _terminal_get(buf);
313         if (tdesktop) goto have_desktop;
314      }
315    
316    for (i = 0; terms[i]; i++)
317      {
318         tdesktop = efreet_util_desktop_file_id_find(terms[i]);
319         if (tdesktop) goto have_desktop;
320      }
321    if (!tdesktop)
322      {
323         l = efreet_util_desktop_category_list("TerminalEmulator");
324         if (l)
325           {
326              // just take first one since above list doesn't work.
327              tdesktop = l->data;
328              EINA_LIST_FREE(l, td)
329                {
330                   // free/unref the desktosp we are not going to use
331                   if (td != tdesktop) efreet_desktop_free(td);
332                }
333           }
334      }
335    if (!tdesktop) return NULL;
336 have_desktop:
337    if (!tdesktop->exec)
338      {
339         efreet_desktop_free(tdesktop);
340         return NULL;
341      }
342    ret = malloc(sizeof(char *) * 2);
343    if (!ret) return NULL;
344    ret[0] = strdup(tdesktop->exec);
345    ret[1] = NULL;
346    if (!ret[0])
347      {
348         free(ret);
349         efreet_desktop_free(tdesktop);
350         return NULL;
351      }
352    efreet_desktop_free(tdesktop);
353    return ret;
354 }
355
356 static char **
357 browser_open(const char * const *argv, int argc)
358 {
359    const char *env = getenv("BROWSER");
360    if (env) return single_command_open(env, argv, argc);
361    return mime_open("x-scheme-handler/http", argv, argc);
362 }
363
364 static char **
365 local_open(const char *path)
366 {
367    const char *mime = efreet_mime_type_get(path);
368    if (mime)
369      {
370         char **ret = mime_open(mime, &path, 1);
371         if (ret)
372           return ret;
373         return single_command_open("enlightenment_filemanager", &path, 1);
374      }
375
376    fprintf(stderr, "ERROR: Could not get mime type for: %s\n", path);
377    return NULL;
378 }
379
380 static char **
381 protocol_open(const char *str)
382 {
383    Efreet_Uri *uri = efreet_uri_decode(str);
384    char **ret = NULL;
385
386    if (!uri)
387      {
388         fprintf(stderr, "ERROR: Could not decode uri: %s\n", str);
389         return NULL;
390      }
391
392    if (!uri->protocol)
393      fprintf(stderr, "ERROR: Could not get protocol from uri: %s\n", str);
394    else if (strcmp(uri->protocol, "file") == 0)
395      ret = local_open(uri->path);
396    else
397      {
398         char mime[256];
399         snprintf(mime, sizeof(mime), "x-scheme-handler/%s", uri->protocol);
400         ret = mime_open(mime, &str, 1);
401      }
402    efreet_uri_free(uri);
403    return ret;
404 }
405
406 static const struct type_mime {
407    const char *type;
408    const char *mime;
409 } type_mimes[] = {
410   /* {"browser", "x-scheme-handler/http"}, */
411   {"mail", "x-scheme-handler/mailto"},
412   /*  {"terminal", NULL}, */
413   {"filemanager", "x-scheme-handler/file"},
414   {"image", "image/jpeg"},
415   {"video", "video/x-mpeg"},
416   {"music", "audio/mp3"},
417   {NULL, NULL}
418 };
419
420 static const char *type_choices[] = {
421   "browser",
422   "mail",
423   "terminal",
424   "filemanager",
425   "image",
426   "video",
427   "music",
428   NULL
429 };
430
431 static const Ecore_Getopt options = {
432    "enlightenment_open",
433    "%prog [options] <file-or-folder-or-url>",
434    PACKAGE_VERSION,
435    "(C) 2012 Gustavo Sverzut Barbieri and others",
436    "BSD 2-Clause",
437    "Opens the file using Enlightenment standards.",
438    EINA_FALSE,
439    {
440       ECORE_GETOPT_CHOICE('t', "type", "Choose program type to launch.",
441                           type_choices),
442       ECORE_GETOPT_VERSION('V', "version"),
443       ECORE_GETOPT_COPYRIGHT('C', "copyright"),
444       ECORE_GETOPT_LICENSE('L', "license"),
445       ECORE_GETOPT_HELP('h', "help"),
446       ECORE_GETOPT_SENTINEL
447    }
448 };
449
450 EAPI int
451 main(int argc, char *argv[])
452 {
453    Eina_Bool quit_option = EINA_FALSE;
454    char *type = NULL;
455    Ecore_Getopt_Value values[] = {
456      ECORE_GETOPT_VALUE_STR(type),
457      ECORE_GETOPT_VALUE_BOOL(quit_option),
458      ECORE_GETOPT_VALUE_BOOL(quit_option),
459      ECORE_GETOPT_VALUE_BOOL(quit_option),
460      ECORE_GETOPT_VALUE_BOOL(quit_option),
461      ECORE_GETOPT_VALUE_NONE
462    };
463    int args;
464    char **cmds;
465
466    args = ecore_getopt_parse(&options, values, argc, argv);
467    if (args < 0)
468      {
469         fputs("ERROR: Could not parse command line options.\n", stderr);
470         return EXIT_FAILURE;
471      }
472    if (quit_option) return EXIT_SUCCESS;
473
474    if ((type == NULL) && (args == argc))
475      {
476         fputs("ERROR: Missing file, directory or URL or --type.\n", stderr);
477         return EXIT_FAILURE;
478      }
479
480    efreet_init();
481    efreet_mime_init();
482
483    if (type)
484      {
485         if (strcmp(type, "terminal") == 0)
486           cmds = terminal_open();
487         else if (strcmp(type, "browser") == 0)
488           cmds = browser_open((const char * const *)argv + args, argc - args);
489         else
490           {
491              const struct type_mime *itr;
492
493              for (itr = type_mimes; itr->type != NULL; itr++)
494                {
495                   if (strcmp(type, itr->type) == 0)
496                     {
497                        cmds = mime_open(itr->mime,
498                                         (const char * const *)argv + args,
499                                         argc - args);
500                        break;
501                     }
502                }
503              if (!itr->type)
504                {
505                   fprintf(stderr, "ERROR: type not supported %s\n", type);
506                   cmds = NULL;
507                }
508           }
509      }
510    else if (strstr(argv[args], "://"))
511      cmds = protocol_open(argv[args]);
512    else
513      cmds = local_open(argv[args]);
514
515    efreet_mime_shutdown();
516    efreet_shutdown();
517
518
519    /* No EFL, plain boring sequential system() calls */
520    if (!cmds)
521      return EXIT_FAILURE;
522    else
523      {
524         char **itr;
525         int ret = EXIT_SUCCESS;
526
527         for (itr = cmds; *itr != NULL; itr++)
528           {
529              /* Question: should we execute them in parallel? */
530              int r = system(*itr);
531              if (r < 0)
532                fprintf(stderr, "ERROR: %s executing %s\n", strerror(errno),
533                        *itr);
534              free(*itr);
535              if (r > 0) /* Question: should we stop the loop on first faiure? */
536                ret = r;
537           }
538         free(cmds);
539
540         return ret;
541      }
542 }