xref: /illumos-gate/usr/src/contrib/ast/src/lib/libast/misc/mime.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
1*b30d1939SAndy Fiddaman /***********************************************************************
2*b30d1939SAndy Fiddaman *                                                                      *
3*b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7*b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8*b30d1939SAndy Fiddaman *                                                                      *
9*b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*b30d1939SAndy Fiddaman *                                                                      *
13*b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14*b30d1939SAndy Fiddaman *                            AT&T Research                             *
15*b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16*b30d1939SAndy Fiddaman *                                                                      *
17*b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18*b30d1939SAndy Fiddaman *                  David Korn <dgk@research.att.com>                   *
19*b30d1939SAndy Fiddaman *                   Phong Vo <kpv@research.att.com>                    *
20*b30d1939SAndy Fiddaman *                                                                      *
21*b30d1939SAndy Fiddaman ***********************************************************************/
22*b30d1939SAndy Fiddaman #pragma prototyped
23*b30d1939SAndy Fiddaman 
24*b30d1939SAndy Fiddaman /*
25*b30d1939SAndy Fiddaman  * Glenn Fowler
26*b30d1939SAndy Fiddaman  * AT&T Research
27*b30d1939SAndy Fiddaman  *
28*b30d1939SAndy Fiddaman  * mime/mailcap support library
29*b30d1939SAndy Fiddaman  */
30*b30d1939SAndy Fiddaman 
31*b30d1939SAndy Fiddaman static const char id[] = "\n@(#)$Id: mime library (AT&T Research) 2002-10-29 $\0\n";
32*b30d1939SAndy Fiddaman 
33*b30d1939SAndy Fiddaman static const char lib[] = "libast:mime";
34*b30d1939SAndy Fiddaman 
35*b30d1939SAndy Fiddaman #include "mimelib.h"
36*b30d1939SAndy Fiddaman 
37*b30d1939SAndy Fiddaman typedef struct Att_s
38*b30d1939SAndy Fiddaman {
39*b30d1939SAndy Fiddaman 	struct Att_s*	next;
40*b30d1939SAndy Fiddaman 	char*		name;
41*b30d1939SAndy Fiddaman 	char*		value;
42*b30d1939SAndy Fiddaman } Att_t;
43*b30d1939SAndy Fiddaman 
44*b30d1939SAndy Fiddaman typedef struct Cap_s
45*b30d1939SAndy Fiddaman {
46*b30d1939SAndy Fiddaman 	struct Cap_s*	next;
47*b30d1939SAndy Fiddaman 	unsigned long	flags;
48*b30d1939SAndy Fiddaman 	Att_t		att;
49*b30d1939SAndy Fiddaman 	char*		test;
50*b30d1939SAndy Fiddaman 	char		data[1];
51*b30d1939SAndy Fiddaman } Cap_t;
52*b30d1939SAndy Fiddaman 
53*b30d1939SAndy Fiddaman typedef struct
54*b30d1939SAndy Fiddaman {
55*b30d1939SAndy Fiddaman 	Dtlink_t	link;
56*b30d1939SAndy Fiddaman 	Cap_t*		cap;
57*b30d1939SAndy Fiddaman 	Cap_t*		pac;
58*b30d1939SAndy Fiddaman 	char		name[1];
59*b30d1939SAndy Fiddaman } Ent_t;
60*b30d1939SAndy Fiddaman 
61*b30d1939SAndy Fiddaman typedef struct
62*b30d1939SAndy Fiddaman {
63*b30d1939SAndy Fiddaman 	char*		data;
64*b30d1939SAndy Fiddaman 	int		size;
65*b30d1939SAndy Fiddaman } String_t;
66*b30d1939SAndy Fiddaman 
67*b30d1939SAndy Fiddaman typedef struct
68*b30d1939SAndy Fiddaman {
69*b30d1939SAndy Fiddaman 	char*		next;
70*b30d1939SAndy Fiddaman 	String_t	name;
71*b30d1939SAndy Fiddaman 	String_t	value;
72*b30d1939SAndy Fiddaman } Parse_t;
73*b30d1939SAndy Fiddaman 
74*b30d1939SAndy Fiddaman typedef struct
75*b30d1939SAndy Fiddaman {
76*b30d1939SAndy Fiddaman 	const char*	pattern;
77*b30d1939SAndy Fiddaman 	int		prefix;
78*b30d1939SAndy Fiddaman 	Sfio_t*		fp;
79*b30d1939SAndy Fiddaman 	int		hit;
80*b30d1939SAndy Fiddaman } Walk_t;
81*b30d1939SAndy Fiddaman 
82*b30d1939SAndy Fiddaman /*
83*b30d1939SAndy Fiddaman  * convert c to lower case
84*b30d1939SAndy Fiddaman  */
85*b30d1939SAndy Fiddaman 
86*b30d1939SAndy Fiddaman static int
lower(int c)87*b30d1939SAndy Fiddaman lower(int c)
88*b30d1939SAndy Fiddaman {
89*b30d1939SAndy Fiddaman 	return isupper(c) ? tolower(c) : c;
90*b30d1939SAndy Fiddaman }
91*b30d1939SAndy Fiddaman 
92*b30d1939SAndy Fiddaman /*
93*b30d1939SAndy Fiddaman  * Ent_t case insensitive comparf
94*b30d1939SAndy Fiddaman  */
95*b30d1939SAndy Fiddaman 
96*b30d1939SAndy Fiddaman static int
order(Dt_t * dt,void * a,void * b,Dtdisc_t * disc)97*b30d1939SAndy Fiddaman order(Dt_t* dt, void* a, void* b, Dtdisc_t* disc)
98*b30d1939SAndy Fiddaman {
99*b30d1939SAndy Fiddaman 	return strcasecmp(a, b);
100*b30d1939SAndy Fiddaman }
101*b30d1939SAndy Fiddaman 
102*b30d1939SAndy Fiddaman /*
103*b30d1939SAndy Fiddaman  * Cap_t free
104*b30d1939SAndy Fiddaman  */
105*b30d1939SAndy Fiddaman 
106*b30d1939SAndy Fiddaman static void
dropcap(Cap_t * cap)107*b30d1939SAndy Fiddaman dropcap(Cap_t* cap)
108*b30d1939SAndy Fiddaman {
109*b30d1939SAndy Fiddaman 	Att_t*	att;
110*b30d1939SAndy Fiddaman 
111*b30d1939SAndy Fiddaman 	while (att = cap->att.next)
112*b30d1939SAndy Fiddaman 	{
113*b30d1939SAndy Fiddaman 		cap->att.next = att->next;
114*b30d1939SAndy Fiddaman 		free(att);
115*b30d1939SAndy Fiddaman 	}
116*b30d1939SAndy Fiddaman 	free(cap);
117*b30d1939SAndy Fiddaman }
118*b30d1939SAndy Fiddaman 
119*b30d1939SAndy Fiddaman /*
120*b30d1939SAndy Fiddaman  * Ent_t freef
121*b30d1939SAndy Fiddaman  */
122*b30d1939SAndy Fiddaman 
123*b30d1939SAndy Fiddaman static void
drop(Dt_t * dt,void * object,Dtdisc_t * disc)124*b30d1939SAndy Fiddaman drop(Dt_t* dt, void* object, Dtdisc_t* disc)
125*b30d1939SAndy Fiddaman {
126*b30d1939SAndy Fiddaman 	Ent_t*	ent = (Ent_t*)object;
127*b30d1939SAndy Fiddaman 	Cap_t*	cap;
128*b30d1939SAndy Fiddaman 
129*b30d1939SAndy Fiddaman 	while (cap = ent->cap)
130*b30d1939SAndy Fiddaman 	{
131*b30d1939SAndy Fiddaman 		ent->cap = cap->next;
132*b30d1939SAndy Fiddaman 		dropcap(cap);
133*b30d1939SAndy Fiddaman 	}
134*b30d1939SAndy Fiddaman 	free(ent);
135*b30d1939SAndy Fiddaman }
136*b30d1939SAndy Fiddaman 
137*b30d1939SAndy Fiddaman /*
138*b30d1939SAndy Fiddaman  * add mime type entry in s to mp
139*b30d1939SAndy Fiddaman  */
140*b30d1939SAndy Fiddaman 
141*b30d1939SAndy Fiddaman int
mimeset(Mime_t * mp,char * s,unsigned long flags)142*b30d1939SAndy Fiddaman mimeset(Mime_t* mp, char* s, unsigned long flags)
143*b30d1939SAndy Fiddaman {
144*b30d1939SAndy Fiddaman 	Ent_t*	ent;
145*b30d1939SAndy Fiddaman 	Cap_t*	cap;
146*b30d1939SAndy Fiddaman 	Att_t*	att;
147*b30d1939SAndy Fiddaman 	char*	t;
148*b30d1939SAndy Fiddaman 	char*	v;
149*b30d1939SAndy Fiddaman 	char*	k;
150*b30d1939SAndy Fiddaman 	char*		x;
151*b30d1939SAndy Fiddaman 	Att_t*		tta;
152*b30d1939SAndy Fiddaman 	int		q;
153*b30d1939SAndy Fiddaman 
154*b30d1939SAndy Fiddaman 	for (; isspace(*s); s++);
155*b30d1939SAndy Fiddaman 	if (*s && *s != '#')
156*b30d1939SAndy Fiddaman 	{
157*b30d1939SAndy Fiddaman 		cap = 0;
158*b30d1939SAndy Fiddaman 		for (v = s; *v && *v != ';'; v++)
159*b30d1939SAndy Fiddaman 			if (isspace(*v) || *v == '/' && *(v + 1) == '*')
160*b30d1939SAndy Fiddaman 				*v = 0;
161*b30d1939SAndy Fiddaman 		if (*v)
162*b30d1939SAndy Fiddaman 		{
163*b30d1939SAndy Fiddaman 			*v++ = 0;
164*b30d1939SAndy Fiddaman 			do
165*b30d1939SAndy Fiddaman 			{
166*b30d1939SAndy Fiddaman 				for (; isspace(*v); v++);
167*b30d1939SAndy Fiddaman 				if (cap)
168*b30d1939SAndy Fiddaman 				{
169*b30d1939SAndy Fiddaman 					for (t = v; *t && !isspace(*t) && *t != '='; t++);
170*b30d1939SAndy Fiddaman 					for (k = t; isspace(*t); t++);
171*b30d1939SAndy Fiddaman 					if (!*t || *t == '=' || *t == ';')
172*b30d1939SAndy Fiddaman 					{
173*b30d1939SAndy Fiddaman 						if (*t)
174*b30d1939SAndy Fiddaman 							while (isspace(*++t));
175*b30d1939SAndy Fiddaman 						*k = 0;
176*b30d1939SAndy Fiddaman 						k = v;
177*b30d1939SAndy Fiddaman 						v = t;
178*b30d1939SAndy Fiddaman 					}
179*b30d1939SAndy Fiddaman 					else
180*b30d1939SAndy Fiddaman 						k = 0;
181*b30d1939SAndy Fiddaman 				}
182*b30d1939SAndy Fiddaman 				if (*v == '"')
183*b30d1939SAndy Fiddaman 					q = *v++;
184*b30d1939SAndy Fiddaman 				else
185*b30d1939SAndy Fiddaman 					q = 0;
186*b30d1939SAndy Fiddaman 				for (t = v; *t; t++)
187*b30d1939SAndy Fiddaman 					if (*t == '\\')
188*b30d1939SAndy Fiddaman 					{
189*b30d1939SAndy Fiddaman 						switch (*(t + 1))
190*b30d1939SAndy Fiddaman 						{
191*b30d1939SAndy Fiddaman 						case 0:
192*b30d1939SAndy Fiddaman 						case '\\':
193*b30d1939SAndy Fiddaman 						case '%':
194*b30d1939SAndy Fiddaman 							*t = *(t + 1);
195*b30d1939SAndy Fiddaman 							break;
196*b30d1939SAndy Fiddaman 						default:
197*b30d1939SAndy Fiddaman 							*t = ' ';
198*b30d1939SAndy Fiddaman 							break;
199*b30d1939SAndy Fiddaman 						}
200*b30d1939SAndy Fiddaman 						if (!*++t)
201*b30d1939SAndy Fiddaman 							break;
202*b30d1939SAndy Fiddaman 					}
203*b30d1939SAndy Fiddaman 					else if (*t == q)
204*b30d1939SAndy Fiddaman 					{
205*b30d1939SAndy Fiddaman 						*t = ' ';
206*b30d1939SAndy Fiddaman 						q = 0;
207*b30d1939SAndy Fiddaman 					}
208*b30d1939SAndy Fiddaman 					else if (*t == ';' && !q)
209*b30d1939SAndy Fiddaman 					{
210*b30d1939SAndy Fiddaman 						*t = ' ';
211*b30d1939SAndy Fiddaman 						break;
212*b30d1939SAndy Fiddaman 					}
213*b30d1939SAndy Fiddaman 				for (; t > v && isspace(*(t - 1)); t--);
214*b30d1939SAndy Fiddaman 				if (t <= v && (!cap || !k))
215*b30d1939SAndy Fiddaman 					break;
216*b30d1939SAndy Fiddaman 				if (!cap)
217*b30d1939SAndy Fiddaman 				{
218*b30d1939SAndy Fiddaman 					if (!(cap = newof(0, Cap_t, 1, strlen(v) + 1)))
219*b30d1939SAndy Fiddaman 						return -1;
220*b30d1939SAndy Fiddaman 					if (*t)
221*b30d1939SAndy Fiddaman 						*t++ = 0;
222*b30d1939SAndy Fiddaman 					tta = &cap->att;
223*b30d1939SAndy Fiddaman 					tta->name = "default";
224*b30d1939SAndy Fiddaman 					x = strcopy(tta->value = cap->data, v) + 1;
225*b30d1939SAndy Fiddaman 				}
226*b30d1939SAndy Fiddaman 				else if (k)
227*b30d1939SAndy Fiddaman 				{
228*b30d1939SAndy Fiddaman 					if (*t)
229*b30d1939SAndy Fiddaman 						*t++ = 0;
230*b30d1939SAndy Fiddaman 					if (!(att = newof(0, Att_t, 1, 0)))
231*b30d1939SAndy Fiddaman 						return -1;
232*b30d1939SAndy Fiddaman 					x = strcopy(att->name = x, k) + 1;
233*b30d1939SAndy Fiddaman 					x = strcopy(att->value = x, v) + 1;
234*b30d1939SAndy Fiddaman 					tta = tta->next = att;
235*b30d1939SAndy Fiddaman 					if (!strcasecmp(k, "test"))
236*b30d1939SAndy Fiddaman 						cap->test = att->value;
237*b30d1939SAndy Fiddaman 				}
238*b30d1939SAndy Fiddaman 			} while (*(v = t));
239*b30d1939SAndy Fiddaman 		}
240*b30d1939SAndy Fiddaman 		ent = (Ent_t*)dtmatch(mp->cap, s);
241*b30d1939SAndy Fiddaman 		if (cap)
242*b30d1939SAndy Fiddaman 		{
243*b30d1939SAndy Fiddaman 			if (ent)
244*b30d1939SAndy Fiddaman 			{
245*b30d1939SAndy Fiddaman 				Cap_t*	dup;
246*b30d1939SAndy Fiddaman 				Cap_t*	pud;
247*b30d1939SAndy Fiddaman 
248*b30d1939SAndy Fiddaman 				for (pud = 0, dup = ent->cap; dup; pud = dup, dup = dup->next)
249*b30d1939SAndy Fiddaman 					if (!cap->test && !dup->test || cap->test && dup->test && streq(cap->test, dup->test))
250*b30d1939SAndy Fiddaman 					{
251*b30d1939SAndy Fiddaman 						if (flags & MIME_REPLACE)
252*b30d1939SAndy Fiddaman 						{
253*b30d1939SAndy Fiddaman 							if (pud)
254*b30d1939SAndy Fiddaman 								pud->next = cap;
255*b30d1939SAndy Fiddaman 							else
256*b30d1939SAndy Fiddaman 								ent->cap = cap;
257*b30d1939SAndy Fiddaman 							if (!(cap->next = dup->next))
258*b30d1939SAndy Fiddaman 								ent->pac = cap;
259*b30d1939SAndy Fiddaman 							cap = dup;
260*b30d1939SAndy Fiddaman 						}
261*b30d1939SAndy Fiddaman 						dropcap(cap);
262*b30d1939SAndy Fiddaman 						return 0;
263*b30d1939SAndy Fiddaman 					}
264*b30d1939SAndy Fiddaman 				ent->pac = ent->pac->next = cap;
265*b30d1939SAndy Fiddaman 			}
266*b30d1939SAndy Fiddaman 			else if (!(ent = newof(0, Ent_t, 1, strlen(s) + 1)))
267*b30d1939SAndy Fiddaman 				return -1;
268*b30d1939SAndy Fiddaman 			else
269*b30d1939SAndy Fiddaman 			{
270*b30d1939SAndy Fiddaman 				strcpy(ent->name, s);
271*b30d1939SAndy Fiddaman 				ent->cap = ent->pac = cap;
272*b30d1939SAndy Fiddaman 				dtinsert(mp->cap, ent);
273*b30d1939SAndy Fiddaman 			}
274*b30d1939SAndy Fiddaman 		}
275*b30d1939SAndy Fiddaman 		else if (ent && (flags & MIME_REPLACE))
276*b30d1939SAndy Fiddaman 			dtdelete(mp->cap, ent);
277*b30d1939SAndy Fiddaman 	}
278*b30d1939SAndy Fiddaman 	return 0;
279*b30d1939SAndy Fiddaman }
280*b30d1939SAndy Fiddaman 
281*b30d1939SAndy Fiddaman /*
282*b30d1939SAndy Fiddaman  * load mime type files into mp
283*b30d1939SAndy Fiddaman  */
284*b30d1939SAndy Fiddaman 
285*b30d1939SAndy Fiddaman int
mimeload(Mime_t * mp,const char * file,unsigned long flags)286*b30d1939SAndy Fiddaman mimeload(Mime_t* mp, const char* file, unsigned long flags)
287*b30d1939SAndy Fiddaman {
288*b30d1939SAndy Fiddaman 	char*	s;
289*b30d1939SAndy Fiddaman 	char*	t;
290*b30d1939SAndy Fiddaman 	char*	e;
291*b30d1939SAndy Fiddaman 	int	n;
292*b30d1939SAndy Fiddaman 	Sfio_t*		fp;
293*b30d1939SAndy Fiddaman 
294*b30d1939SAndy Fiddaman 	if (!(s = (char*)file))
295*b30d1939SAndy Fiddaman 	{
296*b30d1939SAndy Fiddaman 		flags |= MIME_LIST;
297*b30d1939SAndy Fiddaman 		if (!(s = getenv(MIME_FILES_ENV)))
298*b30d1939SAndy Fiddaman 			s = MIME_FILES;
299*b30d1939SAndy Fiddaman 	}
300*b30d1939SAndy Fiddaman 	for (;;)
301*b30d1939SAndy Fiddaman 	{
302*b30d1939SAndy Fiddaman 		if (!(flags & MIME_LIST))
303*b30d1939SAndy Fiddaman 			e = 0;
304*b30d1939SAndy Fiddaman 		else if (e = strchr(s, ':'))
305*b30d1939SAndy Fiddaman 		{
306*b30d1939SAndy Fiddaman 			/*
307*b30d1939SAndy Fiddaman 			 * ok, so ~ won't work for the last list element
308*b30d1939SAndy Fiddaman 			 * we do it for MIME_FILES_ENV anyway
309*b30d1939SAndy Fiddaman 			 */
310*b30d1939SAndy Fiddaman 
311*b30d1939SAndy Fiddaman 			if ((strneq(s, "~/", n = 2) || strneq(s, "$HOME/", n = 6) || strneq(s, "${HOME}/", n = 8)) && (t = getenv("HOME")))
312*b30d1939SAndy Fiddaman 			{
313*b30d1939SAndy Fiddaman 				sfputr(mp->buf, t, -1);
314*b30d1939SAndy Fiddaman 				s += n - 1;
315*b30d1939SAndy Fiddaman 			}
316*b30d1939SAndy Fiddaman 			sfwrite(mp->buf, s, e - s);
317*b30d1939SAndy Fiddaman 			if (!(s = sfstruse(mp->buf)))
318*b30d1939SAndy Fiddaman 				return -1;
319*b30d1939SAndy Fiddaman 		}
320*b30d1939SAndy Fiddaman 		if (fp = tokline(s, SF_READ, NiL))
321*b30d1939SAndy Fiddaman 		{
322*b30d1939SAndy Fiddaman 			while (t = sfgetr(fp, '\n', 1))
323*b30d1939SAndy Fiddaman 				if (mimeset(mp, t, flags))
324*b30d1939SAndy Fiddaman 					break;
325*b30d1939SAndy Fiddaman 			sfclose(fp);
326*b30d1939SAndy Fiddaman 		}
327*b30d1939SAndy Fiddaman 		else if (!(flags & MIME_LIST))
328*b30d1939SAndy Fiddaman 			return -1;
329*b30d1939SAndy Fiddaman 		if (!e)
330*b30d1939SAndy Fiddaman 			break;
331*b30d1939SAndy Fiddaman 		s = e + 1;
332*b30d1939SAndy Fiddaman 	}
333*b30d1939SAndy Fiddaman 	return 0;
334*b30d1939SAndy Fiddaman }
335*b30d1939SAndy Fiddaman 
336*b30d1939SAndy Fiddaman /*
337*b30d1939SAndy Fiddaman  * mimelist walker
338*b30d1939SAndy Fiddaman  */
339*b30d1939SAndy Fiddaman 
340*b30d1939SAndy Fiddaman static int
list(Dt_t * dt,void * object,void * context)341*b30d1939SAndy Fiddaman list(Dt_t* dt, void* object, void* context)
342*b30d1939SAndy Fiddaman {
343*b30d1939SAndy Fiddaman 	Walk_t*	wp = (Walk_t*)context;
344*b30d1939SAndy Fiddaman 	Ent_t*		ent = (Ent_t*)object;
345*b30d1939SAndy Fiddaman 	Cap_t*		cap;
346*b30d1939SAndy Fiddaman 	Att_t*		att;
347*b30d1939SAndy Fiddaman 
348*b30d1939SAndy Fiddaman 	if (!wp->pattern || !strncasecmp(ent->name, wp->pattern, wp->prefix) && (!ent->name[wp->prefix] || ent->name[wp->prefix] == '/'))
349*b30d1939SAndy Fiddaman 	{
350*b30d1939SAndy Fiddaman 		wp->hit++;
351*b30d1939SAndy Fiddaman 		for (cap = ent->cap; cap; cap = cap->next)
352*b30d1939SAndy Fiddaman 		{
353*b30d1939SAndy Fiddaman 			sfprintf(wp->fp, "%s", ent->name);
354*b30d1939SAndy Fiddaman 			for (att = &cap->att; att; att = att->next)
355*b30d1939SAndy Fiddaman 			{
356*b30d1939SAndy Fiddaman 				sfprintf(wp->fp, "\n\t");
357*b30d1939SAndy Fiddaman 				if (att != &cap->att)
358*b30d1939SAndy Fiddaman 				{
359*b30d1939SAndy Fiddaman 					sfprintf(wp->fp, "%s", att->name);
360*b30d1939SAndy Fiddaman 					if (*att->value)
361*b30d1939SAndy Fiddaman 						sfprintf(wp->fp, " = ");
362*b30d1939SAndy Fiddaman 				}
363*b30d1939SAndy Fiddaman 				sfputr(wp->fp, att->value, -1);
364*b30d1939SAndy Fiddaman 			}
365*b30d1939SAndy Fiddaman 			sfprintf(wp->fp, "\n");
366*b30d1939SAndy Fiddaman 		}
367*b30d1939SAndy Fiddaman 	}
368*b30d1939SAndy Fiddaman 	return 0;
369*b30d1939SAndy Fiddaman }
370*b30d1939SAndy Fiddaman 
371*b30d1939SAndy Fiddaman /*
372*b30d1939SAndy Fiddaman  * find entry matching type
373*b30d1939SAndy Fiddaman  * if exact match fails then left and right x- and right version number
374*b30d1939SAndy Fiddaman  * permutations are attempted
375*b30d1939SAndy Fiddaman  */
376*b30d1939SAndy Fiddaman 
377*b30d1939SAndy Fiddaman static Ent_t*
find(Mime_t * mp,const char * type)378*b30d1939SAndy Fiddaman find(Mime_t* mp, const char* type)
379*b30d1939SAndy Fiddaman {
380*b30d1939SAndy Fiddaman 	char*	lp;
381*b30d1939SAndy Fiddaman 	char*	rp;
382*b30d1939SAndy Fiddaman 	char*	rb;
383*b30d1939SAndy Fiddaman 	char*	rv;
384*b30d1939SAndy Fiddaman 	int	rc;
385*b30d1939SAndy Fiddaman 	int	i;
386*b30d1939SAndy Fiddaman 	char*		s;
387*b30d1939SAndy Fiddaman 	Ent_t*		ent;
388*b30d1939SAndy Fiddaman 	char		buf[256];
389*b30d1939SAndy Fiddaman 
390*b30d1939SAndy Fiddaman 	static const char*	prefix[] = { "", "", "x-", "x-", "" };
391*b30d1939SAndy Fiddaman 
392*b30d1939SAndy Fiddaman 	if ((ent = (Ent_t*)dtmatch(mp->cap, type)) ||
393*b30d1939SAndy Fiddaman 	    !(rp = strchr(lp = (char*)type, '/')) ||
394*b30d1939SAndy Fiddaman 	    strlen(lp) >= sizeof(buf))
395*b30d1939SAndy Fiddaman 		return ent;
396*b30d1939SAndy Fiddaman 	strcpy(buf, type);
397*b30d1939SAndy Fiddaman 	rp = buf + (rp - lp);
398*b30d1939SAndy Fiddaman 	*rp++ = 0;
399*b30d1939SAndy Fiddaman 	if (*rp == 'x' && *(rp + 1) == '-')
400*b30d1939SAndy Fiddaman 		rp += 2;
401*b30d1939SAndy Fiddaman 	lp = buf;
402*b30d1939SAndy Fiddaman 	if (*lp == 'x' && *(lp + 1) == '-')
403*b30d1939SAndy Fiddaman 		lp += 2;
404*b30d1939SAndy Fiddaman 	rb = rp;
405*b30d1939SAndy Fiddaman 	for (rv = rp + strlen(rp); rv > rp && (isdigit(*(rv - 1)) || *(rv - 1) == '.'); rv--);
406*b30d1939SAndy Fiddaman 	rc = *rv;
407*b30d1939SAndy Fiddaman 	do
408*b30d1939SAndy Fiddaman 	{
409*b30d1939SAndy Fiddaman 		rp = rb;
410*b30d1939SAndy Fiddaman 		do
411*b30d1939SAndy Fiddaman 		{
412*b30d1939SAndy Fiddaman 			for (i = 0; i < elementsof(prefix) - 1; i++)
413*b30d1939SAndy Fiddaman 			{
414*b30d1939SAndy Fiddaman 				sfprintf(mp->buf, "%s%s/%s%s", prefix[i], lp, prefix[i + 1], rp);
415*b30d1939SAndy Fiddaman 				if (!(s = sfstruse(mp->buf)))
416*b30d1939SAndy Fiddaman 					return 0;
417*b30d1939SAndy Fiddaman 				if (ent = (Ent_t*)dtmatch(mp->cap, s))
418*b30d1939SAndy Fiddaman 					return ent;
419*b30d1939SAndy Fiddaman 				if (rc)
420*b30d1939SAndy Fiddaman 				{
421*b30d1939SAndy Fiddaman 					*rv = 0;
422*b30d1939SAndy Fiddaman 					sfprintf(mp->buf, "%s%s/%s%s", prefix[i], lp, prefix[i + 1], rp);
423*b30d1939SAndy Fiddaman 					if (!(s = sfstruse(mp->buf)))
424*b30d1939SAndy Fiddaman 						return 0;
425*b30d1939SAndy Fiddaman 					if (ent = (Ent_t*)dtmatch(mp->cap, s))
426*b30d1939SAndy Fiddaman 						return ent;
427*b30d1939SAndy Fiddaman 					*rv = rc;
428*b30d1939SAndy Fiddaman 				}
429*b30d1939SAndy Fiddaman 			}
430*b30d1939SAndy Fiddaman 			while (*rp && *rp++ != '-');
431*b30d1939SAndy Fiddaman 		} while (*rp);
432*b30d1939SAndy Fiddaman 		while (*lp && *lp++ != '-');
433*b30d1939SAndy Fiddaman 	} while (*lp);
434*b30d1939SAndy Fiddaman 	return (Ent_t*)dtmatch(mp->cap, buf);
435*b30d1939SAndy Fiddaman }
436*b30d1939SAndy Fiddaman 
437*b30d1939SAndy Fiddaman /*
438*b30d1939SAndy Fiddaman  * list mime <type,data> for pat on fp
439*b30d1939SAndy Fiddaman  */
440*b30d1939SAndy Fiddaman 
441*b30d1939SAndy Fiddaman int
mimelist(Mime_t * mp,Sfio_t * fp,const char * pattern)442*b30d1939SAndy Fiddaman mimelist(Mime_t* mp, Sfio_t* fp, const char* pattern)
443*b30d1939SAndy Fiddaman {
444*b30d1939SAndy Fiddaman 	Ent_t*	ent;
445*b30d1939SAndy Fiddaman 	Walk_t	ws;
446*b30d1939SAndy Fiddaman 
447*b30d1939SAndy Fiddaman 	ws.fp = fp;
448*b30d1939SAndy Fiddaman 	ws.hit = 0;
449*b30d1939SAndy Fiddaman 	ws.prefix = 0;
450*b30d1939SAndy Fiddaman 	if (ws.pattern = pattern)
451*b30d1939SAndy Fiddaman 	{
452*b30d1939SAndy Fiddaman 		while (*pattern && *pattern++ != '/');
453*b30d1939SAndy Fiddaman 		if (!*pattern || *pattern == '*' && !*(pattern + 1))
454*b30d1939SAndy Fiddaman 			ws.prefix = pattern - ws.pattern;
455*b30d1939SAndy Fiddaman 		else if (ent = find(mp, ws.pattern))
456*b30d1939SAndy Fiddaman 		{
457*b30d1939SAndy Fiddaman 			ws.pattern = 0;
458*b30d1939SAndy Fiddaman 			list(mp->cap, ent, &ws);
459*b30d1939SAndy Fiddaman 			return ws.hit;
460*b30d1939SAndy Fiddaman 		}
461*b30d1939SAndy Fiddaman 	}
462*b30d1939SAndy Fiddaman 	dtwalk(mp->cap, list, &ws);
463*b30d1939SAndy Fiddaman 	return ws.hit;
464*b30d1939SAndy Fiddaman }
465*b30d1939SAndy Fiddaman 
466*b30d1939SAndy Fiddaman /*
467*b30d1939SAndy Fiddaman  * get next arg in pp
468*b30d1939SAndy Fiddaman  * 0 returned if no more args
469*b30d1939SAndy Fiddaman  */
470*b30d1939SAndy Fiddaman 
471*b30d1939SAndy Fiddaman static int
arg(Parse_t * pp,int first)472*b30d1939SAndy Fiddaman arg(Parse_t* pp, int first)
473*b30d1939SAndy Fiddaman {
474*b30d1939SAndy Fiddaman 	char*	s;
475*b30d1939SAndy Fiddaman 	int	c;
476*b30d1939SAndy Fiddaman 	int	q;
477*b30d1939SAndy Fiddaman 	int		x;
478*b30d1939SAndy Fiddaman 
479*b30d1939SAndy Fiddaman 	for (s = pp->next; isspace(*s) && *s != '\n'; s++);
480*b30d1939SAndy Fiddaman 	if (!*s || *s == '\n')
481*b30d1939SAndy Fiddaman 	{
482*b30d1939SAndy Fiddaman 		pp->next = s;
483*b30d1939SAndy Fiddaman 		return 0;
484*b30d1939SAndy Fiddaman 	}
485*b30d1939SAndy Fiddaman 	pp->name.data = s;
486*b30d1939SAndy Fiddaman 	pp->value.data = 0;
487*b30d1939SAndy Fiddaman 	q = 0;
488*b30d1939SAndy Fiddaman 	x = 0;
489*b30d1939SAndy Fiddaman 	while ((c = *s++) && c != ';' && c != '\n')
490*b30d1939SAndy Fiddaman 	{
491*b30d1939SAndy Fiddaman 		if (c == '"')
492*b30d1939SAndy Fiddaman 		{
493*b30d1939SAndy Fiddaman 			q = 1;
494*b30d1939SAndy Fiddaman 			if (pp->value.data)
495*b30d1939SAndy Fiddaman 			{
496*b30d1939SAndy Fiddaman 				pp->value.data = s;
497*b30d1939SAndy Fiddaman 				if (x)
498*b30d1939SAndy Fiddaman 					x = -1;
499*b30d1939SAndy Fiddaman 				else
500*b30d1939SAndy Fiddaman 					x = 1;
501*b30d1939SAndy Fiddaman 			}
502*b30d1939SAndy Fiddaman 			else if (!x && pp->name.data == (s - 1))
503*b30d1939SAndy Fiddaman 			{
504*b30d1939SAndy Fiddaman 				x = 1;
505*b30d1939SAndy Fiddaman 				pp->name.data = s;
506*b30d1939SAndy Fiddaman 			}
507*b30d1939SAndy Fiddaman 			do
508*b30d1939SAndy Fiddaman 			{
509*b30d1939SAndy Fiddaman 				if (!(c = *s++) || c == '\n')
510*b30d1939SAndy Fiddaman 				{
511*b30d1939SAndy Fiddaman 					s--;
512*b30d1939SAndy Fiddaman 					break;
513*b30d1939SAndy Fiddaman 				}
514*b30d1939SAndy Fiddaman 			} while (c != '"');
515*b30d1939SAndy Fiddaman 			if (first < 0 || x > 0)
516*b30d1939SAndy Fiddaman 			{
517*b30d1939SAndy Fiddaman 				c = ';';
518*b30d1939SAndy Fiddaman 				break;
519*b30d1939SAndy Fiddaman 			}
520*b30d1939SAndy Fiddaman  		}
521*b30d1939SAndy Fiddaman 		else if (c == '=' && !first)
522*b30d1939SAndy Fiddaman 		{
523*b30d1939SAndy Fiddaman 			first = 1;
524*b30d1939SAndy Fiddaman 			pp->name.size = s - pp->name.data - 1;
525*b30d1939SAndy Fiddaman 			pp->value.data = s;
526*b30d1939SAndy Fiddaman 		}
527*b30d1939SAndy Fiddaman 		else if (first >= 0 && isspace(c))
528*b30d1939SAndy Fiddaman 			break;
529*b30d1939SAndy Fiddaman 	}
530*b30d1939SAndy Fiddaman 	pp->next = s - (c != ';');
531*b30d1939SAndy Fiddaman 	if (first >= 0 || !q)
532*b30d1939SAndy Fiddaman 		for (s--; s > pp->name.data && isspace(*(s - 1)); s--);
533*b30d1939SAndy Fiddaman 	if (pp->value.data)
534*b30d1939SAndy Fiddaman 		pp->value.size = s - pp->value.data - (q && first < 0);
535*b30d1939SAndy Fiddaman 	else
536*b30d1939SAndy Fiddaman 	{
537*b30d1939SAndy Fiddaman 		pp->value.size = 0;
538*b30d1939SAndy Fiddaman 		pp->name.size = s - pp->name.data - (q && first < 0);
539*b30d1939SAndy Fiddaman 	}
540*b30d1939SAndy Fiddaman 	if (first >= 0 && pp->name.size > 0 && pp->name.data[pp->name.size - 1] == ':')
541*b30d1939SAndy Fiddaman 		return 0;
542*b30d1939SAndy Fiddaman 	return pp->name.size > 0;
543*b30d1939SAndy Fiddaman }
544*b30d1939SAndy Fiddaman 
545*b30d1939SAndy Fiddaman /*
546*b30d1939SAndy Fiddaman  * low level for mimeview()
547*b30d1939SAndy Fiddaman  */
548*b30d1939SAndy Fiddaman 
549*b30d1939SAndy Fiddaman static char*
expand(Mime_t * mp,char * s,const char * name,const char * type,const char * opts)550*b30d1939SAndy Fiddaman expand(Mime_t* mp, char* s, const char* name, const char* type, const char* opts)
551*b30d1939SAndy Fiddaman {
552*b30d1939SAndy Fiddaman 	char*	t;
553*b30d1939SAndy Fiddaman 	char*	v;
554*b30d1939SAndy Fiddaman 	int	c;
555*b30d1939SAndy Fiddaman 	int	e;
556*b30d1939SAndy Fiddaman 	int	n;
557*b30d1939SAndy Fiddaman 	Parse_t		pp;
558*b30d1939SAndy Fiddaman 
559*b30d1939SAndy Fiddaman 	mp->disc->flags |= MIME_PIPE;
560*b30d1939SAndy Fiddaman 	for (;;)
561*b30d1939SAndy Fiddaman 	{
562*b30d1939SAndy Fiddaman 		switch (c = *s++)
563*b30d1939SAndy Fiddaman 		{
564*b30d1939SAndy Fiddaman 		case 0:
565*b30d1939SAndy Fiddaman 		case '\n':
566*b30d1939SAndy Fiddaman 			break;
567*b30d1939SAndy Fiddaman 		case '%':
568*b30d1939SAndy Fiddaman 			if ((c = *s++) == '{' && (e = '}') || c == '(' && (e = ')'))
569*b30d1939SAndy Fiddaman 			{
570*b30d1939SAndy Fiddaman 				for (t = s; *s && *s != e; s++);
571*b30d1939SAndy Fiddaman 				n = s - t;
572*b30d1939SAndy Fiddaman 				switch (*s)
573*b30d1939SAndy Fiddaman 				{
574*b30d1939SAndy Fiddaman 				case '}':
575*b30d1939SAndy Fiddaman 					s++;
576*b30d1939SAndy Fiddaman 					c = '{';
577*b30d1939SAndy Fiddaman 					break;
578*b30d1939SAndy Fiddaman 				case ')':
579*b30d1939SAndy Fiddaman 					s++;
580*b30d1939SAndy Fiddaman 					if (c = *s)
581*b30d1939SAndy Fiddaman 						s++;
582*b30d1939SAndy Fiddaman 					break;
583*b30d1939SAndy Fiddaman 				}
584*b30d1939SAndy Fiddaman 			}
585*b30d1939SAndy Fiddaman 			else
586*b30d1939SAndy Fiddaman 				t = 0;
587*b30d1939SAndy Fiddaman 			switch (c)
588*b30d1939SAndy Fiddaman 			{
589*b30d1939SAndy Fiddaman 			case 's':
590*b30d1939SAndy Fiddaman 				v = (char*)name;
591*b30d1939SAndy Fiddaman 				mp->disc->flags &= ~MIME_PIPE;
592*b30d1939SAndy Fiddaman 				break;
593*b30d1939SAndy Fiddaman 			case 't':
594*b30d1939SAndy Fiddaman 				v = (char*)type;
595*b30d1939SAndy Fiddaman 				break;
596*b30d1939SAndy Fiddaman 			case '{':
597*b30d1939SAndy Fiddaman 				for (t = s; *s && *s != '}'; s++);
598*b30d1939SAndy Fiddaman 				if (*s && (c = s++ - t) && (pp.next = (char*)opts))
599*b30d1939SAndy Fiddaman 					while (arg(&pp, 0))
600*b30d1939SAndy Fiddaman 						if (pp.name.size == c && !strncasecmp(pp.name.data, t, c))
601*b30d1939SAndy Fiddaman 						{
602*b30d1939SAndy Fiddaman 							if (pp.value.size)
603*b30d1939SAndy Fiddaman 								sfwrite(mp->buf, pp.value.data, pp.value.size);
604*b30d1939SAndy Fiddaman 							break;
605*b30d1939SAndy Fiddaman 						}
606*b30d1939SAndy Fiddaman 				continue;
607*b30d1939SAndy Fiddaman 			default:
608*b30d1939SAndy Fiddaman 				sfputc(mp->buf, c);
609*b30d1939SAndy Fiddaman 				continue;
610*b30d1939SAndy Fiddaman 			}
611*b30d1939SAndy Fiddaman 			if (v && *v)
612*b30d1939SAndy Fiddaman 				n = strlen(v);
613*b30d1939SAndy Fiddaman 			else if (t)
614*b30d1939SAndy Fiddaman 				v = t;
615*b30d1939SAndy Fiddaman 			else
616*b30d1939SAndy Fiddaman 				continue;
617*b30d1939SAndy Fiddaman 			sfputr(mp->buf, fmtquote(v, 0, 0, n, FMT_SHELL), -1);
618*b30d1939SAndy Fiddaman 			continue;
619*b30d1939SAndy Fiddaman 		default:
620*b30d1939SAndy Fiddaman 			sfputc(mp->buf, c);
621*b30d1939SAndy Fiddaman 			continue;
622*b30d1939SAndy Fiddaman 		}
623*b30d1939SAndy Fiddaman 		break;
624*b30d1939SAndy Fiddaman 	}
625*b30d1939SAndy Fiddaman 	return sfstruse(mp->buf);
626*b30d1939SAndy Fiddaman }
627*b30d1939SAndy Fiddaman 
628*b30d1939SAndy Fiddaman /*
629*b30d1939SAndy Fiddaman  * return expanded command/path/value for <view,name,type,opts>
630*b30d1939SAndy Fiddaman  * return value valid until next mime*() call
631*b30d1939SAndy Fiddaman  */
632*b30d1939SAndy Fiddaman 
633*b30d1939SAndy Fiddaman char*
mimeview(Mime_t * mp,const char * view,const char * name,const char * type,const char * opts)634*b30d1939SAndy Fiddaman mimeview(Mime_t* mp, const char* view, const char* name, const char* type, const char* opts)
635*b30d1939SAndy Fiddaman {
636*b30d1939SAndy Fiddaman 	Ent_t*	ent;
637*b30d1939SAndy Fiddaman 	Cap_t*	cap;
638*b30d1939SAndy Fiddaman 	Att_t*	att;
639*b30d1939SAndy Fiddaman 	char*	s;
640*b30d1939SAndy Fiddaman 	int		c;
641*b30d1939SAndy Fiddaman 
642*b30d1939SAndy Fiddaman 	if (ent = find(mp, type))
643*b30d1939SAndy Fiddaman 	{
644*b30d1939SAndy Fiddaman 		cap = ent->cap;
645*b30d1939SAndy Fiddaman 		if (!view || strcasecmp(view, "test"))
646*b30d1939SAndy Fiddaman 			while (s = cap->test)
647*b30d1939SAndy Fiddaman 			{
648*b30d1939SAndy Fiddaman 				if (s = expand(mp, s, name, type, opts))
649*b30d1939SAndy Fiddaman 				{
650*b30d1939SAndy Fiddaman 					Parse_t	a1;
651*b30d1939SAndy Fiddaman 					Parse_t	a2;
652*b30d1939SAndy Fiddaman 					Parse_t	a3;
653*b30d1939SAndy Fiddaman 					Parse_t	a4;
654*b30d1939SAndy Fiddaman 
655*b30d1939SAndy Fiddaman 					/*
656*b30d1939SAndy Fiddaman 					 * try to do a few common cases here
657*b30d1939SAndy Fiddaman 					 * mailcap consistency is a winning
658*b30d1939SAndy Fiddaman 					 * strategy
659*b30d1939SAndy Fiddaman 					 */
660*b30d1939SAndy Fiddaman 
661*b30d1939SAndy Fiddaman 					a1.next = s;
662*b30d1939SAndy Fiddaman 					if (arg(&a1, -1))
663*b30d1939SAndy Fiddaman 					{
664*b30d1939SAndy Fiddaman 						if ((c = *a1.name.data == '!') && --a1.name.size <= 0 && !arg(&a1, -1))
665*b30d1939SAndy Fiddaman 							goto lose;
666*b30d1939SAndy Fiddaman 						if (a1.name.size == 6 && strneq(a1.name.data, "strcmp", 6) || a1.name.size == 10 && strneq(a1.name.data, "strcasecmp", 10))
667*b30d1939SAndy Fiddaman 						{
668*b30d1939SAndy Fiddaman 							a2.next = a1.next;
669*b30d1939SAndy Fiddaman 							if (!arg(&a2, -1))
670*b30d1939SAndy Fiddaman 								goto lose;
671*b30d1939SAndy Fiddaman 							a3.next = a2.next;
672*b30d1939SAndy Fiddaman 							if (!arg(&a3, -1))
673*b30d1939SAndy Fiddaman 								goto lose;
674*b30d1939SAndy Fiddaman 							if (a2.name.size != a3.name.size)
675*b30d1939SAndy Fiddaman 								c ^= 0;
676*b30d1939SAndy Fiddaman 							else c ^= (a1.name.size == 6 ? strncmp : strncasecmp)(a2.name.data, a3.name.data, a2.name.size) == 0;
677*b30d1939SAndy Fiddaman 							if (c)
678*b30d1939SAndy Fiddaman 								break;
679*b30d1939SAndy Fiddaman 							goto skip;
680*b30d1939SAndy Fiddaman 						}
681*b30d1939SAndy Fiddaman 						else if (a1.name.size == 4 && strneq(a1.name.data, "test", 4))
682*b30d1939SAndy Fiddaman 						{
683*b30d1939SAndy Fiddaman 							if (!arg(&a1, -1))
684*b30d1939SAndy Fiddaman 								goto lose;
685*b30d1939SAndy Fiddaman 							a2.next = a1.next;
686*b30d1939SAndy Fiddaman 							if (!arg(&a2, -1) || a2.name.size > 2 || a2.name.size == 1 && *a2.name.data != '=' || a2.name.size == 2 && (!strneq(a1.name.data, "!=", 2) || !strneq(a2.name.data, "==", 2)))
687*b30d1939SAndy Fiddaman 								goto lose;
688*b30d1939SAndy Fiddaman 							a3.next = a2.next;
689*b30d1939SAndy Fiddaman 							if (!arg(&a3, -1))
690*b30d1939SAndy Fiddaman 								goto lose;
691*b30d1939SAndy Fiddaman 							if (*a3.name.data == '`' && *(a3.name.data + a3.name.size - 1) == '`')
692*b30d1939SAndy Fiddaman 							{
693*b30d1939SAndy Fiddaman 								a4 = a3;
694*b30d1939SAndy Fiddaman 								a3 = a1;
695*b30d1939SAndy Fiddaman 								a1 = a4;
696*b30d1939SAndy Fiddaman 							}
697*b30d1939SAndy Fiddaman 							if (*a1.name.data == '`' && *(a1.name.data + a1.name.size - 1) == '`')
698*b30d1939SAndy Fiddaman 							{
699*b30d1939SAndy Fiddaman 								a1.next = a1.name.data + 1;
700*b30d1939SAndy Fiddaman 								if (!arg(&a1, -1) || a1.name.size != 4 || !strneq(a1.name.data, "echo", 4) || !arg(&a1, -1))
701*b30d1939SAndy Fiddaman 									goto lose;
702*b30d1939SAndy Fiddaman 								a4.next = a1.next;
703*b30d1939SAndy Fiddaman 								if (!arg(&a4, 1) || a4.name.size < 21 || !strneq(a4.name.data, "| tr '[A-Z]' '[a-z]'`", 21))
704*b30d1939SAndy Fiddaman 									goto lose;
705*b30d1939SAndy Fiddaman 							}
706*b30d1939SAndy Fiddaman 							else
707*b30d1939SAndy Fiddaman 								a4.name.size = 0;
708*b30d1939SAndy Fiddaman 							c = *a2.name.data == '!';
709*b30d1939SAndy Fiddaman 							if (a1.name.size != a3.name.size)
710*b30d1939SAndy Fiddaman 								c ^= 0;
711*b30d1939SAndy Fiddaman 							else c ^= (a4.name.size ? strncasecmp : strncmp)(a1.name.data, a3.name.data, a1.name.size) == 0;
712*b30d1939SAndy Fiddaman 							if (c)
713*b30d1939SAndy Fiddaman 								break;
714*b30d1939SAndy Fiddaman 							goto skip;
715*b30d1939SAndy Fiddaman 						}
716*b30d1939SAndy Fiddaman 					}
717*b30d1939SAndy Fiddaman 				lose:
718*b30d1939SAndy Fiddaman 					if (!system(s))
719*b30d1939SAndy Fiddaman 						break;
720*b30d1939SAndy Fiddaman 				}
721*b30d1939SAndy Fiddaman 			skip:
722*b30d1939SAndy Fiddaman 				if (!(cap = cap->next))
723*b30d1939SAndy Fiddaman 					return 0;
724*b30d1939SAndy Fiddaman 			}
725*b30d1939SAndy Fiddaman 		att = &cap->att;
726*b30d1939SAndy Fiddaman 		if (view && *view && !streq(view, "-"))
727*b30d1939SAndy Fiddaman 			while (strcasecmp(view, att->name))
728*b30d1939SAndy Fiddaman 				if (!(att = att->next))
729*b30d1939SAndy Fiddaman 					return 0;
730*b30d1939SAndy Fiddaman 		return expand(mp, att->value, name, type, opts);
731*b30d1939SAndy Fiddaman 	}
732*b30d1939SAndy Fiddaman 	return 0;
733*b30d1939SAndy Fiddaman }
734*b30d1939SAndy Fiddaman 
735*b30d1939SAndy Fiddaman /*
736*b30d1939SAndy Fiddaman  * lower case identifier prefix strcmp
737*b30d1939SAndy Fiddaman  * if e!=0 then it will point to the next char after the match
738*b30d1939SAndy Fiddaman  */
739*b30d1939SAndy Fiddaman 
740*b30d1939SAndy Fiddaman int
mimecmp(const char * s,const char * v,char ** e)741*b30d1939SAndy Fiddaman mimecmp(const char* s, const char* v, char** e)
742*b30d1939SAndy Fiddaman {
743*b30d1939SAndy Fiddaman 	int	n;
744*b30d1939SAndy Fiddaman 
745*b30d1939SAndy Fiddaman 	while (isalnum(*v) || *v == *s && (*v == '_' || *v == '-' || *v == '/'))
746*b30d1939SAndy Fiddaman 		if (n = lower(*s++) - lower(*v++))
747*b30d1939SAndy Fiddaman 			return n;
748*b30d1939SAndy Fiddaman 	if (!isalnum(*s) && *s != '_' && *s != '-')
749*b30d1939SAndy Fiddaman 	{
750*b30d1939SAndy Fiddaman 		if (e)
751*b30d1939SAndy Fiddaman 			*e = (char*)s;
752*b30d1939SAndy Fiddaman 		return 0;
753*b30d1939SAndy Fiddaman 	}
754*b30d1939SAndy Fiddaman 	return lower(*s) - lower(*v);
755*b30d1939SAndy Fiddaman }
756*b30d1939SAndy Fiddaman 
757*b30d1939SAndy Fiddaman static int
_mimecmp(const char * s,const char * v)758*b30d1939SAndy Fiddaman _mimecmp(const char* s, const char* v)
759*b30d1939SAndy Fiddaman {
760*b30d1939SAndy Fiddaman 	return (mimecmp(s, v, NULL));
761*b30d1939SAndy Fiddaman }
762*b30d1939SAndy Fiddaman 
763*b30d1939SAndy Fiddaman /*
764*b30d1939SAndy Fiddaman  * parse mime headers in strsearch(tab,num,siz) from s
765*b30d1939SAndy Fiddaman  * return >0 if mime header consumed
766*b30d1939SAndy Fiddaman  */
767*b30d1939SAndy Fiddaman 
768*b30d1939SAndy Fiddaman int
mimehead(Mime_t * mp,void * tab,size_t num,size_t siz,char * s)769*b30d1939SAndy Fiddaman mimehead(Mime_t* mp, void* tab, size_t num, size_t siz, char* s)
770*b30d1939SAndy Fiddaman {
771*b30d1939SAndy Fiddaman 	void*	p;
772*b30d1939SAndy Fiddaman 	char*		e;
773*b30d1939SAndy Fiddaman 	Parse_t		pp;
774*b30d1939SAndy Fiddaman 	Mimevalue_f	set;
775*b30d1939SAndy Fiddaman 
776*b30d1939SAndy Fiddaman 	set = mp->disc->valuef;
777*b30d1939SAndy Fiddaman 	if (!strncasecmp(s, "original-", 9))
778*b30d1939SAndy Fiddaman 		s += 9;
779*b30d1939SAndy Fiddaman 	if (!strncasecmp(s, "content-", 8))
780*b30d1939SAndy Fiddaman 	{
781*b30d1939SAndy Fiddaman 		s += 8;
782*b30d1939SAndy Fiddaman 		if ((p = strsearch(tab, num, siz, _mimecmp, s, &e)) && *e == ':')
783*b30d1939SAndy Fiddaman 		{
784*b30d1939SAndy Fiddaman 			pp.next = e + 1;
785*b30d1939SAndy Fiddaman 			if (arg(&pp, 1))
786*b30d1939SAndy Fiddaman 			{
787*b30d1939SAndy Fiddaman 				if ((*set)(mp, p, pp.name.data, pp.name.size, mp->disc))
788*b30d1939SAndy Fiddaman 					return 0;
789*b30d1939SAndy Fiddaman 				while (arg(&pp, 0))
790*b30d1939SAndy Fiddaman 					if (pp.value.size &&
791*b30d1939SAndy Fiddaman 					    (p = strsearch(tab, num, siz, _mimecmp, pp.name.data, &e)) &&
792*b30d1939SAndy Fiddaman 					    (*set)(mp, p, pp.value.data, pp.value.size, mp->disc))
793*b30d1939SAndy Fiddaman 						return 0;
794*b30d1939SAndy Fiddaman 				return 1;
795*b30d1939SAndy Fiddaman 			}
796*b30d1939SAndy Fiddaman 		}
797*b30d1939SAndy Fiddaman 		else if (strchr(s, ':'))
798*b30d1939SAndy Fiddaman 			return 1;
799*b30d1939SAndy Fiddaman 	}
800*b30d1939SAndy Fiddaman 	return !strncasecmp(s, "x-", 2);
801*b30d1939SAndy Fiddaman }
802*b30d1939SAndy Fiddaman 
803*b30d1939SAndy Fiddaman /*
804*b30d1939SAndy Fiddaman  * open a mime library handle
805*b30d1939SAndy Fiddaman  */
806*b30d1939SAndy Fiddaman 
807*b30d1939SAndy Fiddaman Mime_t*
mimeopen(Mimedisc_t * disc)808*b30d1939SAndy Fiddaman mimeopen(Mimedisc_t* disc)
809*b30d1939SAndy Fiddaman {
810*b30d1939SAndy Fiddaman 	Mime_t*	mp;
811*b30d1939SAndy Fiddaman 
812*b30d1939SAndy Fiddaman 	if (!(mp = newof(0, Mime_t, 1, 0)))
813*b30d1939SAndy Fiddaman 		return 0;
814*b30d1939SAndy Fiddaman 	mp->id = lib;
815*b30d1939SAndy Fiddaman 	mp->disc = disc;
816*b30d1939SAndy Fiddaman 	mp->dict.key = offsetof(Ent_t, name);
817*b30d1939SAndy Fiddaman 	mp->dict.comparf = order;
818*b30d1939SAndy Fiddaman 	mp->dict.freef = drop;
819*b30d1939SAndy Fiddaman 	if (!(mp->buf = sfstropen()) || !(mp->cap = dtopen(&mp->dict, Dtoset)))
820*b30d1939SAndy Fiddaman 	{
821*b30d1939SAndy Fiddaman 		mimeclose(mp);
822*b30d1939SAndy Fiddaman 		return 0;
823*b30d1939SAndy Fiddaman 	}
824*b30d1939SAndy Fiddaman 	return mp;
825*b30d1939SAndy Fiddaman }
826*b30d1939SAndy Fiddaman 
827*b30d1939SAndy Fiddaman /*
828*b30d1939SAndy Fiddaman  * close a mimeopen() handle
829*b30d1939SAndy Fiddaman  */
830*b30d1939SAndy Fiddaman 
831*b30d1939SAndy Fiddaman int
mimeclose(Mime_t * mp)832*b30d1939SAndy Fiddaman mimeclose(Mime_t* mp)
833*b30d1939SAndy Fiddaman {
834*b30d1939SAndy Fiddaman 	if (mp)
835*b30d1939SAndy Fiddaman 	{
836*b30d1939SAndy Fiddaman 		if (mp->buf)
837*b30d1939SAndy Fiddaman 			sfclose(mp->buf);
838*b30d1939SAndy Fiddaman 		if (mp->cap)
839*b30d1939SAndy Fiddaman 			dtclose(mp->cap);
840*b30d1939SAndy Fiddaman 		if (mp->freef)
841*b30d1939SAndy Fiddaman 			(*mp->freef)(mp);
842*b30d1939SAndy Fiddaman 		free(mp);
843*b30d1939SAndy Fiddaman 	}
844*b30d1939SAndy Fiddaman 	return 0;
845*b30d1939SAndy Fiddaman }
846