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