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 }