Introduce the MimeHandler class

This commit is contained in:
Pierre Pronchery 2017-12-07 17:51:44 +01:00
parent e5f5729e56
commit 94c0dae8a9
6 changed files with 336 additions and 5 deletions

View File

@ -32,6 +32,7 @@
# define LIBDESKTOP_DESKTOP_MIME_H # define LIBDESKTOP_DESKTOP_MIME_H
# include <gtk/gtk.h> # include <gtk/gtk.h>
# include "mimehandler.h"
/* Mime */ /* Mime */
@ -47,7 +48,7 @@ Mime * mime_new(GtkIconTheme * theme);
void mime_delete(Mime * mime); void mime_delete(Mime * mime);
/* accessors */ /* accessors */
char const * mime_get_handler(Mime * mime, char const * type, MimeHandler * mime_get_handler(Mime * mime, char const * type,
char const * action); char const * action);
int mime_set_handler(Mime * mime, char const * type, char const * action, int mime_set_handler(Mime * mime, char const * type, char const * action,
char const * handler); char const * handler);

View File

@ -0,0 +1,70 @@
/* $Id$ */
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Desktop libDesktop */
/* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#ifndef LIBDESKTOP_DESKTOP_MIMEHANDLER_H
# define LIBDESKTOP_DESKTOP_MIMEHANDLER_H
# include <System/config.h>
# include <System/string.h>
/* MimeHandler */
/* types */
typedef struct _Hash MimeHandler;
typedef enum _MimeHandlerType
{
MIME_HANDLER_TYPE_UNKNOWN = 0,
MIME_HANDLER_TYPE_APPLICATION,
MIME_HANDLER_TYPE_DIRECTORY,
MIME_HANDLER_TYPE_URL
} MimeHandlerType;
/* functions */
MimeHandler * mimehandler_new(void);
MimeHandler * mimehandler_new_load(String const * name);
void mimehandler_delete(MimeHandler * handler);
/* accessors */
int mimehandler_can_display(MimeHandler * handler);
int mimehandler_can_execute(MimeHandler * handler);
String const * mimehandler_get_name(MimeHandler * handler);
String const * mimehandler_get_program(MimeHandler * handler);
MimeHandlerType mimehandler_get_type(MimeHandler * handler);
int mimehandler_is_hidden(MimeHandler * handler);
/* useful */
int mimehandler_load_by_name(MimeHandler * handler, String const * name);
int mimehandler_save(MimeHandler * handler);
#endif /* !LIBDESKTOP_DESKTOP_MIMEHANDLER_H */

View File

@ -1,4 +1,4 @@
includes=about.h,accel.h,compat.h,help.h,menubar.h,message.h,mime.h,toolbar.h,widget.h includes=about.h,accel.h,compat.h,help.h,menubar.h,message.h,mime.h,mimehandler.h,toolbar.h,widget.h
dist=Makefile dist=Makefile
[about.h] [about.h]
@ -22,6 +22,9 @@ install=$(INCLUDEDIR)/Desktop
[mime.h] [mime.h]
install=$(INCLUDEDIR)/Desktop install=$(INCLUDEDIR)/Desktop
[mimehandler.h]
install=$(INCLUDEDIR)/Desktop
[toolbar.h] [toolbar.h]
install=$(INCLUDEDIR)/Desktop install=$(INCLUDEDIR)/Desktop

View File

