1 /* types.c
2 * (c) 2002 Mikulas Patocka
3 * This file is a part of the Links program, released under GPL.
4 */
5
6 #include "links.h"
7
8
9 /*------------------------ ASSOCIATIONS -----------------------*/
10
11 /* DECLARATIONS */
12
13 static void assoc_edit_item(struct dialog_data *, struct list *, void (*)(struct dialog_data *, struct list *, struct list *, struct list_description *), struct list *, unsigned char);
14 static void assoc_copy_item(struct list *, struct list *);
15 static struct list *assoc_new_item(void *);
16 static void assoc_delete_item(struct list *);
17 static struct list *assoc_find_item(struct list *start, unsigned char *str, int direction);
18 static unsigned char *assoc_type_item(struct terminal *, struct list *, int);
19
20
21 struct list assoc = { init_list_1st(&assoc.list_entry) 0, -1, NULL, init_list_last(&assoc.list_entry) };
22
23 static struct history assoc_search_history = { 0, { &assoc_search_history.items, &assoc_search_history.items } };
24
25 struct assoc_ok_struct {
26 void (*fn)(struct dialog_data *, struct list *, struct list *, struct list_description *);
27 struct list *data;
28 struct dialog_data *dlg;
29 };
30
31
32 static struct list_description assoc_ld={
33 0, /* 0= flat; 1=tree */
34 &assoc, /* list */
35 assoc_new_item,
36 assoc_edit_item,
37 NULL,
38 assoc_delete_item,
39 assoc_copy_item,
40 assoc_type_item,
41 assoc_find_item,
42 &assoc_search_history,
43 0, /* this is set in init_assoc function */
44 15, /* # of items in main window */
45 T_ASSOCIATION,
46 T_ASSOCIATIONS_ALREADY_IN_USE,
47 T_ASSOCIATIONS_MANAGER,
48 T_DELETE_ASSOCIATION,
49 0, /* no button */
50 NULL, /* no button */
51 NULL, /* no save*/
52
53 NULL,NULL,0,0, /* internal vars */
54 0, /* modified */
55 NULL,
56 NULL,
57 1,
58 };
59
assoc_new_item(void * ignore)60 static struct list *assoc_new_item(void *ignore)
61 {
62 struct assoc *neww;
63
64 neww = mem_calloc(sizeof(struct assoc));
65 neww->label = stracpy(cast_uchar "");
66 neww->ct = stracpy(cast_uchar "");
67 neww->prog = stracpy(cast_uchar "");
68 neww->block = neww->xwin = neww->cons = 1;
69 neww->ask = 1;
70 neww->accept_http = 0;
71 neww->accept_ftp = 0;
72 neww->head.type = 0;
73 neww->system = SYSTEM_ID;
74 return &neww->head;
75 }
76
assoc_delete_item(struct list * data)77 static void assoc_delete_item(struct list *data)
78 {
79 struct assoc *del = get_struct(data, struct assoc, head);
80
81 if (del->head.list_entry.next) del_from_list(&del->head);
82 mem_free(del->label);
83 mem_free(del->ct);
84 mem_free(del->prog);
85 mem_free(del);
86 }
87
assoc_copy_item(struct list * in,struct list * out)88 static void assoc_copy_item(struct list *in, struct list *out)
89 {
90 struct assoc *item_in = get_struct(in, struct assoc, head);
91 struct assoc *item_out = get_struct(out, struct assoc, head);
92
93 item_out->cons = item_in->cons;
94 item_out->xwin = item_in->xwin;
95 item_out->block = item_in->block;
96 item_out->ask = item_in->ask;
97 item_out->accept_http = item_in->accept_http;
98 item_out->accept_ftp = item_in->accept_ftp;
99 item_out->system = item_in->system;
100
101 mem_free(item_out->label);
102 mem_free(item_out->ct);
103 mem_free(item_out->prog);
104
105 item_out->label = stracpy(item_in->label);
106 item_out->ct = stracpy(item_in->ct);
107 item_out->prog = stracpy(item_in->prog);
108 }
109
110 /* allocate string and print association into it */
111 /* x: 0=type all, 1=type title only */
assoc_type_item(struct terminal * term,struct list * data,int x)112 static unsigned char *assoc_type_item(struct terminal *term, struct list *data, int x)
113 {
114 unsigned char *txt, *txt1;
115 struct assoc *item;
116
117 if (data == &assoc) return stracpy(get_text_translation(TEXT_(T_ASSOCIATIONS), term));
118
119 item = get_struct(data, struct assoc, head);
120 txt = stracpy(cast_uchar "");
121 if (item->system != SYSTEM_ID) add_to_strn(&txt, cast_uchar "XX ");
122 add_to_strn(&txt, item->label);
123 add_to_strn(&txt, cast_uchar ": ");
124 add_to_strn(&txt, item->ct);
125 if (!x) {
126 add_to_strn(&txt, cast_uchar " -> ");
127 if (item->prog) add_to_strn(&txt, item->prog);
128 }
129 txt1 = convert(assoc_ld.codepage, term_charset(term), txt, NULL);
130 mem_free(txt);
131
132 return txt1;
133 }
134
menu_assoc_manager(struct terminal * term,void * fcp,void * ses_)135 void menu_assoc_manager(struct terminal *term, void *fcp, void *ses_)
136 {
137 struct session *ses = (struct session *)ses_;
138 create_list_window(&assoc_ld,&assoc, term, ses);
139 }
140
141 static unsigned char * const ct_msg[] = {
142 TEXT_(T_LABEL),
143 TEXT_(T_CONTENT_TYPES),
144 TEXT_(T_PROGRAM__IS_REPLACED_WITH_FILE_NAME),
145 #ifdef ASSOC_BLOCK
146 TEXT_(T_BLOCK_TERMINAL_WHILE_PROGRAM_RUNNING),
147 #endif
148 #ifdef ASSOC_CONS_XWIN
149 TEXT_(T_RUN_ON_TERMINAL),
150 TEXT_(T_RUN_IN_XWINDOW),
151 #endif
152 TEXT_(T_ASK_BEFORE_OPENING),
153 TEXT_(T_ACCEPT_HTTP),
154 TEXT_(T_ACCEPT_FTP),
155 };
156
assoc_edit_item_fn(struct dialog_data * dlg)157 static void assoc_edit_item_fn(struct dialog_data *dlg)
158 {
159 struct terminal *term = dlg->win->term;
160 int max = 0, min = 0;
161 int w, rw;
162 int y = gf_val(-1, -G_BFU_FONT_SIZE);
163 int p = 3;
164 if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
165 #ifdef ASSOC_BLOCK
166 p++;
167 #endif
168 #ifdef ASSOC_CONS_XWIN
169 p += 2;
170 #endif
171 max_text_width(term, ct_msg[0], &max, AL_LEFT);
172 min_text_width(term, ct_msg[0], &min, AL_LEFT);
173 max_text_width(term, ct_msg[1], &max, AL_LEFT);
174 min_text_width(term, ct_msg[1], &min, AL_LEFT);
175 max_text_width(term, ct_msg[2], &max, AL_LEFT);
176 min_text_width(term, ct_msg[2], &min, AL_LEFT);
177 max_group_width(term, ct_msg + 3, dlg->items + 3, p, &max);
178 min_group_width(term, ct_msg + 3, dlg->items + 3, p, &min);
179 max_buttons_width(term, dlg->items + 3 + p, 2, &max);
180 min_buttons_width(term, dlg->items + 3 + p, 2, &min);
181 w = term->x * 9 / 10 - 2 * DIALOG_LB;
182 if (w > max) w = max;
183 if (w < min) w = min;
184 if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
185 if (w < 1) w = 1;
186 rw = 0;
187 dlg_format_text_and_field(dlg, NULL, get_text_translation(ct_msg[0], term), &dlg->items[0], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
188 y += gf_val(1, G_BFU_FONT_SIZE * 1);
189 dlg_format_text_and_field(dlg, NULL, get_text_translation(ct_msg[1], term), &dlg->items[1], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
190 y += gf_val(1, G_BFU_FONT_SIZE * 1);
191 dlg_format_text_and_field(dlg, NULL, get_text_translation(ct_msg[2], term), &dlg->items[2], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
192 y += gf_val(1, G_BFU_FONT_SIZE * 1);
193 dlg_format_group(dlg, NULL, ct_msg + 3, dlg->items + 3, p, 0, &y, w, &rw);
194 y += gf_val(1, G_BFU_FONT_SIZE);
195 dlg_format_buttons(dlg, NULL, dlg->items + 3 + p, 2, 0, &y, w, &rw, AL_CENTER);
196 w = rw;
197 dlg->xw = w + 2 * DIALOG_LB;
198 dlg->yw = y + 2 * DIALOG_TB;
199 center_dlg(dlg);
200 draw_dlg(dlg);
201 y = dlg->y + DIALOG_TB;
202 if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
203 dlg_format_text_and_field(dlg, term, ct_msg[0], &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
204 y += gf_val(1, G_BFU_FONT_SIZE);
205 dlg_format_text_and_field(dlg, term, ct_msg[1], &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
206 y += gf_val(1, G_BFU_FONT_SIZE);
207 dlg_format_text_and_field(dlg, term, ct_msg[2], &dlg->items[2], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
208 y += gf_val(1, G_BFU_FONT_SIZE);
209 dlg_format_group(dlg, term, ct_msg + 3, &dlg->items[3], p, dlg->x + DIALOG_LB, &y, w, NULL);
210 y += gf_val(1, G_BFU_FONT_SIZE);
211 dlg_format_buttons(dlg, term, &dlg->items[3 + p], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
212 }
213
214 /* Puts url and title into the bookmark item */
assoc_edit_done(void * data)215 static void assoc_edit_done(void *data)
216 {
217 struct dialog *d = (struct dialog *)data;
218 struct assoc *item = (struct assoc *)d->udata;
219 struct assoc_ok_struct *s = (struct assoc_ok_struct *)d->udata2;
220 unsigned char *txt;
221 unsigned char *label, *ct, *prog;
222
223 label = (unsigned char *)&d->items[12];
224 ct = label + MAX_STR_LEN;
225 prog = ct + MAX_STR_LEN;
226
227 txt = convert(term_charset(s->dlg->win->term), assoc_ld.codepage, label, NULL);
228 mem_free(item->label);
229 item->label = txt;
230
231 txt = convert(term_charset(s->dlg->win->term), assoc_ld.codepage, ct, NULL);
232 mem_free(item->ct);
233 item->ct = txt;
234
235 txt = convert(term_charset(s->dlg->win->term), assoc_ld.codepage, prog, NULL);
236 mem_free(item->prog);
237 item->prog = txt;
238
239 s->fn(s->dlg, s->data, &item->head, &assoc_ld);
240 d->udata = NULL; /* for abort function */
241 }
242
243 /* destroys an item, this function is called when edit window is aborted */
assoc_edit_abort(struct dialog_data * data)244 static void assoc_edit_abort(struct dialog_data *data)
245 {
246 struct dialog *dlg = data->dlg;
247 struct assoc *item = (struct assoc *)dlg->udata;
248
249 mem_free(dlg->udata2);
250 if (item) assoc_delete_item(&item->head);
251 }
252
assoc_edit_item(struct dialog_data * dlg,struct list * data,void (* ok_fn)(struct dialog_data *,struct list *,struct list *,struct list_description *),struct list * ok_arg,unsigned char dlg_title)253 static void assoc_edit_item(struct dialog_data *dlg, struct list *data, void (*ok_fn)(struct dialog_data *, struct list *, struct list *, struct list_description *), struct list *ok_arg, unsigned char dlg_title)
254 {
255 int p;
256 struct assoc *neww = get_struct(data, struct assoc, head);
257 struct terminal *term = dlg->win->term;
258 struct dialog *d;
259 struct assoc_ok_struct *s;
260 unsigned char *ct, *prog, *label;
261
262 d = mem_calloc(sizeof(struct dialog) + 11 * sizeof(struct dialog_item) + 3 * MAX_STR_LEN);
263
264 label = (unsigned char *)&d->items[12];
265 ct = label + MAX_STR_LEN;
266 prog = ct + MAX_STR_LEN;
267
268 safe_strncpy(label, neww->label, MAX_STR_LEN);
269 safe_strncpy(ct, neww->ct, MAX_STR_LEN);
270 safe_strncpy(prog, neww->prog, MAX_STR_LEN);
271
272 /* Create the dialog */
273 s = mem_alloc(sizeof(struct assoc_ok_struct));
274 s->fn = ok_fn;
275 s->data = ok_arg;
276 s->dlg = dlg;
277
278 switch (dlg_title) {
279 case TITLE_EDIT:
280 d->title = TEXT_(T_EDIT_ASSOCIATION);
281 break;
282
283 case TITLE_ADD:
284 d->title = TEXT_(T_ADD_ASSOCIATION);
285 break;
286
287 default:
288 internal_error("Unsupported dialog title.\n");
289 }
290
291 d->udata = neww;
292 d->udata2 = s;
293 d->fn = assoc_edit_item_fn;
294 d->abort = assoc_edit_abort;
295 d->refresh = assoc_edit_done;
296 d->refresh_data = d;
297 d->items[0].type = D_FIELD;
298 d->items[0].dlen = MAX_STR_LEN;
299 d->items[0].data = label;
300 d->items[0].fn = check_nonempty;
301 d->items[1].type = D_FIELD;
302 d->items[1].dlen = MAX_STR_LEN;
303 d->items[1].data = ct;
304 d->items[1].fn = check_nonempty;
305 d->items[2].type = D_FIELD;
306 d->items[2].dlen = MAX_STR_LEN;
307 d->items[2].data = prog;
308 d->items[2].fn = check_nonempty;
309 p = 3;
310 #ifdef ASSOC_BLOCK
311 d->items[p].type = D_CHECKBOX;
312 d->items[p].data = (unsigned char *)&neww->block;
313 d->items[p++].dlen = sizeof(int);
314 #endif
315 #ifdef ASSOC_CONS_XWIN
316 d->items[p].type = D_CHECKBOX;
317 d->items[p].data = (unsigned char *)&neww->cons;
318 d->items[p++].dlen = sizeof(int);
319 d->items[p].type = D_CHECKBOX;
320 d->items[p].data = (unsigned char *)&neww->xwin;
321 d->items[p++].dlen = sizeof(int);
322 #endif
323 d->items[p].type = D_CHECKBOX;
324 d->items[p].data = (unsigned char *)&neww->ask;
325 d->items[p++].dlen = sizeof(int);
326 d->items[p].type = D_CHECKBOX;
327 d->items[p].data = (unsigned char *)&neww->accept_http;
328 d->items[p++].dlen = sizeof(int);
329 d->items[p].type = D_CHECKBOX;
330 d->items[p].data = (unsigned char *)&neww->accept_ftp;
331 d->items[p++].dlen = sizeof(int);
332 d->items[p].type = D_BUTTON;
333 d->items[p].gid = B_ENTER;
334 d->items[p].fn = ok_dialog;
335 d->items[p++].text = TEXT_(T_OK);
336 d->items[p].type = D_BUTTON;
337 d->items[p].gid = B_ESC;
338 d->items[p].text = TEXT_(T_CANCEL);
339 d->items[p++].fn = cancel_dialog;
340 d->items[p++].type = D_END;
341 do_dialog(term, d, getml(d, NULL));
342 }
343
assoc_test_entry(struct list * e,unsigned char * str)344 static int assoc_test_entry(struct list *e, unsigned char *str)
345 {
346 struct assoc *a = get_struct(e, struct assoc, head);
347 return casestrstr(a->label, str) || casestrstr(a->ct, str);
348 }
349
assoc_find_item(struct list * s,unsigned char * str,int direction)350 static struct list *assoc_find_item(struct list *s, unsigned char *str, int direction)
351 {
352 struct list *e;
353
354 if (direction >= 0) {
355 for (e = list_next(s); e != s; e = list_next(e)) {
356 if (e->depth >= 0 && assoc_test_entry(e, str))
357 return e;
358 }
359 } else {
360 for (e = list_prev(s); e != s; e = list_prev(e)) {
361 if (e->depth >= 0 && assoc_test_entry(e, str))
362 return e;
363 }
364 }
365
366 if (e->depth >= 0 && assoc_test_entry(e, str))
367 return e;
368
369 return NULL;
370 }
371
372
update_assoc(struct assoc * neww)373 void update_assoc(struct assoc *neww)
374 {
375 struct assoc *repl;
376 struct list *r;
377 struct list_head *lr;
378 if (!neww->label[0] || !neww->ct[0] || !neww->prog[0]) return;
379 foreach(struct list, r, lr, assoc.list_entry) {
380 repl = get_struct(r, struct assoc, head);
381 if (!strcmp(cast_const_char repl->label, cast_const_char neww->label)
382 && !strcmp(cast_const_char repl->ct, cast_const_char neww->ct)
383 && !strcmp(cast_const_char repl->prog, cast_const_char neww->prog)
384 && repl->block == neww->block
385 && repl->cons == neww->cons
386 && repl->xwin == neww->xwin
387 && repl->ask == neww->ask
388 && repl->accept_http == neww->accept_http
389 && repl->accept_ftp == neww->accept_ftp
390 && repl->system == neww->system) {
391 del_from_list(&repl->head);
392 add_to_list(assoc.list_entry, &repl->head);
393 return;
394 }
395 }
396 repl = mem_calloc(sizeof(struct assoc));
397 repl->label = stracpy(neww->label);
398 repl->ct = stracpy(neww->ct);
399 repl->prog = stracpy(neww->prog);
400 repl->block = neww->block;
401 repl->cons = neww->cons;
402 repl->xwin = neww->xwin;
403 repl->ask = neww->ask;
404 repl->accept_http = neww->accept_http;
405 repl->accept_ftp = neww->accept_ftp;
406 repl->system = neww->system;
407 repl->head.type = 0;
408 add_to_list(assoc.list_entry, &repl->head);
409 }
410
411 /*------------------------ EXTENSIONS -----------------------*/
412
413 /* DECLARATIONS */
414 static void ext_edit_item(struct dialog_data *, struct list *, void (*)(struct dialog_data *, struct list *, struct list *, struct list_description *), struct list *, unsigned char);
415 static void ext_copy_item(struct list *, struct list *);
416 static struct list *ext_new_item(void *);
417 static void ext_delete_item(struct list *);
418 static struct list *ext_find_item(struct list *start, unsigned char *str, int direction);
419 static unsigned char *ext_type_item(struct terminal *, struct list *, int);
420
421 struct list extensions = { init_list_1st(&extensions.list_entry) 0, -1, NULL, init_list_last(&extensions.list_entry) };
422
423 static struct history ext_search_history = { 0, { &ext_search_history.items, &ext_search_history.items } };
424
425
426 static struct list_description ext_ld={
427 0, /* 0= flat; 1=tree */
428 &extensions, /* list */
429 ext_new_item,
430 ext_edit_item,
431 NULL,
432 ext_delete_item,
433 ext_copy_item,
434 ext_type_item,
435 ext_find_item,
436 &ext_search_history,
437 0, /* this is set in init_assoc function */
438 15, /* # of items in main window */
439 T_eXTENSION,
440 T_EXTENSIONS_ALREADY_IN_USE,
441 T_EXTENSIONS_MANAGER,
442 T_DELETE_EXTENSION,
443 0, /* no button */
444 NULL, /* no button */
445 NULL, /* no save*/
446
447 NULL,NULL,0,0, /* internal vars */
448 0, /* modified */
449 NULL,
450 NULL,
451 0,
452 };
453
454
455
456
457
ext_new_item(void * ignore)458 static struct list *ext_new_item(void *ignore)
459 {
460 struct extension *neww;
461
462 neww = mem_calloc(sizeof(struct extension));
463 neww->ext = stracpy(cast_uchar "");
464 neww->ct = stracpy(cast_uchar "");
465 neww->head.type = 0;
466 return &neww->head;
467 }
468
469
ext_delete_item(struct list * data)470 static void ext_delete_item(struct list *data)
471 {
472 struct extension *del = get_struct(data, struct extension, head);
473
474 if (del->head.list_entry.next) del_from_list(&del->head);
475 if (del->ext) mem_free(del->ext);
476 if (del->ct) mem_free(del->ct);
477 mem_free(del);
478 }
479
480
ext_copy_item(struct list * in,struct list * out)481 static void ext_copy_item(struct list *in, struct list *out)
482 {
483 struct extension *item_in = get_struct(in, struct extension, head);
484 struct extension *item_out = get_struct(out, struct extension, head);
485
486 mem_free(item_out->ext);
487 mem_free(item_out->ct);
488
489 item_out->ext = stracpy(item_in->ext);
490 item_out->ct = stracpy(item_in->ct);
491 }
492
493
494 /* allocate string and print extension into it */
495 /* x: 0=type all, 1=type title only */
ext_type_item(struct terminal * term,struct list * data,int x)496 static unsigned char *ext_type_item(struct terminal *term, struct list *data, int x)
497 {
498 unsigned char *txt, *txt1;
499 struct extension *item;
500
501 if (data == &extensions) return stracpy(get_text_translation(TEXT_(T_FILE_EXTENSIONS), term));
502
503 item = get_struct(data, struct extension, head);
504 txt = stracpy(item->ext);
505 add_to_strn(&txt, cast_uchar ": ");
506 add_to_strn(&txt, item->ct);
507 txt1 = convert(assoc_ld.codepage, term_charset(term), txt, NULL);
508 mem_free(txt);
509
510 return txt1;
511 }
512
513
menu_ext_manager(struct terminal * term,void * fcp,void * ses_)514 void menu_ext_manager(struct terminal *term, void *fcp, void *ses_)
515 {
516 struct session *ses = (struct session *)ses_;
517 create_list_window(&ext_ld, &extensions, term, ses);
518 }
519
520 static unsigned char * const ext_msg[] = {
521 TEXT_(T_EXTENSION_S),
522 TEXT_(T_CONTENT_TYPE),
523 };
524
ext_edit_item_fn(struct dialog_data * dlg)525 static void ext_edit_item_fn(struct dialog_data *dlg)
526 {
527 struct terminal *term = dlg->win->term;
528 int max = 0, min = 0;
529 int w, rw;
530 int y = gf_val(-1, -G_BFU_FONT_SIZE);
531 if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
532 max_text_width(term, ext_msg[0], &max, AL_LEFT);
533 min_text_width(term, ext_msg[0], &min, AL_LEFT);
534 max_text_width(term, ext_msg[1], &max, AL_LEFT);
535 min_text_width(term, ext_msg[1], &min, AL_LEFT);
536 max_buttons_width(term, dlg->items + 2, 2, &max);
537 min_buttons_width(term, dlg->items + 2, 2, &min);
538 w = term->x * 9 / 10 - 2 * DIALOG_LB;
539 if (w > max) w = max;
540 if (w < min) w = min;
541 if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
542 if (w < 1) w = 1;
543 rw = 0;
544 dlg_format_text_and_field(dlg, NULL, ext_msg[0], &dlg->items[0], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
545 y += gf_val(1, G_BFU_FONT_SIZE * 1);
546 dlg_format_text_and_field(dlg, NULL, ext_msg[1], &dlg->items[1], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
547 y += gf_val(1, G_BFU_FONT_SIZE * 1);
548 dlg_format_buttons(dlg, NULL, dlg->items + 2, 2, 0, &y, w, &rw, AL_CENTER);
549 w = rw;
550 dlg->xw = w + 2 * DIALOG_LB;
551 dlg->yw = y + 2 * DIALOG_TB;
552 center_dlg(dlg);
553 draw_dlg(dlg);
554 y = dlg->y + DIALOG_TB;
555 if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
556 dlg_format_text_and_field(dlg, term, ext_msg[0], &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
557 y += gf_val(1, G_BFU_FONT_SIZE);
558 dlg_format_text_and_field(dlg, term, ext_msg[1], &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
559 y += gf_val(1, G_BFU_FONT_SIZE);
560 dlg_format_buttons(dlg, term, &dlg->items[2], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
561 }
562
563
564 /* Puts url and title into the bookmark item */
ext_edit_done(void * data)565 static void ext_edit_done(void *data)
566 {
567 struct dialog *d = (struct dialog*)data;
568 struct extension *item = (struct extension *)d->udata;
569 struct assoc_ok_struct *s = (struct assoc_ok_struct *)d->udata2;
570 unsigned char *txt;
571 unsigned char *ext, *ct;
572
573 ext = (unsigned char *)&d->items[5];
574 ct = ext + MAX_STR_LEN;
575
576 txt = convert(term_charset(s->dlg->win->term), ext_ld.codepage,ext, NULL);
577 mem_free(item->ext);
578 item->ext = txt;
579
580 txt = convert(term_charset(s->dlg->win->term), ext_ld.codepage,ct, NULL);
581 mem_free(item->ct);
582 item->ct=txt;
583
584 s->fn(s->dlg, s->data, &item->head, &ext_ld);
585 d->udata = NULL; /* for abort function */
586 }
587
588
589 /* destroys an item, this function is called when edit window is aborted */
ext_edit_abort(struct dialog_data * data)590 static void ext_edit_abort(struct dialog_data *data)
591 {
592 struct dialog *dlg = data->dlg;
593 struct extension *item = (struct extension *)dlg->udata;
594
595 mem_free(dlg->udata2);
596 if (item) ext_delete_item(&item->head);
597 }
598
599
ext_edit_item(struct dialog_data * dlg,struct list * data,void (* ok_fn)(struct dialog_data *,struct list *,struct list *,struct list_description *),struct list * ok_arg,unsigned char dlg_title)600 static void ext_edit_item(struct dialog_data *dlg, struct list *data, void (*ok_fn)(struct dialog_data *, struct list *, struct list *, struct list_description *), struct list *ok_arg, unsigned char dlg_title)
601 {
602 struct extension *neww = get_struct(data, struct extension, head);
603 struct terminal *term = dlg->win->term;
604 struct dialog *d;
605 struct assoc_ok_struct *s;
606 unsigned char *ext;
607 unsigned char *ct;
608
609 d = mem_calloc(sizeof(struct dialog) + 4 * sizeof(struct dialog_item) + 2 * MAX_STR_LEN);
610
611 ext = (unsigned char *)&d->items[5];
612 ct = ext + MAX_STR_LEN;
613 safe_strncpy(ext, neww->ext, MAX_STR_LEN);
614 safe_strncpy(ct, neww->ct, MAX_STR_LEN);
615
616 /* Create the dialog */
617 s = mem_alloc(sizeof(struct assoc_ok_struct));
618 s->fn = ok_fn;
619 s->data = ok_arg;
620 s->dlg = dlg;
621
622 switch (dlg_title) {
623 case TITLE_EDIT:
624 d->title = TEXT_(T_EDIT_EXTENSION);
625 break;
626
627 case TITLE_ADD:
628 d->title = TEXT_(T_ADD_EXTENSION);
629 break;
630
631 default:
632 internal_error("Unsupported dialog title.\n");
633 }
634
635 d->udata = neww;
636 d->udata2 = s;
637 d->abort = ext_edit_abort;
638 d->refresh = ext_edit_done;
639 d->refresh_data = d;
640 d->title = TEXT_(T_EXTENSION);
641 d->fn = ext_edit_item_fn;
642 d->items[0].type = D_FIELD;
643 d->items[0].dlen = MAX_STR_LEN;
644 d->items[0].data = ext;
645 d->items[0].fn = check_nonempty;
646 d->items[1].type = D_FIELD;
647 d->items[1].dlen = MAX_STR_LEN;
648 d->items[1].data = ct;
649 d->items[1].fn = check_nonempty;
650 d->items[2].type = D_BUTTON;
651 d->items[2].gid = B_ENTER;
652 d->items[2].fn = ok_dialog;
653 d->items[2].text = TEXT_(T_OK);
654 d->items[3].type = D_BUTTON;
655 d->items[3].gid = B_ESC;
656 d->items[3].text = TEXT_(T_CANCEL);
657 d->items[3].fn = cancel_dialog;
658 d->items[4].type = D_END;
659 do_dialog(term, d, getml(d, NULL));
660 }
661
662
ext_test_entry(struct list * e,unsigned char * str)663 static int ext_test_entry(struct list *e, unsigned char *str)
664 {
665 struct extension *ext = get_struct(e, struct extension, head);
666 return casestrstr(ext->ext, str) || casestrstr(ext->ct, str);
667 }
668
ext_find_item(struct list * s,unsigned char * str,int direction)669 static struct list *ext_find_item(struct list *s, unsigned char *str, int direction)
670 {
671 struct list *e;
672
673 if (direction >= 0) {
674 for (e = list_next(s); e != s; e = list_next(e)) {
675 if (e->depth >= 0 && ext_test_entry(e, str))
676 return e;
677 }
678 } else {
679 for (e = list_prev(s); e != s; e = list_prev(e)) {
680 if (e->depth >= 0 && ext_test_entry(e, str))
681 return e;
682 }
683 }
684
685 if (e->depth >= 0 && ext_test_entry(e, str))
686 return e;
687
688 return NULL;
689 }
690
691
update_ext(struct extension * neww)692 void update_ext(struct extension *neww)
693 {
694 struct extension *repl;
695 struct list *r;
696 struct list_head *lr;
697 if (!neww->ext[0] || !neww->ct[0]) return;
698 foreach(struct list, r, lr, extensions.list_entry) {
699 repl = get_struct(r, struct extension, head);
700 if (!strcmp(cast_const_char repl->ext, cast_const_char neww->ext)
701 && !strcmp(cast_const_char repl->ct, cast_const_char neww->ct)) {
702 del_from_list(&repl->head);
703 add_to_list(extensions.list_entry, &repl->head);
704 return;
705 }
706 }
707 repl = mem_calloc(sizeof(struct extension));
708 repl->ext = stracpy(neww->ext);
709 repl->ct = stracpy(neww->ct);
710 repl->head.type = 0;
711 add_to_list(extensions.list_entry, &repl->head);
712 }
713
update_prog(struct list_head * l,unsigned char * p,int s)714 void update_prog(struct list_head *l, unsigned char *p, int s)
715 {
716 struct protocol_program *repl;
717 struct list_head *lrepl;
718 foreach(struct protocol_program, repl, lrepl, *l) if (repl->system == s) {
719 mem_free(repl->prog);
720 goto ss;
721 }
722 repl = mem_alloc(sizeof(struct protocol_program));
723 add_to_list(*l, repl);
724 repl->system = s;
725 ss:
726 repl->prog = mem_alloc(MAX_STR_LEN);
727 safe_strncpy(repl->prog, p, MAX_STR_LEN);
728 }
729
get_prog(struct list_head * l)730 unsigned char *get_prog(struct list_head *l)
731 {
732 struct protocol_program *repl;
733 struct list_head *lrepl;
734 foreach(struct protocol_program, repl, lrepl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
735 update_prog(l, cast_uchar "", SYSTEM_ID);
736 foreach(struct protocol_program, repl, lrepl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
737 internal_error("get_prog: program was not added");
738 return cast_uchar "";;
739 }
740
741
742 /* creates default extensions if extension list is empty */
create_initial_extensions(void)743 void create_initial_extensions(void)
744 {
745 struct extension ext;
746
747 if (!list_empty(extensions.list_entry)) return;
748
749 /* here you can add any default extension you want */
750 ext.ext = cast_uchar "xpm", ext.ct=cast_uchar "image/x-xpixmap", update_ext(&ext);
751 ext.ext = cast_uchar "xls", ext.ct=cast_uchar "application/excel", update_ext(&ext);
752 ext.ext = cast_uchar "xbm", ext.ct=cast_uchar "image/x-xbitmap", update_ext(&ext);
753 ext.ext = cast_uchar "wav", ext.ct=cast_uchar "audio/x-wav", update_ext(&ext);
754 ext.ext = cast_uchar "tiff,tif", ext.ct=cast_uchar "image/tiff", update_ext(&ext);
755 ext.ext = cast_uchar "tga", ext.ct=cast_uchar "image/targa", update_ext(&ext);
756 ext.ext = cast_uchar "sxw", ext.ct=cast_uchar "application/x-openoffice", update_ext(&ext);
757 ext.ext = cast_uchar "swf", ext.ct=cast_uchar "application/x-shockwave-flash", update_ext(&ext);
758 ext.ext = cast_uchar "svg", ext.ct=cast_uchar "image/svg+xml", update_ext(&ext);
759 ext.ext = cast_uchar "sch", ext.ct=cast_uchar "application/gschem", update_ext(&ext);
760 ext.ext = cast_uchar "rtf", ext.ct=cast_uchar "application/rtf", update_ext(&ext);
761 ext.ext = cast_uchar "ra,rm,ram", ext.ct=cast_uchar "audio/x-pn-realaudio", update_ext(&ext);
762 ext.ext = cast_uchar "qt,mov", ext.ct=cast_uchar "video/quicktime", update_ext(&ext);
763 ext.ext = cast_uchar "ps,eps,ai", ext.ct=cast_uchar "application/postscript", update_ext(&ext);
764 ext.ext = cast_uchar "ppt", ext.ct=cast_uchar "application/powerpoint", update_ext(&ext);
765 ext.ext = cast_uchar "ppm", ext.ct=cast_uchar "image/x-portable-pixmap", update_ext(&ext);
766 ext.ext = cast_uchar "pnm", ext.ct=cast_uchar "image/x-portable-anymap", update_ext(&ext);
767 ext.ext = cast_uchar "png", ext.ct=cast_uchar "image/png", update_ext(&ext);
768 ext.ext = cast_uchar "pgp", ext.ct=cast_uchar "application/pgp-signature", update_ext(&ext);
769 ext.ext = cast_uchar "pgm", ext.ct=cast_uchar "image/x-portable-graymap", update_ext(&ext);
770 ext.ext = cast_uchar "pdf", ext.ct=cast_uchar "application/pdf", update_ext(&ext);
771 ext.ext = cast_uchar "pcb", ext.ct=cast_uchar "application/pcb", update_ext(&ext);
772 ext.ext = cast_uchar "pbm", ext.ct=cast_uchar "image/x-portable-bitmap", update_ext(&ext);
773 ext.ext = cast_uchar "mpeg,mpg,mpe", ext.ct=cast_uchar "video/mpeg", update_ext(&ext);
774 ext.ext = cast_uchar "mp3", ext.ct=cast_uchar "audio/mpeg", update_ext(&ext);
775 ext.ext = cast_uchar "mid,midi", ext.ct=cast_uchar "audio/midi", update_ext(&ext);
776 ext.ext = cast_uchar "jpg,jpeg,jpe", ext.ct=cast_uchar "image/jpeg", update_ext(&ext);
777 ext.ext = cast_uchar "grb", ext.ct=cast_uchar "application/gerber", update_ext(&ext);
778 ext.ext = cast_uchar "gl", ext.ct=cast_uchar "video/gl", update_ext(&ext);
779 ext.ext = cast_uchar "gif", ext.ct=cast_uchar "image/gif", update_ext(&ext);
780 ext.ext = cast_uchar "gbr", ext.ct=cast_uchar "application/gerber", update_ext(&ext);
781 ext.ext = cast_uchar "g", ext.ct=cast_uchar "application/brlcad", update_ext(&ext);
782 ext.ext = cast_uchar "fli", ext.ct=cast_uchar "video/fli", update_ext(&ext);
783 ext.ext = cast_uchar "dxf", ext.ct=cast_uchar "application/dxf", update_ext(&ext);
784 ext.ext = cast_uchar "dvi", ext.ct=cast_uchar "application/x-dvi", update_ext(&ext);
785 ext.ext = cast_uchar "dl", ext.ct=cast_uchar "video/dl", update_ext(&ext);
786 ext.ext = cast_uchar "deb", ext.ct=cast_uchar "application/x-debian-package", update_ext(&ext);
787 ext.ext = cast_uchar "avi", ext.ct=cast_uchar "video/x-msvideo", update_ext(&ext);
788 ext.ext = cast_uchar "au,snd", ext.ct=cast_uchar "audio/basic", update_ext(&ext);
789 ext.ext = cast_uchar "aif,aiff,aifc", ext.ct=cast_uchar "audio/x-aiff", update_ext(&ext);
790 }
791
792 /* --------------------------- PROG -----------------------------*/
793
794
795 struct list_head mailto_prog = { &mailto_prog, &mailto_prog };
796 struct list_head telnet_prog = { &telnet_prog, &telnet_prog };
797 struct list_head tn3270_prog = { &tn3270_prog, &tn3270_prog };
798 struct list_head mms_prog = { &mms_prog, &mms_prog };
799 struct list_head magnet_prog = { &magnet_prog, &magnet_prog };
800
801
is_in_list(unsigned char * list,unsigned char * str,int l)802 static int is_in_list(unsigned char *list, unsigned char *str, int l)
803 {
804 unsigned char *l2, *l3;
805 if (!l) return 0;
806 rep:
807 while (*list && *list <= ' ') list++;
808 if (!*list) return 0;
809 for (l2 = list; *l2 && *l2 != ','; l2++)
810 ;
811 for (l3 = l2 - 1; l3 >= list && *l3 <= ' '; l3--)
812 ;
813 l3++;
814 if (l3 - list == l && !casecmp(str, list, l)) return 1;
815 list = l2;
816 if (*list == ',') list++;
817 goto rep;
818 }
819
canonical_compressed_ext(unsigned char * ext,unsigned char * ext_end)820 static unsigned char *canonical_compressed_ext(unsigned char *ext, unsigned char *ext_end)
821 {
822 size_t len;
823 if (!ext_end) ext_end = cast_uchar strchr(cast_const_char ext, 0);
824 len = ext_end - ext;
825 if (len == 3 && !casecmp(ext, cast_uchar "tgz", 3)) return cast_uchar "gz";
826 if (len == 3 && !casecmp(ext, cast_uchar "tbz", 3)) return cast_uchar "bz2";
827 if (len == 3 && !casecmp(ext, cast_uchar "txz", 3)) return cast_uchar "xz";
828 if (len == 6 && !casecmp(ext, cast_uchar "tar-gz", 3)) return cast_uchar "gz";
829 if (len == 7 && !casecmp(ext, cast_uchar "tar-bz2", 3)) return cast_uchar "bz2";
830 if (len == 6 && !casecmp(ext, cast_uchar "tar-xz", 3)) return cast_uchar "xz";
831 return NULL;
832 }
833
get_compress_by_extension(unsigned char * ext,unsigned char * ext_end)834 unsigned char *get_compress_by_extension(unsigned char *ext, unsigned char *ext_end)
835 {
836 size_t len;
837 unsigned char *x;
838 if ((x = canonical_compressed_ext(ext, ext_end))) {
839 ext = x;
840 ext_end = cast_uchar strchr(cast_const_char x, 0);
841 }
842 len = ext_end - ext;
843 if (len == 1 && !casecmp(ext, cast_uchar "z", 1)) return cast_uchar "compress";
844 if (len == 2 && !casecmp(ext, cast_uchar "gz", 2)) return cast_uchar "gzip";
845 if (len == 2 && !casecmp(ext, cast_uchar "br", 2)) return cast_uchar "br";
846 if (len == 3 && !casecmp(ext, cast_uchar "zst", 3)) return cast_uchar "zstd";
847 if (len == 3 && !casecmp(ext, cast_uchar "bz2", 3)) return cast_uchar "bzip2";
848 if (len == 4 && !casecmp(ext, cast_uchar "lzma", 4)) return cast_uchar "lzma";
849 if (len == 2 && !casecmp(ext, cast_uchar "xz", 2)) return cast_uchar "lzma2";
850 if (len == 2 && !casecmp(ext, cast_uchar "lz", 2)) return cast_uchar "lzip";
851 return NULL;
852 }
853
get_content_type_by_extension(unsigned char * url)854 unsigned char *get_content_type_by_extension(unsigned char *url)
855 {
856 struct list *l;
857 struct list_head *ll;
858 unsigned char *ct, *eod, *ext, *exxt;
859 int extl, el;
860 ext = NULL, extl = 0;
861 if (!(ct = get_url_data(url))) ct = url;
862 for (eod = ct; *eod && !end_of_dir(url, *eod); eod++)
863 ;
864 for (; ct < eod; ct++)
865 if (*ct == '.') {
866 if (ext) {
867 if (get_compress_by_extension(ct + 1, eod))
868 break;
869 }
870 ext = ct + 1;
871 } else if (dir_sep(*ct)) {
872 ext = NULL;
873 }
874 if (ext) while (ext[extl] && ext[extl] != '.' && !dir_sep(ext[extl]) && !end_of_dir(url, ext[extl])) extl++;
875 if (force_html ||
876 (extl == 3 && !casecmp(ext, cast_uchar "htm", 3)) ||
877 (extl == 4 && !casecmp(ext, cast_uchar "html", 4)) ||
878 (extl == 5 && !casecmp(ext, cast_uchar "xhtml", 5))) return stracpy(cast_uchar "text/html");
879 foreach(struct list, l, ll, extensions.list_entry) {
880 struct extension *e = get_struct(l, struct extension, head);
881 unsigned char *fname = NULL;
882 if (!(ct = get_url_data(url))) ct = url;
883 for (; *ct && !end_of_dir(url, *ct); ct++)
884 if (dir_sep(*ct)) fname = ct + 1;
885 if (!fname) {
886 if (is_in_list(e->ext, ext, extl)) return stracpy(e->ct);
887 } else {
888 int fnlen = 0;
889 int x;
890 while (fname[fnlen] && !end_of_dir(url, fname[fnlen])) fnlen++;
891 for (x = 0; x < fnlen; x++) if (fname[x] == '.') if (is_in_list(e->ext, fname + x + 1, fnlen - x - 1)) return stracpy(e->ct);
892 }
893 }
894
895 if ((extl == 3 && !casecmp(ext, cast_uchar "jpg", 3)) ||
896 (extl == 4 && !casecmp(ext, cast_uchar "pjpg", 4))||
897 (extl == 4 && !casecmp(ext, cast_uchar "jpeg", 4))||
898 (extl == 5 && !casecmp(ext, cast_uchar "pjpeg", 5))) return stracpy(cast_uchar "image/jpeg");
899 if ((extl == 3 && !casecmp(ext, cast_uchar "png", 3))) return stracpy(cast_uchar "image/png");
900 if ((extl == 3 && !casecmp(ext, cast_uchar "gif", 3))) return stracpy(cast_uchar "image/gif");
901 if ((extl == 3 && !casecmp(ext, cast_uchar "xbm", 3))) return stracpy(cast_uchar "image/x-xbitmap");
902 if ((extl == 3 && !casecmp(ext, cast_uchar "tif", 3)) ||
903 (extl == 4 && !casecmp(ext, cast_uchar "tiff", 4))) return stracpy(cast_uchar "image/tiff");
904 exxt = init_str(); el = 0;
905 add_to_str(&exxt, &el, cast_uchar "application/x-");
906 add_bytes_to_str(&exxt, &el, ext, extl);
907 foreach(struct list, l, ll, assoc.list_entry) {
908 struct assoc *a = get_struct(l, struct assoc, head);
909 if (is_in_list(a->ct, exxt, el))
910 return exxt;
911 }
912 mem_free(exxt);
913 return NULL;
914 }
915
get_content_type_by_header_and_extension(unsigned char * head,unsigned char * url)916 static unsigned char *get_content_type_by_header_and_extension(unsigned char *head, unsigned char *url)
917 {
918 unsigned char *ct, *file;
919 ct = get_content_type_by_extension(url);
920 if (ct) return ct;
921 file = get_filename_from_header(head);
922 if (file) {
923 ct = get_content_type_by_extension(file);
924 mem_free(file);
925 if (ct) return ct;
926 }
927 return NULL;
928 }
929
get_extension_by_content_type(unsigned char * ct)930 static unsigned char *get_extension_by_content_type(unsigned char *ct)
931 {
932 struct list *l;
933 struct list_head *ll;
934 unsigned char *x, *y;
935 if (is_html_type(ct)) return stracpy(cast_uchar "html");
936 foreach(struct list, l, ll, extensions.list_entry) {
937 struct extension *e = get_struct(l, struct extension, head);
938 if (!casestrcmp(e->ct, ct)) {
939 x = stracpy(e->ext);
940 if ((y = cast_uchar strchr(cast_const_char x, ','))) *y = 0;
941 return x;
942 }
943 }
944 if (!casestrcmp(ct, cast_uchar "image/jpeg") ||
945 !casestrcmp(ct, cast_uchar "image/jpg") ||
946 !casestrcmp(ct, cast_uchar "image/jpe") ||
947 !casestrcmp(ct, cast_uchar "image/pjpe") ||
948 !casestrcmp(ct, cast_uchar "image/pjpeg") ||
949 !casestrcmp(ct, cast_uchar "image/pjpg"))
950 return stracpy(cast_uchar "jpg");
951 if (!casestrcmp(ct, cast_uchar "image/png") ||
952 !casestrcmp(ct, cast_uchar "image/x-png"))
953 return stracpy(cast_uchar "png");
954 if (!casestrcmp(ct, cast_uchar "image/gif"))
955 return stracpy(cast_uchar "gif");
956 if (!casestrcmp(ct, cast_uchar "image/x-bitmap"))
957 return stracpy(cast_uchar "xbm");
958 if (!casestrcmp(ct, cast_uchar "image/tiff") ||
959 !casestrcmp(ct, cast_uchar "image/tif"))
960 return stracpy(cast_uchar "tiff");
961 if (!casestrcmp(ct, cast_uchar "image/svg") ||
962 !casestrcmp(ct, cast_uchar "image/svg+xml"))
963 return stracpy(cast_uchar "svg");
964 if (!cmpbeg(ct, cast_uchar "application/x-")) {
965 x = ct + strlen("application/x-");
966 if (casestrcmp(x, cast_uchar "z") &&
967 casestrcmp(x, cast_uchar "gz") &&
968 casestrcmp(x, cast_uchar "gzip") &&
969 casestrcmp(x, cast_uchar "br") &&
970 casestrcmp(x, cast_uchar "zst") &&
971 casestrcmp(x, cast_uchar "bz2") &&
972 casestrcmp(x, cast_uchar "bzip2") &&
973 casestrcmp(x, cast_uchar "lzma") &&
974 casestrcmp(x, cast_uchar "lzma2") &&
975 casestrcmp(x, cast_uchar "xz") &&
976 casestrcmp(x, cast_uchar "lz") &&
977 !strchr(cast_const_char x, '-') &&
978 strlen(cast_const_char x) <= 4) {
979 return stracpy(x);
980 }
981 }
982 return NULL;
983 }
984
get_content_encoding_from_content_type(unsigned char * ct)985 static unsigned char *get_content_encoding_from_content_type(unsigned char *ct)
986 {
987 if (!casestrcmp(ct, cast_uchar "application/x-gzip") ||
988 !casestrcmp(ct, cast_uchar "application/x-tgz") ||
989 !casestrcmp(ct, cast_uchar "application/x-gtar")) return cast_uchar "gzip";
990 if (!casestrcmp(ct, cast_uchar "application/x-br")) return cast_uchar "br";
991 if (!casestrcmp(ct, cast_uchar "application/x-zstd") ||
992 !casestrcmp(ct, cast_uchar "application/zstd")) return cast_uchar "zstd";
993 if (!casestrcmp(ct, cast_uchar "application/x-bzip2") ||
994 !casestrcmp(ct, cast_uchar "application/x-bzip")) return cast_uchar "bzip2";
995 if (!casestrcmp(ct, cast_uchar "application/x-lzma")) return cast_uchar "lzma";
996 if (!casestrcmp(ct, cast_uchar "application/x-lzma2") ||
997 !casestrcmp(ct, cast_uchar "application/x-xz")) return cast_uchar "lzma2";
998 if (!casestrcmp(ct, cast_uchar "application/x-lz") ||
999 !casestrcmp(ct, cast_uchar "application/x-lzip")) return cast_uchar "lzip";
1000 return NULL;
1001 }
1002
get_content_type(unsigned char * head,unsigned char * url)1003 unsigned char *get_content_type(unsigned char *head, unsigned char *url)
1004 {
1005 unsigned char *ct;
1006 int code;
1007 if ((ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) {
1008 unsigned char *s;
1009 if ((s = cast_uchar strchr(cast_const_char ct, ';'))) *s = 0;
1010 while (*ct && ct[strlen(cast_const_char ct) - 1] <= ' ') ct[strlen(cast_const_char ct) - 1] = 0;
1011 if (*ct == '"' && ct[1] && ct[strlen(cast_const_char ct) - 1] == '"') {
1012 memmove(ct, ct + 1, strlen(cast_const_char ct));
1013 ct[strlen(cast_const_char ct) - 1] = 0;
1014 }
1015 if (!casestrcmp(ct, cast_uchar "text/plain") ||
1016 !casestrcmp(ct, cast_uchar "application/octet-stream") ||
1017 !casestrcmp(ct, cast_uchar "application/octetstream") ||
1018 !casestrcmp(ct, cast_uchar "application/octet_stream") ||
1019 !casestrcmp(ct, cast_uchar "application/binary") ||
1020 !casestrcmp(ct, cast_uchar "application/x-www-form-urlencoded") ||
1021 get_content_encoding_from_content_type(ct)) {
1022 unsigned char *ctt;
1023 if (!get_http_code(head, &code, NULL) && code >= 300)
1024 goto no_code_by_extension;
1025 ctt = get_content_type_by_header_and_extension(head, url);
1026 if (ctt) {
1027 mem_free(ct);
1028 return ctt;
1029 }
1030 }
1031 no_code_by_extension:
1032 if (!*ct) mem_free(ct);
1033 else return ct;
1034 }
1035 if (!get_http_code(head, &code, NULL) && code >= 300)
1036 return stracpy(cast_uchar "text/html");
1037 ct = get_content_type_by_header_and_extension(head, url);
1038 if (ct) return ct;
1039 return !force_html ? stracpy(cast_uchar "text/plain") : stracpy(cast_uchar "text/html");
1040 }
1041
get_content_encoding(unsigned char * head,unsigned char * url,int just_ce)1042 unsigned char *get_content_encoding(unsigned char *head, unsigned char *url, int just_ce)
1043 {
1044 unsigned char *ce, *ct, *ext, *extd;
1045 unsigned char *u;
1046 int code;
1047 if ((ce = parse_http_header(head, cast_uchar "Content-Encoding", NULL))) return ce;
1048 if (just_ce) return NULL;
1049 if ((ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) {
1050 unsigned char *s;
1051 if ((s = cast_uchar strchr(cast_const_char ct, ';'))) *s = 0;
1052 ce = get_content_encoding_from_content_type(ct);
1053 if (ce) {
1054 mem_free(ct);
1055 return stracpy(ce);
1056 }
1057 if (is_html_type(ct)) {
1058 mem_free(ct);
1059 return NULL;
1060 }
1061 mem_free(ct);
1062 }
1063 if (!get_http_code(head, &code, NULL) && code >= 300) return NULL;
1064 if (!(ext = get_url_data(url))) ext = url;
1065 for (u = ext; *u; u++) if (end_of_dir(url, *u)) goto skip_ext;
1066 extd = cast_uchar strrchr(cast_const_char ext, '.');
1067 if (extd) {
1068 ce = get_compress_by_extension(extd + 1, cast_uchar strchr(cast_const_char(extd + 1), 0));
1069 if (ce) return stracpy(ce);
1070 }
1071 skip_ext:
1072 if ((ext = get_filename_from_header(head))) {
1073 extd = cast_uchar strrchr(cast_const_char ext, '.');
1074 if (extd) {
1075 ce = get_compress_by_extension(extd + 1, cast_uchar strchr(cast_const_char(extd + 1), 0));
1076 if (ce) {
1077 mem_free(ext);
1078 return stracpy(ce);
1079 }
1080 }
1081 mem_free(ext);
1082 }
1083 return NULL;
1084 }
1085
encoding_2_extension(unsigned char * encoding)1086 unsigned char *encoding_2_extension(unsigned char *encoding)
1087 {
1088 if (!casestrcmp(encoding, cast_uchar "gzip") ||
1089 !casestrcmp(encoding, cast_uchar "x-gzip")) return cast_uchar "gz";
1090 if (!casestrcmp(encoding, cast_uchar "compress") ||
1091 !casestrcmp(encoding, cast_uchar "x-compress")) return cast_uchar "Z";
1092 if (!casestrcmp(encoding, cast_uchar "br")) return cast_uchar "br";
1093 if (!casestrcmp(encoding, cast_uchar "zstd")) return cast_uchar "zst";
1094 if (!casestrcmp(encoding, cast_uchar "bzip2")) return cast_uchar "bz2";
1095 if (!casestrcmp(encoding, cast_uchar "lzma")) return cast_uchar "lzma";
1096 if (!casestrcmp(encoding, cast_uchar "lzma2")) return cast_uchar "xz";
1097 if (!casestrcmp(encoding, cast_uchar "lzip")) return cast_uchar "lz";
1098 return NULL;
1099 }
1100
1101 /* returns field with associations */
get_type_assoc(struct terminal * term,unsigned char * type,int * n)1102 struct assoc *get_type_assoc(struct terminal *term, unsigned char *type, int *n)
1103 {
1104 struct assoc *assoc_array;
1105 struct list *l;
1106 struct list_head *ll;
1107 int count=0;
1108 foreach(struct list, l, ll, assoc.list_entry) {
1109 struct assoc *a = get_struct(l, struct assoc, head);
1110 if (a->system == SYSTEM_ID && (term->environment & ENV_XWIN ? a->xwin : a->cons) && is_in_list(a->ct, type, (int)strlen(cast_const_char type))) {
1111 if (count == MAXINT) overalloc();
1112 count++;
1113 }
1114 }
1115 *n = count;
1116 if (!count) return NULL;
1117 if ((unsigned)count > MAXINT / sizeof(struct assoc)) overalloc();
1118 assoc_array = mem_alloc(count * sizeof(struct assoc));
1119 count = 0;
1120 foreach(struct list, l, ll, assoc.list_entry) {
1121 struct assoc *a = get_struct(l, struct assoc, head);
1122 if (a->system == SYSTEM_ID && (term->environment & ENV_XWIN ? a->xwin : a->cons) && is_in_list(a->ct, type, (int)strlen(cast_const_char type))) {
1123 assoc_array[count++] = *a;
1124 }
1125 }
1126 return assoc_array;
1127 }
1128
is_html_type(unsigned char * ct)1129 int is_html_type(unsigned char *ct)
1130 {
1131 return !casestrcmp(ct, cast_uchar "text/html") ||
1132 !casestrcmp(ct, cast_uchar "text-html") ||
1133 !casestrcmp(ct, cast_uchar "text/x-server-parsed-html") ||
1134 !casestrcmp(ct, cast_uchar "text/xml") ||
1135 !casecmp(ct, cast_uchar "application/xhtml", strlen("application/xhtml"));
1136 }
1137
get_filename_from_header(unsigned char * head)1138 unsigned char *get_filename_from_header(unsigned char *head)
1139 {
1140 int extended = 0;
1141 unsigned char *ct, *x, *y, *codepage;
1142 int ly;
1143 int cp_idx;
1144 if ((ct = parse_http_header(head, cast_uchar "Content-Disposition", NULL))) {
1145 x = parse_header_param(ct, cast_uchar "filename*", 1);
1146 if (x) extended = 1;
1147 else x = parse_header_param(ct, cast_uchar "filename", 1);
1148 mem_free(ct);
1149 if (x) {
1150 if (*x) goto ret_x;
1151 mem_free(x);
1152 }
1153 }
1154 if ((ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) {
1155 x = parse_header_param(ct, cast_uchar "name*", 0);
1156 if (x) extended = 1;
1157 else x = parse_header_param(ct, cast_uchar "name", 0);
1158 mem_free(ct);
1159 if (x) {
1160 if (*x) goto ret_x;
1161 mem_free(x);
1162 }
1163 }
1164 return NULL;
1165 ret_x:
1166 codepage = NULL;
1167 if (extended) {
1168 unsigned char *ap1, *ap2;
1169 ap1 = cast_uchar strchr(cast_const_char x, '\'');
1170 if (!ap1)
1171 goto no_extended;
1172 ap2 = cast_uchar strchr(cast_const_char (ap1 + 1), '\'');
1173 if (ap2) ap2++;
1174 else ap2 = ap1 + 1;
1175 codepage = memacpy(x, ap1 - x);
1176 memmove(x, ap2, strlen(cast_const_char ap2) + 1);
1177 }
1178
1179 no_extended:
1180 y = init_str();
1181 ly = 0;
1182 add_conv_str(&y, &ly, x, (int)strlen(cast_const_char x), -2);
1183 mem_free(x);
1184 x = y;
1185
1186 cp_idx = -1;
1187 if (codepage) {
1188 cp_idx = get_cp_index(codepage);
1189 mem_free(codepage);
1190 }
1191 if (cp_idx < 0) {
1192 cp_idx = get_cp_index(cast_uchar "iso-8859-1");
1193 if (cp_idx < 0) cp_idx = 0;
1194 }
1195 y = convert(cp_idx, 0, x, NULL);
1196 mem_free(x);
1197 x = y;
1198
1199 for (y = x; *y; y++) if (dir_sep(*y)
1200 #if defined(DOS_FS) || defined(SPAD)
1201 || *y == ':'
1202 #endif
1203 ) *y = '-';
1204 return x;
1205 }
1206
get_filename_from_url(unsigned char * url,unsigned char * head,int tmp)1207 unsigned char *get_filename_from_url(unsigned char *url, unsigned char *head, int tmp)
1208 {
1209 int ll = 0;
1210 unsigned char *u, *s, *e, *f, *x, *ww;
1211 unsigned char *ct, *want_ext;
1212 if (!casecmp(url, cast_uchar "data:", 5)) {
1213 url = cast_uchar "data:/data";
1214 }
1215 want_ext = stracpy(cast_uchar "");
1216 f = get_filename_from_header(head);
1217 if (f) {
1218 goto no_ct;
1219 }
1220 if (!(u = get_url_data(url))) u = url;
1221 for (e = s = u; *e && !end_of_dir(url, *e); e++) {
1222 if (dir_sep(*e)) s = e + 1;
1223 }
1224 ll = 0;
1225 f = init_str();
1226 add_conv_str(&f, &ll, s, (int)(e - s), -2);
1227 if (!(ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) goto no_ct;
1228 mem_free(ct);
1229 ct = get_content_type(head, url);
1230 if (ct) {
1231 x = get_extension_by_content_type(ct);
1232 if (x) {
1233 add_to_strn(&want_ext, cast_uchar ".");
1234 add_to_strn(&want_ext, x);
1235 mem_free(x);
1236 }
1237 mem_free(ct);
1238 }
1239 no_ct:
1240 if (!*want_ext) {
1241 x = cast_uchar strrchr(cast_const_char f, '.');
1242 if (x) {
1243 mem_free(want_ext);
1244 want_ext = stracpy(x);
1245 }
1246 }
1247 ct = get_content_encoding(head, url, 0);
1248 if (ct) {
1249 x = encoding_2_extension(ct);
1250 if (!tmp) {
1251 unsigned char *ct1;
1252 ct1 = get_content_encoding(head, url, 1);
1253 if (ct1) {
1254 mem_free(ct1);
1255 } else if (x) {
1256 unsigned char *w = cast_uchar strrchr(cast_const_char want_ext, '.');
1257 if (w && (ww = canonical_compressed_ext(w + 1, NULL)) && !casestrcmp(x, ww))
1258 goto skip_want_ext;
1259 if (w && !casestrcmp(w + 1, x))
1260 goto skip_want_ext;
1261 add_to_strn(&want_ext, cast_uchar ".");
1262 add_to_strn(&want_ext, x);
1263 skip_want_ext:;
1264 }
1265 } else {
1266 if (x) {
1267 if (strlen(cast_const_char x) + 1 < strlen(cast_const_char f) && f[strlen(cast_const_char f) - strlen(cast_const_char x) - 1] == '.' && !casestrcmp(f + strlen(cast_const_char f) - strlen(cast_const_char x), x)) {
1268 f[strlen(cast_const_char f) - strlen(cast_const_char x) - 1] = 0;
1269 }
1270 }
1271 }
1272 mem_free(ct);
1273 }
1274 if (strlen(cast_const_char want_ext) > strlen(cast_const_char f) || casestrcmp(want_ext, f + strlen(cast_const_char f) - strlen(cast_const_char want_ext))) {
1275 x = cast_uchar strrchr(cast_const_char f, '.');
1276 if (x && (ww = canonical_compressed_ext(x + 1, NULL)) && want_ext[0] == '.' && !casestrcmp(want_ext + 1, ww))
1277 goto skip_tgz_2;
1278 if (x) *x = 0;
1279 add_to_strn(&f, want_ext);
1280 skip_tgz_2:;
1281 }
1282 mem_free(want_ext);
1283 return f;
1284 }
1285
free_prog_list(struct list_head * l)1286 static void free_prog_list(struct list_head *l)
1287 {
1288 struct list_head *lp;
1289 struct protocol_program *p;
1290 foreach(struct protocol_program, p, lp, *l)
1291 mem_free(p->prog);
1292 free_list(struct protocol_program, *l);
1293 }
1294
free_types(void)1295 void free_types(void)
1296 {
1297 struct list *l;
1298 struct list_head *ll;
1299 foreach(struct list, l, ll, assoc.list_entry) {
1300 struct assoc *a = get_struct(l, struct assoc, head);
1301 mem_free(a->ct);
1302 mem_free(a->prog);
1303 mem_free(a->label);
1304 ll = ll->prev;
1305 del_from_list(&a->head);
1306 mem_free(a);
1307 }
1308 foreach(struct list, l, ll, extensions.list_entry) {
1309 struct extension *e = get_struct(l, struct extension, head);
1310 mem_free(e->ext);
1311 mem_free(e->ct);
1312 ll = ll->prev;
1313 del_from_list(&e->head);
1314 mem_free(e);
1315 }
1316 free_prog_list(&mailto_prog);
1317 free_prog_list(&telnet_prog);
1318 free_prog_list(&tn3270_prog);
1319 free_prog_list(&mms_prog);
1320 free_prog_list(&magnet_prog);
1321
1322 free_history(ext_search_history);
1323 free_history(assoc_search_history);
1324 }
1325
1326