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