4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* type.c - code for dealing with filetypes */
30 #include <sys/param.h>
38 #include "gui_support.h"
44 /* Static prototypes */
45 static char *import_extensions(guchar
*line
);
46 static void import_for_dir(guchar
*path
);
48 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *) */
49 static GHashTable
*extension_hash
= NULL
;
50 static char *current_type
= NULL
; /* (used while reading file) */
52 /* Most things on Unix are text files, so this is the default type */
53 MIME_type text_plain
= {"text", "plain", NULL
};
55 MIME_type special_directory
= {"special", "directory", NULL
};
56 MIME_type special_pipe
= {"special", "pipe", NULL
};
57 MIME_type special_socket
= {"special", "socket", NULL
};
58 MIME_type special_block_dev
= {"special", "block-device", NULL
};
59 MIME_type special_char_dev
= {"special", "char-device", NULL
};
60 MIME_type special_unknown
= {"special", "unknown", NULL
};
67 extension_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
71 list
= choices_list_dirs("MIME-info");
72 for (i
= 0; i
< list
->len
; i
++)
73 import_for_dir((gchar
*) g_ptr_array_index(list
, i
));
74 choices_free_list(list
);
77 /* Parse every file in 'dir' */
78 static void import_for_dir(guchar
*path
)
87 while ((item
= readdir(dir
)))
89 if (item
->d_name
[0] == '.')
93 parse_file(make_path(path
, item
->d_name
)->str
,
100 /* Add one entry to the extension_hash table */
101 static void add_ext(char *type_name
, char *ext
)
107 slash
= strchr(type_name
, '/');
108 g_return_if_fail(slash
!= NULL
); /* XXX: Report nicely */
109 len
= slash
- type_name
;
111 new = g_new(MIME_type
, 1);
112 new->media_type
= g_malloc(sizeof(char) * (len
+ 1));
113 memcpy(new->media_type
, type_name
, len
);
114 new->media_type
[len
] = '\0';
116 new->subtype
= g_strdup(slash
+ 1);
119 g_hash_table_insert(extension_hash
, g_strdup(ext
), new);
122 /* Parse one line from the file and add entries to extension_hash */
123 static char *import_extensions(guchar
*line
)
126 if (*line
== '\0' || *line
== '#')
127 return NULL
; /* Comment */
132 return _("Missing MIME-type");
133 while (*line
&& isspace(*line
))
136 if (strncmp(line
, "ext:", 4) == 0)
143 while (*line
&& isspace(*line
))
148 while (*line
&& !isspace(*line
))
152 add_ext(current_type
, ext
);
160 while (*line
&& *line
!= ':' && !isspace(*line
))
164 while (*line
&& isspace(*line
))
167 return _("Trailing chars after MIME-type");
168 current_type
= g_strdup(type
);
173 char *basetype_name(DirItem
*item
)
175 if (item
->flags
& ITEM_FLAG_SYMLINK
)
176 return _("Sym link");
177 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
178 return _("Mount point");
179 else if (item
->flags
& ITEM_FLAG_APPDIR
)
182 switch (item
->base_type
)
188 case TYPE_CHAR_DEVICE
:
189 return _("Char dev");
190 case TYPE_BLOCK_DEVICE
:
191 return _("Block dev");
201 /* MIME-type guessing */
203 /* Returns a pointer to the MIME-type. Defaults to text/plain if we have
206 MIME_type
*type_from_path(char *path
)
210 dot
= strrchr(path
, '.');
214 type
= g_hash_table_lookup(extension_hash
, dot
+ 1);
222 /* Actions for types */
224 gboolean
type_open(char *path
, MIME_type
*type
)
226 char *argv
[] = {NULL
, NULL
, NULL
};
229 gboolean retval
= TRUE
;
234 type_name
= g_strconcat(type
->media_type
, "_", type
->subtype
, NULL
);
235 open
= choices_find_path_load(type_name
, "MIME-types");
239 open
= choices_find_path_load(type
->media_type
,
245 if (stat(open
, &info
))
247 report_error(PROJECT
, g_strerror(errno
));
251 if (S_ISDIR(info
.st_mode
))
252 argv
[0] = g_strconcat(open
, "/AppRun", NULL
);
256 if (!spawn_full(argv
, home_dir
))
258 report_error(PROJECT
,
259 _("Failed to fork() child process"));
269 /* Return the image for this type, loading it if needed.
270 * Places to check are: (eg type="text_plain", base="text")
271 * 1. Choices:MIME-icons/<type>
272 * 2. Choices:MIME-icons/<base>
273 * 3. Unknown type icon.
275 * Note: You must pixmap_unref() the image afterwards.
277 MaskedPixmap
*type_to_icon(MIME_type
*type
)
285 pixmap_ref(im_unknown
);
290 /* Already got an image? */
293 /* Yes - don't recheck too often */
294 if (abs(now
- type
->image_time
) < 2)
296 pixmap_ref(type
->image
);
299 pixmap_unref(type
->image
);
303 type_name
= g_strconcat(type
->media_type
, "_",
304 type
->subtype
, ".xpm", NULL
);
305 path
= choices_find_path_load(type_name
, "MIME-icons");
308 strcpy(type_name
+ strlen(type
->media_type
), ".xpm");
309 path
= choices_find_path_load(type_name
, "MIME-icons");
315 type
->image
= g_fscache_lookup(pixmap_cache
, path
);
319 type
->image
= im_unknown
;
320 pixmap_ref(type
->image
);
323 type
->image_time
= now
;
325 pixmap_ref(type
->image
);
329 GdkAtom
type_to_atom(MIME_type
*type
)
334 g_return_val_if_fail(type
!= NULL
, GDK_NONE
);
336 str
= g_strconcat(type
->media_type
, "/", type
->subtype
, NULL
);
337 retval
= gdk_atom_intern(str
, FALSE
);
343 /* The user wants to set a new default action for files of this type.
344 * Ask the user if they want to set eg 'text/plain' or just 'text'.
345 * Removes the current binding if possible and returns the path to
346 * save the new one to. NULL means cancel.
348 char *type_ask_which_action(guchar
*media_type
, guchar
*subtype
)
351 guchar
*tmp
, *type_name
, *path
;
354 g_return_val_if_fail(media_type
!= NULL
, NULL
);
355 g_return_val_if_fail(subtype
!= NULL
, NULL
);
357 if (!choices_find_path_save("", PROJECT
, FALSE
))
359 report_error(PROJECT
,
360 _("Choices saving is disabled by CHOICESPATH variable"));
364 type_name
= g_strconcat(media_type
, "/", subtype
, NULL
);
365 tmp
= g_strdup_printf(
366 _("You can choose to set the action for just '%s' files, or "
367 "the default action for all '%s' files which don't already "
368 "have a run action:"), type_name
, media_type
);
369 r
= get_choice(PROJECT
, tmp
, 3, type_name
, media_type
, "Cancel");
375 type_name
= g_strconcat(media_type
, "_", subtype
, NULL
);
376 path
= choices_find_path_save(type_name
, "MIME-types", TRUE
);
380 path
= choices_find_path_save(media_type
, "MIME-types", TRUE
);
384 if (lstat(path
, &info
) == 0)
386 /* A binding already exists... */
387 if (S_ISREG(info
.st_mode
) && info
.st_size
> 256)
389 if (get_choice(PROJECT
,
390 _("A run action already exists and is quite "
391 "a big program - are you sure you want to "
392 "delete it?"), 2, "Delete", "Cancel") != 0)
398 tmp
= g_strdup_printf( _("Can't remove %s: %s"),
399 path
, g_strerror(errno
));
400 report_error(PROJECT
, tmp
);
409 MIME_type
*mime_type_from_base_type(int base_type
)
414 return &special_directory
;
416 return &special_pipe
;
418 return &special_socket
;
419 case TYPE_BLOCK_DEVICE
:
420 return &special_block_dev
;
421 case TYPE_CHAR_DEVICE
:
422 return &special_char_dev
;
424 return &special_unknown
;
427 /* Takes the st_mode field from stat() and returns the base type.
428 * Should not be a symlink.
430 int mode_to_base_type(int st_mode
)
432 if (S_ISREG(st_mode
))
434 else if (S_ISDIR(st_mode
))
435 return TYPE_DIRECTORY
;
436 else if (S_ISBLK(st_mode
))
437 return TYPE_BLOCK_DEVICE
;
438 else if (S_ISCHR(st_mode
))
439 return TYPE_CHAR_DEVICE
;
440 else if (S_ISFIFO(st_mode
))
442 else if (S_ISSOCK(st_mode
))