1 #include "links.h"
2
3 struct list_head mailto_prog = { &mailto_prog, &mailto_prog };
4 struct list_head telnet_prog = { &telnet_prog, &telnet_prog };
5 struct list_head tn3270_prog = { &tn3270_prog, &tn3270_prog };
6 struct list_head mms_prog = { &mms_prog, &mms_prog };
7
8 struct list_head assoc = { &assoc, &assoc };
9
get_assoc_cnt()10 unsigned get_assoc_cnt()
11 {
12 static unsigned assoc_cnt = 0;
13 if (!++assoc_cnt) assoc_cnt = 1;
14 return assoc_cnt;
15 }
16
17 struct list_head extensions = { &extensions, &extensions };
18
delete_association(struct assoc * del)19 void delete_association(struct assoc *del)
20 {
21 del_from_list(del);
22 mem_free(del->label);
23 mem_free(del->ct);
24 mem_free(del->prog);
25 mem_free(del);
26 }
27
delete_extension(struct extension * del)28 void delete_extension(struct extension *del)
29 {
30 del_from_list(del);
31 mem_free(del->ext);
32 mem_free(del->ct);
33 mem_free(del);
34 }
35
is_in_list(unsigned char * list,unsigned char * str,int l)36 int is_in_list(unsigned char *list, unsigned char *str, int l)
37 {
38 unsigned char *l2, *l3;
39 if (!l) return 0;
40 rep:
41 while (*list && *list <= ' ') list++;
42 if (!*list) return 0;
43 for (l2 = list; *l2 && *l2 != ','; l2++) ;
44 for (l3 = l2 - 1; l3 >= list && *l3 <= ' '; l3--) ;
45 l3++;
46 if (l3 - list == l && !casecmp(str, list, l)) return 1;
47 list = l2;
48 if (*list == ',') list++;
49 goto rep;
50 }
51
get_content_type(unsigned char * head,unsigned char * url)52 unsigned char *get_content_type(unsigned char *head, unsigned char *url)
53 {
54 struct extension *e;
55 struct assoc *a;
56 unsigned char *ct, *ext, *exxt;
57 int extl, el;
58 int code, vers;
59 if (head && (ct = parse_http_header(head, "Content-Type", NULL))) {
60 unsigned char *s;
61 if ((s = strchr(ct, ';'))) *s = 0;
62 while (*ct && ct[strlen(ct) - 1] <= ' ') ct[strlen(ct) - 1] = 0;
63 return ct;
64 }
65 if (!get_http_code(head, &code, &vers) && code >= 300)
66 return stracpy("text/html");
67 ext = NULL, extl = 0;
68 for (ct = url; *ct && !end_of_dir(*ct); ct++)
69 if (*ct == '.') ext = ct + 1;
70 else if (dir_sep(*ct)) ext = NULL;
71 if (ext) while (ext[extl] && !dir_sep(ext[extl]) && !end_of_dir(ext[extl])) extl++;
72 if (force_html ||
73 (extl == 3 && !casecmp(ext, "htm", 3)) ||
74 (extl == 4 && !casecmp(ext, "html", 4))) return stracpy("text/html");
75 foreach(e, extensions) if (is_in_list(e->ext, ext, extl)) return stracpy(e->ct);
76 exxt = init_str(); el = 0;
77 add_to_str(&exxt, &el, "application/x-");
78 add_bytes_to_str(&exxt, &el, ext, extl);
79 foreach(a, assoc) if (is_in_list(a->ct, exxt, el)) return exxt;
80 mem_free(exxt);
81 return !force_html ? stracpy("text/plain") : stracpy("text/html");
82 }
83
get_type_assoc(struct terminal * term,unsigned char * type)84 struct assoc *get_type_assoc(struct terminal *term, unsigned char *type)
85 {
86 struct assoc *a;
87 foreach(a, assoc) if (a->system == SYSTEM_ID && (term->environment & ENV_XWIN ? a->xwin : a->cons) && is_in_list(a->ct, type, strlen(type))) return a;
88 return NULL;
89 }
90
free_types()91 void free_types()
92 {
93 struct assoc *a;
94 struct extension *e;
95 struct protocol_program *p;
96 foreach(a, assoc) {
97 mem_free(a->ct);
98 mem_free(a->prog);
99 mem_free(a->label);
100 }
101 free_list(assoc);
102 foreach(e, extensions) {
103 mem_free(e->ext);
104 mem_free(e->ct);
105 }
106 free_list(extensions);
107 foreach(p, mailto_prog) mem_free(p->prog);
108 free_list(mailto_prog);
109 foreach(p, telnet_prog) mem_free(p->prog);
110 free_list(telnet_prog);
111 foreach(p, tn3270_prog) mem_free(p->prog);
112 free_list(tn3270_prog);
113 foreach(p, mms_prog) mem_free(p->prog);
114 free_list(mms_prog);
115 }
116
117 unsigned char *ct_msg[] = {
118 TEXT_(T_LABEL),
119 TEXT_(T_CONTENT_TYPES),
120 TEXT_(T_PROGRAM__IS_REPLACED_WITH_FILE_NAME),
121 #ifdef ASSOC_BLOCK
122 TEXT_(T_BLOCK_TERMINAL_WHILE_PROGRAM_RUNNING),
123 #endif
124 #ifdef ASSOC_CONS_XWIN
125 TEXT_(T_RUN_ON_TERMINAL),
126 TEXT_(T_RUN_IN_XWINDOW),
127 #endif
128 TEXT_(T_ASK_BEFORE_OPENING),
129 };
130
add_ct_fn(struct dialog_data * dlg)131 void add_ct_fn(struct dialog_data *dlg)
132 {
133 struct terminal *term = dlg->win->term;
134 int max = 0, min = 0;
135 int w, rw;
136 int y = -1;
137 int p = 1;
138 #ifdef ASSOC_BLOCK
139 p++;
140 #endif
141 #ifdef ASSOC_CONS_XWIN
142 p += 2;
143 #endif
144 max_text_width(term, ct_msg[0], &max);
145 min_text_width(term, ct_msg[0], &min);
146 max_text_width(term, ct_msg[1], &max);
147 min_text_width(term, ct_msg[1], &min);
148 max_text_width(term, ct_msg[2], &max);
149 min_text_width(term, ct_msg[2], &min);
150 max_group_width(term, ct_msg + 3, dlg->items + 3, p, &max);
151 min_group_width(term, ct_msg + 3, dlg->items + 3, p, &min);
152 max_buttons_width(term, dlg->items + 3 + p, 2, &max);
153 min_buttons_width(term, dlg->items + 3 + p, 2, &min);
154 w = term->x * 9 / 10 - 2 * DIALOG_LB;
155 if (w > max) w = max;
156 if (w < min) w = min;
157 if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
158 if (w < 1) w = 1;
159 rw = 0;
160 dlg_format_text(NULL, term, _(ct_msg[0], term), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
161 y += 2;
162 dlg_format_text(NULL, term, _(ct_msg[1], term), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
163 y += 2;
164 dlg_format_text(NULL, term, _(ct_msg[2], term), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
165 y += 2;
166 dlg_format_group(NULL, term, ct_msg + 3, dlg->items + 3, p, 0, &y, w, &rw);
167 y++;
168 dlg_format_buttons(NULL, term, dlg->items + 3 + p, 2, 0, &y, w, &rw, AL_CENTER);
169 w = rw;
170 dlg->xw = w + 2 * DIALOG_LB;
171 dlg->yw = y + 2 * DIALOG_TB;
172 center_dlg(dlg);
173 draw_dlg(dlg);
174 y = dlg->y + DIALOG_TB;
175 dlg_format_text(term, term, ct_msg[0], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
176 dlg_format_field(term, term, &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
177 y++;
178 dlg_format_text(term, term, ct_msg[1], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
179 dlg_format_field(term, term, &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
180 y++;
181 dlg_format_text(term, term, ct_msg[2], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
182 dlg_format_field(term, term, &dlg->items[2], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
183 y++;
184 dlg_format_group(term, term, ct_msg + 3, &dlg->items[3], p, dlg->x + DIALOG_LB, &y, w, NULL);
185 y++;
186 dlg_format_buttons(term, term, &dlg->items[3 + p], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
187 }
188
update_assoc(struct assoc * new)189 void update_assoc(struct assoc *new)
190 {
191 struct assoc *repl;
192 if (!new->label[0] || !new->ct[0] || !new->prog[0]) return;
193 if (new->cnt) {
194 foreach(repl, assoc) if (repl->cnt == new->cnt) {
195 mem_free(repl->label);
196 mem_free(repl->ct);
197 mem_free(repl->prog);
198 goto replace;
199 }
200 return;
201 }
202 foreach(repl, assoc) if (!strcmp(repl->label, new->label) && !strcmp(repl->ct, new->ct) && !strcmp(repl->prog, new->prog) && repl->block == new->block && repl->cons == new->cons && repl->xwin == new->xwin && repl->ask == new->ask && repl->system == new->system) {
203 del_from_list(repl);
204 add_to_list(assoc, repl);
205 return;
206 }
207 new->cnt = get_assoc_cnt();
208 repl = mem_alloc(sizeof(struct assoc));
209 add_to_list(assoc, repl);
210 replace:
211 repl->label = stracpy(new->label);
212 repl->ct = stracpy(new->ct);
213 repl->prog = stracpy(new->prog);
214 repl->block = new->block;
215 repl->cons = new->cons;
216 repl->xwin = new->xwin;
217 repl->ask = new->ask;
218 repl->system = new->system;
219 repl->cnt = new->cnt;
220 }
221
really_del_ct(void * fcp)222 void really_del_ct(void *fcp)
223 {
224 unsigned fc = (unsigned)(my_uintptr_t)fcp;
225 struct assoc *del;
226 foreach(del, assoc) if (del->cnt == fc) goto ok;
227 return;
228 ok:
229 delete_association(del);
230 }
231
menu_del_ct(struct terminal * term,void * fcp,void * xxx2)232 void menu_del_ct(struct terminal *term, void *fcp, void *xxx2)
233 {
234 unsigned char *str;
235 int l;
236 unsigned fc = (unsigned)(my_uintptr_t)fcp;
237 struct assoc *del;
238 foreach(del, assoc) if (del->cnt == fc) goto ok;
239 return;
240 ok:
241 str = init_str(), l = 0;
242 add_to_str(&str, &l, del->ct);
243 add_to_str(&str, &l, " -> ");
244 add_to_str(&str, &l, del->prog);
245 msg_box(term, getml(str, NULL), TEXT_(T_DELETE_ASSOCIATION), AL_CENTER | AL_EXTD_TEXT, TEXT_(T_DELETE_ASSOCIATION), ": ", str, "?", NULL, fcp, 2, TEXT_(T_YES), really_del_ct, B_ENTER, TEXT_(T_NO), NULL, B_ESC);
246 }
247
menu_add_ct(struct terminal * term,void * fcp,void * xxx2)248 void menu_add_ct(struct terminal *term, void *fcp, void *xxx2)
249 {
250 int p;
251 unsigned fc = (unsigned)(my_uintptr_t)fcp;
252 struct assoc *new, *from;
253 unsigned char *label;
254 unsigned char *ct;
255 unsigned char *prog;
256 struct dialog *d;
257 if (fc) {
258 foreach(from, assoc) if (from->cnt == fc) goto ok;
259 return;
260 }
261 from = NULL;
262 ok:
263 d = mem_alloc(sizeof(struct dialog) + 10 * sizeof(struct dialog_item) + sizeof(struct assoc) + 3 * MAX_STR_LEN);
264 memset(d, 0, sizeof(struct dialog) + 10 * sizeof(struct dialog_item) + sizeof(struct assoc) + 3 * MAX_STR_LEN);
265 new = (struct assoc *)&d->items[10];
266 new->label = label = (unsigned char *)(new + 1);
267 new->ct = ct = label + MAX_STR_LEN;
268 new->prog = prog = ct + MAX_STR_LEN;
269 if (from) {
270 safe_strncpy(label, from->label, MAX_STR_LEN);
271 safe_strncpy(ct, from->ct, MAX_STR_LEN);
272 safe_strncpy(prog, from->prog, MAX_STR_LEN);
273 new->block = from->block;
274 new->cons = from->cons;
275 new->xwin = from->xwin;
276 new->ask = from->ask;
277 new->system = from->system;
278 new->cnt = from->cnt;
279 } else {
280 new->block = new->xwin = new->cons = 1;
281 new->ask = 1;
282 new->system = SYSTEM_ID;
283 }
284 d->title = TEXT_(T_ASSOCIATION);
285 d->fn = add_ct_fn;
286 d->refresh = (void (*)(void *))update_assoc;
287 d->refresh_data = new;
288 d->items[0].type = D_FIELD;
289 d->items[0].dlen = MAX_STR_LEN;
290 d->items[0].data = label;
291 d->items[0].fn = check_nonempty;
292 d->items[1].type = D_FIELD;
293 d->items[1].dlen = MAX_STR_LEN;
294 d->items[1].data = ct;
295 d->items[1].fn = check_nonempty;
296 d->items[2].type = D_FIELD;
297 d->items[2].dlen = MAX_STR_LEN;
298 d->items[2].data = prog;
299 d->items[2].fn = check_nonempty;
300 p = 3;
301 #ifdef ASSOC_BLOCK
302 d->items[p].type = D_CHECKBOX;
303 d->items[p].data = (unsigned char *)&new->block;
304 d->items[p++].dlen = sizeof(int);
305 #endif
306 #ifdef ASSOC_CONS_XWIN
307 d->items[p].type = D_CHECKBOX;
308 d->items[p].data = (unsigned char *)&new->cons;
309 d->items[p++].dlen = sizeof(int);
310 d->items[p].type = D_CHECKBOX;
311 d->items[p].data = (unsigned char *)&new->xwin;
312 d->items[p++].dlen = sizeof(int);
313 #endif
314 d->items[p].type = D_CHECKBOX;
315 d->items[p].data = (unsigned char *)&new->ask;
316 d->items[p++].dlen = sizeof(int);
317 d->items[p].type = D_BUTTON;
318 d->items[p].gid = B_ENTER;
319 d->items[p].fn = ok_dialog;
320 d->items[p++].text = TEXT_(T_OK);
321 d->items[p].type = D_BUTTON;
322 d->items[p].gid = B_ESC;
323 d->items[p].text = TEXT_(T_CANCEL);
324 d->items[p++].fn = cancel_dialog;
325 d->items[p++].type = D_END;
326 do_dialog(term, d, getml(d, NULL));
327 }
328
329 struct menu_item mi_no_assoc[] = {
330 { TEXT_(T_NO_ASSOCIATIONS), "", M_BAR, NULL, NULL, 0, 0 },
331 { NULL, NULL, 0, NULL, NULL, 0, 0 },
332 };
333
menu_list_assoc(struct terminal * term,void * fn,void * xxx)334 void menu_list_assoc(struct terminal *term, void *fn, void *xxx)
335 {
336 struct assoc *a;
337 struct menu_item *mi = NULL;
338 int n = 0;
339 foreachback(a, assoc) if (a->system == SYSTEM_ID) {
340 if (!mi && !(mi = new_menu(7))) return;
341 add_to_menu(&mi, stracpy(a->label), stracpy(a->ct), "", MENU_FUNC fn, (void *)(my_uintptr_t)a->cnt, 0), n++;
342 }
343 if (!mi) do_menu(term, mi_no_assoc, xxx);
344 else do_menu(term, mi, xxx);
345 }
346
347 unsigned char *ext_msg[] = {
348 TEXT_(T_EXTENSION_S),
349 TEXT_(T_CONTENT_TYPE),
350 };
351
add_ext_fn(struct dialog_data * dlg)352 void add_ext_fn(struct dialog_data *dlg)
353 {
354 struct terminal *term = dlg->win->term;
355 int max = 0, min = 0;
356 int w, rw;
357 int y = -1;
358 max_text_width(term, ext_msg[0], &max);
359 min_text_width(term, ext_msg[0], &min);
360 max_text_width(term, ext_msg[1], &max);
361 min_text_width(term, ext_msg[1], &min);
362 max_buttons_width(term, dlg->items + 2, 2, &max);
363 min_buttons_width(term, dlg->items + 2, 2, &min);
364 w = term->x * 9 / 10 - 2 * DIALOG_LB;
365 if (w > max) w = max;
366 if (w < min) w = min;
367 if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
368 if (w < 1) w = 1;
369 rw = 0;
370 dlg_format_text(NULL, term, ext_msg[0], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
371 y += 2;
372 dlg_format_text(NULL, term, ext_msg[1], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
373 y += 2;
374 dlg_format_buttons(NULL, term, dlg->items + 2, 2, 0, &y, w, &rw, AL_CENTER);
375 w = rw;
376 dlg->xw = w + 2 * DIALOG_LB;
377 dlg->yw = y + 2 * DIALOG_TB;
378 center_dlg(dlg);
379 draw_dlg(dlg);
380 y = dlg->y + DIALOG_TB;
381 dlg_format_text(term, term, ext_msg[0], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
382 dlg_format_field(term, term, &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
383 y++;
384 dlg_format_text(term, term, ext_msg[1], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
385 dlg_format_field(term, term, &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
386 y++;
387 dlg_format_buttons(term, term, &dlg->items[2], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
388 }
389
update_ext(struct extension * new)390 void update_ext(struct extension *new)
391 {
392 struct extension *repl;
393 if (!new->ext[0] || !new->ct[0]) return;
394 if (new->cnt) {
395 foreach(repl, extensions) if (repl->cnt == new->cnt) {
396 mem_free(repl->ext);
397 mem_free(repl->ct);
398 goto replace;
399 }
400 return;
401 }
402 foreach(repl, extensions) if (!strcmp(repl->ext, new->ext) && !strcmp(repl->ct, new->ct)) {
403 del_from_list(repl);
404 add_to_list(extensions, repl);
405 return;
406 }
407 new->cnt = get_assoc_cnt();
408 repl = mem_alloc(sizeof(struct extension));
409 add_to_list(extensions, repl);
410 replace:
411 repl->ext = stracpy(new->ext);
412 repl->ct = stracpy(new->ct);
413 repl->cnt = new->cnt;
414 }
415
really_del_ext(void * fcp)416 void really_del_ext(void *fcp)
417 {
418 unsigned fc = (unsigned)(my_uintptr_t)fcp;
419 struct extension *del;
420 foreach(del, extensions) if (del->cnt == fc) goto ok;
421 return;
422 ok:
423 delete_extension(del);
424 }
425
menu_del_ext(struct terminal * term,void * fcp,void * xxx2)426 void menu_del_ext(struct terminal *term, void *fcp, void *xxx2)
427 {
428 unsigned char *str;
429 int l;
430 unsigned fc = (unsigned)(my_uintptr_t)fcp;
431 struct extension *del;
432 foreach(del, extensions) if (del->cnt == fc) goto ok;
433 return;
434 ok:
435 str = init_str(), l = 0;
436 add_to_str(&str, &l, del->ext);
437 add_to_str(&str, &l, " -> ");
438 add_to_str(&str, &l, del->ct);
439 msg_box(term, getml(str, NULL), TEXT_(T_DELETE_EXTENSION), AL_CENTER | AL_EXTD_TEXT, TEXT_(T_DELETE_EXTENSION), " ", str, "?", NULL, fcp, 2, TEXT_(T_YES), really_del_ext, B_ENTER, TEXT_(T_NO), NULL, B_ESC);
440 }
441
menu_add_ext(struct terminal * term,void * fcp,void * xxx2)442 void menu_add_ext(struct terminal *term, void *fcp, void *xxx2)
443 {
444 unsigned fc = (unsigned)(my_uintptr_t)fcp;
445 struct extension *new, *from;
446 unsigned char *ext;
447 unsigned char *ct;
448 struct dialog *d;
449 if (fc) {
450 foreach(from, extensions) if (from->cnt == fc) goto ok;
451 return;
452 }
453 from = NULL;
454 ok:
455 d = mem_alloc(sizeof(struct dialog) + 5 * sizeof(struct dialog_item) + sizeof(struct extension) + 2 * MAX_STR_LEN);
456 memset(d, 0, sizeof(struct dialog) + 5 * sizeof(struct dialog_item) + sizeof(struct extension) + 2 * MAX_STR_LEN);
457 new = (struct extension *)&d->items[5];
458 new->ext = ext = (unsigned char *)(new + 1);
459 new->ct = ct = ext + MAX_STR_LEN;
460 if (from) {
461 safe_strncpy(ext, from->ext, MAX_STR_LEN);
462 safe_strncpy(ct, from->ct, MAX_STR_LEN);
463 new->cnt = from->cnt;
464 }
465 d->title = TEXT_(T_EXTENSION);
466 d->fn = add_ext_fn;
467 d->refresh = (void (*)(void *))update_ext;
468 d->refresh_data = new;
469 d->items[0].type = D_FIELD;
470 d->items[0].dlen = MAX_STR_LEN;
471 d->items[0].data = ext;
472 d->items[0].fn = check_nonempty;
473 d->items[1].type = D_FIELD;
474 d->items[1].dlen = MAX_STR_LEN;
475 d->items[1].data = ct;
476 d->items[1].fn = check_nonempty;
477 d->items[2].type = D_BUTTON;
478 d->items[2].gid = B_ENTER;
479 d->items[2].fn = ok_dialog;
480 d->items[2].text = TEXT_(T_OK);
481 d->items[3].type = D_BUTTON;
482 d->items[3].gid = B_ESC;
483 d->items[3].text = TEXT_(T_CANCEL);
484 d->items[3].fn = cancel_dialog;
485 d->items[4].type = D_END;
486 do_dialog(term, d, getml(d, NULL));
487 }
488
489 struct menu_item mi_no_ext[] = {
490 { TEXT_(T_NO_EXTENSIONS), "", M_BAR, NULL, NULL, 0, 0 },
491 { NULL, NULL, 0, NULL, NULL, 0, 0 },
492 };
493
menu_list_ext(struct terminal * term,void * fn,void * xxx)494 void menu_list_ext(struct terminal *term, void *fn, void *xxx)
495 {
496 struct extension *a;
497 struct menu_item *mi = NULL;
498 int n = 0;
499 foreachback(a, extensions) {
500 if (!mi && !(mi = new_menu(7))) return;
501 add_to_menu(&mi, stracpy(a->ext), stracpy(a->ct), "", MENU_FUNC fn, (void *)(my_uintptr_t)a->cnt, 0), n++;
502 }
503 if (!mi) do_menu(term, mi_no_ext, xxx);
504 else do_menu(term, mi, xxx);
505 }
506
update_prog(struct list_head * l,unsigned char * p,int s)507 void update_prog(struct list_head *l, unsigned char *p, int s)
508 {
509 struct protocol_program *repl;
510 foreach(repl, *l) if (repl->system == s) {
511 mem_free(repl->prog);
512 goto ss;
513 }
514 repl = mem_alloc(sizeof(struct protocol_program));
515 add_to_list(*l, repl);
516 repl->system = s;
517 ss:
518 repl->prog = mem_alloc(MAX_STR_LEN);
519 safe_strncpy(repl->prog, p, MAX_STR_LEN);
520 }
521
get_prog(struct list_head * l)522 unsigned char *get_prog(struct list_head *l)
523 {
524 struct protocol_program *repl;
525 foreach(repl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
526 update_prog(l, "", SYSTEM_ID);
527 foreach(repl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
528 return NULL;
529 }
530
is_html_type(unsigned char * ct)531 int is_html_type(unsigned char *ct)
532 {
533 return !strcasecmp(ct, "text/html") || !strcasecmp(ct, "text/x-server-parsed-html") || !casecmp(ct, "application/xhtml", strlen("application/xhtml"));
534 }
535