w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

mailcap.c (9246B)


      1 /* $Id$ */
      2 #include "fm.h"
      3 #include "myctype.h"
      4 #include <stdio.h>
      5 #include <errno.h>
      6 #include "parsetag.h"
      7 #include "local.h"
      8 
      9 static struct mailcap DefaultMailcap[] = {
     10     {"image/*", DEF_IMAGE_VIEWER " %s", 0, NULL, NULL, NULL},	/* */
     11     {"audio/basic", DEF_AUDIO_PLAYER " %s", 0, NULL, NULL, NULL},
     12     {NULL, NULL, 0, NULL, NULL, NULL}
     13 };
     14 
     15 static TextList *mailcap_list;
     16 static struct mailcap **UserMailcap;
     17 
     18 int
     19 mailcapMatch(struct mailcap *mcap, char *type)
     20 {
     21     char *cap = mcap->type, *p;
     22     int level;
     23     for (p = cap; *p != '/'; p++) {
     24 	if (TOLOWER(*p) != TOLOWER(*type))
     25 	    return 0;
     26 	type++;
     27     }
     28     if (*type != '/')
     29 	return 0;
     30     p++;
     31     type++;
     32     if (mcap->flags & MAILCAP_HTMLOUTPUT)
     33 	level = 1;
     34     else
     35 	level = 0;
     36     if (*p == '*')
     37 	return 10 + level;
     38     while (*p) {
     39 	if (TOLOWER(*p) != TOLOWER(*type))
     40 	    return 0;
     41 	p++;
     42 	type++;
     43     }
     44     if (*type != '\0')
     45 	return 0;
     46     return 20 + level;
     47 }
     48 
     49 struct mailcap *
     50 searchMailcap(struct mailcap *table, char *type)
     51 {
     52     int level = 0;
     53     struct mailcap *mcap = NULL;
     54     int i;
     55 
     56     if (table == NULL)
     57 	return NULL;
     58     for (; table->type; table++) {
     59 	i = mailcapMatch(table, type);
     60 	if (i > level) {
     61 	    if (table->test) {
     62 		Str command =
     63 		    unquote_mailcap(table->test, type, NULL, NULL, NULL);
     64 		if (system(command->ptr) != 0)
     65 		    continue;
     66 	    }
     67 	    level = i;
     68 	    mcap = table;
     69 	}
     70     }
     71     return mcap;
     72 }
     73 
     74 static int
     75 matchMailcapAttr(char *p, char *attr, int len, Str *value)
     76 {
     77     int quoted;
     78     char *q = NULL;
     79 
     80     if (strncasecmp(p, attr, len) == 0) {
     81 	p += len;
     82 	SKIP_BLANKS(p);
     83 	if (value) {
     84 	    *value = Strnew();
     85 	    if (*p == '=') {
     86 		p++;
     87 		SKIP_BLANKS(p);
     88 		quoted = 0;
     89 		while (*p && (quoted || *p != ';')) {
     90 		    if (quoted || !IS_SPACE(*p))
     91 			q = p;
     92 		    if (quoted)
     93 			quoted = 0;
     94 		    else if (*p == '\\')
     95 			quoted = 1;
     96 		    Strcat_char(*value, *p);
     97 		    p++;
     98 		}
     99 		if (q)
    100 		    Strshrink(*value, p - q - 1);
    101 	    }
    102 	    return 1;
    103 	}
    104 	else {
    105 	    if (*p == '\0' || *p == ';') {
    106 		return 1;
    107 	    }
    108 	}
    109     }
    110     return 0;
    111 }
    112 
    113 static int
    114 extractMailcapEntry(char *mcap_entry, struct mailcap *mcap)
    115 {
    116     int j, k;
    117     char *p;
    118     int quoted;
    119     Str tmp;
    120 
    121     bzero(mcap, sizeof(struct mailcap));
    122     p = mcap_entry;
    123     SKIP_BLANKS(p);
    124     k = -1;
    125     for (j = 0; p[j] && p[j] != ';'; j++) {
    126 	if (!IS_SPACE(p[j]))
    127 	    k = j;
    128     }
    129     mcap->type = allocStr(p, (k >= 0) ? k + 1 : j);
    130     if (!p[j])
    131 	return 0;
    132     p += j + 1;
    133 
    134     SKIP_BLANKS(p);
    135     k = -1;
    136     quoted = 0;
    137     for (j = 0; p[j] && (quoted || p[j] != ';'); j++) {
    138 	if (quoted || !IS_SPACE(p[j]))
    139 	    k = j;
    140 	if (quoted)
    141 	    quoted = 0;
    142 	else if (p[j] == '\\')
    143 	    quoted = 1;
    144     }
    145     mcap->viewer = allocStr(p, (k >= 0) ? k + 1 : j);
    146     p += j;
    147 
    148     while (*p == ';') {
    149 	p++;
    150 	SKIP_BLANKS(p);
    151 	if (matchMailcapAttr(p, "needsterminal", 13, NULL)) {
    152 	    mcap->flags |= MAILCAP_NEEDSTERMINAL;
    153 	}
    154 	else if (matchMailcapAttr(p, "copiousoutput", 13, NULL)) {
    155 	    mcap->flags |= MAILCAP_COPIOUSOUTPUT;
    156 	}
    157 	else if (matchMailcapAttr(p, "x-htmloutput", 12, NULL) ||
    158 		 matchMailcapAttr(p, "htmloutput", 10, NULL)) {
    159 	    mcap->flags |= MAILCAP_HTMLOUTPUT;
    160 	}
    161 	else if (matchMailcapAttr(p, "test", 4, &tmp)) {
    162 	    mcap->test = allocStr(tmp->ptr, tmp->length);
    163 	}
    164 	else if (matchMailcapAttr(p, "nametemplate", 12, &tmp)) {
    165 	    mcap->nametemplate = allocStr(tmp->ptr, tmp->length);
    166 	}
    167 	else if (matchMailcapAttr(p, "edit", 4, &tmp)) {
    168 	    mcap->edit = allocStr(tmp->ptr, tmp->length);
    169 	}
    170 	quoted = 0;
    171 	while (*p && (quoted || *p != ';')) {
    172 	    if (quoted)
    173 		quoted = 0;
    174 	    else if (*p == '\\')
    175 		quoted = 1;
    176 	    p++;
    177 	}
    178     }
    179     return 1;
    180 }
    181 
    182 static struct mailcap *
    183 loadMailcap(char *filename)
    184 {
    185     FILE *f;
    186     int i, n;
    187     Str tmp;
    188     struct mailcap *mcap;
    189 
    190     f = fopen(expandPath(filename), "r");
    191     if (f == NULL)
    192 	return NULL;
    193     i = 0;
    194     while (tmp = Strfgets(f), tmp->length > 0) {
    195 	if (tmp->ptr[0] != '#')
    196 	    i++;
    197     }
    198     fseek(f, 0, 0);
    199     n = i;
    200     mcap = New_N(struct mailcap, n + 1);
    201     i = 0;
    202     while (tmp = Strfgets(f), tmp->length > 0) {
    203 	if (tmp->ptr[0] == '#')
    204 	    continue;
    205       redo:
    206 	while (IS_SPACE(Strlastchar(tmp)))
    207 	    Strshrink(tmp, 1);
    208 	if (Strlastchar(tmp) == '\\') {
    209 	    /* continuation */
    210 	    Strshrink(tmp, 1);
    211 	    Strcat(tmp, Strfgets(f));
    212 	    goto redo;
    213 	}
    214 	if (extractMailcapEntry(tmp->ptr, &mcap[i]))
    215 	    i++;
    216     }
    217     bzero(&mcap[i], sizeof(struct mailcap));
    218     fclose(f);
    219     return mcap;
    220 }
    221 
    222 void
    223 initMailcap()
    224 {
    225     TextListItem *tl;
    226     int i;
    227 
    228     if (non_null(mailcap_files))
    229 	mailcap_list = make_domain_list(mailcap_files);
    230     else
    231 	mailcap_list = NULL;
    232     if (mailcap_list == NULL)
    233 	return;
    234     UserMailcap = New_N(struct mailcap *, mailcap_list->nitem);
    235     for (i = 0, tl = mailcap_list->first; tl; i++, tl = tl->next)
    236 	UserMailcap[i] = loadMailcap(tl->ptr);
    237 
    238 }
    239 
    240 char *
    241 acceptableMimeTypes()
    242 {
    243     static Str types = NULL;
    244     TextList *l;
    245     Hash_si *mhash;
    246     char *p;
    247     int i;
    248 
    249     if (types != NULL)
    250 	return types->ptr;
    251 
    252     /* generate acceptable media types */
    253     l = newTextList();
    254     mhash = newHash_si(16);	/* XXX */
    255     /* pushText(l, "text"); */
    256     putHash_si(mhash, "text", 1);
    257     pushText(l, "image");
    258     putHash_si(mhash, "image", 1);
    259     for (i = 0; i < mailcap_list->nitem; i++) {
    260 	struct mailcap *mp = UserMailcap[i];
    261 	char *mt;
    262 	if (mp == NULL)
    263 	    continue;
    264 	for (; mp->type; mp++) {
    265 	    p = strchr(mp->type, '/');
    266 	    if (p == NULL)
    267 		continue;
    268 	    mt = allocStr(mp->type, p - mp->type);
    269 	    if (getHash_si(mhash, mt, 0) == 0) {
    270 		pushText(l, mt);
    271 		putHash_si(mhash, mt, 1);
    272 	    }
    273 	}
    274     }
    275     types = Strnew();
    276     Strcat_charp(types, "text/html, text/*;q=0.5");
    277     while ((p = popText(l)) != NULL) {
    278 	Strcat_charp(types, ", ");
    279 	Strcat_charp(types, p);
    280 	Strcat_charp(types, "/*");
    281     }
    282     return types->ptr;
    283 }
    284 
    285 struct mailcap *
    286 searchExtViewer(char *type)
    287 {
    288     struct mailcap *p;
    289     int i;
    290 
    291     if (mailcap_list == NULL)
    292 	goto no_user_mailcap;
    293 
    294     for (i = 0; i < mailcap_list->nitem; i++) {
    295 	if ((p = searchMailcap(UserMailcap[i], type)) != NULL)
    296 	    return p;
    297     }
    298 
    299   no_user_mailcap:
    300     return searchMailcap(DefaultMailcap, type);
    301 }
    302 
    303 #define MC_NORMAL 0
    304 #define MC_PREC   1
    305 #define MC_PREC2  2
    306 #define MC_QUOTED 3
    307 
    308 #define MCF_SQUOTED (1 << 0)
    309 #define MCF_DQUOTED (1 << 1)
    310 
    311 Str
    312 quote_mailcap(char *s, int flag)
    313 {
    314     Str d;
    315 
    316     d = Strnew();
    317 
    318     for (;; ++s)
    319 	switch (*s) {
    320 	case '\0':
    321 	    goto end;
    322 	case '$':
    323 	case '`':
    324 	case '"':
    325 	case '\\':
    326 	    if (!(flag & MCF_SQUOTED))
    327 		Strcat_char(d, '\\');
    328 
    329 	    Strcat_char(d, *s);
    330 	    break;
    331 	case '\'':
    332 	    if (flag & MCF_SQUOTED) {
    333 		Strcat_charp(d, "'\\''");
    334 		break;
    335 	    }
    336 	default:
    337 	    if (!flag && !IS_ALNUM(*s))
    338 		Strcat_char(d, '\\');
    339 	case '_':
    340 	case '.':
    341 	case ':':
    342 	case '/':
    343 	    Strcat_char(d, *s);
    344 	    break;
    345 	}
    346   end:
    347     return d;
    348 }
    349 
    350 
    351 static Str
    352 unquote_mailcap_loop(char *qstr, char *type, char *name, char *attr,
    353 		     int *mc_stat, int flag0)
    354 {
    355     Str str, tmp, test, then;
    356     char *p;
    357     int status = MC_NORMAL, prev_status = MC_NORMAL, sp = 0, flag;
    358 
    359     if (mc_stat)
    360 	*mc_stat = 0;
    361 
    362     if (qstr == NULL)
    363 	return NULL;
    364 
    365     str = Strnew();
    366     tmp = test = then = NULL;
    367 
    368     for (flag = flag0, p = qstr; *p; p++) {
    369 	if (status == MC_QUOTED) {
    370 	    if (prev_status == MC_PREC2)
    371 		Strcat_char(tmp, *p);
    372 	    else
    373 		Strcat_char(str, *p);
    374 	    status = prev_status;
    375 	    continue;
    376 	}
    377 	else if (*p == '\\') {
    378 	    prev_status = status;
    379 	    status = MC_QUOTED;
    380 	    continue;
    381 	}
    382 	switch (status) {
    383 	case MC_NORMAL:
    384 	    if (*p == '%') {
    385 		status = MC_PREC;
    386 	    }
    387 	    else {
    388 		if (*p == '\'') {
    389 		    if (!flag0 && flag & MCF_SQUOTED)
    390 			flag &= ~MCF_SQUOTED;
    391 		    else if (!flag)
    392 			flag |= MCF_SQUOTED;
    393 		}
    394 		else if (*p == '"') {
    395 		    if (!flag0 && flag & MCF_DQUOTED)
    396 			flag &= ~MCF_DQUOTED;
    397 		    else if (!flag)
    398 			flag |= MCF_DQUOTED;
    399 		}
    400 		Strcat_char(str, *p);
    401 	    }
    402 	    break;
    403 	case MC_PREC:
    404 	    if (IS_ALPHA(*p)) {
    405 		switch (*p) {
    406 		case 's':
    407 		    if (name) {
    408 			Strcat_charp(str, quote_mailcap(name, flag)->ptr);
    409 			if (mc_stat)
    410 			    *mc_stat |= MCSTAT_REPNAME;
    411 		    }
    412 		    break;
    413 		case 't':
    414 		    if (type) {
    415 			Strcat_charp(str, quote_mailcap(type, flag)->ptr);
    416 			if (mc_stat)
    417 			    *mc_stat |= MCSTAT_REPTYPE;
    418 		    }
    419 		    break;
    420 		}
    421 		status = MC_NORMAL;
    422 	    }
    423 	    else if (*p == '{') {
    424 		status = MC_PREC2;
    425 		test = then = NULL;
    426 		tmp = Strnew();
    427 	    }
    428 	    else if (*p == '%') {
    429 		Strcat_char(str, *p);
    430 	    }
    431 	    break;
    432 	case MC_PREC2:
    433 	    if (sp > 0 || *p == '{') {
    434 		Strcat_char(tmp, *p);
    435 
    436 		switch (*p) {
    437 		case '{':
    438 		    ++sp;
    439 		    break;
    440 		case '}':
    441 		    --sp;
    442 		    break;
    443 		default:
    444 		    break;
    445 		}
    446 	    }
    447 	    else if (*p == '}') {
    448 		char *q;
    449 		if (attr && (q = strcasestr(attr, tmp->ptr)) != NULL &&
    450 		    (q == attr || IS_SPACE(*(q - 1)) || *(q - 1) == ';') &&
    451 		    matchattr(q, tmp->ptr, tmp->length, &tmp)) {
    452 		    Strcat_charp(str, quote_mailcap(tmp->ptr, flag)->ptr);
    453 		    if (mc_stat)
    454 			*mc_stat |= MCSTAT_REPPARAM;
    455 		}
    456 		status = MC_NORMAL;
    457 	    }
    458 	    else {
    459 		Strcat_char(tmp, *p);
    460 	    }
    461 	    break;
    462 	}
    463     }
    464     return str;
    465 }
    466 
    467 Str
    468 unquote_mailcap(char *qstr, char *type, char *name, char *attr, int *mc_stat)
    469 {
    470     return unquote_mailcap_loop(qstr, type, name, attr, mc_stat, 0);
    471 }