14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * Phong Vo <kpv@research.att.com> * 204887Schin * * 214887Schin ***********************************************************************/ 224887Schin #pragma prototyped 234887Schin 244887Schin /* 254887Schin * Glenn Fowler 264887Schin * AT&T Research 274887Schin * 284887Schin * mime/mailcap support library 294887Schin */ 304887Schin 314887Schin static const char id[] = "\n@(#)$Id: mime library (AT&T Research) 2002-10-29 $\0\n"; 324887Schin 334887Schin static const char lib[] = "libast:mime"; 344887Schin 354887Schin #include "mimelib.h" 364887Schin 374887Schin typedef struct Att_s 384887Schin { 394887Schin struct Att_s* next; 404887Schin char* name; 414887Schin char* value; 424887Schin } Att_t; 434887Schin 444887Schin typedef struct Cap_s 454887Schin { 464887Schin struct Cap_s* next; 474887Schin unsigned long flags; 484887Schin Att_t att; 494887Schin char* test; 504887Schin char data[1]; 514887Schin } Cap_t; 524887Schin 534887Schin typedef struct 544887Schin { 554887Schin Dtlink_t link; 564887Schin Cap_t* cap; 574887Schin Cap_t* pac; 584887Schin char name[1]; 594887Schin } Ent_t; 604887Schin 614887Schin typedef struct 624887Schin { 634887Schin char* data; 644887Schin int size; 654887Schin } String_t; 664887Schin 674887Schin typedef struct 684887Schin { 694887Schin char* next; 704887Schin String_t name; 714887Schin String_t value; 724887Schin } Parse_t; 734887Schin 744887Schin typedef struct 754887Schin { 764887Schin const char* pattern; 774887Schin int prefix; 784887Schin Sfio_t* fp; 794887Schin int hit; 804887Schin } Walk_t; 814887Schin 824887Schin /* 834887Schin * convert c to lower case 844887Schin */ 854887Schin 864887Schin static int 874887Schin lower(register int c) 884887Schin { 894887Schin return isupper(c) ? tolower(c) : c; 904887Schin } 914887Schin 924887Schin /* 934887Schin * Ent_t case insensitive comparf 944887Schin */ 954887Schin 964887Schin static int 974887Schin order(Dt_t* dt, void* a, void* b, Dtdisc_t* disc) 984887Schin { 994887Schin return strcasecmp(a, b); 1004887Schin } 1014887Schin 1024887Schin /* 1034887Schin * Cap_t free 1044887Schin */ 1054887Schin 1064887Schin static void 1074887Schin dropcap(register Cap_t* cap) 1084887Schin { 1094887Schin register Att_t* att; 1104887Schin 1114887Schin while (att = cap->att.next) 1124887Schin { 1134887Schin cap->att.next = att->next; 1144887Schin free(att); 1154887Schin } 1164887Schin free(cap); 1174887Schin } 1184887Schin 1194887Schin /* 1204887Schin * Ent_t freef 1214887Schin */ 1224887Schin 1234887Schin static void 1244887Schin drop(Dt_t* dt, void* object, Dtdisc_t* disc) 1254887Schin { 1264887Schin register Ent_t* ent = (Ent_t*)object; 1274887Schin register Cap_t* cap; 1284887Schin 1294887Schin while (cap = ent->cap) 1304887Schin { 1314887Schin ent->cap = cap->next; 1324887Schin dropcap(cap); 1334887Schin } 1344887Schin free(ent); 1354887Schin } 1364887Schin 1374887Schin /* 1384887Schin * add mime type entry in s to mp 1394887Schin */ 1404887Schin 1414887Schin int 1424887Schin mimeset(Mime_t* mp, register char* s, unsigned long flags) 1434887Schin { 1444887Schin register Ent_t* ent; 1454887Schin register Cap_t* cap; 1464887Schin register Att_t* att; 1474887Schin register char* t; 1484887Schin register char* v; 1494887Schin register char* k; 1504887Schin char* x; 1514887Schin Att_t* tta; 1524887Schin int q; 1534887Schin 1544887Schin for (; isspace(*s); s++); 1554887Schin if (*s && *s != '#') 1564887Schin { 1574887Schin cap = 0; 1584887Schin for (v = s; *v && *v != ';'; v++) 1594887Schin if (isspace(*v) || *v == '/' && *(v + 1) == '*') 1604887Schin *v = 0; 1614887Schin if (*v) 1624887Schin { 1634887Schin *v++ = 0; 1644887Schin do 1654887Schin { 1664887Schin for (; isspace(*v); v++); 1674887Schin if (cap) 1684887Schin { 1694887Schin for (t = v; *t && !isspace(*t) && *t != '='; t++); 1704887Schin for (k = t; isspace(*t); t++); 1714887Schin if (!*t || *t == '=' || *t == ';') 1724887Schin { 1734887Schin if (*t) 1744887Schin while (isspace(*++t)); 1754887Schin *k = 0; 1764887Schin k = v; 1774887Schin v = t; 1784887Schin } 1794887Schin else 1804887Schin k = 0; 1814887Schin } 1824887Schin if (*v == '"') 1834887Schin q = *v++; 1844887Schin else 1854887Schin q = 0; 1864887Schin for (t = v; *t; t++) 1874887Schin if (*t == '\\') 1884887Schin { 1894887Schin switch (*(t + 1)) 1904887Schin { 1914887Schin case 0: 1924887Schin case '\\': 1934887Schin case '%': 1944887Schin *t = *(t + 1); 1954887Schin break; 1964887Schin default: 1974887Schin *t = ' '; 1984887Schin break; 1994887Schin } 2004887Schin if (!*++t) 2014887Schin break; 2024887Schin } 2034887Schin else if (*t == q) 2044887Schin { 2054887Schin *t = ' '; 2064887Schin q = 0; 2074887Schin } 2084887Schin else if (*t == ';' && !q) 2094887Schin { 2104887Schin *t = ' '; 2114887Schin break; 2124887Schin } 2134887Schin for (; t > v && isspace(*(t - 1)); t--); 2144887Schin if (t <= v && (!cap || !k)) 2154887Schin break; 2164887Schin if (!cap) 2174887Schin { 2184887Schin if (!(cap = newof(0, Cap_t, 1, strlen(v) + 1))) 2194887Schin return -1; 2204887Schin if (*t) 2214887Schin *t++ = 0; 2224887Schin tta = &cap->att; 2234887Schin tta->name = "default"; 2244887Schin x = strcopy(tta->value = cap->data, v) + 1; 2254887Schin } 2264887Schin else if (k) 2274887Schin { 2284887Schin if (*t) 2294887Schin *t++ = 0; 2304887Schin if (!(att = newof(0, Att_t, 1, 0))) 2314887Schin return -1; 2324887Schin x = strcopy(att->name = x, k) + 1; 2334887Schin x = strcopy(att->value = x, v) + 1; 2344887Schin tta = tta->next = att; 2354887Schin if (!strcasecmp(k, "test")) 2364887Schin cap->test = att->value; 2374887Schin } 2384887Schin } while (*(v = t)); 2394887Schin } 2404887Schin ent = (Ent_t*)dtmatch(mp->cap, s); 2414887Schin if (cap) 2424887Schin { 2434887Schin if (ent) 2444887Schin { 2454887Schin register Cap_t* dup; 2464887Schin register Cap_t* pud; 2474887Schin 2484887Schin for (pud = 0, dup = ent->cap; dup; pud = dup, dup = dup->next) 2494887Schin if (!cap->test && !dup->test || cap->test && dup->test && streq(cap->test, dup->test)) 2504887Schin { 2514887Schin if (flags & MIME_REPLACE) 2524887Schin { 2534887Schin if (pud) 2544887Schin pud->next = cap; 2554887Schin else 2564887Schin ent->cap = cap; 2574887Schin if (!(cap->next = dup->next)) 2584887Schin ent->pac = cap; 2594887Schin cap = dup; 2604887Schin } 2614887Schin dropcap(cap); 2624887Schin return 0; 2634887Schin } 2644887Schin ent->pac = ent->pac->next = cap; 2654887Schin } 2664887Schin else if (!(ent = newof(0, Ent_t, 1, strlen(s) + 1))) 2674887Schin return -1; 2684887Schin else 2694887Schin { 2704887Schin strcpy(ent->name, s); 2714887Schin ent->cap = ent->pac = cap; 2724887Schin dtinsert(mp->cap, ent); 2734887Schin } 2744887Schin } 2754887Schin else if (ent && (flags & MIME_REPLACE)) 2764887Schin dtdelete(mp->cap, ent); 2774887Schin } 2784887Schin return 0; 2794887Schin } 2804887Schin 2814887Schin /* 2824887Schin * load mime type files into mp 2834887Schin */ 2844887Schin 2854887Schin int 2864887Schin mimeload(Mime_t* mp, const char* file, unsigned long flags) 2874887Schin { 2884887Schin register char* s; 2894887Schin register char* t; 2904887Schin register char* e; 2914887Schin register int n; 2924887Schin Sfio_t* fp; 2934887Schin 2944887Schin if (!(s = (char*)file)) 2954887Schin { 2964887Schin flags |= MIME_LIST; 2974887Schin if (!(s = getenv(MIME_FILES_ENV))) 2984887Schin s = MIME_FILES; 2994887Schin } 3004887Schin for (;;) 3014887Schin { 3024887Schin if (!(flags & MIME_LIST)) 3034887Schin e = 0; 3044887Schin else if (e = strchr(s, ':')) 3054887Schin { 3064887Schin /* 3074887Schin * ok, so ~ won't work for the last list element 3084887Schin * we do it for MIME_FILES_ENV anyway 3094887Schin */ 3104887Schin 3114887Schin if ((strneq(s, "~/", n = 2) || strneq(s, "$HOME/", n = 6) || strneq(s, "${HOME}/", n = 8)) && (t = getenv("HOME"))) 3124887Schin { 3134887Schin sfputr(mp->buf, t, -1); 3144887Schin s += n - 1; 3154887Schin } 3164887Schin sfwrite(mp->buf, s, e - s); 3174887Schin if (!(s = sfstruse(mp->buf))) 3184887Schin return -1; 3194887Schin } 3204887Schin if (fp = tokline(s, SF_READ, NiL)) 3214887Schin { 3224887Schin while (t = sfgetr(fp, '\n', 1)) 3234887Schin if (mimeset(mp, t, flags)) 3244887Schin break; 3254887Schin sfclose(fp); 3264887Schin } 3274887Schin else if (!(flags & MIME_LIST)) 3284887Schin return -1; 3294887Schin if (!e) 3304887Schin break; 3314887Schin s = e + 1; 3324887Schin } 3334887Schin return 0; 3344887Schin } 3354887Schin 3364887Schin /* 3374887Schin * mimelist walker 3384887Schin */ 3394887Schin 3404887Schin static int 3414887Schin list(Dt_t* dt, void* object, void* context) 3424887Schin { 3434887Schin register Walk_t* wp = (Walk_t*)context; 3444887Schin register Ent_t* ent = (Ent_t*)object; 3454887Schin register Cap_t* cap; 3464887Schin register Att_t* att; 3474887Schin 3484887Schin if (!wp->pattern || !strncasecmp(ent->name, wp->pattern, wp->prefix) && (!ent->name[wp->prefix] || ent->name[wp->prefix] == '/')) 3494887Schin { 3504887Schin wp->hit++; 3514887Schin for (cap = ent->cap; cap; cap = cap->next) 3524887Schin { 3534887Schin sfprintf(wp->fp, "%s", ent->name); 3544887Schin for (att = &cap->att; att; att = att->next) 3554887Schin { 3564887Schin sfprintf(wp->fp, "\n\t"); 3574887Schin if (att != &cap->att) 3584887Schin { 3594887Schin sfprintf(wp->fp, "%s", att->name); 3604887Schin if (*att->value) 3614887Schin sfprintf(wp->fp, " = "); 3624887Schin } 3634887Schin sfputr(wp->fp, att->value, -1); 3644887Schin } 3654887Schin sfprintf(wp->fp, "\n"); 3664887Schin } 3674887Schin } 3684887Schin return 0; 3694887Schin } 3704887Schin 3714887Schin /* 3724887Schin * find entry matching type 3734887Schin * if exact match fails then left and right x- and right version number 3744887Schin * permutations are attempted 3754887Schin */ 3764887Schin 3774887Schin static Ent_t* 3784887Schin find(Mime_t* mp, const char* type) 3794887Schin { 3804887Schin register char* lp; 3814887Schin register char* rp; 3824887Schin register char* rb; 3834887Schin register char* rv; 3844887Schin register int rc; 3854887Schin register int i; 3864887Schin char* s; 3874887Schin Ent_t* ent; 3884887Schin char buf[256]; 3894887Schin 3904887Schin static const char* prefix[] = { "", "", "x-", "x-", "" }; 3914887Schin 3924887Schin if ((ent = (Ent_t*)dtmatch(mp->cap, type)) || 3934887Schin !(rp = strchr(lp = (char*)type, '/')) || 3944887Schin strlen(lp) >= sizeof(buf)) 3954887Schin return ent; 3964887Schin strcpy(buf, type); 3974887Schin rp = buf + (rp - lp); 3984887Schin *rp++ = 0; 3994887Schin if (*rp == 'x' && *(rp + 1) == '-') 4004887Schin rp += 2; 4014887Schin lp = buf; 4024887Schin if (*lp == 'x' && *(lp + 1) == '-') 4034887Schin lp += 2; 4044887Schin rb = rp; 4054887Schin for (rv = rp + strlen(rp); rv > rp && (isdigit(*(rv - 1)) || *(rv - 1) == '.'); rv--); 4064887Schin rc = *rv; 4074887Schin do 4084887Schin { 4094887Schin rp = rb; 4104887Schin do 4114887Schin { 4124887Schin for (i = 0; i < elementsof(prefix) - 1; i++) 4134887Schin { 4144887Schin sfprintf(mp->buf, "%s%s/%s%s", prefix[i], lp, prefix[i + 1], rp); 4154887Schin if (!(s = sfstruse(mp->buf))) 4164887Schin return 0; 4174887Schin if (ent = (Ent_t*)dtmatch(mp->cap, s)) 4184887Schin return ent; 4194887Schin if (rc) 4204887Schin { 4214887Schin *rv = 0; 4224887Schin sfprintf(mp->buf, "%s%s/%s%s", prefix[i], lp, prefix[i + 1], rp); 4234887Schin if (!(s = sfstruse(mp->buf))) 4244887Schin return 0; 4254887Schin if (ent = (Ent_t*)dtmatch(mp->cap, s)) 4264887Schin return ent; 4274887Schin *rv = rc; 4284887Schin } 4294887Schin } 4304887Schin while (*rp && *rp++ != '-'); 4314887Schin } while (*rp); 4324887Schin while (*lp && *lp++ != '-'); 4334887Schin } while (*lp); 4344887Schin return (Ent_t*)dtmatch(mp->cap, buf); 4354887Schin } 4364887Schin 4374887Schin /* 4384887Schin * list mime <type,data> for pat on fp 4394887Schin */ 4404887Schin 4414887Schin int 4424887Schin mimelist(Mime_t* mp, Sfio_t* fp, register const char* pattern) 4434887Schin { 4444887Schin Ent_t* ent; 4454887Schin Walk_t ws; 4464887Schin 4474887Schin ws.fp = fp; 4484887Schin ws.hit = 0; 4494887Schin ws.prefix = 0; 4504887Schin if (ws.pattern = pattern) 4514887Schin { 4524887Schin while (*pattern && *pattern++ != '/'); 4534887Schin if (!*pattern || *pattern == '*' && !*(pattern + 1)) 4544887Schin ws.prefix = pattern - ws.pattern; 4554887Schin else if (ent = find(mp, ws.pattern)) 4564887Schin { 4574887Schin ws.pattern = 0; 4584887Schin list(mp->cap, ent, &ws); 4594887Schin return ws.hit; 4604887Schin } 4614887Schin } 4624887Schin dtwalk(mp->cap, list, &ws); 4634887Schin return ws.hit; 4644887Schin } 4654887Schin 4664887Schin /* 4674887Schin * get next arg in pp 4684887Schin * 0 returned if no more args 4694887Schin */ 4704887Schin 4714887Schin static int 4724887Schin arg(register Parse_t* pp, int first) 4734887Schin { 4744887Schin register char* s; 4754887Schin register int c; 4764887Schin register int q; 4774887Schin int x; 4784887Schin 4794887Schin for (s = pp->next; isspace(*s) && *s != '\n'; s++); 4804887Schin if (!*s || *s == '\n') 4814887Schin { 4824887Schin pp->next = s; 4834887Schin return 0; 4844887Schin } 4854887Schin pp->name.data = s; 4864887Schin pp->value.data = 0; 4874887Schin q = 0; 4884887Schin x = 0; 4894887Schin while ((c = *s++) && c != ';' && c != '\n') 4904887Schin { 4914887Schin if (c == '"') 4924887Schin { 4934887Schin q = 1; 4944887Schin if (pp->value.data) 4954887Schin { 4964887Schin pp->value.data = s; 4974887Schin if (x) 4984887Schin x = -1; 4994887Schin else 5004887Schin x = 1; 5014887Schin } 5024887Schin else if (!x && pp->name.data == (s - 1)) 5034887Schin { 5044887Schin x = 1; 5054887Schin pp->name.data = s; 5064887Schin } 5074887Schin do 5084887Schin { 5094887Schin if (!(c = *s++) || c == '\n') 5104887Schin { 5114887Schin s--; 5124887Schin break; 5134887Schin } 5144887Schin } while (c != '"'); 5154887Schin if (first < 0 || x > 0) 5164887Schin { 5174887Schin c = ';'; 5184887Schin break; 5194887Schin } 5204887Schin } 5214887Schin else if (c == '=' && !first) 5224887Schin { 5234887Schin first = 1; 5244887Schin pp->name.size = s - pp->name.data - 1; 5254887Schin pp->value.data = s; 5264887Schin } 5274887Schin else if (first >= 0 && isspace(c)) 5284887Schin break; 5294887Schin } 5304887Schin pp->next = s - (c != ';'); 5314887Schin if (first >= 0 || !q) 5324887Schin for (s--; s > pp->name.data && isspace(*(s - 1)); s--); 5334887Schin if (pp->value.data) 5344887Schin pp->value.size = s - pp->value.data - (q && first < 0); 5354887Schin else 5364887Schin { 5374887Schin pp->value.size = 0; 5384887Schin pp->name.size = s - pp->name.data - (q && first < 0); 5394887Schin } 5404887Schin if (first >= 0 && pp->name.size > 0 && pp->name.data[pp->name.size - 1] == ':') 5414887Schin return 0; 5424887Schin return pp->name.size > 0; 5434887Schin } 5444887Schin 5454887Schin /* 5464887Schin * low level for mimeview() 5474887Schin */ 5484887Schin 5494887Schin static char* 5504887Schin expand(Mime_t* mp, register char* s, const char* name, const char* type, const char* opts) 5514887Schin { 5524887Schin register char* t; 5534887Schin register int c; 5544887Schin Parse_t pp; 5554887Schin 5564887Schin mp->disc->flags |= MIME_PIPE; 5574887Schin for (;;) 5584887Schin { 5594887Schin switch (c = *s++) 5604887Schin { 5614887Schin case 0: 5624887Schin case '\n': 5634887Schin break; 5644887Schin case '%': 5654887Schin switch (c = *s++) 5664887Schin { 5674887Schin case 's': 5684887Schin sfputr(mp->buf, (char*)name, -1); 5694887Schin mp->disc->flags &= ~MIME_PIPE; 5704887Schin continue; 5714887Schin case 't': 5724887Schin sfputr(mp->buf, (char*)type, -1); 5734887Schin continue; 5744887Schin case '{': 5754887Schin for (t = s; *s && *s != '}'; s++); 5764887Schin if (*s && (c = s++ - t) && (pp.next = (char*)opts)) 5774887Schin while (arg(&pp, 0)) 5784887Schin if (pp.name.size == c && !strncasecmp(pp.name.data, t, c)) 5794887Schin { 5804887Schin if (pp.value.size) 5814887Schin sfwrite(mp->buf, pp.value.data, pp.value.size); 5824887Schin break; 5834887Schin } 5844887Schin continue; 5854887Schin } 5864887Schin /*FALLTHROUGH*/ 5874887Schin default: 5884887Schin sfputc(mp->buf, c); 5894887Schin continue; 5904887Schin } 5914887Schin break; 5924887Schin } 5934887Schin return sfstruse(mp->buf); 5944887Schin } 5954887Schin 5964887Schin /* 5974887Schin * return expanded command/path/value for <view,name,type,opts> 5984887Schin * return value valid until next mime*() call 5994887Schin */ 6004887Schin 6014887Schin char* 6024887Schin mimeview(Mime_t* mp, const char* view, const char* name, const char* type, const char* opts) 6034887Schin { 6044887Schin register Ent_t* ent; 6054887Schin register Cap_t* cap; 6064887Schin register Att_t* att; 6074887Schin register char* s; 6084887Schin int c; 6094887Schin 6104887Schin if (ent = find(mp, type)) 6114887Schin { 6124887Schin cap = ent->cap; 6134887Schin if (!view || strcasecmp(view, "test")) 6144887Schin while (s = cap->test) 6154887Schin { 6164887Schin if (s = expand(mp, s, name, type, opts)) 6174887Schin { 6184887Schin Parse_t a1; 6194887Schin Parse_t a2; 6204887Schin Parse_t a3; 6214887Schin Parse_t a4; 6224887Schin 6234887Schin /* 6244887Schin * try to do a few common cases here 6254887Schin * mailcap consistency is a winning 6264887Schin * strategy 6274887Schin */ 6284887Schin 6294887Schin a1.next = s; 6304887Schin if (arg(&a1, -1)) 6314887Schin { 6324887Schin if ((c = *a1.name.data == '!') && --a1.name.size <= 0 && !arg(&a1, -1)) 6334887Schin goto lose; 6344887Schin if (a1.name.size == 6 && strneq(a1.name.data, "strcmp", 6) || a1.name.size == 10 && strneq(a1.name.data, "strcasecmp", 10)) 6354887Schin { 6364887Schin a2.next = a1.next; 6374887Schin if (!arg(&a2, -1)) 6384887Schin goto lose; 6394887Schin a3.next = a2.next; 6404887Schin if (!arg(&a3, -1)) 6414887Schin goto lose; 6424887Schin if (a2.name.size != a3.name.size) 6434887Schin c ^= 0; 6444887Schin else c ^= (a1.name.size == 6 ? strncmp : strncasecmp)(a2.name.data, a3.name.data, a2.name.size) == 0; 6454887Schin if (c) 6464887Schin break; 6474887Schin goto skip; 6484887Schin } 6494887Schin else if (a1.name.size == 4 && strneq(a1.name.data, "test", 4)) 6504887Schin { 6514887Schin if (!arg(&a1, -1)) 6524887Schin goto lose; 6534887Schin a2.next = a1.next; 6544887Schin 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))) 6554887Schin goto lose; 6564887Schin a3.next = a2.next; 6574887Schin if (!arg(&a3, -1)) 6584887Schin goto lose; 6594887Schin if (*a3.name.data == '`' && *(a3.name.data + a3.name.size - 1) == '`') 6604887Schin { 6614887Schin a4 = a3; 6624887Schin a3 = a1; 6634887Schin a1 = a4; 6644887Schin } 6654887Schin if (*a1.name.data == '`' && *(a1.name.data + a1.name.size - 1) == '`') 6664887Schin { 6674887Schin a1.next = a1.name.data + 1; 6684887Schin if (!arg(&a1, -1) || a1.name.size != 4 || !strneq(a1.name.data, "echo", 4) || !arg(&a1, -1)) 6694887Schin goto lose; 6704887Schin a4.next = a1.next; 6714887Schin if (!arg(&a4, 1) || a4.name.size < 21 || !strneq(a4.name.data, "| tr '[A-Z]' '[a-z]'`", 21)) 6724887Schin goto lose; 6734887Schin } 6744887Schin else 6754887Schin a4.name.size = 0; 6764887Schin c = *a2.name.data == '!'; 6774887Schin if (a1.name.size != a3.name.size) 6784887Schin c ^= 0; 6794887Schin else c ^= (a4.name.size ? strncasecmp : strncmp)(a1.name.data, a3.name.data, a1.name.size) == 0; 6804887Schin if (c) 6814887Schin break; 6824887Schin goto skip; 6834887Schin } 6844887Schin } 6854887Schin lose: 6864887Schin if (!system(s)) 6874887Schin break; 6884887Schin } 6894887Schin skip: 6904887Schin if (!(cap = cap->next)) 6914887Schin return 0; 6924887Schin } 6934887Schin att = &cap->att; 6944887Schin if (view && *view && !streq(view, "-")) 6954887Schin while (strcasecmp(view, att->name)) 6964887Schin if (!(att = att->next)) 6974887Schin return 0; 6984887Schin return expand(mp, att->value, name, type, opts); 6994887Schin } 7004887Schin return 0; 7014887Schin } 7024887Schin 7034887Schin /* 7044887Schin * lower case identifier prefix strcmp 7054887Schin * if e!=0 then it will point to the next char after the match 7064887Schin */ 7074887Schin 7084887Schin int 7094887Schin mimecmp(register const char* s, register const char* v, char** e) 7104887Schin { 7114887Schin register int n; 7124887Schin 7134887Schin while (isalnum(*v) || *v == *s && (*v == '_' || *v == '-' || *v == '/')) 7144887Schin if (n = lower(*s++) - lower(*v++)) 7154887Schin return n; 7164887Schin if (!isalnum(*s) && *s != '_' && *s != '-') 7174887Schin { 7184887Schin if (e) 7194887Schin *e = (char*)s; 7204887Schin return 0; 7214887Schin } 7224887Schin return lower(*s) - lower(*v); 7234887Schin } 7244887Schin 7254887Schin /* 7264887Schin * parse mime headers in strsearch(tab,num,siz) from s 7274887Schin * return >0 if mime header consumed 7284887Schin */ 7294887Schin 7304887Schin int 7314887Schin mimehead(Mime_t* mp, void* tab, size_t num, size_t siz, register char* s) 7324887Schin { 7334887Schin register void* p; 7344887Schin char* e; 7354887Schin Parse_t pp; 7364887Schin Mimevalue_f set; 7374887Schin 7384887Schin set = mp->disc->valuef; 7394887Schin if (!strncasecmp(s, "original-", 9)) 7404887Schin s += 9; 7414887Schin if (!strncasecmp(s, "content-", 8)) 7424887Schin { 7434887Schin s += 8; 7444887Schin if ((p = strsearch(tab, num, siz, (Strcmp_f)mimecmp, s, &e)) && *e == ':') 7454887Schin { 7464887Schin pp.next = e + 1; 7474887Schin if (arg(&pp, 1)) 7484887Schin { 7494887Schin if ((*set)(mp, p, pp.name.data, pp.name.size, mp->disc)) 7504887Schin return 0; 7514887Schin while (arg(&pp, 0)) 7524887Schin if (pp.value.size && 7534887Schin (p = strsearch(tab, num, siz, (Strcmp_f)mimecmp, pp.name.data, &e)) && 7544887Schin (*set)(mp, p, pp.value.data, pp.value.size, mp->disc)) 7554887Schin return 0; 7564887Schin return 1; 7574887Schin } 7584887Schin } 7594887Schin else if (strchr(s, ':')) 7604887Schin return 1; 7614887Schin } 7624887Schin return !strncasecmp(s, "x-", 2); 7634887Schin } 7644887Schin 7654887Schin /* 7664887Schin * open a mime library handle 7674887Schin */ 7684887Schin 7694887Schin Mime_t* 7704887Schin mimeopen(Mimedisc_t* disc) 7714887Schin { 7724887Schin register Mime_t* mp; 7734887Schin 7744887Schin if (!(mp = newof(0, Mime_t, 1, 0))) 7754887Schin return 0; 7764887Schin mp->id = lib; 7774887Schin mp->disc = disc; 7784887Schin mp->dict.key = offsetof(Ent_t, name); 7794887Schin mp->dict.comparf = order; 7804887Schin mp->dict.freef = drop; 7814887Schin if (!(mp->buf = sfstropen()) || !(mp->cap = dtopen(&mp->dict, Dtorder))) 7824887Schin { 7834887Schin mimeclose(mp); 7844887Schin return 0; 7854887Schin } 7864887Schin return mp; 7874887Schin } 7884887Schin 7894887Schin /* 7904887Schin * close a mimeopen() handle 7914887Schin */ 7924887Schin 7934887Schin int 7944887Schin mimeclose(Mime_t* mp) 7954887Schin { 7964887Schin if (mp) 7974887Schin { 7984887Schin if (mp->buf) 7994887Schin sfclose(mp->buf); 8004887Schin if (mp->cap) 8014887Schin dtclose(mp->cap); 8024887Schin if (mp->freef) 8034887Schin (*mp->freef)(mp); 8044887Schin free(mp); 8054887Schin } 8064887Schin return 0; 8074887Schin } 808