@ -225,7 +225,7 @@ void mime_delete(Mime * mime)
/* accessors */ /* accessors */
/* mime_get_handler */ /* mime_get_handler */
char const * mime_get_handler(Mime * mime, char const * type, MimeHandler * mime_get_handler(Mime * mime, char const * type,
char const * action) char const * action)
{ {
char const * program; char const * program;
@ -250,7 +250,7 @@ char const * mime_get_handler(Mime * mime, char const * type,
q[2] = '\0'; q[2] = '\0';
program = config_get(mime->config, p, action); program = config_get(mime->config, p, action);
free(p); free(p);
return program; return mimehandler_new_load(program);
} }

257
src/mimehandler.c Normal file
View File

@ -0,0 +1,257 @@
/* $Id$ */
/* Copyright (c) 2017 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS libDesktop */
/* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "Desktop.h"
/* private */
/* constants */
#define EXTENSION ".desktop"
#define SECTION "Desktop Entry"
/* public */
/* functions */
/* mimehandler_new */
MimeHandler * mimehandler_new(void)
{
return config_new();
}
/* mimehandler_new_load */
MimeHandler * mimehandler_new_load(String const * name)
{
MimeHandler * handler;
if((handler = mimehandler_new()) == NULL)
return NULL;
if(mimehandler_load_by_name(handler, name) != 0)
{
mimehandler_delete(handler);
return NULL;
}
return handler;
}
/* mimehandler_delete */
void mimehandler_delete(MimeHandler * handler)
{
config_delete(handler);
}
/* accessors */
/* mimehandler_can_display */
int mimehandler_can_display(MimeHandler * handler)
{
String const * p;
if((p = config_get(handler, SECTION, "NoDisplay")) == NULL)
return 1;
return (string_compare(p, "true") == 0) ? 1 : 0;
}
/* mimehandler_can_execute */
static int _can_execute_access(String const * path, int mode);
static int _can_execute_access_path(String const * path,
String const * filename, int mode);
int mimehandler_can_execute(MimeHandler * handler)
{
String const * p;
if(mimehandler_get_type(handler) != MIME_HANDLER_TYPE_APPLICATION)
return 0;
if((p = config_get(handler, SECTION, "TryExec")) == NULL)
return 1;
return _can_execute_access(p, X_OK);
}
static int _can_execute_access(String const * path, int mode)
{
int ret = -1;
String const * p;
String * q;
String * last;
if(path[0] == '/')
return access(path, mode);
if((p = getenv("PATH")) == NULL)
return 0;
if((q = string_new(p)) == NULL)
return 0;
for(p = strtok_r(q, ":", &last); p != NULL;
p = strtok_r(NULL, ":", &last))
ret = _can_execute_access_path(p, path, mode);
string_delete(q);
return ret;
}
static int _can_execute_access_path(String const * path,
String const * filename, int mode)
{
int ret;
String * p;
if((p = string_new_append(path, "/", filename, NULL)) == NULL)
return -1;
ret = access(p, mode);
string_delete(p);
return ret;
}
/* mimehandler_get_name */
String const * mimehandler_get_name(MimeHandler * handler)
{
return config_get(handler, SECTION, "Name");
}
/* mimehandler_get_program */
String const * mimehandler_get_program(MimeHandler * handler)
{
switch(mimehandler_get_type(handler))
{
case MIME_HANDLER_TYPE_APPLICATION:
/* XXX may be a format string */
return config_get(handler, SECTION, "Exec");
case MIME_HANDLER_TYPE_DIRECTORY:
case MIME_HANDLER_TYPE_UNKNOWN:
case MIME_HANDLER_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",MIME_HANDLER_TYPE_APPLICATION },
{ "Directory", MIME_HANDLER_TYPE_DIRECTORY },
{ "URL", MIME_HANDLER_TYPE_URL }
};
size_t i;
if((type = config_get(handler, SECTION, "Type")) == NULL)
return MIME_HANDLER_TYPE_UNKNOWN;
for(i = 0; i < sizeof(types) / sizeof(*types); i++)
if(string_compare(types[i].name, type) == 0)
return types[i].type;
return MIME_HANDLER_TYPE_UNKNOWN;
}
/* mimehandler_is_hidden */
int mimehandler_is_hidden(MimeHandler * handler)
{
String const * p;
if((p = config_get(handler, SECTION, "Hidden")) == NULL)
return 0;
return (string_compare(p, "true") == 0) ? 1 : 0;
}
/* useful */
/* mimehandler_load_by_name */
static int _load_by_name_path(MimeHandler * handler, String const * name,
String const * path);
int mimehandler_load_by_name(MimeHandler * handler, String const * name)
{
int ret;
String const fallback[] = ".local/share";
String const * path;
String const * homedir;
String * p;
String const * q;
String * last;
/* use $XDG_DATA_HOME if set and not empty */
if((path = getenv("XDG_DATA_HOME")) != NULL && strlen(path) > 0
&& _load_by_name_path(handler, name, path) == 0)
return 0;
/* fallback to "$HOME/.local/share" */
if((homedir = getenv("HOME")) == NULL)
homedir = g_get_home_dir();
if((p = string_new_append(homedir, "/", fallback, NULL)) == NULL)
return -1;
ret = _load_by_name_path(handler, name, p);
string_delete(p);
if(ret == 0)
return ret;
/* read through every XDG application folder */
if((path = getenv("XDG_DATA_DIRS")) == NULL || strlen(path) == 0)
path = "/usr/local/share:/usr/share";
if((p = string_new(path)) == NULL)
return -1;
for(q = strtok_r(p, ":", &last); q != NULL;
q = strtok_r(NULL, ":", &last))
if((ret = _load_by_name_path(handler, name, q)) == 0)
break;
string_delete(p);
return ret;
}
static int _load_by_name_path(MimeHandler * handler, String const * name,
String const * path)
{
int ret;
String const applications[] = "/applications/";
String * pathname;
if((pathname = string_new_append(path, applications, name, EXTENSION,
NULL)) == NULL)
return -1;
ret = (config_reset(handler) == 0
&& config_load(handler, pathname) == 0
&& mimehandler_get_type(handler)
!= MIME_HANDLER_TYPE_UNKNOWN
&& mimehandler_get_name(handler) != NULL
&& mimehandler_is_hidden(handler) == 0)
? 0 : -1;
string_delete(pathname);
return ret;
}

View File

@ -12,7 +12,7 @@ dist=Makefile
[libDesktop] [libDesktop]
type=library type=library
sources=about.c,accel.c,compat.c,help.c,menubar.c,message.c,mime.c,toolbar.c,widget.c sources=about.c,accel.c,compat.c,help.c,menubar.c,message.c,mime.c,mimehandler.c,toolbar.c,widget.c
install=$(PREFIX)/lib install=$(PREFIX)/lib
[help.c] [help.c]