source: trunk/third/gnome-vfs/libgnomevfs/gnome-vfs-application-registry.c @ 17128

Revision 17128, 45.5 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17127, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3/* gnome-vfs-mime-info.c - GNOME mime-information implementation.
4
5   Copyright (C) 1998 Miguel de Icaza
6   Copyright (C) 2000 Eazel, Inc
7   All rights reserved.
8
9   The Gnome Library is free software; you can redistribute it and/or
10   modify it under the terms of the GNU Library General Public License as
11   published by the Free Software Foundation; either version 2 of the
12   License, or (at your option) any later version.
13
14   The Gnome Library is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   Library General Public License for more details.
18
19   You should have received a copy of the GNU Library General Public
20   License along with the Gnome Library; see the file COPYING.LIB.  If not,
21   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22   Boston, MA 02111-1307, USA.  */
23/*
24 * Authors: George Lebl
25 *      Based on original mime-info database code by Miguel de Icaza
26 */
27
28#include "config.h"
29#include "gnome-vfs-application-registry.h"
30
31#include "gnome-vfs-mime-handlers.h"
32#include "gnome-vfs-mime-private.h"
33#include "gnome-vfs-mime.h"
34#include "gnome-vfs-private.h"
35#include "gnome-vfs-result.h"
36#include <ctype.h>
37#include <dirent.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <glib.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <string.h>
45#include <sys/stat.h>
46#include <sys/time.h>
47#include <sys/types.h>
48#include <time.h>
49#include <unistd.h>
50
51#if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
52# define getc_unlocked(fp) getc (fp)
53#endif
54
55typedef struct _Application Application;
56struct _Application {
57        char       *app_id;
58        int         ref_count;
59        /* The following is true if this was found in the
60         * home directory or if the user changed any keys
61         * here.  It means that it will be saved into a user
62         * file */
63        gboolean    user_owned;
64        GHashTable *keys;
65        GnomeVFSMimeApplicationArgumentType expects_uris;
66        GList      *mime_types;
67        GList      *supported_uri_schemes;
68        /* The user_owned version of this if this is a system
69         * version */
70        Application *user_application;
71};
72
73/* Describes the directories we scan for information */
74typedef struct {
75        char *dirname;
76        unsigned int valid : 1;
77        unsigned int system_dir : 1;
78} ApplicationRegistryDir;
79
80/* These ones are used to automatically reload mime info on demand */
81static FileDateTracker *registry_date_tracker;
82static ApplicationRegistryDir gnome_registry_dir;
83static ApplicationRegistryDir user_registry_dir;
84
85/* To initialize the module automatically */
86static gboolean gnome_vfs_application_registry_initialized = FALSE;
87
88
89static GList *current_lang = NULL;
90/* we want to replace the previous key if the current key has a higher
91   language level */
92static char *previous_key = NULL;
93static int previous_key_lang_level = -1;
94
95/*
96 * A hash table containing application registry record (Application)
97 * keyed by application ids.
98 */
99static GHashTable *global_applications = NULL;
100/*
101 * A hash table containing GList's of application registry records (Application)
102 * keyed by the mime types
103 */
104/* specific mime_types (e.g. image/png) */
105static GHashTable *specific_mime_types = NULL;
106/* generic mime_types (e.g. image/<star>) */
107static GHashTable *generic_mime_types = NULL;
108
109/*
110 * Dirty flag, just to make sure we don't sync needlessly
111 */
112static gboolean user_file_dirty = FALSE;
113
114/*
115 * Some local prototypes
116 */
117static void gnome_vfs_application_registry_init (void);
118static void application_clear_mime_types (Application *application);
119
120static Application *
121application_ref (Application *application)
122{
123        g_return_val_if_fail(application != NULL, NULL);
124
125        application->ref_count ++;
126
127        return application;
128}
129
130static void
131hash_foreach_free_key_value(gpointer key, gpointer value, gpointer user_data)
132{
133        g_free(key);
134        g_free(value);
135}
136
137static void
138application_unref (Application *application)
139{
140        g_return_if_fail(application != NULL);
141
142        application->ref_count --;
143
144        if (application->ref_count == 0) {
145                application_clear_mime_types (application);
146
147                if (application->keys != NULL) {
148                        g_hash_table_foreach(application->keys, hash_foreach_free_key_value, NULL);
149                        g_hash_table_destroy(application->keys);
150                        application->keys = NULL;
151                }
152
153                g_free(application->app_id);
154                application->app_id = NULL;
155
156                if (application->user_application != NULL) {
157                        application_unref (application->user_application);
158                        application->user_application = NULL;
159                }
160
161                g_free(application);
162        }
163}
164
165static Application *
166application_new (const char *app_id, gboolean user_owned)
167{
168        Application *application;
169
170        application = g_new0 (Application, 1);
171        application->app_id = g_strdup(app_id);
172        application->ref_count = 1;
173        application->expects_uris = GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_PATHS;
174        application->user_owned = user_owned;
175
176        return application;
177}
178
179static Application *
180application_lookup_or_create (const char *app_id, gboolean user_owned)
181{
182        Application *application;
183
184        g_return_val_if_fail(app_id != NULL, NULL);
185
186        application = g_hash_table_lookup (global_applications, app_id);
187        if (application != NULL) {
188                if ( ! user_owned) {
189                        /* if we find only a user app, do magic */
190                        if (application->user_owned) {
191                                Application *new_application;
192                                new_application = application_new (app_id, FALSE/*user_owned*/);
193                                new_application->user_application = application;
194                                /* override the user application */
195                                g_hash_table_insert (global_applications, new_application->app_id,
196                                                     new_application);
197                                return new_application;
198                        } else {
199                                return application;
200                        }
201                } else {
202                        if (application->user_owned) {
203                                return application;
204                        } if (application->user_application != NULL) {
205                                return application->user_application;
206                        } else {
207                                Application *new_application;
208                                new_application = application_new (app_id, TRUE/*user_owned*/);
209                                application->user_application = new_application;
210                                return new_application;
211                        }
212                }
213        }
214
215        application = application_new (app_id, user_owned);
216
217        g_hash_table_insert (global_applications, application->app_id, application);
218
219        return application;
220}
221
222static Application *
223application_lookup (const char *app_id)
224{
225        g_return_val_if_fail(app_id != NULL, NULL);
226
227        if (global_applications == NULL)
228                return NULL;
229
230        return g_hash_table_lookup (global_applications, app_id);
231}
232
233static const char *
234peek_value (const Application *application, const char *key)
235{
236        g_return_val_if_fail(application != NULL, NULL);
237        g_return_val_if_fail(key != NULL, NULL);
238
239        if (application->keys == NULL)
240                return NULL;
241
242        return g_hash_table_lookup (application->keys, key);
243}
244
245static void
246set_value (Application *application, const char *key, const char *value)
247{
248        char *old_value, *old_key;
249
250        g_return_if_fail(application != NULL);
251        g_return_if_fail(key != NULL);
252        g_return_if_fail(value != NULL);
253
254        if (application->keys == NULL)
255                application->keys = g_hash_table_new (g_str_hash, g_str_equal);
256
257        if (g_hash_table_lookup_extended (application->keys, key,
258                                          (gpointer *)&old_key,
259                                          (gpointer *)&old_value)) {
260                g_hash_table_insert (application->keys,
261                                     old_key, g_strdup (value));
262                g_free (old_value);
263        } else {
264                g_hash_table_insert (application->keys,
265                                     g_strdup (key), g_strdup (value));
266        }
267}
268
269static void
270unset_key (Application *application, const char *key)
271{
272        char *old_value, *old_key;
273
274        g_return_if_fail(application != NULL);
275        g_return_if_fail(key != NULL);
276
277        if (application->keys == NULL)
278                return;
279
280        if (g_hash_table_lookup_extended (application->keys, key,
281                                          (gpointer *)&old_key,
282                                          (gpointer *)&old_value)) {
283                g_hash_table_remove (application->keys, old_key);
284                g_free (old_key);
285                g_free (old_value);
286        }
287}
288
289static gboolean
290value_looks_true (const char *value)
291{
292        if (value &&
293            (value[0] == 'T' ||
294             value[0] == 't' ||
295             value[0] == 'Y' ||
296             value[0] == 'y' ||
297             atoi (value) != 0)) {
298                return TRUE;
299        } else {
300                return FALSE;
301        }
302}
303
304static gboolean
305get_bool_value (const Application *application, const char *key,
306                gboolean *got_key)
307{
308        const char *value = peek_value (application, key);
309        if (got_key) {
310                if (value != NULL)
311                        *got_key = TRUE;
312                else
313                        *got_key = FALSE;
314        }
315        return value_looks_true (value);
316
317}
318
319static void
320set_bool_value (Application *application, const char *key,
321                gboolean value)
322{
323        set_value (application, key, value ? "true" : "false");
324}
325
326static int
327application_compare (Application *application1,
328                     Application *application2)
329{
330        return strcmp (application1->app_id, application2->app_id);
331}
332
333static void
334add_application_to_mime_type_table (Application *application,
335                                    const char *mime_type)
336{
337        GList *application_list;
338        GHashTable *table;
339        char *old_key;
340
341        if (gnome_vfs_mime_type_is_supertype (mime_type))
342                table = generic_mime_types;
343        else
344                table = specific_mime_types;
345       
346        g_assert (table != NULL);
347
348        if (g_hash_table_lookup_extended (table, mime_type,
349                                          (gpointer *)&old_key,
350                                          (gpointer *)&application_list)) {
351                /* Sorted order is important as we can then easily
352                 * uniquify the results */
353                application_list = g_list_insert_sorted
354                        (application_list,
355                         application_ref (application),
356                         (GCompareFunc) application_compare);
357                g_hash_table_insert (table, old_key, application_list);
358        } else {
359                application_list = g_list_prepend (NULL,
360                                                   application_ref (application));
361                g_hash_table_insert (table, g_strdup (mime_type), application_list);
362        }
363}
364
365static void
366add_mime_type_to_application (Application *application, const char *mime_type)
367{
368        /* if this exists already, just return */
369        if (g_list_find_custom (application->mime_types,
370                                /*glib is const incorrect*/(gpointer)mime_type,
371                                (GCompareFunc) strcmp) != NULL)
372                return;
373       
374        application->mime_types =
375                g_list_prepend (application->mime_types,
376                                g_strdup (mime_type));
377       
378        add_application_to_mime_type_table (application, mime_type);
379
380}
381
382static void
383add_supported_uri_scheme_to_application (Application *application,
384                                         const char *supported_uri_scheme)
385{
386        if (g_list_find_custom (application->supported_uri_schemes,
387                                /*glib is const incorrect*/(gpointer) supported_uri_scheme,
388                                (GCompareFunc) strcmp) != NULL) {
389                return;
390        }
391       
392        application->supported_uri_schemes =
393                g_list_prepend (application->supported_uri_schemes,
394                                g_strdup (supported_uri_scheme));
395
396}
397
398static GList *
399supported_uri_scheme_list_copy (GList *supported_uri_schemes)
400{
401        GList *copied_list, *node;
402
403        copied_list = NULL;
404        for (node = supported_uri_schemes; node != NULL;
405             node = node->next) {
406                copied_list = g_list_prepend (copied_list,
407                                              g_strdup ((char *) node->data));
408        }
409
410        return copied_list;
411}
412
413static void
414remove_application_from_mime_type_table (Application *application,
415                                         const char *mime_type)
416{
417        GHashTable *table;
418        char *old_key;
419        GList *application_list, *entry;
420
421        if (gnome_vfs_mime_type_is_supertype (mime_type))
422                table = generic_mime_types;
423        else
424                table = specific_mime_types;
425
426        g_assert (table != NULL);
427
428        if (g_hash_table_lookup_extended (table, mime_type,
429                                          (gpointer *)&old_key,
430                                          (gpointer *)&application_list)) {
431                entry = g_list_find (application_list, application);
432
433                /* if this fails we're in deep doodoo I guess */
434                g_assert (entry != NULL);
435
436                application_list = g_list_remove_link (application_list, entry);
437                entry->data = NULL;
438                application_unref (application);
439
440                if (application_list != NULL) {
441                        g_hash_table_insert (table, old_key, application_list);
442                } else {
443                        g_hash_table_remove (table, old_key);
444                        g_free(old_key);
445                }
446        } else
447                g_assert_not_reached ();
448}
449
450static void
451remove_mime_type_for_application (Application *application, const char *mime_type)
452{
453        GList *entry;
454
455        g_return_if_fail(application != NULL);
456        g_return_if_fail(mime_type != NULL);
457
458        entry = g_list_find_custom
459                (application->mime_types,
460                 /*glib is const incorrect*/(gpointer)mime_type,
461                 (GCompareFunc) strcmp);
462
463        /* if this doesn't exist, just return */
464        if (entry == NULL) {
465                return;
466        }
467
468        remove_application_from_mime_type_table (application, mime_type);
469
470        /* Free data last, in case caller passed in mime_type string
471         * that was stored in this table.
472         */
473        application->mime_types =
474                g_list_remove_link (application->mime_types, entry);
475        g_free (entry->data);
476        g_list_free_1 (entry); 
477}
478
479
480static void
481application_clear_mime_types (Application *application)
482{
483        g_return_if_fail (application != NULL);
484
485        while (application->mime_types)
486                remove_mime_type_for_application (application, application->mime_types->data);
487}
488
489static void
490application_remove (Application *application)
491{
492        Application *main_application;
493
494        g_return_if_fail (application != NULL);
495
496        if (global_applications == NULL) {
497                return;
498        }
499
500        main_application = application_lookup (application->app_id);
501        if (main_application == NULL) {
502                return;
503        }
504
505        /* We make sure the mime types are killed even if the application
506         * entry lives after unreffing it */
507        application_clear_mime_types (application);
508
509        if (main_application == application) {
510                if (application->user_application)
511                        application_clear_mime_types (application->user_application);
512
513                g_hash_table_remove (global_applications, application->app_id);
514        } else {
515                /* This must be a user application */
516                g_assert (main_application->user_application == application);
517
518                main_application->user_application = NULL;
519        }
520
521        application_unref (application);
522
523}
524
525static void
526sync_key (gpointer key, gpointer value, gpointer user_data)
527{
528        char *key_string = key;
529        char *value_string = value;
530        FILE *fp = user_data;
531
532        fprintf (fp, "\t%s=%s\n", key_string, value_string);
533}
534
535/* write an application to a file */
536static void
537application_sync (Application *application, FILE *fp)
538{
539        GList *li;
540
541        g_return_if_fail (application != NULL);
542        g_return_if_fail (fp != NULL);
543
544        fprintf (fp, "%s\n", application->app_id);
545
546        if (application->keys != NULL)
547                g_hash_table_foreach (application->keys, sync_key, fp);
548
549        if (application->mime_types != NULL) {
550                char *separator;
551                fprintf (fp, "\tmime_types=");
552                separator = "";
553                for (li = application->mime_types; li != NULL; li = li->next) {
554                        char *mime_type = li->data;
555                        fprintf (fp, "%s%s", separator, mime_type);
556                        separator = ",";
557                }
558                fprintf (fp, "\n");
559        }
560        fprintf (fp, "\n");
561}
562
563
564/* this gives us a number of the language in the current language list,
565   the higher the number the "better" the translation */
566static int
567language_level (const char *lang)
568{
569        int i;
570        GList *li;
571
572        if (lang == NULL)
573                return 0;
574
575        for (i = 1, li = current_lang; li != NULL; i++, li = g_list_next (li)) {
576                if (strcmp ((const char *) li->data, lang) == 0)
577                        return i;
578        }
579
580        return -1;
581}
582
583
584static void
585application_add_key (Application *application, const char *key,
586                     const char *lang, const char *value)
587{
588        int lang_level;
589
590        g_return_if_fail (application != NULL);
591        g_return_if_fail (key != NULL);
592        g_return_if_fail (value != NULL);
593
594        if (strcmp (key, "mime_types") == 0 ||
595            strcmp (key, "supported_uri_schemes") == 0) {
596                char *value_copy = g_strdup (value);
597                char *next_value;
598                /* FIXME: There used to be a check here for
599                   the value of "lang", but spamming
600                   the terminal about it is not really
601                   the right way to deal with that, nor
602                   is "MIME Types can't have languages, bad!"
603                   which is what was here before */
604                next_value = strtok (value_copy, ", \t");
605                while (next_value != NULL) {
606                        if (strcmp (key, "mime_types") == 0) {
607                                add_mime_type_to_application (application, next_value);
608                        }
609                        else {
610                                add_supported_uri_scheme_to_application (application, next_value);
611                        }
612                        next_value = strtok (NULL, ", \t");
613                }
614                g_free(value_copy);
615                return;           
616        }
617        else if (strcmp (key, "expects_uris") == 0) {
618                if (strcmp (value, "non-file") == 0) {
619                        application->expects_uris = GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS_FOR_NON_FILES;
620                }
621                else if (value_looks_true (value)) {
622                        application->expects_uris = GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS;
623                }
624                else {
625                        application->expects_uris = GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_PATHS;
626                }
627        }
628
629        lang_level = language_level (lang);
630        /* wrong language completely */
631        if (lang_level < 0)
632                return;
633
634        /* if we have some language defined and
635           if there was a previous_key */
636        if (lang_level > 0 &&
637            previous_key &&
638            /* our language level really sucks and the previous
639               translation was of better language quality so just
640               ignore us */
641            previous_key_lang_level > lang_level) {
642                return;
643        }
644
645        set_value (application, key, value);
646
647        /* set this as the previous key */
648        g_free(previous_key);
649        previous_key = g_strdup(key);
650        previous_key_lang_level = lang_level;
651}
652
653typedef enum {
654        STATE_NONE,
655        STATE_LANG,
656        STATE_LOOKING_FOR_KEY,
657        STATE_ON_APPLICATION,
658        STATE_ON_KEY,
659        STATE_ON_VALUE
660} ParserState;
661
662/**
663 * strip_trailing_whitespace
664 *
665 * string
666 *
667 * strips the white space from a string.
668 *
669 */
670
671static void
672strip_trailing_whitespace (GString *string)
673{
674        int i;
675
676        for (i = string->len - 1; i >= 0; i--) {
677                if (!isspace ((guchar) string->str[i]))
678                        break;
679        }
680
681        g_string_truncate (string, i + 1);
682}
683
684/**
685 * load_application_info_from
686 *
687 * filename:  Target filename to application info from.
688 * user_owned: if application is user owned or not.
689 *
690 * This function will load application info from a file and parse through the
691 * application loading the registry with the information contained in the file.
692 *
693 *
694 **/
695
696static void
697load_application_info_from (const char *filename, gboolean user_owned)
698{
699        FILE *fp;
700        gboolean in_comment, app_used;
701        GString *line;
702        int column, c;
703        ParserState state;
704        Application *application;
705        char *key;
706        char *lang;
707       
708        fp = fopen (filename, "r");
709        if (fp == NULL)
710                return;
711
712        in_comment = FALSE;
713        app_used = FALSE;
714        column = -1;
715        application = NULL;
716        key = NULL;
717        lang = NULL;
718        line = g_string_sized_new (120);
719        state = STATE_NONE;
720       
721        while ((c = getc_unlocked (fp)) != EOF){
722                column++;
723                if (c == '\r')
724                        continue;
725
726                if (c == '#' && column == 0){           
727                        in_comment = TRUE;
728                        continue;
729                }
730               
731                if (c == '\n'){
732                        in_comment = FALSE;
733                        column = -1;
734                        if (state == STATE_ON_APPLICATION) {
735
736                                /* set previous key to nothing
737                                   for this mime type */
738                                g_free(previous_key);
739                                previous_key = NULL;
740                                previous_key_lang_level = -1;
741
742                                strip_trailing_whitespace (line);
743                                application = application_lookup_or_create (line->str, user_owned);
744                                app_used = FALSE;
745                                g_string_assign (line, "");
746                                state = STATE_LOOKING_FOR_KEY;
747                                continue;
748                        }
749                        if (state == STATE_ON_VALUE){
750                                app_used = TRUE;
751                                application_add_key (application, key, lang, line->str);
752                                g_string_assign (line, "");
753                                g_free (key);
754                                key = NULL;
755                                g_free (lang);
756                                lang = NULL;
757                                state = STATE_LOOKING_FOR_KEY;
758                                continue;
759                        }
760                        continue;
761                }
762
763                if (in_comment)
764                        continue;
765
766                switch (state){
767                case STATE_NONE:
768                        if (c != ' ' && c != '\t')
769                                state = STATE_ON_APPLICATION;
770                        else
771                                break;
772                        /* fall down */
773                       
774                case STATE_ON_APPLICATION:
775                        if (c == ':'){
776                                in_comment = TRUE;
777                                break;
778                        }
779                        g_string_append_c (line, c);
780                        break;
781
782                case STATE_LOOKING_FOR_KEY:
783                        if (c == '\t' || c == ' ')
784                                break;
785
786                        if (c == '['){
787                                state = STATE_LANG;
788                                break;
789                        }
790
791                        if (column == 0){
792                                state = STATE_ON_APPLICATION;
793                                g_string_append_c (line, c);
794                                break;
795                        }
796                        state = STATE_ON_KEY;
797                        /* falldown */
798
799                case STATE_ON_KEY:
800                        if (c == '\\'){
801                                c = getc (fp);
802                                if (c == EOF)
803                                        break;
804                        }
805                        if (c == '='){
806                                key = g_strdup (line->str);
807                                g_string_assign (line, "");
808                                state = STATE_ON_VALUE;
809                                break;
810                        }
811                        g_string_append_c (line, c);
812                        break;
813
814                case STATE_ON_VALUE:
815                        g_string_append_c (line, c);
816                        break;
817                       
818                case STATE_LANG:
819                        if (c == ']'){
820                                state = STATE_ON_KEY;     
821                                if (line->str [0]){
822                                        g_free(lang);
823                                        lang = g_strdup(line->str);
824                                } else {
825                                        in_comment = TRUE;
826                                        state = STATE_LOOKING_FOR_KEY;
827                                }
828                                g_string_assign (line, "");
829                                break;
830                        }
831                        g_string_append_c (line, c);
832                        break;
833                }
834        }
835
836        if (application){
837                if (key && line->str [0])
838                        application_add_key (application, key, lang, line->str);
839                else
840                        if ( ! app_used)
841                                application_remove (application);
842        }
843
844        g_string_free (line, TRUE);
845        g_free (key);
846        g_free (lang);
847
848        /* free the previous_key stuff */
849        g_free(previous_key);
850        previous_key = NULL;
851        previous_key_lang_level = -1;
852
853        fclose (fp);
854
855        gnome_vfs_file_date_tracker_start_tracking_file (registry_date_tracker, filename);
856}
857
858/**
859 * application_info_load:
860 *
861 * source:
862 *
863 *
864 */
865
866static void
867application_info_load (ApplicationRegistryDir *source)
868{
869        DIR *dir;
870        struct dirent *dent;
871        const int extlen = sizeof (".applications") - 1;
872        char *filename;
873        struct stat s;
874
875        if (stat (source->dirname, &s) != -1)
876                source->valid = TRUE;
877        else
878                source->valid = FALSE;
879       
880        dir = opendir (source->dirname);
881        if (dir == NULL) {
882                source->valid = FALSE;
883                return;
884        }
885        if (source->system_dir) {
886                filename = g_strconcat (source->dirname, "/gnome-vfs.applications", NULL);
887                load_application_info_from (filename, FALSE /*user_owned*/);
888                g_free (filename);
889        }
890
891        while ((dent = readdir (dir)) != NULL){
892               
893                int len = strlen (dent->d_name);
894
895                if (len <= extlen)
896                        continue;
897                if (strcmp (dent->d_name + len - extlen, ".applications"))
898                        continue;
899                if (source->system_dir && strcmp (dent->d_name, "gnome-vfs.applications") == 0)
900                        continue;
901                if ( ! source->system_dir && strcmp (dent->d_name, "user.applications") == 0)
902                        continue;
903                filename = g_strconcat (source->dirname, "/", dent->d_name, NULL);
904                load_application_info_from (filename, FALSE /*user_owned*/);
905                g_free (filename);
906        }
907
908        if ( ! source->system_dir) {
909                filename = g_strconcat (source->dirname, "/user.applications", NULL);
910                /* Currently this is the only file that is "user owned".  It actually makes
911                 * sense.  Editting of other files from the API would be too complex */
912                load_application_info_from (filename, TRUE /*user_owned*/);
913                g_free (filename);
914        }
915        closedir (dir);
916
917        gnome_vfs_file_date_tracker_start_tracking_file (registry_date_tracker, source->dirname);
918}
919
920/**
921 * load_application_info
922 *
923 * This function will load the registry for an application from disk.
924 **/
925
926static void
927load_application_info (void)
928{
929        application_info_load (&gnome_registry_dir);
930        application_info_load (&user_registry_dir);
931}
932
933/**
934 * gnome_vfs_application_registry_init
935 *
936 * This function initializes gnome-vfs's registry. 
937 **/
938
939static void
940gnome_vfs_application_registry_init (void)
941{
942        if (gnome_vfs_application_registry_initialized)
943                return;
944
945        registry_date_tracker = gnome_vfs_file_date_tracker_new ();
946
947        /*
948         * The hash tables that store the mime keys.
949         */
950        global_applications = g_hash_table_new (g_str_hash, g_str_equal);
951        generic_mime_types  = g_hash_table_new (g_str_hash, g_str_equal);
952        specific_mime_types  = g_hash_table_new (g_str_hash, g_str_equal);
953       
954        current_lang = gnome_vfs_i18n_get_language_list ("LC_MESSAGES");
955
956        /*
957         * Setup the descriptors for the information loading
958         */
959
960        gnome_registry_dir.dirname = g_strconcat (GNOME_VFS_DATADIR, "/application-registry", NULL);
961        gnome_registry_dir.system_dir = TRUE;
962       
963        user_registry_dir.dirname = g_strconcat (g_get_home_dir(), "/.gnome/application-info", NULL);
964        user_registry_dir.system_dir = FALSE;
965
966        /* Make sure user directory exists */
967        if (mkdir (user_registry_dir.dirname, 0700) &&
968            errno != EEXIST) {
969                g_warning("Could not create per-user Gnome application-registry directory: %s",
970                          user_registry_dir.dirname);
971        }
972
973        /*
974         * Load
975         */
976        load_application_info ();
977
978        gnome_vfs_application_registry_initialized = TRUE;
979}
980
981/*
982 * maybe_reload
983 *
984 * This function will initialize the registry in memory and then reloads the
985 *
986 */
987
988static void
989maybe_reload (void)
990{
991        gnome_vfs_application_registry_init ();
992
993        if (!gnome_vfs_file_date_tracker_date_has_changed (registry_date_tracker)) {
994                return;
995        }
996       
997        gnome_vfs_application_registry_reload ();
998}
999
1000/**
1001 * remove_apps
1002 *
1003 * key:
1004 * value:
1005 * user_data:
1006 *
1007 * FIXME: I need a clearer explanation on what this does.
1008 *
1009 */
1010
1011static gboolean
1012remove_apps (gpointer key, gpointer value, gpointer user_data)
1013{
1014        Application *application = value;
1015
1016        application_clear_mime_types (application);
1017
1018        application_unref (application);
1019       
1020        return TRUE;
1021}
1022
1023/**
1024 * gnome_vfs_application_registry_clear:
1025 *
1026 * This will wipe the registry clean removing everything from the registry.
1027 * This is different from gnome_vfs_application_registry_shutdown which will
1028 * actually delete the registry and leave it in an uninitialized state.
1029 *
1030 */
1031
1032static void
1033gnome_vfs_application_registry_clear (void)
1034{
1035        if (global_applications != NULL)
1036                g_hash_table_foreach_remove (global_applications, remove_apps, NULL);
1037}
1038
1039/**
1040 * gnome_vfs_application_registry_shutdown
1041 *
1042 * This will delete the global gnome-vfs registry.
1043 *
1044 **/
1045
1046void
1047gnome_vfs_application_registry_shutdown (void)
1048{
1049        gnome_vfs_application_registry_clear ();
1050
1051        if (global_applications != NULL) {
1052                g_hash_table_destroy (global_applications);
1053                global_applications = NULL;
1054        }
1055
1056        if(generic_mime_types != NULL) {
1057                g_hash_table_destroy (generic_mime_types);
1058                generic_mime_types = NULL;
1059        }
1060
1061        if(specific_mime_types != NULL) {
1062                g_hash_table_destroy (specific_mime_types);
1063                specific_mime_types = NULL;
1064        }
1065
1066        gnome_vfs_file_date_tracker_free (registry_date_tracker);
1067
1068        g_free(gnome_registry_dir.dirname);
1069        gnome_registry_dir.dirname = NULL;
1070        g_free(user_registry_dir.dirname);
1071        user_registry_dir.dirname = NULL;
1072
1073        g_list_free(current_lang);
1074        current_lang = NULL;
1075
1076        gnome_vfs_application_registry_initialized = FALSE;
1077}
1078
1079
1080/**
1081 * gnome_vfs_application_registry_reload:
1082 *
1083 * If this function is called for the first time it will initialize the
1084 * registry.  Subsequent calls to the function will clear out the current
1085 * registry contents and load registry contents from the save file.  Make
1086 * certain that you've saved your registry before calling this function.  It
1087 * will destroy unsaved changes.
1088 *
1089 */
1090
1091void
1092gnome_vfs_application_registry_reload (void)
1093{
1094        if ( ! gnome_vfs_application_registry_initialized) {
1095                /* If not initialized, initialization will do a "reload" */
1096                gnome_vfs_application_registry_init ();
1097        } else {
1098                gnome_vfs_application_registry_clear ();
1099                load_application_info ();
1100        }
1101}
1102
1103/*
1104 * Existance check
1105 */
1106
1107/**
1108 * gnome_vfs_application_registry_exists:
1109 *
1110 * This function will check, if given an application name, exists in the
1111 * registry.
1112 *
1113 * @app_id:  String containing the application name
1114 *
1115 * Returns: gboolean
1116 *
1117 **/
1118
1119gboolean
1120gnome_vfs_application_registry_exists (const char *app_id)
1121{
1122        g_return_val_if_fail (app_id != NULL, FALSE);
1123
1124        maybe_reload ();
1125
1126        if (application_lookup (app_id) != NULL)
1127                return TRUE;
1128        else
1129                return FALSE;
1130}
1131
1132
1133/*
1134 * Getting arbitrary keys
1135 */
1136
1137
1138/**
1139 * get_keys_foreach
1140 *
1141 * key:
1142 * user_data:
1143 *
1144 * FIXME: I have no idea what this function does.
1145 **/
1146
1147static void
1148get_keys_foreach(gpointer key, gpointer value, gpointer user_data)
1149{
1150        GList **listp = user_data;
1151
1152        /* make sure we only insert unique keys */
1153        if ( (*listp) && strcmp ((const char *) (*listp)->data, (const char *) key) == 0)
1154                return;
1155
1156        (*listp) = g_list_insert_sorted ((*listp), key,
1157                                         (GCompareFunc) strcmp);
1158}
1159
1160/**
1161 * gnome_vfs_application_registry_get_keys:
1162 *
1163 * @app_id: registry id of the application
1164 *
1165 * This function wil return a list of keys for an applicaton id from the
1166 * registry.
1167 *
1168 * Returns: GList
1169 **/
1170
1171GList *
1172gnome_vfs_application_registry_get_keys (const char *app_id)
1173{
1174        GList *retval;
1175        Application *application;
1176
1177        g_return_val_if_fail (app_id != NULL, NULL);
1178
1179        maybe_reload ();
1180
1181        application = application_lookup (app_id);
1182        if (application == NULL)
1183                return NULL;
1184
1185        retval = NULL;
1186
1187        if (application->keys != NULL)
1188                g_hash_table_foreach (application->keys, get_keys_foreach,
1189                                      &retval);
1190
1191        if (application->user_application != NULL &&
1192            application->user_application->keys)
1193                g_hash_table_foreach (application->user_application->keys,
1194                                      get_keys_foreach, &retval);
1195
1196        return retval;
1197}
1198
1199
1200/**
1201 * real_peek_value:
1202 *
1203 * @application: registry application
1204 * @key: target key
1205 *
1206 * This function looks and returns the value of the target key in the registry
1207 * application
1208 *
1209 * Returns: const char *
1210 **/
1211
1212static const char *
1213real_peek_value (const Application *application, const char *key)
1214{
1215        const char *retval;
1216
1217        g_return_val_if_fail (application != NULL, NULL);
1218        g_return_val_if_fail (key != NULL, NULL);
1219
1220        retval = NULL;
1221
1222        if (application->user_application)
1223                retval = peek_value (application->user_application, key);
1224
1225        if (retval == NULL)
1226                retval = peek_value (application, key);
1227
1228        return retval;
1229}
1230
1231/**
1232 * real_get_bool_value
1233 *
1234 * application:  Application structure
1235 * key: taget key
1236 * got_key: actual key stored in application if key exists.
1237 *
1238 * This function will try to determine whether a key exists in the application.
1239 * It first checks the user applications and then the system applications and
1240 * then returns whether the key exists and what the value is from the value of
1241 * got_key.
1242 *
1243 * Returns: gboolean
1244 **/
1245
1246static gboolean
1247real_get_bool_value (const Application *application, const char *key, gboolean *got_key)
1248{
1249        gboolean sub_got_key, retval;
1250
1251        g_return_val_if_fail (application != NULL, FALSE);
1252        g_return_val_if_fail (key != NULL, FALSE);
1253
1254        sub_got_key = FALSE;
1255        retval = FALSE;
1256        if (application->user_application)
1257                retval = get_bool_value (application->user_application, key,
1258                                         &sub_got_key);
1259
1260        if ( ! sub_got_key)
1261                retval = get_bool_value (application, key, &sub_got_key);
1262
1263        if (got_key != NULL)
1264                *got_key = sub_got_key;
1265
1266        return retval;
1267}
1268
1269/**
1270 * gnome_vfs_application_registry_peek_value:
1271 *
1272 * @app_id: registry id of the application
1273 * @key: key we want to look up.
1274 *
1275 * This will return the value of the key in registry pointed to by app_id.
1276 *
1277 * Returns: a string (const char *)
1278 *
1279 **/
1280
1281const char *
1282gnome_vfs_application_registry_peek_value (const char *app_id, const char *key)
1283{
1284        Application *application;
1285
1286        g_return_val_if_fail (app_id != NULL, NULL);
1287        g_return_val_if_fail (key != NULL, NULL);
1288
1289        maybe_reload ();
1290
1291        application = application_lookup (app_id);
1292        if (application == NULL)
1293                return NULL;
1294
1295        return real_peek_value (application, key);
1296}
1297
1298/**
1299 * gnome_vfs_application_registry_get_bool_value:
1300 *
1301 * @app_id:  registry id of the application
1302 * @key: key to look up
1303 * @got_key: key you have
1304 *
1305 * This will look up a key in the structure pointed to by app_id and return the
1306 * boolean value of that key.  It will return false if there are no
1307 * applications associated with the app_id.
1308 *
1309 * Returns: gboolean
1310 **/
1311
1312gboolean
1313gnome_vfs_application_registry_get_bool_value (const char *app_id, const char *key,
1314                                               gboolean *got_key)
1315{
1316        Application *application;
1317
1318        g_return_val_if_fail (app_id != NULL, FALSE);
1319        g_return_val_if_fail (key != NULL, FALSE);
1320
1321        maybe_reload ();
1322
1323        application = application_lookup (app_id);
1324        if (application == NULL)
1325                return FALSE;
1326
1327        return real_get_bool_value (application, key, got_key);
1328}
1329
1330/*
1331 * Setting stuff
1332 */
1333
1334/**
1335 * gnome_vfs_application_registry_remove_application:
1336 *
1337 * @app_id:  registry id of the application
1338 *
1339 * Given the registry id this function will remove all applications that has
1340 * been set by the user.  You will need to call
1341 * gnome_vfs_application_registry_sync to save the changes.
1342 *
1343 **/
1344
1345void
1346gnome_vfs_application_registry_remove_application (const char *app_id)
1347{
1348        Application *application;
1349
1350        g_return_if_fail (app_id != NULL);
1351
1352        maybe_reload ();
1353
1354        application = application_lookup (app_id);
1355        if (application == NULL)
1356                return;
1357
1358        /* Only remove the user_owned stuff */
1359        if (application->user_owned) {
1360                application_remove (application);
1361                user_file_dirty = TRUE;
1362        } else if (application->user_application != NULL) {
1363                application_remove (application->user_application);
1364                user_file_dirty = TRUE;
1365        }
1366}
1367
1368/**
1369 * gnome_vfs_application_registry_set_value:
1370 *
1371 * @app_id:  registry id of the application
1372 * @key: target key
1373 * @value: value to set the target key to
1374 *
1375 * This function will set values pertaining to registry entry pointed to by
1376 * app_id.  You will need to call gnome_vfs_application_registry_sync to
1377 * realize the changes.
1378 *
1379 **/
1380
1381void
1382gnome_vfs_application_registry_set_value (const char *app_id,
1383                                          const char *key,
1384                                          const char *value)
1385{
1386        Application *application;
1387
1388        g_return_if_fail (app_id != NULL);
1389        g_return_if_fail (key != NULL);
1390        g_return_if_fail (value != NULL);
1391
1392        maybe_reload ();
1393
1394        application = application_lookup_or_create (app_id, TRUE/*user_owned*/);
1395
1396        set_value (application, key, value);
1397
1398        user_file_dirty = TRUE;
1399}
1400
1401/**
1402 * gnome_vfs_application_registry_set_bool_value:
1403 *
1404 * @app_id:  registry id of the application
1405 * @key: target key
1406 * @value: value you want to set the target key to.
1407 *
1408 * This function will modify those registry values that are of type boolean to
1409 * a value specified by the user.  You will need to call
1410 * gnome_vfs_application_registry_sync to save your changes.
1411 *
1412 **/
1413
1414void
1415gnome_vfs_application_registry_set_bool_value (const char *app_id,
1416                                               const char *key,
1417                                               gboolean value)
1418{
1419        Application *application;
1420
1421        g_return_if_fail (app_id != NULL);
1422        g_return_if_fail (key != NULL);
1423
1424        maybe_reload ();
1425
1426        application = application_lookup_or_create (app_id, TRUE/*user_owned*/);
1427
1428        set_bool_value (application, key, value);
1429
1430        user_file_dirty = TRUE;
1431}
1432
1433/**
1434 * gnome_vfs_application_registry_unset_key:
1435 *
1436 * @app_id:  registry id of the application
1437 * @key:  search key
1438 *
1439 * This function given the application and the target will wipe the current
1440 * value that the key contains.
1441 *
1442 **/
1443
1444void
1445gnome_vfs_application_registry_unset_key (const char *app_id,
1446                                          const char *key)
1447{
1448        Application *application;
1449
1450        g_return_if_fail (app_id != NULL);
1451        g_return_if_fail (key != NULL);
1452
1453        maybe_reload ();
1454
1455        application = application_lookup_or_create (app_id, TRUE/*user_owned*/);
1456
1457        unset_key (application, key);
1458
1459        user_file_dirty = TRUE;
1460}
1461
1462/*
1463 * Query functions
1464 */
1465
1466
1467/**
1468 *
1469 * gnome_vfs_application_registry_get_applications:
1470 *
1471 * @mime_type:  mime type string
1472 *
1473 * This will return all applications from the registry that are associated with
1474 * the given mime type string.
1475 **/
1476
1477GList *
1478gnome_vfs_application_registry_get_applications (const char *mime_type)
1479{
1480        GList *app_list, *app_list2, *retval, *li;
1481        char *supertype;
1482
1483        g_return_val_if_fail (mime_type != NULL, NULL);
1484
1485        maybe_reload ();
1486
1487        app_list2 = NULL;
1488
1489        if (gnome_vfs_mime_type_is_supertype (mime_type)) {
1490                app_list = g_hash_table_lookup (generic_mime_types, mime_type);
1491        } else {
1492                app_list = g_hash_table_lookup (specific_mime_types, mime_type);
1493
1494                supertype = gnome_vfs_get_supertype_from_mime_type (mime_type);
1495                if (supertype != NULL) {
1496                        app_list2 = g_hash_table_lookup (generic_mime_types, supertype);
1497                        g_free (supertype);
1498                }
1499        }
1500
1501        retval = NULL;
1502        for (li = app_list; li != NULL; li = li->next) {
1503                Application *application = li->data;
1504                /* Note that this list is sorted so to kill duplicates
1505                 * in app_list we only need to check the first entry */
1506                if (retval == NULL ||
1507                    strcmp ((const char *) retval->data, application->app_id) != 0)
1508                        retval = g_list_prepend (retval, application->app_id);
1509        }
1510
1511        for (li = app_list2; li != NULL; li = li->next) {
1512                Application *application = li->data;
1513                if (g_list_find_custom (retval, application->app_id,
1514                                        (GCompareFunc) strcmp) == NULL)
1515                        retval = g_list_prepend (retval, application->app_id);
1516        }
1517
1518        return retval;
1519}
1520
1521/**
1522 *
1523 * gnome_vfs_application_registry_get_mime_types:
1524 *
1525 * @app_id: registry id of application
1526 *
1527 * This function returns a list of mime types that is associated with a
1528 * registry id.
1529 *
1530 * Returns: GList
1531 *
1532 **/
1533
1534GList *
1535gnome_vfs_application_registry_get_mime_types (const char *app_id)
1536{
1537        Application *application;
1538        GList *retval;
1539
1540        g_return_val_if_fail (app_id != NULL, NULL);
1541
1542        maybe_reload ();
1543
1544        application = application_lookup (app_id);
1545        if (application == NULL)
1546                return NULL;
1547
1548        retval = g_list_copy (application->mime_types);
1549
1550        /* merge in the mime types from the user_application,
1551         * if it exists */
1552        if (application->user_application) {
1553                GList *li;
1554                for (li = application->user_application->mime_types;
1555                     li != NULL;
1556                     li = li->next) {
1557                        Application *application = li->data;
1558                        if (g_list_find_custom (retval, application->app_id,
1559                                                (GCompareFunc) strcmp) == NULL)
1560                                retval = g_list_prepend (retval,
1561                                                         application->app_id);
1562                }
1563        }
1564
1565        return retval;
1566}
1567
1568/**
1569 * gnome_vfs_application_registry_supports_uri_scheme:
1570 *
1571 * @app_id: registry id of application
1572 * @uri_scheme: uri schme string
1573 *
1574 *  Given the id of the application this function will
1575 *  determine if the uri scheme will given is supported.
1576 *
1577 *  Returns: gboolean
1578 **/
1579
1580gboolean
1581gnome_vfs_application_registry_supports_uri_scheme (const char *app_id,
1582                                                    const char *uri_scheme)
1583{
1584        Application *application;
1585
1586        g_return_val_if_fail (app_id != NULL, FALSE);
1587        g_return_val_if_fail (uri_scheme != NULL, FALSE);
1588
1589        maybe_reload ();
1590
1591        application = application_lookup (app_id);
1592        if (application == NULL)
1593                return FALSE;
1594
1595        if (strcmp (uri_scheme, "file") == 0 &&
1596            application->supported_uri_schemes == NULL &&
1597            application->user_application->supported_uri_schemes == NULL) {
1598                return TRUE;
1599        }
1600
1601        /* check both the application and the user application
1602         * mime_types lists */
1603        /* FIXME: This method does not allow a user to override and remove
1604           uri schemes that an application can handle.  Is this an issue? */
1605
1606        if ((g_list_find_custom (application->supported_uri_schemes,
1607                                 /*glib is const incorrect*/(gpointer)uri_scheme,
1608                                (GCompareFunc) strcmp) != NULL) ||
1609            (application->user_application &&
1610             g_list_find_custom (application->user_application->supported_uri_schemes,
1611                                 /*glib is const incorrect*/(gpointer) uri_scheme,
1612                                 (GCompareFunc) strcmp) != NULL)) {
1613                return TRUE;
1614        }
1615
1616        return FALSE;
1617}
1618
1619/**
1620 * gnome_vfs_application_registry_supports_mime_type:
1621 *
1622 * @app_id: registry id of application
1623 * @mime_type: mime type string
1624 *
1625 * Use this function to see if there is an application associated with a given
1626 * mime type.  The function will return true or false.
1627 *
1628 * Returns: gboolean
1629 **/
1630
1631gboolean
1632gnome_vfs_application_registry_supports_mime_type (const char *app_id,
1633                                                   const char *mime_type)
1634{
1635        Application *application;
1636
1637        g_return_val_if_fail (app_id != NULL, FALSE);
1638        g_return_val_if_fail (mime_type != NULL, FALSE);
1639
1640        maybe_reload ();
1641
1642        application = application_lookup (app_id);
1643        if (application == NULL)
1644                return FALSE;
1645
1646        /* check both the application and the user application
1647         * mime_types lists */
1648        /* FIXME: This method does not allow a user to override and remove
1649           mime types that an application can handle.  Is this an issue? */
1650        if ((g_list_find_custom (application->mime_types,
1651                                 /*glib is const incorrect*/(gpointer)mime_type,
1652                                (GCompareFunc) strcmp) != NULL) ||
1653            (application->user_application &&
1654             g_list_find_custom (application->user_application->mime_types,
1655                                 /*glib is const incorrect*/(gpointer)mime_type,
1656                                 (GCompareFunc) strcmp) != NULL))
1657                return TRUE;
1658        else
1659                return FALSE;
1660}
1661
1662
1663/*
1664 * Mime type functions
1665 * Note that mime_type can be a specific (image/png) or generic (image/<star>) type
1666 */
1667
1668
1669/**
1670 * gnome_vfs_application_registry_clear_mime_types:
1671 * @app_id: Application id
1672 *
1673 * This function will remove the mime types associated with the application.
1674 * Changes are not realized until the  gnome_vfs_application_registry_sync
1675 * function is called to save the changes to the file.
1676 *
1677 **/
1678
1679void
1680gnome_vfs_application_registry_clear_mime_types (const char *app_id)
1681{
1682        Application *application;
1683
1684        g_return_if_fail (app_id != NULL);
1685
1686        maybe_reload ();
1687
1688        application = application_lookup_or_create (app_id, TRUE/*user_owned*/);
1689
1690        application_clear_mime_types (application);
1691
1692        user_file_dirty = TRUE;
1693}
1694
1695/**
1696 * gnome_vfs_application_registry_add_mime_type:
1697 * @app_id:  registry id of application
1698 * @mime_type: mime type string
1699 *
1700 * This function will associate a mime type with an application given the   
1701 * application registry id and the mime type.  Changes are not realized until
1702 * the gnome_vfs_application_registry_sync function is called to save the
1703 * changes to the file.
1704 *
1705 **/
1706
1707void
1708gnome_vfs_application_registry_add_mime_type (const char *app_id,
1709                                              const char *mime_type)
1710{
1711        Application *application;
1712
1713        g_return_if_fail (app_id != NULL);
1714        g_return_if_fail (mime_type != NULL);
1715
1716        maybe_reload ();
1717
1718        application = application_lookup_or_create (app_id, TRUE/*user_owned*/);
1719
1720        add_mime_type_to_application (application, mime_type);
1721
1722        user_file_dirty = TRUE;
1723}
1724
1725/**
1726 * gnome_vfs_application_registry_remove_mime_type:
1727 * @app_id: registry id of the application
1728 * @mime_type: mime type string
1729 *
1730 * This function will de-associate a mime type from an application registry. 
1731 * Given the application registry id and the mime type.  Changes are not
1732 * realized until the gnome_vfs_application_registry_sync function is called to
1733 * save the changes to the file.
1734 *
1735 */
1736
1737void
1738gnome_vfs_application_registry_remove_mime_type (const char *app_id,
1739                                                 const char *mime_type)
1740{
1741        Application *application;
1742
1743        g_return_if_fail (app_id != NULL);
1744
1745        maybe_reload ();
1746
1747        application = application_lookup_or_create (app_id, TRUE/*user_owned*/);
1748
1749        remove_mime_type_for_application (application, mime_type);
1750
1751        user_file_dirty = TRUE;
1752}
1753
1754/*
1755 * Syncing to disk
1756 */
1757
1758static void
1759application_sync_foreach (gpointer key, gpointer value, gpointer user_data)
1760{
1761        Application *application = value;
1762        FILE *fp = user_data;
1763
1764        /* Only sync things that are user owned */
1765        if (application->user_owned)
1766                application_sync (application, fp);
1767        else if (application->user_application)
1768                application_sync (application->user_application, fp);
1769}
1770
1771/**
1772 * gnome_vfs_application_registry_sync:
1773 *
1774 * This function will sync the registry.  Typically you would use this function
1775 * after a modification of the registry.  When you modify the registry a dirty
1776 * flag is set.  Calling this function will save your modifications to disk and
1777 * reset the flag.
1778 *
1779 * If successful, will return GNOME_VFS_OK
1780 *
1781 * Returns: GnomeVFSResult
1782 *
1783 **/
1784
1785GnomeVFSResult
1786gnome_vfs_application_registry_sync (void)
1787{
1788        FILE *fp;
1789        char *file;
1790        time_t curtime;
1791
1792        if ( ! user_file_dirty)
1793                return GNOME_VFS_OK;
1794
1795        maybe_reload ();
1796
1797        file = g_strconcat (user_registry_dir.dirname, "/user.applications", NULL);
1798        fp = fopen (file, "w");
1799
1800        if ( ! fp) {
1801                g_warning ("Cannot open '%s' for writing", file);
1802                g_free (file);
1803                return gnome_vfs_result_from_errno ();
1804        }
1805
1806        g_free (file);
1807
1808        time(&curtime);
1809
1810        fprintf (fp, "# This file is automatically generated by gnome-vfs "
1811                 "application registry\n"
1812                 "# Do NOT edit by hand\n# Generated: %s\n",
1813                 ctime (&curtime));
1814
1815        if (global_applications != NULL)
1816                g_hash_table_foreach (global_applications, application_sync_foreach, fp);
1817
1818        fclose (fp);
1819
1820        user_file_dirty = FALSE;
1821
1822        return GNOME_VFS_OK;
1823}
1824
1825
1826/**
1827 * gnome_vfs_application_registry_get_mime_application:
1828 * @app_id:  registry id of the application
1829 *
1830 * Returns a structure that contains the application that handles
1831 * the mime type associated by the application referred by app_id.
1832 *
1833 * Returns: GnomeVFSMimeApplication
1834 **/
1835
1836GnomeVFSMimeApplication *
1837gnome_vfs_application_registry_get_mime_application (const char *app_id)
1838{
1839        Application *i_application;
1840        GnomeVFSMimeApplication *application;
1841
1842        g_return_val_if_fail (app_id != NULL, NULL);
1843
1844        maybe_reload ();
1845
1846        i_application = application_lookup (app_id);
1847
1848        if (i_application == NULL)
1849                return NULL;
1850
1851        application = g_new0 (GnomeVFSMimeApplication, 1);
1852
1853        application->id = g_strdup (app_id);
1854
1855        application->name =
1856                g_strdup (real_peek_value
1857                          (i_application,
1858                           GNOME_VFS_APPLICATION_REGISTRY_NAME));
1859        application->command =
1860                g_strdup (real_peek_value
1861                          (i_application,
1862                           GNOME_VFS_APPLICATION_REGISTRY_COMMAND));
1863
1864        application->can_open_multiple_files =
1865                real_get_bool_value
1866                        (i_application,
1867                         GNOME_VFS_APPLICATION_REGISTRY_CAN_OPEN_MULTIPLE_FILES,
1868                         NULL);
1869        application->expects_uris = i_application->expects_uris;
1870        application->supported_uri_schemes =
1871                supported_uri_scheme_list_copy (i_application->supported_uri_schemes);
1872
1873        application->requires_terminal =
1874                real_get_bool_value
1875                        (i_application,
1876                         GNOME_VFS_APPLICATION_REGISTRY_REQUIRES_TERMINAL,
1877                         NULL);
1878
1879        return application;
1880}
1881
1882/**
1883 * gnome_vfs_application_registry_save_mime_application:
1884 *
1885 * @application: application associated with the mime type
1886 *
1887 * This will save to the registry the application that will be associated with
1888 * a defined mime type.  The defined mime type is located within the
1889 * GnomeVFSMimeApplication structure.  Changes are not realized until the
1890 * gnome_vfs_application_registry_sync function is called.
1891 *
1892 **/
1893
1894void
1895gnome_vfs_application_registry_save_mime_application (const GnomeVFSMimeApplication *application)
1896{
1897        Application *i_application;
1898
1899        g_return_if_fail (application != NULL);
1900
1901        /* make us a new user application */
1902        i_application = application_lookup_or_create (application->id, TRUE);
1903
1904        application_ref (i_application);
1905
1906        set_value (i_application, GNOME_VFS_APPLICATION_REGISTRY_NAME,
1907                   application->name);
1908        set_value (i_application, GNOME_VFS_APPLICATION_REGISTRY_COMMAND,
1909                   application->command);
1910        set_bool_value (i_application, GNOME_VFS_APPLICATION_REGISTRY_CAN_OPEN_MULTIPLE_FILES,
1911                        application->can_open_multiple_files);
1912        i_application->expects_uris = application->expects_uris;
1913        set_bool_value (i_application, GNOME_VFS_APPLICATION_REGISTRY_REQUIRES_TERMINAL,
1914                        application->requires_terminal);
1915        /* FIXME: Need to save supported_uri_schemes information */
1916        user_file_dirty = TRUE;
1917}
1918
1919/**
1920 * gnome_vfs_application_is_user_owned_application:
1921 *
1922 * @application:  data structure of the mime application
1923 *
1924 * This function will determine if a mime application is user owned or not.  By
1925 * user ownered this means that the application is not a system application
1926 * located in the prerequisite /usr area but rather in the user's area.
1927 *
1928 * Returns: gboolean
1929 **/
1930
1931gboolean
1932gnome_vfs_application_is_user_owned_application (const GnomeVFSMimeApplication *application)
1933{
1934        Application *i_application;
1935
1936        g_return_val_if_fail (application != NULL, FALSE);
1937
1938        /* make us a new user application */
1939        i_application = g_hash_table_lookup (global_applications, application->id);
1940        if (i_application != NULL) {
1941                return i_application->user_owned;
1942        }
1943       
1944        return FALSE;
1945}
1946
Note: See TracBrowser for help on using the repository browser.