1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* Caja
4
5 Copyright (C) 2008 Red Hat, Inc.
6
7 The Mate 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 Mate 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 Mate Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21
22 Author: David Zeuthen <davidz@redhat.com>
23 */
24
25
26 #include <config.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <time.h>
30 #include <errno.h>
31
32 #include <gtk/gtk.h>
33 #include <gio/gio.h>
34 #include <glib/gi18n.h>
35
36 #include <libcaja-private/caja-module.h>
37 #include <libcaja-private/caja-icon-info.h>
38
39 typedef struct
40 {
41 GtkWidget *dialog;
42 GMount *mount;
43 } AutorunSoftwareDialogData;
44
45 static void autorun_software_dialog_mount_unmounted (GMount *mount, AutorunSoftwareDialogData *data);
46
47 static void
autorun_software_dialog_destroy(AutorunSoftwareDialogData * data)48 autorun_software_dialog_destroy (AutorunSoftwareDialogData *data)
49 {
50 g_signal_handlers_disconnect_by_func (G_OBJECT (data->mount),
51 G_CALLBACK (autorun_software_dialog_mount_unmounted),
52 data);
53
54 gtk_widget_destroy (GTK_WIDGET (data->dialog));
55 g_object_unref (data->mount);
56 g_free (data);
57 }
58
59 static void
autorun_software_dialog_mount_unmounted(GMount * mount,AutorunSoftwareDialogData * data)60 autorun_software_dialog_mount_unmounted (GMount *mount, AutorunSoftwareDialogData *data)
61 {
62 autorun_software_dialog_destroy (data);
63 }
64
65 static gboolean
_check_file(GFile * mount_root,const char * file_path,gboolean must_be_executable)66 _check_file (GFile *mount_root, const char *file_path, gboolean must_be_executable)
67 {
68 GFile *file;
69 GFileInfo *file_info;
70 gboolean ret;
71
72 ret = FALSE;
73
74 file = g_file_get_child (mount_root, file_path);
75 file_info = g_file_query_info (file,
76 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
77 G_FILE_QUERY_INFO_NONE,
78 NULL,
79 NULL);
80 if (file_info != NULL)
81 {
82 if (must_be_executable)
83 {
84 if (g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
85 {
86 ret = TRUE;
87 }
88 }
89 else
90 {
91 ret = TRUE;
92 }
93 g_object_unref (file_info);
94 }
95 g_object_unref (file);
96
97 return ret;
98 }
99
100 static void
autorun(GMount * mount)101 autorun (GMount *mount)
102 {
103 char *error_string;
104 GFile *root;
105 GFile *program_to_spawn;
106 char *path_to_spawn;
107 char *cwd_for_program;
108
109 root = g_mount_get_root (mount);
110
111 /* Careful here, according to
112 *
113 * https://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
114 *
115 * the ordering does matter.
116 */
117
118 program_to_spawn = NULL;
119 path_to_spawn = NULL;
120
121 if (_check_file (root, ".autorun", TRUE))
122 {
123 program_to_spawn = g_file_get_child (root, ".autorun");
124 }
125 else if (_check_file (root, "autorun", TRUE))
126 {
127 program_to_spawn = g_file_get_child (root, "autorun");
128 }
129 else if (_check_file (root, "autorun.sh", TRUE))
130 {
131 program_to_spawn = g_file_get_child (root, "autorun.sh");
132 }
133 else if (_check_file (root, "autorun.exe", TRUE))
134 {
135 /* TODO */
136 }
137 else if (_check_file (root, "AUTORUN.EXE", TRUE))
138 {
139 /* TODO */
140 }
141 else if (_check_file (root, "autorun.inf", FALSE))
142 {
143 /* TODO */
144 }
145 else if (_check_file (root, "AUTORUN.INF", FALSE))
146 {
147 /* TODO */
148 }
149
150 if (program_to_spawn != NULL)
151 {
152 path_to_spawn = g_file_get_path (program_to_spawn);
153 }
154
155 cwd_for_program = g_file_get_path (root);
156
157 error_string = NULL;
158 if (path_to_spawn != NULL && cwd_for_program != NULL)
159 {
160 if (chdir (cwd_for_program) == 0)
161 {
162 execl (path_to_spawn, path_to_spawn, NULL);
163 error_string = g_strdup_printf (_("Error starting autorun program: %s"), strerror (errno));
164 goto out;
165 }
166 error_string = g_strdup_printf (_("Error starting autorun program: %s"), strerror (errno));
167 goto out;
168 }
169 error_string = g_strdup_printf (_("Cannot find the autorun program"));
170
171 out:
172 if (program_to_spawn != NULL)
173 {
174 g_object_unref (program_to_spawn);
175 }
176 if (root != NULL)
177 {
178 g_object_unref (root);
179 }
180 g_free (path_to_spawn);
181 g_free (cwd_for_program);
182
183 if (error_string != NULL)
184 {
185 GtkWidget *dialog;
186 dialog = gtk_message_dialog_new_with_markup (NULL, /* TODO: parent window? */
187 0,
188 GTK_MESSAGE_ERROR,
189 GTK_BUTTONS_OK,
190 _("<big><b>Error autorunning software</b></big>"));
191 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error_string);
192 gtk_dialog_run (GTK_DIALOG (dialog));
193 gtk_widget_destroy (dialog);
194 g_free (error_string);
195 }
196 }
197
198 static void
present_autorun_for_software_dialog(GMount * mount)199 present_autorun_for_software_dialog (GMount *mount)
200 {
201 GIcon *icon;
202 int icon_size;
203 CajaIconInfo *icon_info;
204 GdkPixbuf *pixbuf;
205 GtkWidget *image;
206 char *mount_name;
207 GtkWidget *dialog;
208 AutorunSoftwareDialogData *data;
209
210 mount_name = g_mount_get_name (mount);
211
212 dialog = gtk_message_dialog_new_with_markup (NULL, /* TODO: parent window? */
213 0,
214 GTK_MESSAGE_OTHER,
215 GTK_BUTTONS_CANCEL,
216 _("<big><b>This medium contains software intended to be automatically started. Would you like to run it?</b></big>"));
217 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
218 _("The software will run directly from the medium \"%s\". "
219 "You should never run software that you don't trust.\n"
220 "\n"
221 "If in doubt, press Cancel."),
222 mount_name);
223
224 /* TODO: in a star trek future add support for verifying
225 * software on media (e.g. if it has a certificate, check it
226 * etc.)
227 */
228
229
230 icon = g_mount_get_icon (mount);
231 icon_size = caja_get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG);
232 icon_info = caja_icon_info_lookup (icon, icon_size,
233 gtk_widget_get_scale_factor (GTK_WIDGET (dialog)));
234 pixbuf = caja_icon_info_get_pixbuf_at_size (icon_info, icon_size);
235 image = gtk_image_new_from_pixbuf (pixbuf);
236 gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
237 gtk_widget_set_valign (image, GTK_ALIGN_START);
238 gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image);
239
240 gtk_window_set_title (GTK_WINDOW (dialog), mount_name);
241 gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf);
242
243 data = g_new0 (AutorunSoftwareDialogData, 1);
244 data->dialog = dialog;
245 data->mount = g_object_ref (mount);
246
247 g_signal_connect (G_OBJECT (mount),
248 "unmounted",
249 G_CALLBACK (autorun_software_dialog_mount_unmounted),
250 data);
251
252 gtk_dialog_add_button (GTK_DIALOG (dialog),
253 _("_Run"),
254 GTK_RESPONSE_OK);
255
256 gtk_widget_show_all (dialog);
257
258 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
259 {
260 gtk_widget_destroy (dialog);
261 autorun (mount);
262 }
263
264 g_object_unref (icon_info);
265 g_object_unref (pixbuf);
266 g_free (mount_name);
267 }
268
269 int
main(int argc,char * argv[])270 main (int argc, char *argv[])
271 {
272 GVolumeMonitor *monitor;
273 GFile *file;
274 GMount *mount;
275
276 #ifdef ENABLE_NLS
277 bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
278 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
279 textdomain (GETTEXT_PACKAGE);
280 #endif /* ENABLE_NLS */
281
282 gtk_init (&argc, &argv);
283
284 if (argc != 2)
285 {
286 goto out;
287 }
288
289 /* instantiate monitor so we get the "unmounted" signal properly */
290 monitor = g_volume_monitor_get ();
291 if (monitor == NULL)
292 {
293 goto out;
294 }
295
296 file = g_file_new_for_commandline_arg (argv[1]);
297 if (file == NULL)
298 {
299 g_object_unref (monitor);
300 goto out;
301 }
302
303 mount = g_file_find_enclosing_mount (file, NULL, NULL);
304 if (mount == NULL)
305 {
306 g_object_unref (file);
307 g_object_unref (monitor);
308 goto out;
309 }
310
311 present_autorun_for_software_dialog (mount);
312 g_object_unref (file);
313 g_object_unref (monitor);
314 g_object_unref (mount);
315
316 out:
317 return 0;
318 }
319