nautilus-3.6.3/src/nautilus-autorun-software.c

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 }