diff --git a/include/Desktop/mimehandler.h b/include/Desktop/mimehandler.h index a8bf691..d8ff6d7 100644 --- a/include/Desktop/mimehandler.h +++ b/include/Desktop/mimehandler.h @@ -37,7 +37,7 @@ /* MimeHandler */ /* types */ -typedef struct _Hash MimeHandler; +typedef struct _MimeHandler MimeHandler; typedef enum _MimeHandlerType { @@ -59,19 +59,23 @@ int mimehandler_can_display(MimeHandler * handler); int mimehandler_can_execute(MimeHandler * handler); int mimehandler_can_open(MimeHandler * handler); +String const ** mimehandler_get_categories(MimeHandler * handler); String const * mimehandler_get_comment(MimeHandler * handler); +String const * mimehandler_get_filename(MimeHandler * handler); String const * mimehandler_get_generic_name(MimeHandler * handler); String const * mimehandler_get_icon(MimeHandler * handler); String const * mimehandler_get_name(MimeHandler * handler); String const * mimehandler_get_path(MimeHandler * handler); String const * mimehandler_get_program(MimeHandler * handler); MimeHandlerType mimehandler_get_type(MimeHandler * handler); -String ** mimehandler_get_types(MimeHandler * handler); +String const ** mimehandler_get_types(MimeHandler * handler); String const * mimehandler_get_url(MimeHandler * handler); int mimehandler_is_hidden(MimeHandler * handler); /* useful */ +int mimehandler_execute(MimeHandler * handler, String const * filename); + int mimehandler_load(MimeHandler * handler, String const * filename); int mimehandler_load_by_name(MimeHandler * handler, String const * name); int mimehandler_save(MimeHandler * handler); diff --git a/src/mimehandler.c b/src/mimehandler.c index 8c9e688..0a156a8 100644 --- a/src/mimehandler.c +++ b/src/mimehandler.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "Desktop.h" #ifndef PREFIX @@ -42,17 +44,44 @@ /* private */ +/* types */ +struct _MimeHandler +{ + Config * config; + String * filename; + String ** categories; + String ** types; +}; + + /* constants */ #define EXTENSION ".desktop" #define SECTION "Desktop Entry" +/* prototypes */ +static void _mimehandler_cache_invalidate(MimeHandler * handler); + + /* public */ /* functions */ /* mimehandler_new */ MimeHandler * mimehandler_new(void) { - return config_new(); + MimeHandler * handler; + + if((handler = object_new(sizeof(*handler))) == NULL) + return NULL; + handler->config = config_new(); + handler->filename = NULL; + handler->categories = NULL; + handler->types = NULL; + if(handler->config == NULL) + { + mimehandler_delete(handler); + return NULL; + } + return handler; } @@ -91,7 +120,10 @@ MimeHandler * mimehandler_new_open(String const * filename) /* mimehandler_delete */ void mimehandler_delete(MimeHandler * handler) { - config_delete(handler); + _mimehandler_cache_invalidate(handler); + config_delete(handler->config); + string_delete(handler->filename); + object_delete(handler); } @@ -101,7 +133,7 @@ int mimehandler_can_display(MimeHandler * handler) { String const * p; - if((p = config_get(handler, SECTION, "NoDisplay")) == NULL) + if((p = config_get(handler->config, SECTION, "NoDisplay")) == NULL) return 1; return (string_compare(p, "true") == 0) ? 1 : 0; } @@ -118,10 +150,10 @@ int mimehandler_can_execute(MimeHandler * handler) if(mimehandler_get_type(handler) != MIMEHANDLER_TYPE_APPLICATION) return 0; - if((p = config_get(handler, SECTION, "TryExec")) != NULL + if((p = config_get(handler->config, SECTION, "TryExec")) != NULL && _can_execute_access(p, X_OK) == 0) return 0; - return (config_get(handler, SECTION, "Exec") != NULL) ? 1 : 0; + return (config_get(handler->config, SECTION, "Exec") != NULL) ? 1 : 0; } static int _can_execute_access(String const * path, int mode) @@ -178,92 +210,8 @@ int mimehandler_can_open(MimeHandler * handler) } -/* mimehandler_get_comment */ -String const * mimehandler_get_comment(MimeHandler * handler) -{ - return config_get(handler, SECTION, "Comment"); -} - - -/* mimehandler_get_generic_name */ -String const * mimehandler_get_generic_name(MimeHandler * handler) -{ - return config_get(handler, SECTION, "GenericName"); -} - - -/* mimehandler_get_icon */ -String const * mimehandler_get_icon(MimeHandler * handler) -{ - return config_get(handler, SECTION, "Icon"); -} - - -/* mimehandler_get_name */ -String const * mimehandler_get_name(MimeHandler * handler) -{ - return config_get(handler, SECTION, "Name"); -} - - -/* mimehandler_get_path */ -String const * mimehandler_get_path(MimeHandler * handler) -{ - switch(mimehandler_get_type(handler)) - { - case MIMEHANDLER_TYPE_APPLICATION: - case MIMEHANDLER_TYPE_DIRECTORY: - return config_get(handler, SECTION, "Path"); - default: - return NULL; - } -} - - -/* mimehandler_get_program */ -String const * mimehandler_get_program(MimeHandler * handler) -{ - switch(mimehandler_get_type(handler)) - { - case MIMEHANDLER_TYPE_APPLICATION: - /* XXX may be a format string */ - return config_get(handler, SECTION, "Exec"); - case MIMEHANDLER_TYPE_DIRECTORY: - case MIMEHANDLER_TYPE_UNKNOWN: - case MIMEHANDLER_TYPE_URL: - return NULL; - } - return NULL; -} - - -/* mimehandler_get_type */ -MimeHandlerType mimehandler_get_type(MimeHandler * handler) -{ - String const * type; - struct - { - String const * name; - MimeHandlerType type; - } types[] = - { - { "Application",MIMEHANDLER_TYPE_APPLICATION }, - { "Directory", MIMEHANDLER_TYPE_DIRECTORY }, - { "URL", MIMEHANDLER_TYPE_URL } - }; - size_t i; - - if((type = config_get(handler, SECTION, "Type")) == NULL) - return MIMEHANDLER_TYPE_UNKNOWN; - for(i = 0; i < sizeof(types) / sizeof(*types); i++) - if(string_compare(types[i].name, type) == 0) - return types[i].type; - return MIMEHANDLER_TYPE_UNKNOWN; -} - - -/* mimehandler_get_types */ -String ** mimehandler_get_types(MimeHandler * handler) +/* mimehandler_get_categories */ +String const ** mimehandler_get_categories(MimeHandler * handler) { String ** ret = NULL; size_t cnt = 0; @@ -273,13 +221,14 @@ String ** mimehandler_get_types(MimeHandler * handler) String * last; String ** r; - if(mimehandler_get_type(handler) != MIMEHANDLER_TYPE_APPLICATION) - return NULL; - if((p = config_get(handler, SECTION, "MimeType")) == NULL) + if(handler->categories != NULL) + return (String const **)handler->categories; + if((p = config_get(handler->config, SECTION, "Categories")) == NULL) { if((ret = malloc(sizeof(String *))) == NULL) return NULL; ret[0] = NULL; + handler->categories = ret; return ret; } if((q = string_new(p)) == NULL) @@ -305,6 +254,149 @@ String ** mimehandler_get_types(MimeHandler * handler) } if(ret != NULL) ret[cnt] = NULL; + handler->categories = ret; + return ret; +} + + +/* mimehandler_get_comment */ +String const * mimehandler_get_comment(MimeHandler * handler) +{ + return config_get(handler->config, SECTION, "Comment"); +} + + +/* mimehandler_get_filename */ +String const * mimehandler_get_filename(MimeHandler * handler) +{ + return handler->filename; +} + + +/* mimehandler_get_generic_name */ +String const * mimehandler_get_generic_name(MimeHandler * handler) +{ + return config_get(handler->config, SECTION, "GenericName"); +} + + +/* mimehandler_get_icon */ +String const * mimehandler_get_icon(MimeHandler * handler) +{ + return config_get(handler->config, SECTION, "Icon"); +} + + +/* mimehandler_get_name */ +String const * mimehandler_get_name(MimeHandler * handler) +{ + return config_get(handler->config, SECTION, "Name"); +} + + +/* mimehandler_get_path */ +String const * mimehandler_get_path(MimeHandler * handler) +{ + switch(mimehandler_get_type(handler)) + { + case MIMEHANDLER_TYPE_APPLICATION: + case MIMEHANDLER_TYPE_DIRECTORY: + return config_get(handler->config, SECTION, "Path"); + default: + return NULL; + } +} + + +/* mimehandler_get_program */ +String const * mimehandler_get_program(MimeHandler * handler) +{ + switch(mimehandler_get_type(handler)) + { + case MIMEHANDLER_TYPE_APPLICATION: + /* XXX may be a format string */ + return config_get(handler->config, SECTION, "Exec"); + case MIMEHANDLER_TYPE_DIRECTORY: + case MIMEHANDLER_TYPE_UNKNOWN: + case MIMEHANDLER_TYPE_URL: + return NULL; + } + return NULL; +} + + +/* mimehandler_get_type */ +MimeHandlerType mimehandler_get_type(MimeHandler * handler) +{ + String const * type; + struct + { + String const * name; + MimeHandlerType type; + } types[] = + { + { "Application",MIMEHANDLER_TYPE_APPLICATION }, + { "Directory", MIMEHANDLER_TYPE_DIRECTORY }, + { "URL", MIMEHANDLER_TYPE_URL } + }; + size_t i; + + if((type = config_get(handler->config, SECTION, "Type")) == NULL) + return MIMEHANDLER_TYPE_UNKNOWN; + for(i = 0; i < sizeof(types) / sizeof(*types); i++) + if(string_compare(types[i].name, type) == 0) + return types[i].type; + return MIMEHANDLER_TYPE_UNKNOWN; +} + + +/* mimehandler_get_types */ +String const ** mimehandler_get_types(MimeHandler * handler) +{ + String ** ret = NULL; + size_t cnt = 0; + size_t i; + String const * p; + String * q; + String * last; + String ** r; + + if(handler->types != NULL) + return handler->types; + if(mimehandler_get_type(handler) != MIMEHANDLER_TYPE_APPLICATION) + return NULL; + if((p = config_get(handler->config, SECTION, "MimeType")) == NULL) + { + if((ret = malloc(sizeof(String *))) == NULL) + return NULL; + ret[0] = NULL; + handler->types = ret; + return ret; + } + if((q = string_new(p)) == NULL) + return NULL; + for(p = strtok_r(q, ":", &last); p != NULL; + p = strtok_r(NULL, ":", &last)) + { + if(strlen(p) == 0) + continue; + if((r = realloc(ret, sizeof(*ret) * (cnt + 1))) != NULL) + { + ret = r; + ret[cnt] = string_new(p); + } + if(r == NULL || ret[cnt] == NULL) + { + for(i = 0; i < cnt; i++) + string_delete(ret[i]); + free(ret); + return NULL; + } + cnt++; + } + if(ret != NULL) + ret[cnt] = NULL; + handler->types = ret; return ret; } @@ -313,7 +405,7 @@ String ** mimehandler_get_types(MimeHandler * handler) String const * mimehandler_get_url(MimeHandler * handler) { if(mimehandler_get_type(handler) == MIMEHANDLER_TYPE_URL) - return config_get(handler, SECTION, "URL"); + return config_get(handler->config, SECTION, "URL"); return NULL; } @@ -323,23 +415,86 @@ int mimehandler_is_hidden(MimeHandler * handler) { String const * p; - if((p = config_get(handler, SECTION, "Hidden")) == NULL) + if((p = config_get(handler->config, SECTION, "Hidden")) == NULL) return 0; return (string_compare(p, "true") == 0) ? 1 : 0; } /* useful */ +/* mimehandler_execute */ +int mimehandler_execute(MimeHandler * handler, String const * filename) +{ + /* FIXME implement filename */ + int ret = 0; + String * program; + String * p; + String const * q; + pid_t pid; + GError * error = NULL; + + if((q = config_get(handler->config, SECTION, "Exec")) == NULL) + return -1; + if((program = string_new(q)) == NULL) + return -1; + /* XXX crude way to ignore %f, %F, %u and %U */ + if((p = strchr(program, '%')) != NULL) + *p = '\0'; +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() \"%s\"", __func__, program); +#endif + if((q = mimehandler_get_path(handler)) == NULL) + { + /* execute the program directly */ + if(g_spawn_command_line_async(program, &error) != TRUE) + { + error_set_code(1, "%s: %s", program, error->message); + g_error_free(error); + } + } + else if((pid = fork()) == 0) + { + /* change the current working directory */ + if(chdir(q) != 0) + error_set_code(-errno, "%s: %s: %s", program, q, + strerror(errno)); + else if(g_spawn_command_line_async(program, &error) != TRUE) + { + error_set_code(1, "%s: %s", program, error->message); + g_error_free(error); + } + exit(125); + } + else if(pid < 0) + { + error_set_code(-errno, "%s: %s", program, strerror(errno)); + ret = -1; + } + string_delete(program); + return ret; +} + + /* mimehandler_load */ int mimehandler_load(MimeHandler * handler, String const * filename) { - return (config_reset(handler) == 0 - && config_load(handler, filename) == 0 - && mimehandler_get_type(handler) - != MIMEHANDLER_TYPE_UNKNOWN - && mimehandler_get_name(handler) != NULL - && mimehandler_is_hidden(handler) == 0) - ? 0 : -1; + Config * config; + String * p; + + if((config = config_new()) == NULL) + return -1; + if(config_load(config, filename) != 0 + || (p = string_new(filename)) == NULL) + { + config_delete(config); + return -1; + } + config_delete(handler->config); + handler->config = config; + string_delete(handler->filename); + handler->filename = p; + _mimehandler_cache_invalidate(handler); + return 0; } @@ -397,3 +552,22 @@ static int _load_by_name_path(MimeHandler * handler, String const * name, string_delete(filename); return ret; } + + +/* private */ +/* mimehandler_cache_invalidate */ +static void _mimehandler_cache_invalidate(MimeHandler * handler) +{ + size_t i; + + if(handler->categories != NULL) + for(i = 0; handler->categories[i] != NULL; i++) + string_delete(handler->categories[i]); + free(handler->categories); + handler->categories = NULL; + if(handler->types != NULL) + for(i = 0; handler->types[i] != NULL; i++) + string_delete(handler->types[i]); + free(handler->types); + handler->types = NULL; +}