r233: Tidied up choices.c quite a lot. Also, replaced the 'guess' file with a
[rox-filer/dt.git] / ROX-Filer / src / type.c
blobcecc533c60e524260212ee8e48c1b29f98c1ebd1
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
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)
10 * any later version.
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
15 * more details.
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 */
24 #include "config.h"
26 #include <glib.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <time.h>
34 #include "string.h"
35 #include "main.h"
36 #include "filer.h"
37 #include "pixmaps.h"
38 #include "run.h"
39 #include "gui_support.h"
40 #include "choices.h"
41 #include "type.h"
42 #include "support.h"
43 #include "options.h"
45 /* Static prototypes */
46 static char *import_extensions(guchar *line);
47 static void import_for_dir(guchar *path);
49 /* Maps extensions to MIME_types (eg 'png'-> MIME_type *) */
50 static GHashTable *extension_hash = NULL;
51 static char *current_type = NULL; /* (used while reading file) */
53 /* Most things on Unix are text files, so this is the default type */
54 MIME_type text_plain = {"text", "plain", NULL};
56 void type_init()
58 int i;
59 GPtrArray *list;
61 extension_hash = g_hash_table_new(g_str_hash, g_str_equal);
63 current_type = NULL;
64 parse_file(make_path(getenv("APP_DIR"), "MIME-types")->str,
65 import_extensions);
67 list = choices_list_dirs("MIME-info");
68 for (i = 0; i < list->len; i++)
69 import_for_dir((gchar *) g_ptr_array_index(list, i));
70 choices_free_list(list);
73 /* Parse every file in 'dir' */
74 static void import_for_dir(guchar *path)
76 DIR *dir;
77 struct dirent *item;
79 dir = opendir(path);
80 if (!dir)
81 return;
83 while ((item = readdir(dir)))
85 if (item->d_name[0] == '.')
86 continue;
88 current_type = NULL;
89 parse_file(make_path(path, item->d_name)->str,
90 import_extensions);
93 closedir(dir);
96 /* Add one entry to the extension_hash table */
97 static void add_ext(char *type_name, char *ext)
99 MIME_type *new;
100 char *slash;
101 int len;
103 slash = strchr(type_name, '/');
104 g_return_if_fail(slash != NULL); /* XXX: Report nicely */
105 len = slash - type_name;
107 new = g_new(MIME_type, 1);
108 new->media_type = g_malloc(sizeof(char) * (len + 1));
109 memcpy(new->media_type, type_name, len);
110 new->media_type[len] = '\0';
112 new->subtype = g_strdup(slash + 1);
113 new->image = NULL;
115 g_hash_table_insert(extension_hash, g_strdup(ext), new);
118 /* Parse one line from the file and add entries to extension_hash */
119 static char *import_extensions(guchar *line)
122 if (*line == '\0' || *line == '#')
123 return NULL; /* Comment */
125 if (isspace(*line))
127 if (!current_type)
128 return "Missing MIME-type";
129 while (*line && isspace(*line))
130 line++;
132 if (strncmp(line, "ext:", 4) == 0)
134 char *ext;
135 line += 4;
137 for (;;)
139 while (*line && isspace(*line))
140 line++;
141 if (*line == '\0')
142 break;
143 ext = line;
144 while (*line && !isspace(*line))
145 line++;
146 if (*line)
147 *line++ = '\0';
148 add_ext(current_type, ext);
151 /* else ignore */
153 else
155 char *type = line;
156 while (*line && *line != ':' && !isspace(*line))
157 line++;
158 if (*line)
159 *line++ = '\0';
160 while (*line && isspace(*line))
161 line++;
162 if (*line)
163 return "Trailing chars after MIME-type";
164 current_type = g_strdup(type);
166 return NULL;
169 char *basetype_name(DirItem *item)
171 if (item->flags & ITEM_FLAG_SYMLINK)
172 return "Sym link";
173 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
174 return "Mount point";
175 else if (item->flags & ITEM_FLAG_APPDIR)
176 return "App dir";
178 switch (item->base_type)
180 case TYPE_FILE:
181 return "File";
182 case TYPE_DIRECTORY:
183 return "Dir";
184 case TYPE_CHAR_DEVICE:
185 return "Char dev";
186 case TYPE_BLOCK_DEVICE:
187 return "Block dev";
188 case TYPE_PIPE:
189 return "Pipe";
190 case TYPE_SOCKET:
191 return "Socket";
194 return "Unknown";
197 /* MIME-type guessing */
199 /* Returns a pointer to the MIME-type string, or NULL if we have
200 * no opinion.
202 MIME_type *type_from_path(char *path)
204 char *dot;
206 dot = strrchr(path, '.');
207 if (dot)
209 MIME_type *type;
210 type = g_hash_table_lookup(extension_hash, dot + 1);
211 if (type)
212 return type;
215 return &text_plain;
218 /* Actions for types */
220 gboolean type_open(char *path, MIME_type *type)
222 char *argv[] = {NULL, NULL, NULL};
223 char *open;
224 char *type_name;
225 gboolean retval = TRUE;
226 struct stat info;
228 argv[1] = path;
230 type_name = g_strconcat(type->media_type, "_", type->subtype, NULL);
231 open = choices_find_path_load(type_name, "MIME-types");
232 g_free(type_name);
233 if (!open)
235 open = choices_find_path_load(type->media_type,
236 "MIME-types");
237 if (!open)
238 return FALSE;
241 if (stat(open, &info))
243 report_error("ROX-Filer", g_strerror(errno));
244 return FALSE;
247 if (S_ISDIR(info.st_mode))
248 argv[0] = g_strconcat(open, "/AppRun", NULL);
249 else
250 argv[0] = open;
252 if (!spawn_full(argv, home_dir))
254 report_error("ROX-Filer",
255 "Failed to fork() child process");
256 retval = FALSE;
259 if (argv[0] != open)
260 g_free(argv[0]);
262 return retval;
265 /* Return the image for this type, loading it if needed.
266 * Places to check are: (eg type="text_plain", base="text")
267 * 1. Choices:MIME-icons/<type>
268 * 2. Choices:MIME-icons/<base>
269 * 3. Unknown type icon.
271 * Note: You must pixmap_unref() the image afterwards.
273 MaskedPixmap *type_to_icon(MIME_type *type)
275 char *path;
276 char *type_name;
277 time_t now;
279 g_return_val_if_fail(type != NULL, default_pixmap + TYPE_UNKNOWN);
281 now = time(NULL);
282 /* Already got an image? */
283 if (type->image)
285 /* Yes - don't recheck too often */
286 if (abs(now - type->image_time) < 2)
288 pixmap_ref(type->image);
289 return type->image;
291 pixmap_unref(type->image);
292 type->image = NULL;
295 type_name = g_strconcat(type->media_type, "_",
296 type->subtype, ".xpm", NULL);
297 path = choices_find_path_load(type_name, "MIME-icons");
298 if (!path)
300 strcpy(type_name + strlen(type->media_type), ".xpm");
301 path = choices_find_path_load(type_name, "MIME-icons");
304 g_free(type_name);
306 if (path)
307 type->image = g_fscache_lookup(pixmap_cache, path);
309 if (!type->image)
311 type->image = default_pixmap + TYPE_UNKNOWN;
312 pixmap_ref(type->image);
315 type->image_time = now;
317 pixmap_ref(type->image);
318 return type->image;
321 GdkAtom type_to_atom(MIME_type *type)
323 char *str;
324 GdkAtom retval;
326 g_return_val_if_fail(type != NULL, GDK_NONE);
328 str = g_strconcat(type->media_type, "/", type->subtype, NULL);
329 retval = gdk_atom_intern(str, FALSE);
330 g_free(str);
332 return retval;