From 774fa628467f394b3afe36bc785562b0049d122c Mon Sep 17 00:00:00 2001 From: Stefano Karapetsas Date: Thu, 17 Oct 2013 16:26:20 +0200 Subject: Add gksu extension --- Makefile.am | 1 + configure.ac | 7 +- gksu/Makefile.am | 9 ++ gksu/libcaja-gksu.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + 5 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 gksu/Makefile.am create mode 100644 gksu/libcaja-gksu.c diff --git a/Makefile.am b/Makefile.am index 478fedb..c43bfa5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = \ po \ + gksu \ open-terminal EXTRA_DIST = \ diff --git a/configure.ac b/configure.ac index be1702e..ffcdfc8 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ AC_CONFIG_HEADERS(config.h) CAJA_REQUIRED=1.5.0 LIBMATE_DESKTOP_REQUIRED=1.5.0 -GLIB_REQUIRED=2.13.3 +GLIB_REQUIRED=2.14.0 GLIB_GSETTINGS @@ -22,12 +22,12 @@ if test "x$HAVE_PKGCONFIG" = "xno"; then fi # Common requirements -PKG_CHECK_MODULES(CAJA, libcaja-extension >= $CAJA_REQUIRED glib-2.0 >= $GLIB_REQUIRED) +PKG_CHECK_MODULES(CAJA, libcaja-extension >= $CAJA_REQUIRED) AC_SUBST(CAJA_CFLAGS) AC_SUBST(CAJA_LIBS) # open-terminal -PKG_CHECK_MODULES(OPENTERMINAL, mate-desktop-2.0 >= $LIBMATE_DESKTOP_REQUIRED) +PKG_CHECK_MODULES(OPENTERMINAL, glib-2.0 >= $GLIB_REQUIRED mate-desktop-2.0 >= $LIBMATE_DESKTOP_REQUIRED) AC_SUBST(OPENTERMINAL_CFLAGS) AC_SUBST(OPENTERMINAL_LIBS) @@ -45,6 +45,7 @@ AM_GLIB_GNU_GETTEXT AC_OUTPUT([ Makefile + gksu/Makefile open-terminal/Makefile po/Makefile.in ]) diff --git a/gksu/Makefile.am b/gksu/Makefile.am new file mode 100644 index 0000000..4180075 --- /dev/null +++ b/gksu/Makefile.am @@ -0,0 +1,9 @@ +AM_CFLAGS = -g -O2 -Wall +INCLUDES = ${CAJA_CFLAGS} +AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/locale\" -DDATA_DIR=\"$(datadir)\" -DPREFIX=\"$(prefix)\" + +caja_extensiondir=$(libdir)/caja/extensions-2.0 +caja_extension_LTLIBRARIES = libcaja-gksu.la +libcaja_gksu_la_SOURCES = libcaja-gksu.c +libcaja_gksu_la_LDFLAGS = LDFLAGS = -module -avoid-version -no-undefined +libcaja_gksu_la_LIBADD = $(CAJA_LIBS) diff --git a/gksu/libcaja-gksu.c b/gksu/libcaja-gksu.c new file mode 100644 index 0000000..18c8db1 --- /dev/null +++ b/gksu/libcaja-gksu.c @@ -0,0 +1,281 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../config.h" + +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) + +#define GKSU_TYPE_CONTEXT_MENU (gksu_context_menu_get_type ()) +#define GKSU_CONTEXT_MENU(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GKSU_TYPE_CONTEXT_MENU)) + +typedef struct { + GObject parent; +} GksuContextMenu; + +typedef struct { + GObjectClass parent_class; +} GksuContextMenuClass; + +static GType gksucm_type = 0; +static GObjectClass *parent_class = NULL; + +static void +gksu_context_menu_init (GksuContextMenu *self); +static void +gksu_context_menu_class_init (GksuContextMenuClass *class); +static void +menu_provider_iface_init (CajaMenuProviderIface *iface); + +static GList* +gksu_context_menu_get_file_items (CajaMenuProvider *provider, + GtkWidget *window, + GList *files); +static void +gksu_context_menu_activate (CajaMenuItem *item, + CajaFileInfo *file); + +static GType +gksu_context_menu_get_type (void) +{ + return gksucm_type; +} + +static void +gksu_context_menu_register_type (GTypeModule *module) +{ + static const GTypeInfo info = { + sizeof (GksuContextMenuClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gksu_context_menu_class_init, + NULL, + NULL, + sizeof (GksuContextMenu), + 0, + (GInstanceInitFunc) gksu_context_menu_init + }; + static const GInterfaceInfo menu_provider_iface_info = { + (GInterfaceInitFunc)menu_provider_iface_init, + NULL, + NULL + }; + + gksucm_type = g_type_module_register_type (module, + G_TYPE_OBJECT, + "GksuContextMenu", + &info, 0); + g_type_module_add_interface (module, + gksucm_type, + CAJA_TYPE_MENU_PROVIDER, + &menu_provider_iface_info); +} + +static void +gksu_context_menu_class_init (GksuContextMenuClass *class) +{ + parent_class = g_type_class_peek_parent (class); +} + +static void menu_provider_iface_init (CajaMenuProviderIface *iface) +{ + iface->get_file_items = gksu_context_menu_get_file_items; +} + +static void +gksu_context_menu_init (GksuContextMenu *self) +{ + g_message ("Initializing gksu extension..."); +} + +static GList * +gksu_context_menu_get_file_items (CajaMenuProvider *provider, + GtkWidget *window, + GList *files) +{ + GList *items = NULL; + CajaFileInfo *file; + CajaMenuItem *item; + + /* if we're already root, really or effectively, do not add + the menu item */ + if (geteuid () == 0) + return NULL; + + /* only add a menu item if a single file is selected ... */ + if (files == NULL || files->next != NULL) + return NULL; + + file = files->data; + + /* ... and if it is not a caja special item */ + { + gchar *uri_scheme = NULL; + + uri_scheme = caja_file_info_get_uri_scheme (file); + if (!strncmp (uri_scheme, "x-caja-desktop", 18)) + { + g_free (uri_scheme); + return NULL; + } + g_free (uri_scheme); + } + + /* create the context menu item */ + item = caja_menu_item_new ("Gksu::open_as_root", + _("Open as administrator"), + _("Opens the file with administrator privileges"), + NULL); + g_signal_connect_object (item, "activate", + G_CALLBACK (gksu_context_menu_activate), + file, 0); + items = g_list_prepend (items, item); + + return items; +} + +gboolean +is_gksu_dead (gpointer data) +{ + GPid pid = GPOINTER_TO_INT(data); + if (waitpid (pid, NULL, WNOHANG) > 0) + return FALSE; + return TRUE; +} + +static void* +start_gksu_thread (void *data) +{ + GPid pid; + gchar **argv = (gchar**) g_malloc (sizeof (gchar*) * 3); + gchar *full_cmd = (gchar*) data; + + argv[0] = g_strdup ("gksu"); + argv[1] = full_cmd; + argv[2] = NULL; + + g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, + &pid, NULL); + g_timeout_add (5000, is_gksu_dead, GINT_TO_POINTER(pid)); + + g_free (argv[0]); + g_free (full_cmd); + g_free (argv); + + return NULL; +} + +static void +gksu_context_menu_activate (CajaMenuItem *item, + CajaFileInfo *file) +{ + gchar *uri = NULL; + gchar *mime_type = NULL; + gchar *cmd = NULL; + gchar *full_cmd = NULL; + gchar *tmp = NULL; + gboolean is_desktop = FALSE; + + uri = caja_file_info_get_uri (file); + mime_type = caja_file_info_get_mime_type (file); + + if (!strcmp (mime_type, "application/x-desktop")) + { /* we're handling a .desktop file */ + GKeyFile *key_file = g_key_file_new (); + gint retval = 0; + + is_desktop = TRUE; + + gchar *file_path = g_filename_from_uri (uri, NULL, NULL); + retval = g_key_file_load_from_file (key_file, file_path, 0, NULL); + g_free (file_path); + + if (retval) + cmd = g_key_file_get_string (key_file, "Desktop Entry", "Exec", NULL); + g_key_file_free (key_file); + } + else + { + GAppInfo *app_info = g_app_info_get_default_for_type (mime_type, strncmp (uri, "file://", 7)); + if (app_info) + { + cmd = g_strdup (g_app_info_get_executable (app_info)); + g_object_unref (app_info); + } + } + + if (cmd == NULL) + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new_with_markup (NULL, 0, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("" + "Unable to determine the program to run." + "\n\n" + "The item you selected cannot be open with " + "administrator powers because the correct " + "application cannot be determined.")); + gtk_dialog_run (GTK_DIALOG(dialog)); + gtk_widget_destroy (dialog); + return; + } + + /* + * FIXME: remove any FreeDesktop substitution variable for now; we + * need to process them! + */ + tmp = strstr (cmd, "%"); + if (tmp) + *tmp = '\0'; + + if (is_desktop) + full_cmd = cmd; + else + { + full_cmd = g_strdup_printf ("%s '%s'", cmd, uri); + g_free (cmd); + } + + { + pthread_t new_thread; + pthread_create (&new_thread, NULL, start_gksu_thread, (void*)full_cmd); + } + + /* full_cmd is freed by start_gksu_thread */ + g_free (uri); + g_free (mime_type); +} + +/* --- extension interface --- */ +void +caja_module_initialize (GTypeModule *module) +{ + gksu_context_menu_register_type (module); +} + +void +caja_module_shutdown (void) +{ +} + +void +caja_module_list_types (const GType **types, + int *num_types) +{ + static GType type_list[1]; + + type_list[0] = GKSU_TYPE_CONTEXT_MENU; + *types = type_list; + *num_types = G_N_ELEMENTS (type_list); +} diff --git a/po/POTFILES.in b/po/POTFILES.in index ff9a8c2..6dfb3c2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,4 +1,5 @@ # List of source files containing translatable strings. # Please keep this list in alphabetic order. +gksu/libcaja-gksu.c open-terminal/caja-open-terminal.c open-terminal/org.mate.caja-open-terminal.gschema.xml.in -- cgit v1.2.1