source: trunk/third/gnome-vfs/libgnomevfs/gnome-vfs-mime-handlers.c @ 15497

Revision 15497, 48.4 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15496, 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/* gnome-vfs-mime-handlers.c - Mime type handlers for the GNOME Virtual
3   File System.
4
5   Copyright (C) 2000 Eazel, Inc.
6
7   The Gnome Library is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   The Gnome Library is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public
18   License along with the Gnome Library; see the file COPYING.LIB.  If not,
19   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.
21
22   Author: Maciej Stachowiak <mjs@eazel.com> */
23
24#include <config.h>
25#include "gnome-vfs-mime-handlers.h"
26
27#include "gnome-vfs-mime-info.h"
28#include "gnome-vfs-application-registry.h"
29#include <gconf/gconf.h>
30#include <stdio.h>
31#include <string.h>
32#include <unistd.h>
33#include <sys/stat.h>
34#include "gnome-vfs-result.h"
35
36static char *         get_user_level                          (void);
37static char *         extract_prefix_add_suffix               (const char         *string,
38                                                               const char         *separator,
39                                                               const char         *suffix);
40static char *         mime_type_get_supertype                 (const char         *mime_type);
41static char **        strsplit_handle_null                    (const char         *str,
42                                                               const char         *delim,
43                                                               int                 max);
44static char *         join_str_list                           (const char         *separator,
45                                                               GList              *list);
46static GList *        OAF_ServerInfoList_to_ServerInfo_g_list (OAF_ServerInfoList *info_list);
47static GList *        comma_separated_str_to_str_list         (const char         *str);
48static GList *        str_list_difference                     (GList              *a,
49                                                               GList              *b);
50static char *         str_list_to_comma_separated_str         (GList              *list);
51static GList *        gnome_vfs_strsplit_to_list              (const char         *str,
52                                                               const char         *delim,
53                                                               int                 max);
54static char *         gnome_vfs_strjoin_from_list             (const char         *separator,
55                                                               GList              *list);
56static void           g_list_free_deep                        (GList              *list);
57static GList *        prune_ids_for_nonexistent_applications  (GList              *list);
58static GnomeVFSResult gnome_vfs_mime_edit_user_file           (const char         *mime_type,
59                                                               const char         *key,
60                                                               const char         *value);
61static gboolean       application_known_to_be_nonexistent     (const char         *application_id);
62
63
64static GConfEngine *gconf_engine = NULL;
65
66static GnomeVFSMimeActionType
67gnome_vfs_mime_get_default_action_type_without_fallback (const char *mime_type)
68{
69        const char *action_type_string;
70
71        action_type_string = gnome_vfs_mime_get_value
72                (mime_type, "default_action_type");
73
74        if (action_type_string != NULL && strcasecmp (action_type_string, "application") == 0) {
75                return GNOME_VFS_MIME_ACTION_TYPE_APPLICATION;
76        } else if (action_type_string != NULL && strcasecmp (action_type_string, "component") == 0) {
77                return GNOME_VFS_MIME_ACTION_TYPE_COMPONENT;
78        } else {
79                return GNOME_VFS_MIME_ACTION_TYPE_NONE;
80        }
81}
82
83
84
85/**
86 * gnome_vfs_mime_get_description:
87 * @mime_type: the mime type
88 *
89 * Returns the description for this mime-type
90 */
91const char *
92gnome_vfs_mime_get_description (const char *mime_type)
93{
94        return gnome_vfs_mime_get_value (mime_type, "description");
95}
96
97
98
99GnomeVFSMimeActionType
100gnome_vfs_mime_get_default_action_type (const char *mime_type)
101{
102        char *supertype;
103        GnomeVFSMimeActionType action_type;
104
105        action_type = gnome_vfs_mime_get_default_action_type_without_fallback (mime_type);
106
107        /* FIXME bugzilla.eazel.com 2650: the current (and the previous) implementation of
108           gnome_vfs_mime_get_value
109           tries the supertype. This means that the folowing code is useless.
110           The correct fix for this is to add a new funciotn in gnome-vfs-mime-info.c
111           gnome_vfs_mime_get_value_without_callback. Waiting for evolution guys to fix it.
112           Might remove this code too if we can convince them that wht they do with this
113           function is bad.
114        */
115        if (action_type == GNOME_VFS_MIME_ACTION_TYPE_NONE) {
116                /* Fall back to the supertype. */
117                supertype = mime_type_get_supertype (mime_type);
118
119                action_type = gnome_vfs_mime_get_default_action_type_without_fallback (supertype);
120                g_free (supertype);
121        }
122
123        return action_type;
124}
125
126GnomeVFSMimeAction *
127gnome_vfs_mime_get_default_action_without_fallback (const char *mime_type)
128{
129        GnomeVFSMimeAction *action;
130
131        action = g_new0 (GnomeVFSMimeAction, 1);
132
133        action->action_type = gnome_vfs_mime_get_default_action_type_without_fallback (mime_type);
134
135        switch (action->action_type) {
136        case GNOME_VFS_MIME_ACTION_TYPE_APPLICATION:
137                action->action.application =
138                        gnome_vfs_mime_get_default_application (mime_type);
139                if (action->action.application == NULL) {
140                        g_free (action);
141                        action = NULL;
142                }
143                break;
144        case GNOME_VFS_MIME_ACTION_TYPE_COMPONENT:
145                action->action.component =
146                        gnome_vfs_mime_get_default_component (mime_type);
147                if (action->action.component == NULL) {
148                        g_free (action);
149                        action = NULL;
150                }
151                break;
152        case GNOME_VFS_MIME_ACTION_TYPE_NONE:
153                g_free (action);
154                action = NULL;
155                break;
156        default:
157                g_assert_not_reached ();
158        }
159
160        return action;
161}
162
163GnomeVFSMimeAction *
164gnome_vfs_mime_get_default_action (const char *mime_type)
165{
166        GnomeVFSMimeAction *action;
167        char *supertype;
168
169        action = gnome_vfs_mime_get_default_action_without_fallback (mime_type);
170        if (action == NULL) {
171                /* Fall back to the supertype. */
172                supertype = mime_type_get_supertype (mime_type);
173                action = gnome_vfs_mime_get_default_action_without_fallback (supertype);
174                g_free (supertype);
175        }
176
177        return action;
178}
179
180GnomeVFSMimeApplication *
181gnome_vfs_mime_get_default_application (const char *mime_type)
182{
183        const char *default_application_id;
184        GnomeVFSMimeApplication *default_application;
185        char *supertype;
186        GList *short_list;
187
188        default_application = NULL;
189
190        /* First, try the default for the mime type */
191        default_application_id = gnome_vfs_mime_get_value
192                (mime_type, "default_application_id");
193
194        if (default_application_id != NULL &&
195            strcmp (default_application_id, "") != 0
196            && ! application_known_to_be_nonexistent (default_application_id)) {
197                default_application =
198                        gnome_vfs_application_registry_get_mime_application (default_application_id);
199        }
200
201        if (default_application == NULL) {
202                /* Failing that, try something from the short list */
203
204                short_list = gnome_vfs_mime_get_short_list_applications (mime_type);
205
206                if (short_list != NULL) {
207                        default_application = gnome_vfs_mime_application_copy
208                                ((GnomeVFSMimeApplication *) (short_list->data));
209                        gnome_vfs_mime_application_list_free (short_list);
210                }
211        }
212
213        if (default_application == NULL) {
214                /* If that still fails, try the supertype */
215
216                supertype = mime_type_get_supertype (mime_type);
217                /* Check if already a supertype */
218                if (strcmp (supertype, mime_type) != 0) {
219                        default_application = gnome_vfs_mime_get_default_application (supertype);
220                }
221                g_free (supertype);
222        }
223
224        return default_application;
225}
226
227const char *
228gnome_vfs_mime_get_icon (const char *mime_type)
229{
230        return (gnome_vfs_mime_get_value (mime_type, "icon-filename"));
231}
232
233GnomeVFSResult
234gnome_vfs_mime_set_icon (const char *mime_type, const char *filename)
235{
236        return gnome_vfs_mime_edit_user_file
237                (mime_type, "icon-filename", filename);
238}
239
240
241OAF_ServerInfo *
242gnome_vfs_mime_get_default_component (const char *mime_type)
243{
244        const char *default_component_iid;
245        OAF_ServerInfoList *info_list;
246        OAF_ServerInfo *default_component;
247        CORBA_Environment ev;
248        char *supertype;
249        char *query;
250        char *sort[6];
251        GList *short_list;
252        GList *p;
253        char *prev;
254
255        if (mime_type == NULL) {
256                return NULL;
257        }
258
259        CORBA_exception_init (&ev);
260
261        supertype = mime_type_get_supertype (mime_type);
262
263        /* Find a component that supports either the exact mime type,
264           the supertype, or all mime types. */
265
266        /* First try the component specified in the mime database, if available. */
267        default_component_iid = gnome_vfs_mime_get_value
268                (mime_type, "default_component_iid");
269        if (default_component_iid == NULL || default_component_iid[0] == '\0') {
270                /* Fall back to the supertype. */
271                /* Check if already a supertype */
272                if (strcmp (supertype, mime_type) != 0) {
273                        default_component = gnome_vfs_mime_get_default_component (supertype);
274                        if (default_component != NULL) {
275                                default_component_iid = g_strdup (default_component->iid);
276                                CORBA_free (default_component);
277                        }
278                }
279        }
280
281        /* FIXME bugzilla.eazel.com 1142: should probably check for
282           the right interfaces too. Also slightly semantically
283           different from nautilus in other tiny ways.
284        */
285        query = g_strconcat ("bonobo:supported_mime_types.has_one (['", mime_type,
286                             "', '", supertype,
287                             "', '*'])", NULL);
288
289
290        if (default_component_iid != NULL) {
291                sort[0] = g_strconcat ("iid == '", default_component_iid, "'", NULL);
292        } else {
293                sort[0] = g_strdup ("true");
294        }
295
296        short_list = gnome_vfs_mime_get_short_list_components (mime_type);
297
298        if (short_list != NULL) {
299                sort[1] = g_strdup ("has (['");
300
301                for (p = short_list; p != NULL; p = p->next) {
302                        prev = sort[1];
303                       
304                        if (p->next != NULL) {
305                                sort[1] = g_strconcat (prev, ((OAF_ServerInfo *) (p->data))->iid,
306                                                                    "','", NULL);
307                        } else {
308                                sort[1] = g_strconcat (prev, ((OAF_ServerInfo *) (p->data))->iid,
309                                                                    "'], iid)", NULL);
310                        }
311                        g_free (prev);
312                }
313        } else {
314                sort[1] = g_strdup ("true");
315        }
316
317
318        /* Prefer something that matches the exact type to something
319           that matches the supertype */
320        sort[2] = g_strconcat ("bonobo:supported_mime_types.has ('", mime_type, "')", NULL);
321
322        /* Prefer something that matches the supertype to something that matches `*' */
323        sort[3] = g_strconcat ("bonobo:supported_mime_types.has ('", supertype, "')", NULL);
324
325        /* At lowest priority, alphebetize by name, for the sake of consistency */
326        sort[4] = g_strdup ("name");
327
328        sort[5] = NULL;
329
330        info_list = oaf_query (query, sort, &ev);
331       
332        default_component = NULL;
333        if (ev._major == CORBA_NO_EXCEPTION) {
334                if (info_list != NULL && info_list->_length > 0) {
335                        default_component = OAF_ServerInfo_duplicate (&info_list->_buffer[0]);
336                }
337                CORBA_free (info_list);
338        }
339
340        g_free (supertype);
341        g_free (query);
342        g_free (sort[0]);
343        g_free (sort[1]);
344        g_free (sort[2]);
345        g_free (sort[3]);
346        g_free (sort[4]);
347
348        CORBA_exception_free (&ev);
349
350        return default_component;
351}
352
353static GList *
354gnome_vfs_mime_str_list_merge (GList *a,
355                               GList *b)
356{
357        GList *pruned_b;
358        GList *extended_a;
359        GList *a_copy;
360
361        pruned_b = str_list_difference (b, a);
362
363        a_copy = g_list_copy (a);
364        extended_a = g_list_concat (a_copy, pruned_b);
365
366        /* No need to free a_copy or
367         * pruned_b since they were concat()ed into
368         * extended_a
369         */
370
371        return extended_a;
372}
373
374
375static GList *
376gnome_vfs_mime_str_list_apply_delta (GList *list_to_process,
377                                     GList *additions,
378                                     GList *removals)
379{
380        GList *extended_original_list;
381        GList *processed_list;
382
383        extended_original_list = gnome_vfs_mime_str_list_merge (list_to_process, additions);
384
385        processed_list = str_list_difference (extended_original_list, removals);
386       
387        g_list_free (extended_original_list);
388
389        return processed_list;
390}
391
392static const char *
393gnome_vfs_mime_get_value_for_user_level (const char *mime_type,
394                                         const char *key_prefix)
395{
396        char *user_level;
397        char *full_key;
398        const char *value;
399
400        /* Base list depends on user level. */
401        user_level = get_user_level ();
402        full_key = g_strconcat (key_prefix,
403                                "_for_",
404                                user_level,
405                                "_user_level",
406                                NULL);
407        g_free (user_level);
408        value = gnome_vfs_mime_get_value (mime_type, full_key);
409        g_free (full_key);
410
411        return value;
412}
413
414
415static GList *gnome_vfs_mime_do_short_list_processing (GList *short_list,
416                                                       GList *additions,
417                                                       GList *removals,
418                                                       GList *supertype_short_list,
419                                                       GList *supertype_additions,
420                                                       GList *supertype_removals)
421{
422        GList *processed_supertype_list;
423        GList *merged_system_and_supertype;
424        GList *final_list;
425
426        processed_supertype_list = gnome_vfs_mime_str_list_apply_delta (supertype_short_list,
427                                                                        supertype_additions,
428                                                                        supertype_removals);
429
430        merged_system_and_supertype = gnome_vfs_mime_str_list_merge (short_list,
431                                                                     processed_supertype_list);
432
433        final_list = gnome_vfs_mime_str_list_apply_delta (merged_system_and_supertype,
434                                                          additions,
435                                                          removals);
436       
437        g_list_free (processed_supertype_list);
438        g_list_free (merged_system_and_supertype);
439
440        return final_list;
441}
442
443
444/* sort_application_list
445 *
446 * Sort list alphabetically
447 */
448 
449static int
450sort_application_list (gconstpointer a, gconstpointer b)
451{
452        GnomeVFSMimeApplication *application1, *application2;
453
454        application1 = (GnomeVFSMimeApplication *) a;
455        application2 = (GnomeVFSMimeApplication *) b;
456
457        return g_strcasecmp (application1->name, application2->name);
458}
459
460/* gnome_vfs_mime_get_short_list_applications
461 *
462 * Return alphabetically sorted list of GnomeVFSMimeApplication
463 * data structures for the requested mime type.
464 */
465 
466GList *
467gnome_vfs_mime_get_short_list_applications (const char *mime_type)
468{
469        GList *system_short_list;
470        GList *short_list_additions;
471        GList *short_list_removals;
472        char *supertype;
473        GList *supertype_short_list;
474        GList *supertype_additions;
475        GList *supertype_removals;
476        GList *id_list;
477        GList *p;
478        GnomeVFSMimeApplication *application;
479        GList *preferred_applications;
480
481        if (mime_type == NULL) {
482                return NULL;
483        }
484
485
486        system_short_list = comma_separated_str_to_str_list (gnome_vfs_mime_get_value_for_user_level
487                                                             (mime_type,
488                                                              "short_list_application_ids"));
489        system_short_list = prune_ids_for_nonexistent_applications
490                (system_short_list);
491
492        /* get user short list delta (add list and remove list) */
493
494        short_list_additions = comma_separated_str_to_str_list (gnome_vfs_mime_get_value
495                                                                (mime_type,
496                                                                 "short_list_application_user_additions"));
497        short_list_removals = comma_separated_str_to_str_list (gnome_vfs_mime_get_value
498                                                               (mime_type,
499                                                                "short_list_application_user_removals"));
500
501        /* Only include the supertype in the short list if we came up empty with
502           the specific types */
503        supertype = mime_type_get_supertype (mime_type);
504
505        if ((strcmp (supertype, mime_type) != 0) && (system_short_list == NULL)) {
506                supertype_short_list = comma_separated_str_to_str_list
507                        (gnome_vfs_mime_get_value_for_user_level
508                         (supertype,
509                          "short_list_application_ids"));
510                supertype_short_list = prune_ids_for_nonexistent_applications
511                        (supertype_short_list);
512
513                /* get supertype short list delta (add list and remove list) */
514
515                supertype_additions = comma_separated_str_to_str_list
516                        (gnome_vfs_mime_get_value
517                         (supertype,
518                          "short_list_application_user_additions"));
519                supertype_removals = comma_separated_str_to_str_list
520                        (gnome_vfs_mime_get_value
521                         (supertype,
522                          "short_list_application_user_removals"));
523        } else {
524                supertype_short_list = NULL;
525                supertype_additions = NULL;
526                supertype_removals = NULL;
527        }
528
529
530        /* compute list modified by delta */
531
532        id_list = gnome_vfs_mime_do_short_list_processing (system_short_list,
533                                                           short_list_additions,
534                                                           short_list_removals,
535                                                           supertype_short_list,
536                                                           supertype_additions,
537                                                           supertype_removals);
538
539        preferred_applications = NULL;
540
541        for (p = id_list; p != NULL; p = p->next) {
542                application = gnome_vfs_application_registry_get_mime_application (p->data);
543                if (application != NULL) {
544                        preferred_applications = g_list_prepend
545                                (preferred_applications, application);
546                }
547        }
548
549
550        preferred_applications = g_list_reverse (preferred_applications);
551
552        g_list_free_deep (system_short_list);
553        g_list_free_deep (short_list_additions);
554        g_list_free_deep (short_list_removals);
555        g_list_free_deep (supertype_short_list);
556        g_list_free_deep (supertype_additions);
557        g_list_free_deep (supertype_removals);
558        g_list_free (id_list);
559
560        /* Sort list alphabetically by application name */
561        preferred_applications = g_list_sort (preferred_applications, sort_application_list);
562       
563        return preferred_applications;
564}
565
566
567static char *
568join_str_list (const char *separator, GList *list)
569{
570        char **strv;
571        GList *p;
572        int i;
573        char *retval;
574
575        strv = g_new0 (char *, g_list_length (list) + 1);
576
577        /* Convert to a strv so we can use g_strjoinv.
578         * Saves code but could be made faster if we want.
579         */
580        strv = g_new (char *, g_list_length (list) + 1);
581        for (p = list, i = 0; p != NULL; p = p->next, i++) {
582                strv[i] = (char *) p->data;
583        }
584        strv[i] = NULL;
585
586        retval = g_strjoinv (separator, strv);
587
588        g_free (strv);
589
590        return retval;
591}
592
593
594/* sort_component_list
595 *
596 * Sort list alphabetically by component name
597 */
598 
599static int
600sort_component_list (gconstpointer a, gconstpointer b)
601{
602        OAF_ServerInfo *component1, *component2;
603               
604        component1 = (OAF_ServerInfo *) a;
605        component2 = (OAF_ServerInfo *) b;
606
607        return g_strcasecmp (component1->iid, component2->iid);
608}
609
610GList *
611gnome_vfs_mime_get_short_list_components (const char *mime_type)
612{
613        GList *system_short_list;
614        GList *short_list_additions;
615        GList *short_list_removals;
616        char *supertype;
617        GList *supertype_short_list;
618        GList *supertype_additions;
619        GList *supertype_removals;
620        GList *iid_list;
621        char *query;
622        char *sort[2];
623        char *iids_delimited;
624        CORBA_Environment ev;
625        OAF_ServerInfoList *info_list;
626        GList *preferred_components;
627
628        if (mime_type == NULL) {
629                return NULL;
630        }
631
632
633        /* get short list IIDs for that user level */
634        system_short_list = comma_separated_str_to_str_list (gnome_vfs_mime_get_value_for_user_level
635                                                             (mime_type,
636                                                              "short_list_component_iids"));
637
638        /* get user short list delta (add list and remove list) */
639
640        short_list_additions = comma_separated_str_to_str_list (gnome_vfs_mime_get_value
641                                                                (mime_type,
642                                                                 "short_list_component_user_additions"));
643       
644        short_list_removals = comma_separated_str_to_str_list (gnome_vfs_mime_get_value
645                                                               (mime_type,
646                                                                "short_list_component_user_removals"));
647
648
649        supertype = mime_type_get_supertype (mime_type);
650       
651        if (strcmp (supertype, mime_type) != 0) {
652                supertype_short_list = comma_separated_str_to_str_list
653                        (gnome_vfs_mime_get_value_for_user_level
654                         (supertype,
655                          "short_list_component_iids"));
656
657                /* get supertype short list delta (add list and remove list) */
658
659                supertype_additions = comma_separated_str_to_str_list
660                        (gnome_vfs_mime_get_value
661                         (supertype,
662                          "short_list_component_user_additions"));
663                supertype_removals = comma_separated_str_to_str_list
664                        (gnome_vfs_mime_get_value
665                         (supertype,
666                          "short_list_component_user_removals"));
667        } else {
668                supertype_short_list = NULL;
669                supertype_additions = NULL;
670                supertype_removals = NULL;
671        }
672
673        /* compute list modified by delta */
674
675        iid_list = gnome_vfs_mime_do_short_list_processing (system_short_list,
676                                                            short_list_additions,
677                                                            short_list_removals,
678                                                            supertype_short_list,
679                                                            supertype_additions,
680                                                            supertype_removals);
681
682
683
684        /* Do usual query but requiring that IIDs be one of the ones
685           in the short list IID list. */
686       
687        preferred_components = NULL;
688        if (iid_list != NULL) {
689                CORBA_exception_init (&ev);
690
691                iids_delimited = join_str_list ("','", iid_list);
692
693                /* FIXME bugzilla.eazel.com 1142: should probably check for
694                   the right interfaces too. Also slightly semantically
695                   different from nautilus in other tiny ways.
696                */
697                query = g_strconcat ("bonobo:supported_mime_types.has_one (['", mime_type,
698                                     "', '", supertype,
699                                     "', '*'])",
700                                     " AND has(['", iids_delimited, "'], iid)", NULL);
701               
702                /* Alphebetize by name, for the sake of consistency */
703                sort[0] = g_strdup ("name");
704                sort[1] = NULL;
705               
706                info_list = oaf_query (query, sort, &ev);
707               
708                if (ev._major == CORBA_NO_EXCEPTION) {
709                        preferred_components = OAF_ServerInfoList_to_ServerInfo_g_list (info_list);
710                        CORBA_free (info_list);
711                }
712
713                g_free (iids_delimited);
714                g_free (query);
715                g_free (sort[0]);
716
717                CORBA_exception_free (&ev);
718        }
719
720        g_free (supertype);
721        g_list_free_deep (system_short_list);
722        g_list_free_deep (short_list_additions);
723        g_list_free_deep (short_list_removals);
724        g_list_free_deep (supertype_short_list);
725        g_list_free_deep (supertype_additions);
726        g_list_free_deep (supertype_removals);
727        g_list_free (iid_list);
728
729        /* Sort list alphabetically by component name */
730        preferred_components = g_list_sort (preferred_components, sort_component_list);
731
732        return preferred_components;
733}
734
735
736
737GList *
738gnome_vfs_mime_get_all_applications (const char *mime_type)
739{
740        GList *applications, *li;
741
742        g_return_val_if_fail (mime_type != NULL, NULL);
743
744        applications = gnome_vfs_application_registry_get_applications (mime_type);
745
746        /* convert list to list of GnomeVFSMimeApplication's */
747        li = applications;
748        while (li != NULL) {
749                const char *application_id = li->data;
750                li->data = gnome_vfs_application_registry_get_mime_application (application_id);
751                /* Make sure we get no NULLs */
752                if (li->data == NULL) {
753                        GList *link_to_remove = li;
754
755                        li = li->next;
756
757                        applications = g_list_remove_link (applications,
758                                                           link_to_remove);
759                        g_list_free_1 (link_to_remove);
760                } else
761                        li = li->next;
762        }
763
764        return applications;
765}
766
767GList *
768gnome_vfs_mime_get_all_components (const char *mime_type)
769{
770        OAF_ServerInfoList *info_list;
771        GList *components_list;
772        CORBA_Environment ev;
773        char *supertype;
774        char *query;
775        char *sort[2];
776
777        if (mime_type == NULL) {
778                return NULL;
779        }
780
781        CORBA_exception_init (&ev);
782
783        /* Find a component that supports either the exact mime type,
784           the supertype, or all mime types. */
785
786        /* FIXME bugzilla.eazel.com 1142: should probably check for
787           the right interfaces too. Also slightly semantically
788           different from nautilus in other tiny ways.
789        */
790        supertype = mime_type_get_supertype (mime_type);
791        query = g_strconcat ("bonobo:supported_mime_types.has_one (['", mime_type,
792                             "', '", supertype,
793                             "', '*'])", NULL);
794        g_free (supertype);
795       
796        /* Alphebetize by name, for the sake of consistency */
797        sort[0] = g_strdup ("name");
798        sort[1] = NULL;
799
800        info_list = oaf_query (query, sort, &ev);
801       
802        if (ev._major == CORBA_NO_EXCEPTION) {
803                components_list = OAF_ServerInfoList_to_ServerInfo_g_list (info_list);
804                CORBA_free (info_list);
805        } else {
806                components_list = NULL;
807        }
808
809        g_free (query);
810        g_free (sort[0]);
811
812        CORBA_exception_free (&ev);
813
814        return components_list;
815}
816
817static GnomeVFSResult
818gnome_vfs_mime_edit_user_file_full (const char *mime_type, GList *keys, GList *values)
819{
820        GnomeVFSResult result;
821        GList *p, *q;
822        const char *key, *value;
823
824        if (mime_type == NULL) {
825                return GNOME_VFS_OK;
826        }
827
828        result = GNOME_VFS_OK;
829
830        gnome_vfs_mime_freeze ();
831        for (p = keys, q = values; p != NULL && q != NULL; p = p->next, q = q->next) {
832                key = p->data;
833                value = q->data;
834                if (value == NULL) {
835                        value = "";
836                }
837                gnome_vfs_mime_set_value (mime_type, g_strdup (key), g_strdup (value));
838        }
839        gnome_vfs_mime_thaw ();
840
841        return result;
842}
843
844static GnomeVFSResult
845gnome_vfs_mime_edit_user_file_args (const char *mime_type, va_list args)
846{
847        GList *keys, *values;
848        char *key, *value;
849        GnomeVFSResult result;
850
851        keys = NULL;
852        values = NULL;
853        for (;;) {
854                key = va_arg (args, char *);
855                if (key == NULL) {
856                        break;
857                }
858                value = va_arg (args, char *);
859                keys = g_list_prepend (keys, key);
860                values = g_list_prepend (values, value);
861        }
862
863        result = gnome_vfs_mime_edit_user_file_full (mime_type, keys, values);
864
865        g_list_free (keys);
866        g_list_free (values);
867
868        return result;
869}
870
871static GnomeVFSResult
872gnome_vfs_mime_edit_user_file_multiple (const char *mime_type, ...)
873{
874        va_list args;
875        GnomeVFSResult result;
876
877        va_start (args, mime_type);
878        result = gnome_vfs_mime_edit_user_file_args (mime_type, args);
879        va_end (args);
880
881        return result;
882}
883
884static GnomeVFSResult
885gnome_vfs_mime_edit_user_file (const char *mime_type, const char *key, const char *value)
886{
887        g_return_val_if_fail (key != NULL, GNOME_VFS_OK);
888        return gnome_vfs_mime_edit_user_file_multiple (mime_type, key, value, NULL);
889}
890
891GnomeVFSResult
892gnome_vfs_mime_set_default_action_type (const char *mime_type,
893                                        GnomeVFSMimeActionType action_type)
894{
895        const char *action_string;
896
897        switch (action_type) {
898        case GNOME_VFS_MIME_ACTION_TYPE_APPLICATION:
899                action_string = "application";
900                break;         
901        case GNOME_VFS_MIME_ACTION_TYPE_COMPONENT:
902                action_string = "component";
903                break;
904        case GNOME_VFS_MIME_ACTION_TYPE_NONE:
905        default:
906                action_string = "none";
907        }
908
909        return gnome_vfs_mime_edit_user_file
910                (mime_type, "default_action_type", action_string);
911}
912
913GnomeVFSResult
914gnome_vfs_mime_set_default_application (const char *mime_type,
915                                        const char *application_id)
916{
917        GnomeVFSResult result;
918
919        result = gnome_vfs_mime_edit_user_file
920                (mime_type, "default_application_id", application_id);
921
922        /* If there's no default action type, set it to match this. */
923        if (result == GNOME_VFS_OK
924            && application_id != NULL
925            && gnome_vfs_mime_get_default_action_type (mime_type) == GNOME_VFS_MIME_ACTION_TYPE_NONE) {
926                result = gnome_vfs_mime_set_default_action_type (mime_type, GNOME_VFS_MIME_ACTION_TYPE_APPLICATION);
927        }
928
929        return result;
930}
931
932GnomeVFSResult
933gnome_vfs_mime_set_default_component (const char *mime_type,
934                                      const char *component_iid)
935{
936        GnomeVFSResult result;
937
938        result = gnome_vfs_mime_edit_user_file
939                (mime_type, "default_component_iid", component_iid);
940
941        /* If there's no default action type, set it to match this. */
942        if (result == GNOME_VFS_OK
943            && component_iid != NULL
944            && gnome_vfs_mime_get_default_action_type (mime_type) == GNOME_VFS_MIME_ACTION_TYPE_NONE) {
945                gnome_vfs_mime_set_default_action_type (mime_type, GNOME_VFS_MIME_ACTION_TYPE_COMPONENT);
946        }
947
948        return result;
949}
950
951GnomeVFSResult
952gnome_vfs_mime_set_short_list_applications (const char *mime_type,
953                                            GList *application_ids)
954{
955        char *user_level, *id_list_key;
956        char *addition_string, *removal_string;
957        GList *short_list_id_list;
958        GList *short_list_addition_list;
959        GList *short_list_removal_list;
960        GnomeVFSResult result;
961
962        /* Get base list. */
963        /* Base list depends on user level. */
964        user_level = get_user_level ();
965        id_list_key = g_strconcat ("short_list_application_ids_for_",
966                                   user_level,
967                                   "_user_level",
968                                   NULL);
969        g_free (user_level);
970        short_list_id_list = comma_separated_str_to_str_list
971                (gnome_vfs_mime_get_value (mime_type, id_list_key));
972        g_free (id_list_key);
973
974        /* Compute delta. */
975        short_list_addition_list = str_list_difference (application_ids, short_list_id_list);
976        short_list_removal_list = str_list_difference (short_list_id_list, application_ids);
977        addition_string = str_list_to_comma_separated_str (short_list_addition_list);
978        removal_string = str_list_to_comma_separated_str (short_list_removal_list);
979        g_list_free_deep (short_list_id_list);
980        g_list_free (short_list_addition_list);
981        g_list_free (short_list_removal_list);
982
983        /* Write it. */
984        result = gnome_vfs_mime_edit_user_file_multiple
985                (mime_type,
986                 "short_list_application_user_additions", addition_string,
987                 "short_list_application_user_removals", removal_string,
988                 NULL);
989
990        g_free (addition_string);
991        g_free (removal_string);
992
993        return result;
994}
995
996GnomeVFSResult
997gnome_vfs_mime_set_short_list_components (const char *mime_type,
998                                          GList *component_iids)
999{
1000        char *user_level, *id_list_key;
1001        char *addition_string, *removal_string;
1002        GList *short_list_id_list;
1003        GList *short_list_addition_list;
1004        GList *short_list_removal_list;
1005        GnomeVFSResult result;
1006
1007        /* Get base list. */
1008        /* Base list depends on user level. */
1009        user_level = get_user_level ();
1010        id_list_key = g_strconcat ("short_list_component_iids_for_",
1011                                   user_level,
1012                                   "_user_level",
1013                                   NULL);
1014        g_free (user_level);
1015        short_list_id_list = comma_separated_str_to_str_list
1016                (gnome_vfs_mime_get_value (mime_type, id_list_key));
1017        g_free (id_list_key);
1018
1019        /* Compute delta. */
1020        short_list_addition_list = str_list_difference (component_iids, short_list_id_list);
1021        short_list_removal_list = str_list_difference (short_list_id_list, component_iids);
1022        addition_string = str_list_to_comma_separated_str (short_list_addition_list);
1023        removal_string = str_list_to_comma_separated_str (short_list_removal_list);
1024        g_list_free (short_list_addition_list);
1025        g_list_free (short_list_removal_list);
1026
1027        /* Write it. */
1028        result = gnome_vfs_mime_edit_user_file_multiple
1029                (mime_type,
1030                 "short_list_component_user_additions", addition_string,
1031                 "short_list_component_user_removals", removal_string,
1032                 NULL);
1033
1034        g_free (addition_string);
1035        g_free (removal_string);
1036
1037        return result;
1038}
1039
1040/* FIXME bugzilla.eazel.com 1148:
1041 * The next set of helper functions are all replicated in nautilus-mime-actions.c.
1042 * Need to refactor so they can share code.
1043 */
1044static gint
1045gnome_vfs_mime_application_has_id (GnomeVFSMimeApplication *application, const char *id)
1046{
1047        return strcmp (application->id, id);
1048}
1049
1050static gint
1051gnome_vfs_mime_id_matches_application (const char *id, GnomeVFSMimeApplication *application)
1052{
1053        return gnome_vfs_mime_application_has_id (application, id);
1054}
1055
1056#ifdef USING_OAF
1057static gint
1058gnome_vfs_mime_id_matches_component (const char *iid, OAF_ServerInfo *component)
1059{
1060        return strcmp (component->iid, iid);
1061}
1062#endif
1063
1064static gint
1065gnome_vfs_mime_application_matches_id (GnomeVFSMimeApplication *application, const char *id)
1066{
1067        return gnome_vfs_mime_id_matches_application (id, application);
1068}
1069
1070#ifdef USING_OAF
1071static gint
1072gnome_vfs_mime_component_matches_id (OAF_ServerInfo *component, const char *iid)
1073{
1074        return gnome_vfs_mime_id_matches_component (iid, component);
1075}
1076#endif
1077
1078/**
1079 * gnome_vfs_mime_id_in_application_list:
1080 *
1081 * Check whether an application id is in a list of GnomeVFSMimeApplications.
1082 *
1083 * @id: An application id.
1084 * @applications: A GList * whose nodes are GnomeVFSMimeApplications, such as the
1085 * result of gnome_vfs_mime_get_short_list_applications.
1086 *
1087 * Return value: TRUE if an application whose id matches @id is in @applications.
1088 */
1089gboolean
1090gnome_vfs_mime_id_in_application_list (const char *id, GList *applications)
1091{
1092        return g_list_find_custom
1093                (applications, (gpointer) id,
1094                 (GCompareFunc) gnome_vfs_mime_application_matches_id) != NULL;
1095}
1096
1097/**
1098 * gnome_vfs_mime_id_in_component_list:
1099 *
1100 * Check whether a component iid is in a list of OAF_ServerInfos.
1101 *
1102 * @iid: A component iid.
1103 * @applications: A GList * whose nodes are OAF_ServerInfos, such as the
1104 * result of gnome_vfs_mime_get_short_list_components.
1105 *
1106 * Return value: TRUE if a component whose iid matches @iid is in @components.
1107 */
1108gboolean
1109gnome_vfs_mime_id_in_component_list (const char *iid, GList *components)
1110{
1111        return g_list_find_custom
1112                (components, (gpointer) iid,
1113                 (GCompareFunc) gnome_vfs_mime_component_matches_id) != NULL;
1114        return FALSE;
1115}
1116
1117/**
1118 * gnome_vfs_mime_id_list_from_application_list:
1119 *
1120 * Create a list of application ids from a list of GnomeVFSMimeApplications.
1121 *
1122 * @applications: A GList * whose nodes are GnomeVFSMimeApplications, such as the
1123 * result of gnome_vfs_mime_get_short_list_applications.
1124 *
1125 * Return value: A new list where each GnomeVFSMimeApplication in the original
1126 * list is replaced by a char * with the application's id. The original list is
1127 * not modified.
1128 */
1129GList *
1130gnome_vfs_mime_id_list_from_application_list (GList *applications)
1131{
1132        GList *result;
1133        GList *node;
1134
1135        result = NULL;
1136       
1137        for (node = applications; node != NULL; node = node->next) {
1138                result = g_list_append
1139                        (result, g_strdup (((GnomeVFSMimeApplication *)node->data)->id));
1140        }
1141
1142        return result;
1143}
1144
1145/**
1146 * gnome_vfs_mime_id_list_from_component_list:
1147 *
1148 * Create a list of component iids from a list of OAF_ServerInfos.
1149 *
1150 * @components: A GList * whose nodes are OAF_ServerInfos, such as the
1151 * result of gnome_vfs_mime_get_short_list_components.
1152 *
1153 * Return value: A new list where each OAF_ServerInfo in the original
1154 * list is replaced by a char * with the component's iid. The original list is
1155 * not modified.
1156 */
1157GList *
1158gnome_vfs_mime_id_list_from_component_list (GList *components)
1159{
1160        GList *list = NULL;
1161        GList *node;
1162
1163        for (node = components; node != NULL; node = node->next) {
1164                list = g_list_prepend
1165                        (list, g_strdup (((OAF_ServerInfo *)node->data)->iid));
1166        }
1167        return g_list_reverse (list);
1168}
1169
1170static void
1171g_list_free_deep (GList *list)
1172{
1173        g_list_foreach (list, (GFunc) g_free, NULL);
1174        g_list_free (list);
1175}
1176
1177GnomeVFSResult
1178gnome_vfs_mime_add_application_to_short_list (const char *mime_type,
1179                                              const char *application_id)
1180{
1181        GList *old_list, *new_list;
1182        GnomeVFSResult result;
1183
1184        old_list = gnome_vfs_mime_get_short_list_applications (mime_type);
1185
1186        if (gnome_vfs_mime_id_in_application_list (application_id, old_list)) {
1187                result = GNOME_VFS_OK;
1188        } else {
1189                new_list = g_list_append (gnome_vfs_mime_id_list_from_application_list (old_list),
1190                                          g_strdup (application_id));
1191                result = gnome_vfs_mime_set_short_list_applications (mime_type, new_list);
1192                g_list_free_deep (new_list);
1193        }
1194
1195        gnome_vfs_mime_application_list_free (old_list);
1196
1197        return result;
1198}
1199
1200/**
1201 * gnome_vfs_mime_remove_application_from_list:
1202 *
1203 * Remove an application specified by id from a list of GnomeVFSMimeApplications.
1204 *
1205 * @applications: A GList * whose nodes are GnomeVFSMimeApplications, such as the
1206 * result of gnome_vfs_mime_get_short_list_applications.
1207 * @application_id: The id of an application to remove from @applications.
1208 * @did_remove: If non-NULL, this is filled in with TRUE if the application
1209 * was found in the list, FALSE otherwise.
1210 *
1211 * Return value: The modified list. If the application is not found, the list will
1212 * be unchanged.
1213 */
1214GList *
1215gnome_vfs_mime_remove_application_from_list (GList *applications,
1216                                             const char *application_id,
1217                                             gboolean *did_remove)
1218{
1219        GList *matching_node;
1220       
1221        matching_node = g_list_find_custom
1222                (applications, (gpointer)application_id,
1223                 (GCompareFunc) gnome_vfs_mime_application_matches_id);
1224        if (matching_node != NULL) {
1225                applications = g_list_remove_link (applications, matching_node);
1226                gnome_vfs_mime_application_list_free (matching_node);
1227        }
1228
1229        if (did_remove != NULL) {
1230                *did_remove = matching_node != NULL;
1231        }
1232
1233        return applications;
1234}
1235
1236GnomeVFSResult
1237gnome_vfs_mime_remove_application_from_short_list (const char *mime_type,
1238                                                   const char *application_id)
1239{
1240        GnomeVFSResult result;
1241        GList *old_list, *new_list;
1242        gboolean was_in_list;
1243
1244        old_list = gnome_vfs_mime_get_short_list_applications (mime_type);
1245        old_list = gnome_vfs_mime_remove_application_from_list
1246                (old_list, application_id, &was_in_list);
1247
1248        if (!was_in_list) {
1249                result = GNOME_VFS_OK;
1250        } else {
1251                new_list = gnome_vfs_mime_id_list_from_application_list (old_list);
1252                result = gnome_vfs_mime_set_short_list_applications (mime_type, new_list);
1253                g_list_free_deep (new_list);
1254        }
1255
1256        gnome_vfs_mime_application_list_free (old_list);
1257
1258        return result;
1259}
1260
1261GnomeVFSResult
1262gnome_vfs_mime_add_component_to_short_list (const char *mime_type,
1263                                            const char *iid)
1264{
1265        GnomeVFSResult result;
1266        GList *old_list, *new_list;
1267
1268        old_list = gnome_vfs_mime_get_short_list_components (mime_type);
1269
1270        if (gnome_vfs_mime_id_in_component_list (iid, old_list)) {
1271                result = GNOME_VFS_OK;
1272        } else {
1273                new_list = g_list_append (gnome_vfs_mime_id_list_from_component_list (old_list),
1274                                          g_strdup (iid));
1275                result = gnome_vfs_mime_set_short_list_components (mime_type, new_list);
1276                g_list_free_deep (new_list);
1277        }
1278
1279        gnome_vfs_mime_component_list_free (old_list);
1280
1281        return result;
1282}
1283
1284/**
1285 * gnome_vfs_mime_remove_component_from_list:
1286 *
1287 * Remove a component specified by iid from a list of OAF_ServerInfos.
1288 *
1289 * @components: A GList * whose nodes are OAF_ServerInfos, such as the
1290 * result of gnome_vfs_mime_get_short_list_components.
1291 * @iid: The iid of a component to remove from @components.
1292 * @did_remove: If non-NULL, this is filled in with TRUE if the component
1293 * was found in the list, FALSE otherwise.
1294 *
1295 * Return value: The modified list. If the component is not found, the list will
1296 * be unchanged.
1297 */
1298GList *
1299gnome_vfs_mime_remove_component_from_list (GList *components,
1300                                           const char *iid,
1301                                           gboolean *did_remove)
1302{
1303        GList *matching_node;
1304       
1305        matching_node = g_list_find_custom
1306                (components, (gpointer)iid,
1307                 (GCompareFunc) gnome_vfs_mime_component_matches_id);
1308        if (matching_node != NULL) {
1309                components = g_list_remove_link (components, matching_node);
1310                gnome_vfs_mime_component_list_free (matching_node);
1311        }
1312
1313        if (did_remove != NULL) {
1314                *did_remove = matching_node != NULL;
1315        }
1316        return components;
1317}
1318
1319GnomeVFSResult
1320gnome_vfs_mime_remove_component_from_short_list (const char *mime_type,
1321                                                 const char *iid)
1322{
1323        GnomeVFSResult result;
1324        GList *old_list, *new_list;
1325        gboolean was_in_list;
1326
1327        old_list = gnome_vfs_mime_get_short_list_components (mime_type);
1328        old_list = gnome_vfs_mime_remove_component_from_list
1329                (old_list, iid, &was_in_list);
1330
1331        if (!was_in_list) {
1332                result = GNOME_VFS_OK;
1333        } else {
1334                new_list = gnome_vfs_mime_id_list_from_component_list (old_list);
1335                result = gnome_vfs_mime_set_short_list_components (mime_type, new_list);
1336                g_list_free_deep (new_list);
1337        }
1338
1339        gnome_vfs_mime_component_list_free (old_list);
1340
1341        return result;
1342}
1343
1344/**
1345 * gnome_vfs_mime_add_extension:
1346 *
1347 * Add an extension mapping to specified mime type.
1348 *
1349 * @mime_type: The mime type to add the mapping to.
1350 *
1351 * @extension: The extension to add.
1352 *
1353 * Return value: None
1354 */
1355 
1356GnomeVFSResult
1357gnome_vfs_mime_add_extension (const char *mime_type, const char *extension)
1358{
1359        GnomeVFSResult result;
1360        GList *list, *element;
1361        gchar *extensions, *old_extensions;
1362
1363        extensions = NULL;
1364        old_extensions = NULL;
1365
1366        result = GNOME_VFS_OK;
1367       
1368        list = gnome_vfs_mime_get_extensions_list (mime_type); 
1369        if (list == NULL) {
1370                /* List is NULL. This means there are no current registered extensions.
1371                 * Add the new extension and it will cause the list to be created next time.
1372                 */
1373                result = gnome_vfs_mime_set_registered_type_key (mime_type, "ext", extension);
1374                return result;
1375        }
1376
1377        /* Check for duplicates */
1378        for (element = list; element != NULL; element = element->next) {
1379                if (strcmp (extension, (char *)element->data) == 0) {                                   
1380                        gnome_vfs_mime_extensions_list_free (list);
1381                        return result;
1382                }
1383        }
1384
1385        /* Add new extension to list */
1386        for (element = list; element != NULL; element = element->next) {               
1387                if (extensions != NULL) {
1388                        old_extensions = extensions;
1389                        extensions = g_strdup_printf ("%s %s", old_extensions, (char *)element->data);
1390                        g_free (old_extensions);
1391                } else {
1392                        extensions = g_strdup_printf ("%s", (char *)element->data);
1393                }
1394        }
1395       
1396        if (extensions != NULL) {
1397                old_extensions = extensions;
1398                extensions = g_strdup_printf ("%s %s", old_extensions, extension);
1399                g_free (old_extensions);
1400
1401                /* Add extensions to hash table and flush into the file. */
1402                gnome_vfs_mime_set_registered_type_key (mime_type, "ext", extensions);
1403        }
1404       
1405        gnome_vfs_mime_extensions_list_free (list);
1406
1407        return result;
1408}
1409
1410GnomeVFSResult
1411gnome_vfs_mime_remove_extension (const char *mime_type, const char *extension)
1412{
1413        GList *list, *element;
1414        gchar *extensions, *old_extensions;
1415        gboolean in_list;
1416        GnomeVFSResult result;
1417
1418        result = GNOME_VFS_OK;
1419        extensions = NULL;
1420        old_extensions = NULL;
1421        in_list = FALSE;
1422       
1423        list = gnome_vfs_mime_get_extensions_list (mime_type); 
1424        if (list == NULL) {
1425                return result;
1426        }
1427
1428        /* See if extension is in list */
1429        for (element = list; element != NULL; element = element->next) {
1430                if (strcmp (extension, (char *)element->data) == 0) {                                   
1431                        /* Remove extension from list */                       
1432                        in_list = TRUE;
1433                        list = g_list_remove (list, element->data);
1434                        g_free (element->data);
1435                        element = NULL;
1436                }
1437
1438                if (in_list) {
1439                        break;
1440                }
1441        }
1442
1443        /* Exit if we found no match */
1444        if (!in_list) {
1445                gnome_vfs_mime_extensions_list_free (list);
1446                return result;
1447        }
1448       
1449        /* Create new extension list */
1450        for (element = list; element != NULL; element = element->next) {               
1451                if (extensions != NULL) {
1452                        old_extensions = extensions;
1453                        extensions = g_strdup_printf ("%s %s", old_extensions, (char *)element->data);
1454                        g_free (old_extensions);
1455                } else {
1456                        extensions = g_strdup_printf ("%s", (char *)element->data);
1457                }
1458        }
1459       
1460        if (extensions != NULL) {
1461                /* Add extensions to hash table and flush into the file */
1462                gnome_vfs_mime_set_registered_type_key (mime_type, "ext", extensions);
1463        }
1464       
1465        gnome_vfs_mime_extensions_list_free (list);
1466
1467        return result;
1468}
1469
1470
1471GnomeVFSResult
1472gnome_vfs_mime_extend_all_applications (const char *mime_type,
1473                                        GList *application_ids)
1474{
1475        GList *li;
1476
1477        g_return_val_if_fail (mime_type != NULL, GNOME_VFS_ERROR_INTERNAL);
1478
1479        for (li = application_ids; li != NULL; li = li->next) {
1480                const char *application_id = li->data;
1481                gnome_vfs_application_registry_add_mime_type (application_id,
1482                                                              mime_type);
1483        }
1484
1485        return gnome_vfs_application_registry_sync ();
1486}
1487
1488GnomeVFSResult
1489gnome_vfs_mime_remove_from_all_applications (const char *mime_type,
1490                                             GList *application_ids)
1491{
1492        GList *li;
1493
1494        g_return_val_if_fail (mime_type != NULL, GNOME_VFS_ERROR_INTERNAL);
1495
1496        for (li = application_ids; li != NULL; li = li->next) {
1497                const char *application_id = li->data;
1498                gnome_vfs_application_registry_remove_mime_type (application_id,
1499                                                                 mime_type);
1500        }
1501
1502        return gnome_vfs_application_registry_sync ();
1503}
1504
1505GnomeVFSMimeApplication *
1506gnome_vfs_mime_application_copy (GnomeVFSMimeApplication *application)
1507{
1508        GnomeVFSMimeApplication *result;
1509
1510        if (application == NULL) {
1511                return NULL;
1512        }
1513       
1514        result = g_new0 (GnomeVFSMimeApplication, 1);
1515        result->id = g_strdup (application->id);
1516        result->name = g_strdup (application->name);
1517        result->command = g_strdup (application->command);
1518        result->can_open_multiple_files = application->can_open_multiple_files;
1519        result->can_open_uris = application->can_open_uris;
1520
1521        return result;
1522}
1523
1524void
1525gnome_vfs_mime_application_free (GnomeVFSMimeApplication *application)
1526{
1527        if (application != NULL) {
1528                g_free (application->name);
1529                g_free (application->command);
1530                g_free (application->id);
1531                g_free (application);
1532        }
1533}
1534
1535
1536void
1537gnome_vfs_mime_action_free (GnomeVFSMimeAction *action)
1538{
1539        switch (action->action_type) {
1540        case GNOME_VFS_MIME_ACTION_TYPE_APPLICATION:
1541                gnome_vfs_mime_application_free (action->action.application);
1542                break;
1543        case GNOME_VFS_MIME_ACTION_TYPE_COMPONENT:
1544                CORBA_free (action->action.component);
1545                break;
1546        default:
1547                g_assert_not_reached ();
1548        }
1549
1550        g_free (action);
1551}
1552
1553void
1554gnome_vfs_mime_application_list_free (GList *list)
1555{
1556        g_list_foreach (list, (GFunc) gnome_vfs_mime_application_free, NULL);
1557        g_list_free (list);
1558}
1559
1560void
1561gnome_vfs_mime_component_list_free (GList *list)
1562{
1563        g_list_foreach (list, (GFunc) CORBA_free, NULL);
1564        g_list_free (list);
1565}
1566
1567static char *
1568extract_prefix_add_suffix (const char *string, const char *separator, const char *suffix)
1569{
1570        const char *separator_position;
1571        int prefix_length;
1572        char *result;
1573
1574        separator_position = strstr (string, separator);
1575        prefix_length = separator_position == NULL
1576                ? strlen (string)
1577                : separator_position - string;
1578
1579        result = g_malloc (prefix_length + strlen(suffix) + 1);
1580       
1581        strncpy (result, string, prefix_length);
1582        result[prefix_length] = '\0';
1583
1584        strcat (result, suffix);
1585
1586        return result;
1587}
1588
1589static char *
1590mime_type_get_supertype (const char *mime_type)
1591{
1592        if (mime_type == NULL) {
1593                return NULL;
1594        }
1595        return extract_prefix_add_suffix (mime_type, "/", "/*");
1596}
1597
1598
1599static char **
1600strsplit_handle_null (const char *str, const char *delim, int max)
1601{
1602        return g_strsplit ((str == NULL ? "" : str), delim, max);
1603}
1604
1605GnomeVFSMimeApplication *
1606gnome_vfs_mime_application_new_from_id (const char *id)
1607{
1608        GnomeVFSMimeApplication *application;
1609
1610        application = gnome_vfs_application_registry_get_mime_application (id);
1611
1612        return application;
1613}
1614
1615static char *
1616strdup_to (const char *string, const char *end)
1617{
1618        if (end == NULL) {
1619                return g_strdup (string);
1620        }
1621        return g_strndup (string, end - string);
1622}
1623
1624static gboolean
1625is_executable_file (const char *path)
1626{
1627        struct stat stat_buffer;
1628
1629        /* Check that it exists. */
1630        if (stat (path, &stat_buffer) != 0) {
1631                return FALSE;
1632        }
1633
1634        /* Check that it is a file. */
1635        if (!S_ISREG (stat_buffer.st_mode)) {
1636                return FALSE;
1637        }
1638
1639        /* Check that it's executable. */
1640        if (access (path, X_OK) != 0) {
1641                return FALSE;
1642        }
1643
1644        return TRUE;
1645}
1646
1647static gboolean
1648executable_in_path (const char *executable_name)
1649{
1650        const char *path_list, *piece_start, *piece_end;
1651        char *piece, *path;
1652        gboolean is_good;
1653
1654        path_list = g_getenv ("PATH");
1655
1656        for (piece_start = path_list; ; piece_start = piece_end + 1) {
1657                /* Find the next piece of PATH. */
1658                piece_end = strchr (piece_start, ':');
1659                piece = strdup_to (piece_start, piece_end);
1660                g_strstrip (piece);
1661               
1662                if (piece[0] == '\0') {
1663                        is_good = FALSE;
1664                } else {
1665                        /* Try out this path with the executable. */
1666                        path = g_strconcat (piece, "/", executable_name, NULL);
1667                        is_good = is_executable_file (path);
1668                        g_free (path);
1669                }
1670               
1671                g_free (piece);
1672               
1673                if (is_good) {
1674                        return TRUE;
1675                }
1676
1677                if (piece_end == NULL) {
1678                        return FALSE;
1679                }
1680        }
1681}
1682
1683static char *
1684get_executable_name_from_command_string (const char *command)
1685{
1686        /* FIXME bugzilla.eazel.com 2757: Do we need to handle quoting? */
1687        return strdup_to (command, strchr (command, ' '));
1688}
1689
1690static gboolean
1691application_known_to_be_nonexistent (const char *application_id)
1692{
1693        const char *command;
1694        char *executable_name;
1695        gboolean found;
1696
1697        g_return_val_if_fail (application_id != NULL, FALSE);
1698
1699        command = gnome_vfs_application_registry_peek_value
1700                (application_id,
1701                 GNOME_VFS_APPLICATION_REGISTRY_COMMAND);
1702
1703        if (command == NULL) {
1704                return TRUE;
1705        }
1706
1707        executable_name = get_executable_name_from_command_string (command);
1708        g_strstrip (executable_name);
1709        found = executable_in_path (executable_name);
1710        g_free (executable_name);
1711
1712        return !found;
1713}
1714
1715static GList *
1716prune_ids_for_nonexistent_applications (GList *list)
1717{
1718        GList *p, *next;
1719
1720        for (p = list; p != NULL; p = next) {
1721                next = p->next;
1722
1723                if (application_known_to_be_nonexistent (p->data)) {
1724                        list = g_list_remove_link (list, p);
1725                        g_free (p->data);
1726                        g_list_free (p);
1727                }
1728        }
1729
1730        return list;
1731}
1732
1733static GList *
1734OAF_ServerInfoList_to_ServerInfo_g_list (OAF_ServerInfoList *info_list)
1735{
1736        GList *retval;
1737        int i;
1738       
1739        retval = NULL;
1740        if (info_list != NULL && info_list->_length > 0) {
1741                for (i = 0; i < info_list->_length; i++) {
1742                        retval = g_list_prepend (retval, OAF_ServerInfo_duplicate (&info_list->_buffer[i]));
1743                }
1744                retval = g_list_reverse (retval);
1745        }
1746
1747        return retval;
1748}
1749
1750static void
1751unref_gconf_engine (void)
1752{
1753        gconf_engine_unref (gconf_engine);
1754}
1755
1756/* Returns the Nautilus user level, a string.
1757 * This does beg the question: Why does gnome-vfs have the Nautilus
1758 * user level coded into it? Eventually we might want to call this the
1759 * GNOME user level or something if we can figure out a clear concept
1760 * that works across GNOME.
1761 */
1762static char *
1763get_user_level (void)
1764{
1765        char *user_level = NULL;
1766
1767        /* Create the gconf engine once. */
1768        if (gconf_engine == NULL) {
1769                /* This sequence is needed in case no one has initialized GConf. */
1770                if (!gconf_is_initialized ()) {
1771                        char *fake_argv[] = { "gnome-vfs", NULL };
1772                        gconf_init (1, fake_argv, NULL);
1773                }
1774
1775                gconf_engine = gconf_engine_get_default ();
1776                g_atexit (unref_gconf_engine);
1777        }
1778
1779        user_level = gconf_engine_get_string (gconf_engine, "/apps/nautilus/user_level", NULL);
1780
1781        if (user_level == NULL) {
1782                user_level = g_strdup ("novice");
1783        }
1784
1785        /* If value is invalid, assume "novice". */
1786        if (strcmp (user_level, "novice") != 0 &&
1787            strcmp (user_level, "intermediate") != 0 &&
1788            strcmp (user_level, "hacker") != 0) {
1789                g_free (user_level);
1790                user_level = g_strdup ("novice");
1791        }
1792
1793        return user_level;
1794}
1795
1796
1797
1798
1799
1800static GList *
1801gnome_vfs_strsplit_to_list (const char *str, const char *delim, int max)
1802{
1803        char **strv;
1804        GList *retval;
1805        int i;
1806
1807        strv = strsplit_handle_null (str, delim, max);
1808
1809        retval = NULL;
1810
1811        for (i = 0; strv[i] != NULL; i++) {
1812                retval = g_list_prepend (retval, strv[i]);
1813        }
1814
1815        retval = g_list_reverse (retval);
1816       
1817        /* Don't strfreev, since we didn't copy the individual strings. */
1818        g_free (strv);
1819
1820        return retval;
1821}
1822
1823static char *
1824gnome_vfs_strjoin_from_list (const char *separator, GList *list)
1825{
1826        char **strv;
1827        int i;
1828        GList *p;
1829        char *retval;
1830
1831        strv = g_new0 (char *, (g_list_length (list) + 1));
1832
1833        for (p = list, i = 0; p != NULL; p = p->next, i++) {
1834                strv[i] = p->data;
1835        }
1836
1837        retval = g_strjoinv (separator, strv);
1838
1839        g_free (strv);
1840
1841        return retval;
1842}
1843
1844static GList *
1845comma_separated_str_to_str_list (const char *str)
1846{
1847        return gnome_vfs_strsplit_to_list (str, ",", 0);
1848}
1849
1850static char *
1851str_list_to_comma_separated_str (GList *list)
1852{
1853        return gnome_vfs_strjoin_from_list (",", list);
1854}
1855
1856
1857static GList *
1858str_list_difference (GList *a, GList *b)
1859{
1860        GList *p;
1861        GList *retval;
1862
1863        retval = NULL;
1864
1865        for (p = a; p != NULL; p = p->next) {
1866                if (g_list_find_custom (b, p->data, (GCompareFunc) strcmp) == NULL) {
1867                        retval = g_list_prepend (retval, p->data);
1868                }
1869        }
1870
1871        retval = g_list_reverse (retval);
1872        return retval;
1873}
Note: See TracBrowser for help on using the repository browser.