1 /* Option system based mime backend */
2 
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 
7 #include <string.h>
8 
9 #include "elinks.h"
10 
11 #include "config/options.h"
12 #include "intl/gettext/libintl.h"
13 #include "main/module.h"
14 #include "mime/backend/common.h"
15 #include "mime/backend/default.h"
16 #include "mime/mime.h"
17 #include "osdep/osdep.h"		/* For get_system_str() */
18 #include "terminal/terminal.h"
19 #include "util/conv.h"
20 #include "util/memory.h"
21 #include "util/string.h"
22 
23 
24 static struct option_info default_mime_options[] = {
25 	INIT_OPT_TREE("mime", N_("MIME type associations"),
26 		"type", OPT_AUTOCREATE,
27 		N_("Handler <-> MIME type association. The first sub-tree is the MIME\n"
28 		"class while the second sub-tree is the MIME type (ie. image/gif\n"
29 		"handler will reside at mime.type.image.gif). Each MIME type option\n"
30 		"should contain (case-sensitive) name of the MIME handler (its\n"
31 		"properties are stored at mime.handler.<name>).")),
32 
33 	INIT_OPT_TREE("mime.type", NULL,
34 		"_template_", OPT_AUTOCREATE,
35 		N_("Handler matching this MIME-type class ('*' is used here in place\n"
36 		"of '.').")),
37 
38 	INIT_OPT_STRING("mime.type._template_", NULL,
39 		"_template_", 0, "",
40 		N_("Handler matching this MIME-type name ('*' is used here in place\n"
41 		"of '.').")),
42 
43 
44 	INIT_OPT_TREE("mime", N_("File type handlers"),
45 		"handler", OPT_AUTOCREATE,
46 		N_("A file type handler is a set of information about how to use\n"
47 		"an external program to view a file. It is possible to refer to it\n"
48 		"for several MIME types -- e.g., you can define an 'image' handler\n"
49 		"to which mime.type.image.png, mime.type.image.jpeg, and so on will\n"
50 		"refer; or one might define a handler for a more specific type of file\n"
51 		"-- e.g., PDF files.\n"
52 		"Note you must define both a MIME handler and a MIME type association\n"
53 		"for it to work.")),
54 
55 	INIT_OPT_TREE("mime.handler", NULL,
56 		"_template_", OPT_AUTOCREATE,
57 		N_("Description of this handler.")),
58 
59 	INIT_OPT_TREE("mime.handler._template_", NULL,
60 		"_template_", 0,
61 		N_("System-specific handler description (ie. unix, unix-xwin, ...).")),
62 
63 	INIT_OPT_BOOL("mime.handler._template_._template_", N_("Ask before opening"),
64 		"ask", 0, 1,
65 		N_("Ask before opening.")),
66 
67 	INIT_OPT_BOOL("mime.handler._template_._template_", N_("Block terminal"),
68 		"block", 0, 1,
69 		N_("Block the terminal when the handler is running.")),
70 
71 	INIT_OPT_STRING("mime.handler._template_._template_", N_("Program"),
72 		"program", 0, "",
73 		/* xgettext:no-c-format */
74 		N_("External viewer for this file type. '%' in this string will be\n"
75 		"substituted by a file name.")),
76 
77 
78 	INIT_OPT_TREE("mime", N_("File extension associations"),
79 		"extension", OPT_AUTOCREATE,
80 		N_("Extension <-> MIME type association.")),
81 
82 	INIT_OPT_STRING("mime.extension", NULL,
83 		"_template_", 0, "",
84 		N_("MIME-type matching this file extension ('*' is used here in place\n"
85 		"of '.').")),
86 
87 #define INIT_OPT_MIME_EXTENSION(extension, type) \
88 	INIT_OPT_STRING("mime.extension", NULL, extension, 0, type, NULL)
89 
90 	INIT_OPT_MIME_EXTENSION("gif",		"image/gif"),
91 	INIT_OPT_MIME_EXTENSION("jpg",		"image/jpg"),
92 	INIT_OPT_MIME_EXTENSION("jpeg",		"image/jpeg"),
93 	INIT_OPT_MIME_EXTENSION("png",		"image/png"),
94 	INIT_OPT_MIME_EXTENSION("txt",		"text/plain"),
95 	INIT_OPT_MIME_EXTENSION("htm",		"text/html"),
96 	INIT_OPT_MIME_EXTENSION("html",		"text/html"),
97 #ifdef CONFIG_BITTORRENT
98 	INIT_OPT_MIME_EXTENSION("torrent",	"application/x-bittorrent"),
99 #endif
100 #ifdef CONFIG_DOM
101 	INIT_OPT_MIME_EXTENSION("rss",		"application/rss+xml"),
102 	INIT_OPT_MIME_EXTENSION("xbel",		"application/xbel+xml"),
103 #endif
104 
105 	NULL_OPTION_INFO,
106 };
107 
108 static unsigned char *
get_content_type_default(unsigned char * extension)109 get_content_type_default(unsigned char *extension)
110 {
111 	struct option *opt_tree;
112 	struct option *opt;
113 	unsigned char *extend = extension + strlen(extension) - 1;
114 
115 	if (extend < extension)	return NULL;
116 
117 	opt_tree = get_opt_rec_real(config_options, "mime.extension");
118 
119 	foreach (opt, *opt_tree->value.tree) {
120 		unsigned char *namepos = opt->name + strlen(opt->name) - 1;
121 		unsigned char *extpos = extend;
122 
123 		/* Match the longest possible part of URL.. */
124 
125 #define star2dot(achar)	((achar) == '*' ? '.' : (achar))
126 
127 		while (extension <= extpos && opt->name <= namepos
128 		       && *extpos == star2dot(*namepos)) {
129 			extpos--;
130 			namepos--;
131 		}
132 
133 #undef star2dot
134 
135 		/* If we matched whole extension and it is really an
136 		 * extension.. */
137 		if (namepos < opt->name
138 		    && (extpos < extension || *extpos == '.'))
139 			return stracpy(opt->value.string);
140 	}
141 
142 	return NULL;
143 }
144 
145 static unsigned char *
get_mime_type_name(unsigned char * type)146 get_mime_type_name(unsigned char *type)
147 {
148 	struct string name;
149 	int oldlength;
150 
151 	if (!init_string(&name)) return NULL;
152 
153 	add_to_string(&name, "mime.type.");
154 	oldlength = name.length;
155 	if (add_optname_to_string(&name, type, strlen(type))) {
156 		unsigned char *pos = name.source + oldlength;
157 
158 		/* Search for end of the base type. */
159 		pos = strchr(pos, '/');
160 		if (pos) {
161 			*pos = '.';
162 			return name.source;
163 		}
164 	}
165 
166 	done_string(&name);
167 	return NULL;
168 }
169 
170 static inline unsigned char *
get_mime_handler_name(unsigned char * type,int xwin)171 get_mime_handler_name(unsigned char *type, int xwin)
172 {
173 	struct option *opt;
174 	unsigned char *name = get_mime_type_name(type);
175 
176 	if (!name) return NULL;
177 
178 	opt = get_opt_rec_real(config_options, name);
179 	mem_free(name);
180 	if (!opt) return NULL;
181 
182 	return straconcat("mime.handler.", opt->value.string,
183 			  ".", get_system_str(xwin), NULL);
184 }
185 
186 static struct mime_handler *
get_mime_handler_default(unsigned char * type,int have_x)187 get_mime_handler_default(unsigned char *type, int have_x)
188 {
189 	struct option *opt_tree;
190 	unsigned char *handler_name = get_mime_handler_name(type, have_x);
191 
192 	if (!handler_name) return NULL;
193 
194 	opt_tree = get_opt_rec_real(config_options, handler_name);
195 	mem_free(handler_name);
196 
197 	if (opt_tree) {
198 		unsigned char *desc = "";
199 		unsigned char *mt = get_mime_type_name(type);
200 
201 		/* Try to find some description to assing to @name */
202 		if (mt) {
203 			struct option *opt;
204 
205 			opt = get_opt_rec_real(config_options, mt);
206 			mem_free(mt);
207 
208 			if (opt) desc = opt->value.string;
209 		}
210 
211 		return init_mime_handler(get_opt_str_tree(opt_tree, "program"),
212 					 desc, default_mime_module.name,
213 					 get_opt_bool_tree(opt_tree, "ask"),
214 					 get_opt_bool_tree(opt_tree, "block"));
215 	}
216 
217 	return NULL;
218 }
219 
220 
221 struct mime_backend default_mime_backend = {
222 	/* get_content_type: */	get_content_type_default,
223 	/* get_mime_handler: */	get_mime_handler_default,
224 };
225 
226 struct module default_mime_module = struct_module(
227 	/* name: */		N_("Option system"),
228 	/* options: */		default_mime_options,
229 	/* hooks: */		NULL,
230 	/* submodules: */	NULL,
231 	/* data: */		NULL,
232 	/* init: */		NULL,
233 	/* done: */		NULL
234 );
235