summaryrefslogtreecommitdiff
path: root/src/lib/efreet/efreet_desktop_command.c
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-29 23:04:40 +0000
committerGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-29 23:04:40 +0000
commit4bc0210bd31ed1de6554441562bd93ea863ee9d9 (patch)
tree5d83be12538f8c8d3816bbf65916ce383d050c2e /src/lib/efreet/efreet_desktop_command.c
parent727ddbeaf0c53f31cd62c254fdebe26823d537eb (diff)
efl: merge efreet.
seems to be fine, pass distcheck and friends. please report. changes: - documentation hierarchy fixes - replaced __UNUSED__ with EINA_UNUSED - replaced PKG_DATA_DIR with PACKAGE_DATA_DIR"/efreet" SVN revision: 81889
Diffstat (limited to 'src/lib/efreet/efreet_desktop_command.c')
-rw-r--r--src/lib/efreet/efreet_desktop_command.c903
1 files changed, 903 insertions, 0 deletions
diff --git a/src/lib/efreet/efreet_desktop_command.c b/src/lib/efreet/efreet_desktop_command.c
new file mode 100644
index 0000000..c8f80e4
--- /dev/null
+++ b/src/lib/efreet/efreet_desktop_command.c
@@ -0,0 +1,903 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "efreet_alloca.h"
6
7#include <unistd.h>
8#include <ctype.h>
9
10#ifdef _WIN32
11# include <winsock2.h>
12#endif
13
14#include <Ecore.h>
15#include <Ecore_File.h>
16
17/* define macros and variable for using the eina logging system */
18#define EFREET_MODULE_LOG_DOM _efreet_desktop_log_dom
19extern int _efreet_desktop_log_dom;
20
21#include "Efreet.h"
22#include "efreet_private.h"
23
24/**
25 * @internal
26 * The different types of commands in an Exec entry
27 */
28typedef enum Efreet_Desktop_Command_Flag
29{
30 EFREET_DESKTOP_EXEC_FLAG_FULLPATH = 0x0001,
31 EFREET_DESKTOP_EXEC_FLAG_URI = 0x0002
32} Efreet_Desktop_Command_Flag;
33
34/**
35 * @internal
36 * Efreet_Desktop_Command
37 */
38typedef struct Efreet_Desktop_Command Efreet_Desktop_Command;
39
40/**
41 * @internal
42 * Holds information on a desktop Exec command entry
43 */
44struct Efreet_Desktop_Command
45{
46 Efreet_Desktop *desktop;
47 int num_pending;
48
49 Efreet_Desktop_Command_Flag flags;
50
51 Efreet_Desktop_Command_Cb cb_command;
52 Efreet_Desktop_Progress_Cb cb_progress;
53 void *data;
54
55 Eina_List *files; /**< list of Efreet_Desktop_Command_File */
56};
57
58/**
59 * @internal
60 * Efreet_Desktop_Command_File
61 */
62typedef struct Efreet_Desktop_Command_File Efreet_Desktop_Command_File;
63
64/**
65 * @internal
66 * Stores information on a file passed to the desktop Exec command
67 */
68struct Efreet_Desktop_Command_File
69{
70 Efreet_Desktop_Command *command;
71 char *dir;
72 char *file;
73 char *fullpath;
74 char *uri;
75
76 int pending;
77};
78
79static int efreet_desktop_command_file_id = 0;
80
81static void *efreet_desktop_exec_cb(void *data, Efreet_Desktop *desktop,
82 char *exec, int remaining);
83static int efreet_desktop_command_flags_get(Efreet_Desktop *desktop);
84static void *efreet_desktop_command_execs_process(Efreet_Desktop_Command *command, Eina_List *execs);
85
86static Eina_List *efreet_desktop_command_build(Efreet_Desktop_Command *command);
87static void efreet_desktop_command_free(Efreet_Desktop_Command *command);
88static char *efreet_desktop_command_append_quoted(char *dest, int *size,
89 int *len, char *src);
90static char *efreet_desktop_command_append_multiple(char *dest, int *size, int *len,
91 Efreet_Desktop_Command *command,
92 char type);
93static char *efreet_desktop_command_append_single(char *dest, int *size, int *len,
94 Efreet_Desktop_Command_File *file,
95 char type);
96static char *efreet_desktop_command_append_icon(char *dest, int *size, int *len,
97 Efreet_Desktop *desktop);
98
99static Efreet_Desktop_Command_File *efreet_desktop_command_file_process(
100 Efreet_Desktop_Command *command,
101 const char *file);
102static const char *efreet_desktop_command_file_uri_process(const char *uri);
103static void efreet_desktop_command_file_free(Efreet_Desktop_Command_File *file);
104
105static void efreet_desktop_cb_download_complete(void *data, const char *file,
106 int status);
107static int efreet_desktop_cb_download_progress(void *data, const char *file,
108 long int dltotal, long int dlnow,
109 long int ultotal, long int ulnow);
110
111static char *efreet_desktop_command_path_absolute(const char *path);
112
113static char *efreet_string_append(char *dest, int *size,
114 int *len, const char *src);
115static char *efreet_string_append_char(char *dest, int *size,
116 int *len, char c);
117
118
119EAPI void
120efreet_desktop_exec(Efreet_Desktop *desktop, Eina_List *files, void *data)
121{
122 efreet_desktop_command_get(desktop, files, efreet_desktop_exec_cb, data);
123}
124
125EAPI void *
126efreet_desktop_command_get(Efreet_Desktop *desktop, Eina_List *files,
127 Efreet_Desktop_Command_Cb func, void *data)
128{
129 return efreet_desktop_command_progress_get(desktop, files, func, NULL, data);
130}
131
132EAPI Eina_List *
133efreet_desktop_command_local_get(Efreet_Desktop *desktop, Eina_List *files)
134{
135 Efreet_Desktop_Command *command;
136 char *file;
137 Eina_List *execs, *l;
138
139 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL);
140 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->exec, NULL);
141
142 command = NEW(Efreet_Desktop_Command, 1);
143 if (!command) return 0;
144
145 command->desktop = desktop;
146
147 command->flags = efreet_desktop_command_flags_get(desktop);
148 /* get the required info for each file passed in */
149 if (files)
150 {
151 EINA_LIST_FOREACH(files, l, file)
152 {
153 Efreet_Desktop_Command_File *dcf;
154
155 dcf = efreet_desktop_command_file_process(command, file);
156 if (!dcf) continue;
157 if (dcf->pending)
158 {
159 efreet_desktop_command_file_free(dcf);
160 continue;
161 }
162 command->files = eina_list_append(command->files, dcf);
163 }
164 }
165
166 execs = efreet_desktop_command_build(command);
167 efreet_desktop_command_free(command);
168
169 return execs;
170}
171
172EAPI void *
173efreet_desktop_command_progress_get(Efreet_Desktop *desktop, Eina_List *files,
174 Efreet_Desktop_Command_Cb cb_command,
175 Efreet_Desktop_Progress_Cb cb_progress,
176 void *data)
177{
178 Efreet_Desktop_Command *command;
179 Eina_List *l;
180 char *file;
181 void *ret = NULL;
182
183 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL);
184 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->exec, NULL);
185 EINA_SAFETY_ON_NULL_RETURN_VAL(cb_command, NULL);
186
187 command = NEW(Efreet_Desktop_Command, 1);
188 if (!command) return NULL;
189
190 command->cb_command = cb_command;
191 command->cb_progress = cb_progress;
192 command->data = data;
193 command->desktop = desktop;
194
195 command->flags = efreet_desktop_command_flags_get(desktop);
196 /* get the required info for each file passed in */
197 if (files)
198 {
199 EINA_LIST_FOREACH(files, l, file)
200 {
201 Efreet_Desktop_Command_File *dcf;
202
203 dcf = efreet_desktop_command_file_process(command, file);
204 if (!dcf) continue;
205 command->files = eina_list_append(command->files, dcf);
206 command->num_pending += dcf->pending;
207 }
208 }
209
210 if (command->num_pending == 0)
211 {
212 Eina_List *execs;
213
214 execs = efreet_desktop_command_build(command);
215 if (execs)
216 {
217 ret = efreet_desktop_command_execs_process(command, execs);
218 eina_list_free(execs);
219 }
220 efreet_desktop_command_free(command);
221 }
222
223 return ret;
224}
225
226static void *
227efreet_desktop_exec_cb(void *data,
228 Efreet_Desktop *desktop EINA_UNUSED,
229 char *exec,
230 int remaining EINA_UNUSED)
231{
232 ecore_exe_run(exec, data);
233 free(exec);
234
235 return NULL;
236}
237
238/**
239 * @internal
240 *
241 * @brief Determine which file related field codes are present in the Exec string of a .desktop
242 * @params desktop and Efreet Desktop
243 * @return a bitmask of file field codes present in exec string
244 */
245static int
246efreet_desktop_command_flags_get(Efreet_Desktop *desktop)
247{
248 int flags = 0;
249 const char *p;
250 /* first, determine which fields are present in the Exec string */
251 p = strchr(desktop->exec, '%');
252 while (p)
253 {
254 p++;
255 switch(*p)
256 {
257 case 'f':
258 case 'F':
259 flags |= EFREET_DESKTOP_EXEC_FLAG_FULLPATH;
260 break;
261 case 'u':
262 case 'U':
263 flags |= EFREET_DESKTOP_EXEC_FLAG_URI;
264 break;
265 case '%':
266 p++;
267 break;
268 default:
269 break;
270 }
271
272 p = strchr(p, '%');
273 }
274#ifdef SLOPPY_SPEC
275 /* NON-SPEC!!! this is to work around LOTS of 'broken' .desktop files that
276 * do not specify %U/%u, %F/F etc. etc. at all. just a command. this is
277 * unlikely to be fixed in distributions etc. in the long run as gnome/kde
278 * seem to have workarounds too so no one notices.
279 */
280 if (!flags) flags |= EFREET_DESKTOP_EXEC_FLAG_FULLPATH;
281#endif
282
283 return flags;
284}
285
286
287/**
288 * @internal
289 *
290 * @brief Call the command callback for each exec in the list
291 * @param command
292 * @param execs
293 */
294static void *
295efreet_desktop_command_execs_process(Efreet_Desktop_Command *command, Eina_List *execs)
296{
297 Eina_List *l;
298 char *exec;
299 int num;
300 void *ret = NULL;
301
302 num = eina_list_count(execs);
303 EINA_LIST_FOREACH(execs, l, exec)
304 {
305 ret = command->cb_command(command->data, command->desktop, exec, --num);
306 }
307 return ret;
308}
309
310
311/**
312 * @brief Builds the actual exec string from the raw string and a list of
313 * processed filename information. The callback passed in to
314 * efreet_desktop_command_get is called for each exec string created.
315 *
316 * @param command the command to build
317 * @return a list of executable strings
318 */
319static Eina_List *
320efreet_desktop_command_build(Efreet_Desktop_Command *command)
321{
322 Eina_List *execs = NULL;
323 const Eina_List *l;
324 char *exec;
325
326 /* if the Exec field appends multiple, that will run the list to the end,
327 * causing this loop to only run once. otherwise, this loop will generate a
328 * command for each file in the list. if the list is empty, this
329 * will run once, removing any file field codes */
330 l = command->files;
331 do
332 {
333 const char *p;
334 int len = 0;
335 int size = PATH_MAX;
336 int file_added = 0;
337 Efreet_Desktop_Command_File *file = eina_list_data_get(l);
338 int single;
339
340 exec = malloc(size);
341 if (!exec) goto error;
342 p = command->desktop->exec;
343 len = 0;
344
345 single = 0;
346 while (*p)
347 {
348 if (len >= size - 1)
349 {
350 char *tmp;
351
352 size = len + 1024;
353 tmp = realloc(exec, size);
354 if (!tmp) goto error;
355 exec = tmp;
356 }
357
358 /* XXX handle fields inside quotes? */
359 if (*p == '%')
360 {
361 p++;
362 switch (*p)
363 {
364 case 'f':
365 case 'u':
366 case 'd':
367 case 'n':
368 if (file)
369 {
370 exec = efreet_desktop_command_append_single(exec, &size,
371 &len, file, *p);
372 if (!exec) goto error;
373 file_added = 1;
374 single = 1;
375 }
376 break;
377 case 'F':
378 case 'U':
379 case 'D':
380 case 'N':
381 if (file)
382 {
383 exec = efreet_desktop_command_append_multiple(exec, &size,
384 &len, command, *p);
385 fprintf(stderr, "EXE: '%s'\n", exec);
386 if (!exec) goto error;
387 file_added = 1;
388 }
389 break;
390 case 'i':
391 exec = efreet_desktop_command_append_icon(exec, &size, &len,
392 command->desktop);
393 if (!exec) goto error;
394 break;
395 case 'c':
396 exec = efreet_desktop_command_append_quoted(exec, &size, &len,
397 command->desktop->name);
398 if (!exec) goto error;
399 break;
400 case 'k':
401 exec = efreet_desktop_command_append_quoted(exec, &size, &len,
402 command->desktop->orig_path);
403 if (!exec) goto error;
404 break;
405 case 'v':
406 case 'm':
407 WRN("[Efreet]: Deprecated conversion char: '%c' in file '%s'",
408 *p, command->desktop->orig_path);
409 break;
410 case '%':
411 exec[len++] = *p;
412 break;
413 default:
414#ifdef STRICT_SPEC
415 WRN("[Efreet_desktop]: Unknown conversion character: '%c'", *p);
416#endif
417 break;
418 }
419 }
420 else exec[len++] = *p;
421 p++;
422 }
423
424#ifdef SLOPPY_SPEC
425 /* NON-SPEC!!! this is to work around LOTS of 'broken' .desktop files that
426 * do not specify %U/%u, %F/F etc. etc. at all. just a command. this is
427 * unlikely to be fixed in distributions etc. in the long run as gnome/kde
428 * seem to have workarounds too so no one notices.
429 */
430 if ((file) && (!file_added))
431 {
432 WRN("Efreet_desktop: %s\n"
433 " command: %s\n"
434 " has no file path/uri spec info for executing this app WITH a\n"
435 " file/uri as a parameter. This is unlikely to be the intent.\n"
436 " please check the .desktop file and fix it by adding a %%U or %%F\n"
437 " or something appropriate.",
438 command->desktop->orig_path, command->desktop->exec);
439 if (len >= size - 1)
440 {
441 char *tmp;
442 size = len + 1024;
443 tmp = realloc(exec, size);
444 if (!tmp) goto error;
445 exec = tmp;
446 }
447 exec[len++] = ' ';
448 exec = efreet_desktop_command_append_multiple(exec, &size,
449 &len, command, 'F');
450 if (!exec) goto error;
451 file_added = 1;
452 }
453#endif
454 exec[len++] = '\0';
455
456 if ((single) || (!execs))
457 {
458 execs = eina_list_append(execs, exec);
459 exec = NULL;
460 }
461
462 /* If no file was added, then the Exec field doesn't contain any file
463 * fields (fFuUdDnN). We only want to run the app once in this case. */
464 if (!file_added) break;
465 }
466 while ((l = eina_list_next(l)));
467
468 return execs;
469error:
470 IF_FREE(exec);
471 EINA_LIST_FREE(execs, exec)
472 free(exec);
473 return NULL;
474}
475
476static void
477efreet_desktop_command_free(Efreet_Desktop_Command *command)
478{
479 Efreet_Desktop_Command_File *dcf;
480
481 if (!command) return;
482
483 while (command->files)
484 {
485 dcf = eina_list_data_get(command->files);
486 efreet_desktop_command_file_free(dcf);
487 command->files = eina_list_remove_list(command->files,
488 command->files);
489 }
490 FREE(command);
491}
492
493static char *
494efreet_desktop_command_append_quoted(char *dest, int *size, int *len, char *src)
495{
496 if (!src) return dest;
497 dest = efreet_string_append(dest, size, len, "'");
498 if (!dest) return NULL;
499
500 /* single quotes in src need to be escaped */
501 if (strchr(src, '\''))
502 {
503 char *p;
504 p = src;
505 while (*p)
506 {
507 if (*p == '\'')
508 {
509 dest = efreet_string_append(dest, size, len, "\'\\\'");
510 if (!dest) return NULL;
511 }
512
513 dest = efreet_string_append_char(dest, size, len, *p);
514 if (!dest) return NULL;
515 p++;
516 }
517 }
518 else
519 {
520 dest = efreet_string_append(dest, size, len, src);
521 if (!dest) return NULL;
522 }
523
524 dest = efreet_string_append(dest, size, len, "'");
525 if (!dest) return NULL;
526
527 return dest;
528}
529
530static char *
531efreet_desktop_command_append_multiple(char *dest, int *size, int *len,
532 Efreet_Desktop_Command *command,
533 char type)
534{
535 Efreet_Desktop_Command_File *file;
536 Eina_List *l;
537 int first = 1;
538
539 if (!command->files) return dest;
540
541 EINA_LIST_FOREACH(command->files, l, file)
542 {
543 if (first)
544 first = 0;
545 else
546 {
547 dest = efreet_string_append_char(dest, size, len, ' ');
548 if (!dest) return NULL;
549 }
550
551 dest = efreet_desktop_command_append_single(dest, size, len,
552 file, tolower(type));
553 if (!dest) return NULL;
554 }
555
556 return dest;
557}
558
559static char *
560efreet_desktop_command_append_single(char *dest, int *size, int *len,
561 Efreet_Desktop_Command_File *file,
562 char type)
563{
564 char *str;
565 switch(type)
566 {
567 case 'f':
568 str = file->fullpath;
569 break;
570 case 'u':
571 str = file->uri;
572 break;
573 case 'd':
574 str = file->dir;
575 break;
576 case 'n':
577 str = file->file;
578 break;
579 default:
580 ERR("Invalid type passed to efreet_desktop_command_append_single:"
581 " '%c'", type);
582 return dest;
583 }
584
585 if (!str) return dest;
586
587 dest = efreet_desktop_command_append_quoted(dest, size, len, str);
588 if (!dest) return NULL;
589
590 return dest;
591}
592
593static char *
594efreet_desktop_command_append_icon(char *dest, int *size, int *len,
595 Efreet_Desktop *desktop)
596{
597 if (!desktop->icon || !desktop->icon[0]) return dest;
598
599 dest = efreet_string_append(dest, size, len, "--icon ");
600 if (!dest) return NULL;
601 dest = efreet_desktop_command_append_quoted(dest, size, len, desktop->icon);
602 if (!dest) return NULL;
603
604 return dest;
605}
606
607/**
608 * @param command the Efreet_Desktop_Comand that this file is for
609 * @param file the filname as either an absolute path, relative path, or URI
610 */
611static Efreet_Desktop_Command_File *
612efreet_desktop_command_file_process(Efreet_Desktop_Command *command, const char *file)
613{
614 Efreet_Desktop_Command_File *f;
615 const char *uri, *base;
616 int nonlocal = 0;
617/*
618 DBG("FLAGS: %d, %d, %d, %d\n",
619 command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH ? 1 : 0,
620 command->flags & EFREET_DESKTOP_EXEC_FLAG_URI ? 1 : 0);
621*/
622 f = NEW(Efreet_Desktop_Command_File, 1);
623 if (!f) return NULL;
624
625 f->command = command;
626
627 /* handle uris */
628 if (!strncmp(file, "http://", 7) || !strncmp(file, "ftp://", 6))
629 {
630 uri = file;
631 base = ecore_file_file_get(file);
632
633 nonlocal = 1;
634 }
635 else if (!strncmp(file, "file:", 5))
636 {
637 file = efreet_desktop_command_file_uri_process(file);
638 if (!file)
639 {
640 efreet_desktop_command_file_free(f);
641 return NULL;
642 }
643 }
644
645 if (nonlocal)
646 {
647 /* process non-local uri */
648 if (command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH)
649 {
650 char buf[PATH_MAX];
651
652 snprintf(buf, sizeof(buf), "/tmp/%d-%d-%s", getpid(),
653 efreet_desktop_command_file_id++, base);
654 f->fullpath = strdup(buf);
655 f->pending = 1;
656
657 ecore_file_download(uri, f->fullpath, efreet_desktop_cb_download_complete,
658 efreet_desktop_cb_download_progress, f, NULL);
659 }
660
661 if (command->flags & EFREET_DESKTOP_EXEC_FLAG_URI)
662 f->uri = strdup(uri);
663 }
664 else
665 {
666 char *absol = efreet_desktop_command_path_absolute(file);
667 if (!absol) goto error;
668 /* process local uri/path */
669 if (command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH)
670 f->fullpath = strdup(absol);
671
672 if (command->flags & EFREET_DESKTOP_EXEC_FLAG_URI)
673 {
674 const char *buf;
675 Efreet_Uri ef_uri;
676 ef_uri.protocol = "file";
677 ef_uri.hostname = "";
678 ef_uri.path = absol;
679 buf = efreet_uri_encode(&ef_uri);
680
681 f->uri = strdup(buf);
682
683 eina_stringshare_del(buf);
684 }
685
686 free(absol);
687 }
688#if 0
689 INF(" fullpath: %s", f->fullpath);
690 INF(" uri: %s", f->uri);
691 INF(" dir: %s", f->dir);
692 INF(" file: %s", f->file);
693#endif
694 return f;
695error:
696 IF_FREE(f);
697 return NULL;
698}
699
700/**
701 * @brief Find the local path portion of a file uri.
702 * @param uri a uri beginning with "file"
703 * @return the location of the path portion of the uri,
704 * or NULL if the file is not on this machine
705 */
706static const char *
707efreet_desktop_command_file_uri_process(const char *uri)
708{
709 const char *path = NULL;
710 int len = strlen(uri);
711
712 /* uri:foo/bar => relative path foo/bar*/
713 if (len >= 4 && uri[5] != '/')
714 path = uri + strlen("file:");
715
716 /* uri:/foo/bar => absolute path /foo/bar */
717 else if (len >= 5 && uri[6] != '/')
718 path = uri + strlen("file:");
719
720 /* uri://foo/bar => absolute path /bar on machine foo */
721 else if (len >= 6 && uri[7] != '/')
722 {
723 char *tmp, *p;
724 char hostname[PATH_MAX];
725 size_t len2;
726
727 len2 = strlen(uri + 7) + 1;
728 tmp = alloca(len2);
729 memcpy(tmp, uri + 7, len2);
730 p = strchr(tmp, '/');
731 if (p)
732 {
733 *p = '\0';
734 if (!strcmp(tmp, "localhost"))
735 path = uri + strlen("file://localhost");
736 else
737 {
738 int ret;
739
740 ret = gethostname(hostname, PATH_MAX);
741 if ((ret == 0) && !strcmp(tmp, hostname))
742 path = uri + strlen("file://") + strlen(hostname);
743 }
744 }
745 }
746
747 /* uri:///foo/bar => absolute path /foo/bar on local machine */
748 else if (len >= 7)
749 path = uri + strlen("file://");
750
751 return path;
752}
753
754static void
755efreet_desktop_command_file_free(Efreet_Desktop_Command_File *file)
756{
757 if (!file) return;
758
759 IF_FREE(file->fullpath);
760 IF_FREE(file->uri);
761 IF_FREE(file->dir);
762 IF_FREE(file->file);
763
764 FREE(file);
765}
766
767
768static void
769efreet_desktop_cb_download_complete(void *data, const char *file EINA_UNUSED,
770 int status EINA_UNUSED)
771{
772 Efreet_Desktop_Command_File *f;
773
774 f = data;
775
776 /* XXX check status... error handling, etc */
777 f->pending = 0;
778 f->command->num_pending--;
779
780 if (f->command->num_pending <= 0)
781 {
782 Eina_List *execs;
783
784 execs = efreet_desktop_command_build(f->command);
785 if (execs)
786 {
787 /* TODO: Need to handle the return value from efreet_desktop_command_execs_process */
788 efreet_desktop_command_execs_process(f->command, execs);
789 eina_list_free(execs);
790 }
791 efreet_desktop_command_free(f->command);
792 }
793}
794
795static int
796efreet_desktop_cb_download_progress(void *data,
797 const char *file EINA_UNUSED,
798 long int dltotal, long int dlnow,
799 long int ultotal EINA_UNUSED,
800 long int ulnow EINA_UNUSED)
801{
802 Efreet_Desktop_Command_File *dcf;
803
804 dcf = data;
805 if (dcf->command->cb_progress)
806 return dcf->command->cb_progress(dcf->command->data,
807 dcf->command->desktop,
808 dcf->uri, dltotal, dlnow);
809
810 return 0;
811}
812
813/**
814 * @brief Build an absolute path from an absolute or relative one.
815 * @param path an absolute or relative path
816 * @return an allocated absolute path (must be freed)
817 */
818static char *
819efreet_desktop_command_path_absolute(const char *path)
820{
821 char *buf;
822 int size = PATH_MAX;
823 int len = 0;
824
825 /* relative url */
826 if (path[0] != '/')
827 {
828 if (!(buf = malloc(size))) return NULL;
829 if (!getcwd(buf, size))
830 {
831 FREE(buf);
832 return NULL;
833 }
834 len = strlen(buf);
835
836 if (buf[len-1] != '/') buf = efreet_string_append(buf, &size, &len, "/");
837 if (!buf) return NULL;
838 buf = efreet_string_append(buf, &size, &len, path);
839 if (!buf) return NULL;
840
841 return buf;
842 }
843
844 /* just dup an already absolute buffer */
845 return strdup(path);
846}
847
848/**
849 * Append a string to a buffer, reallocating as necessary.
850 */
851static char *
852efreet_string_append(char *dest, int *size, int *len, const char *src)
853{
854 int l;
855 int off = 0;
856
857 l = eina_strlcpy(dest + *len, src, *size - *len);
858
859 while (l > *size - *len)
860 {
861 char *tmp;
862 /* we successfully appended this much */
863 off += *size - *len - 1;
864 *len = *size - 1;
865 *size += 1024;
866 tmp = realloc(dest, *size);
867 if (!tmp)
868 {
869 free(dest);
870 return NULL;
871 }
872 dest = tmp;
873 *(dest + *len) = '\0';
874
875 l = eina_strlcpy(dest + *len, src + off, *size - *len);
876 }
877 *len += l;
878
879 return dest;
880}
881
882static char *
883efreet_string_append_char(char *dest, int *size, int *len, char c)
884{
885 if (*len >= *size - 1)
886 {
887 char *tmp;
888 *size += 1024;
889 tmp = realloc(dest, *size);
890 if (!tmp)
891 {
892 free(dest);
893 return NULL;
894 }
895 dest = tmp;
896 }
897
898 dest[(*len)++] = c;
899 dest[*len] = '\0';
900
901 return dest;
902}
903