links/types.c
2023-04-06 20:18:18 +03:00

1334 lines
44 KiB
C

/* types.c
* (c) 2002 Mikulas Patocka
* This file is a part of the Links program, released under GPL.
*/
#include "links.h"
/*------------------------ ASSOCIATIONS -----------------------*/
/* DECLARATIONS */
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);
static void assoc_copy_item(struct list *, struct list *);
static struct list *assoc_new_item(void *);
static void assoc_delete_item(struct list *);
static struct list *assoc_find_item(struct list *start, unsigned char *str, int direction);
static unsigned char *assoc_type_item(struct terminal *, struct list *, int);
struct list assoc = { init_list_1st(&assoc.list_entry) 0, -1, NULL, init_list_last(&assoc.list_entry) };
static struct history assoc_search_history = { 0, { &assoc_search_history.items, &assoc_search_history.items } };
struct assoc_ok_struct {
void (*fn)(struct dialog_data *, struct list *, struct list *, struct list_description *);
struct list *data;
struct dialog_data *dlg;
};
static struct list_description assoc_ld={
0, /* 0= flat; 1=tree */
&assoc, /* list */
assoc_new_item,
assoc_edit_item,
NULL,
assoc_delete_item,
assoc_copy_item,
assoc_type_item,
assoc_find_item,
&assoc_search_history,
0, /* this is set in init_assoc function */
15, /* # of items in main window */
T_ASSOCIATION,
T_ASSOCIATIONS_ALREADY_IN_USE,
T_ASSOCIATIONS_MANAGER,
T_DELETE_ASSOCIATION,
0, /* no button */
NULL, /* no button */
NULL, /* no save*/
NULL,NULL,0,0, /* internal vars */
0, /* modified */
NULL,
NULL,
1,
};
static struct list *assoc_new_item(void *ignore)
{
struct assoc *neww;
neww = mem_calloc(sizeof(struct assoc));
neww->label = stracpy(cast_uchar "");
neww->ct = stracpy(cast_uchar "");
neww->prog = stracpy(cast_uchar "");
neww->block = neww->xwin = neww->cons = 1;
neww->ask = 1;
neww->accept_http = 0;
neww->accept_ftp = 0;
neww->head.type = 0;
neww->system = SYSTEM_ID;
return &neww->head;
}
static void assoc_delete_item(struct list *data)
{
struct assoc *del = get_struct(data, struct assoc, head);
if (del->head.list_entry.next) del_from_list(&del->head);
mem_free(del->label);
mem_free(del->ct);
mem_free(del->prog);
mem_free(del);
}
static void assoc_copy_item(struct list *in, struct list *out)
{
struct assoc *item_in = get_struct(in, struct assoc, head);
struct assoc *item_out = get_struct(out, struct assoc, head);
item_out->cons = item_in->cons;
item_out->xwin = item_in->xwin;
item_out->block = item_in->block;
item_out->ask = item_in->ask;
item_out->accept_http = item_in->accept_http;
item_out->accept_ftp = item_in->accept_ftp;
item_out->system = item_in->system;
mem_free(item_out->label);
mem_free(item_out->ct);
mem_free(item_out->prog);
item_out->label = stracpy(item_in->label);
item_out->ct = stracpy(item_in->ct);
item_out->prog = stracpy(item_in->prog);
}
/* allocate string and print association into it */
/* x: 0=type all, 1=type title only */
static unsigned char *assoc_type_item(struct terminal *term, struct list *data, int x)
{
unsigned char *txt, *txt1;
struct assoc *item;
if (data == &assoc) return stracpy(get_text_translation(TEXT_(T_ASSOCIATIONS), term));
item = get_struct(data, struct assoc, head);
txt = stracpy(cast_uchar "");
if (item->system != SYSTEM_ID) add_to_strn(&txt, cast_uchar "XX ");
add_to_strn(&txt, item->label);
add_to_strn(&txt, cast_uchar ": ");
add_to_strn(&txt, item->ct);
if (!x) {
add_to_strn(&txt, cast_uchar " -> ");
if (item->prog) add_to_strn(&txt, item->prog);
}
txt1 = convert(assoc_ld.codepage, term_charset(term), txt, NULL);
mem_free(txt);
return txt1;
}
void menu_assoc_manager(struct terminal *term, void *fcp, void *ses_)
{
struct session *ses = (struct session *)ses_;
create_list_window(&assoc_ld,&assoc, term, ses);
}
static unsigned char * const ct_msg[] = {
TEXT_(T_LABEL),
TEXT_(T_CONTENT_TYPES),
TEXT_(T_PROGRAM__IS_REPLACED_WITH_FILE_NAME),
#ifdef ASSOC_BLOCK
TEXT_(T_BLOCK_TERMINAL_WHILE_PROGRAM_RUNNING),
#endif
#ifdef ASSOC_CONS_XWIN
TEXT_(T_RUN_ON_TERMINAL),
TEXT_(T_RUN_IN_XWINDOW),
#endif
TEXT_(T_ASK_BEFORE_OPENING),
TEXT_(T_ACCEPT_HTTP),
TEXT_(T_ACCEPT_FTP),
};
static void assoc_edit_item_fn(struct dialog_data *dlg)
{
struct terminal *term = dlg->win->term;
int max = 0, min = 0;
int w, rw;
int y = gf_val(-1, -G_BFU_FONT_SIZE);
int p = 3;
if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
#ifdef ASSOC_BLOCK
p++;
#endif
#ifdef ASSOC_CONS_XWIN
p += 2;
#endif
max_text_width(term, ct_msg[0], &max, AL_LEFT);
min_text_width(term, ct_msg[0], &min, AL_LEFT);
max_text_width(term, ct_msg[1], &max, AL_LEFT);
min_text_width(term, ct_msg[1], &min, AL_LEFT);
max_text_width(term, ct_msg[2], &max, AL_LEFT);
min_text_width(term, ct_msg[2], &min, AL_LEFT);
max_group_width(term, ct_msg + 3, dlg->items + 3, p, &max);
min_group_width(term, ct_msg + 3, dlg->items + 3, p, &min);
max_buttons_width(term, dlg->items + 3 + p, 2, &max);
min_buttons_width(term, dlg->items + 3 + p, 2, &min);
w = term->x * 9 / 10 - 2 * DIALOG_LB;
if (w > max) w = max;
if (w < min) w = min;
if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
if (w < 1) w = 1;
rw = 0;
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);
y += gf_val(1, G_BFU_FONT_SIZE * 1);
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);
y += gf_val(1, G_BFU_FONT_SIZE * 1);
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);
y += gf_val(1, G_BFU_FONT_SIZE * 1);
dlg_format_group(dlg, NULL, ct_msg + 3, dlg->items + 3, p, 0, &y, w, &rw);
y += gf_val(1, G_BFU_FONT_SIZE);
dlg_format_buttons(dlg, NULL, dlg->items + 3 + p, 2, 0, &y, w, &rw, AL_CENTER);
w = rw;
dlg->xw = w + 2 * DIALOG_LB;
dlg->yw = y + 2 * DIALOG_TB;
center_dlg(dlg);
draw_dlg(dlg);
y = dlg->y + DIALOG_TB;
if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
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);
y += gf_val(1, G_BFU_FONT_SIZE);
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);
y += gf_val(1, G_BFU_FONT_SIZE);
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);
y += gf_val(1, G_BFU_FONT_SIZE);
dlg_format_group(dlg, term, ct_msg + 3, &dlg->items[3], p, dlg->x + DIALOG_LB, &y, w, NULL);
y += gf_val(1, G_BFU_FONT_SIZE);
dlg_format_buttons(dlg, term, &dlg->items[3 + p], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
}
/* Puts url and title into the bookmark item */
static void assoc_edit_done(void *data)
{
struct dialog *d = (struct dialog *)data;
struct assoc *item = (struct assoc *)d->udata;
struct assoc_ok_struct *s = (struct assoc_ok_struct *)d->udata2;
unsigned char *txt;
unsigned char *label, *ct, *prog;
label = (unsigned char *)&d->items[12];
ct = label + MAX_STR_LEN;
prog = ct + MAX_STR_LEN;
txt = convert(term_charset(s->dlg->win->term), assoc_ld.codepage, label, NULL);
mem_free(item->label);
item->label = txt;
txt = convert(term_charset(s->dlg->win->term), assoc_ld.codepage, ct, NULL);
mem_free(item->ct);
item->ct = txt;
txt = convert(term_charset(s->dlg->win->term), assoc_ld.codepage, prog, NULL);
mem_free(item->prog);
item->prog = txt;
s->fn(s->dlg, s->data, &item->head, &assoc_ld);
d->udata = NULL; /* for abort function */
}
/* destroys an item, this function is called when edit window is aborted */
static void assoc_edit_abort(struct dialog_data *data)
{
struct dialog *dlg = data->dlg;
struct assoc *item = (struct assoc *)dlg->udata;
mem_free(dlg->udata2);
if (item) assoc_delete_item(&item->head);
}
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)
{
int p;
struct assoc *neww = get_struct(data, struct assoc, head);
struct terminal *term = dlg->win->term;
struct dialog *d;
struct assoc_ok_struct *s;
unsigned char *ct, *prog, *label;
d = mem_calloc(sizeof(struct dialog) + 11 * sizeof(struct dialog_item) + 3 * MAX_STR_LEN);
label = (unsigned char *)&d->items[12];
ct = label + MAX_STR_LEN;
prog = ct + MAX_STR_LEN;
safe_strncpy(label, neww->label, MAX_STR_LEN);
safe_strncpy(ct, neww->ct, MAX_STR_LEN);
safe_strncpy(prog, neww->prog, MAX_STR_LEN);
/* Create the dialog */
s = mem_alloc(sizeof(struct assoc_ok_struct));
s->fn = ok_fn;
s->data = ok_arg;
s->dlg = dlg;
switch (dlg_title) {
case TITLE_EDIT:
d->title = TEXT_(T_EDIT_ASSOCIATION);
break;
case TITLE_ADD:
d->title = TEXT_(T_ADD_ASSOCIATION);
break;
default:
internal_error("Unsupported dialog title.\n");
}
d->udata = neww;
d->udata2 = s;
d->fn = assoc_edit_item_fn;
d->abort = assoc_edit_abort;
d->refresh = assoc_edit_done;
d->refresh_data = d;
d->items[0].type = D_FIELD;
d->items[0].dlen = MAX_STR_LEN;
d->items[0].data = label;
d->items[0].fn = check_nonempty;
d->items[1].type = D_FIELD;
d->items[1].dlen = MAX_STR_LEN;
d->items[1].data = ct;
d->items[1].fn = check_nonempty;
d->items[2].type = D_FIELD;
d->items[2].dlen = MAX_STR_LEN;
d->items[2].data = prog;
d->items[2].fn = check_nonempty;
p = 3;
#ifdef ASSOC_BLOCK
d->items[p].type = D_CHECKBOX;
d->items[p].data = (unsigned char *)&neww->block;
d->items[p++].dlen = sizeof(int);
#endif
#ifdef ASSOC_CONS_XWIN
d->items[p].type = D_CHECKBOX;
d->items[p].data = (unsigned char *)&neww->cons;
d->items[p++].dlen = sizeof(int);
d->items[p].type = D_CHECKBOX;
d->items[p].data = (unsigned char *)&neww->xwin;
d->items[p++].dlen = sizeof(int);
#endif
d->items[p].type = D_CHECKBOX;
d->items[p].data = (unsigned char *)&neww->ask;
d->items[p++].dlen = sizeof(int);
d->items[p].type = D_CHECKBOX;
d->items[p].data = (unsigned char *)&neww->accept_http;
d->items[p++].dlen = sizeof(int);
d->items[p].type = D_CHECKBOX;
d->items[p].data = (unsigned char *)&neww->accept_ftp;
d->items[p++].dlen = sizeof(int);
d->items[p].type = D_BUTTON;
d->items[p].gid = B_ENTER;
d->items[p].fn = ok_dialog;
d->items[p++].text = TEXT_(T_OK);
d->items[p].type = D_BUTTON;
d->items[p].gid = B_ESC;
d->items[p].text = TEXT_(T_CANCEL);
d->items[p++].fn = cancel_dialog;
d->items[p++].type = D_END;
do_dialog(term, d, getml(d, NULL));
}
static int assoc_test_entry(struct list *e, unsigned char *str)
{
struct assoc *a = get_struct(e, struct assoc, head);
return casestrstr(a->label, str) || casestrstr(a->ct, str);
}
static struct list *assoc_find_item(struct list *s, unsigned char *str, int direction)
{
struct list *e;
if (direction >= 0) {
for (e = list_next(s); e != s; e = list_next(e)) {
if (e->depth >= 0 && assoc_test_entry(e, str))
return e;
}
} else {
for (e = list_prev(s); e != s; e = list_prev(e)) {
if (e->depth >= 0 && assoc_test_entry(e, str))
return e;
}
}
if (e->depth >= 0 && assoc_test_entry(e, str))
return e;
return NULL;
}
void update_assoc(struct assoc *neww)
{
struct assoc *repl;
struct list *r;
struct list_head *lr;
if (!neww->label[0] || !neww->ct[0] || !neww->prog[0]) return;
foreach(struct list, r, lr, assoc.list_entry) {
repl = get_struct(r, struct assoc, head);
if (!strcmp(cast_const_char repl->label, cast_const_char neww->label)
&& !strcmp(cast_const_char repl->ct, cast_const_char neww->ct)
&& !strcmp(cast_const_char repl->prog, cast_const_char neww->prog)
&& repl->block == neww->block
&& repl->cons == neww->cons
&& repl->xwin == neww->xwin
&& repl->ask == neww->ask
&& repl->accept_http == neww->accept_http
&& repl->accept_ftp == neww->accept_ftp
&& repl->system == neww->system) {
del_from_list(&repl->head);
add_to_list(assoc.list_entry, &repl->head);
return;
}
}
repl = mem_calloc(sizeof(struct assoc));
repl->label = stracpy(neww->label);
repl->ct = stracpy(neww->ct);
repl->prog = stracpy(neww->prog);
repl->block = neww->block;
repl->cons = neww->cons;
repl->xwin = neww->xwin;
repl->ask = neww->ask;
repl->accept_http = neww->accept_http;
repl->accept_ftp = neww->accept_ftp;
repl->system = neww->system;
repl->head.type = 0;
add_to_list(assoc.list_entry, &repl->head);
}
/*------------------------ EXTENSIONS -----------------------*/
/* DECLARATIONS */
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);
static void ext_copy_item(struct list *, struct list *);
static struct list *ext_new_item(void *);
static void ext_delete_item(struct list *);
static struct list *ext_find_item(struct list *start, unsigned char *str, int direction);
static unsigned char *ext_type_item(struct terminal *, struct list *, int);
struct list extensions = { init_list_1st(&extensions.list_entry) 0, -1, NULL, init_list_last(&extensions.list_entry) };
static struct history ext_search_history = { 0, { &ext_search_history.items, &ext_search_history.items } };
static struct list_description ext_ld={
0, /* 0= flat; 1=tree */
&extensions, /* list */
ext_new_item,
ext_edit_item,
NULL,
ext_delete_item,
ext_copy_item,
ext_type_item,
ext_find_item,
&ext_search_history,
0, /* this is set in init_assoc function */
15, /* # of items in main window */
T_eXTENSION,
T_EXTENSIONS_ALREADY_IN_USE,
T_EXTENSIONS_MANAGER,
T_DELETE_EXTENSION,
0, /* no button */
NULL, /* no button */
NULL, /* no save*/
NULL,NULL,0,0, /* internal vars */
0, /* modified */
NULL,
NULL,
0,
};
static struct list *ext_new_item(void *ignore)
{
struct extension *neww;
neww = mem_calloc(sizeof(struct extension));
neww->ext = stracpy(cast_uchar "");
neww->ct = stracpy(cast_uchar "");
neww->head.type = 0;
return &neww->head;
}
static void ext_delete_item(struct list *data)
{
struct extension *del = get_struct(data, struct extension, head);
if (del->head.list_entry.next) del_from_list(&del->head);
if (del->ext) mem_free(del->ext);
if (del->ct) mem_free(del->ct);
mem_free(del);
}
static void ext_copy_item(struct list *in, struct list *out)
{
struct extension *item_in = get_struct(in, struct extension, head);
struct extension *item_out = get_struct(out, struct extension, head);
mem_free(item_out->ext);
mem_free(item_out->ct);
item_out->ext = stracpy(item_in->ext);
item_out->ct = stracpy(item_in->ct);
}
/* allocate string and print extension into it */
/* x: 0=type all, 1=type title only */
static unsigned char *ext_type_item(struct terminal *term, struct list *data, int x)
{
unsigned char *txt, *txt1;
struct extension *item;
if (data == &extensions) return stracpy(get_text_translation(TEXT_(T_FILE_EXTENSIONS), term));
item = get_struct(data, struct extension, head);
txt = stracpy(item->ext);
add_to_strn(&txt, cast_uchar ": ");
add_to_strn(&txt, item->ct);
txt1 = convert(assoc_ld.codepage, term_charset(term), txt, NULL);
mem_free(txt);
return txt1;
}
void menu_ext_manager(struct terminal *term, void *fcp, void *ses_)
{
struct session *ses = (struct session *)ses_;
create_list_window(&ext_ld, &extensions, term, ses);
}
static unsigned char * const ext_msg[] = {
TEXT_(T_EXTENSION_S),
TEXT_(T_CONTENT_TYPE),
};
static void ext_edit_item_fn(struct dialog_data *dlg)
{
struct terminal *term = dlg->win->term;
int max = 0, min = 0;
int w, rw;
int y = gf_val(-1, -G_BFU_FONT_SIZE);
if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
max_text_width(term, ext_msg[0], &max, AL_LEFT);
min_text_width(term, ext_msg[0], &min, AL_LEFT);
max_text_width(term, ext_msg[1], &max, AL_LEFT);
min_text_width(term, ext_msg[1], &min, AL_LEFT);
max_buttons_width(term, dlg->items + 2, 2, &max);
min_buttons_width(term, dlg->items + 2, 2, &min);
w = term->x * 9 / 10 - 2 * DIALOG_LB;
if (w > max) w = max;
if (w < min) w = min;
if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
if (w < 1) w = 1;
rw = 0;
dlg_format_text_and_field(dlg, NULL, ext_msg[0], &dlg->items[0], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
y += gf_val(1, G_BFU_FONT_SIZE * 1);
dlg_format_text_and_field(dlg, NULL, ext_msg[1], &dlg->items[1], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
y += gf_val(1, G_BFU_FONT_SIZE * 1);
dlg_format_buttons(dlg, NULL, dlg->items + 2, 2, 0, &y, w, &rw, AL_CENTER);
w = rw;
dlg->xw = w + 2 * DIALOG_LB;
dlg->yw = y + 2 * DIALOG_TB;
center_dlg(dlg);
draw_dlg(dlg);
y = dlg->y + DIALOG_TB;
if (dlg->win->term->spec->braille) y += gf_val(1, G_BFU_FONT_SIZE);
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);
y += gf_val(1, G_BFU_FONT_SIZE);
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);
y += gf_val(1, G_BFU_FONT_SIZE);
dlg_format_buttons(dlg, term, &dlg->items[2], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
}
/* Puts url and title into the bookmark item */
static void ext_edit_done(void *data)
{
struct dialog *d = (struct dialog*)data;
struct extension *item = (struct extension *)d->udata;
struct assoc_ok_struct *s = (struct assoc_ok_struct *)d->udata2;
unsigned char *txt;
unsigned char *ext, *ct;
ext = (unsigned char *)&d->items[5];
ct = ext + MAX_STR_LEN;
txt = convert(term_charset(s->dlg->win->term), ext_ld.codepage,ext, NULL);
mem_free(item->ext);
item->ext = txt;
txt = convert(term_charset(s->dlg->win->term), ext_ld.codepage,ct, NULL);
mem_free(item->ct);
item->ct=txt;
s->fn(s->dlg, s->data, &item->head, &ext_ld);
d->udata = NULL; /* for abort function */
}
/* destroys an item, this function is called when edit window is aborted */
static void ext_edit_abort(struct dialog_data *data)
{
struct dialog *dlg = data->dlg;
struct extension *item = (struct extension *)dlg->udata;
mem_free(dlg->udata2);
if (item) ext_delete_item(&item->head);
}
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)
{
struct extension *neww = get_struct(data, struct extension, head);
struct terminal *term = dlg->win->term;
struct dialog *d;
struct assoc_ok_struct *s;
unsigned char *ext;
unsigned char *ct;
d = mem_calloc(sizeof(struct dialog) + 4 * sizeof(struct dialog_item) + 2 * MAX_STR_LEN);
ext = (unsigned char *)&d->items[5];
ct = ext + MAX_STR_LEN;
safe_strncpy(ext, neww->ext, MAX_STR_LEN);
safe_strncpy(ct, neww->ct, MAX_STR_LEN);
/* Create the dialog */
s = mem_alloc(sizeof(struct assoc_ok_struct));
s->fn = ok_fn;
s->data = ok_arg;
s->dlg = dlg;
switch (dlg_title) {
case TITLE_EDIT:
d->title = TEXT_(T_EDIT_EXTENSION);
break;
case TITLE_ADD:
d->title = TEXT_(T_ADD_EXTENSION);
break;
default:
internal_error("Unsupported dialog title.\n");
}
d->udata = neww;
d->udata2 = s;
d->abort = ext_edit_abort;
d->refresh = ext_edit_done;
d->refresh_data = d;
d->title = TEXT_(T_EXTENSION);
d->fn = ext_edit_item_fn;
d->items[0].type = D_FIELD;
d->items[0].dlen = MAX_STR_LEN;
d->items[0].data = ext;
d->items[0].fn = check_nonempty;
d->items[1].type = D_FIELD;
d->items[1].dlen = MAX_STR_LEN;
d->items[1].data = ct;
d->items[1].fn = check_nonempty;
d->items[2].type = D_BUTTON;
d->items[2].gid = B_ENTER;
d->items[2].fn = ok_dialog;
d->items[2].text = TEXT_(T_OK);
d->items[3].type = D_BUTTON;
d->items[3].gid = B_ESC;
d->items[3].text = TEXT_(T_CANCEL);
d->items[3].fn = cancel_dialog;
d->items[4].type = D_END;
do_dialog(term, d, getml(d, NULL));
}
static int ext_test_entry(struct list *e, unsigned char *str)
{
struct extension *ext = get_struct(e, struct extension, head);
return casestrstr(ext->ext, str) || casestrstr(ext->ct, str);
}
static struct list *ext_find_item(struct list *s, unsigned char *str, int direction)
{
struct list *e;
if (direction >= 0) {
for (e = list_next(s); e != s; e = list_next(e)) {
if (e->depth >= 0 && ext_test_entry(e, str))
return e;
}
} else {
for (e = list_prev(s); e != s; e = list_prev(e)) {
if (e->depth >= 0 && ext_test_entry(e, str))
return e;
}
}
if (e->depth >= 0 && ext_test_entry(e, str))
return e;
return NULL;
}
void update_ext(struct extension *neww)
{
struct extension *repl;
struct list *r;
struct list_head *lr;
if (!neww->ext[0] || !neww->ct[0]) return;
foreach(struct list, r, lr, extensions.list_entry) {
repl = get_struct(r, struct extension, head);
if (!strcmp(cast_const_char repl->ext, cast_const_char neww->ext)
&& !strcmp(cast_const_char repl->ct, cast_const_char neww->ct)) {
del_from_list(&repl->head);
add_to_list(extensions.list_entry, &repl->head);
return;
}
}
repl = mem_calloc(sizeof(struct extension));
repl->ext = stracpy(neww->ext);
repl->ct = stracpy(neww->ct);
repl->head.type = 0;
add_to_list(extensions.list_entry, &repl->head);
}
void update_prog(struct list_head *l, unsigned char *p, int s)
{
struct protocol_program *repl;
struct list_head *lrepl;
foreach(struct protocol_program, repl, lrepl, *l) if (repl->system == s) {
mem_free(repl->prog);
goto ss;
}
repl = mem_alloc(sizeof(struct protocol_program));
add_to_list(*l, repl);
repl->system = s;
ss:
repl->prog = mem_alloc(MAX_STR_LEN);
safe_strncpy(repl->prog, p, MAX_STR_LEN);
}
unsigned char *get_prog(struct list_head *l)
{
struct protocol_program *repl;
struct list_head *lrepl;
foreach(struct protocol_program, repl, lrepl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
update_prog(l, cast_uchar "", SYSTEM_ID);
foreach(struct protocol_program, repl, lrepl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
internal_error("get_prog: program was not added");
return cast_uchar "";;
}
/* creates default extensions if extension list is empty */
void create_initial_extensions(void)
{
struct extension ext;
if (!list_empty(extensions.list_entry)) return;
/* here you can add any default extension you want */
ext.ext = cast_uchar "xpm", ext.ct=cast_uchar "image/x-xpixmap", update_ext(&ext);
ext.ext = cast_uchar "xls", ext.ct=cast_uchar "application/excel", update_ext(&ext);
ext.ext = cast_uchar "xbm", ext.ct=cast_uchar "image/x-xbitmap", update_ext(&ext);
ext.ext = cast_uchar "webp", ext.ct=cast_uchar "image/webp", update_ext(&ext);
ext.ext = cast_uchar "wav", ext.ct=cast_uchar "audio/x-wav", update_ext(&ext);
ext.ext = cast_uchar "tiff,tif", ext.ct=cast_uchar "image/tiff", update_ext(&ext);
ext.ext = cast_uchar "tga", ext.ct=cast_uchar "image/targa", update_ext(&ext);
ext.ext = cast_uchar "sxw", ext.ct=cast_uchar "application/x-openoffice", update_ext(&ext);
ext.ext = cast_uchar "swf", ext.ct=cast_uchar "application/x-shockwave-flash", update_ext(&ext);
ext.ext = cast_uchar "svg", ext.ct=cast_uchar "image/svg+xml", update_ext(&ext);
ext.ext = cast_uchar "sch", ext.ct=cast_uchar "application/gschem", update_ext(&ext);
ext.ext = cast_uchar "rtf", ext.ct=cast_uchar "application/rtf", update_ext(&ext);
ext.ext = cast_uchar "ra,rm,ram", ext.ct=cast_uchar "audio/x-pn-realaudio", update_ext(&ext);
ext.ext = cast_uchar "qt,mov", ext.ct=cast_uchar "video/quicktime", update_ext(&ext);
ext.ext = cast_uchar "ps,eps,ai", ext.ct=cast_uchar "application/postscript", update_ext(&ext);
ext.ext = cast_uchar "ppt", ext.ct=cast_uchar "application/powerpoint", update_ext(&ext);
ext.ext = cast_uchar "ppm", ext.ct=cast_uchar "image/x-portable-pixmap", update_ext(&ext);
ext.ext = cast_uchar "pnm", ext.ct=cast_uchar "image/x-portable-anymap", update_ext(&ext);
ext.ext = cast_uchar "png", ext.ct=cast_uchar "image/png", update_ext(&ext);
ext.ext = cast_uchar "pgp", ext.ct=cast_uchar "application/pgp-signature", update_ext(&ext);
ext.ext = cast_uchar "pgm", ext.ct=cast_uchar "image/x-portable-graymap", update_ext(&ext);
ext.ext = cast_uchar "pdf", ext.ct=cast_uchar "application/pdf", update_ext(&ext);
ext.ext = cast_uchar "pcb", ext.ct=cast_uchar "application/pcb", update_ext(&ext);
ext.ext = cast_uchar "pbm", ext.ct=cast_uchar "image/x-portable-bitmap", update_ext(&ext);
ext.ext = cast_uchar "mpeg,mpg,mpe", ext.ct=cast_uchar "video/mpeg", update_ext(&ext);
ext.ext = cast_uchar "mp3", ext.ct=cast_uchar "audio/mpeg", update_ext(&ext);
ext.ext = cast_uchar "mid,midi", ext.ct=cast_uchar "audio/midi", update_ext(&ext);
ext.ext = cast_uchar "jpg,jpeg,jpe", ext.ct=cast_uchar "image/jpeg", update_ext(&ext);
ext.ext = cast_uchar "grb", ext.ct=cast_uchar "application/gerber", update_ext(&ext);
ext.ext = cast_uchar "gl", ext.ct=cast_uchar "video/gl", update_ext(&ext);
ext.ext = cast_uchar "gif", ext.ct=cast_uchar "image/gif", update_ext(&ext);
ext.ext = cast_uchar "gbr", ext.ct=cast_uchar "application/gerber", update_ext(&ext);
ext.ext = cast_uchar "g", ext.ct=cast_uchar "application/brlcad", update_ext(&ext);
ext.ext = cast_uchar "fli", ext.ct=cast_uchar "video/fli", update_ext(&ext);
ext.ext = cast_uchar "dxf", ext.ct=cast_uchar "application/dxf", update_ext(&ext);
ext.ext = cast_uchar "dvi", ext.ct=cast_uchar "application/x-dvi", update_ext(&ext);
ext.ext = cast_uchar "dl", ext.ct=cast_uchar "video/dl", update_ext(&ext);
ext.ext = cast_uchar "deb", ext.ct=cast_uchar "application/x-debian-package", update_ext(&ext);
ext.ext = cast_uchar "avif", ext.ct=cast_uchar "image/avif", update_ext(&ext);
ext.ext = cast_uchar "avi", ext.ct=cast_uchar "video/x-msvideo", update_ext(&ext);
ext.ext = cast_uchar "au,snd", ext.ct=cast_uchar "audio/basic", update_ext(&ext);
ext.ext = cast_uchar "aif,aiff,aifc", ext.ct=cast_uchar "audio/x-aiff", update_ext(&ext);
}
/* --------------------------- PROG -----------------------------*/
struct list_head mailto_prog = { &mailto_prog, &mailto_prog };
struct list_head telnet_prog = { &telnet_prog, &telnet_prog };
struct list_head tn3270_prog = { &tn3270_prog, &tn3270_prog };
struct list_head mms_prog = { &mms_prog, &mms_prog };
struct list_head magnet_prog = { &magnet_prog, &magnet_prog };
struct list_head gopher_prog = { &gopher_prog, &gopher_prog };
static int is_in_list(unsigned char *list, unsigned char *str, int l)
{
unsigned char *l2, *l3;
if (!l) return 0;
rep:
while (*list && *list <= ' ') list++;
if (!*list) return 0;
for (l2 = list; *l2 && *l2 != ','; l2++)
;
for (l3 = l2 - 1; l3 >= list && *l3 <= ' '; l3--)
;
l3++;
if (l3 - list == l && !casecmp(str, list, l)) return 1;
list = l2;
if (*list == ',') list++;
goto rep;
}
static unsigned char *canonical_compressed_ext(unsigned char *ext, unsigned char *ext_end)
{
size_t len;
if (!ext_end) ext_end = cast_uchar strchr(cast_const_char ext, 0);
len = ext_end - ext;
if (len == 3 && !casecmp(ext, cast_uchar "tgz", 3)) return cast_uchar "gz";
if (len == 3 && !casecmp(ext, cast_uchar "tbz", 3)) return cast_uchar "bz2";
if (len == 3 && !casecmp(ext, cast_uchar "txz", 3)) return cast_uchar "xz";
if (len == 6 && !casecmp(ext, cast_uchar "tar-gz", 3)) return cast_uchar "gz";
if (len == 7 && !casecmp(ext, cast_uchar "tar-bz2", 3)) return cast_uchar "bz2";
if (len == 6 && !casecmp(ext, cast_uchar "tar-xz", 3)) return cast_uchar "xz";
return NULL;
}
unsigned char *get_compress_by_extension(unsigned char *ext, unsigned char *ext_end)
{
size_t len;
unsigned char *x;
if ((x = canonical_compressed_ext(ext, ext_end))) {
ext = x;
ext_end = cast_uchar strchr(cast_const_char x, 0);
}
len = ext_end - ext;
if (len == 1 && !casecmp(ext, cast_uchar "z", 1)) return cast_uchar "compress";
if (len == 2 && !casecmp(ext, cast_uchar "gz", 2)) return cast_uchar "gzip";
if (len == 2 && !casecmp(ext, cast_uchar "br", 2)) return cast_uchar "br";
if (len == 3 && !casecmp(ext, cast_uchar "zst", 3)) return cast_uchar "zstd";
if (len == 3 && !casecmp(ext, cast_uchar "bz2", 3)) return cast_uchar "bzip2";
if (len == 4 && !casecmp(ext, cast_uchar "lzma", 4)) return cast_uchar "lzma";
if (len == 2 && !casecmp(ext, cast_uchar "xz", 2)) return cast_uchar "lzma2";
if (len == 2 && !casecmp(ext, cast_uchar "lz", 2)) return cast_uchar "lzip";
return NULL;
}
unsigned char *get_content_type_by_extension(unsigned char *url)
{
struct list *l;
struct list_head *ll;
unsigned char *ct, *eod, *ext, *exxt;
int extl, el;
ext = NULL, extl = 0;
if (!(ct = get_url_data(url))) ct = url;
for (eod = ct; *eod && !end_of_dir(url, *eod); eod++)
;
for (; ct < eod; ct++)
if (*ct == '.') {
if (ext) {
if (get_compress_by_extension(ct + 1, eod))
break;
}
ext = ct + 1;
} else if (dir_sep(*ct)) {
ext = NULL;
}
if (ext) while (ext[extl] && ext[extl] != '.' && !dir_sep(ext[extl]) && !end_of_dir(url, ext[extl])) extl++;
if ((extl == 3 && !casecmp(ext, cast_uchar "htm", 3)) ||
(extl == 4 && !casecmp(ext, cast_uchar "html", 4)) ||
(extl == 5 && !casecmp(ext, cast_uchar "xhtml", 5))) return stracpy(cast_uchar "text/html");
foreach(struct list, l, ll, extensions.list_entry) {
struct extension *e = get_struct(l, struct extension, head);
unsigned char *fname = NULL;
if (!(ct = get_url_data(url))) ct = url;
for (; *ct && !end_of_dir(url, *ct); ct++)
if (dir_sep(*ct)) fname = ct + 1;
if (!fname) {
if (is_in_list(e->ext, ext, extl)) return stracpy(e->ct);
} else {
int fnlen = 0;
int x;
while (fname[fnlen] && !end_of_dir(url, fname[fnlen])) fnlen++;
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);
}
}
if ((extl == 3 && !casecmp(ext, cast_uchar "jpg", 3)) ||
(extl == 4 && !casecmp(ext, cast_uchar "pjpg", 4))||
(extl == 4 && !casecmp(ext, cast_uchar "jpeg", 4))||
(extl == 5 && !casecmp(ext, cast_uchar "pjpeg", 5))) return stracpy(cast_uchar "image/jpeg");
if ((extl == 3 && !casecmp(ext, cast_uchar "png", 3))) return stracpy(cast_uchar "image/png");
if ((extl == 3 && !casecmp(ext, cast_uchar "gif", 3))) return stracpy(cast_uchar "image/gif");
if ((extl == 3 && !casecmp(ext, cast_uchar "xbm", 3))) return stracpy(cast_uchar "image/x-xbitmap");
if ((extl == 3 && !casecmp(ext, cast_uchar "tif", 3)) ||
(extl == 4 && !casecmp(ext, cast_uchar "tiff", 4))) return stracpy(cast_uchar "image/tiff");
if ((extl == 3 && !casecmp(ext, cast_uchar "svg", 3))) return stracpy(cast_uchar "image/svg+xml");
if ((extl == 4 && !casecmp(ext, cast_uchar "webp", 4))) return stracpy(cast_uchar "image/webp");
if ((extl == 4 && !casecmp(ext, cast_uchar "avif", 4))) return stracpy(cast_uchar "image/avif");
exxt = init_str(); el = 0;
add_to_str(&exxt, &el, cast_uchar "application/x-");
add_bytes_to_str(&exxt, &el, ext, extl);
foreach(struct list, l, ll, assoc.list_entry) {
struct assoc *a = get_struct(l, struct assoc, head);
if (is_in_list(a->ct, exxt, el))
return exxt;
}
mem_free(exxt);
return NULL;
}
static unsigned char *get_content_type_by_header_and_extension(unsigned char *head, unsigned char *url)
{
unsigned char *ct, *file;
ct = get_content_type_by_extension(url);
if (ct) return ct;
file = get_filename_from_header(head);
if (file) {
ct = get_content_type_by_extension(file);
mem_free(file);
if (ct) return ct;
}
return NULL;
}
static unsigned char *get_extension_by_content_type(unsigned char *ct)
{
struct list *l;
struct list_head *ll;
unsigned char *x, *y;
if (is_html_type(ct)) return stracpy(cast_uchar "html");
foreach(struct list, l, ll, extensions.list_entry) {
struct extension *e = get_struct(l, struct extension, head);
if (!casestrcmp(e->ct, ct)) {
x = stracpy(e->ext);
if ((y = cast_uchar strchr(cast_const_char x, ','))) *y = 0;
return x;
}
}
if (!casestrcmp(ct, cast_uchar "image/jpeg") ||
!casestrcmp(ct, cast_uchar "image/jpg") ||
!casestrcmp(ct, cast_uchar "image/jpe") ||
!casestrcmp(ct, cast_uchar "image/pjpe") ||
!casestrcmp(ct, cast_uchar "image/pjpeg") ||
!casestrcmp(ct, cast_uchar "image/pjpg"))
return stracpy(cast_uchar "jpg");
if (!casestrcmp(ct, cast_uchar "image/png") ||
!casestrcmp(ct, cast_uchar "image/x-png"))
return stracpy(cast_uchar "png");
if (!casestrcmp(ct, cast_uchar "image/gif"))
return stracpy(cast_uchar "gif");
if (!casestrcmp(ct, cast_uchar "image/x-bitmap"))
return stracpy(cast_uchar "xbm");
if (!casestrcmp(ct, cast_uchar "image/tiff") ||
!casestrcmp(ct, cast_uchar "image/tif"))
return stracpy(cast_uchar "tiff");
if (!casestrcmp(ct, cast_uchar "image/svg") ||
!casestrcmp(ct, cast_uchar "image/svg+xml"))
return stracpy(cast_uchar "svg");
if (!casestrcmp(ct, cast_uchar "image/webp"))
return stracpy(cast_uchar "webp");
if (!casestrcmp(ct, cast_uchar "image/avif"))
return stracpy(cast_uchar "avif");
if (!cmpbeg(ct, cast_uchar "application/x-")) {
x = ct + strlen("application/x-");
if (casestrcmp(x, cast_uchar "z") &&
casestrcmp(x, cast_uchar "gz") &&
casestrcmp(x, cast_uchar "gzip") &&
casestrcmp(x, cast_uchar "br") &&
casestrcmp(x, cast_uchar "zst") &&
casestrcmp(x, cast_uchar "bz2") &&
casestrcmp(x, cast_uchar "bzip2") &&
casestrcmp(x, cast_uchar "lzma") &&
casestrcmp(x, cast_uchar "lzma2") &&
casestrcmp(x, cast_uchar "xz") &&
casestrcmp(x, cast_uchar "lz") &&
!strchr(cast_const_char x, '-') &&
strlen(cast_const_char x) <= 4) {
return stracpy(x);
}
}
return NULL;
}
static unsigned char *get_content_encoding_from_content_type(unsigned char *ct)
{
if (!casestrcmp(ct, cast_uchar "application/x-gzip") ||
!casestrcmp(ct, cast_uchar "application/x-tgz") ||
!casestrcmp(ct, cast_uchar "application/x-gtar")) return cast_uchar "gzip";
if (!casestrcmp(ct, cast_uchar "application/x-br")) return cast_uchar "br";
if (!casestrcmp(ct, cast_uchar "application/x-zstd") ||
!casestrcmp(ct, cast_uchar "application/zstd")) return cast_uchar "zstd";
if (!casestrcmp(ct, cast_uchar "application/x-bzip2") ||
!casestrcmp(ct, cast_uchar "application/x-bzip")) return cast_uchar "bzip2";
if (!casestrcmp(ct, cast_uchar "application/x-lzma")) return cast_uchar "lzma";
if (!casestrcmp(ct, cast_uchar "application/x-lzma2") ||
!casestrcmp(ct, cast_uchar "application/x-xz")) return cast_uchar "lzma2";
if (!casestrcmp(ct, cast_uchar "application/x-lz") ||
!casestrcmp(ct, cast_uchar "application/x-lzip")) return cast_uchar "lzip";
return NULL;
}
unsigned char *get_content_type(unsigned char *head, unsigned char *url)
{
unsigned char *ct;
int code;
if ((ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) {
unsigned char *s;
if ((s = cast_uchar strchr(cast_const_char ct, ';'))) *s = 0;
while (*ct && ct[strlen(cast_const_char ct) - 1] <= ' ') ct[strlen(cast_const_char ct) - 1] = 0;
if (*ct == '"' && ct[1] && ct[strlen(cast_const_char ct) - 1] == '"') {
memmove(ct, ct + 1, strlen(cast_const_char ct));
ct[strlen(cast_const_char ct) - 1] = 0;
}
if (!casestrcmp(ct, cast_uchar "text/plain") ||
!casestrcmp(ct, cast_uchar "application/octet-stream") ||
!casestrcmp(ct, cast_uchar "application/octetstream") ||
!casestrcmp(ct, cast_uchar "application/octet_stream") ||
!casestrcmp(ct, cast_uchar "application/binary") ||
!casestrcmp(ct, cast_uchar "application/x-www-form-urlencoded") ||
get_content_encoding_from_content_type(ct)) {
unsigned char *ctt;
if (!get_http_code(head, &code, NULL) && code >= 300)
goto no_code_by_extension;
ctt = get_content_type_by_header_and_extension(head, url);
if (ctt) {
mem_free(ct);
return ctt;
}
}
no_code_by_extension:
if (!*ct) mem_free(ct);
else return ct;
}
if (!get_http_code(head, &code, NULL) && code >= 300)
return stracpy(cast_uchar "text/html");
ct = get_content_type_by_header_and_extension(head, url);
if (ct) return ct;
return !force_html ? stracpy(cast_uchar "text/plain") : stracpy(cast_uchar "text/html");
}
unsigned char *get_content_encoding(unsigned char *head, unsigned char *url, int just_ce)
{
unsigned char *ce, *ct, *ext, *extd;
unsigned char *u;
int code;
if ((ce = parse_http_header(head, cast_uchar "Content-Encoding", NULL))) return ce;
if (just_ce) return NULL;
if ((ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) {
unsigned char *s;
if ((s = cast_uchar strchr(cast_const_char ct, ';'))) *s = 0;
ce = get_content_encoding_from_content_type(ct);
if (ce) {
mem_free(ct);
return stracpy(ce);
}
if (is_html_type(ct)) {
mem_free(ct);
return NULL;
}
mem_free(ct);
}
if (!get_http_code(head, &code, NULL) && code >= 300) return NULL;
if (!(ext = get_url_data(url))) ext = url;
for (u = ext; *u; u++) if (end_of_dir(url, *u)) goto skip_ext;
extd = cast_uchar strrchr(cast_const_char ext, '.');
if (extd) {
ce = get_compress_by_extension(extd + 1, cast_uchar strchr(cast_const_char(extd + 1), 0));
if (ce) return stracpy(ce);
}
skip_ext:
if ((ext = get_filename_from_header(head))) {
extd = cast_uchar strrchr(cast_const_char ext, '.');
if (extd) {
ce = get_compress_by_extension(extd + 1, cast_uchar strchr(cast_const_char(extd + 1), 0));
if (ce) {
mem_free(ext);
return stracpy(ce);
}
}
mem_free(ext);
}
return NULL;
}
unsigned char *encoding_2_extension(unsigned char *encoding)
{
if (!casestrcmp(encoding, cast_uchar "gzip") ||
!casestrcmp(encoding, cast_uchar "x-gzip")) return cast_uchar "gz";
if (!casestrcmp(encoding, cast_uchar "compress") ||
!casestrcmp(encoding, cast_uchar "x-compress")) return cast_uchar "Z";
if (!casestrcmp(encoding, cast_uchar "br")) return cast_uchar "br";
if (!casestrcmp(encoding, cast_uchar "zstd")) return cast_uchar "zst";
if (!casestrcmp(encoding, cast_uchar "bzip2")) return cast_uchar "bz2";
if (!casestrcmp(encoding, cast_uchar "lzma")) return cast_uchar "lzma";
if (!casestrcmp(encoding, cast_uchar "lzma2")) return cast_uchar "xz";
if (!casestrcmp(encoding, cast_uchar "lzip")) return cast_uchar "lz";
return NULL;
}
/* returns field with associations */
struct assoc *get_type_assoc(struct terminal *term, unsigned char *type, int *n)
{
struct assoc *assoc_array;
struct list *l;
struct list_head *ll;
int count=0;
foreach(struct list, l, ll, assoc.list_entry) {
struct assoc *a = get_struct(l, struct assoc, head);
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))) {
if (count == MAXINT) overalloc();
count++;
}
}
*n = count;
if (!count) return NULL;
if ((unsigned)count > MAXINT / sizeof(struct assoc)) overalloc();
assoc_array = mem_alloc(count * sizeof(struct assoc));
count = 0;
foreach(struct list, l, ll, assoc.list_entry) {
struct assoc *a = get_struct(l, struct assoc, head);
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))) {
assoc_array[count++] = *a;
}
}
return assoc_array;
}
int is_html_type(unsigned char *ct)
{
return !casestrcmp(ct, cast_uchar "text/html") ||
!casestrcmp(ct, cast_uchar "text-html") ||
!casestrcmp(ct, cast_uchar "text/x-server-parsed-html") ||
!casestrcmp(ct, cast_uchar "text/xml") ||
!casecmp(ct, cast_uchar "application/xhtml", strlen("application/xhtml"));
}
unsigned char *get_filename_from_header(unsigned char *head)
{
int extended = 0;
unsigned char *ct, *x, *y, *codepage;
int ly;
int cp_idx;
if ((ct = parse_http_header(head, cast_uchar "Content-Disposition", NULL))) {
x = parse_header_param(ct, cast_uchar "filename*", 1);
if (x) extended = 1;
else x = parse_header_param(ct, cast_uchar "filename", 1);
mem_free(ct);
if (x) {
if (*x) goto ret_x;
mem_free(x);
}
}
if ((ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) {
x = parse_header_param(ct, cast_uchar "name*", 0);
if (x) extended = 1;
else x = parse_header_param(ct, cast_uchar "name", 0);
mem_free(ct);
if (x) {
if (*x) goto ret_x;
mem_free(x);
}
}
return NULL;
ret_x:
codepage = NULL;
if (extended) {
unsigned char *ap1, *ap2;
ap1 = cast_uchar strchr(cast_const_char x, '\'');
if (!ap1)
goto no_extended;
ap2 = cast_uchar strchr(cast_const_char (ap1 + 1), '\'');
if (ap2) ap2++;
else ap2 = ap1 + 1;
codepage = memacpy(x, ap1 - x);
memmove(x, ap2, strlen(cast_const_char ap2) + 1);
}
no_extended:
y = init_str();
ly = 0;
add_conv_str(&y, &ly, x, (int)strlen(cast_const_char x), -2);
mem_free(x);
x = y;
cp_idx = -1;
if (codepage) {
cp_idx = get_cp_index(codepage);
mem_free(codepage);
}
if (cp_idx < 0) {
cp_idx = get_cp_index(cast_uchar "iso-8859-1");
if (cp_idx < 0) cp_idx = 0;
}
y = convert(cp_idx, 0, x, NULL);
mem_free(x);
x = y;
for (y = x; *y; y++) if (dir_sep(*y)
#if defined(DOS_FS) || defined(SPAD)
|| *y == ':'
#endif
) *y = '-';
return x;
}
unsigned char *get_filename_from_url(unsigned char *url, unsigned char *head, int tmp)
{
int ll = 0;
unsigned char *u, *s, *e, *f, *x, *ww;
unsigned char *ct, *want_ext;
if (!casecmp(url, cast_uchar "data:", 5)) {
url = cast_uchar "data:/data";
}
want_ext = stracpy(cast_uchar "");
f = get_filename_from_header(head);
if (f) {
goto no_ct;
}
if (!(u = get_url_data(url))) u = url;
for (e = s = u; *e && !end_of_dir(url, *e); e++) {
if (dir_sep(*e)) s = e + 1;
}
ll = 0;
f = init_str();
add_conv_str(&f, &ll, s, (int)(e - s), -2);
if (!(ct = parse_http_header(head, cast_uchar "Content-Type", NULL))) goto no_ct;
mem_free(ct);
ct = get_content_type(head, url);
if (ct) {
x = get_extension_by_content_type(ct);
if (x) {
add_to_strn(&want_ext, cast_uchar ".");
add_to_strn(&want_ext, x);
mem_free(x);
}
mem_free(ct);
}
no_ct:
if (!*want_ext) {
x = cast_uchar strrchr(cast_const_char f, '.');
if (x) {
mem_free(want_ext);
want_ext = stracpy(x);
}
}
ct = get_content_encoding(head, url, 0);
if (ct) {
x = encoding_2_extension(ct);
if (!tmp) {
unsigned char *ct1;
ct1 = get_content_encoding(head, url, 1);
if (ct1) {
mem_free(ct1);
} else if (x) {
unsigned char *w = cast_uchar strrchr(cast_const_char want_ext, '.');
if (w && (ww = canonical_compressed_ext(w + 1, NULL)) && !casestrcmp(x, ww))
goto skip_want_ext;
if (w && !casestrcmp(w + 1, x))
goto skip_want_ext;
add_to_strn(&want_ext, cast_uchar ".");
add_to_strn(&want_ext, x);
skip_want_ext:;
}
} else {
if (x) {
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)) {
f[strlen(cast_const_char f) - strlen(cast_const_char x) - 1] = 0;
}
}
}
mem_free(ct);
}
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))) {
x = cast_uchar strrchr(cast_const_char f, '.');
if (x && (ww = canonical_compressed_ext(x + 1, NULL)) && want_ext[0] == '.' && !casestrcmp(want_ext + 1, ww))
goto skip_tgz_2;
if (x) *x = 0;
add_to_strn(&f, want_ext);
skip_tgz_2:;
}
mem_free(want_ext);
return f;
}
static void free_prog_list(struct list_head *l)
{
struct list_head *lp;
struct protocol_program *p;
foreach(struct protocol_program, p, lp, *l)
mem_free(p->prog);
free_list(struct protocol_program, *l);
}
void free_types(void)
{
struct list *l;
struct list_head *ll;
foreach(struct list, l, ll, assoc.list_entry) {
struct assoc *a = get_struct(l, struct assoc, head);
mem_free(a->ct);
mem_free(a->prog);
mem_free(a->label);
ll = ll->prev;
del_from_list(&a->head);
mem_free(a);
}
foreach(struct list, l, ll, extensions.list_entry) {
struct extension *e = get_struct(l, struct extension, head);
mem_free(e->ext);
mem_free(e->ct);
ll = ll->prev;
del_from_list(&e->head);
mem_free(e);
}
free_prog_list(&mailto_prog);
free_prog_list(&telnet_prog);
free_prog_list(&tn3270_prog);
free_prog_list(&mms_prog);
free_prog_list(&magnet_prog);
free_prog_list(&gopher_prog);
free_history(ext_search_history);
free_history(assoc_search_history);
}