From a6b1453b3527eec71c1eafc8ecce2c1d93672d38 Mon Sep 17 00:00:00 2001 From: englebass Date: Thu, 15 Apr 2010 18:23:42 +0000 Subject: [PATCH] efreet: split desktop command to separate file git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/efreet@48025 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- src/lib/Makefile.am | 1 + src/lib/efreet_desktop.c | 844 +---------------------------------------------- 2 files changed, 2 insertions(+), 843 deletions(-) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index f3d1c6c..f8c461a 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -20,6 +20,7 @@ efreet_icon.c \ efreet_xml.c \ efreet_ini.c \ efreet_desktop.c \ +efreet_desktop_command.c \ efreet_menu.c \ efreet_utils.c \ efreet_uri.c diff --git a/src/lib/efreet_desktop.c b/src/lib/efreet_desktop.c index a86db18..973b8dc 100644 --- a/src/lib/efreet_desktop.c +++ b/src/lib/efreet_desktop.c @@ -6,8 +6,6 @@ #include #include -#include -#include #include #include #include @@ -38,61 +36,6 @@ struct _Efreet_Event_Cache_Data }; /** - * @internal - * The different types of commands in an Exec entry - */ -typedef enum Efreet_Desktop_Command_Flag -{ - EFREET_DESKTOP_EXEC_FLAG_FULLPATH = 0x0001, - EFREET_DESKTOP_EXEC_FLAG_URI = 0x0002 -} Efreet_Desktop_Command_Flag; - -/** - * @internal - * Efreet_Desktop_Command - */ -typedef struct Efreet_Desktop_Command Efreet_Desktop_Command; - -/** - * @internal - * Holds information on a desktop Exec command entry - */ -struct Efreet_Desktop_Command -{ - Efreet_Desktop *desktop; - int num_pending; - - Efreet_Desktop_Command_Flag flags; - - Efreet_Desktop_Command_Cb cb_command; - Efreet_Desktop_Progress_Cb cb_progress; - void *data; - - Eina_List *files; /**< list of Efreet_Desktop_Command_File */ -}; - -/** - * @internal - * Efreet_Desktop_Command_File - */ -typedef struct Efreet_Desktop_Command_File Efreet_Desktop_Command_File; - -/** - * @internal - * Stores information on a file passed to the desktop Exec command - */ -struct Efreet_Desktop_Command_File -{ - Efreet_Desktop_Command *command; - char *dir; - char *file; - char *fullpath; - char *uri; - - int pending; -}; - -/** * The current desktop environment (e.g. "Enlightenment" or "Gnome") */ static const char *desktop_environment = NULL; @@ -114,11 +57,6 @@ static Eina_List *efreet_desktop_types = NULL; static Eina_List *efreet_desktop_dirs = NULL; /** - * A unique id for each tmp file created while building a command - */ -static int efreet_desktop_command_file_id = 0; - -/** * A job pointer for cache updates */ static Ecore_Job *efreet_desktop_job = NULL; @@ -140,7 +78,7 @@ static Eina_Hash *change_monitors = NULL; #endif #define EFREET_MODULE_LOG_DOM _efreet_desktop_log_dom -static int _efreet_desktop_log_dom = -1; +int _efreet_desktop_log_dom = -1; EAPI int EFREET_DESKTOP_TYPE_APPLICATION = 0; EAPI int EFREET_DESKTOP_TYPE_LINK = 0; @@ -186,44 +124,7 @@ static Eina_Bool efreet_desktop_x_fields_save(const Eina_Hash *hash, void *value, void *fdata); static int efreet_desktop_environment_check(Efreet_Ini *ini); -static char *efreet_string_append(char *dest, int *size, - int *len, const char *src); -static char *efreet_string_append_char(char *dest, int *size, - int *len, char c); -static Eina_List *efreet_desktop_command_build(Efreet_Desktop_Command *command); -static void efreet_desktop_command_free(Efreet_Desktop_Command *command); -static char *efreet_desktop_command_append_quoted(char *dest, int *size, - int *len, char *src); -static char *efreet_desktop_command_append_icon(char *dest, int *size, int *len, - Efreet_Desktop *desktop); -static char *efreet_desktop_command_append_single(char *dest, int *size, int *len, - Efreet_Desktop_Command_File *file, - char type); -static char *efreet_desktop_command_append_multiple(char *dest, int *size, int *len, - Efreet_Desktop_Command *command, - char type); - -static char *efreet_desktop_command_path_absolute(const char *path); -static Efreet_Desktop_Command_File *efreet_desktop_command_file_process( - Efreet_Desktop_Command *command, - const char *file); -static const char *efreet_desktop_command_file_uri_process(const char *uri); -static void efreet_desktop_command_file_free(Efreet_Desktop_Command_File *file); - -static void efreet_desktop_cb_download_complete(void *data, const char *file, - int status); -static int efreet_desktop_cb_download_progress(void *data, const char *file, - long int dltotal, long int dlnow, - long int ultotal, long int ulnow); - - -static void *efreet_desktop_exec_cb(void *data, Efreet_Desktop *desktop, - char *exec, int remaining); - static void efreet_desktop_type_info_free(Efreet_Desktop_Type_Info *info); -static int efreet_desktop_command_flags_get(Efreet_Desktop *desktop); -static void *efreet_desktop_command_execs_process(Efreet_Desktop_Command *command, Eina_List *execs); - static void efreet_desktop_update_cache_dirs(void); static void efreet_desktop_cache_update(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path); @@ -862,30 +763,6 @@ efreet_desktop_free(Efreet_Desktop *desktop) } /** - * @param desktop: The desktop file to work with - * @param files: The files to be substituted into the exec line - * @param data: The data pointer to pass - * @return Returns the Ecore_Exce for @a desktop - * @brief Parses the @a desktop exec line and returns an Ecore_Exe. - */ -EAPI void -efreet_desktop_exec(Efreet_Desktop *desktop, Eina_List *files, void *data) -{ - efreet_desktop_command_get(desktop, files, efreet_desktop_exec_cb, data); -} - -static void * -efreet_desktop_exec_cb(void *data, Efreet_Desktop *desktop __UNUSED__, - char *exec, int remaining __UNUSED__) -{ -#ifndef _WIN32 - ecore_exe_run(exec, data); - free(exec); -#endif - return NULL; -} - -/** * @param environment: the environment name * @brief sets the global desktop environment name */ @@ -1405,725 +1282,6 @@ efreet_desktop_environment_check(Efreet_Ini *ini) return !found; } - -/** - * @param desktop: the desktop entry - * @param files: an eina list of file names to execute, as either absolute paths, - * relative paths, or uris - * @param func: a callback to call for each prepared command line - * @param data: user data passed to the callback - * @return Returns the return value of @p func on success or NULL on failure - * @brief Get a command to use to execute a desktop entry. - */ -EAPI void * -efreet_desktop_command_get(Efreet_Desktop *desktop, Eina_List *files, - Efreet_Desktop_Command_Cb func, void *data) -{ - return efreet_desktop_command_progress_get(desktop, files, func, NULL, data); -} - -/** - * @param desktop: the desktop entry - * @param files an eina list of local files, as absolute paths, local paths, or file:// uris (or NULL to get exec string with no files appended) - * @return Returns an eina list of exec strings - * @brief Get the command to use to execute a desktop entry - * - * The returned list and each of its elements must be freed. - */ -EAPI Eina_List * -efreet_desktop_command_local_get(Efreet_Desktop *desktop, Eina_List *files) -{ - Efreet_Desktop_Command *command; - char *file; - Eina_List *execs, *l; - - if (!desktop || !desktop->exec) return NULL; - - command = NEW(Efreet_Desktop_Command, 1); - if (!command) return 0; - - command->desktop = desktop; - - command->flags = efreet_desktop_command_flags_get(desktop); - /* get the required info for each file passed in */ - if (files) - { - EINA_LIST_FOREACH(files, l, file) - { - Efreet_Desktop_Command_File *dcf; - - dcf = efreet_desktop_command_file_process(command, file); - if (!dcf) continue; - if (dcf->pending) - { - efreet_desktop_command_file_free(dcf); - continue; - } - command->files = eina_list_append(command->files, dcf); - } - } - - execs = efreet_desktop_command_build(command); - efreet_desktop_command_free(command); - - return execs; -} - - -/** - * @param desktop: the desktop entry - * @param files: an eina list of file names to execute, as either absolute paths, - * relative paths, or uris - * @param cb_command: a callback to call for each prepared command line - * @param cb_progress: a callback to get progress for the downloads - * @param data: user data passed to the callback - * @return Returns 1 on success or 0 on failure - * @brief Get a command to use to execute a desktop entry, and receive progress - * updates for downloading of remote URI's passed in. - */ -EAPI void * -efreet_desktop_command_progress_get(Efreet_Desktop *desktop, Eina_List *files, - Efreet_Desktop_Command_Cb cb_command, - Efreet_Desktop_Progress_Cb cb_progress, - void *data) -{ - Efreet_Desktop_Command *command; - Eina_List *l; - char *file; - void *ret = NULL; - - if (!desktop || !cb_command || !desktop->exec) return NULL; - - command = NEW(Efreet_Desktop_Command, 1); - if (!command) return NULL; - - command->cb_command = cb_command; - command->cb_progress = cb_progress; - command->data = data; - command->desktop = desktop; - - command->flags = efreet_desktop_command_flags_get(desktop); - /* get the required info for each file passed in */ - if (files) - { - EINA_LIST_FOREACH(files, l, file) - { - Efreet_Desktop_Command_File *dcf; - - dcf = efreet_desktop_command_file_process(command, file); - if (!dcf) continue; - command->files = eina_list_append(command->files, dcf); - command->num_pending += dcf->pending; - } - } - - if (command->num_pending == 0) - { - Eina_List *execs; - - execs = efreet_desktop_command_build(command); - ret = efreet_desktop_command_execs_process(command, execs); - eina_list_free(execs); - efreet_desktop_command_free(command); - } - - return ret; -} - -/** - * @internal - * - * @brief Determine which file related field codes are present in the Exec string of a .desktop - * @params desktop and Efreet Desktop - * @return a bitmask of file field codes present in exec string - */ -static int -efreet_desktop_command_flags_get(Efreet_Desktop *desktop) -{ - int flags = 0; - const char *p; - /* first, determine which fields are present in the Exec string */ - p = strchr(desktop->exec, '%'); - while (p) - { - p++; - switch(*p) - { - case 'f': - case 'F': - flags |= EFREET_DESKTOP_EXEC_FLAG_FULLPATH; - break; - case 'u': - case 'U': - flags |= EFREET_DESKTOP_EXEC_FLAG_URI; - break; - case '%': - p++; - break; - default: - break; - } - - p = strchr(p, '%'); - } -#ifdef SLOPPY_SPEC - /* NON-SPEC!!! this is to work around LOTS of 'broken' .desktop files that - * do not specify %U/%u, %F/F etc. etc. at all. just a command. this is - * unlikely to be fixed in distributions etc. in the long run as gnome/kde - * seem to have workarounds too so no one notices. - */ - if (!flags) flags |= EFREET_DESKTOP_EXEC_FLAG_FULLPATH; -#endif - - return flags; -} - - -/** - * @internal - * - * @brief Call the command callback for each exec in the list - * @param command - * @param execs - */ -static void * -efreet_desktop_command_execs_process(Efreet_Desktop_Command *command, Eina_List *execs) -{ - Eina_List *l; - char *exec; - int num; - void *ret = NULL; - - num = eina_list_count(execs); - EINA_LIST_FOREACH(execs, l, exec) - { - ret = command->cb_command(command->data, command->desktop, exec, --num); - } - return ret; -} - - -/** - * @brief Builds the actual exec string from the raw string and a list of - * processed filename information. The callback passed in to - * efreet_desktop_command_get is called for each exec string created. - * - * @param command: the command to build - * @return a list of executable strings - */ -static Eina_List * -efreet_desktop_command_build(Efreet_Desktop_Command *command) -{ - Eina_List *execs = NULL; - const Eina_List *l; - char *exec; - - /* if the Exec field appends multiple, that will run the list to the end, - * causing this loop to only run once. otherwise, this loop will generate a - * command for each file in the list. if the list is empty, this - * will run once, removing any file field codes */ - l = command->files; - do - { - const char *p; - int len = 0; - int size = PATH_MAX; - int file_added = 0; - Efreet_Desktop_Command_File *file = eina_list_data_get(l); - - exec = malloc(size); - p = command->desktop->exec; - len = 0; - - while (*p) - { - if (len >= size - 1) - { - size = len + 1024; - exec = realloc(exec, size); - } - - /* XXX handle fields inside quotes? */ - if (*p == '%') - { - p++; - switch (*p) - { - case 'f': - case 'u': - case 'd': - case 'n': - if (file) - { - exec = efreet_desktop_command_append_single(exec, &size, - &len, file, *p); - file_added = 1; - } - break; - case 'F': - case 'U': - case 'D': - case 'N': - if (file) - { - exec = efreet_desktop_command_append_multiple(exec, &size, - &len, command, *p); - file_added = 1; - } - break; - case 'i': - exec = efreet_desktop_command_append_icon(exec, &size, &len, - command->desktop); - break; - case 'c': - exec = efreet_desktop_command_append_quoted(exec, &size, &len, - command->desktop->name); - break; - case 'k': - exec = efreet_desktop_command_append_quoted(exec, &size, &len, - command->desktop->orig_path); - break; - case 'v': - case 'm': - WRN("[Efreet]: Deprecated conversion char: '%c' in file '%s'", - *p, command->desktop->orig_path); - break; - case '%': - exec[len++] = *p; - break; - default: -#ifdef STRICT_SPEC - WRN("[Efreet_desktop]: Unknown conversion character: '%c'", *p); -#endif - break; - } - } - else exec[len++] = *p; - p++; - } - -#ifdef SLOPPY_SPEC - /* NON-SPEC!!! this is to work around LOTS of 'broken' .desktop files that - * do not specify %U/%u, %F/F etc. etc. at all. just a command. this is - * unlikely to be fixed in distributions etc. in the long run as gnome/kde - * seem to have workarounds too so no one notices. - */ - if ((file) && (!file_added)) - { - WRN("Efreet_desktop: %s\n" - " command: %s\n" - " has no file path/uri spec info for executing this app WITH a\n" - " file/uri as a parameter. This is unlikely to be the intent.\n" - " please check the .desktop file and fix it by adding a %%U or %%F\n" - " or something appropriate.", - command->desktop->orig_path, command->desktop->exec); - if (len >= size - 1) - { - size = len + 1024; - exec = realloc(exec, size); - } - exec[len++] = ' '; - exec = efreet_desktop_command_append_multiple(exec, &size, - &len, command, 'F'); - file_added = 1; - } -#endif - exec[len++] = '\0'; - - execs = eina_list_append(execs, exec); - - /* If no file was added, then the Exec field doesn't contain any file - * fields (fFuUdDnN). We only want to run the app once in this case. */ - if (!file_added) break; - } - while ((l = eina_list_next(l)) != NULL); - - return execs; -} - -static void -efreet_desktop_command_free(Efreet_Desktop_Command *command) -{ - Efreet_Desktop_Command_File *dcf; - - if (!command) return; - - while (command->files) - { - dcf = eina_list_data_get(command->files); - efreet_desktop_command_file_free(dcf); - command->files = eina_list_remove_list(command->files, - command->files); - } - FREE(command); -} - -static char * -efreet_desktop_command_append_quoted(char *dest, int *size, int *len, char *src) -{ - if (!src) return dest; - dest = efreet_string_append(dest, size, len, "'"); - - /* single quotes in src need to be escaped */ - if (strchr(src, '\'')) - { - char *p; - p = src; - while (*p) - { - if (*p == '\'') - dest = efreet_string_append(dest, size, len, "\'\\\'"); - - dest = efreet_string_append_char(dest, size, len, *p); - p++; - } - } - else - dest = efreet_string_append(dest, size, len, src); - - dest = efreet_string_append(dest, size, len, "'"); - - return dest; -} - -static char * -efreet_desktop_command_append_multiple(char *dest, int *size, int *len, - Efreet_Desktop_Command *command, - char type) -{ - Efreet_Desktop_Command_File *file; - Eina_List *l; - int first = 1; - - if (!command->files) return dest; - - EINA_LIST_FOREACH(command->files, l, file) - { - if (first) - first = 0; - else - dest = efreet_string_append_char(dest, size, len, ' '); - - dest = efreet_desktop_command_append_single(dest, size, len, - file, tolower(type)); - } - - return dest; -} - -static char * -efreet_desktop_command_append_single(char *dest, int *size, int *len, - Efreet_Desktop_Command_File *file, - char type) -{ - char *str; - switch(type) - { - case 'f': - str = file->fullpath; - break; - case 'u': - str = file->uri; - break; - case 'd': - str = file->dir; - break; - case 'n': - str = file->file; - break; - default: - ERR("Invalid type passed to efreet_desktop_command_append_single:" - " '%c'", type); - return dest; - } - - if (!str) return dest; - - dest = efreet_desktop_command_append_quoted(dest, size, len, str); - - return dest; -} - -static char * -efreet_desktop_command_append_icon(char *dest, int *size, int *len, - Efreet_Desktop *desktop) -{ - if (!desktop->icon || !desktop->icon[0]) return dest; - - dest = efreet_string_append(dest, size, len, "--icon "); - dest = efreet_desktop_command_append_quoted(dest, size, len, desktop->icon); - - return dest; -} - - -/** - * Append a string to a buffer, reallocating as necessary. - */ -static char * -efreet_string_append(char *dest, int *size, int *len, const char *src) -{ - int l; - int off = 0; - - l = eina_strlcpy(dest + *len, src, *size - *len); - - while (l > *size - *len) - { - /* we successfully appended this much */ - off += *size - *len - 1; - *len = *size - 1; - *size += 1024; - dest = realloc(dest, *size); - *(dest + *len) = '\0'; - - l = eina_strlcpy(dest + *len, src + off, *size - *len); - } - *len += l; - - return dest; -} - -static char * -efreet_string_append_char(char *dest, int *size, int *len, char c) -{ - if (*len >= *size - 1) - { - *size += 1024; - dest = realloc(dest, *size); - } - - dest[(*len)++] = c; - dest[*len] = '\0'; - - return dest; -} - -/** - * @param command: the Efreet_Desktop_Comand that this file is for - * @param file: the filname as either an absolute path, relative path, or URI - */ -static Efreet_Desktop_Command_File * -efreet_desktop_command_file_process(Efreet_Desktop_Command *command, const char *file) -{ - Efreet_Desktop_Command_File *f; - const char *uri, *base; - int nonlocal = 0; -/* - DBG("FLAGS: %d, %d, %d, %d\n", - command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH ? 1 : 0, - command->flags & EFREET_DESKTOP_EXEC_FLAG_URI ? 1 : 0); -*/ - f = NEW(Efreet_Desktop_Command_File, 1); - if (!f) return NULL; - - f->command = command; - - /* handle uris */ - if (!strncmp(file, "http://", 7) || !strncmp(file, "ftp://", 6)) - { - uri = file; - base = ecore_file_file_get(file); - - nonlocal = 1; - } - else if (!strncmp(file, "file:", 5)) - { - file = efreet_desktop_command_file_uri_process(file); - if (!file) - { - efreet_desktop_command_file_free(f); - return NULL; - } - } - - if (nonlocal) - { - /* process non-local uri */ - if (command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH) - { - char buf[PATH_MAX]; - - snprintf(buf, sizeof(buf), "/tmp/%d-%d-%s", getpid(), - efreet_desktop_command_file_id++, base); - f->fullpath = strdup(buf); - f->pending = 1; - - ecore_file_download(uri, f->fullpath, efreet_desktop_cb_download_complete, - efreet_desktop_cb_download_progress, f, NULL); - } - - if (command->flags & EFREET_DESKTOP_EXEC_FLAG_URI) - f->uri = strdup(uri); - } - else - { - char *absol = efreet_desktop_command_path_absolute(file); - /* process local uri/path */ - if (command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH) - f->fullpath = strdup(absol); - - if (command->flags & EFREET_DESKTOP_EXEC_FLAG_URI) - { - char buf[PATH_MAX]; - snprintf(buf, sizeof(buf), "file://%s", absol); - f->uri = strdup(buf); - } - - free(absol); - } -#if 0 - INF(" fullpath: %s", f->fullpath); - INF(" uri: %s", f->uri); - INF(" dir: %s", f->dir); - INF(" file: %s", f->file); -#endif - return f; -} - -/** - * @brief Find the local path portion of a file uri. - * @param uri: a uri beginning with "file:" - * @return the location of the path portion of the uri, - * or NULL if the file is not on this machine - */ -static const char * -efreet_desktop_command_file_uri_process(const char *uri) -{ - const char *path = NULL; - int len = strlen(uri); - - /* uri:foo/bar => relative path foo/bar*/ - if (len >= 4 && uri[5] != '/') - path = uri + strlen("file:"); - - /* uri:/foo/bar => absolute path /foo/bar */ - else if (len >= 5 && uri[6] != '/') - path = uri + strlen("file:"); - - /* uri://foo/bar => absolute path /bar on machine foo */ - else if (len >= 6 && uri[7] != '/') - { - char *tmp, *p; - char hostname[PATH_MAX]; - size_t len2; - - len2 = strlen(uri + 7) + 1; - tmp = alloca(len2); - memcpy(tmp, uri + 7, len2); - p = strchr(tmp, '/'); - if (p) - { - *p = '\0'; - if (!strcmp(tmp, "localhost")) - path = uri + strlen("file://localhost"); - else - { - int ret; - - ret = gethostname(hostname, PATH_MAX); - if ((ret == 0) && !strcmp(tmp, hostname)) - path = uri + strlen("file://") + strlen(hostname); - } - } - } - - /* uri:///foo/bar => absolute path /foo/bar on local machine */ - else if (len >= 7) - path = uri + strlen("file://"); - - return path; -} - -static void -efreet_desktop_command_file_free(Efreet_Desktop_Command_File *file) -{ - if (!file) return; - - IF_FREE(file->fullpath); - IF_FREE(file->uri); - IF_FREE(file->dir); - IF_FREE(file->file); - - FREE(file); -} - - -static void -efreet_desktop_cb_download_complete(void *data, const char *file __UNUSED__, - int status __UNUSED__) -{ - Efreet_Desktop_Command_File *f; - - f = data; - - /* XXX check status... error handling, etc */ - f->pending = 0; - f->command->num_pending--; - - if (f->command->num_pending <= 0) - { - Eina_List *execs; - - execs = efreet_desktop_command_build(f->command); - /* TODO: Need to handle the return value from efreet_desktop_command_execs_process */ - efreet_desktop_command_execs_process(f->command, execs); - eina_list_free(execs); - efreet_desktop_command_free(f->command); - } -} - -static int -efreet_desktop_cb_download_progress(void *data, - const char *file __UNUSED__, - long int dltotal, long int dlnow, - long int ultotal __UNUSED__, - long int ulnow __UNUSED__) -{ - Efreet_Desktop_Command_File *dcf; - - dcf = data; - if (dcf->command->cb_progress) - return dcf->command->cb_progress(dcf->command->data, - dcf->command->desktop, - dcf->uri, dltotal, dlnow); - - return 0; -} - -/** - * @brief Build an absolute path from an absolute or relative one. - * @param path: an absolute or relative path - * @return an allocated absolute path (must be freed) - */ -static char * -efreet_desktop_command_path_absolute(const char *path) -{ - char *buf; - int size = PATH_MAX; - int len = 0; - - /* relative url */ - if (path[0] != '/') - { - if (!(buf = malloc(size))) return NULL; - if (!getcwd(buf, size)) - { - FREE(buf); - return NULL; - } - len = strlen(buf); - - if (buf[len-1] != '/') buf = efreet_string_append(buf, &size, &len, "/"); - buf = efreet_string_append(buf, &size, &len, path); - - return buf; - } - - /* just dup an already absolute buffer */ - return strdup(path); -} - EAPI Eina_Bool efreet_desktop_x_field_set(Efreet_Desktop *desktop, const char *key, const char *data) { -- 2.7.4