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

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