2 * @file purple-desktop-item.c Functions for managing .desktop files
6 /* Purple is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27 * The following code has been adapted from gnome-desktop-item.[ch],
28 * as found on gnome-desktop-2.8.1.
30 * Copyright (C) 2004 by Alceste Scalas <alceste.scalas@gmx.net>.
32 * Original copyright notice:
34 * Copyright (C) 1999, 2000 Red Hat Inc.
35 * Copyright (C) 2001 Sid Vicious
36 * All rights reserved.
38 * This file is part of the Gnome Library.
40 * The Gnome Library is free software; you can redistribute it and/or
41 * modify it under the terms of the GNU Library General Public License as
42 * published by the Free Software Foundation; either version 2 of the
43 * License, or (at your option) any later version.
45 * The Gnome Library is distributed in the hope that it will be useful,
46 * but WITHOUT ANY WARRANTY; without even the implied warranty of
47 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
48 * Library General Public License for more details.
50 * You should have received a copy of the GNU Library General Public
51 * License along with the Gnome Library; see the file COPYING.LIB. If not,
52 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
53 * Boston, MA 02111-1301, USA.
61 #include "desktopitem.h"
63 struct _PurpleDesktopItem
{
66 /* all languages used */
69 PurpleDesktopItemType type
;
71 /* `modified' means that the ditem has been
72 * modified since the last save. */
75 /* Keys of the main section only */
80 /* This includes ALL keys, including
81 * other sections, separated by '/' */
82 GHashTable
*main_hash
;
100 /**************************************************************************
101 * Private utility functions
102 **************************************************************************/
103 static PurpleDesktopItemType
104 type_from_string (const char *type
)
107 return PURPLE_DESKTOP_ITEM_TYPE_NULL
;
111 if (purple_strequal (type
, "Application"))
112 return PURPLE_DESKTOP_ITEM_TYPE_APPLICATION
;
115 if (purple_strequal (type
, "Link"))
116 return PURPLE_DESKTOP_ITEM_TYPE_LINK
;
119 if (purple_strequal (type
, "FSDevice"))
120 return PURPLE_DESKTOP_ITEM_TYPE_FSDEVICE
;
123 if (purple_strequal (type
, "MimeType"))
124 return PURPLE_DESKTOP_ITEM_TYPE_MIME_TYPE
;
127 if (purple_strequal (type
, "Directory"))
128 return PURPLE_DESKTOP_ITEM_TYPE_DIRECTORY
;
131 if (purple_strequal (type
, "Service"))
132 return PURPLE_DESKTOP_ITEM_TYPE_SERVICE
;
134 else if (purple_strequal (type
, "ServiceType"))
135 return PURPLE_DESKTOP_ITEM_TYPE_SERVICE_TYPE
;
141 return PURPLE_DESKTOP_ITEM_TYPE_OTHER
;
145 find_section (PurpleDesktopItem
*item
, const char *section
)
152 if (purple_strequal (section
, "Desktop Entry"))
155 for (li
= item
->sections
; li
!= NULL
; li
= li
->next
) {
157 if (purple_strequal (sec
->name
, section
))
161 sec
= g_new0 (Section
, 1);
162 sec
->name
= g_strdup (section
);
165 item
->sections
= g_list_append (item
->sections
, sec
);
167 /* Don't mark the item modified, this is just an empty section,
168 * it won't be saved even */
174 section_from_key (PurpleDesktopItem
*item
, const char *key
)
183 p
= strchr (key
, '/');
187 name
= g_strndup (key
, p
- key
);
189 sec
= find_section (item
, name
);
197 key_basename (const char *key
)
199 char *p
= strrchr (key
, '/');
207 set (PurpleDesktopItem
*item
, const char *key
, const char *value
)
209 Section
*sec
= section_from_key (item
, key
);
213 if (g_hash_table_lookup (item
->main_hash
, key
) == NULL
)
214 sec
->keys
= g_list_append
216 g_strdup (key_basename (key
)));
218 g_hash_table_replace (item
->main_hash
,
222 GList
*list
= g_list_find_custom
223 (sec
->keys
, key_basename (key
),
224 (GCompareFunc
)strcmp
);
228 g_list_delete_link (sec
->keys
, list
);
230 g_hash_table_remove (item
->main_hash
, key
);
234 if (g_hash_table_lookup (item
->main_hash
, key
) == NULL
)
235 item
->keys
= g_list_append (item
->keys
,
238 g_hash_table_replace (item
->main_hash
,
242 GList
*list
= g_list_find_custom
243 (item
->keys
, key
, (GCompareFunc
)strcmp
);
247 g_list_delete_link (item
->keys
, list
);
249 g_hash_table_remove (item
->main_hash
, key
);
252 item
->modified
= TRUE
;
257 _purple_desktop_item_set_string (PurpleDesktopItem
*item
,
261 g_return_if_fail (item
!= NULL
);
262 g_return_if_fail (item
->refcount
> 0);
263 g_return_if_fail (attr
!= NULL
);
265 set (item
, attr
, value
);
267 if (purple_strequal (attr
, PURPLE_DESKTOP_ITEM_TYPE
))
268 item
->type
= type_from_string (value
);
271 static PurpleDesktopItem
*
272 _purple_desktop_item_new (void)
274 PurpleDesktopItem
*retval
;
276 retval
= g_new0 (PurpleDesktopItem
, 1);
280 retval
->main_hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
281 (GDestroyNotify
) g_free
,
282 (GDestroyNotify
) g_free
);
284 /* These are guaranteed to be set */
285 _purple_desktop_item_set_string (retval
,
286 PURPLE_DESKTOP_ITEM_NAME
,
288 _purple_desktop_item_set_string (retval
,
289 PURPLE_DESKTOP_ITEM_ENCODING
,
291 _purple_desktop_item_set_string (retval
,
292 PURPLE_DESKTOP_ITEM_VERSION
,
299 _purple_desktop_item_copy (gpointer boxed
)
301 return purple_desktop_item_copy (boxed
);
305 _purple_desktop_item_free (gpointer boxed
)
307 purple_desktop_item_unref (boxed
);
310 /* Note, does not include the trailing \n */
312 my_fgets (char *buf
, gsize bufsize
, FILE *df
)
317 g_return_val_if_fail (buf
!= NULL
, NULL
);
318 g_return_val_if_fail (df
!= NULL
, NULL
);
325 if (c
== EOF
|| c
== '\n')
328 } while (pos
< bufsize
-1);
330 if (c
== EOF
&& pos
== 0)
339 get_encoding (FILE *df
)
341 gboolean old_kde
= FALSE
;
343 gboolean all_valid_utf8
= TRUE
;
345 while (my_fgets (buf
, sizeof (buf
), df
) != NULL
) {
346 if (strncmp (PURPLE_DESKTOP_ITEM_ENCODING
,
348 strlen (PURPLE_DESKTOP_ITEM_ENCODING
)) == 0) {
349 char *p
= &buf
[strlen (PURPLE_DESKTOP_ITEM_ENCODING
)];
357 if (purple_strequal (p
, "UTF-8")) {
358 return ENCODING_UTF8
;
359 } else if (purple_strequal (p
, "Legacy-Mixed")) {
360 return ENCODING_LEGACY_MIXED
;
362 /* According to the spec we're not supposed
363 * to read a file like this */
364 return ENCODING_UNKNOWN
;
366 } else if (purple_strequal ("[KDE Desktop Entry]", buf
)) {
368 /* don't break yet, we still want to support
369 * Encoding even here */
371 if (all_valid_utf8
&& ! g_utf8_validate (buf
, -1, NULL
))
372 all_valid_utf8
= FALSE
;
376 return ENCODING_LEGACY_MIXED
;
378 /* A dilemma, new KDE files are in UTF-8 but have no Encoding
379 * info, at this time we really can't tell. The best thing to
380 * do right now is to just assume UTF-8 if the whole file
381 * validates as utf8 I suppose */
384 return ENCODING_UTF8
;
386 return ENCODING_LEGACY_MIXED
;
390 snarf_locale_from_key (const char *key
)
395 brace
= strchr (key
, '[');
399 locale
= g_strdup (brace
+ 1);
400 if (*locale
== '\0') {
404 p
= strchr (locale
, ']');
414 check_locale (const char *locale
)
416 GIConv cd
= g_iconv_open ("UTF-8", locale
);
417 if ((GIConv
)-1 == cd
)
424 insert_locales (GHashTable
*encodings
, char *enc
, ...)
429 va_start (args
, enc
);
431 s
= va_arg (args
, char *);
434 g_hash_table_insert (encodings
, s
, enc
);
439 /* make a standard conversion table from the desktop standard spec */
441 init_encodings (void)
443 GHashTable
*encodings
= g_hash_table_new (g_str_hash
, g_str_equal
);
445 /* "C" is plain ascii */
446 insert_locales (encodings
, "ASCII", "C", NULL
);
448 insert_locales (encodings
, "ARMSCII-8", "by", NULL
);
449 insert_locales (encodings
, "BIG5", "zh_TW", NULL
);
450 insert_locales (encodings
, "CP1251", "be", "bg", NULL
);
451 if (check_locale ("EUC-CN")) {
452 insert_locales (encodings
, "EUC-CN", "zh_CN", NULL
);
454 insert_locales (encodings
, "GB2312", "zh_CN", NULL
);
456 insert_locales (encodings
, "EUC-JP", "ja", NULL
);
457 insert_locales (encodings
, "EUC-KR", "ko", NULL
);
458 /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
459 insert_locales (encodings
, "GEORGIAN-PS", "ka", NULL
);
460 insert_locales (encodings
, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL
);
461 insert_locales (encodings
, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL
);
462 insert_locales (encodings
, "ISO-8859-3", "eo", NULL
);
463 insert_locales (encodings
, "ISO-8859-5", "mk", "sp", NULL
);
464 insert_locales (encodings
, "ISO-8859-7", "el", NULL
);
465 insert_locales (encodings
, "ISO-8859-9", "tr", NULL
);
466 insert_locales (encodings
, "ISO-8859-13", "lt", "lv", "mi", NULL
);
467 insert_locales (encodings
, "ISO-8859-14", "ga", "cy", NULL
);
468 insert_locales (encodings
, "ISO-8859-15", "et", NULL
);
469 insert_locales (encodings
, "KOI8-R", "ru", NULL
);
470 insert_locales (encodings
, "KOI8-U", "uk", NULL
);
471 if (check_locale ("TCVN-5712")) {
472 insert_locales (encodings
, "TCVN-5712", "vi", NULL
);
474 insert_locales (encodings
, "TCVN", "vi", NULL
);
476 insert_locales (encodings
, "TIS-620", "th", NULL
);
477 /*insert_locales (encodings, "VISCII", NULL);*/
483 get_encoding_from_locale (const char *locale
)
486 const char *encoding
;
487 static GHashTable
*encodings
= NULL
;
492 /* if locale includes encoding, use it */
493 encoding
= strchr (locale
, '.');
494 if (encoding
!= NULL
) {
498 if (encodings
== NULL
)
499 encodings
= init_encodings ();
501 /* first try the entire locale (at this point ll_CC) */
502 encoding
= g_hash_table_lookup (encodings
, locale
);
503 if (encoding
!= NULL
)
506 /* Try just the language */
507 strncpy (lang
, locale
, 2);
509 return g_hash_table_lookup (encodings
, lang
);
513 decode_string_and_dup (const char *s
)
515 char *p
= g_malloc (strlen (s
) + 1);
550 decode_string (const char *value
, Encoding encoding
, const char *locale
)
554 /* if legacy mixed, then convert */
555 if (locale
!= NULL
&& encoding
== ENCODING_LEGACY_MIXED
) {
556 const char *char_encoding
= get_encoding_from_locale (locale
);
558 if (char_encoding
== NULL
)
560 if (purple_strequal (char_encoding
, "ASCII")) {
561 return decode_string_and_dup (value
);
563 utf8_string
= g_convert (value
, -1, "UTF-8", char_encoding
,
565 if (utf8_string
== NULL
)
567 retval
= decode_string_and_dup (utf8_string
);
568 g_free (utf8_string
);
570 /* if utf8, then validate */
571 } else if (locale
!= NULL
&& encoding
== ENCODING_UTF8
) {
572 if ( ! g_utf8_validate (value
, -1, NULL
))
573 /* invalid utf8, ignore this key */
575 return decode_string_and_dup (value
);
577 /* Meaning this is not a localized string */
578 return decode_string_and_dup (value
);
582 /************************************************************
584 ************************************************************/
586 static gboolean G_GNUC_CONST
587 standard_is_boolean (const char * key
)
589 static GHashTable
*bools
= NULL
;
592 bools
= g_hash_table_new (g_str_hash
, g_str_equal
);
593 g_hash_table_insert (bools
,
594 PURPLE_DESKTOP_ITEM_NO_DISPLAY
,
595 PURPLE_DESKTOP_ITEM_NO_DISPLAY
);
596 g_hash_table_insert (bools
,
597 PURPLE_DESKTOP_ITEM_HIDDEN
,
598 PURPLE_DESKTOP_ITEM_HIDDEN
);
599 g_hash_table_insert (bools
,
600 PURPLE_DESKTOP_ITEM_TERMINAL
,
601 PURPLE_DESKTOP_ITEM_TERMINAL
);
602 g_hash_table_insert (bools
,
603 PURPLE_DESKTOP_ITEM_READ_ONLY
,
604 PURPLE_DESKTOP_ITEM_READ_ONLY
);
607 return g_hash_table_lookup (bools
, key
) != NULL
;
610 static gboolean G_GNUC_CONST
611 standard_is_strings (const char *key
)
613 static GHashTable
*strings
= NULL
;
615 if (strings
== NULL
) {
616 strings
= g_hash_table_new (g_str_hash
, g_str_equal
);
617 g_hash_table_insert (strings
,
618 PURPLE_DESKTOP_ITEM_FILE_PATTERN
,
619 PURPLE_DESKTOP_ITEM_FILE_PATTERN
);
620 g_hash_table_insert (strings
,
621 PURPLE_DESKTOP_ITEM_ACTIONS
,
622 PURPLE_DESKTOP_ITEM_ACTIONS
);
623 g_hash_table_insert (strings
,
624 PURPLE_DESKTOP_ITEM_MIME_TYPE
,
625 PURPLE_DESKTOP_ITEM_MIME_TYPE
);
626 g_hash_table_insert (strings
,
627 PURPLE_DESKTOP_ITEM_PATTERNS
,
628 PURPLE_DESKTOP_ITEM_PATTERNS
);
629 g_hash_table_insert (strings
,
630 PURPLE_DESKTOP_ITEM_SORT_ORDER
,
631 PURPLE_DESKTOP_ITEM_SORT_ORDER
);
634 return g_hash_table_lookup (strings
, key
) != NULL
;
637 /* If no need to cannonize, returns NULL */
639 cannonize (const char *key
, const char *value
)
641 if (standard_is_boolean (key
)) {
642 if (value
[0] == 'T' ||
647 return g_strdup ("true");
649 return g_strdup ("false");
651 } else if (standard_is_strings (key
)) {
652 int len
= strlen (value
);
653 if (len
== 0 || value
[len
-1] != ';') {
654 return g_strconcat (value
, ";", NULL
);
657 /* XXX: Perhaps we should canonize numeric values as well, but this
658 * has caused some subtle problems before so it needs to be done
659 * carefully if at all */
664 insert_key (PurpleDesktopItem
*item
,
665 Section
*cur_section
,
670 gboolean no_translations
)
674 /* we always store everything in UTF-8 */
675 if (cur_section
== NULL
&&
676 purple_strequal (key
, PURPLE_DESKTOP_ITEM_ENCODING
)) {
678 val
= g_strdup ("UTF-8");
680 char *locale
= snarf_locale_from_key (key
);
681 /* If we're ignoring translations */
682 if (no_translations
&& locale
!= NULL
) {
686 val
= decode_string (value
, encoding
, locale
);
688 /* Ignore this key, it's whacked */
696 /* For old KDE entries, we can also split by a comma
697 * on sort order, so convert to semicolons */
699 cur_section
== NULL
&&
700 purple_strequal (key
, PURPLE_DESKTOP_ITEM_SORT_ORDER
) &&
701 strchr (val
, ';') == NULL
) {
703 for (i
= 0; val
[i
] != '\0'; i
++) {
709 /* Check some types, not perfect, but catches a lot
711 if (cur_section
== NULL
) {
712 char *cannon
= cannonize (key
, val
);
713 if (cannon
!= NULL
) {
721 /* Take care of the language part */
722 if (locale
!= NULL
&&
723 purple_strequal (locale
, "C")) {
729 } else if (locale
!= NULL
) {
732 /* Whack the encoding part */
733 p
= strchr (locale
, '.');
737 if (g_list_find_custom (item
->languages
, locale
,
738 (GCompareFunc
)strcmp
) == NULL
) {
739 item
->languages
= g_list_prepend
740 (item
->languages
, locale
);
745 /* Whack encoding from encoding in the key */
746 brace
= strchr (k
, '[');
748 p
= strchr (brace
, '.');
758 if (cur_section
== NULL
) {
759 /* only add to list if we haven't seen it before */
760 if (g_hash_table_lookup (item
->main_hash
, k
) == NULL
) {
761 item
->keys
= g_list_prepend (item
->keys
,
764 /* later duplicates override earlier ones */
765 g_hash_table_replace (item
->main_hash
, k
, val
);
767 char *full
= g_strdup_printf
769 cur_section
->name
, k
);
770 /* only add to list if we haven't seen it before */
771 if (g_hash_table_lookup (item
->main_hash
, full
) == NULL
) {
773 g_list_prepend (cur_section
->keys
, k
);
775 /* later duplicates override earlier ones */
776 g_hash_table_replace (item
->main_hash
,
782 lookup (const PurpleDesktopItem
*item
, const char *key
)
784 return g_hash_table_lookup (item
->main_hash
, key
);
788 setup_type (PurpleDesktopItem
*item
, const char *uri
)
790 const char *type
= g_hash_table_lookup (item
->main_hash
,
791 PURPLE_DESKTOP_ITEM_TYPE
);
792 if (type
== NULL
&& uri
!= NULL
) {
793 char *base
= g_path_get_basename (uri
);
794 if (purple_strequal(base
, ".directory")) {
795 /* This gotta be a directory */
796 g_hash_table_replace (item
->main_hash
,
797 g_strdup (PURPLE_DESKTOP_ITEM_TYPE
),
798 g_strdup ("Directory"));
799 item
->keys
= g_list_prepend
800 (item
->keys
, g_strdup (PURPLE_DESKTOP_ITEM_TYPE
));
801 item
->type
= PURPLE_DESKTOP_ITEM_TYPE_DIRECTORY
;
803 item
->type
= PURPLE_DESKTOP_ITEM_TYPE_NULL
;
807 item
->type
= type_from_string (type
);
812 lookup_locale (const PurpleDesktopItem
*item
, const char *key
, const char *locale
)
814 if (locale
== NULL
||
815 purple_strequal (locale
, "C")) {
816 return lookup (item
, key
);
819 char *full
= g_strdup_printf ("%s[%s]", key
, locale
);
820 ret
= lookup (item
, full
);
827 * Fallback to find something suitable for C locale.
829 * @return A newly allocated string which should be g_freed by the caller.
832 try_english_key (PurpleDesktopItem
*item
, const char *key
)
835 char *locales
[] = { "en_US", "en_GB", "en_AU", "en", NULL
};
838 for (i
= 0; locales
[i
] != NULL
&& str
== NULL
; i
++) {
839 str
= g_strdup (lookup_locale (item
, key
, locales
[i
]));
842 /* We need a 7-bit ascii string, so whack all
845 for (p
= (guchar
*)str
; *p
!= '\0'; p
++) {
855 sanitize (PurpleDesktopItem
*item
, const char *uri
)
859 type
= lookup (item
, PURPLE_DESKTOP_ITEM_TYPE
);
861 /* understand old gnome style url exec thingies */
862 if (purple_strequal(type
, "URL")) {
863 const char *exec
= lookup (item
, PURPLE_DESKTOP_ITEM_EXEC
);
864 set (item
, PURPLE_DESKTOP_ITEM_TYPE
, "Link");
866 /* Note, this must be in this order */
867 set (item
, PURPLE_DESKTOP_ITEM_URL
, exec
);
868 set (item
, PURPLE_DESKTOP_ITEM_EXEC
, NULL
);
872 /* we make sure we have Name, Encoding and Version */
873 if (lookup (item
, PURPLE_DESKTOP_ITEM_NAME
) == NULL
) {
874 char *name
= try_english_key (item
, PURPLE_DESKTOP_ITEM_NAME
);
875 /* If no name, use the basename */
876 if (name
== NULL
&& uri
!= NULL
)
877 name
= g_path_get_basename (uri
);
878 /* If no uri either, use same default as gnome_desktop_item_new */
880 name
= g_strdup (_("No name"));
881 g_hash_table_replace (item
->main_hash
,
882 g_strdup (PURPLE_DESKTOP_ITEM_NAME
),
884 item
->keys
= g_list_prepend
885 (item
->keys
, g_strdup (PURPLE_DESKTOP_ITEM_NAME
));
887 if (lookup (item
, PURPLE_DESKTOP_ITEM_ENCODING
) == NULL
) {
888 /* We store everything in UTF-8 so write that down */
889 g_hash_table_replace (item
->main_hash
,
890 g_strdup (PURPLE_DESKTOP_ITEM_ENCODING
),
892 item
->keys
= g_list_prepend
893 (item
->keys
, g_strdup (PURPLE_DESKTOP_ITEM_ENCODING
));
895 if (lookup (item
, PURPLE_DESKTOP_ITEM_VERSION
) == NULL
) {
896 /* this is the version that we follow, so write it down */
897 g_hash_table_replace (item
->main_hash
,
898 g_strdup (PURPLE_DESKTOP_ITEM_VERSION
),
900 item
->keys
= g_list_prepend
901 (item
->keys
, g_strdup (PURPLE_DESKTOP_ITEM_VERSION
));
915 static PurpleDesktopItem
*
916 ditem_load (FILE *df
,
917 gboolean no_translations
,
921 char CharBuffer
[1024];
922 char *next
= CharBuffer
;
925 PurpleDesktopItem
*item
;
926 Section
*cur_section
= NULL
;
928 gboolean old_kde
= FALSE
;
930 encoding
= get_encoding (df
);
931 if (encoding
== ENCODING_UNKNOWN
) {
933 /* spec says, don't read this file */
934 printf ("Unknown encoding of .desktop file");
939 /* Rewind since get_encoding goes through the file */
940 if (fseek(df
, 0L, SEEK_SET
)) {
942 /* spec says, don't read this file */
943 printf ("fseek() error on .desktop file");
947 item
= _purple_desktop_item_new ();
948 item
->modified
= FALSE
;
950 /* Note: location and mtime are filled in by the new_from_file
951 * function since it has those values */
953 #define PURPLE_DESKTOP_ITEM_OVERFLOW (next == &CharBuffer [sizeof(CharBuffer)-1])
956 while ((c
= getc (df
)) != EOF
) {
957 if (c
== '\r') /* Ignore Carriage Return */
963 if (c
== ']' || PURPLE_DESKTOP_ITEM_OVERFLOW
) {
967 /* keys were inserted in reverse */
968 if (cur_section
!= NULL
&&
969 cur_section
->keys
!= NULL
) {
970 cur_section
->keys
= g_list_reverse
973 if (purple_strequal (CharBuffer
, "KDE Desktop Entry")) {
977 } else if (purple_strequal(CharBuffer
, "Desktop Entry")) {
981 cur_section
= g_new0 (Section
, 1);
983 g_strdup (CharBuffer
);
984 cur_section
->keys
= NULL
;
985 item
->sections
= g_list_prepend
986 (item
->sections
, cur_section
);
989 } else if (c
== '[') {
990 /* FIXME: probably error out instead of ignoring this */
997 case IgnoreToEOLFirst
:
999 if (state
== IgnoreToEOLFirst
)
1011 if (state
== FirstBrace
)
1012 state
= IgnoreToEOLFirst
;
1014 state
= IgnoreToEOL
;
1018 if (c
== '[' && state
!= KeyDefOnKey
){
1019 state
= OnSecHeader
;
1025 /* On first pass, don't allow dangling keys */
1026 if (state
== FirstBrace
)
1029 if ((c
== ' ' && state
!= KeyDefOnKey
) || c
== '\t')
1032 if (c
== '\n' || PURPLE_DESKTOP_ITEM_OVERFLOW
) { /* Abort Definition */
1038 if (c
== '=' || PURPLE_DESKTOP_ITEM_OVERFLOW
){
1042 key
= g_strdup (CharBuffer
);
1047 state
= KeyDefOnKey
;
1052 if (PURPLE_DESKTOP_ITEM_OVERFLOW
|| c
== '\n'){
1055 insert_key (item
, cur_section
, encoding
,
1056 key
, CharBuffer
, old_kde
,
1062 state
= (c
== '\n') ? KeyDef
: IgnoreToEOL
;
1071 } /* while ((c = getc_unlocked (f)) != EOF) */
1072 if (c
== EOF
&& state
== KeyValue
) {
1075 insert_key (item
, cur_section
, encoding
,
1076 key
, CharBuffer
, old_kde
,
1083 #undef PURPLE_DESKTOP_ITEM_OVERFLOW
1085 /* keys were inserted in reverse */
1086 if (cur_section
!= NULL
&&
1087 cur_section
->keys
!= NULL
) {
1088 cur_section
->keys
= g_list_reverse (cur_section
->keys
);
1090 /* keys were inserted in reverse */
1091 item
->keys
= g_list_reverse (item
->keys
);
1092 /* sections were inserted in reverse */
1093 item
->sections
= g_list_reverse (item
->sections
);
1095 /* sanitize some things */
1096 sanitize (item
, uri
);
1098 /* make sure that we set up the type */
1099 setup_type (item
, uri
);
1107 copy_string_hash (gpointer key
, gpointer value
, gpointer user_data
)
1109 GHashTable
*copy
= user_data
;
1110 g_hash_table_replace (copy
,
1116 free_section (gpointer data
, gpointer user_data
)
1118 Section
*section
= data
;
1120 g_free (section
->name
);
1121 section
->name
= NULL
;
1123 g_list_foreach (section
->keys
, (GFunc
)g_free
, NULL
);
1124 g_list_free (section
->keys
);
1125 section
->keys
= NULL
;
1131 dup_section (Section
*sec
)
1134 Section
*retval
= g_new0 (Section
, 1);
1136 retval
->name
= g_strdup (sec
->name
);
1138 retval
->keys
= g_list_copy (sec
->keys
);
1139 for (li
= retval
->keys
; li
!= NULL
; li
= li
->next
)
1140 li
->data
= g_strdup (li
->data
);
1145 /**************************************************************************
1147 **************************************************************************/
1149 purple_desktop_item_new_from_file (const char *filename
)
1151 PurpleDesktopItem
*retval
;
1154 g_return_val_if_fail (filename
!= NULL
, NULL
);
1156 dfile
= g_fopen(filename
, "r");
1158 printf ("Can't open %s: %s", filename
, g_strerror(errno
));
1162 retval
= ditem_load(dfile
, FALSE
, filename
);
1167 PurpleDesktopItemType
1168 purple_desktop_item_get_entry_type (const PurpleDesktopItem
*item
)
1170 g_return_val_if_fail (item
!= NULL
, 0);
1171 g_return_val_if_fail (item
->refcount
> 0, 0);
1177 purple_desktop_item_get_string (const PurpleDesktopItem
*item
,
1180 g_return_val_if_fail (item
!= NULL
, NULL
);
1181 g_return_val_if_fail (item
->refcount
> 0, NULL
);
1182 g_return_val_if_fail (attr
!= NULL
, NULL
);
1184 return lookup (item
, attr
);
1188 purple_desktop_item_copy (const PurpleDesktopItem
*item
)
1191 PurpleDesktopItem
*retval
;
1193 g_return_val_if_fail (item
!= NULL
, NULL
);
1194 g_return_val_if_fail (item
->refcount
> 0, NULL
);
1196 retval
= _purple_desktop_item_new ();
1198 retval
->type
= item
->type
;
1199 retval
->modified
= item
->modified
;
1200 retval
->location
= g_strdup (item
->location
);
1201 retval
->mtime
= item
->mtime
;
1204 retval
->languages
= g_list_copy (item
->languages
);
1205 for (li
= retval
->languages
; li
!= NULL
; li
= li
->next
)
1206 li
->data
= g_strdup (li
->data
);
1209 retval
->keys
= g_list_copy (item
->keys
);
1210 for (li
= retval
->keys
; li
!= NULL
; li
= li
->next
)
1211 li
->data
= g_strdup (li
->data
);
1214 retval
->sections
= g_list_copy (item
->sections
);
1215 for (li
= retval
->sections
; li
!= NULL
; li
= li
->next
)
1216 li
->data
= dup_section (li
->data
);
1218 retval
->main_hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
1219 (GDestroyNotify
) g_free
,
1220 (GDestroyNotify
) g_free
);
1222 g_hash_table_foreach (item
->main_hash
,
1230 purple_desktop_item_unref (PurpleDesktopItem
*item
)
1232 g_return_if_fail (item
!= NULL
);
1233 g_return_if_fail (item
->refcount
> 0);
1237 if(item
->refcount
!= 0)
1240 g_list_foreach (item
->languages
, (GFunc
)g_free
, NULL
);
1241 g_list_free (item
->languages
);
1242 item
->languages
= NULL
;
1244 g_list_foreach (item
->keys
, (GFunc
)g_free
, NULL
);
1245 g_list_free (item
->keys
);
1248 g_list_foreach (item
->sections
, free_section
, NULL
);
1249 g_list_free (item
->sections
);
1250 item
->sections
= NULL
;
1252 g_hash_table_destroy (item
->main_hash
);
1253 item
->main_hash
= NULL
;
1255 g_free (item
->location
);
1256 item
->location
= NULL
;
1262 purple_desktop_item_get_type (void)
1264 static GType type
= 0;
1267 type
= g_boxed_type_register_static ("PurpleDesktopItem",
1268 _purple_desktop_item_copy
,
1269 _purple_desktop_item_free
);