1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 
5 #include <glib/gi18n-lib.h>
6 
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <glib.h>
11 #include <gtk/gtk.h>
12 #include <gio/gio.h>
13 #include <libcaja-extension/caja-extension-types.h>
14 #include <libcaja-extension/caja-menu-provider.h>
15 
16 #define GKSU_TYPE_CONTEXT_MENU (gksu_context_menu_get_type ())
17 
18 typedef struct {
19     GObject parent;
20 } GksuContextMenu;
21 
22 typedef struct {
23     GObjectClass parent_class;
24 } GksuContextMenuClass;
25 
26 static GType gksucm_type = 0;
27 static GObjectClass *parent_class = NULL;
28 
29 static void
30 gksu_context_menu_init (GksuContextMenu *self);
31 static void
32 gksu_context_menu_class_init (GksuContextMenuClass *class);
33 static void
34 menu_provider_iface_init (CajaMenuProviderIface *iface);
35 
36 static GList*
37 gksu_context_menu_get_file_items (CajaMenuProvider *provider,
38 				  GtkWidget *window,
39 				  GList *files);
40 static void
41 gksu_context_menu_activate (CajaMenuItem *item,
42 			    CajaFileInfo *file);
43 
44 static GType
gksu_context_menu_get_type(void)45 gksu_context_menu_get_type (void)
46 {
47     return gksucm_type;
48 }
49 
50 static void
gksu_context_menu_register_type(GTypeModule * module)51 gksu_context_menu_register_type (GTypeModule *module)
52 {
53     static const GTypeInfo info = {
54 	sizeof (GksuContextMenuClass),
55 	(GBaseInitFunc) NULL,
56 	(GBaseFinalizeFunc) NULL,
57 	(GClassInitFunc) gksu_context_menu_class_init,
58 	NULL,
59 	NULL,
60 	sizeof (GksuContextMenu),
61 	0,
62 	(GInstanceInitFunc) gksu_context_menu_init
63     };
64     static const GInterfaceInfo menu_provider_iface_info = {
65 	(GInterfaceInitFunc)menu_provider_iface_init,
66 	NULL,
67 	NULL
68     };
69 
70     gksucm_type = g_type_module_register_type (module,
71 					    G_TYPE_OBJECT,
72 					    "GksuContextMenu",
73 					    &info, 0);
74     g_type_module_add_interface (module,
75 				 gksucm_type,
76 				 CAJA_TYPE_MENU_PROVIDER,
77 				 &menu_provider_iface_info);
78 }
79 
80 static void
gksu_context_menu_class_init(GksuContextMenuClass * class)81 gksu_context_menu_class_init (GksuContextMenuClass *class)
82 {
83     parent_class = g_type_class_peek_parent (class);
84 }
85 
menu_provider_iface_init(CajaMenuProviderIface * iface)86 static void menu_provider_iface_init (CajaMenuProviderIface *iface)
87 {
88     iface->get_file_items = gksu_context_menu_get_file_items;
89 }
90 
91 static void
gksu_context_menu_init(GksuContextMenu * self)92 gksu_context_menu_init (GksuContextMenu *self)
93 {
94   g_message ("Initializing gksu extension...");
95 }
96 
97 static GList *
gksu_context_menu_get_file_items(CajaMenuProvider * provider,GtkWidget * window,GList * files)98 gksu_context_menu_get_file_items (CajaMenuProvider *provider,
99 				  GtkWidget *window,
100 				  GList *files)
101 {
102     GList *items = NULL;
103     CajaFileInfo *file;
104     CajaMenuItem *item;
105 
106     /* if we're already root, really or effectively, do not add
107        the menu item */
108     if (geteuid () == 0)
109       return NULL;
110 
111     /* only add a menu item if a single file is selected ... */
112     if (files == NULL || files->next != NULL)
113       return NULL;
114 
115     file = files->data;
116 
117     /* ... and if it is not a caja special item */
118     {
119       gchar *uri_scheme = NULL;
120 
121       uri_scheme = caja_file_info_get_uri_scheme (file);
122       if (!strncmp (uri_scheme, "x-caja-desktop", 18))
123 	{
124 	  g_free (uri_scheme);
125 	  return NULL;
126 	}
127       g_free (uri_scheme);
128     }
129 
130     /* create the context menu item */
131     item = caja_menu_item_new ("Gksu::open_as_root",
132 				   _("Open as administrator"),
133 				   _("Opens the file with administrator privileges"),
134 				   NULL);
135     g_signal_connect_object (item, "activate",
136 			     G_CALLBACK (gksu_context_menu_activate),
137 			     file, 0);
138     items = g_list_prepend (items, item);
139 
140     return items;
141 }
142 
143 static void
gksu_context_menu_activate(CajaMenuItem * item,CajaFileInfo * file)144 gksu_context_menu_activate (CajaMenuItem *item,
145 			    CajaFileInfo *file)
146 {
147   gchar *exec_path;
148   gchar *uri = NULL;
149   gchar *mime_type = NULL;
150   gchar *cmd = NULL;
151   gchar *full_cmd = NULL;
152   gchar *tmp = NULL;
153   gboolean is_desktop = FALSE;
154 
155   uri = caja_file_info_get_uri (file);
156   mime_type = caja_file_info_get_mime_type (file);
157 
158   if (!strcmp (mime_type, "application/x-desktop"))
159     { /* we're handling a .desktop file */
160       GKeyFile *key_file = g_key_file_new ();
161       gint retval = 0;
162 
163       is_desktop = TRUE;
164 
165       gchar *file_path = g_filename_from_uri (uri, NULL, NULL);
166       retval = g_key_file_load_from_file (key_file, file_path, 0, NULL);
167       g_free (file_path);
168 
169       if (retval)
170         cmd = g_key_file_get_string (key_file, "Desktop Entry", "Exec", NULL);
171       g_key_file_free (key_file);
172     }
173   else
174     {
175       GAppInfo *app_info = g_app_info_get_default_for_type (mime_type, strncmp (uri, "file://", 7));
176       if (app_info)
177 	{
178 	  cmd = g_strdup (g_app_info_get_executable (app_info));
179           g_object_unref (app_info);
180 	}
181     }
182 
183   if (cmd == NULL)
184     {
185       GtkWidget *dialog;
186 
187       dialog = gtk_message_dialog_new_with_markup (NULL, 0,
188 						   GTK_MESSAGE_ERROR,
189 						   GTK_BUTTONS_CLOSE,
190 						   _("<big><b>"
191 						     "Unable to determine the program to run."
192 						     "</b></big>\n\n"
193 						     "The item you selected cannot be open with "
194 						     "administrator powers because the correct "
195 						     "application cannot be determined."));
196       gtk_dialog_run (GTK_DIALOG(dialog));
197       gtk_widget_destroy (dialog);
198       return;
199     }
200 
201   /*
202    * FIXME: remove any FreeDesktop substitution variable for now; we
203    * need to process them!
204    */
205   tmp = strstr (cmd, "%");
206   if (tmp)
207     *tmp = '\0';
208 
209   if (is_desktop)
210     full_cmd = cmd;
211   else
212     {
213       full_cmd = g_strdup_printf ("%s '%s'", cmd, uri);
214       g_free (cmd);
215     }
216 
217   if ((exec_path = g_find_program_in_path ("gksu")) == NULL)
218     {
219        if ((exec_path = g_find_program_in_path ("beesu")) == NULL)
220          {
221            GtkWidget *dialog;
222 
223            dialog = gtk_message_dialog_new_with_markup (NULL, 0,
224                                                         GTK_MESSAGE_ERROR,
225                                                         GTK_BUTTONS_CLOSE,
226                                                         _("<big><b>"
227                                                           "Unable to determine the graphical wrapper for su"
228                                                            "</b></big>\n\n"
229                                                            "The item you selected cannot be open with "
230                                                            "administrator powers because the graphical wrapper "
231                                                            "for su cannot be determined, such as gtksu or beesu."));
232            gtk_dialog_run (GTK_DIALOG (dialog));
233            gtk_widget_destroy (dialog);
234          }
235     }
236 
237   if (exec_path != NULL)
238     {
239       GError *error = NULL;
240       gchar **argv = (gchar**) g_malloc (sizeof (gchar*) * 3);
241 
242       argv[0] = exec_path;
243       argv[1] = full_cmd;
244       argv[2] = NULL;
245 
246       if (!g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error))
247         {
248            GtkWidget *dialog;
249 
250            dialog = gtk_message_dialog_new (NULL, 0,
251                                             GTK_MESSAGE_ERROR,
252                                             GTK_BUTTONS_CLOSE,
253                                             _("Error: %s"),
254                                             error->message);
255            gtk_dialog_run (GTK_DIALOG (dialog));
256            gtk_widget_destroy (dialog);
257            g_error_free (error);
258         }
259       g_strfreev (argv);
260     }
261   else
262     {
263       g_free (full_cmd);
264     }
265 
266   g_free (uri);
267   g_free (mime_type);
268 }
269 
270 /* --- extension interface --- */
271 void
caja_module_initialize(GTypeModule * module)272 caja_module_initialize (GTypeModule *module)
273 {
274     g_print ("Initializing caja-gksu extension\n");
275     gksu_context_menu_register_type (module);
276 }
277 
278 void
caja_module_shutdown(void)279 caja_module_shutdown (void)
280 {
281     g_print ("Shutting down caja-gksu extension\n");
282 }
283 
284 void
caja_module_list_types(const GType ** types,int * num_types)285 caja_module_list_types (const GType **types,
286 			    int *num_types)
287 {
288     static GType type_list[1];
289 
290     type_list[0] = GKSU_TYPE_CONTEXT_MENU;
291     *types = type_list;
292     *num_types = G_N_ELEMENTS (type_list);
293 }
294