ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / modules / desktop-method.c.network-uri
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */
2
3 /* desktop-method.c
4
5    Copyright (C) 2001 Red Hat, 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
23 /* URI scheme for remapping directories under magic URIs, used
24  * for the magic desktop file directories such as start-here.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <glib.h>
32 #include <sys/types.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41
42 #include <libgnomevfs/gnome-vfs-mime.h>
43
44 #include <libgnomevfs/gnome-vfs-module.h>
45 #include <libgnomevfs/gnome-vfs-method.h>
46 #include <libgnomevfs/gnome-vfs-utils.h>
47 #include <libgnomevfs/gnome-vfs-ops.h>
48 #include <libgnomevfs/gnome-vfs-module-shared.h>
49 #include <libgnomevfs/gnome-vfs-monitor-private.h>
50
51 /* FIXME Maybe when chaining to file:, we should call the gnome-vfs wrapper
52  * functions, instead of the file: methods directly.
53  */
54
55 #define N_ELEMENTS(arr)         (sizeof (arr) / sizeof ((arr)[0]))
56
57 static GnomeVFSURI* desktop_uri_to_file_uri (GnomeVFSURI *desktop_uri);
58
59 static GnomeVFSResult open_merged_directory (GnomeVFSMethod *method,
60                                              GnomeVFSMethodHandle **method_handle,
61                                              GnomeVFSURI *uri,
62                                              GnomeVFSFileInfoOptions options,
63                                              GnomeVFSContext *context);
64
65 static char*         create_file_uri_in_dir (const char  *dir,
66                                              const char  *filename);
67
68 static GnomeVFSMethod *parent_method = NULL;
69
70 static GnomeVFSResult
71 do_open (GnomeVFSMethod *method,
72          GnomeVFSMethodHandle **method_handle,
73          GnomeVFSURI *uri,
74          GnomeVFSOpenMode mode,
75          GnomeVFSContext *context)
76 {
77         GnomeVFSURI *file_uri;
78         GnomeVFSResult result;
79
80         file_uri = desktop_uri_to_file_uri (uri);
81         result = (* parent_method->open) (parent_method,
82                                           method_handle,
83                                           file_uri,
84                                           mode,
85                                           context);
86         gnome_vfs_uri_unref (file_uri);
87
88         return result;
89 }
90
91 static GnomeVFSResult
92 do_create (GnomeVFSMethod *method,
93            GnomeVFSMethodHandle **method_handle,
94            GnomeVFSURI *uri,
95            GnomeVFSOpenMode mode,
96            gboolean exclusive,
97            guint perm,
98            GnomeVFSContext *context)
99 {
100         GnomeVFSURI *file_uri;
101         GnomeVFSResult result;
102
103         file_uri = desktop_uri_to_file_uri (uri);
104         result = (* parent_method->create) (parent_method,
105                                             method_handle,
106                                             file_uri,
107                                             mode,
108                                             exclusive,
109                                             perm,
110                                             context);
111         gnome_vfs_uri_unref (file_uri);
112
113         return result;
114 }
115
116 static GnomeVFSResult
117 do_close (GnomeVFSMethod *method,
118           GnomeVFSMethodHandle *method_handle,
119           GnomeVFSContext *context)
120 {
121         GnomeVFSResult result;
122         
123         result = (* parent_method->close) (parent_method,
124                                            method_handle,
125                                            context);
126
127         return result;
128 }
129
130 static GnomeVFSResult
131 do_read (GnomeVFSMethod *method,
132          GnomeVFSMethodHandle *method_handle,
133          gpointer buffer,
134          GnomeVFSFileSize num_bytes,
135          GnomeVFSFileSize *bytes_read,
136          GnomeVFSContext *context)
137 {
138         GnomeVFSResult result;
139         
140         result = (* parent_method->read) (parent_method,
141                                           method_handle,
142                                           buffer, num_bytes,
143                                           bytes_read,
144                                           context);
145
146         return result;
147 }
148
149 static GnomeVFSResult
150 do_write (GnomeVFSMethod *method,
151           GnomeVFSMethodHandle *method_handle,
152           gconstpointer buffer,
153           GnomeVFSFileSize num_bytes,
154           GnomeVFSFileSize *bytes_written,
155           GnomeVFSContext *context)
156 {
157         GnomeVFSResult result;
158         
159         result = (* parent_method->write) (parent_method,
160                                            method_handle,
161                                            buffer, num_bytes,
162                                            bytes_written,
163                                            context);
164
165         return result;
166 }
167
168
169 static GnomeVFSResult
170 do_seek (GnomeVFSMethod *method,
171          GnomeVFSMethodHandle *method_handle,
172          GnomeVFSSeekPosition whence,
173          GnomeVFSFileOffset offset,
174          GnomeVFSContext *context)
175 {
176         GnomeVFSResult result;
177         
178         result = (* parent_method->seek) (parent_method,
179                                           method_handle,
180                                           whence, offset,
181                                           context);
182
183         return result;
184 }
185
186 static GnomeVFSResult
187 do_tell (GnomeVFSMethod *method,
188          GnomeVFSMethodHandle *method_handle,
189          GnomeVFSFileOffset *offset_return)
190 {
191         GnomeVFSResult result;
192         
193         result = (* parent_method->tell) (parent_method,
194                                           method_handle,
195                                           offset_return);
196
197         return result;
198 }
199
200
201 static GnomeVFSResult
202 do_truncate_handle (GnomeVFSMethod *method,
203                     GnomeVFSMethodHandle *method_handle,
204                     GnomeVFSFileSize where,
205                     GnomeVFSContext *context)
206 {
207         GnomeVFSResult result;
208         
209         result = (* parent_method->truncate_handle) (parent_method,
210                                                      method_handle,
211                                                      where,
212                                                      context);
213
214         return result;
215 }
216
217 static GnomeVFSResult
218 do_truncate (GnomeVFSMethod *method,
219              GnomeVFSURI *uri,
220              GnomeVFSFileSize where,
221              GnomeVFSContext *context)
222 {
223         GnomeVFSURI *file_uri;
224         GnomeVFSResult result;
225
226         file_uri = desktop_uri_to_file_uri (uri);
227         result = (* parent_method->truncate) (parent_method,
228                                               file_uri,
229                                               where,
230                                               context);
231
232         gnome_vfs_uri_unref (file_uri);
233
234         return result;
235 }
236
237 typedef struct _DirHandle DirHandle;
238
239 struct _DirHandle
240 {
241         GSList *next;
242         GSList *handles;
243 };
244
245 static GnomeVFSResult
246 do_open_directory (GnomeVFSMethod *method,
247                    GnomeVFSMethodHandle **method_handle,
248                    GnomeVFSURI *uri,
249                    GnomeVFSFileInfoOptions options,
250                    GnomeVFSContext *context)
251 {
252         return open_merged_directory (method, method_handle,
253                                       uri, options, context);
254 }
255
256 static GnomeVFSResult
257 do_close_directory (GnomeVFSMethod *method,
258                     GnomeVFSMethodHandle *method_handle,
259                     GnomeVFSContext *context)
260 {
261         GnomeVFSResult result;
262         GSList *tmp;
263         DirHandle *dh;
264
265         dh = (DirHandle*) method_handle;
266
267         result = GNOME_VFS_OK;
268         tmp = dh->handles;
269         while (tmp != NULL) {
270                 GnomeVFSResult this_result;
271                 
272                 this_result = (* parent_method->close_directory) (parent_method,
273                                                                   tmp->data,
274                                                                   context);
275
276                 if (this_result != GNOME_VFS_OK)
277                         result = this_result;
278                 
279                 tmp = tmp->next;
280         }
281
282         g_slist_free (dh->handles);
283         g_free (dh);
284         
285         return result;
286 }
287
288 static GnomeVFSResult
289 do_read_directory (GnomeVFSMethod *method,
290                    GnomeVFSMethodHandle *method_handle,
291                    GnomeVFSFileInfo *file_info,
292                    GnomeVFSContext *context)
293 {
294         GnomeVFSResult result;
295         GnomeVFSMethodHandle *parent_handle;
296         DirHandle *dh;
297
298         dh = (DirHandle*) method_handle;
299
300         if (dh->next == NULL) {
301                 return GNOME_VFS_ERROR_EOF;
302         }
303
304  next:
305         parent_handle = dh->next->data;
306         
307         result = (* parent_method->read_directory) (parent_method,
308                                                     parent_handle,
309                                                     file_info,
310                                                     context);
311
312         if (result != GNOME_VFS_OK) {
313                 dh->next = dh->next->next;
314                 if (dh->next)
315                         goto next;
316                 else
317                         return result;
318         } else {
319                 return GNOME_VFS_OK;
320         }
321 }
322
323
324 static void
325 set_directory_mime_type (GnomeVFSFileInfo *file_info)
326 {
327         g_free (file_info->mime_type);
328
329         file_info->mime_type = g_strdup ("x-directory/vfolder-desktop");
330         file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
331 }
332
333 static GnomeVFSResult
334 do_get_file_info (GnomeVFSMethod *method,
335                   GnomeVFSURI *uri,
336                   GnomeVFSFileInfo *file_info,
337                   GnomeVFSFileInfoOptions options,
338                   GnomeVFSContext *context)
339 {
340         GnomeVFSURI *file_uri;
341         GnomeVFSResult result;
342
343         file_uri = desktop_uri_to_file_uri (uri);
344         result = (* parent_method->get_file_info) (parent_method,
345                                                    file_uri,
346                                                    file_info,
347                                                    options,
348                                                    context);
349
350         if (file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
351                 set_directory_mime_type (file_info);
352         
353         gnome_vfs_uri_unref (file_uri);
354
355         return result;
356 }
357
358 static GnomeVFSResult
359 do_get_file_info_from_handle (GnomeVFSMethod *method,
360                               GnomeVFSMethodHandle *method_handle,
361                               GnomeVFSFileInfo *file_info,
362                               GnomeVFSFileInfoOptions options,
363                               GnomeVFSContext *context)
364 {
365         GnomeVFSResult result;
366
367         result = (* parent_method->get_file_info_from_handle) (parent_method,
368                                                                method_handle,
369                                                                file_info,
370                                                                options,
371                                                                context);
372
373         if (file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
374                 set_directory_mime_type (file_info);
375
376         return result;
377 }
378
379
380 static gboolean
381 do_is_local (GnomeVFSMethod *method,
382              const GnomeVFSURI *uri)
383 {
384         return TRUE;
385 }
386
387
388 static GnomeVFSResult
389 do_make_directory (GnomeVFSMethod *method,
390                    GnomeVFSURI *uri,
391                    guint perm,
392                    GnomeVFSContext *context)
393 {
394         GnomeVFSURI *file_uri;
395         GnomeVFSResult result;
396
397         file_uri = desktop_uri_to_file_uri (uri);
398         result = (* parent_method->make_directory) (parent_method,
399                                                     file_uri,
400                                                     perm,
401                                                     context);
402         
403         gnome_vfs_uri_unref (file_uri);
404
405         return result;
406 }
407
408 static GnomeVFSResult
409 do_remove_directory (GnomeVFSMethod *method,
410                      GnomeVFSURI *uri,
411                      GnomeVFSContext *context)
412 {
413         GnomeVFSURI *file_uri;
414         GnomeVFSResult result;
415
416         file_uri = desktop_uri_to_file_uri (uri);
417         result = (* parent_method->remove_directory) (parent_method,
418                                                       file_uri,
419                                                       context);
420         
421         gnome_vfs_uri_unref (file_uri);
422
423         return result;
424 }
425
426 static GnomeVFSResult
427 do_find_directory (GnomeVFSMethod *method,
428                    GnomeVFSURI *near_uri,
429                    GnomeVFSFindDirectoryKind kind,
430                    GnomeVFSURI **result_uri,
431                    gboolean create_if_needed,
432                    gboolean find_if_needed,
433                    guint permissions,
434                    GnomeVFSContext *context)
435 {
436         GnomeVFSURI *file_uri;
437         GnomeVFSURI *file_result_uri;
438         GnomeVFSResult result;
439
440         file_result_uri = NULL;
441         file_uri = desktop_uri_to_file_uri (near_uri);
442         result = (* parent_method->find_directory) (parent_method,
443                                                     file_uri,
444                                                     kind,
445                                                     &file_result_uri,
446                                                     create_if_needed,
447                                                     find_if_needed,
448                                                     permissions,
449                                                     context);
450         
451         gnome_vfs_uri_unref (file_uri);
452
453         if (result_uri)
454                 *result_uri = file_result_uri;
455         
456         if (file_result_uri == NULL)
457                 result = GNOME_VFS_ERROR_NOT_FOUND;
458                 
459         return result;
460 }
461
462 static GnomeVFSResult
463 do_move (GnomeVFSMethod *method,
464          GnomeVFSURI *old_uri,
465          GnomeVFSURI *new_uri,
466          gboolean force_replace,
467          GnomeVFSContext *context)
468 {
469         GnomeVFSURI *old_file_uri;
470         GnomeVFSURI *new_file_uri;
471         GnomeVFSResult result;
472
473         old_file_uri = desktop_uri_to_file_uri (old_uri);
474         new_file_uri = desktop_uri_to_file_uri (new_uri);
475
476         result = (* parent_method->move) (parent_method,
477                                           old_file_uri,
478                                           new_file_uri,
479                                           force_replace,
480                                           context);
481         gnome_vfs_uri_unref (old_file_uri);
482         gnome_vfs_uri_unref (new_file_uri);
483
484         return result;
485 }
486
487 static GnomeVFSResult
488 do_unlink (GnomeVFSMethod *method,
489            GnomeVFSURI *uri,
490            GnomeVFSContext *context)
491 {
492         GnomeVFSURI *file_uri;
493         GnomeVFSResult result;
494
495         file_uri = desktop_uri_to_file_uri (uri);
496         result = (* parent_method->unlink) (parent_method,
497                                             file_uri,
498                                             context);
499         
500         gnome_vfs_uri_unref (file_uri);
501
502         return result;  
503 }
504
505 static GnomeVFSResult
506 do_create_symbolic_link (GnomeVFSMethod *method,
507                          GnomeVFSURI *uri,
508                          const char *target_reference,
509                          GnomeVFSContext *context)
510 {
511         GnomeVFSURI *file_uri;
512         GnomeVFSResult result;
513
514         file_uri = desktop_uri_to_file_uri (uri);
515         result = (* parent_method->create_symbolic_link) (parent_method,
516                                                           file_uri,
517                                                           target_reference,
518                                                           context);
519         
520         gnome_vfs_uri_unref (file_uri);
521
522         return result;  
523 }
524
525 static GnomeVFSResult
526 do_check_same_fs (GnomeVFSMethod *method,
527                   GnomeVFSURI *source_uri,
528                   GnomeVFSURI *target_uri,
529                   gboolean *same_fs_return,
530                   GnomeVFSContext *context)
531 {
532         GnomeVFSURI *source_file_uri;
533         GnomeVFSURI *target_file_uri;
534         GnomeVFSResult result;
535
536         source_file_uri = desktop_uri_to_file_uri (source_uri);
537         target_file_uri = desktop_uri_to_file_uri (target_uri);
538
539         result = (* parent_method->check_same_fs) (parent_method,
540                                                    source_file_uri,
541                                                    target_file_uri,
542                                                    same_fs_return,
543                                                    context);
544         gnome_vfs_uri_unref (source_file_uri);
545         gnome_vfs_uri_unref (target_file_uri);
546
547         return result;  
548 }
549
550 static GnomeVFSResult
551 do_set_file_info (GnomeVFSMethod *method,
552                   GnomeVFSURI *uri,
553                   const GnomeVFSFileInfo *info,
554                   GnomeVFSSetFileInfoMask mask,
555                   GnomeVFSContext *context)
556 {
557         GnomeVFSURI *file_uri;
558         GnomeVFSResult result;
559
560         file_uri = desktop_uri_to_file_uri (uri);
561         result = (* parent_method->set_file_info) (parent_method,
562                                                    file_uri,
563                                                    info,
564                                                    mask,
565                                                    context);
566         
567         gnome_vfs_uri_unref (file_uri);
568
569         return result;  
570 }
571
572 typedef struct {
573         GnomeVFSMonitorHandle *handle;
574         GnomeVFSURI           *desktop_uri;
575 } DesktopMonitorHandle;
576
577 static void 
578 monitor_notify_cb (GnomeVFSMonitorHandle    *handle,
579                    const gchar              *monitor_uri,
580                    const gchar              *info_uri,
581                    GnomeVFSMonitorEventType  event_type,
582                    gpointer                  user_data)
583 {
584         DesktopMonitorHandle *monitor_handle;
585         GnomeVFSURI *desktop_info_uri;
586         const gchar *uri_diff;
587         gint monitor_uri_len;
588
589         monitor_handle = (DesktopMonitorHandle *) user_data;
590         desktop_info_uri = NULL;
591         monitor_uri_len = strlen (monitor_uri);
592
593         if (info_uri != NULL &&
594             strncmp (info_uri, monitor_uri, monitor_uri_len) == 0) {
595                 uri_diff = &info_uri [monitor_uri_len];
596
597                 if (*uri_diff != '\0') {
598                         desktop_info_uri = 
599                                 gnome_vfs_uri_append_string (
600                                         monitor_handle->desktop_uri,
601                                         uri_diff);
602                 } else {
603                         desktop_info_uri = monitor_handle->desktop_uri;
604                         gnome_vfs_uri_ref (desktop_info_uri);
605                 }
606         }
607
608         gnome_vfs_monitor_callback ((GnomeVFSMethodHandle *) monitor_handle,
609                                     desktop_info_uri,
610                                     event_type);
611
612         gnome_vfs_uri_unref (desktop_info_uri);
613 }
614
615 static GnomeVFSResult
616 do_monitor_add (GnomeVFSMethod *method,
617                 GnomeVFSMethodHandle **method_handle_return,
618                 GnomeVFSURI *uri,
619                 GnomeVFSMonitorType monitor_type)
620 {
621         DesktopMonitorHandle *monitor_handle;
622         GnomeVFSURI *file_uri;
623         GnomeVFSResult result;
624
625         monitor_handle = g_new0 (DesktopMonitorHandle, 1);
626         monitor_handle->desktop_uri = uri;
627         gnome_vfs_uri_ref (uri);
628
629         file_uri = desktop_uri_to_file_uri (uri);
630         result = gnome_vfs_monitor_do_add (parent_method,
631                                            &monitor_handle->handle,
632                                            file_uri,
633                                            monitor_type,
634                                            monitor_notify_cb,
635                                            monitor_handle);
636         gnome_vfs_uri_unref (file_uri);
637
638         if (result != GNOME_VFS_OK) {
639                 gnome_vfs_uri_unref (monitor_handle->desktop_uri);
640                 g_free (monitor_handle);
641         }
642
643         *method_handle_return = (GnomeVFSMethodHandle *) monitor_handle;
644
645         return result;  
646 }
647
648 static GnomeVFSResult
649 do_monitor_cancel (GnomeVFSMethod *method,
650                    GnomeVFSMethodHandle *method_handle)
651 {
652         DesktopMonitorHandle *monitor_handle;
653         GnomeVFSResult result;
654
655         monitor_handle = (DesktopMonitorHandle *) method_handle;
656
657         result = gnome_vfs_monitor_do_cancel (monitor_handle->handle);
658
659         gnome_vfs_uri_unref (monitor_handle->desktop_uri);
660         g_free (monitor_handle);
661
662         return result;
663 }
664
665
666 \f
667 /* gnome-vfs bureaucracy */
668
669 static GnomeVFSMethod method = {
670         sizeof (GnomeVFSMethod),
671         do_open,
672         do_create,
673         do_close,
674         do_read,
675         do_write,
676         do_seek,
677         do_tell,
678         do_truncate_handle,
679         do_open_directory,
680         do_close_directory,
681         do_read_directory,
682         do_get_file_info,
683         do_get_file_info_from_handle,
684         do_is_local,
685         do_make_directory,
686         do_remove_directory,
687         do_move,
688         do_unlink,
689         do_check_same_fs,
690         do_set_file_info,
691         do_truncate,
692         do_find_directory,
693         do_create_symbolic_link,
694         do_monitor_add,
695         do_monitor_cancel
696 };
697
698
699 typedef enum
700 {
701         SCHEME_FAVORITES,
702         SCHEME_PREFERENCES,
703         SCHEME_START_HERE,
704         SCHEME_SYSTEM_SETTINGS,
705         SCHEME_SERVER_SETTINGS,
706         SCHEME_PROGRAMS
707 } SchemeID;
708
709 #define MAX_DIRECTORIES 3
710 #define DIRECTORIES_INITIALIZER { NULL, NULL, NULL }
711
712 typedef struct _SchemeDescription SchemeDescription;
713
714 struct _SchemeDescription
715 {
716         SchemeID id;
717         
718         const char *scheme;
719
720         char *directories[MAX_DIRECTORIES];
721 };
722
723 static SchemeDescription schemes[] = 
724 {
725         { SCHEME_FAVORITES, "favorites",
726           DIRECTORIES_INITIALIZER },
727         { SCHEME_PREFERENCES, "preferences",
728           DIRECTORIES_INITIALIZER },
729         { SCHEME_START_HERE, "start-here",
730           DIRECTORIES_INITIALIZER },
731         { SCHEME_SYSTEM_SETTINGS, "system-settings",
732           DIRECTORIES_INITIALIZER },
733         { SCHEME_SERVER_SETTINGS, "server-settings",
734           DIRECTORIES_INITIALIZER },
735         { SCHEME_PROGRAMS, "programs",
736           DIRECTORIES_INITIALIZER }
737 };
738
739 GnomeVFSMethod *
740 vfs_module_init (const char *method_name, 
741                  const char *args)
742 {
743         int i;
744         
745         parent_method = gnome_vfs_method_get ("file");
746
747         if (parent_method == NULL) {
748                 g_error ("Could not find 'file' method for gnome-vfs");
749                 return NULL;
750         }
751
752         i = 0;
753         while (i < N_ELEMENTS (schemes)) {
754                 switch (schemes[i].id) {
755                 case SCHEME_FAVORITES:
756                         schemes[i].directories[0] =
757                                 g_strconcat (g_get_home_dir (),
758                                              "/.gnome/apps",
759                                              NULL);
760                         break;
761                 case SCHEME_PREFERENCES:
762                         /* FIXME I think the GNOME 2 control center will move
763                          * this, but we don't know where to yet
764                          */
765                         schemes[i].directories[0] =
766                                 g_strconcat (DATADIR, "/control-center/capplets", NULL);
767                         break;
768                 case SCHEME_START_HERE:
769                         schemes[i].directories[0] = g_strconcat (SYSCONFDIR,
770                                                                  "/X11/starthere",
771                                                                  NULL);
772                         break;
773                 case SCHEME_SYSTEM_SETTINGS:
774                         schemes[i].directories[0] =
775                                 g_strconcat (SYSCONFDIR, "/X11/sysconfig", NULL);
776                         break;
777                 case SCHEME_SERVER_SETTINGS:
778                         schemes[i].directories[0] =
779                                 g_strconcat (SYSCONFDIR, "/X11/serverconfig", NULL);
780                         break;
781                 case SCHEME_PROGRAMS:
782                         schemes[i].directories[0] = g_strconcat (SYSCONFDIR,
783                                                                  "/X11/applnk",
784                                                                  NULL);
785                         schemes[i].directories[1] =
786                                 g_strconcat (DATADIR, "gnome/apps", NULL);
787                         break;
788                 default:
789                         g_assert_not_reached ();
790                         break;
791                 }
792
793                 ++i;
794         }
795         
796         return &method;
797 }
798
799 void
800 vfs_module_shutdown (GnomeVFSMethod *method)
801 {
802         int i;
803         
804         i = 0;
805         while (i < N_ELEMENTS (schemes)) {
806                 int j;
807
808                 j = 0;
809                 while (j < MAX_DIRECTORIES) {
810                         g_free (schemes[i].directories[j]);
811                         schemes[i].directories[j] = NULL;
812                         ++j;
813                 }
814                 
815                 ++i;
816         }
817 }
818
819 \f
820
821 static const SchemeDescription*
822 get_desc_for_uri (GnomeVFSURI *desktop_uri)
823 {
824         const SchemeDescription *desc;
825         int i;
826         const char *scheme;
827         
828         scheme = gnome_vfs_uri_get_scheme (desktop_uri);
829
830         desc = NULL;
831         i = 0;
832         while (i < N_ELEMENTS (schemes)) {
833                 if (strcmp (schemes[i].scheme, scheme) == 0) {
834                         desc = &schemes[i];
835                         break;
836                 }
837                 
838                 ++i;
839         }
840
841         return desc;
842 }
843
844 static GnomeVFSURI*
845 desktop_uri_to_file_uri (GnomeVFSURI *desktop_uri)
846 {
847         const SchemeDescription *desc;
848         GnomeVFSURI *new_uri;
849         const char *path;
850         int i;
851
852         desc = get_desc_for_uri (desktop_uri);
853
854         if (desc == NULL) {
855                 gnome_vfs_uri_ref (desktop_uri);
856                 return desktop_uri;
857         }
858
859         /* Prepend the base for the desktop URI.
860          * If the SchemeDescription contains > 1 directory, we use the directory
861          * after the first if the given file actually exists there.
862          */
863         new_uri = NULL;
864         path = gnome_vfs_uri_get_path (desktop_uri);
865         i = 0;
866         while (desc->directories[i])
867                 ++i;
868         do {
869                 char *s;
870
871                 --i;
872                 
873                 s = create_file_uri_in_dir (desc->directories[i], path);
874
875                 new_uri = gnome_vfs_uri_new (s);
876
877                 g_free (s);
878                 
879                 if (i == 0 ||
880                     gnome_vfs_uri_exists (new_uri)) {
881                         return new_uri;
882                 } else {
883                         gnome_vfs_uri_unref (new_uri);
884                         new_uri = NULL;
885                 }
886         } while (i > 0);
887
888
889         g_assert_not_reached ();
890
891         return NULL;
892 }
893
894
895 static GnomeVFSResult
896 open_merged_directory (GnomeVFSMethod *method,
897                        GnomeVFSMethodHandle **method_handle,
898                        GnomeVFSURI *desktop_uri,
899                        GnomeVFSFileInfoOptions options,
900                        GnomeVFSContext *context)
901 {
902         GnomeVFSResult result;
903         DirHandle *dh;
904         const SchemeDescription *desc;
905         int i;
906         gboolean found;
907         const char *path;
908         
909         desc = get_desc_for_uri (desktop_uri);
910         
911         if (desc == NULL) {
912                 return GNOME_VFS_ERROR_NOT_FOUND;
913         }
914
915         dh = g_new0 (DirHandle, 1);
916         
917         /* Prepend the base for the desktop URI.
918          * If the SchemeDescription contains > 1 directory, we use the directory
919          * after the first if the given file actually exists there.
920          */
921         found = FALSE;
922         path = gnome_vfs_uri_get_path (desktop_uri);
923         i = 0;
924         while (desc->directories[i]) {
925                 char *s;
926                 GnomeVFSURI *file_uri;
927                 GnomeVFSMethodHandle *parent_handle = NULL;
928                 
929                 s = create_file_uri_in_dir (desc->directories[i], path);
930
931                 file_uri = gnome_vfs_uri_new (s);
932
933                 g_free (s);
934
935                 result = (* parent_method->open_directory) (parent_method,
936                                                             &parent_handle,
937                                                             file_uri,
938                                                             options,
939                                                             context);
940
941                 if (result == GNOME_VFS_OK) {
942                         found = TRUE;
943                         dh->handles = g_slist_prepend (dh->handles, parent_handle);
944                 }
945
946                 gnome_vfs_uri_unref (file_uri);
947
948                 ++i;
949         }
950
951         dh->next = dh->handles;
952
953         *method_handle = (GnomeVFSMethodHandle*) dh;
954         
955         return found ? GNOME_VFS_OK : GNOME_VFS_ERROR_NOT_FOUND;
956 }
957
958
959 static char*
960 create_file_uri_in_dir (const char  *dir,
961                         const char  *filename)
962 {
963         char *dir_uri;
964         char *retval;
965         
966         dir_uri = gnome_vfs_get_uri_from_local_path (dir);
967
968         retval = g_strconcat (dir_uri, "/", filename, NULL);
969
970         g_free (dir_uri);
971         
972         return retval;
973 }
974
975
976
977
978