default.c (47033B)
1 /* default.c 2 * (c) 2002 Mikulas Patocka, Petr 'Brain' Kulhavy 3 * This file is a part of the Links program, released under GPL 4 * 5 * Does the configuration file. 6 */ 7 8 #include <limits.h> 9 #include <string.h> 10 #include <sys/stat.h> 11 #include <sys/types.h> 12 #include <unistd.h> 13 14 #include "links.h" 15 16 unsigned char system_name[MAX_STR_LEN]; 17 18 static void 19 get_system_name(void) 20 { 21 { 22 struct utsname name; 23 int rs; 24 memset(&name, 0, sizeof name); 25 EINTRLOOP(rs, uname(&name)); 26 if (!rs) { 27 unsigned char *str = NULL; 28 size_t l; 29 l = add_to_str(&str, 0, cast_uchar name.sysname); 30 l = add_chr_to_str(&str, l, ' '); 31 l = add_to_str(&str, l, cast_uchar name.release); 32 l = add_chr_to_str(&str, l, ' '); 33 l = add_to_str(&str, l, cast_uchar name.machine); 34 safe_strncpy(system_name, str, MAX_STR_LEN); 35 free(str); 36 return; 37 } 38 } 39 strcpy(cast_char system_name, SYSTEM_NAME); 40 } 41 42 struct option { 43 int p; 44 unsigned char *(*rd_cmd)(struct option *, unsigned char ***, int *); 45 unsigned char *(*rd_cfg)(struct option *, unsigned char *); 46 size_t (*wr_cfg)(struct option *, unsigned char **, size_t); 47 int min, max; /* for double min and max are in 1/100's (e.g. 0.1 is 48 min==10) */ 49 void *ptr; 50 char *cfg_name; 51 char *cmd_name; 52 }; 53 54 static unsigned char * 55 p_arse_options(int argc, unsigned char *argv[], struct option **opt) 56 { 57 unsigned char *e, *u = NULL; 58 int i; 59 for (i = 0; i < argc; i++) { 60 if (strlen(cast_const_char argv[i]) >= INT_MAX) { 61 fprintf(stderr, "Too long parameter\n"); 62 return NULL; 63 } 64 } 65 while (argc) { 66 argv++; 67 argc--; 68 if (argv[-1][0] == '-') { 69 struct option *options; 70 struct option **op; 71 for (op = opt; (options = *op); op++) 72 for (i = 0; options[i].p; i++) 73 if (options[i].rd_cmd 74 && options[i].cmd_name 75 && !casestrcmp( 76 cast_uchar options[i].cmd_name, 77 &argv[-1][1])) { 78 if ((e = options[i].rd_cmd( 79 &options[i], &argv, 80 &argc))) { 81 if (e[0]) 82 usage(); 83 return NULL; 84 } 85 goto found; 86 } 87 uu: 88 usage(); 89 return NULL; 90 } else if (!u) 91 u = argv[-1]; 92 else 93 goto uu; 94 found:; 95 } 96 if (u) 97 return u; 98 return cast_uchar ""; 99 } 100 101 static unsigned char * 102 get_token(unsigned char **line) 103 { 104 unsigned char *s = NULL; 105 int l = 0; 106 int escape = 0; 107 int quote = 0; 108 109 while (**line == ' ' || **line == 9) 110 (*line)++; 111 if (**line) { 112 for (s = NULL; **line; (*line)++) { 113 if (escape) 114 escape = 0; 115 else if (**line == '\\') { 116 escape = 1; 117 continue; 118 } else if (**line == '"') { 119 quote = !quote; 120 continue; 121 } else if ((**line == ' ' || **line == 9) && !quote) 122 break; 123 l = add_chr_to_str(&s, l, **line); 124 } 125 } 126 return s; 127 } 128 129 static void 130 parse_config_file(unsigned char *name, unsigned char *file, struct option **opt) 131 { 132 struct option *options; 133 struct option **op; 134 int err = 0; 135 int line = 0; 136 unsigned char *e; 137 int i; 138 unsigned char *n, *p; 139 unsigned char *tok; 140 int nl, pl; 141 while (file[0]) { 142 line++; 143 while (file[0] && (file[0] == ' ' || file[0] == 9)) 144 file++; 145 n = file; 146 while (file[0] && file[0] > ' ') 147 file++; 148 if (file == n) { 149 if (file[0]) 150 file++; 151 continue; 152 } 153 while (file[0] == 9 || file[0] == ' ') 154 file++; 155 p = file; 156 while (file[0] && file[0] != 10 && file[0] != 13) 157 file++; 158 pl = (int)(file - p); 159 if (file[0]) { 160 if ((file[1] == 10 || file[1] == 13) 161 && file[0] != file[1]) 162 file++; 163 file++; 164 } 165 tok = NULL; 166 if (n[0] == '#') 167 goto f; 168 if (!(tok = get_token(&n))) 169 goto f; 170 nl = (int)strlen(cast_const_char tok); 171 for (op = opt; (options = *op); op++) 172 for (i = 0; options[i].p; i++) 173 if (options[i].cfg_name 174 && (size_t)nl 175 == strlen(cast_const_char options[i] 176 .cfg_name) 177 && !casecmp(tok, 178 cast_uchar options[i].cfg_name, 179 nl)) { 180 unsigned char *o = memacpy(p, pl); 181 if (options[i].rd_cfg 182 && (e = options[i].rd_cfg( 183 &options[i], o))) { 184 if (e[0]) { 185 fprintf( 186 stderr, 187 "Error parsing " 188 "config file %s, " 189 "line %d: %s\n", 190 name, line, e); 191 err = 1; 192 } 193 } 194 free(o); 195 goto f; 196 } 197 fprintf(stderr, "Unknown option in config file %s, line %d\n", 198 name, line); 199 err = 1; 200 f: 201 free(tok); 202 } 203 if (err) { 204 fprintf(stderr, "\007"); 205 portable_sleep(1000); 206 } 207 } 208 209 static unsigned char * 210 create_config_string(struct option *options) 211 { 212 unsigned char *s = NULL; 213 size_t l; 214 int i; 215 l = add_to_str(&s, 0, 216 cast_uchar 217 "# This file is automatically generated by Links " 218 "-- please do not edit."); 219 for (i = 0; options[i].p; i++) { 220 if (options[i].wr_cfg) 221 l = options[i].wr_cfg(&options[i], &s, l); 222 } 223 l = add_chr_to_str(&s, l, '\n'); 224 return s; 225 } 226 227 unsigned char * 228 read_config_file(unsigned char *name) 229 { 230 int h, r; 231 int l = 0; 232 unsigned char *cfg_buffer, *s; 233 int rs; 234 h = c_open(name, O_RDONLY | O_NOCTTY); 235 if (h == -1) 236 return NULL; 237 s = NULL; 238 cfg_buffer = xmalloc(page_size); 239 while ((r = hard_read(h, cfg_buffer, page_size)) > 0) { 240 int i; 241 for (i = 0; i < r; i++) 242 if (!cfg_buffer[i]) 243 cfg_buffer[i] = ' '; 244 l = add_bytes_to_str(&s, l, cfg_buffer, r); 245 } 246 free(cfg_buffer); 247 if (r == -1) { 248 free(s); 249 s = NULL; 250 } 251 EINTRLOOP(rs, close(h)); 252 return s; 253 } 254 255 int 256 write_to_config_file(unsigned char *name, unsigned char *c, int do_sync) 257 { 258 int rr; 259 int h, w; 260 int count = 0; 261 size_t tmp_namel; 262 unsigned char *tmp_name; 263 int rs, err; 264 try_new_count: 265 tmp_name = NULL; 266 tmp_namel = add_to_str(&tmp_name, 0, name); 267 for (w = tmp_namel - 1; w >= 0; w--) { 268 if (dir_sep(tmp_name[w])) 269 break; 270 if (tmp_name[w] == '.') { 271 if (w <= tmp_namel - 2) { 272 tmp_name[w + 2] = 0; 273 tmp_namel = w + 2; 274 } 275 break; 276 } 277 } 278 tmp_namel = add_num_to_str(&tmp_name, tmp_namel, count); 279 h = c_open3(tmp_name, O_WRONLY | O_NOCTTY | O_CREAT | O_TRUNC | O_EXCL, 280 0600); 281 if (h == -1) { 282 err = errno; 283 if (err == EEXIST && count < INT_MAX) { 284 count++; 285 free(tmp_name); 286 goto try_new_count; 287 } 288 goto free_err; 289 } 290 rr = (int)strlen(cast_const_char c); 291 if (hard_write(h, c, rr) != rr) { 292 err = errno; 293 goto close_unlink_err; 294 } 295 if (do_sync) { 296 EINTRLOOP(rs, fsync(h)); 297 if (rs) { 298 err = errno; 299 goto close_unlink_err; 300 } 301 } 302 EINTRLOOP(rs, close(h)); 303 if (rs) { 304 err = errno; 305 goto unlink_err; 306 } 307 EINTRLOOP(rs, rename(cast_const_char tmp_name, cast_const_char name)); 308 if (rs) { 309 err = errno; 310 goto unlink_err; 311 } 312 free(tmp_name); 313 if (do_sync) { 314 unsigned char *e, *le; 315 tmp_name = stracpy(name); 316 le = tmp_name; 317 for (e = tmp_name; *e; e++) 318 if (dir_sep(*e)) 319 le = e; 320 while (le > tmp_name && dir_sep(le[-1])) 321 le--; 322 if (le == tmp_name && dir_sep(*le)) 323 le++; 324 *le = 0; 325 326 h = c_open(*tmp_name ? tmp_name : cast_uchar ".", 327 O_RDONLY | O_NOCTTY); 328 if (h != -1) { 329 EINTRLOOP(rs, fsync(h)); 330 EINTRLOOP(rs, close(h)); 331 } 332 free(tmp_name); 333 } 334 335 return 0; 336 337 close_unlink_err: 338 EINTRLOOP(rs, close(h)); 339 unlink_err: 340 EINTRLOOP(rs, unlink(cast_const_char tmp_name)); 341 free_err: 342 free(tmp_name); 343 return get_error_from_errno(err); 344 } 345 346 static unsigned char * 347 get_home(void) 348 { 349 struct stat st; 350 int rs; 351 unsigned char *home; 352 unsigned char *home_links; 353 unsigned char *config_dir; 354 355 if (stat(".", &st)) 356 die("stat: %s: %s\n", ".", strerror(errno)); 357 358 first_use = 1; 359 home = stracpy(cast_uchar getenv("HOME")); 360 config_dir = cast_uchar getenv("XDG_CONFIG_HOME"); 361 362 if (!home) { 363 int i; 364 home = (unsigned char *)argv0; 365 for (i = strlen(argv0) - 1; i >= 0; i--) 366 if (dir_sep(home[i])) { 367 home[i + 1] = 0; 368 goto br; 369 } 370 home[0] = 0; 371 br:; 372 } 373 /* clears any '/' from the end of home */ 374 while (home[0] && home[1] 375 && dir_sep(home[strlen(cast_const_char home) - 1])) 376 home[strlen(cast_const_char home) - 1] = 0; 377 if (home[0]) 378 add_to_strn(&home, cast_uchar "/"); 379 if (config_dir == NULL || config_dir[0] == 0) { 380 home_links = stracpy(home); 381 add_to_strn(&home_links, cast_uchar ".config"); 382 } else { 383 home_links = stracpy(config_dir); 384 while (home_links[0] 385 && dir_sep( 386 home_links[strlen(cast_const_char home_links) - 1])) 387 home_links[strlen(cast_const_char home_links) - 1] = 0; 388 } 389 add_to_strn(&home_links, cast_uchar "/links"); 390 EINTRLOOP(rs, stat(cast_const_char home_links, &st)); 391 if (rs) { 392 EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700)); 393 if (!rs) 394 goto home_creat; 395 if (config_dir) 396 goto failed; 397 goto first_failed; 398 } 399 if (S_ISDIR(st.st_mode)) 400 goto home_ok; 401 /* This is a Cygwin hack! Cygwin reports stat for "links" if no 402 "links" exists and only "links.exe" does. So try to create directory 403 anyway. */ 404 EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700)); 405 if (!rs) 406 goto home_creat; 407 first_failed: 408 free(home_links); 409 home_links = stracpy(home); 410 add_to_strn(&home_links, cast_uchar "links"); 411 EINTRLOOP(rs, stat(cast_const_char home_links, &st)); 412 if (rs) { 413 EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700)); 414 if (!rs) 415 goto home_creat; 416 goto failed; 417 } 418 if (S_ISDIR(st.st_mode)) 419 goto home_ok; 420 EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700)); 421 if (!rs) 422 goto home_creat; 423 failed: 424 free(home_links); 425 free(home); 426 return NULL; 427 428 home_ok: 429 first_use = 0; 430 if ((st.st_mode & 07777) != 0700) { 431 home_creat: 432 EINTRLOOP(rs, chmod(cast_const_char home_links, 0700)); 433 } 434 add_to_strn(&home_links, cast_uchar "/"); 435 free(home); 436 return home_links; 437 } 438 439 void 440 init_home(void) 441 { 442 get_system_name(); 443 links_home = get_home(); 444 if (!links_home) { 445 fprintf(stderr, 446 "Unable to find or create links config directory. " 447 "Please check, that you have $HOME variable set " 448 "correctly and that you have write permission to your " 449 "home directory.\n\007"); 450 portable_sleep(3000); 451 return; 452 } 453 } 454 455 /* prefix: directory 456 * name: name of the configuration file (typ. links.cfg) 457 */ 458 static int 459 write_config_data(unsigned char *prefix, unsigned char *name, struct option *o, 460 struct terminal *term) 461 { 462 int err; 463 unsigned char *c, *config_file; 464 if (!(c = create_config_string(o))) 465 return -1; 466 config_file = stracpy(prefix); 467 if (!config_file) { 468 free(c); 469 if (term) 470 msg_box(term, NULL, TEXT_(T_CONFIG_ERROR), AL_CENTER, 471 TEXT_(T_UNABLE_TO_WRITE_TO_CONFIG_FILE), 472 cast_uchar ": ", 473 TEXT_(T_HOME_DIRECTORY_INACCESSIBLE), 474 MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), 475 msg_box_null, B_ENTER | B_ESC); 476 return -1; 477 } 478 add_to_strn(&config_file, name); 479 if ((err = write_to_config_file(config_file, c, 1))) { 480 if (term) 481 msg_box(term, NULL, TEXT_(T_CONFIG_ERROR), AL_CENTER, 482 TEXT_(T_UNABLE_TO_WRITE_TO_CONFIG_FILE), 483 cast_uchar ": ", get_err_msg(err), MSG_BOX_END, 484 NULL, 1, TEXT_(T_CANCEL), msg_box_null, 485 B_ENTER | B_ESC); 486 free(c); 487 free(config_file); 488 return -1; 489 } 490 free(c); 491 free(config_file); 492 return 0; 493 } 494 495 static size_t 496 add_nm(struct option *o, unsigned char **s, size_t l) 497 { 498 if (l) 499 l = add_chr_to_str(s, l, '\n'); 500 l = add_to_str(s, l, cast_uchar o->cfg_name); 501 return add_chr_to_str(s, l, ' '); 502 } 503 504 static size_t 505 add_quoted_to_str(unsigned char **s, size_t l, unsigned char *q) 506 { 507 l = add_chr_to_str(s, l, '"'); 508 while (*q) { 509 if (*q == '"' || *q == '\\') 510 l = add_chr_to_str(s, l, '\\'); 511 l = add_chr_to_str(s, l, *q); 512 q++; 513 } 514 return add_chr_to_str(s, l, '"'); 515 } 516 517 static unsigned char * 518 num_rd(struct option *o, unsigned char *c) 519 { 520 unsigned char *tok = get_token(&c); 521 unsigned char *end; 522 long l; 523 if (!tok) 524 return cast_uchar "Missing argument"; 525 l = strtolx(tok, &end); 526 if (*end) { 527 free(tok); 528 return cast_uchar "Number expected"; 529 } 530 if (l < o->min || l > o->max || l != (long)(int)l) { 531 free(tok); 532 return cast_uchar "Out of range"; 533 } 534 *(int *)o->ptr = (int)l; 535 free(tok); 536 return NULL; 537 } 538 539 static size_t 540 num_wr(struct option *o, unsigned char **s, size_t l) 541 { 542 l = add_nm(o, s, l); 543 return add_knum_to_str(s, l, *(int *)o->ptr); 544 } 545 546 static unsigned char * 547 dbl_rd(struct option *o, unsigned char *c) 548 { 549 unsigned char *tok = get_token(&c); 550 char *end; 551 double d; 552 553 if (!tok) 554 return cast_uchar "Missing argument"; 555 556 if (strlen(cast_const_char tok) >= 1000) { 557 free(tok); 558 return cast_uchar "Number is too long"; 559 } 560 561 d = strtod(cast_const_char tok, &end); 562 563 if (*end) { 564 free(tok); 565 return cast_uchar "Number expected"; 566 } 567 if (d < 0 || d > o->max || 100 * d < o->min || 100 * d > o->max) { 568 free(tok); 569 return cast_uchar "Out of range"; 570 } 571 *(double *)o->ptr = d; 572 free(tok); 573 return NULL; 574 } 575 576 static size_t 577 dbl_wr(struct option *o, unsigned char **s, size_t l) 578 { 579 unsigned char number[80]; 580 snprintf(cast_char number, sizeof number, "%.6f", *(double *)o->ptr); 581 582 l = add_nm(o, s, l); 583 return add_to_str(s, l, number); 584 } 585 586 static unsigned char * 587 str_rd(struct option *o, unsigned char *c) 588 { 589 unsigned char *tok = get_token(&c); 590 unsigned char *e = NULL; 591 if (!tok) 592 tok = stracpy(cast_uchar ""); 593 if (strlen(cast_const_char tok) + 1 > (size_t)o->max) 594 e = cast_uchar "String too long"; 595 else 596 strcpy(cast_char o->ptr, cast_const_char tok); 597 free(tok); 598 return e; 599 } 600 601 static size_t 602 str_wr(struct option *o, unsigned char **s, size_t l) 603 { 604 l = add_nm(o, s, l); 605 if (strlen(cast_const_char o->ptr) + 1 > (size_t)o->max) { 606 unsigned char *s1 = NULL; 607 add_bytes_to_str(&s1, 0, o->ptr, o->max - 1); 608 l = add_quoted_to_str(s, l, s1); 609 free(s1); 610 } else 611 l = add_quoted_to_str(s, l, o->ptr); 612 613 return l; 614 } 615 616 static unsigned char * 617 cp_rd(struct option *o, unsigned char *c) 618 { 619 unsigned char *tok = get_token(&c); 620 if (!tok) 621 return cast_uchar "Missing argument"; 622 *(int *)o->ptr = 0; 623 free(tok); 624 return NULL; 625 } 626 627 static size_t 628 cp_wr(struct option *o, unsigned char **s, size_t l) 629 { 630 unsigned char *n = get_cp_mime_name(0); 631 l = add_nm(o, s, l); 632 return add_to_str(s, l, n); 633 } 634 635 static int 636 getnum(unsigned char *s, int *n, int r1, int r2) 637 { 638 char *e; 639 long l = strtol(cast_const_char s, &e, 10); 640 if (*e || !*s) 641 return -1; 642 if (l < r1 || l >= r2) 643 return -1; 644 *n = (int)l; 645 return 0; 646 } 647 648 static unsigned char * 649 type_rd(struct option *o, unsigned char *c) 650 { 651 unsigned char *err = 652 cast_uchar "Error reading association specification"; 653 struct assoc neww; 654 unsigned char *w; 655 int n = 0; /* against warning */ 656 memset(&neww, 0, sizeof(struct assoc)); 657 if (!(neww.label = get_token(&c))) 658 goto err; 659 if (!(neww.ct = get_token(&c))) 660 goto err; 661 if (!(neww.prog = get_token(&c))) 662 goto err; 663 if (!(w = get_token(&c))) 664 goto err; 665 if (getnum(w, &n, 0, 128)) 666 goto err_f; 667 free(w); 668 neww.cons = !!(n & 1); 669 neww.xwin = !!(n & 2); 670 neww.ask = !!(n & 4); 671 if ((n & 8) || (n & 16)) 672 neww.block = !!(n & 16); 673 else 674 neww.block = !neww.xwin || neww.cons; 675 neww.accept_http = !!(n & 32); 676 neww.accept_ftp = !!(n & 64); 677 if (!(w = get_token(&c))) 678 goto err; 679 if (getnum(w, &neww.system, 0, 256)) 680 goto err_f; 681 free(w); 682 update_assoc(&neww); 683 err = NULL; 684 err: 685 free(neww.label); 686 free(neww.ct); 687 free(neww.prog); 688 return err; 689 err_f: 690 free(w); 691 goto err; 692 } 693 694 static size_t 695 type_wr(struct option *o, unsigned char **s, size_t l) 696 { 697 struct list *a = NULL; 698 struct list_head *la; 699 foreachback (struct list, a, la, assoc.list_entry) { 700 struct assoc *as = get_struct(a, struct assoc, head); 701 l = add_nm(o, s, l); 702 l = add_quoted_to_str(s, l, as->label); 703 l = add_chr_to_str(s, l, ' '); 704 l = add_quoted_to_str(s, l, as->ct); 705 l = add_chr_to_str(s, l, ' '); 706 l = add_quoted_to_str(s, l, as->prog); 707 l = add_chr_to_str(s, l, ' '); 708 l = add_num_to_str( 709 s, l, 710 (!!as->cons) + (!!as->xwin) * 2 + (!!as->ask) * 4 711 + (!as->block) * 8 + (!!as->block) * 16 712 + (!!as->accept_http) * 32 + (!!as->accept_ftp) * 64); 713 l = add_chr_to_str(s, l, ' '); 714 l = add_num_to_str(s, l, as->system); 715 } 716 return l; 717 } 718 719 static unsigned char * 720 ext_rd(struct option *o, unsigned char *c) 721 { 722 unsigned char *err = cast_uchar "Error reading extension specification"; 723 struct extension neww; 724 memset(&neww, 0, sizeof(struct extension)); 725 if (!(neww.ext = get_token(&c))) 726 goto err; 727 if (!(neww.ct = get_token(&c))) 728 goto err; 729 update_ext(&neww); 730 err = NULL; 731 err: 732 free(neww.ext); 733 free(neww.ct); 734 return err; 735 } 736 737 static size_t 738 ext_wr(struct option *o, unsigned char **s, size_t l) 739 { 740 struct list *a = NULL; 741 struct list_head *la; 742 foreachback (struct list, a, la, extensions.list_entry) { 743 struct extension *e = get_struct(a, struct extension, head); 744 l = add_nm(o, s, l); 745 l = add_quoted_to_str(s, l, e->ext); 746 l = add_chr_to_str(s, l, ' '); 747 l = add_quoted_to_str(s, l, e->ct); 748 } 749 return l; 750 } 751 752 static unsigned char * 753 term_rd(struct option *o, unsigned char *c) 754 { 755 struct term_spec *ts; 756 unsigned char *w; 757 if (!(w = get_token(&c))) 758 goto err; 759 ts = new_term_spec(w); 760 free(w); 761 if (!(w = get_token(&c))) 762 goto err; 763 if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '4') 764 goto err_f; 765 ts->mode = w[0] - '0'; 766 free(w); 767 if (!(w = get_token(&c))) 768 goto err; 769 if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '3') 770 goto err_f; 771 ts->m11_hack = (w[0] - '0') & 1; 772 free(w); 773 if (!(w = get_token(&c))) 774 goto err; 775 if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '7') 776 goto err_f; 777 ts->col = (w[0] - '0') & 1; 778 ts->restrict_852 = !!((w[0] - '0') & 2); 779 ts->block_cursor = !!((w[0] - '0') & 4); 780 free(w); 781 if (!(w = get_token(&c))) 782 goto err; 783 ts->character_set = 0; 784 free(w); 785 ts->left_margin = 0; 786 ts->right_margin = 0; 787 ts->top_margin = 0; 788 ts->bottom_margin = 0; 789 return NULL; 790 err_f: 791 free(w); 792 err: 793 return cast_uchar "Error reading terminal specification"; 794 } 795 796 static unsigned char * 797 term2_rd(struct option *o, unsigned char *c) 798 { 799 struct term_spec *ts; 800 unsigned char *w; 801 if (!(w = get_token(&c))) 802 goto err; 803 ts = new_term_spec(w); 804 free(w); 805 if (!(w = get_token(&c))) 806 goto err; 807 if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '3') 808 goto err_f; 809 ts->mode = w[0] - '0'; 810 free(w); 811 if (!(w = get_token(&c))) 812 goto err; 813 if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '1') 814 goto err_f; 815 ts->m11_hack = w[0] - '0'; 816 free(w); 817 if (!(w = get_token(&c))) 818 goto err; 819 if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '1') 820 goto err_f; 821 ts->restrict_852 = w[0] - '0'; 822 free(w); 823 if (!(w = get_token(&c))) 824 goto err; 825 if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '1') 826 goto err_f; 827 ts->col = w[0] - '0'; 828 free(w); 829 if (!(w = get_token(&c))) 830 goto err; 831 ts->character_set = 0; 832 free(w); 833 return NULL; 834 err_f: 835 free(w); 836 err: 837 return cast_uchar "Error reading terminal specification"; 838 } 839 840 static size_t 841 term_wr(struct option *o, unsigned char **s, size_t l) 842 { 843 struct term_spec *ts = NULL; 844 struct list_head *lts; 845 foreachback (struct term_spec, ts, lts, term_specs) { 846 l = add_nm(o, s, l); 847 l = add_quoted_to_str(s, l, ts->term); 848 l = add_chr_to_str(s, l, ' '); 849 l = add_num_to_str(s, l, ts->mode); 850 l = add_chr_to_str(s, l, ' '); 851 l = add_num_to_str(s, l, !!ts->m11_hack); 852 l = add_chr_to_str(s, l, ' '); 853 l = add_num_to_str(s, l, 854 !!ts->col + !!ts->restrict_852 * 2 855 + !!ts->block_cursor * 4); 856 l = add_chr_to_str(s, l, ' '); 857 l = add_to_str(s, l, get_cp_mime_name(ts->character_set)); 858 if (ts->left_margin || ts->right_margin || ts->top_margin 859 || ts->bottom_margin) { 860 l = add_chr_to_str(s, l, ' '); 861 l = add_num_to_str(s, l, ts->left_margin); 862 l = add_chr_to_str(s, l, ' '); 863 l = add_num_to_str(s, l, ts->right_margin); 864 l = add_chr_to_str(s, l, ' '); 865 l = add_num_to_str(s, l, ts->top_margin); 866 l = add_chr_to_str(s, l, ' '); 867 l = add_num_to_str(s, l, ts->bottom_margin); 868 } 869 } 870 return l; 871 } 872 873 static struct list_head driver_params = { &driver_params, &driver_params }; 874 875 struct driver_param * 876 get_driver_param(unsigned char *n) 877 { 878 struct driver_param *dp = NULL; 879 size_t sl; 880 struct list_head *ldp; 881 foreach (struct driver_param, dp, ldp, driver_params) 882 if (!casestrcmp(dp->name, n)) 883 return dp; 884 sl = strlen(cast_const_char n); 885 if (sl > INT_MAX - sizeof(struct driver_param)) 886 overalloc(); 887 dp = mem_calloc(sizeof(struct driver_param) + sl); 888 strcpy(cast_char dp->name, cast_const_char n); 889 dp->kbd_codepage = -1; 890 dp->palette_mode = 0; 891 dp->nosave = 1; 892 add_to_list(driver_params, dp); 893 return dp; 894 } 895 896 static unsigned char * 897 dp_rd(struct option *o, unsigned char *c) 898 { 899 int cc; 900 unsigned char *n, *param, *cp; 901 struct driver_param *dp; 902 if (!(n = get_token(&c))) 903 goto err; 904 dp = get_driver_param(n); 905 free(n); 906 if (!(param = get_token(&c))) 907 goto err; 908 free(dp->param); 909 dp->param = param; 910 if (!(param = get_token(&c))) 911 goto err; 912 safe_strncpy(dp->shell_term, param, MAX_STR_LEN); 913 free(param); 914 if (!(cp = get_token(&c))) 915 goto err; 916 if (!casestrcmp(cp, cast_uchar "default")) 917 cc = -1; 918 else 919 cc = 0; 920 free(cp); 921 dp->kbd_codepage = cc; 922 dp->nosave = 0; 923 return NULL; 924 err: 925 return cast_uchar "Error reading driver mode specification"; 926 } 927 928 static size_t 929 dp_wr(struct option *o, unsigned char **s, size_t l) 930 { 931 struct driver_param *dp = NULL; 932 struct list_head *ldp; 933 foreachback (struct driver_param, dp, ldp, driver_params) { 934 if ((!dp->param || !*dp->param) && !*dp->shell_term 935 && dp->kbd_codepage < 0 && !dp->palette_mode) 936 continue; 937 if (dp->nosave) 938 continue; 939 l = add_nm(o, s, l); 940 l = add_quoted_to_str(s, l, dp->name); 941 l = add_chr_to_str(s, l, ' '); 942 l = add_quoted_to_str( 943 s, l, dp->param ? dp->param : (unsigned char *)""); 944 l = add_chr_to_str(s, l, ' '); 945 l = add_quoted_to_str(s, l, dp->shell_term); 946 l = add_chr_to_str(s, l, ' '); 947 if (dp->kbd_codepage == -1) 948 l = add_to_str(s, l, cast_uchar "default"); 949 else 950 l = add_to_str(s, l, 951 get_cp_mime_name(dp->kbd_codepage)); 952 l = add_chr_to_str(s, l, ' '); 953 l = add_num_to_str(s, l, dp->palette_mode); 954 /* pokud se sem neco prida, opravit podminku na zacatku cyklu */ 955 } 956 return l; 957 } 958 959 static unsigned char * 960 ip_rd(struct option *o, unsigned char *c) 961 { 962 unsigned char *e; 963 e = str_rd(o, c); 964 if (e) 965 return e; 966 if (*(unsigned char *)o->ptr && numeric_ip_address(o->ptr, NULL) == -1) 967 return cast_uchar "Invalid IP address"; 968 return NULL; 969 } 970 971 static unsigned char * 972 ipv6_rd(struct option *o, unsigned char *c) 973 { 974 unsigned char *e; 975 e = str_rd(o, c); 976 if (e) 977 return e; 978 if (*(unsigned char *)o->ptr 979 && numeric_ipv6_address(o->ptr, NULL, NULL) == -1) 980 return cast_uchar "Invalid IPv6 address"; 981 return NULL; 982 } 983 984 static unsigned char * 985 gen_cmd(struct option *o, unsigned char ***argv, int *argc) 986 { 987 unsigned char *e; 988 unsigned char *r; 989 if (!*argc) 990 return cast_uchar "Parameter expected"; 991 e = NULL; 992 add_quoted_to_str(&e, 0, **argv); 993 r = o->rd_cfg ? o->rd_cfg(o, e) : 0; 994 free(e); 995 if (r) 996 return r; 997 (*argv)++; 998 (*argc)--; 999 return NULL; 1000 } 1001 1002 static unsigned char * 1003 x_proxy_cmd(struct option *o, unsigned char ***argv, int *argc, 1004 int (*save)(int, unsigned char *, unsigned char *), 1005 unsigned char *err) 1006 { 1007 unsigned char **pass_argv; 1008 unsigned char *result, *ret; 1009 if (!*argc) 1010 return cast_uchar "Parameter expected"; 1011 result = xmalloc(MAX_STR_LEN); 1012 if (save(0, result, **argv)) { 1013 free(result); 1014 return err; 1015 } 1016 pass_argv = &result; 1017 ret = gen_cmd(o, &pass_argv, argc); 1018 free(result); 1019 if (ret) 1020 return ret; 1021 (*argv)++; 1022 return NULL; 1023 } 1024 1025 static unsigned char * 1026 proxy_cmd(struct option *o, unsigned char ***argv, int *argc) 1027 { 1028 return x_proxy_cmd(o, argv, argc, save_proxy, 1029 cast_uchar "Invalid proxy"); 1030 } 1031 1032 static unsigned char * 1033 noproxy_cmd(struct option *o, unsigned char ***argv, int *argc) 1034 { 1035 return x_proxy_cmd(o, argv, argc, save_noproxy_list, 1036 cast_uchar "Invalid list of domains"); 1037 } 1038 1039 static unsigned char * 1040 version_cmd(struct option *o, unsigned char ***argv, int *argc) 1041 { 1042 printf("Links " VERSION "\n"); 1043 fflush(stdout); 1044 exit(RET_OK); 1045 } 1046 1047 static unsigned char * 1048 set_cmd(struct option *o, unsigned char ***argv, int *argc) 1049 { 1050 *(int *)o->ptr = 1; 1051 return NULL; 1052 } 1053 1054 static unsigned char * 1055 setstr_cmd(struct option *o, unsigned char ***argv, int *argc) 1056 { 1057 if (!*argc) 1058 return cast_uchar "Parameter expected"; 1059 safe_strncpy(o->ptr, **argv, o->max); 1060 (*argv)++; 1061 (*argc)--; 1062 return NULL; 1063 } 1064 1065 static unsigned char * 1066 dump_cmd(struct option *o, unsigned char ***argv, int *argc) 1067 { 1068 if (dmp != o->min && dmp) 1069 return cast_uchar "Can't use both -dump and -source"; 1070 dmp = o->min; 1071 no_connect = 1; 1072 return NULL; 1073 } 1074 1075 static unsigned char * 1076 printhelp_cmd(struct option *o, unsigned char ***argv, int *argc) 1077 { 1078 usage(); 1079 /* FIXME: never reached */ 1080 return NULL; 1081 } 1082 1083 void 1084 end_config(void) 1085 { 1086 struct driver_param *dp = NULL; 1087 struct list_head *ldp; 1088 foreach (struct driver_param, dp, ldp, driver_params) { 1089 free(dp->param); 1090 } 1091 free_list(struct driver_param, driver_params); 1092 free(links_home); 1093 } 1094 1095 int anonymous = 0; 1096 1097 unsigned char default_target[MAX_STR_LEN] = ""; 1098 1099 unsigned char *links_home = NULL; 1100 int first_use = 0; 1101 1102 int disable_libevent = 0; 1103 int no_connect = 0; 1104 int base_session = 0; 1105 int dmp = 0; 1106 int screen_width = 80; 1107 int dump_codepage = -1; 1108 int force_html = 0; 1109 1110 int max_connections = 10; 1111 int max_connections_to_host = 8; 1112 int max_tries = 3; 1113 int receive_timeout = 120; 1114 int unrestartable_receive_timeout = 600; 1115 int timeout_multiple_addresses = 3; 1116 unsigned char bind_ip_address[16] = ""; 1117 unsigned char bind_ipv6_address[INET6_ADDRSTRLEN] = ""; 1118 int download_utime = 0; 1119 1120 int max_format_cache_entries = 5; 1121 int memory_cache_size = 4194304; 1122 int image_cache_size = 1048576; 1123 int font_cache_size = 2097152; 1124 int aggressive_cache = 1; 1125 1126 struct ipv6_options ipv6_options = { ADDR_PREFERENCE_DEFAULT }; 1127 struct proxies proxies = { "", "", "", "", "", 0 }; 1128 struct ssl_options ssl_options = { SSL_WARN_ON_INVALID_CERTIFICATE, 0, "", "", 1129 "" }; 1130 struct http_options http_options = { 1131 0, 1, 0, 0, 0, {0, "", ""} 1132 }; 1133 1134 unsigned char download_dir[MAX_STR_LEN] = ""; 1135 1136 double display_red_gamma = 2.2; /* Red gamma exponent of the display */ 1137 double display_green_gamma = 2.2; /* Green gamma exponent of the display */ 1138 double display_blue_gamma = 2.2; /* Blue gamma exponent of the display */ 1139 double user_gamma = 1.0; /* 1.0 for 64 lx. This is the number user directly 1140 changes in the menu */ 1141 double bfu_aspect = 1; /* 0.1 to 10.0, 1.0 default. >1 makes circle wider */ 1142 int dither_letters = 1; 1143 int dither_images = 1; 1144 int gamma_bits = 2; /*0 --- 8, 1 --- 16, 2 --- auto */ 1145 int overwrite_instead_of_scroll = 1; 1146 1147 unsigned char bookmarks_file[MAX_STR_LEN] = ""; 1148 1149 int save_history = 1; 1150 1151 struct document_setup dds = { 1152 0, /* assumed codepage */ 1153 0, /* ignore codepage from server */ 1154 1, /* tables */ 1155 1, /* frames */ 1156 0, /* break_long_lines */ 1157 0, /* images */ 1158 0, /* image_names */ 1159 3, /* margin */ 1160 0, /* num_links */ 1161 0, /* table_order */ 1162 0, /* auto_refresh */ 1163 20, /* font_size */ 1164 1, /* display images */ 1165 100, /* image scale */ 1166 0, /* porn enable */ 1167 0, /* target in new window */ 1168 7, /* t text color */ 1169 15, /* t link color */ 1170 0, /* t background color */ 1171 0, /* t ignore document color */ 1172 0x000000, /* g text color */ 1173 0x0000ff, /* g link color */ 1174 0xc0c0c0, /* g background color */ 1175 0, /* g ignore document color */ 1176 }; 1177 1178 static struct option links_options[] = { 1179 {1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "?" }, 1180 { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "h" }, 1181 { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "help" }, 1182 { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "-help" }, 1183 { 1, version_cmd, NULL, NULL, 0, 0, NULL, NULL, "version" }, 1184 { 1, set_cmd, NULL, NULL, 0, 0, &no_connect, NULL, "no-connect" }, 1185 { 1, set_cmd, NULL, NULL, 0, 0, &anonymous, NULL, "anonymous" }, 1186 { 1, setstr_cmd, NULL, NULL, 0, MAX_STR_LEN, default_target, NULL, 1187 "target" }, 1188 { 1, gen_cmd, num_rd, NULL, 0, INT_MAX, &base_session, NULL, 1189 "base-session" }, 1190 { 1, set_cmd, NULL, NULL, 0, 0, &force_html, NULL, "force-html" }, 1191 { 1, dump_cmd, NULL, NULL, D_SOURCE, 0, NULL, NULL, "source" }, 1192 { 1, dump_cmd, NULL, NULL, D_DUMP, 0, NULL, NULL, "dump" }, 1193 { 1, gen_cmd, num_rd, NULL, 10, 512, &screen_width, "dump_width", 1194 "width" }, 1195 { 1, gen_cmd, cp_rd, NULL, 1, 0, &dump_codepage, "dump_codepage", 1196 "codepage" }, 1197 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, download_dir, 1198 "download_dir", "download-dir" }, 1199 { 1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections, 1200 "max_connections", "max-connections" }, 1201 { 1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections_to_host, 1202 "max_connections_to_host", "max-connections-to-host" }, 1203 { 1, gen_cmd, num_rd, num_wr, 0, 16, &max_tries, "retries", "retries" }, 1204 { 1, gen_cmd, num_rd, num_wr, 1, 9999, &receive_timeout, 1205 "receive_timeout", "receive-timeout" }, 1206 { 1, gen_cmd, num_rd, num_wr, 1, 9999, &unrestartable_receive_timeout, 1207 "unrestartable_receive_timeout", "unrestartable-receive-timeout" }, 1208 { 1, gen_cmd, num_rd, num_wr, 1, 999, &timeout_multiple_addresses, 1209 "timeout_when_trying_multiple_addresses", "timeout-when-trying-multiple-addresses"}, 1210 { 1, gen_cmd, ip_rd, str_wr, 0, 16, bind_ip_address, "bind_address", 1211 "bind-address" }, 1212 { 1, gen_cmd, ipv6_rd, str_wr, 0, INET6_ADDRSTRLEN, bind_ipv6_address, 1213 "bind_address_ipv6", "bind-address-ipv6" }, 1214 { 1, set_cmd, NULL, NULL, 0, 0, &disable_libevent, NULL, 1215 "no-libevent" }, 1216 { 1, gen_cmd, num_rd, num_wr, 0, 1, &download_utime, "download_utime", 1217 "download-utime" }, 1218 { 1, gen_cmd, num_rd, num_wr, 0, 999, &max_format_cache_entries, 1219 "format_cache_size", "format-cache-size" }, 1220 { 1, gen_cmd, num_rd, num_wr, 0, INT_MAX, &memory_cache_size, 1221 "memory_cache_size", "memory-cache-size" }, 1222 { 1, gen_cmd, num_rd, num_wr, 0, INT_MAX, &image_cache_size, 1223 "image_cache_size", "image-cache-size" }, 1224 { 1, gen_cmd, num_rd, num_wr, 0, INT_MAX, &font_cache_size, 1225 "font_cache_size", "font-cache-size" }, 1226 { 1, gen_cmd, num_rd, num_wr, 0, 1, &aggressive_cache, 1227 "http_bugs.aggressive_cache", "aggressive-cache" }, 1228 { 1, gen_cmd, num_rd, num_wr, 0, 4, &ipv6_options.addr_preference, 1229 "ipv6.address_preference", "address-preference" }, 1230 { 1, proxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.http_proxy, 1231 "http_proxy", "http-proxy" }, 1232 { 1, proxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.https_proxy, 1233 "https_proxy", "https-proxy" }, 1234 { 1, proxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.socks_proxy, 1235 "socks_proxy", "socks-proxy" }, 1236 { 1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, proxies.dns_append, 1237 "-append_text_to_dns_lookups", NULL }, /* old version incorrectly saved it with '-' */ 1238 { 1, noproxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.no_proxy, 1239 "no_proxy_domains", "no-proxy-domains" }, 1240 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.dns_append, 1241 "append_text_to_dns_lookups", "append-text-to-dns-lookups" }, 1242 { 1, gen_cmd, num_rd, num_wr, 0, 1, &proxies.only_proxies, 1243 "only_proxies", "only-proxies" }, 1244 { 1, gen_cmd, num_rd, num_wr, 0, 2, &ssl_options.certificates, 1245 "ssl.certificates", "ssl.certificates" }, 1246 { 1, gen_cmd, num_rd, num_wr, 0, 1, &ssl_options.built_in_certificates, 1247 "ssl.builtin_certificates", "ssl.builtin-certificates" }, 1248 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, 1249 &ssl_options.client_cert_key, "ssl.client_cert_key", 1250 "ssl.client-cert-key" }, 1251 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, 1252 &ssl_options.client_cert_crt, "ssl.client_cert_crt", 1253 "ssl.client-cert-crt" }, 1254 { 1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, 1255 &ssl_options.client_cert_password, NULL, "ssl.client-cert-password" }, 1256 { 1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, 1257 &ssl_options.client_cert_key, "client_cert_key", 1258 "http.client_cert_key" }, /* backward compatibility with Debian 1259 patches */ 1260 { 1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, 1261 &ssl_options.client_cert_crt, "client_cert_crt", 1262 "http.client_cert_crt" }, /* backward compatibility with Debian 1263 patches */ 1264 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.http10, 1265 "http_bugs.http10", "http-bugs.http10" }, 1266 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.allow_blacklist, 1267 "http_bugs.allow_blacklist", "http-bugs.allow-blacklist" }, 1268 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.no_accept_charset, 1269 "http_bugs.no_accept_charset", "http-bugs.bug-no-accept-charset" }, 1270 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.no_compression, 1271 "http_bugs.no_compression", "http-bugs.no-compression" }, 1272 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.retry_internal_errors, 1273 "http_bugs.retry_internal_errors", "http-bugs.retry-internal-errors" }, 1274 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.header.fake_firefox, 1275 "fake_firefox", "http.fake-firefox" }, 1276 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, 1277 &http_options.header.fake_useragent, "fake_useragent", 1278 "http.fake-user-agent" }, 1279 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, 1280 &http_options.header.extra_header, "http.extra_header", 1281 "http.extra-header" }, 1282 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, bookmarks_file, 1283 "bookmarks_file", "bookmarks-file" }, 1284 { 1, gen_cmd, num_rd, num_wr, 0, 1, &save_history, "save_url_history", 1285 "save-url-history" }, 1286 { 1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &display_red_gamma, 1287 "display_red_gamma", "display-red-gamma" }, 1288 { 1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &display_green_gamma, 1289 "display_green_gamma", "display-green-gamma" }, 1290 { 1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &display_blue_gamma, 1291 "display_blue_gamma", "display-blue-gamma" }, 1292 { 1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &user_gamma, "user_gamma", 1293 "user-gamma" }, 1294 { 1, gen_cmd, dbl_rd, dbl_wr, 25, 400, &bfu_aspect, "bfu_aspect", 1295 "bfu-aspect" }, 1296 { 1, gen_cmd, NULL, NULL, 0, 1, NULL, "aspect_on", NULL }, 1297 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dither_letters, "dither_letters", 1298 "dither-letters" }, 1299 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dither_images, "dither_images", 1300 "dither-images" }, 1301 { 1, gen_cmd, num_rd, num_wr, 0, 2, &gamma_bits, "gamma_correction", 1302 "gamma-correction" }, 1303 { 1, gen_cmd, num_rd, num_wr, 0, 1, &overwrite_instead_of_scroll, 1304 "overwrite_instead_of_scroll", "overwrite-instead-of-scroll" }, 1305 { 1, gen_cmd, cp_rd, NULL, 0, 0, &dds.assume_cp, "assume_codepage", 1306 NULL }, 1307 { 1, NULL, term_rd, term_wr, 0, 0, NULL, "terminal", NULL }, 1308 { 1, NULL, term2_rd, NULL, 0, 0, NULL, "terminal2", NULL }, 1309 { 1, NULL, type_rd, type_wr, 0, 0, NULL, "association", NULL }, 1310 { 1, NULL, ext_rd, ext_wr, 0, 0, NULL, "extension", NULL }, 1311 { 1, NULL, dp_rd, dp_wr, 0, 0, NULL, "video_driver", NULL }, 1312 { 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL }, 1313 }; 1314 1315 static struct option html_options[] = { 1316 {1, gen_cmd, cp_rd, cp_wr, 0, 0, &dds.assume_cp, 1317 "html_assume_codepage", "html-assume-codepage" }, 1318 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.hard_assume, 1319 "html_hard_assume", "html-hard-assume" }, 1320 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.tables, "html_tables", 1321 "html-tables" }, 1322 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.frames, "html_frames", 1323 "html-frames" }, 1324 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.break_long_lines, 1325 "html_break_long_lines", "html-break-long-lines" }, 1326 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.images, "html_images", 1327 "html-images" }, 1328 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.image_names, 1329 "html_image_names", "html-image-names" }, 1330 { 1, gen_cmd, num_rd, num_wr, 0, 9, &dds.margin, "html_margin", 1331 "html-margin" }, 1332 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.num_links, 1333 "html_numbered_links", "html-numbered-links" }, 1334 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.table_order, 1335 "html_table_order", "html-table-order" }, 1336 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.auto_refresh, 1337 "html_auto_refresh", "html-auto-refresh" }, 1338 { 1, gen_cmd, num_rd, num_wr, 1, MAX_FONT_SIZE, &dds.font_size, 1339 "html_font_size", "html-user-font-size" }, 1340 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.display_images, 1341 "html_display_images", "html-display-images" }, 1342 { 1, gen_cmd, num_rd, num_wr, 1, 999, &dds.image_scale, 1343 "html_image_scale", "html-image-scale" }, 1344 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.porn_enable, 1345 "html_bare_image_autoscale", "html-bare-image-autoscale" }, 1346 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.target_in_new_window, 1347 "html_target_in_new_window", "html-target-in-new-window" }, 1348 { 1, gen_cmd, num_rd, num_wr, 0, 15, &dds.t_text_color, 1349 "html_text_color", "html-text-color" }, 1350 { 1, gen_cmd, num_rd, num_wr, 0, 15, &dds.t_link_color, 1351 "html_link_color", "html-link-color" }, 1352 { 1, gen_cmd, num_rd, num_wr, 0, 7, &dds.t_background_color, 1353 "html_background_color", "html-background-color" }, 1354 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.t_ignore_document_color, 1355 "html_ignore_document_color", "html-ignore-document-color" }, 1356 { 1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &dds.g_text_color, 1357 "html_g_text_color", "html-g-text-color" }, 1358 { 1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &dds.g_link_color, 1359 "html_g_link_color", "html-g-link-color" }, 1360 { 1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &dds.g_background_color, 1361 "html_g_background_color", "html-g-background-color" }, 1362 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.g_ignore_document_color, 1363 "html_g_ignore_document_color", "html-g-ignore-document-color"}, 1364 { 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL }, 1365 }; 1366 1367 static struct option *all_options[] = { 1368 links_options, 1369 html_options, 1370 NULL, 1371 }; 1372 1373 unsigned char * 1374 parse_options(int argc, char *argv[]) 1375 { 1376 int i; 1377 unsigned char **u_argv, *ret; 1378 if ((argc * sizeof(unsigned char *)) > INT_MAX) 1379 overalloc(); 1380 u_argv = xmalloc(argc * sizeof(unsigned char *)); 1381 for (i = 0; i < argc; i++) 1382 u_argv[i] = cast_uchar argv[i]; 1383 ret = p_arse_options(argc, u_argv, all_options); 1384 free(u_argv); 1385 return ret; 1386 } 1387 1388 static void 1389 load_config_file(unsigned char *prefix, unsigned char *name) 1390 { 1391 unsigned char *c, *config_file; 1392 config_file = stracpy(prefix); 1393 if (!config_file) 1394 return; 1395 add_to_strn(&config_file, name); 1396 if ((c = read_config_file(config_file))) 1397 goto ok; 1398 free(config_file); 1399 config_file = stracpy(prefix); 1400 if (!config_file) 1401 return; 1402 add_to_strn(&config_file, cast_uchar "."); 1403 add_to_strn(&config_file, name); 1404 if ((c = read_config_file(config_file))) 1405 goto ok; 1406 free(config_file); 1407 return; 1408 ok: 1409 parse_config_file(config_file, c, all_options); 1410 free(c); 1411 free(config_file); 1412 } 1413 1414 void 1415 load_config(void) 1416 { 1417 #ifdef SHARED_CONFIG_DIR 1418 load_config_file(cast_uchar SHARED_CONFIG_DIR, cast_uchar "links.cfg"); 1419 #endif 1420 load_config_file(links_home, cast_uchar "links.cfg"); 1421 load_config_file(links_home, cast_uchar "html.cfg"); 1422 load_config_file(links_home, cast_uchar "user.cfg"); 1423 } 1424 1425 void 1426 write_config(struct terminal *term) 1427 { 1428 write_config_data(links_home, cast_uchar "links.cfg", links_options, 1429 term); 1430 } 1431 1432 void 1433 write_html_config(struct terminal *term) 1434 { 1435 write_config_data(links_home, cast_uchar "html.cfg", html_options, 1436 term); 1437 } 1438 1439 void 1440 load_url_history(void) 1441 { 1442 unsigned char *history_file, *hs; 1443 unsigned char *hsp; 1444 1445 if (anonymous) 1446 return; 1447 /* Must have been called after init_home */ 1448 if (!links_home) 1449 return; 1450 history_file = stracpy(links_home); 1451 add_to_strn(&history_file, cast_uchar "links.his"); 1452 hs = read_config_file(history_file); 1453 free(history_file); 1454 if (!hs) 1455 return; 1456 for (hsp = hs; *hsp;) { 1457 unsigned char *hsl, *hsc; 1458 for (hsl = hsp; *hsl && *hsl != 10 && *hsl != 13; hsl++) 1459 ; 1460 hsc = memacpy(hsp, hsl - hsp); 1461 add_to_history(NULL, &goto_url_history, hsc); 1462 free(hsc); 1463 hsp = hsl; 1464 while (*hsp == 10 || *hsp == 13) 1465 hsp++; 1466 } 1467 free(hs); 1468 } 1469 1470 void 1471 save_url_history(void) 1472 { 1473 struct history_item *hi = NULL; 1474 struct list_head *lhi; 1475 unsigned char *history_file; 1476 unsigned char *hs = NULL; 1477 size_t hsl = 0; 1478 if (anonymous || !save_history || proxies.only_proxies) 1479 return; 1480 1481 /* Must have been called after init_home */ 1482 if (!links_home) 1483 return; 1484 history_file = stracpy(links_home); 1485 add_to_strn(&history_file, cast_uchar "links.his"); 1486 foreachback (struct history_item, hi, lhi, goto_url_history.items) { 1487 if (!*hi->str || hi->str[0] == ' ' 1488 || strchr(cast_const_char hi->str, 10) 1489 || strchr(cast_const_char hi->str, 13)) 1490 continue; 1491 if (!url_not_saveable(hi->str)) { 1492 hsl = add_to_str(&hs, hsl, hi->str); 1493 hsl = add_chr_to_str(&hs, hsl, '\n'); 1494 } 1495 } 1496 write_to_config_file(history_file, hs, 0); 1497 free(history_file); 1498 free(hs); 1499 return; 1500 }