1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 
3 /* nemo-file-utilities.c - implementation of file manipulation routines.
4 
5    Copyright (C) 1999, 2000, 2001 Eazel, 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., 51 Franklin Street - Suite 500,
20    Boston, MA 02110-1335, USA.
21 
22    Authors: John Sullivan <sullivan@eazel.com>
23 */
24 
25 #include <config.h>
26 #include "nemo-file-utilities.h"
27 
28 #include "nemo-global-preferences.h"
29 #include "nemo-lib-self-check-functions.h"
30 #include "nemo-metadata.h"
31 #include "nemo-file.h"
32 #include "nemo-file-operations.h"
33 #include "nemo-search-directory.h"
34 #include "nemo-signaller.h"
35 #include "nemo-statx.h"
36 #include <eel/eel-glib-extensions.h>
37 #include <eel/eel-stock-dialogs.h>
38 #include <eel/eel-string.h>
39 #include <eel/eel-debug.h>
40 #include <glib.h>
41 #include <glib/gi18n.h>
42 #include <glib/gstdio.h>
43 #include <gio/gio.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 
47 #define NEMO_USER_DIRECTORY_NAME "nemo"
48 
49 #define DESKTOP_DIRECTORY_NAME "Desktop"
50 #define LEGACY_DESKTOP_DIRECTORY_NAME ".gnome-desktop"
51 
52 static void update_xdg_dir_cache (void);
53 static void schedule_user_dirs_changed (void);
54 static void desktop_dir_changed (void);
55 static GFile *nemo_find_file_insensitive_next (GFile *parent, const gchar *name);
56 
57 char *
nemo_compute_title_for_location(GFile * location)58 nemo_compute_title_for_location (GFile *location)
59 {
60 	NemoFile *file;
61 	char *title;
62     char *builder;
63 	/* TODO-gio: This doesn't really work all that great if the
64 	   info about the file isn't known atm... */
65 
66 	if (nemo_is_home_directory (location)) {
67 		return g_strdup (_("Home"));
68 	}
69 
70 	builder = NULL;
71 	if (location) {
72 		file = nemo_file_get (location);
73 		builder = nemo_file_get_description (file);
74 		if (builder == NULL) {
75 			builder = nemo_file_get_display_name (file);
76 		}
77 		nemo_file_unref (file);
78 	}
79 
80 	if (builder == NULL) {
81 		builder = g_file_get_basename (location);
82 	}
83 
84     if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_FULL_PATH_TITLES)) {
85         gchar *uri, *path;
86         file = nemo_file_get (location);
87 
88         uri = nemo_file_get_uri (file);
89         path = g_filename_from_uri (uri, NULL, NULL);
90 
91         if (path != NULL) {
92             title = g_strdup_printf("%s - %s", builder, path);
93         } else {
94             title = g_strdup_printf("%s - %s", builder, uri);
95         }
96         nemo_file_unref (file);
97         g_free (uri);
98         g_free (path);
99         g_free (builder);
100     } else {
101         title = g_strdup(builder);
102         g_free (builder);
103     }
104     return title;
105 }
106 
107 // TODO: Maybe this can replace nemo_compute_title_for_location() all around?
108 char *
nemo_compute_search_title_for_location(GFile * location)109 nemo_compute_search_title_for_location (GFile *location)
110 {
111     GFile *home_file;
112     gchar *location_string;
113 
114     if (nemo_is_home_directory (location)) {
115         return g_strdup (_("Home"));
116     }
117 
118     home_file = g_file_new_for_path (g_get_home_dir ());
119 
120     location_string = NULL;
121 
122     location_string = g_file_get_relative_path (home_file, location);
123 
124     if (location_string == NULL) {
125         if (g_file_is_native (location)) {
126             location_string = g_file_get_path (location);
127         } else {
128             location_string = g_file_get_uri (location);
129         }
130     }
131 
132     g_object_unref (home_file);
133 
134     return location_string;
135 }
136 
137 /**
138  * nemo_get_user_directory:
139  *
140  * Get the path for the directory containing nemo settings.
141  *
142  * Return value: the directory path.
143  **/
144 char *
nemo_get_user_directory(void)145 nemo_get_user_directory (void)
146 {
147 	char *user_directory = NULL;
148 
149 	user_directory = g_build_filename (g_get_user_config_dir (),
150 					   NEMO_USER_DIRECTORY_NAME,
151 					   NULL);
152 
153 	if (!g_file_test (user_directory, G_FILE_TEST_EXISTS)) {
154 		g_mkdir_with_parents (user_directory, DEFAULT_NEMO_DIRECTORY_MODE);
155 		/* FIXME bugzilla.gnome.org 41286:
156 		 * How should we handle the case where this mkdir fails?
157 		 * Note that nemo_application_startup will refuse to launch if this
158 		 * directory doesn't get created, so that case is OK. But the directory
159 		 * could be deleted after Nemo was launched, and perhaps
160 		 * there is some bad side-effect of not handling that case.
161 		 */
162 	}
163 
164 	return user_directory;
165 }
166 
167 /**
168  * nemo_get_accel_map_file:
169  *
170  * Get the path for the filename containing nemo accelerator map.
171  * The filename need not exist.
172  *
173  * Return value: the filename path, or NULL if the home directory could not be found
174  **/
175 char *
nemo_get_accel_map_file(void)176 nemo_get_accel_map_file (void)
177 {
178 	const gchar *override;
179 
180 	override = g_getenv ("GNOME22_USER_DIR");
181 
182 	if (override) {
183 		return g_build_filename (override, "accels/nemo", NULL);
184 	} else {
185 		return g_build_filename (g_get_home_dir (), ".gnome2/accels/nemo", NULL);
186 	}
187 }
188 
189 /**
190  * nemo_get_scripts_directory_path:
191  *
192  * Get the path for the directory containing nemo scripts.
193  *
194  * Return value: the directory path containing nemo scripts
195  **/
196 char *
nemo_get_scripts_directory_path(void)197 nemo_get_scripts_directory_path (void)
198 {
199 	return g_build_filename (g_get_user_data_dir (), "nemo", "scripts", NULL);
200 }
201 
202 typedef struct {
203 	char *type;
204 	char *path;
205 	NemoFile *file;
206 } XdgDirEntry;
207 
208 
209 static XdgDirEntry *
parse_xdg_dirs(const char * config_file)210 parse_xdg_dirs (const char *config_file)
211 {
212   GArray *array;
213   char *config_file_free = NULL;
214   XdgDirEntry dir;
215   char *data;
216   char **lines;
217   char *p, *d;
218   int i;
219   char *type_start, *type_end;
220   char *value, *unescaped;
221   gboolean relative;
222 
223   array = g_array_new (TRUE, TRUE, sizeof (XdgDirEntry));
224 
225   if (config_file == NULL)
226     {
227       config_file_free = g_build_filename (g_get_user_config_dir (),
228 					   "user-dirs.dirs", NULL);
229       config_file = (const char *)config_file_free;
230     }
231 
232   if (g_file_get_contents (config_file, &data, NULL, NULL))
233     {
234       lines = g_strsplit (data, "\n", 0);
235       g_free (data);
236       for (i = 0; lines[i] != NULL; i++)
237 	{
238 	  p = lines[i];
239 	  while (g_ascii_isspace (*p))
240 	    p++;
241 
242 	  if (*p == '#')
243 	    continue;
244 
245 	  value = strchr (p, '=');
246 	  if (value == NULL)
247 	    continue;
248 	  *value++ = 0;
249 
250 	  g_strchug (g_strchomp (p));
251 	  if (!g_str_has_prefix (p, "XDG_"))
252 	    continue;
253 	  if (!g_str_has_suffix (p, "_DIR"))
254 	    continue;
255 	  type_start = p + 4;
256 	  type_end = p + strlen (p) - 4;
257 
258 	  while (g_ascii_isspace (*value))
259 	    value++;
260 
261 	  if (*value != '"')
262 	    continue;
263 	  value++;
264 
265 	  relative = FALSE;
266 	  if (g_str_has_prefix (value, "$HOME"))
267 	    {
268 	      relative = TRUE;
269 	      value += 5;
270 	      while (*value == '/')
271 		      value++;
272 	    }
273 	  else if (*value != '/')
274 	    continue;
275 
276 	  d = unescaped = g_malloc (strlen (value) + 1);
277 	  while (*value && *value != '"')
278 	    {
279 	      if ((*value == '\\') && (*(value + 1) != 0))
280 		value++;
281 	      *d++ = *value++;
282 	    }
283 	  *d = 0;
284 
285 	  *type_end = 0;
286 	  dir.type = g_strdup (type_start);
287 	  if (relative)
288 	    {
289 	      dir.path = g_build_filename (g_get_home_dir (), unescaped, NULL);
290 	      g_free (unescaped);
291 	    }
292 	  else
293 	    dir.path = unescaped;
294 
295 	  g_array_append_val (array, dir);
296 	}
297 
298       g_strfreev (lines);
299     }
300 
301   g_free (config_file_free);
302 
303   return (XdgDirEntry *)g_array_free (array, FALSE);
304 }
305 
306 static XdgDirEntry *cached_xdg_dirs = NULL;
307 static GFileMonitor *cached_xdg_dirs_monitor = NULL;
308 
309 static void
xdg_dir_changed(NemoFile * file,XdgDirEntry * dir)310 xdg_dir_changed (NemoFile *file,
311 		 XdgDirEntry *dir)
312 {
313 	GFile *location, *dir_location;
314 	char *path;
315 
316 	location = nemo_file_get_location (file);
317 	dir_location = g_file_new_for_path (dir->path);
318 	if (!g_file_equal (location, dir_location)) {
319 		path = g_file_get_path (location);
320 
321 		if (path) {
322 			char *argv[5];
323 			int i;
324 
325 			g_free (dir->path);
326 			dir->path = path;
327 
328 			i = 0;
329 			argv[i++] = (char *)"xdg-user-dirs-update";
330 			argv[i++] = (char *)"--set";
331 			argv[i++] = dir->type;
332 			argv[i++] = dir->path;
333 			argv[i++] = NULL;
334 
335 			/* We do this sync, to avoid possible race-conditions
336 			   if multiple dirs change at the same time. Its
337 			   blocking the main thread, but these updates should
338 			   be very rare and very fast. */
339 			g_spawn_sync (NULL,
340 				      argv, NULL,
341 				      G_SPAWN_SEARCH_PATH |
342 				      G_SPAWN_STDOUT_TO_DEV_NULL |
343 				      G_SPAWN_STDERR_TO_DEV_NULL,
344 				      NULL, NULL,
345 				      NULL, NULL, NULL, NULL);
346 			g_reload_user_special_dirs_cache ();
347 			schedule_user_dirs_changed ();
348 			desktop_dir_changed ();
349 			/* Icon might have changed */
350 			nemo_file_invalidate_attributes (file, NEMO_FILE_ATTRIBUTE_INFO);
351 		}
352 	}
353 	g_object_unref (location);
354 	g_object_unref (dir_location);
355 }
356 
357 static void
xdg_dir_cache_changed_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type)358 xdg_dir_cache_changed_cb (GFileMonitor  *monitor,
359 			  GFile *file,
360 			  GFile *other_file,
361 			  GFileMonitorEvent event_type)
362 {
363 	if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
364 	    event_type == G_FILE_MONITOR_EVENT_CREATED) {
365 		update_xdg_dir_cache ();
366 	}
367 }
368 
369 static int user_dirs_changed_tag = 0;
370 
371 static gboolean
emit_user_dirs_changed_idle(gpointer data)372 emit_user_dirs_changed_idle (gpointer data)
373 {
374 	g_signal_emit_by_name (nemo_signaller_get_current (),
375 			       "user_dirs_changed");
376 	user_dirs_changed_tag = 0;
377 	return FALSE;
378 }
379 
380 static void
schedule_user_dirs_changed(void)381 schedule_user_dirs_changed (void)
382 {
383 	if (user_dirs_changed_tag == 0) {
384 		user_dirs_changed_tag = g_idle_add (emit_user_dirs_changed_idle, NULL);
385 	}
386 }
387 
388 static void
unschedule_user_dirs_changed(void)389 unschedule_user_dirs_changed (void)
390 {
391 	if (user_dirs_changed_tag != 0) {
392 		g_source_remove (user_dirs_changed_tag);
393 		user_dirs_changed_tag = 0;
394 	}
395 }
396 
397 static void
free_xdg_dir_cache(void)398 free_xdg_dir_cache (void)
399 {
400 	int i;
401 
402 	if (cached_xdg_dirs != NULL) {
403 		for (i = 0; cached_xdg_dirs[i].type != NULL; i++) {
404 			if (cached_xdg_dirs[i].file != NULL) {
405 				nemo_file_monitor_remove (cached_xdg_dirs[i].file,
406 							      &cached_xdg_dirs[i]);
407 				g_signal_handlers_disconnect_by_func (cached_xdg_dirs[i].file,
408 								      G_CALLBACK (xdg_dir_changed),
409 								      &cached_xdg_dirs[i]);
410 				nemo_file_unref (cached_xdg_dirs[i].file);
411 			}
412 			g_free (cached_xdg_dirs[i].type);
413 			g_free (cached_xdg_dirs[i].path);
414 		}
415 		g_free (cached_xdg_dirs);
416 	}
417 }
418 
419 static void
destroy_xdg_dir_cache(void)420 destroy_xdg_dir_cache (void)
421 {
422 	free_xdg_dir_cache ();
423 	unschedule_user_dirs_changed ();
424 	desktop_dir_changed ();
425 
426 	if (cached_xdg_dirs_monitor != NULL) {
427 		g_object_unref  (cached_xdg_dirs_monitor);
428 		cached_xdg_dirs_monitor = NULL;
429 	}
430 }
431 
432 static void
update_xdg_dir_cache(void)433 update_xdg_dir_cache (void)
434 {
435 	GFile *file;
436 	char *config_file, *uri;
437 	int i;
438 
439 	free_xdg_dir_cache ();
440 	g_reload_user_special_dirs_cache ();
441 	schedule_user_dirs_changed ();
442 	desktop_dir_changed ();
443 
444 	cached_xdg_dirs = parse_xdg_dirs (NULL);
445 
446 	for (i = 0 ; cached_xdg_dirs[i].type != NULL; i++) {
447 		cached_xdg_dirs[i].file = NULL;
448 		if (strcmp (cached_xdg_dirs[i].path, g_get_home_dir ()) != 0) {
449 			uri = g_filename_to_uri (cached_xdg_dirs[i].path, NULL, NULL);
450 			cached_xdg_dirs[i].file = nemo_file_get_by_uri (uri);
451 			nemo_file_monitor_add (cached_xdg_dirs[i].file,
452 						   &cached_xdg_dirs[i],
453 						   NEMO_FILE_ATTRIBUTE_INFO);
454 			g_signal_connect (cached_xdg_dirs[i].file,
455 					  "changed", G_CALLBACK (xdg_dir_changed), &cached_xdg_dirs[i]);
456 			g_free (uri);
457 		}
458 	}
459 
460 	if (cached_xdg_dirs_monitor == NULL) {
461 		config_file = g_build_filename (g_get_user_config_dir (),
462 						     "user-dirs.dirs", NULL);
463 		file = g_file_new_for_path (config_file);
464 		cached_xdg_dirs_monitor = g_file_monitor_file (file, 0, NULL, NULL);
465 		g_signal_connect (cached_xdg_dirs_monitor, "changed",
466 				  G_CALLBACK (xdg_dir_cache_changed_cb), NULL);
467 		g_object_unref (file);
468 		g_free (config_file);
469 
470 		eel_debug_call_at_shutdown (destroy_xdg_dir_cache);
471 	}
472 }
473 
474 char *
nemo_get_xdg_dir(const char * type)475 nemo_get_xdg_dir (const char *type)
476 {
477 	int i;
478 
479 	if (cached_xdg_dirs == NULL) {
480 		update_xdg_dir_cache ();
481 	}
482 
483 	for (i = 0 ; cached_xdg_dirs != NULL && cached_xdg_dirs[i].type != NULL; i++) {
484 		if (strcmp (cached_xdg_dirs[i].type, type) == 0) {
485 			return g_strdup (cached_xdg_dirs[i].path);
486 		}
487 	}
488 	if (strcmp ("DESKTOP", type) == 0) {
489 		return g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL);
490 	}
491 	if (strcmp ("TEMPLATES", type) == 0) {
492 		return g_build_filename (g_get_home_dir (), "Templates", NULL);
493 	}
494 
495 	return g_strdup (g_get_home_dir ());
496 }
497 
498 static char *
get_desktop_path(void)499 get_desktop_path (void)
500 {
501 	if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR)) {
502 		return g_strdup (g_get_home_dir());
503 	} else {
504 		return nemo_get_xdg_dir ("DESKTOP");
505 	}
506 }
507 
508 /**
509  * nemo_get_desktop_directory:
510  *
511  * Get the path for the directory containing files on the desktop.
512  *
513  * Return value: the directory path.
514  **/
515 char *
nemo_get_desktop_directory(void)516 nemo_get_desktop_directory (void)
517 {
518 	char *desktop_directory;
519 
520 	desktop_directory = get_desktop_path ();
521 
522 	/* Don't try to create a home directory */
523 	if (!g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR)) {
524 		if (!g_file_test (desktop_directory, G_FILE_TEST_EXISTS)) {
525 			g_mkdir (desktop_directory, DEFAULT_DESKTOP_DIRECTORY_MODE);
526 			/* FIXME bugzilla.gnome.org 41286:
527 			 * How should we handle the case where this mkdir fails?
528 			 * Note that nemo_application_startup will refuse to launch if this
529 			 * directory doesn't get created, so that case is OK. But the directory
530 			 * could be deleted after Nemo was launched, and perhaps
531 			 * there is some bad side-effect of not handling that case.
532 			 */
533 		}
534 	}
535 
536 	return desktop_directory;
537 }
538 
539 GFile *
nemo_get_desktop_location(void)540 nemo_get_desktop_location (void)
541 {
542 	char *desktop_directory;
543 	GFile *res;
544 
545 	desktop_directory = get_desktop_path ();
546 
547 	res = g_file_new_for_path (desktop_directory);
548 	g_free (desktop_directory);
549 	return res;
550 }
551 
552 
553 /**
554  * nemo_get_desktop_directory_uri:
555  *
556  * Get the uri for the directory containing files on the desktop.
557  *
558  * Return value: the directory path.
559  **/
560 char *
nemo_get_desktop_directory_uri(void)561 nemo_get_desktop_directory_uri (void)
562 {
563 	char *desktop_path;
564 	char *desktop_uri;
565 
566 	desktop_path = nemo_get_desktop_directory ();
567 	desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
568 	g_free (desktop_path);
569 
570 	return desktop_uri;
571 }
572 
573 char *
nemo_get_desktop_directory_uri_no_create(void)574 nemo_get_desktop_directory_uri_no_create (void)
575 {
576 	char *desktop_path;
577 	char *desktop_uri;
578 
579 	desktop_path = get_desktop_path ();
580 	desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
581 	g_free (desktop_path);
582 
583 	return desktop_uri;
584 }
585 
586 char *
nemo_get_home_directory_uri(void)587 nemo_get_home_directory_uri (void)
588 {
589 	return  g_filename_to_uri (g_get_home_dir (), NULL, NULL);
590 }
591 
592 
593 gboolean
nemo_should_use_templates_directory(void)594 nemo_should_use_templates_directory (void)
595 {
596 	char *dir;
597 	gboolean res;
598 
599 	dir = nemo_get_xdg_dir ("TEMPLATES");
600 	res = strcmp (dir, g_get_home_dir ()) != 0;
601 	g_free (dir);
602 	return res;
603 }
604 
605 char *
nemo_get_templates_directory(void)606 nemo_get_templates_directory (void)
607 {
608 	return nemo_get_xdg_dir ("TEMPLATES");
609 }
610 
611 void
nemo_create_templates_directory(void)612 nemo_create_templates_directory (void)
613 {
614 	char *dir;
615 
616 	dir = nemo_get_templates_directory ();
617 	if (!g_file_test (dir, G_FILE_TEST_EXISTS)) {
618 		g_mkdir (dir, DEFAULT_NEMO_DIRECTORY_MODE);
619 	}
620 	g_free (dir);
621 }
622 
623 char *
nemo_get_templates_directory_uri(void)624 nemo_get_templates_directory_uri (void)
625 {
626 	char *directory, *uri;
627 
628 	directory = nemo_get_templates_directory ();
629 	uri = g_filename_to_uri (directory, NULL, NULL);
630 	g_free (directory);
631 	return uri;
632 }
633 
634 char *
nemo_get_searches_directory(void)635 nemo_get_searches_directory (void)
636 {
637 	char *user_dir;
638 	char *searches_dir;
639 
640 	user_dir = nemo_get_user_directory ();
641 	searches_dir = g_build_filename (user_dir, "searches", NULL);
642 	g_free (user_dir);
643 
644 	if (!g_file_test (searches_dir, G_FILE_TEST_EXISTS))
645 		g_mkdir (searches_dir, DEFAULT_NEMO_DIRECTORY_MODE);
646 
647 	return searches_dir;
648 }
649 
650 /* These need to be reset to NULL when desktop_is_home_dir changes */
651 static GFile *desktop_dir = NULL;
652 static GFile *desktop_dir_dir = NULL;
653 static char *desktop_dir_filename = NULL;
654 static gboolean desktop_dir_changed_callback_installed = FALSE;
655 
656 
657 static void
desktop_dir_changed(void)658 desktop_dir_changed (void)
659 {
660 	if (desktop_dir) {
661 		g_object_unref (desktop_dir);
662 	}
663 	if (desktop_dir_dir) {
664 		g_object_unref (desktop_dir_dir);
665 	}
666 	g_free (desktop_dir_filename);
667 	desktop_dir = NULL;
668 	desktop_dir_dir = NULL;
669 	desktop_dir_filename = NULL;
670 }
671 
672 static void
desktop_dir_changed_callback(gpointer callback_data)673 desktop_dir_changed_callback (gpointer callback_data)
674 {
675 	desktop_dir_changed ();
676 }
677 
678 static void
update_desktop_dir(void)679 update_desktop_dir (void)
680 {
681 	char *path;
682 	char *dirname;
683 
684 	path = get_desktop_path ();
685 	desktop_dir = g_file_new_for_path (path);
686 
687 	dirname = g_path_get_dirname (path);
688 	desktop_dir_dir = g_file_new_for_path (dirname);
689 	g_free (dirname);
690 	desktop_dir_filename = g_path_get_basename (path);
691 	g_free (path);
692 }
693 
694 gboolean
nemo_is_home_directory_file(GFile * dir,const char * filename)695 nemo_is_home_directory_file (GFile *dir,
696 				 const char *filename)
697 {
698 	char *dirname;
699 	static GFile *home_dir_dir = NULL;
700 	static char *home_dir_filename = NULL;
701 
702 	if (home_dir_dir == NULL) {
703 		dirname = g_path_get_dirname (g_get_home_dir ());
704 		home_dir_dir = g_file_new_for_path (dirname);
705 		g_free (dirname);
706 		home_dir_filename = g_path_get_basename (g_get_home_dir ());
707 	}
708 
709 	return (g_file_equal (dir, home_dir_dir) &&
710 		strcmp (filename, home_dir_filename) == 0);
711 }
712 
713 gboolean
nemo_is_home_directory(GFile * dir)714 nemo_is_home_directory (GFile *dir)
715 {
716 	static GFile *home_dir = NULL;
717 
718 	if (home_dir == NULL) {
719 		home_dir = g_file_new_for_path (g_get_home_dir ());
720 	}
721 
722 	return g_file_equal (dir, home_dir);
723 }
724 
725 gboolean
nemo_is_root_directory(GFile * dir)726 nemo_is_root_directory (GFile *dir)
727 {
728 	static GFile *root_dir = NULL;
729 
730 	if (root_dir == NULL) {
731 		root_dir = g_file_new_for_path ("/");
732 	}
733 
734 	return g_file_equal (dir, root_dir);
735 }
736 
737 
738 gboolean
nemo_is_desktop_directory_file(GFile * dir,const char * file)739 nemo_is_desktop_directory_file (GFile *dir,
740 				    const char *file)
741 {
742 
743 	if (!desktop_dir_changed_callback_installed) {
744 		g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR,
745 					  G_CALLBACK(desktop_dir_changed_callback),
746 					  NULL);
747 		desktop_dir_changed_callback_installed = TRUE;
748 	}
749 
750 	if (desktop_dir == NULL) {
751 		update_desktop_dir ();
752 	}
753 
754 	return (g_file_equal (dir, desktop_dir_dir) &&
755 		strcmp (file, desktop_dir_filename) == 0);
756 }
757 
758 gboolean
nemo_is_desktop_directory(GFile * dir)759 nemo_is_desktop_directory (GFile *dir)
760 {
761 
762 	if (!desktop_dir_changed_callback_installed) {
763 		g_signal_connect_swapped (nemo_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_IS_HOME_DIR,
764 					  G_CALLBACK(desktop_dir_changed_callback),
765 					  NULL);
766 		desktop_dir_changed_callback_installed = TRUE;
767 	}
768 
769 	if (desktop_dir == NULL) {
770 		update_desktop_dir ();
771 	}
772 
773 	return g_file_equal (dir, desktop_dir);
774 }
775 
776 
777 /**
778  * nemo_get_gmc_desktop_directory:
779  *
780  * Get the path for the directory containing the legacy gmc desktop.
781  *
782  * Return value: the directory path.
783  **/
784 char *
nemo_get_gmc_desktop_directory(void)785 nemo_get_gmc_desktop_directory (void)
786 {
787 	return g_build_filename (g_get_home_dir (), LEGACY_DESKTOP_DIRECTORY_NAME, NULL);
788 }
789 
790 char *
nemo_get_data_file_path(const char * partial_path)791 nemo_get_data_file_path (const char *partial_path)
792 {
793 	char *path;
794 	char *user_directory;
795 
796 	/* first try the user's home directory */
797 	user_directory = nemo_get_user_directory ();
798 	path = g_build_filename (user_directory, partial_path, NULL);
799 	g_free (user_directory);
800 	if (g_file_test (path, G_FILE_TEST_EXISTS)) {
801 		return path;
802 	}
803 	g_free (path);
804 
805 	/* next try the shared directory */
806 	path = g_build_filename (NEMO_DATADIR, partial_path, NULL);
807 	if (g_file_test (path, G_FILE_TEST_EXISTS)) {
808 		return path;
809 	}
810 	g_free (path);
811 
812 	return NULL;
813 }
814 
815 char *
nemo_ensure_unique_file_name(const char * directory_uri,const char * base_name,const char * extension)816 nemo_ensure_unique_file_name (const char *directory_uri,
817 				  const char *base_name,
818 				  const char *extension)
819 {
820 	GFileInfo *info;
821 	char *filename;
822 	GFile *dir, *child;
823 	int copy;
824 	char *res;
825 
826 	dir = g_file_new_for_uri (directory_uri);
827 
828 	info = g_file_query_info (dir, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL);
829 	if (info == NULL) {
830 		g_object_unref (dir);
831 		return NULL;
832 	}
833 	g_object_unref (info);
834 
835 	filename = g_strdup_printf ("%s%s",
836 				    base_name,
837 				    extension);
838 	child = g_file_get_child (dir, filename);
839 	g_free (filename);
840 
841 	copy = 1;
842 	while ((info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL)) != NULL) {
843 		g_object_unref (info);
844 		g_object_unref (child);
845 
846 		filename = g_strdup_printf ("%s-%d%s",
847 					    base_name,
848 					    copy,
849 					    extension);
850 		child = g_file_get_child (dir, filename);
851 		g_free (filename);
852 
853 		copy++;
854 	}
855 
856 	res = g_file_get_uri (child);
857 	g_object_unref (child);
858 	g_object_unref (dir);
859 
860 	return res;
861 }
862 
863 char *
nemo_unique_temporary_file_name(void)864 nemo_unique_temporary_file_name (void)
865 {
866 	const char *prefix = "/tmp/nemo-temp-file";
867 	char *file_name;
868 	int fd;
869 
870 	file_name = g_strdup_printf ("%sXXXXXX", prefix);
871 
872 	fd = g_mkstemp (file_name);
873 	if (fd == -1) {
874 		g_free (file_name);
875 		file_name = NULL;
876 	} else {
877 		close (fd);
878 	}
879 
880 	return file_name;
881 }
882 
883 GFile *
nemo_find_existing_uri_in_hierarchy(GFile * location)884 nemo_find_existing_uri_in_hierarchy (GFile *location)
885 {
886 	GFileInfo *info;
887 	GFile *tmp;
888 
889 	g_assert (location != NULL);
890 
891 	location = g_object_ref (location);
892 	while (location != NULL) {
893 		info = g_file_query_info (location,
894 					  G_FILE_ATTRIBUTE_STANDARD_NAME,
895 					  0, NULL, NULL);
896 		g_object_unref (info);
897 		if (info != NULL) {
898 			return location;
899 		}
900 		tmp = location;
901 		location = g_file_get_parent (location);
902 		g_object_unref (tmp);
903 	}
904 
905 	return location;
906 }
907 
908 /**
909  * nemo_find_file_insensitive
910  *
911  * Attempt to find a file case-insentively. If the path can be found, the
912  * returned file maps directly to it. Otherwise, a file using the
913  * originally-cased path is returned. This function performs might perform
914  * I/O.
915  *
916  * Return value: a #GFile to a child specified by @name.
917  **/
918 GFile *
nemo_find_file_insensitive(GFile * parent,const gchar * name)919 nemo_find_file_insensitive (GFile *parent, const gchar *name)
920 {
921 	gchar **split_path;
922 	gchar *component;
923 	GFile *file, *next;
924 	gint i;
925 
926 	split_path = g_strsplit (name, G_DIR_SEPARATOR_S, -1);
927 
928 	file = g_object_ref (parent);
929 
930 	for (i = 0; (component = split_path[i]) != NULL; i++) {
931 		if (!(next = nemo_find_file_insensitive_next (file,
932 		                                                  component))) {
933 			/* File does not exist */
934 			g_object_unref (file);
935 			file = NULL;
936 			break;
937 		}
938 		g_object_unref (file);
939 		file = next;
940 	}
941 	g_strfreev (split_path);
942 
943 	if (file) {
944 		return file;
945 	}
946 	return g_file_get_child (parent, name);
947 }
948 
949 static GFile *
nemo_find_file_insensitive_next(GFile * parent,const gchar * name)950 nemo_find_file_insensitive_next (GFile *parent, const gchar *name)
951 {
952 	GFileEnumerator *children;
953 	GFileInfo *info;
954 	gboolean use_utf8, found;
955 	char *filename, *case_folded_name, *utf8_collation_key, *ascii_collation_key, *child_key;
956 	GFile *file;
957 	const char *child_name, *compare_key;
958 
959 	/* First check the given version */
960 	file = g_file_get_child (parent, name);
961 	if (g_file_query_exists (file, NULL)) {
962 		return file;
963 	}
964 	g_object_unref (file);
965 
966 	ascii_collation_key = g_ascii_strdown (name, -1);
967 	use_utf8 = g_utf8_validate (name, -1, NULL);
968 	utf8_collation_key = NULL;
969 	if (use_utf8) {
970 		case_folded_name = g_utf8_casefold (name, -1);
971 		utf8_collation_key = g_utf8_collate_key (case_folded_name, -1);
972 		g_free (case_folded_name);
973 	}
974 
975 	/* Enumerate and compare insensitive */
976 	filename = NULL;
977 	children = g_file_enumerate_children (parent,
978 	                                      G_FILE_ATTRIBUTE_STANDARD_NAME,
979 	                                      0, NULL, NULL);
980 	if (children != NULL) {
981 		while ((info = g_file_enumerator_next_file (children, NULL, NULL))) {
982 			child_name = g_file_info_get_name (info);
983 
984 			if (use_utf8 && g_utf8_validate (child_name, -1, NULL)) {
985 				gchar *case_folded;
986 
987 				case_folded = g_utf8_casefold (child_name, -1);
988 				child_key = g_utf8_collate_key (case_folded, -1);
989 				g_free (case_folded);
990 				compare_key = utf8_collation_key;
991 			} else {
992 				child_key = g_ascii_strdown (child_name, -1);
993 				compare_key = ascii_collation_key;
994 			}
995 
996 			found = strcmp (child_key, compare_key) == 0;
997 			g_free (child_key);
998 			if (found) {
999 				filename = g_strdup (child_name);
1000 				break;
1001 			}
1002 		}
1003 		g_file_enumerator_close (children, NULL, NULL);
1004 		g_object_unref (children);
1005 	}
1006 
1007 	g_free (ascii_collation_key);
1008 	g_free (utf8_collation_key);
1009 
1010 	if (filename) {
1011 		file = g_file_get_child (parent, filename);
1012 		g_free (filename);
1013 		return file;
1014 	}
1015 
1016 	return NULL;
1017 }
1018 
1019 static gboolean
have_program_in_path(const char * name)1020 have_program_in_path (const char *name)
1021 {
1022 	char *path;
1023 	gboolean result;
1024 
1025 	path = g_find_program_in_path (name);
1026 	result = (path != NULL);
1027 	g_free (path);
1028 	return result;
1029 }
1030 
1031 gboolean
nemo_is_file_roller_installed(void)1032 nemo_is_file_roller_installed (void)
1033 {
1034 	static int installed = - 1;
1035 
1036 	if (installed < 0) {
1037 		if (have_program_in_path ("file-roller")) {
1038 			installed = 1;
1039 		} else {
1040 			installed = 0;
1041 		}
1042 	}
1043 
1044 	return installed > 0 ? TRUE : FALSE;
1045 }
1046 
1047 #define GSM_NAME  "org.gnome.SessionManager"
1048 #define GSM_PATH "/org/gnome/SessionManager"
1049 #define GSM_INTERFACE "org.gnome.SessionManager"
1050 
1051 /* The following values come from
1052  * http://www.gnome.org/~mccann/gnome-session/docs/gnome-session.html#org.gnome.SessionManager.Inhibit
1053  */
1054 #define INHIBIT_LOGOUT (1U)
1055 #define INHIBIT_SUSPEND (4U)
1056 
1057 static GDBusConnection *
get_dbus_connection(void)1058 get_dbus_connection (void)
1059 {
1060 	static GDBusConnection *conn = NULL;
1061 
1062 	if (conn == NULL) {
1063 		GError *error = NULL;
1064 
1065 	        conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1066 
1067 		if (conn == NULL) {
1068 	                g_warning ("Could not connect to session bus: %s", error->message);
1069 			g_error_free (error);
1070 		}
1071 	}
1072 
1073 	return conn;
1074 }
1075 
1076 /**
1077  * nemo_inhibit_power_manager:
1078  * @message: a human readable message for the reason why power management
1079  *       is being suspended.
1080  *
1081  * Inhibits the power manager from logging out or suspending the machine
1082  * (e.g. whenever Nemo is doing file operations).
1083  *
1084  * Returns: an integer cookie, which must be passed to
1085  *    nemo_uninhibit_power_manager() to resume
1086  *    normal power management.
1087  */
1088 int
nemo_inhibit_power_manager(const char * message)1089 nemo_inhibit_power_manager (const char *message)
1090 {
1091 	GDBusConnection *connection;
1092 	GVariant *result;
1093 	GError *error = NULL;
1094 	guint cookie = 0;
1095 
1096 	g_return_val_if_fail (message != NULL, -1);
1097 
1098         connection = get_dbus_connection ();
1099 
1100         if (connection == NULL) {
1101                 return -1;
1102         }
1103 
1104 	result = g_dbus_connection_call_sync (connection,
1105 					      GSM_NAME,
1106 					      GSM_PATH,
1107 					      GSM_INTERFACE,
1108 					      "Inhibit",
1109 					      g_variant_new ("(susu)",
1110 							     "Nemo",
1111 							     (guint) 0,
1112 							     message,
1113 							     (guint) (INHIBIT_LOGOUT | INHIBIT_SUSPEND)),
1114 					      G_VARIANT_TYPE ("(u)"),
1115 					      G_DBUS_CALL_FLAGS_NO_AUTO_START,
1116 					      -1,
1117 					      NULL,
1118 					      &error);
1119 
1120 	if (error != NULL) {
1121 		g_warning ("Could not inhibit power management: %s", error->message);
1122 		g_error_free (error);
1123 		return -1;
1124 	}
1125 
1126 	g_variant_get (result, "(u)", &cookie);
1127 	g_variant_unref (result);
1128 
1129 	return (int) cookie;
1130 }
1131 
1132 /**
1133  * nemo_uninhibit_power_manager:
1134  * @cookie: the cookie value returned by nemo_inhibit_power_manager()
1135  *
1136  * Uninhibits power management. This function must be called after the task
1137  * which inhibited power management has finished, or the system will not
1138  * return to normal power management.
1139  */
1140 void
nemo_uninhibit_power_manager(gint cookie)1141 nemo_uninhibit_power_manager (gint cookie)
1142 {
1143 	GDBusConnection *connection;
1144 	GVariant *result;
1145 	GError *error = NULL;
1146 
1147 	g_return_if_fail (cookie > 0);
1148 
1149 	connection = get_dbus_connection ();
1150 
1151 	if (connection == NULL) {
1152 		return;
1153 	}
1154 
1155 	result = g_dbus_connection_call_sync (connection,
1156 					      GSM_NAME,
1157 					      GSM_PATH,
1158 					      GSM_INTERFACE,
1159 					      "Uninhibit",
1160 					      g_variant_new ("(u)", (guint) cookie),
1161 					      NULL,
1162 					      G_DBUS_CALL_FLAGS_NO_AUTO_START,
1163 					      -1,
1164 					      NULL,
1165 					      &error);
1166 
1167 	if (result == NULL) {
1168 		g_warning ("Could not uninhibit power management: %s", error->message);
1169 		g_error_free (error);
1170 		return;
1171 	}
1172 
1173 	g_variant_unref (result);
1174 }
1175 
1176 /* Returns TRUE if the file is in XDG_DATA_DIRS or
1177    in "~/.gnome2/". This is used for deciding
1178    if a desktop file is "trusted" based on the path */
1179 gboolean
nemo_is_in_system_dir(GFile * file)1180 nemo_is_in_system_dir (GFile *file)
1181 {
1182 	const char * const * data_dirs;
1183 	char *path, *gnome2;
1184 	int i;
1185 	gboolean res;
1186 
1187 	if (!g_file_is_native (file)) {
1188 		return FALSE;
1189 	}
1190 
1191 	path = g_file_get_path (file);
1192 
1193 	res = FALSE;
1194 
1195 	data_dirs = g_get_system_data_dirs ();
1196 	for (i = 0; path != NULL && data_dirs[i] != NULL; i++) {
1197 		if (g_str_has_prefix (path, data_dirs[i])) {
1198 			res = TRUE;
1199 			break;
1200 		}
1201 
1202 	}
1203 
1204 	if (!res) {
1205 		/* Panel desktop files are here, trust them */
1206 		gnome2 = g_build_filename (g_get_home_dir (), ".gnome2", NULL);
1207 		if (g_str_has_prefix (path, gnome2)) {
1208 			res = TRUE;
1209 		}
1210 		g_free (gnome2);
1211 	}
1212 	g_free (path);
1213 
1214 	return res;
1215 }
1216 
1217 GHashTable *
nemo_trashed_files_get_original_directories(GList * files,GList ** unhandled_files)1218 nemo_trashed_files_get_original_directories (GList *files,
1219 						 GList **unhandled_files)
1220 {
1221 	GHashTable *directories;
1222 	NemoFile *file, *original_file, *original_dir;
1223 	GList *l, *m;
1224 
1225 	directories = NULL;
1226 
1227 	if (unhandled_files != NULL) {
1228 		*unhandled_files = NULL;
1229 	}
1230 
1231 	for (l = files; l != NULL; l = l->next) {
1232 		file = NEMO_FILE (l->data);
1233 		original_file = nemo_file_get_trash_original_file (file);
1234 
1235 		original_dir = NULL;
1236 		if (original_file != NULL) {
1237 			original_dir = nemo_file_get_parent (original_file);
1238 		}
1239 
1240 		if (original_dir != NULL) {
1241 			if (directories == NULL) {
1242 				directories = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1243 								     (GDestroyNotify) nemo_file_unref,
1244 								     (GDestroyNotify) nemo_file_list_free);
1245 			}
1246 			nemo_file_ref (original_dir);
1247 			m = g_hash_table_lookup (directories, original_dir);
1248 			if (m != NULL) {
1249 				g_hash_table_steal (directories, original_dir);
1250 				nemo_file_unref (original_dir);
1251 			}
1252 			m = g_list_append (m, nemo_file_ref (file));
1253 			g_hash_table_insert (directories, original_dir, m);
1254 		} else if (unhandled_files != NULL) {
1255 			*unhandled_files = g_list_append (*unhandled_files, nemo_file_ref (file));
1256 		}
1257 
1258 		if (original_file != NULL) {
1259 			nemo_file_unref (original_file);
1260 		}
1261 
1262 		if (original_dir != NULL) {
1263 			nemo_file_unref (original_dir);
1264 		}
1265 	}
1266 
1267 	return directories;
1268 }
1269 
1270 static GList *
locations_from_file_list(GList * file_list)1271 locations_from_file_list (GList *file_list)
1272 {
1273 	NemoFile *file;
1274 	GList *l, *ret;
1275 
1276 	ret = NULL;
1277 
1278 	for (l = file_list; l != NULL; l = l->next) {
1279 		file = NEMO_FILE (l->data);
1280 		ret = g_list_prepend (ret, nemo_file_get_location (file));
1281 	}
1282 
1283 	return g_list_reverse (ret);
1284 }
1285 
1286 typedef struct {
1287 	GHashTable *original_dirs_hash;
1288 	GtkWindow  *parent_window;
1289 } RestoreFilesData;
1290 
1291 static void
ensure_dirs_task_ready_cb(GObject * _source,GAsyncResult * res,gpointer user_data)1292 ensure_dirs_task_ready_cb (GObject *_source,
1293 			   GAsyncResult *res,
1294 			   gpointer user_data)
1295 {
1296 	NemoFile *original_dir;
1297 	GFile *original_dir_location;
1298 	GList *original_dirs, *files, *locations, *l;
1299 	RestoreFilesData *data = user_data;
1300 
1301 	original_dirs = g_hash_table_get_keys (data->original_dirs_hash);
1302 	for (l = original_dirs; l != NULL; l = l->next) {
1303 		original_dir = NEMO_FILE (l->data);
1304 		original_dir_location = nemo_file_get_location (original_dir);
1305 
1306 		files = g_hash_table_lookup (data->original_dirs_hash, original_dir);
1307 		locations = locations_from_file_list (files);
1308 
1309 		nemo_file_operations_move
1310 			(locations, NULL,
1311 			 original_dir_location,
1312 			 data->parent_window,
1313 			 NULL, NULL);
1314 
1315 		g_list_free_full (locations, g_object_unref);
1316 		g_object_unref (original_dir_location);
1317 	}
1318 
1319 	g_list_free (original_dirs);
1320 
1321 	g_hash_table_unref (data->original_dirs_hash);
1322 	g_slice_free (RestoreFilesData, data);
1323 }
1324 
1325 static void
ensure_dirs_task_thread_func(GTask * task,gpointer source,gpointer task_data,GCancellable * cancellable)1326 ensure_dirs_task_thread_func (GTask *task,
1327 			      gpointer source,
1328 			      gpointer task_data,
1329 			      GCancellable *cancellable)
1330 {
1331 	RestoreFilesData *data = task_data;
1332 	NemoFile *original_dir;
1333 	GFile *original_dir_location;
1334 	GList *original_dirs, *l;
1335 
1336 	original_dirs = g_hash_table_get_keys (data->original_dirs_hash);
1337 	for (l = original_dirs; l != NULL; l = l->next) {
1338 		original_dir = NEMO_FILE (l->data);
1339 		original_dir_location = nemo_file_get_location (original_dir);
1340 
1341 		g_file_make_directory_with_parents (original_dir_location, cancellable, NULL);
1342 		g_object_unref (original_dir_location);
1343 	}
1344 
1345 	g_task_return_pointer (task, NULL, NULL);
1346 }
1347 
1348 static void
restore_files_ensure_parent_directories(GHashTable * original_dirs_hash,GtkWindow * parent_window)1349 restore_files_ensure_parent_directories (GHashTable *original_dirs_hash,
1350 					 GtkWindow  *parent_window)
1351 {
1352 	RestoreFilesData *data;
1353 	GTask *ensure_dirs_task;
1354 
1355 	data = g_slice_new0 (RestoreFilesData);
1356 	data->parent_window = parent_window;
1357 	data->original_dirs_hash = g_hash_table_ref (original_dirs_hash);
1358 
1359 	ensure_dirs_task = g_task_new (NULL, NULL, ensure_dirs_task_ready_cb, data);
1360 	g_task_set_task_data (ensure_dirs_task, data, NULL);
1361 	g_task_run_in_thread (ensure_dirs_task, ensure_dirs_task_thread_func);
1362 	g_object_unref (ensure_dirs_task);
1363 }
1364 
1365 void
nemo_restore_files_from_trash(GList * files,GtkWindow * parent_window)1366 nemo_restore_files_from_trash (GList *files,
1367 				   GtkWindow *parent_window)
1368 {
1369 	NemoFile *file;
1370 	GHashTable *original_dirs_hash;
1371 	GList *unhandled_files, *l;
1372 	char *message, *file_name;
1373 
1374 	original_dirs_hash = nemo_trashed_files_get_original_directories (files, &unhandled_files);
1375 
1376 	for (l = unhandled_files; l != NULL; l = l->next) {
1377 		file = NEMO_FILE (l->data);
1378 		file_name = nemo_file_get_display_name (file);
1379 		message = g_strdup_printf (_("Could not determine original location of \"%s\" "), file_name);
1380 		g_free (file_name);
1381 
1382 		eel_show_warning_dialog (message,
1383 					 _("The item cannot be restored from trash"),
1384 					 parent_window);
1385 		g_free (message);
1386 	}
1387 
1388 	if (original_dirs_hash != NULL) {
1389 		restore_files_ensure_parent_directories (original_dirs_hash, parent_window);
1390 		g_hash_table_unref (original_dirs_hash);
1391 	}
1392 
1393 	nemo_file_list_unref (unhandled_files);
1394 }
1395 
1396 typedef struct {
1397 	NemoMountGetContent callback;
1398 	gpointer user_data;
1399 } GetContentTypesData;
1400 
1401 static void
get_types_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1402 get_types_cb (GObject *source_object,
1403 	      GAsyncResult *res,
1404 	      gpointer user_data)
1405 {
1406 	GetContentTypesData *data;
1407 	char **types;
1408 
1409 	data = user_data;
1410 	types = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, NULL);
1411 
1412 	g_object_set_data_full (source_object,
1413 				"nemo-content-type-cache",
1414 				g_strdupv (types),
1415 				(GDestroyNotify)g_strfreev);
1416 
1417 	if (data->callback) {
1418 		data->callback ((const char **) types, data->user_data);
1419 	}
1420 	g_strfreev (types);
1421 	g_slice_free (GetContentTypesData, data);
1422 }
1423 
1424 void
nemo_get_x_content_types_for_mount_async(GMount * mount,NemoMountGetContent callback,GCancellable * cancellable,gpointer user_data)1425 nemo_get_x_content_types_for_mount_async (GMount *mount,
1426 					      NemoMountGetContent callback,
1427 					      GCancellable *cancellable,
1428 					      gpointer user_data)
1429 {
1430 	char **cached;
1431 	GetContentTypesData *data;
1432 
1433 	if (mount == NULL) {
1434 		if (callback) {
1435 			callback (NULL, user_data);
1436 		}
1437 		return;
1438 	}
1439 
1440 	cached = g_object_get_data (G_OBJECT (mount), "nemo-content-type-cache");
1441 	if (cached != NULL) {
1442 		if (callback) {
1443 			callback ((const char **) cached, user_data);
1444 		}
1445 		return;
1446 	}
1447 
1448 	data = g_slice_new0 (GetContentTypesData);
1449 	data->callback = callback;
1450 	data->user_data = user_data;
1451 
1452 	g_mount_guess_content_type (mount,
1453 				    FALSE,
1454 				    cancellable,
1455 				    get_types_cb,
1456 				    data);
1457 }
1458 
1459 char **
nemo_get_cached_x_content_types_for_mount(GMount * mount)1460 nemo_get_cached_x_content_types_for_mount (GMount *mount)
1461 {
1462 	char **cached;
1463 
1464 	if (mount == NULL) {
1465 		return NULL;
1466 	}
1467 
1468 	cached = g_object_get_data (G_OBJECT (mount), "nemo-content-type-cache");
1469 	if (cached != NULL) {
1470 		return g_strdupv (cached);
1471 	}
1472 
1473 	return NULL;
1474 }
1475 
1476 static void
debug_icon_names(const gchar * format,...)1477 debug_icon_names (const gchar *format, ...)
1478 {
1479     static gboolean debug_removable_device_icons = FALSE;
1480     static gsize once_init = 0;
1481 
1482     if (g_once_init_enter (&once_init)) {
1483         debug_removable_device_icons = g_getenv ("NEMO_DEBUG_DEVICE_ICONS") != NULL;
1484 
1485         g_once_init_leave (&once_init, 1);
1486     }
1487 
1488     if (!debug_removable_device_icons) {
1489         return;
1490     }
1491 
1492     va_list args;
1493     va_start (args, format);
1494     g_logv (NULL, G_LOG_LEVEL_MESSAGE, format, args);
1495     va_end(args);
1496 }
1497 
1498 static gboolean
icon_name_is_non_specific(const gchar * icon_name)1499 icon_name_is_non_specific (const gchar *icon_name)
1500 {
1501     gint i;
1502 
1503     static const char * non_specific_icon_names[] = { "drive-harddisk-usb-symbolic" };
1504 
1505     for (i = 0; i < G_N_ELEMENTS (non_specific_icon_names); i++) {
1506         if (g_strcmp0 (icon_name, non_specific_icon_names[i]) == 0) {
1507             return TRUE;
1508         }
1509     }
1510 
1511     return FALSE;
1512 }
1513 
1514 gchar *
nemo_get_mount_icon_name(GMount * mount)1515 nemo_get_mount_icon_name (GMount *mount)
1516 {
1517     GDrive *drive;
1518     GIcon *gicon;
1519     gchar *icon_name;
1520     gchar *mount_icon_name;
1521     gchar *dev_name;
1522 
1523     g_return_val_if_fail (mount != NULL, NULL);
1524 
1525     dev_name = g_mount_get_name (mount);
1526     icon_name = NULL;
1527     mount_icon_name = NULL;
1528 
1529     gicon = g_mount_get_symbolic_icon (mount);
1530 
1531     if (G_IS_THEMED_ICON (gicon)) {
1532         mount_icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1533 
1534         if (icon_name_is_non_specific (mount_icon_name)) {
1535             debug_icon_names ("mount %s: icon name '%s' too non-specific", dev_name, mount_icon_name);
1536         } else {
1537             icon_name = g_strdup (mount_icon_name);
1538         }
1539     }
1540 
1541     g_clear_object (&gicon);
1542 
1543     if (icon_name != NULL) {
1544         debug_icon_names ("mount %s: icon name '%s' is being used", dev_name, icon_name);
1545 
1546         g_free (dev_name);
1547         g_free (mount_icon_name);
1548 
1549         return icon_name;
1550     }
1551 
1552     drive = g_mount_get_drive (mount);
1553 
1554     if (drive != NULL) {
1555         gicon = g_drive_get_symbolic_icon (drive);
1556         g_object_unref (drive);
1557 
1558         if (G_IS_THEMED_ICON (gicon)) {
1559             icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1560         }
1561 
1562         g_object_unref (gicon);
1563     }
1564 
1565     if (icon_name == NULL) {
1566         if (mount_icon_name) {
1567             icon_name = g_strdup (mount_icon_name);
1568         } else {
1569             icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?...
1570         }
1571 
1572         debug_icon_names ("mount %s: no other good icon name found, using fallback of '%s'", dev_name, icon_name);
1573     }
1574 
1575     g_free (dev_name);
1576     g_free (mount_icon_name);
1577 
1578     return icon_name;
1579 }
1580 
1581 gchar *
nemo_get_volume_icon_name(GVolume * volume)1582 nemo_get_volume_icon_name (GVolume *volume)
1583 {
1584     GDrive *drive;
1585     GIcon *gicon;
1586     gchar *icon_name;
1587     gchar *dev_name;
1588     gchar *volume_icon_name;
1589 
1590     g_return_val_if_fail (volume != NULL, NULL);
1591 
1592     dev_name = g_volume_get_name (volume);
1593     icon_name = NULL;
1594     volume_icon_name = NULL;
1595 
1596     gicon = g_volume_get_symbolic_icon (volume);
1597 
1598     if (G_IS_THEMED_ICON (gicon)) {
1599         volume_icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1600 
1601         if (icon_name_is_non_specific (volume_icon_name)) {
1602             debug_icon_names ("volume %s: icon name '%s' too non-specific", dev_name, volume_icon_name);
1603         } else {
1604             icon_name = g_strdup (volume_icon_name);
1605         }
1606     }
1607 
1608     g_clear_object (&gicon);
1609 
1610     if (icon_name != NULL) {
1611         debug_icon_names ("volume %s: icon name '%s' is being used", dev_name, icon_name);
1612 
1613         g_free (dev_name);
1614         g_free (volume_icon_name);
1615 
1616         return icon_name;
1617     }
1618 
1619     drive = g_volume_get_drive (volume);
1620 
1621     if (drive != NULL) {
1622         gicon = g_drive_get_symbolic_icon (drive);
1623         g_object_unref (drive);
1624 
1625         if (G_IS_THEMED_ICON (gicon)) {
1626             icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1627         }
1628 
1629         g_object_unref (gicon);
1630     }
1631 
1632     if (icon_name == NULL) {
1633         if (volume_icon_name) {
1634             icon_name = g_strdup (volume_icon_name);
1635         } else {
1636             icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?...
1637 
1638         }
1639 
1640         debug_icon_names ("volume %s: no good icon name found, using fallback of '%s'", dev_name, icon_name);
1641     }
1642 
1643     g_free (dev_name);
1644     g_free (volume_icon_name);
1645 
1646     return icon_name;
1647 }
1648 
1649 gchar *
nemo_get_drive_icon_name(GDrive * drive)1650 nemo_get_drive_icon_name (GDrive *drive)
1651 {
1652     GIcon *gicon;
1653     gchar *icon_name;
1654     gchar *dev_name;
1655 
1656     g_return_val_if_fail (drive != NULL, NULL);
1657 
1658     dev_name = g_drive_get_name (drive);
1659 
1660     gicon = g_drive_get_symbolic_icon (drive);
1661 
1662     if (G_IS_THEMED_ICON (gicon)) {
1663         icon_name = g_strdup (g_themed_icon_get_names (G_THEMED_ICON (gicon))[0]);
1664     } else {
1665         icon_name = g_strdup ("folder-symbolic"); // any theme will have at least this?...
1666     }
1667 
1668     g_object_unref (gicon);
1669 
1670     debug_icon_names ("drive %s: returning icon '%s'", dev_name, icon_name);
1671 
1672     g_free (dev_name);
1673 
1674     return icon_name;
1675 }
1676 
1677 gchar *
nemo_get_best_guess_file_mimetype(const gchar * filename,GFileInfo * info,goffset size)1678 nemo_get_best_guess_file_mimetype (const gchar *filename,
1679                                    GFileInfo   *info,
1680                                    goffset      size)
1681 {
1682     /* This is an attempt to do a better job at identifying file types than
1683      * the current gio implementation.
1684      *
1685      * The current behavior for empty (0 size) size files, is to return
1686      * "text/plain" so users can touch a file, or create an empty one in their
1687      * file manager, and immediately edit it.
1688      *
1689      * This behavior currently applies regardless of whether or not a file has
1690      * an extension.
1691      *
1692      * More discussion: https://bugzilla.gnome.org/show_bug.cgi?id=755795
1693      *
1694      * What we do here instead is take a file's extension into account if the file
1695      * is zero-length.  If, by doing so, we have a high confidence that a file is
1696      * a certain type, we go ahead and use that type.  We only fall back to Gio's
1697      * zero-length implementation if the extension is unknown, or it has none.
1698      *
1699      * - Files that are NOT zero-length are treated the same as before.
1700      * - Files that we are not certain about are treated the same as before.
1701      *
1702      * Again, this only has an effect on zero-length, known-extension files.  My
1703      * argument for this differing from the standing implementation is that if I
1704      * create a file with a particular extension, I did so for a reason, and I'm not
1705      * going to do something silly like make foo.mp3 and attempt to open it with my
1706      * media player.  I do, however, expect that if I touch a foo.h file and open it,
1707      * it will open up in my source code editor, and *not* my general purpose plain-
1708      * text handler.
1709      */
1710 
1711     g_return_val_if_fail (filename != NULL, g_strdup ("application/octet-stream"));
1712     g_return_val_if_fail (info != NULL, g_strdup ("application/octet-stream"));
1713 
1714     gchar *mime_type = NULL;
1715 
1716     if (size > 0) {
1717         /* Default behavior */
1718         mime_type = eel_ref_str_get_unique (g_file_info_get_content_type (info));
1719     } else {
1720         gboolean uncertain;
1721         gchar *guessed_type = NULL;
1722 
1723         /* Only give the file basename, not the full path.  a) We may not have it yet, and
1724          * b) we don't want g_content_type_guess to keep going and snoop the file.  This will
1725          * keep the guess based entirely on the extension, if there is one.
1726          */
1727         guessed_type = g_content_type_guess (filename, NULL, 0, &uncertain);
1728 
1729         /* Uncertain means, it's not a registered extension, so we fall back to our (gio's)
1730          * normal behavior - text/plain (currently at least.) */
1731         if (!uncertain) {
1732             mime_type = eel_ref_str_get_unique (guessed_type);
1733         } else {
1734             mime_type = eel_ref_str_get_unique (g_file_info_get_content_type (info));
1735         }
1736 
1737         g_free (guessed_type);
1738     }
1739 
1740     return mime_type;
1741 }
1742 
1743 static void
query_btime_async_thread(GTask * task,gpointer object,gpointer task_data,GCancellable * cancellable)1744 query_btime_async_thread (GTask         *task,
1745                           gpointer       object,
1746                           gpointer       task_data,
1747                           GCancellable  *cancellable)
1748 {
1749     gchar *path;
1750     time_t btime;
1751 
1752     btime = 0;
1753 
1754     path = g_file_get_path (G_FILE (object));
1755 
1756     if (path != NULL) {
1757         btime = get_file_btime (path);
1758         g_free (path);
1759     }
1760 
1761     if (btime > 0) {
1762         /* Conveniently, gssize is the same as time_t */
1763         g_task_return_int (task, (gssize) btime);
1764     } else {
1765         g_task_return_error (task,
1766                              g_error_new (G_FILE_ERROR,
1767                                           G_FILE_ERROR_FAILED,
1768                                           "statx failed or not supported"));
1769     }
1770 }
1771 
1772 void
nemo_query_btime_async(GFile * file,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1773 nemo_query_btime_async (GFile               *file,
1774                         GCancellable        *cancellable,
1775                         GAsyncReadyCallback  callback,
1776                         gpointer             user_data)
1777 {
1778   GTask *task;
1779 
1780   task = g_task_new (file, cancellable, callback, user_data);
1781   g_task_set_priority (task, G_PRIORITY_DEFAULT);
1782   g_task_run_in_thread (task, query_btime_async_thread);
1783   g_object_unref (task);
1784 }
1785 
1786 time_t
nemo_query_btime_finish(GFile * file,GAsyncResult * res,GError ** error)1787 nemo_query_btime_finish (GFile         *file,
1788                              GAsyncResult  *res,
1789                              GError       **error)
1790 {
1791   g_return_val_if_fail (g_task_is_valid (res, file), -1);
1792 
1793   return (time_t) g_task_propagate_int (G_TASK (res), error);
1794 }
1795 
1796 /* End copied section */
1797 
1798 #if !defined (NEMO_OMIT_SELF_CHECK)
1799 
1800 void
nemo_self_check_file_utilities(void)1801 nemo_self_check_file_utilities (void)
1802 {
1803 }
1804 
1805 #endif /* !NEMO_OMIT_SELF_CHECK */
1806