2010-04-15 11:24:48 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2010-11-25 15:48:59 -08:00
|
|
|
#undef alloca
|
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
|
|
# include <alloca.h>
|
|
|
|
#elif defined __GNUC__
|
|
|
|
# define alloca __builtin_alloca
|
|
|
|
#elif defined _AIX
|
|
|
|
# define alloca __alloca
|
|
|
|
#elif defined _MSC_VER
|
|
|
|
# include <malloc.h>
|
|
|
|
# define alloca _alloca
|
|
|
|
#else
|
|
|
|
# include <stddef.h>
|
|
|
|
# ifdef __cplusplus
|
|
|
|
extern "C"
|
|
|
|
# endif
|
|
|
|
void *alloca (size_t);
|
|
|
|
#endif
|
|
|
|
|
2010-04-15 11:24:48 -07:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2010-11-26 09:05:16 -08:00
|
|
|
#ifdef _WIN32
|
|
|
|
# include <winsock2.h>
|
|
|
|
#endif
|
|
|
|
|
2010-11-26 13:32:34 -08:00
|
|
|
#include <Ecore.h>
|
2010-11-25 15:52:57 -08:00
|
|
|
#include <Ecore_File.h>
|
|
|
|
|
2010-04-15 11:24:48 -07:00
|
|
|
#include "Efreet.h"
|
|
|
|
#include "efreet_private.h"
|
|
|
|
|
|
|
|
#ifdef EFREET_MODULE_LOG_DOM
|
|
|
|
#undef EFREET_MODULE_LOG_DOM
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define EFREET_MODULE_LOG_DOM _efreet_desktop_log_dom
|
|
|
|
extern int _efreet_desktop_log_dom;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A unique id for each tmp file created while building a command
|
|
|
|
*/
|
|
|
|
static int efreet_desktop_command_file_id = 0;
|
|
|
|
|
|
|
|
static void *efreet_desktop_exec_cb(void *data, Efreet_Desktop *desktop,
|
|
|
|
char *exec, int remaining);
|
|
|
|
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 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_multiple(char *dest, int *size, int *len,
|
|
|
|
Efreet_Desktop_Command *command,
|
|
|
|
char type);
|
|
|
|
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_icon(char *dest, int *size, int *len,
|
|
|
|
Efreet_Desktop *desktop);
|
|
|
|
|
|
|
|
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 char *efreet_desktop_command_path_absolute(const char *path);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2011-01-27 09:49:45 -08:00
|
|
|
* @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
|
2010-04-15 11:24:48 -07:00
|
|
|
* @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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-01-27 09:49:45 -08:00
|
|
|
* @param desktop the desktop entry
|
|
|
|
* @param files an eina list of file names to execute, as either absolute paths,
|
2010-04-15 11:24:48 -07:00
|
|
|
* relative paths, or uris
|
2011-01-27 09:49:45 -08:00
|
|
|
* @param func a callback to call for each prepared command line
|
|
|
|
* @param data user data passed to the callback
|
2010-04-15 11:24:48 -07:00
|
|
|
* @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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-01-27 09:49:45 -08:00
|
|
|
* @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)
|
2010-04-15 11:24:48 -07:00
|
|
|
* @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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-01-27 09:49:45 -08:00
|
|
|
* @param desktop the desktop entry
|
|
|
|
* @param files an eina list of file names to execute, as either absolute paths,
|
2010-04-15 11:24:48 -07:00
|
|
|
* relative paths, or uris
|
2011-01-27 09:49:45 -08:00
|
|
|
* @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
|
2010-04-15 11:24:48 -07:00
|
|
|
* @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);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (execs)
|
|
|
|
{
|
|
|
|
ret = efreet_desktop_command_execs_process(command, execs);
|
|
|
|
eina_list_free(execs);
|
|
|
|
}
|
2010-04-15 11:24:48 -07:00
|
|
|
efreet_desktop_command_free(command);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*
|
2011-01-27 09:49:45 -08:00
|
|
|
* @param command the command to build
|
2010-04-15 11:24:48 -07:00
|
|
|
* @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);
|
2010-08-03 12:31:04 -07:00
|
|
|
if (!exec) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
p = command->desktop->exec;
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
while (*p)
|
|
|
|
{
|
|
|
|
if (len >= size - 1)
|
|
|
|
{
|
2010-08-03 12:30:53 -07:00
|
|
|
char *tmp;
|
|
|
|
|
2010-04-15 11:24:48 -07:00
|
|
|
size = len + 1024;
|
2010-08-03 12:30:53 -07:00
|
|
|
tmp = realloc(exec, size);
|
|
|
|
if (!tmp) goto error;
|
|
|
|
exec = tmp;
|
2010-04-15 11:24:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!exec) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
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);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!exec) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
file_added = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
exec = efreet_desktop_command_append_icon(exec, &size, &len,
|
|
|
|
command->desktop);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!exec) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
exec = efreet_desktop_command_append_quoted(exec, &size, &len,
|
|
|
|
command->desktop->name);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!exec) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
exec = efreet_desktop_command_append_quoted(exec, &size, &len,
|
|
|
|
command->desktop->orig_path);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!exec) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
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)
|
|
|
|
{
|
2010-08-03 12:30:53 -07:00
|
|
|
char *tmp;
|
2010-04-15 11:24:48 -07:00
|
|
|
size = len + 1024;
|
2010-08-03 12:30:53 -07:00
|
|
|
tmp = realloc(exec, size);
|
|
|
|
if (!tmp) goto error;
|
|
|
|
exec = tmp;
|
2010-04-15 11:24:48 -07:00
|
|
|
}
|
|
|
|
exec[len++] = ' ';
|
|
|
|
exec = efreet_desktop_command_append_multiple(exec, &size,
|
|
|
|
&len, command, 'F');
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!exec) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
file_added = 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
exec[len++] = '\0';
|
|
|
|
|
|
|
|
execs = eina_list_append(execs, exec);
|
2010-08-03 12:30:53 -07:00
|
|
|
exec = NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
2010-08-21 06:52:25 -07:00
|
|
|
while ((l = eina_list_next(l)));
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
return execs;
|
2010-08-02 13:43:09 -07:00
|
|
|
error:
|
2010-08-03 12:30:53 -07:00
|
|
|
IF_FREE(exec);
|
|
|
|
EINA_LIST_FREE(execs, exec)
|
|
|
|
free(exec);
|
2010-08-02 13:43:09 -07:00
|
|
|
return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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, "'");
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
/* single quotes in src need to be escaped */
|
|
|
|
if (strchr(src, '\''))
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
p = src;
|
|
|
|
while (*p)
|
|
|
|
{
|
|
|
|
if (*p == '\'')
|
2010-08-03 13:46:36 -07:00
|
|
|
{
|
2010-04-15 11:24:48 -07:00
|
|
|
dest = efreet_string_append(dest, size, len, "\'\\\'");
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
|
|
|
}
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
dest = efreet_string_append_char(dest, size, len, *p);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2010-08-03 13:46:36 -07:00
|
|
|
{
|
2010-04-15 11:24:48 -07:00
|
|
|
dest = efreet_string_append(dest, size, len, src);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
|
|
|
}
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
dest = efreet_string_append(dest, size, len, "'");
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
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
|
2010-08-03 13:46:36 -07:00
|
|
|
{
|
2010-04-15 11:24:48 -07:00
|
|
|
dest = efreet_string_append_char(dest, size, len, ' ');
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
|
|
|
}
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
dest = efreet_desktop_command_append_single(dest, size, len,
|
|
|
|
file, tolower(type));
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
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 ");
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
dest = efreet_desktop_command_append_quoted(dest, size, len, desktop->icon);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!dest) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-01-27 09:49:45 -08:00
|
|
|
* @param command the Efreet_Desktop_Comand that this file is for
|
|
|
|
* @param file the filname as either an absolute path, relative path, or URI
|
2010-04-15 11:24:48 -07:00
|
|
|
*/
|
|
|
|
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);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!absol) goto error;
|
2010-04-15 11:24:48 -07:00
|
|
|
/* 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;
|
2010-08-03 13:46:36 -07:00
|
|
|
error:
|
|
|
|
IF_FREE(f);
|
|
|
|
return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Find the local path portion of a file uri.
|
2011-01-27 09:49:45 -08:00
|
|
|
* @param uri a uri beginning with "file"
|
2010-04-15 11:24:48 -07:00
|
|
|
* @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);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (execs)
|
|
|
|
{
|
|
|
|
/* 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);
|
|
|
|
}
|
2010-04-15 11:24:48 -07:00
|
|
|
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.
|
2011-01-27 09:49:45 -08:00
|
|
|
* @param path an absolute or relative path
|
2010-04-15 11:24:48 -07:00
|
|
|
* @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, "/");
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!buf) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
buf = efreet_string_append(buf, &size, &len, path);
|
2010-08-03 13:46:36 -07:00
|
|
|
if (!buf) return NULL;
|
2010-04-15 11:24:48 -07:00
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* just dup an already absolute buffer */
|
|
|
|
return strdup(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
{
|
2010-08-03 12:30:53 -07:00
|
|
|
char *tmp;
|
2010-04-15 11:24:48 -07:00
|
|
|
/* we successfully appended this much */
|
|
|
|
off += *size - *len - 1;
|
|
|
|
*len = *size - 1;
|
|
|
|
*size += 1024;
|
2010-08-03 12:30:53 -07:00
|
|
|
tmp = realloc(dest, *size);
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
free(dest);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
dest = tmp;
|
2010-04-15 11:24:48 -07:00
|
|
|
*(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)
|
|
|
|
{
|
2010-08-03 12:30:53 -07:00
|
|
|
char *tmp;
|
2010-04-15 11:24:48 -07:00
|
|
|
*size += 1024;
|
2010-08-03 12:30:53 -07:00
|
|
|
tmp = realloc(dest, *size);
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
free(dest);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
dest = tmp;
|
2010-04-15 11:24:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
dest[(*len)++] = c;
|
|
|
|
dest[*len] = '\0';
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|