nautilus-3.6.3/libnautilus-private/nautilus-link.c

No issues found

  1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
  2 
  3    nautilus-link.c: .desktop link files.
  4  
  5    Copyright (C) 2001 Red Hat, Inc.
  6   
  7    This program is free software; you can redistribute it and/or
  8    modify it under the terms of the GNU 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    This program is distributed in the hope that it will be useful,
 13    but WITHOUT ANY WARRANTY; without even the historicalied warranty of
 14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15    General Public License for more details.
 16   
 17    You should have received a copy of the GNU General Public
 18    License along with this program; if not, write to the
 19    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 20    Boston, MA 02111-1307, USA.
 21   
 22    Authors: Jonathan Blandford <jrb@redhat.com>
 23             Alexander Larsson <alexl@redhat.com>
 24 */
 25 
 26 #include <config.h>
 27 #include "nautilus-link.h"
 28 
 29 #include "nautilus-directory-notify.h"
 30 #include "nautilus-directory.h"
 31 #include "nautilus-file-utilities.h"
 32 #include "nautilus-file.h"
 33 #include "nautilus-program-choosing.h"
 34 #include "nautilus-icon-names.h"
 35 #include <eel/eel-vfs-extensions.h>
 36 #include <glib/gi18n.h>
 37 #include <gio/gio.h>
 38 #include <stdlib.h>
 39 #include <string.h>
 40 
 41 #define MAIN_GROUP "Desktop Entry"
 42 
 43 #define NAUTILUS_LINK_GENERIC_TAG	"Link"
 44 #define NAUTILUS_LINK_TRASH_TAG 	"X-nautilus-trash"
 45 #define NAUTILUS_LINK_MOUNT_TAG 	"FSDevice"
 46 #define NAUTILUS_LINK_HOME_TAG 		"X-nautilus-home"
 47 
 48 static gboolean
 49 is_link_mime_type (const char *mime_type)
 50 {
 51 	if (mime_type != NULL &&
 52 	     g_ascii_strcasecmp (mime_type, "application/x-desktop") == 0) {
 53 		return TRUE;
 54 	}
 55 
 56 	return FALSE;
 57 }
 58 
 59 static gboolean
 60 is_local_file_a_link (const char *uri)
 61 {
 62 	gboolean link;
 63 	GFile *file;
 64 	GFileInfo *info;
 65 	GError *error;
 66 
 67 	error = NULL;
 68 	link = FALSE;
 69 
 70 	file = g_file_new_for_uri (uri);
 71 
 72 	info = g_file_query_info (file,
 73 				  G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
 74 				  0, NULL, &error);
 75 	if (info) {
 76 		link = is_link_mime_type (g_file_info_get_content_type (info));
 77 		g_object_unref (info);
 78 	}
 79 	else {
 80 		g_warning ("Error getting info: %s\n", error->message);
 81 		g_error_free (error);
 82 	}
 83 
 84 	g_object_unref (file);
 85 
 86 	return link;
 87 }
 88 
 89 static gboolean
 90 _g_key_file_load_from_gfile (GKeyFile *key_file,
 91 			     GFile *file,
 92 			     GKeyFileFlags flags,
 93 			     GError **error)
 94 {
 95 	char *data;
 96 	gsize len;
 97 	gboolean res;
 98 	
 99 	if (!g_file_load_contents (file, NULL, &data, &len, NULL, error)) {
100 		return FALSE;
101 	}
102 
103 	res = g_key_file_load_from_data (key_file, data, len, flags, error);
104 	
105 	g_free (data);
106 	
107 	return res;
108 }
109 
110 static gboolean
111 _g_key_file_save_to_gfile (GKeyFile *key_file,
112 			   GFile *file,
113 			   GError  **error)
114 {
115 	char *data;
116 	gsize len;
117 
118 	data = g_key_file_to_data (key_file, &len, error);
119 	if (data == NULL) {
120 		return FALSE;
121 	}
122 		
123 	if (!g_file_replace_contents (file,
124 				      data, len,
125 				      NULL, FALSE,
126 				      G_FILE_CREATE_NONE,
127 				      NULL, NULL, error)) {
128 		g_free (data);
129 		return FALSE;
130 	}
131 	g_free (data);
132 	return TRUE;
133 }
134 
135 
136 
137 static GKeyFile *
138 _g_key_file_new_from_uri (const char *uri,
139 			  GKeyFileFlags flags,
140 			  GError **error)
141 {
142 	GKeyFile *key_file;
143 	GFile *file;
144 	
145 	file = g_file_new_for_uri (uri);
146 	key_file = g_key_file_new ();
147 	if (!_g_key_file_load_from_gfile (key_file, file, flags, error)) {
148 		g_key_file_free (key_file);
149 		key_file = NULL;
150 	}
151 	g_object_unref (file);
152 	return key_file;
153 }
154 
155 static char *
156 slurp_key_string (const char *uri,
157 		  const char *keyname,
158                   gboolean    localize)
159 {
160 	GKeyFile *key_file;
161 	char *result;
162 
163 	key_file = _g_key_file_new_from_uri (uri, G_KEY_FILE_NONE, NULL);
164 	if (key_file == NULL) {
165 		return NULL;
166 	}
167 
168 	if (localize) {
169 		result = g_key_file_get_locale_string (key_file, MAIN_GROUP, keyname, NULL, NULL);		
170 	} else {
171 		result = g_key_file_get_string (key_file, MAIN_GROUP, keyname, NULL);		
172 	}
173 	g_key_file_free (key_file);
174 
175 	return result;
176 }
177 
178 gboolean
179 nautilus_link_local_create (const char     *directory_uri,
180 			    const char     *base_name,
181 			    const char     *display_name,
182 			    const char     *image,
183 			    const char     *target_uri,
184 			    const GdkPoint *point,
185 			    int             screen,
186 			    gboolean        unique_filename)
187 {
188 	char *real_directory_uri;
189 	char *uri, *contents;
190 	GFile *file;
191 	GList dummy_list;
192 	NautilusFileChangesQueuePosition item;
193 
194 	g_return_val_if_fail (directory_uri != NULL, FALSE);
195 	g_return_val_if_fail (base_name != NULL, FALSE);
196 	g_return_val_if_fail (display_name != NULL, FALSE);
197 	g_return_val_if_fail (target_uri != NULL, FALSE);
198 
199 	if (eel_uri_is_trash (directory_uri) ||
200 	    eel_uri_is_search (directory_uri)) {
201 		return FALSE;
202 	}
203 
204 	if (eel_uri_is_desktop (directory_uri)) {
205 		real_directory_uri = nautilus_get_desktop_directory_uri ();
206 	} else {
207 		real_directory_uri = g_strdup (directory_uri);
208 	}
209 
210 	if (unique_filename) {
211 		uri = nautilus_ensure_unique_file_name (real_directory_uri,
212 							base_name, ".desktop");
213 		if (uri == NULL) {
214 			g_free (real_directory_uri);
215 			return FALSE;
216 		}
217 		file = g_file_new_for_uri (uri);
218 		g_free (uri);
219 	} else {
220 		char *link_name;
221 		GFile *dir;
222 
223 		link_name = g_strdup_printf ("%s.desktop", base_name);
224 
225 		/* replace '/' with '-', just in case */
226 		g_strdelimit (link_name, "/", '-');
227 
228 		dir = g_file_new_for_uri (directory_uri);
229 		file = g_file_get_child (dir, link_name);
230 
231 		g_free (link_name);
232 		g_object_unref (dir);
233 	}
234 
235 	g_free (real_directory_uri);
236 
237 	contents = g_strdup_printf ("[Desktop Entry]\n"
238 				    "Encoding=UTF-8\n"
239 				    "Name=%s\n"
240 				    "Type=Link\n"
241 				    "URL=%s\n"
242 				    "%s%s\n",
243 				    display_name,
244 				    target_uri,
245 				    image != NULL ? "Icon=" : "",
246 				    image != NULL ? image : "");
247 
248 
249 	if (!g_file_replace_contents (file,
250 				      contents, strlen (contents),
251 				      NULL, FALSE,
252 				      G_FILE_CREATE_NONE,
253 				      NULL, NULL, NULL)) {
254 		g_free (contents);
255 		g_object_unref (file);
256 		return FALSE;
257 	}
258 	g_free (contents);
259 
260 	dummy_list.data = file;
261 	dummy_list.next = NULL;
262 	dummy_list.prev = NULL;
263 	nautilus_directory_notify_files_added (&dummy_list);
264 
265 	if (point != NULL) {
266 		item.location = file;
267 		item.set = TRUE;
268 		item.point.x = point->x;
269 		item.point.y = point->y;
270 		item.screen = screen;
271 		dummy_list.data = &item;
272 		dummy_list.next = NULL;
273 		dummy_list.prev = NULL;
274 	
275 		nautilus_directory_schedule_position_set (&dummy_list);
276 	}
277 
278 	g_object_unref (file);
279 	return TRUE;
280 }
281 
282 static const char *
283 get_language (void)
284 {
285 	const char * const *langs_pointer;
286 	int i;
287 
288 	langs_pointer = g_get_language_names ();
289 	for (i = 0; langs_pointer[i] != NULL; i++) {
290 		/* find first without encoding */
291 		if (strchr (langs_pointer[i], '.') == NULL) {
292 		return langs_pointer[i];
293 		}
294 	}
295 	return NULL;
296 } 
297 
298 static gboolean
299 nautilus_link_local_set_key (const char *uri,
300 			     const char *key,
301 			     const char *value,
302 			     gboolean    localize)
303 {
304 	gboolean success;
305 	GKeyFile *key_file;
306 	GFile *file;
307 	
308 	file = g_file_new_for_uri (uri);
309 	key_file = g_key_file_new ();
310 	if (!_g_key_file_load_from_gfile (key_file, file, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
311 		g_key_file_free (key_file);
312 		g_object_unref (file);
313 		return FALSE;
314 	}
315 	if (localize) {
316 		g_key_file_set_locale_string (key_file,
317 					      MAIN_GROUP,
318 					      key,
319 					      get_language (), 
320 					      value);
321 	} else {
322 		g_key_file_set_string (key_file, MAIN_GROUP, key, value);
323 	}
324 	
325 	
326 	success = _g_key_file_save_to_gfile (key_file,  file, NULL);
327 	g_key_file_free (key_file);
328 	g_object_unref (file);
329 	return success;
330 }
331 
332 gboolean
333 nautilus_link_local_set_text (const char *uri,
334 			      const char *text)
335 {
336 	return nautilus_link_local_set_key (uri, "Name", text, TRUE);
337 }
338 
339 
340 gboolean
341 nautilus_link_local_set_icon (const char        *uri,
342 			      const char        *icon)
343 {
344 	return nautilus_link_local_set_key (uri, "Icon", icon, FALSE);
345 }
346 
347 char *
348 nautilus_link_local_get_text (const char *path)
349 {
350 	return slurp_key_string (path, "Name", TRUE);
351 }
352 
353 static char *
354 nautilus_link_get_link_uri_from_desktop (GKeyFile *key_file, const char *desktop_file_uri)
355 {
356 	GFile *file, *parent;
357 	char *type;
358 	char *retval;
359 	char *scheme;
360 
361 	retval = NULL;
362 
363 	type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL);
364 	if (type == NULL) {
365 		return NULL;
366 	}
367 
368 	if (strcmp (type, "URL") == 0) {
369 		/* Some old broken desktop files use this nonstandard feature, we need handle it though */
370 		retval = g_key_file_get_string (key_file, MAIN_GROUP, "Exec", NULL);
371 	} else if ((strcmp (type, NAUTILUS_LINK_GENERIC_TAG) == 0) ||
372 		   (strcmp (type, NAUTILUS_LINK_MOUNT_TAG) == 0) ||
373 		   (strcmp (type, NAUTILUS_LINK_TRASH_TAG) == 0) ||
374 		   (strcmp (type, NAUTILUS_LINK_HOME_TAG) == 0)) {
375 		retval = g_key_file_get_string (key_file, MAIN_GROUP, "URL", NULL);
376 	}
377 	g_free (type);
378 
379 	if (retval != NULL && desktop_file_uri != NULL) {
380 		/* Handle local file names.
381 		 * Ideally, we'd be able to use
382 		 * g_file_parse_name(), but it does not know how to resolve
383 		 * relative file names, since the base directory is unknown.
384 		 */
385 		scheme = g_uri_parse_scheme (retval);
386 		if (scheme == NULL) {
387 			file = g_file_new_for_uri (desktop_file_uri);
388 			parent = g_file_get_parent (file);
389 			g_object_unref (file);
390 
391 			if (parent != NULL) {
392 				file = g_file_resolve_relative_path (parent, retval);
393 				g_free (retval);
394 				retval = g_file_get_uri (file);
395 				g_object_unref (file);
396 				g_object_unref (parent);
397 			}
398 		}
399 		g_free (scheme);
400 	}
401 
402 	return retval;
403 }
404 
405 static char *
406 nautilus_link_get_link_name_from_desktop (GKeyFile *key_file)
407 {
408 	return g_key_file_get_locale_string (key_file, MAIN_GROUP, "Name", NULL, NULL);
409 }
410 
411 static GIcon *
412 nautilus_link_get_link_icon_from_desktop (GKeyFile *key_file)
413 {
414 	char *icon_str, *p, *type = NULL;
415 	GFile *file;
416 	GIcon *icon;
417 
418 	/* Look at the Icon: key */
419 	icon_str = g_key_file_get_string (key_file, MAIN_GROUP, "Icon", NULL);
420 
421 	/* if it's an absolute path, return a GFileIcon for that path */
422 	if (icon_str != NULL && g_path_is_absolute (icon_str)) {
423 		file = g_file_new_for_path (icon_str);
424 		icon = g_file_icon_new (file);
425 
426 		g_object_unref (file);
427 
428 		goto out;
429 	}
430 
431 	type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL);
432 
433 	if (icon_str == NULL) {
434 		if (g_strcmp0 (type, "Application") == 0) {
435 			icon_str = g_strdup ("application-x-executable");
436 		} else if (g_strcmp0 (type, "FSDevice") == 0) {
437 			icon_str = g_strdup ("drive-harddisk");
438 		} else if (g_strcmp0 (type, "Directory") == 0) {
439 			icon_str = g_strdup (NAUTILUS_ICON_FOLDER);
440 		} else if (g_strcmp0 (type, "Service") == 0 ||
441 			   g_strcmp0 (type, "ServiceType") == 0) {
442 			icon_str = g_strdup ("folder-remote");
443 		} else {
444 			icon_str = g_strdup ("text-x-preview");
445 		}
446 	} else {
447 		/* Strip out any extension on non-filename icons. Old desktop files may have this */
448 		p = strchr (icon_str, '.');
449 		/* Only strip known icon extensions */
450 		if ((p != NULL) &&
451 		    ((g_ascii_strcasecmp (p, ".png") == 0)
452 		     || (g_ascii_strcasecmp (p, ".svn") == 0)
453 		     || (g_ascii_strcasecmp (p, ".jpg") == 0)
454 		     || (g_ascii_strcasecmp (p, ".xpm") == 0)
455 		     || (g_ascii_strcasecmp (p, ".bmp") == 0)
456 		     || (g_ascii_strcasecmp (p, ".jpeg") == 0))) {
457 			*p = 0;
458 		}
459 	}
460 
461 	icon = g_themed_icon_new_with_default_fallbacks (icon_str);
462 
463 	/* apply a link emblem if it's a link */
464 	if (g_strcmp0 (type, "Link") == 0) {
465 		GIcon *emblemed, *emblem_icon;
466 		GEmblem *emblem;
467 
468 		emblem_icon = g_themed_icon_new ("emblem-symbolic-link");
469 		emblem = g_emblem_new (emblem_icon);
470 
471 		emblemed = g_emblemed_icon_new (icon, emblem);
472 
473 		g_object_unref (icon);
474 		g_object_unref (emblem_icon);
475 		g_object_unref (emblem);
476 
477 		icon = emblemed;
478 	}
479 
480  out:
481 	g_free (icon_str);
482 	g_free (type);
483 
484 	return icon;
485 }
486 
487 char *
488 nautilus_link_local_get_link_uri (const char *uri)
489 {
490 	GKeyFile *key_file;
491 	char *retval;
492 
493 	if (!is_local_file_a_link (uri)) {
494 		return NULL;
495 	}
496 
497 	key_file = _g_key_file_new_from_uri (uri, G_KEY_FILE_NONE, NULL);
498 	if (key_file == NULL) {
499 		return NULL;
500 	}
501 
502 	retval = nautilus_link_get_link_uri_from_desktop (key_file, uri);
503 	g_key_file_free (key_file);
504 
505 	return retval;
506 }
507 
508 static gboolean
509 string_array_contains (char **array,
510 		       const char *str)
511 {
512 	char **p;
513 
514 	if (!array)
515 		return FALSE;
516 
517 	for (p = array; *p; p++)
518 		if (g_ascii_strcasecmp (*p, str) == 0) {
519 			return TRUE;
520 		}
521 
522 	return FALSE;
523 }
524 
525 static const gchar *
526 get_session (void)
527 {
528 	const gchar * session;
529 
530 	session = g_getenv ("XDG_CURRENT_DESKTOP");
531 
532 	if (session == NULL || session[0] == 0) {
533 		/* historic behavior */
534 		session = "GNOME";
535 	}
536 
537 	return session;
538 }
539 
540 void
541 nautilus_link_get_link_info_given_file_contents (const char  *file_contents,
542 						 int          link_file_size,
543 						 const char  *file_uri,
544 						 char       **uri,
545 						 char       **name,
546 						 GIcon      **icon,
547 						 gboolean    *is_launcher,
548 						 gboolean    *is_foreign)
549 {
550 	GKeyFile *key_file;
551 	char *type;
552 	char **only_show_in;
553 	char **not_show_in;
554 	const gchar *session;
555 
556 	session = get_session ();
557 	key_file = g_key_file_new ();
558 	if (!g_key_file_load_from_data (key_file,
559 					file_contents,
560 					link_file_size,
561 					G_KEY_FILE_NONE,
562 					NULL)) {
563 		g_key_file_free (key_file);
564 		return; 
565 	}
566 
567 	*uri = nautilus_link_get_link_uri_from_desktop (key_file, file_uri);
568 	*name = nautilus_link_get_link_name_from_desktop (key_file);
569 	*icon = nautilus_link_get_link_icon_from_desktop (key_file);
570 
571 	*is_launcher = FALSE;
572 	type = g_key_file_get_string (key_file, MAIN_GROUP, "Type", NULL);
573 	if (g_strcmp0 (type, "Application") == 0 &&
574 	    g_key_file_has_key (key_file, MAIN_GROUP, "Exec", NULL)) {
575 		*is_launcher = TRUE;
576 	}
577 	g_free (type);
578 
579 	*is_foreign = FALSE;
580 	only_show_in = g_key_file_get_string_list (key_file, MAIN_GROUP,
581 						   "OnlyShowIn", NULL, NULL);
582 	if (session && only_show_in && !string_array_contains (only_show_in, session)) {
583 		*is_foreign = TRUE;
584 	}
585 	g_strfreev (only_show_in);
586 
587 	not_show_in = g_key_file_get_string_list (key_file, MAIN_GROUP,
588 						  "NotShowIn", NULL, NULL);
589 	if (session && not_show_in && string_array_contains (not_show_in, session)) {
590 		*is_foreign = TRUE;
591 	}
592 	g_strfreev (not_show_in);
593 
594 	g_key_file_free (key_file);
595 }