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
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         SCHEME_NETWORK
708 } SchemeID;
709
710 #define MAX_DIRECTORIES 3
711 #define DIRECTORIES_INITIALIZER { NULL, NULL, NULL }
712
713 typedef struct _SchemeDescription SchemeDescription;
714
715 struct _SchemeDescription
716 {
717         SchemeID id;
718         
719         const char *scheme;
720
721         char *directories[MAX_DIRECTORIES];
722 };
723
724 static SchemeDescription schemes[] = 
725 {
726         { SCHEME_FAVORITES, "favorites",
727           DIRECTORIES_INITIALIZER },
728         { SCHEME_PREFERENCES, "preferences",
729           DIRECTORIES_INITIALIZER },
730         { SCHEME_START_HERE, "start-here",
731           DIRECTORIES_INITIALIZER },
732         { SCHEME_SYSTEM_SETTINGS, "system-settings",
733           DIRECTORIES_INITIALIZER },
734         { SCHEME_SERVER_SETTINGS, "server-settings",
735           DIRECTORIES_INITIALIZER },
736         { SCHEME_PROGRAMS, "programs",
737           DIRECTORIES_INITIALIZER },
738         { SCHEME_NETWORK, "network",
739           DIRECTORIES_INITIALIZER }
740 };
741
742 GnomeVFSMethod *
743 vfs_module_init (const char *method_name, 
744                  const char *args)
745 {
746         int i;
747         
748         parent_method = gnome_vfs_method_get ("file");
749
750         if (parent_method == NULL) {
751                 g_error ("Could not find 'file' method for gnome-vfs");
752                 return NULL;
753         }
754
755         i = 0;
756         while (i < N_ELEMENTS (schemes)) {
757                 switch (schemes[i].id) {
758                 case SCHEME_FAVORITES:
759                         schemes[i].directories[0] =
760                                 g_strconcat (g_get_home_dir (),
761                                              "/.gnome/apps",
762                                              NULL);
763                         break;
764                 case SCHEME_PREFERENCES:
765                         /* FIXME I think the GNOME 2 control center will move
766                          * this, but we don't know where to yet
767                          */
768                         schemes[i].directories[0] =
769                                 g_strconcat (DATADIR, "/control-center/capplets", NULL);
770                         break;
771                 case SCHEME_START_HERE:
772                         schemes[i].directories[0] = g_strconcat (SYSCONFDIR,
773                                                                  "/X11/starthere",
774                                                                  NULL);
775                         break;
776                 case SCHEME_SYSTEM_SETTINGS:
777                         schemes[i].directories[0] =
778                                 g_strconcat (SYSCONFDIR, "/X11/sysconfig", NULL);
779                         break;
780                 case SCHEME_SERVER_SETTINGS:
781                         schemes[i].directories[0] =
782                                 g_strconcat (SYSCONFDIR, "/X11/serverconfig", NULL);
783                         break;
784                 case SCHEME_PROGRAMS:
785                         schemes[i].directories[0] = g_strconcat (SYSCONFDIR,
786                                                                  "/X11/applnk",
787                                                                  NULL);
788                         schemes[i].directories[1] =
789                                 g_strconcat (DATADIR, "gnome/apps", NULL);
790                         break;
791                 case SCHEME_NETWORK:
792                         schemes[i].directories[0] =
793                                 g_build_filename (DATADIR, "gnome/network", NULL);
794                         break;
795                 default:
796                         g_assert_not_reached ();
797                         break;
798                 }
799
800                 ++i;
801         }
802         
803         return &method;
804 }
805
806 void
807 vfs_module_shutdown (GnomeVFSMethod *method)
808 {
809         int i;
810         
811         i = 0;
812         while (i < N_ELEMENTS (schemes)) {
813                 int j;
814
815                 j = 0;
816                 while (j < MAX_DIRECTORIES) {
817                         g_free (schemes[i].directories[j]);
818                         schemes[i].directories[j] = NULL;
819                         ++j;
820                 }
821                 
822                 ++i;
823         }
824 }
825
826 \f
827
828 static const SchemeDescription*
829 get_desc_for_uri (GnomeVFSURI *desktop_uri)
830 {
831         const SchemeDescription *desc;
832         int i;
833         const char *scheme;
834         
835         scheme = gnome_vfs_uri_get_scheme (desktop_uri);
836
837         desc = NULL;
838         i = 0;
839         while (i < N_ELEMENTS (schemes)) {
840                 if (strcmp (schemes[i].scheme, scheme) == 0) {
841                         desc = &schemes[i];
842                         break;
843                 }
844                 
845                 ++i;
846         }
847
848         return desc;
849 }
850
851 static GnomeVFSURI*
852 desktop_uri_to_file_uri (GnomeVFSURI *desktop_uri)
853 {
854         const SchemeDescription *desc;
855         GnomeVFSURI *new_uri;
856         const char *path;
857         int i;
858
859         desc = get_desc_for_uri (desktop_uri);
860
861         if (desc == NULL) {
862                 gnome_vfs_uri_ref (desktop_uri);
863                 return desktop_uri;
864         }
865
866         /* Prepend the base for the desktop URI.
867          * If the SchemeDescription contains > 1 directory, we use the directory
868          * after the first if the given file actually exists there.
869          */
870         new_uri = NULL;
871         path = gnome_vfs_uri_get_path (desktop_uri);
872         i = 0;
873         while (desc->directories[i])
874                 ++i;
875         do {
876                 char *s;
877
878                 --i;
879                 
880                 s = create_file_uri_in_dir (desc->directories[i], path);
881
882                 new_uri = gnome_vfs_uri_new (s);
883
884                 g_free (s);
885                 
886                 if (i == 0 ||
887                     gnome_vfs_uri_exists (new_uri)) {
888                         return new_uri;
889                 } else {
890                         gnome_vfs_uri_unref (new_uri);
891                         new_uri = NULL;
892                 }
893         } while (i > 0);
894
895
896         g_assert_not_reached ();
897
898         return NULL;
899 }
900
901
902 static GnomeVFSResult
903 open_merged_directory (GnomeVFSMethod *method,
904                        GnomeVFSMethodHandle **method_handle,
905                        GnomeVFSURI *desktop_uri,
906                        GnomeVFSFileInfoOptions options,
907                        GnomeVFSContext *context)
908 {
909         GnomeVFSResult result;
910         DirHandle *dh;
911         const SchemeDescription *desc;
912         int i;
913         gboolean found;
914         const char *path;
915         
916         desc = get_desc_for_uri (desktop_uri);
917         
918         if (desc == NULL) {
919                 return GNOME_VFS_ERROR_NOT_FOUND;
920         }
921
922         dh = g_new0 (DirHandle, 1);
923         
924         /* Prepend the base for the desktop URI.
925          * If the SchemeDescription contains > 1 directory, we use the directory
926          * after the first if the given file actually exists there.
927          */
928         found = FALSE;
929         path = gnome_vfs_uri_get_path (desktop_uri);
930         i = 0;
931         while (desc->directories[i]) {
932                 char *s;
933                 GnomeVFSURI *file_uri;
934                 GnomeVFSMethodHandle *parent_handle = NULL;
935                 
936                 s = create_file_uri_in_dir (desc->directories[i], path);
937
938                 file_uri = gnome_vfs_uri_new (s);
939
940                 g_free (s);
941
942                 result = (* parent_method->open_directory) (parent_method,
943                                                             &parent_handle,
944                                                             file_uri,
945                                                             options,
946                                                             context);
947
948                 if (result == GNOME_VFS_OK) {
949                         found = TRUE;
950                         dh->handles = g_slist_prepend (dh->handles, parent_handle);
951                 }
952
953                 gnome_vfs_uri_unref (file_uri);
954
955                 ++i;
956         }
957
958         dh->next = dh->handles;
959
960         *method_handle = (GnomeVFSMethodHandle*) dh;
961         
962         return found ? GNOME_VFS_OK : GNOME_VFS_ERROR_NOT_FOUND;
963 }
964
965
966 static char*
967 create_file_uri_in_dir (const char  *dir,
968                         const char  *filename)
969 {
970         char *dir_uri;
971         char *retval;
972         
973         dir_uri = gnome_vfs_get_uri_from_local_path (dir);
974
975         retval = g_strconcat (dir_uri, "/", filename, NULL);
976
977         g_free (dir_uri);
978         
979         return retval;
980 }
981
982
983
984
985