No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* Nautilus
4
5 Copyright (C) 2008 Red Hat, Inc.
6
7 The Gnome Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The Gnome Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21
22 Author: David Zeuthen <davidz@redhat.com>
23 */
24
25
26 #include <config.h>
27
28 #include <unistd.h>
29 #include <string.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <gtk/gtk.h>
33 #include <gio/gio.h>
34
35 #include <glib/gi18n.h>
36
37 #include <libnautilus-private/nautilus-module.h>
38 #include <libnautilus-private/nautilus-icon-info.h>
39
40 typedef struct
41 {
42 GtkWidget *dialog;
43 GMount *mount;
44 } AutorunSoftwareDialogData;
45
46 static void autorun_software_dialog_mount_unmounted (GMount *mount, AutorunSoftwareDialogData *data);
47
48 static void
49 autorun_software_dialog_destroy (AutorunSoftwareDialogData *data)
50 {
51 g_signal_handlers_disconnect_by_func (G_OBJECT (data->mount),
52 G_CALLBACK (autorun_software_dialog_mount_unmounted),
53 data);
54
55 gtk_widget_destroy (GTK_WIDGET (data->dialog));
56 g_object_unref (data->mount);
57 g_free (data);
58 }
59
60 static void
61 autorun_software_dialog_mount_unmounted (GMount *mount, AutorunSoftwareDialogData *data)
62 {
63 autorun_software_dialog_destroy (data);
64 }
65
66 static gboolean
67 _check_file (GFile *mount_root, const char *file_path, gboolean must_be_executable)
68 {
69 GFile *file;
70 GFileInfo *file_info;
71 gboolean ret;
72
73 ret = FALSE;
74
75 file = g_file_get_child (mount_root, file_path);
76 file_info = g_file_query_info (file,
77 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
78 G_FILE_QUERY_INFO_NONE,
79 NULL,
80 NULL);
81 if (file_info != NULL) {
82 if (must_be_executable) {
83 if (g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) {
84 ret = TRUE;
85 }
86 } else {
87 ret = TRUE;
88 }
89 g_object_unref (file_info);
90 }
91 g_object_unref (file);
92
93 return ret;
94 }
95
96 static void
97 autorun (GMount *mount)
98 {
99 char *error_string;
100 GFile *root;
101 GFile *program_to_spawn;
102 GFile *program_parameter_file;
103 char *path_to_spawn;
104 char *cwd_for_program;
105 char *program_parameter;
106
107 root = g_mount_get_root (mount);
108
109 /* Careful here, according to
110 *
111 * http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
112 *
113 * the ordering does matter.
114 */
115
116 program_to_spawn = NULL;
117 path_to_spawn = NULL;
118 program_parameter_file = NULL;
119 program_parameter = NULL;
120
121 if (_check_file (root, ".autorun", TRUE)) {
122 program_to_spawn = g_file_get_child (root, ".autorun");
123 } else if (_check_file (root, "autorun", TRUE)) {
124 program_to_spawn = g_file_get_child (root, "autorun");
125 } else if (_check_file (root, "autorun.sh", TRUE)) {
126 program_to_spawn = g_file_new_for_path ("/bin/sh");
127 program_parameter_file = g_file_get_child (root, "autorun.sh");
128 }
129
130 if (program_to_spawn != NULL) {
131 path_to_spawn = g_file_get_path (program_to_spawn);
132 }
133 if (program_parameter_file != NULL) {
134 program_parameter = g_file_get_path (program_parameter_file);
135 }
136
137 cwd_for_program = g_file_get_path (root);
138
139 error_string = NULL;
140 if (path_to_spawn != NULL && cwd_for_program != NULL) {
141 if (chdir (cwd_for_program) == 0) {
142 execl (path_to_spawn, path_to_spawn, program_parameter, NULL);
143 error_string = g_strdup_printf (_("Unable to start the program:\n%s"), strerror (errno));
144 goto out;
145 }
146 error_string = g_strdup_printf (_("Unable to start the program:\n%s"), strerror (errno));
147 goto out;
148 }
149 error_string = g_strdup_printf (_("Unable to locate the program"));
150
151 out:
152 if (program_to_spawn != NULL) {
153 g_object_unref (program_to_spawn);
154 }
155 if (program_parameter_file != NULL) {
156 g_object_unref (program_parameter_file);
157 }
158 if (root != NULL) {
159 g_object_unref (root);
160 }
161 g_free (path_to_spawn);
162 g_free (cwd_for_program);
163 g_free (program_parameter);
164
165 if (error_string != NULL) {
166 GtkWidget *dialog;
167 dialog = gtk_message_dialog_new_with_markup (NULL, /* TODO: parent window? */
168 0,
169 GTK_MESSAGE_ERROR,
170 GTK_BUTTONS_OK,
171 _("Oops! There was a problem running this software."));
172 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error_string);
173 /* This is required because we don't show dialogs in the
174 window picker and if the window pops under another window
175 there is no way to get it back. */
176 gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
177
178 gtk_dialog_run (GTK_DIALOG (dialog));
179 gtk_widget_destroy (dialog);
180 g_free (error_string);
181 }
182 }
183
184 static void
185 present_autorun_for_software_dialog (GMount *mount)
186 {
187 GIcon *icon;
188 int icon_size;
189 NautilusIconInfo *icon_info;
190 GdkPixbuf *pixbuf;
191 GtkWidget *image;
192 char *mount_name;
193 GtkWidget *dialog;
194 AutorunSoftwareDialogData *data;
195
196 mount_name = g_mount_get_name (mount);
197
198 dialog = gtk_message_dialog_new (NULL, /* TODO: parent window? */
199 0,
200 GTK_MESSAGE_OTHER,
201 GTK_BUTTONS_CANCEL,
202 _("â%sâ contains software intended to be automatically started. Would you like to run it?"),
203 mount_name);
204 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
205 "%s",
206 _("If you don't trust this location or aren't sure, press Cancel."));
207
208 /* This is required because we don't show dialogs in the
209 window picker and if the window pops under another window
210 there is no way to get it back. */
211 gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
212
213 /* TODO: in a star trek future add support for verifying
214 * software on media (e.g. if it has a certificate, check it
215 * etc.)
216 */
217
218
219 icon = g_mount_get_icon (mount);
220 icon_size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG);
221 icon_info = nautilus_icon_info_lookup (icon, icon_size);
222 pixbuf = nautilus_icon_info_get_pixbuf_at_size (icon_info, icon_size);
223 image = gtk_image_new_from_pixbuf (pixbuf);
224 gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
225
226 gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image);
227
228 gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf);
229
230 data = g_new0 (AutorunSoftwareDialogData, 1);
231 data->dialog = dialog;
232 data->mount = g_object_ref (mount);
233
234 g_signal_connect (G_OBJECT (mount),
235 "unmounted",
236 G_CALLBACK (autorun_software_dialog_mount_unmounted),
237 data);
238
239 gtk_dialog_add_button (GTK_DIALOG (dialog),
240 _("_Run"),
241 GTK_RESPONSE_OK);
242
243 gtk_widget_show_all (dialog);
244
245 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
246 gtk_widget_destroy (dialog);
247 autorun (mount);
248 }
249
250 g_object_unref (icon_info);
251 g_object_unref (pixbuf);
252 g_free (mount_name);
253 }
254
255 int
256 main (int argc, char *argv[])
257 {
258 GVolumeMonitor *monitor;
259 GFile *file;
260 GMount *mount;
261 GError *error;
262
263 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
264 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
265 textdomain (GETTEXT_PACKAGE);
266
267 gtk_init (&argc, &argv);
268
269 if (argc != 2) {
270 g_print ("Usage: %s mount-uri\n", argv[0]);
271 goto out;
272 }
273
274 /* instantiate monitor so we get the "unmounted" signal properly */
275 monitor = g_volume_monitor_get ();
276 if (monitor == NULL) {
277 g_warning ("Unable to connect to the volume monitor");
278 goto out;
279 }
280
281 file = g_file_new_for_commandline_arg (argv[1]);
282 if (file == NULL) {
283 g_object_unref (monitor);
284 g_warning ("Unable to parse mount URI");
285 goto out;
286 }
287
288 error = NULL;
289 mount = g_file_find_enclosing_mount (file, NULL, &error);
290 if (mount == NULL) {
291 g_warning ("Unable to find device for URI: %s", error->message);
292 g_clear_error (&error);
293 g_object_unref (file);
294 g_object_unref (monitor);
295 goto out;
296 }
297
298 present_autorun_for_software_dialog (mount);
299 g_object_unref (file);
300 g_object_unref (monitor);
301 g_object_unref (mount);
302
303 out:
304 return 0;
305 }