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