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 "links.h"
9 
10 #ifdef HAIKU
11 #include <FindDirectory.h>
12 #endif
13 
14 unsigned char system_name[MAX_STR_LEN];
15 
get_system_name(void)16 static void get_system_name(void)
17 {
18 #ifdef OS2
19 	if (!os_get_system_name(system_name))
20 		return;
21 #endif
22 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
23 	{
24 		struct utsname name;
25 		int rs;
26 		memset(&name, 0, sizeof name);
27 		EINTRLOOP(rs, uname(&name));
28 		if (rs >= 0) {
29 #ifdef OPENVMS
30 			unsigned char * volatile p;
31 #endif
32 			unsigned char *str = init_str();
33 			int l = 0;
34 			add_to_str(&str, &l, cast_uchar name.sysname);
35 			add_chr_to_str(&str, &l, ' ');
36 #ifdef OPENVMS
37 			add_to_str(&str, &l, cast_uchar name.version);
38 #else
39 			add_to_str(&str, &l, cast_uchar name.release);
40 #endif
41 			add_chr_to_str(&str, &l, ' ');
42 #ifdef OPENVMS
43 			p = cast_uchar name.nodename + sizeof(name.nodename);
44 			if ((unsigned char *)(&name + 1) - p >= 16 && memchr(cast_const_char p, 0, 16))
45 				add_to_str(&str, &l, cast_uchar p);
46 			else
47 #endif
48 			add_to_str(&str, &l, cast_uchar name.machine);
49 			safe_strncpy(system_name, str, MAX_STR_LEN);
50 			mem_free(str);
51 			return;
52 		}
53 	}
54 #endif
55 #ifdef HAVE_POPEN
56 	/*if (0) {
57 		FILE *f;
58 		unsigned char *p;
59 		memset(system_name, 0, MAX_STR_LEN);
60 		ENULLLOOP(f, popen("uname -srm", "r"));
61 		if (!f) goto fail;
62 		if (!fread(system_name, 1, MAX_STR_LEN - 1, f)) {
63 			pclose(f);
64 			goto fail;
65 		}
66 		pclose(f);
67 		for (p = system_name; *p; p++) if (*p < ' ') {
68 			*p = 0;
69 			break;
70 		}
71 		if (system_name[0]) return;
72 	}
73 	fail:*/
74 #endif
75 	strcpy(cast_char system_name, SYSTEM_NAME);
76 }
77 
78 unsigned char compiler_name[MAX_STR_LEN];
79 
get_compiler_name(void)80 static void get_compiler_name(void)
81 {
82 #if defined(__BORLANDC__)
83 
84 	int w = __BORLANDC__+0;
85 	int v1 = w / 0x100;
86 	int v2 = w / 0x10 % 0x10;
87 	int v3 = w % 0x10;
88 	if (v1 == 4 && v2 < 5) v1 = 3;
89 	if (v1 == 4 && v2 == 5) v2 = 0;
90 
91 	if (!v3) sprintf(cast_char compiler_name, "Borland C %d.%d", v1, v2);
92 	else sprintf(cast_char compiler_name, "Borland C %d.%d.%d", v1, v2, v3);
93 
94 #elif defined(__clang__)
95 
96 #if !defined(__clang_major__) || !defined(__clang_minor__)
97 	sprintf(cast_char compiler_name, "LLVM/Clang");
98 #else
99 	int v1 = __clang_major__+0;
100 	int v2 = __clang_minor__+0;
101 #ifdef __clang_patchlevel__
102 	int v3 = __clang_patchlevel__+0;
103 #else
104 	int v3 = 0;
105 #endif
106 	if (v3 > 0) sprintf(cast_char compiler_name, "LLVM/Clang %d.%d.%d", v1, v2, v3);
107 	else sprintf(cast_char compiler_name, "LLVM/Clang %d.%d", v1, v2);
108 #endif
109 
110 #elif defined(__COMO_VERSION__)
111 
112 	int w = __COMO_VERSION__+0;
113 	int v1 = w / 100;
114 	int v2 = w % 100;
115 	if (!(v2 % 10)) sprintf(cast_char compiler_name, "Comeau C %d.%d", v1, v2 / 10);
116 	else sprintf(cast_char compiler_name, "Comeau C %d.%02d", v1, v2);
117 
118 #elif defined(__convexc__)
119 
120 	sprintf(cast_char compiler_name, "Convex C");
121 
122 #elif defined(_CRAYC)
123 
124 #if !defined(_RELEASE) || !defined(_RELEASE_MINOR)
125 	sprintf(cast_char compiler_name, "Cray C");
126 #else
127 	int v1 = _RELEASE+0;
128 	int v2 = _RELEASE_MINOR+0;
129 	sprintf(cast_char compiler_name, "Cray C %d.%d", v1, v2);
130 #endif
131 
132 #elif defined(__DCC__)
133 
134 #ifndef __VERSION_NUMBER__
135 	sprintf(cast_char compiler_name, "Diab C");
136 #else
137 	int w = __VERSION_NUMBER__+0;
138 	int v1 = w / 1000;
139 	int v2 = w / 100 % 10;
140 	int v3 = w % 100;
141 	sprintf(cast_char compiler_name, "Diab C %d.%d.%02d", v1, v2, v3);
142 #endif
143 
144 #elif defined(__DMC__)
145 
146 	int w = __DMC__+0;
147 	int v1 = w / 0x100;
148 	int v2 = w / 0x10 % 0x10;
149 	int v3 = w % 0x10;
150 	if (!v3) sprintf(cast_char compiler_name, "Digital Mars C %d.%d", v1, v2);
151 	else sprintf(cast_char compiler_name, "Digital Mars C %d.%d.%d", v1, v2, v3);
152 
153 #elif defined(__DECC_VER)
154 
155 	int w = __DECC_VER+0;
156 	int v1 = w / 10000000;
157 	int v2 = w / 100000 % 100;
158 	int v3 = w % 10000;
159 	sprintf(cast_char compiler_name, "DEC C %d.%d-%03d", v1, v2, v3);
160 
161 #elif defined(__ghs__)
162 
163 #ifndef __GHS_VERSION_NUMBER__
164 	sprintf(cast_char compiler_name, "Green Hill C");
165 #else
166 	int w = __GHS_VERSION_NUMBER__+0;
167 	int v1 = w / 100;
168 	int v2 = w / 10 % 10;
169 	int v3 = w % 10;
170 	sprintf(cast_char compiler_name, "Green Hill C %d.%d.%d", v1, v2, v3);
171 #endif
172 
173 #elif defined(__HIGHC__)
174 
175 	sprintf(cast_char compiler_name, "MetaWare High C");
176 
177 #elif defined(__HP_cc)
178 
179 	int w = __HP_cc+0;
180 	int v1 = w / 10000;
181 	int v2 = w / 100 % 100;
182 	int v3 = w % 100;
183 	if (w <= 1) sprintf(cast_char compiler_name, "HP CC");
184 	else sprintf(cast_char compiler_name, "HP CC %d.%02d.%02d", v1, v2, v3);
185 
186 #elif defined(__xlc__)
187 
188 	int w = __xlc__+0;
189 	int v1 = w / 0x100;
190 	int v2 = w % 0x100;
191 	sprintf(cast_char compiler_name, "IBM XL C %X.%X", v1, v2);
192 
193 #elif defined(__IBMC__) && defined(__COMPILER_VER__)
194 
195 	unsigned w = __COMPILER_VER__+0;
196 	int v0 = w / 0x10000000;
197 	int v1 = w / 0x1000000 % 0x10;
198 	int v2 = w / 0x10000 % 0x100;
199 	int v3 = w % 0x10000;
200 	unsigned char *os = !v0 ? "S/370" : v0 == 1 ? "OS/390" : v0 == 4 ? "z/OS" : "";
201 	sprintf(cast_char compiler_name, "IBM%s%s XL C %X.%0X.%X", *os ? " " : "", os, v1, v2, v3);
202 
203 #elif defined(__ICC)
204 
205 	int w = __ICC+0;
206 	int v1 = w / 100;
207 	int v2 = w % 100;
208 	if (!(v2 % 10)) sprintf(cast_char compiler_name, "Intel C %d.%d", v1, v2 / 10);
209 	else sprintf(cast_char compiler_name, "Intel C %d.%02d", v1, v2);
210 
211 #elif defined(__LCC__)
212 
213 	sprintf(cast_char compiler_name, "LCC");
214 
215 #elif defined(__NDPC__)
216 
217 	sprintf(cast_char compiler_name, "Microway NDP C");
218 
219 #elif defined(_MSC_VER)
220 
221 	int w = _MSC_VER+0;
222 	int v1 = w / 100;
223 	int v2 = w % 100;
224 	unsigned char *visual = cast_uchar "";
225 	if (v1 >= 8) {
226 		v1 -= 6;
227 		if (v1 == 2) v1 = 1;
228 		visual = cast_uchar "Visual ";
229 	}
230 	if (!(v2 % 10)) sprintf(cast_char compiler_name, "Microsoft %sC %d.%d", visual, v1, v2 / 10);
231 	else sprintf(cast_char compiler_name, "Microsoft %sC %d.%02d", visual, v1, v2);
232 
233 #elif defined(__MWERKS__)
234 
235 	int w = __MWERKS__+0;
236 	int v1 = w / 0x1000;
237 	int v2 = w / 0x100 % 0x10;
238 	int v3 = w % 0x100;
239 	if (w <= 1) sprintf(cast_char compiler_name, "Metrowerks CodeWarrior");
240 	sprintf(cast_char compiler_name, "Metrowerks CodeWarrior %x.%x.%x", v1, v2, v3);
241 
242 #elif defined(__NWCC__)
243 
244 	sprintf(cast_char compiler_name, "NWCC");
245 
246 #elif defined(__OPEN64__)
247 
248 	unsigned char *n = cast_uchar "Open64 " __OPEN64__;
249 	if (strlen(cast_const_char n) >= sizeof(cast_char compiler_name)) n = cast_uchar "Open64";
250 	strcpy(cast_char compiler_name, cast_const_char n);
251 
252 #elif defined(__PATHSCALE__)
253 
254 	unsigned char *n = cast_uchar "PathScale " __PATHSCALE__;
255 	if (strlen(cast_const_char n) >= sizeof(cast_char compiler_name)) n = cast_uchar "PathScale";
256 	strcpy(cast_char compiler_name, cast_const_char n);
257 
258 #elif defined(__PCC__)
259 
260 	int v1 = __PCC__+0;
261 #ifdef __PCC_MINOR__
262 	int v2 = __PCC_MINOR__+0;
263 #else
264 	int v2 = 0;
265 #endif
266 #ifdef __PCC_MINORMINOR__
267 	int v3 = __PCC_MINORMINOR__+0;
268 #else
269 	int v3 = 0;
270 #endif
271 	sprintf(cast_char compiler_name, "PCC %d.%d.%d", v1, v2, v3);
272 
273 #elif defined(__PGI) || defined(__PGIC__)
274 
275 #if !defined(__PGIC__) || !defined(__PGIC_MINOR__)
276 	sprintf(cast_char compiler_name, "The Portland Group C");
277 #else
278 	int v1 = __PGIC__+0;
279 	int v2 = __PGIC_MINOR__+0;
280 #ifdef __PGIC_PATCHLEVEL__
281 	int v3 = __PGIC_PATCHLEVEL__+0;
282 #else
283 	int v3 = 0;
284 #endif
285 	if (v3 > 0) sprintf(cast_char compiler_name, "The Portland Group C %d.%d.%d", v1, v2, v3);
286 	else sprintf(cast_char compiler_name, "The Portland Group C %d.%d", v1, v2);
287 #endif
288 
289 #elif defined(__SASC__)
290 
291 	int w = __SASC__+0;
292 	int v1 = w / 100;
293 	int v2 = w % 100;
294 	sprintf(cast_char compiler_name, "SAS C %d.%02d", v1, v2);
295 
296 #elif (defined(__sgi) && defined(_COMPILER_VERSION)) || defined(_SGI_COMPILER_VERSION)
297 
298 #ifdef _SGI_COMPILER_VERSION
299 	int w = _SGI_COMPILER_VERSION;
300 #else
301 	int w = _COMPILER_VERSION;
302 #endif
303 	int v1 = w / 100;
304 	int v2 = w / 10 % 10;
305 	int v3 = w % 10;
306 	sprintf(cast_char compiler_name, "MIPSpro %d.%d.%d", v1, v2, v3);
307 
308 #elif defined(__SUNPRO_C)
309 
310 	int w = __SUNPRO_C+0;
311 	int div = w >= 0x1000 ? 0x1000 : 0x100;
312 	int v2_digits = w >= 0x1000 ? 2 : 1;
313 	int v1 = w / div;
314 	int v2 = w % div / 0x10;
315 	int v3 = w % 0x10;
316 	if (!v3) sprintf(cast_char compiler_name, "Sun C %X.%0*X", v1, v2_digits, v2);
317 	else sprintf(cast_char compiler_name, "Sun C %X.%0*X.%X", v1, v2_digits, v2, v3);
318 
319 #elif defined(__SYSC__) && defined(__SYSC_VER__)
320 
321 	int w = __SYSC_VER__+0;
322 	int v1 = w / 10000;
323 	int v2 = w / 100 % 100;
324 	int v3 = w % 100;
325 	sprintf(cast_char compiler_name, "Dignus Systems C %d.%02d.%02d", v1, v2, v3);
326 
327 #elif defined(__TenDRA__)
328 
329 	sprintf(cast_char compiler_name, "TenDRA C");
330 
331 #elif defined(__TINYC__)
332 
333 	sprintf(cast_char compiler_name, "Tiny C");
334 
335 #elif defined(_UCC)
336 
337 #if !defined(_MAJOR_REV) || !defined(_MINOR_REV)
338 	sprintf(cast_char compiler_name, "Ultimate C");
339 #else
340 	int v1 = _MAJOR_REV+0;
341 	int v2 = _MAJOR_REV+0;
342 	sprintf(cast_char compiler_name, "Ultimate C %d.%d", v1, v2);
343 #endif
344 
345 #elif defined(__USLC__)
346 
347 	sprintf(cast_char compiler_name, "USL C");
348 
349 #elif defined(__VAXC)
350 
351 	sprintf(cast_char compiler_name, "VAX C");
352 
353 #elif defined(__VOSC__)
354 
355 	sprintf(cast_char compiler_name, "Stratus VOS C");
356 
357 #elif defined(__WATCOMC__)
358 
359 	int w = __WATCOMC__+0;
360 	int v1 = w / 100;
361 	int v2 = w % 100;
362 	unsigned char *op = cast_uchar "";
363 	if (v1 >= 12) {
364 		v1 -= 11;
365 		op = cast_uchar "Open";
366 	}
367 	if (!(v2 % 10)) sprintf(cast_char compiler_name, "%sWatcom C %d.%d", op, v1, v2 / 10);
368 	else sprintf(cast_char compiler_name, "%sWatcom C %d.%02d", op, v1, v2);
369 
370 #elif defined(__GNUC__)
371 
372 	int v1 = __GNUC__+0;
373 #ifdef __GNUC_MINOR__
374 	int v2 = __GNUC_MINOR__+0;
375 #else
376 	int v2 = -1;
377 #endif
378 #ifdef __GNUC_PATCHLEVEL__
379 	int v3 = __GNUC_PATCHLEVEL__+0;
380 #else
381 	int v3 = 0;
382 #endif
383 #if defined(__llvm__)
384 	unsigned char *prefix = cast_uchar "LLVM/";
385 #else
386 	unsigned char *prefix = cast_uchar "";
387 #endif
388 	if (v1 == 2 && (v2 >= 90 && v2 <= 91)) sprintf(cast_char compiler_name, "%sEGCS 1.%d", prefix, v2 - 90);
389 	else if (v3 > 0 && v2 >= 0) sprintf(cast_char compiler_name, "%sGNU C %d.%d.%d", prefix, v1, v2, v3);
390 	else if (v2 >= 0) sprintf(cast_char compiler_name, "%sGNU C %d.%d", prefix, v1, v2);
391 	else sprintf(cast_char compiler_name, "%sGNU C %d", prefix, v1);
392 
393 #else
394 
395 	strcpy(cast_char compiler_name, "unknown compiler");
396 
397 #endif
398 }
399 
do_exit(int x)400 static void do_exit(int x)
401 {
402 	/* avoid compiler warnings about unreachable code */
403 	if (value_1()) exit(x);
404 }
405 
406 struct option {
407 	int p;
408 	unsigned char *(*rd_cmd)(struct option *, unsigned char ***, int *);
409 	unsigned char *(*rd_cfg)(struct option *, unsigned char *);
410 	void (*wr_cfg)(struct option *, unsigned char **, int *);
411 	int min, max;	/* for double min and max are in 1/100's (e.g. 0.1 is min==10) */
412 	void *ptr;
413 	char *cfg_name;
414 	char *cmd_name;
415 };
416 
p_arse_options(int argc,unsigned char * argv[],struct option ** opt)417 static unsigned char *p_arse_options(int argc, unsigned char *argv[], struct option **opt)
418 {
419 	unsigned char *e, *u = NULL;
420 	int i;
421 	for (i = 0; i < argc; i++) {
422 		if (strlen(cast_const_char argv[i]) >= MAXINT) {
423 			fprintf(stderr, "Too long parameter\n");
424 			return NULL;
425 		}
426 	}
427 	while (argc) {
428 		argv++, argc--;
429 		if (argv[-1][0] == '-') {
430 			struct option *options;
431 			struct option **op;
432 			for (op = opt; (options = *op); op++) for (i = 0; options[i].p; i++)
433 				if (options[i].rd_cmd && options[i].cmd_name &&
434 				    !casestrcmp(cast_uchar options[i].cmd_name, &argv[-1][1])) {
435 					if ((e = options[i].rd_cmd(&options[i], &argv, &argc))) {
436 						if (e[0]) fprintf(stderr, "Error parsing option %s: %s\n", argv[-1], e);
437 						return NULL;
438 					}
439 					goto found;
440 				}
441 			uu:
442 #ifdef GRDRV_DIRECTFB
443 			if (!strncmp(cast_const_char argv[-1], "--dfb:", 6))
444 				goto found;
445 #endif
446 			fprintf(stderr, "Unknown option %s\n", argv[-1]);
447 			return NULL;
448 		} else if (!u) u = argv[-1];
449 		else goto uu;
450 		found:;
451 	}
452 	if (u) return u;
453 	return cast_uchar "";
454 }
455 
get_token(unsigned char ** line)456 unsigned char *get_token(unsigned char **line)
457 {
458 	unsigned char *s = NULL;
459 	int l = 0;
460 	int escape = 0;
461 	int quote = 0;
462 
463 	while (**line == ' ' || **line == 9) (*line)++;
464 	if (**line) {
465 		for (s = init_str(); **line; (*line)++) {
466 			if (escape)
467 				escape = 0;
468 			else if (**line == '\\') {
469 				escape = 1;
470 				continue;
471 			}
472 			else if (**line == '"') {
473 				quote = !quote;
474 				continue;
475 			}
476 			else if ((**line == ' ' || **line == 9) && !quote)
477 				break;
478 			add_chr_to_str(&s, &l, **line);
479 		}
480 	}
481 	return s;
482 }
483 
get_token_num(unsigned char ** line,int min,int max,int * result)484 static int get_token_num(unsigned char **line, int min, int max, int *result)
485 {
486 	long l;
487 	unsigned char *end;
488 	unsigned char *t = get_token(line);
489 	if (!t) return -1;
490 	l = strtolx(t, &end);
491 	if (*end || end == t || l < min || l > max) {
492 		mem_free(t);
493 		return -2;
494 	}
495 	mem_free(t);
496 	*result = (int)l;
497 	return 0;
498 }
499 
parse_config_file(unsigned char * name,unsigned char * file,struct option ** opt)500 static void parse_config_file(unsigned char *name, unsigned char *file, struct option **opt)
501 {
502 	struct option *options;
503 	struct option **op;
504 	int err = 0;
505 	int line = 0;
506 	unsigned char *e;
507 	int i;
508 	unsigned char *n, *p;
509 	unsigned char *tok;
510 	int nl, pl;
511 	while (file[0]) {
512 		line++;
513 		while (file[0] && (file[0] == ' ' || file[0] == 9)) file++;
514 		n = file;
515 		while (file[0] && file[0] > ' ') file++;
516 		if (file == n) {
517 			if (file[0]) file++;
518 			continue;
519 		}
520 		while (file[0] == 9 || file[0] == ' ') file++;
521 		p = file;
522 		while (file[0] && file[0] != 10 && file[0] != 13) file++;
523 		pl = (int)(file - p);
524 		if (file[0]) {
525 			if ((file[1] == 10 || file[1] == 13) && file[0] != file[1]) file++;
526 			file++;
527 		}
528 		tok = NULL;
529 		if (n[0] == '#') goto f;
530 		if (!(tok = get_token(&n))) goto f;
531 		nl = (int)strlen(cast_const_char tok);
532 		for (op = opt; (options = *op); op++)
533 			for (i = 0; options[i].p; i++) if (options[i].cfg_name && (size_t)nl == strlen(cast_const_char options[i].cfg_name) && !casecmp(tok, cast_uchar options[i].cfg_name, nl)) {
534 				unsigned char *o = memacpy(p, pl);
535 				if (options[i].rd_cfg && (e = options[i].rd_cfg(&options[i], o))) {
536 					if (e[0]) fprintf(stderr, "Error parsing config file %s, line %d: %s\n", name, line, e), err = 1;
537 				}
538 				mem_free(o);
539 				goto f;
540 			}
541 		fprintf(stderr, "Unknown option in config file %s, line %d\n", name, line);
542 		err = 1;
543 		f:
544 		if (tok) mem_free(tok);
545 	}
546 	if (err) fprintf(stderr, "\007"), portable_sleep(1000);
547 }
548 
create_config_string(struct option * options)549 static unsigned char *create_config_string(struct option *options)
550 {
551 	unsigned char *s = init_str();
552 	int l = 0;
553 	int i;
554 	add_to_str(&s, &l, cast_uchar "# This file is automatically generated by Links -- please do not edit.");
555 #if defined(__DECC_VER) && !defined(OPENVMS)
556 	do_not_optimize_here(&options);
557 #endif
558 	for (i = 0; options[i].p; i++) {
559 		if (options[i].wr_cfg)
560 			options[i].wr_cfg(&options[i], &s, &l);
561 	}
562 	add_to_str(&s, &l, cast_uchar NEWLINE);
563 	return s;
564 }
565 
read_config_file(unsigned char * name)566 unsigned char *read_config_file(unsigned char *name)
567 {
568 	int h, r;
569 	int l = 0;
570 	unsigned char *cfg_buffer, *s;
571 	int rs;
572 	h = c_open(name, O_RDONLY | O_NOCTTY);
573 	if (h == -1) return NULL;
574 	s = init_str();
575 	cfg_buffer = mem_alloc(page_size);
576 	while ((r = hard_read(h, cfg_buffer, page_size)) > 0) {
577 		int i;
578 		for (i = 0; i < r; i++) if (!cfg_buffer[i]) cfg_buffer[i] = ' ';
579 		add_bytes_to_str(&s, &l, cfg_buffer, r);
580 	}
581 	mem_free(cfg_buffer);
582 	if (r == -1) mem_free(s), s = NULL;
583 	EINTRLOOP(rs, close(h));
584 	return s;
585 }
586 
delete_config_file(unsigned char * name)587 void delete_config_file(unsigned char *name)
588 {
589 	int rs;
590 #if defined(OPENVMS)
591 	/* delete all versions of the file */
592 	int count = 0;
593 	do {
594 		EINTRLOOP(rs, unlink(cast_const_char name));
595 	} while (!rs && ++count < 65536);
596 #else
597 	EINTRLOOP(rs, unlink(cast_const_char name));
598 #endif
599 }
600 
write_to_config_file(unsigned char * name,unsigned char * c,int do_sync)601 int write_to_config_file(unsigned char *name, unsigned char *c, int do_sync)
602 {
603 	int rr;
604 	int h, w;
605 	int count = 0;
606 	int tmp_namel;
607 	unsigned char *tmp_name;
608 	int rs, err;
609 try_new_count:
610 	tmp_namel = 0;
611 	tmp_name = init_str();
612 	add_to_str(&tmp_name, &tmp_namel, name);
613 	for (w = tmp_namel - 1; w >= 0; w--) {
614 		if (dir_sep(tmp_name[w]))
615 			break;
616 		if (tmp_name[w] == '.') {
617 			if (w <= tmp_namel - 2) {
618 				tmp_name[w + 2] = 0;
619 				tmp_namel = w + 2;
620 			}
621 			break;
622 		}
623 	}
624 	add_num_to_str(&tmp_name, &tmp_namel, count);
625 	h = c_open3(tmp_name, O_WRONLY | O_NOCTTY | O_CREAT | O_TRUNC | O_EXCL, 0600);
626 	if (h == -1) {
627 		err = errno;
628 		if (err == EEXIST && count < MAXINT) {
629 			count++;
630 			mem_free(tmp_name);
631 			goto try_new_count;
632 		}
633 		goto free_err;
634 	}
635 	rr = (int)strlen(cast_const_char c);
636 	if (hard_write(h, c, rr) != rr) {
637 		err = errno;
638 		goto close_unlink_err;
639 	}
640 	if (do_sync) {
641 		EINTRLOOP(rs, fsync(h));
642 		if (rs) {
643 			err = errno;
644 			goto close_unlink_err;
645 		}
646 #ifdef DOS
647 		_flush_disk_cache();
648 #endif
649 	}
650 	EINTRLOOP(rs, close(h));
651 	if (rs) {
652 		err = errno;
653 		goto unlink_err;
654 	}
655 #if defined(OPENVMS) || !defined(RENAME_OVER_EXISTING_FILES)
656 	delete_config_file(name);
657 #endif
658 	EINTRLOOP(rs, rename(cast_const_char tmp_name, cast_const_char name));
659 	if (rs) {
660 		err = errno;
661 		goto unlink_err;
662 	}
663 	mem_free(tmp_name);
664 	if (do_sync) {
665 #if defined(DOS)
666 		_flush_disk_cache();
667 #elif !defined(OS2) && !defined(OPENVMS)
668 		unsigned char *e, *le;
669 		tmp_name = stracpy(name);
670 		le = tmp_name;
671 		for (e = tmp_name; *e; e++) if (dir_sep(*e)) le = e;
672 		while (le > tmp_name && dir_sep(le[-1])) le--;
673 		if (le == tmp_name && dir_sep(*le)) le++;
674 #ifdef DOS_FS
675 		if (le - tmp_name <= 2 && upcase(tmp_name[0]) >= 'A' && upcase(tmp_name[0]) <= 'Z' && tmp_name[1] == ':') {
676 			if (dir_sep(tmp_name[2]))
677 				le = tmp_name + 3;
678 			else
679 				le = tmp_name + 2;
680 		}
681 #endif
682 		*le = 0;
683 
684 		h = c_open(*tmp_name ? tmp_name : cast_uchar ".", O_RDONLY | O_NOCTTY);
685 		if (h != -1) {
686 			EINTRLOOP(rs, fsync(h));
687 			EINTRLOOP(rs, close(h));
688 		}
689 		mem_free(tmp_name);
690 #endif
691 	}
692 
693 	return 0;
694 
695 	close_unlink_err:
696 	EINTRLOOP(rs, close(h));
697 	unlink_err:
698 	EINTRLOOP(rs, unlink(cast_const_char tmp_name));
699 	free_err:
700 	mem_free(tmp_name);
701 	return get_error_from_errno(err);
702 }
703 
704 #ifdef OPENVMS
translate_vms_to_unix(unsigned char ** str)705 static void translate_vms_to_unix(unsigned char **str)
706 {
707 	unsigned char *n;
708 	if (!*str || strchr(cast_const_char *str, '/')) return;
709 	n = cast_uchar decc$translate_vms(cast_const_char *str);
710 	if (!n || (my_intptr_t)n == -1) return;
711 	mem_free(*str);
712 	*str = stracpy(n);
713 }
714 #endif
715 
get_home(int * n)716 static unsigned char *get_home(int *n)
717 {
718 	struct stat st;
719 	int rs;
720 	unsigned char *home;
721 	unsigned char *home_links;
722 	unsigned char *config_dir;
723 
724 	EINTRLOOP(rs, stat(".", &st));
725 	if (rs && (home = cast_uchar getenv("HOME")))
726 		EINTRLOOP(rs, chdir(cast_const_char home));
727 	home = NULL;
728 
729 	config_dir = stracpy(cast_uchar getenv("CONFIG_DIR"));
730 
731 	if (n) *n = 1;
732 #ifdef WIN
733 	if (!home) {
734 		home = stracpy(cast_uchar getenv("APPDATA"));
735 #ifdef HAVE_CYGWIN_CONV_PATH
736 		/*
737 		 * Newer Cygwin complains about windows-style path, so
738 		 * we have to convert it.
739 		 */
740 		if (home) {
741 			unsigned char *new_path;
742 			ssize_t sz = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, home, NULL, 0);
743 			if (sz < 0 || sz >= MAXINT)
744 				goto skip_path_conv;
745 			new_path = mem_alloc(sz);
746 			sz = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, home, new_path, sz);
747 			if (sz < 0) {
748 				mem_free(new_path);
749 				goto skip_path_conv;
750 			}
751 			mem_free(home);
752 			home = new_path;
753 skip_path_conv:;
754 		}
755 #endif
756 		if (home) {
757 			EINTRLOOP(rs, stat(cast_const_char home, &st));
758 			if (rs || !S_ISDIR(st.st_mode)) {
759 				mem_free(home);
760 				home = NULL;
761 			}
762 		}
763 	}
764 #endif
765 #ifdef HAIKU
766 	home = mem_alloc(B_FILE_NAME_LENGTH);
767 	if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, 1, cast_char home, B_FILE_NAME_LENGTH) != B_OK) {
768 		mem_free(home);
769 		home = NULL;
770 	}
771 #endif
772 	if (!home) home = stracpy(cast_uchar getenv("HOME"));
773 #ifdef WIN
774 /* When we run in Cygwin without Cygwin environment, it reports home "/".
775    Unfortunatelly, it can't write anything to that directory */
776 	if (home && !strcmp(cast_const_char home, "/")) {
777 		mem_free(home);
778 		home = NULL;
779 	}
780 #endif
781 #ifdef OPENVMS
782 	if (!home) home = stracpy(cast_uchar "/SYS$LOGIN");
783 	translate_vms_to_unix(&home);
784 	translate_vms_to_unix(&config_dir);
785 #endif
786 	if (!home) {
787 		int i;
788 		home = stracpy(path_to_exe);
789 		if (!home) {
790 			if (config_dir) mem_free(config_dir);
791 			return NULL;
792 		}
793 		for (i = (int)strlen(cast_const_char home) - 1; i >= 0; i--) if (dir_sep(home[i])) {
794 			home[i + 1] = 0;
795 			goto br;
796 		}
797 		home[0] = 0;
798 		br:;
799 	}
800 	while (home[0] && home[1] && dir_sep(home[strlen(cast_const_char home) - 1])) home[strlen(cast_const_char home) - 1] = 0;
801 	if (home[0]) add_to_strn(&home, cast_uchar "/");
802 	home_links = stracpy(home);
803 	if (config_dir) {
804 		add_to_strn(&home_links, config_dir);
805 		while (home_links[0] && dir_sep(home_links[strlen(cast_const_char home_links) - 1])) home_links[strlen(cast_const_char home_links) - 1] = 0;
806 		EINTRLOOP(rs, stat(cast_const_char home_links, &st));
807 		if (!rs && S_ISDIR(st.st_mode)) {
808 			add_to_strn(&home_links, cast_uchar "/links");
809 		} else {
810 			fprintf(stderr, "CONFIG_DIR set to %s. But directory %s doesn't exist.\n\007", config_dir, home_links);
811 			portable_sleep(3000);
812 			mem_free(home_links);
813 			home_links = stracpy(home);
814 			goto add_dot_links;
815 		}
816 	} else {
817 		add_dot_links:
818 #if defined(DOS)
819 		add_to_strn(&home_links, cast_uchar "links.cfg");
820 #elif defined(OPENVMS) || defined(HAIKU)
821 		add_to_strn(&home_links, cast_uchar "links");
822 #else
823 		add_to_strn(&home_links, cast_uchar ".links");
824 #endif
825 	}
826 	EINTRLOOP(rs, stat(cast_const_char home_links, &st));
827 	if (rs) {
828 		EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700));
829 		if (!rs) goto home_creat;
830 #ifdef OPENVMS
831 		if (errno == EEXIST) {
832 			memset(&st, 0, sizeof st);
833 			goto home_ok;
834 		}
835 #endif
836 		if (config_dir) goto failed;
837 		goto first_failed;
838 	}
839 	if (S_ISDIR(st.st_mode)) goto home_ok;
840 	/* This is a Cygwin hack! Cygwin reports stat for "links" if no
841 	   "links" exists and only "links.exe" does. So try to create directory
842 	   anyway. */
843 	EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700));
844 	if (!rs) goto home_creat;
845 	first_failed:
846 	mem_free(home_links);
847 	home_links = stracpy(home);
848 #ifdef DOS
849 	add_to_strn(&home_links, cast_uchar "links.cfg");
850 #else
851 	add_to_strn(&home_links, cast_uchar "links");
852 #endif
853 	EINTRLOOP(rs, stat(cast_const_char home_links, &st));
854 	if (rs) {
855 		EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700));
856 		if (!rs) goto home_creat;
857 #ifdef OPENVMS
858 		if (errno == EEXIST) {
859 			memset(&st, 0, sizeof st);
860 			goto home_ok;
861 		}
862 #endif
863 		goto failed;
864 	}
865 	if (S_ISDIR(st.st_mode)) goto home_ok;
866 	EINTRLOOP(rs, mkdir(cast_const_char home_links, 0700));
867 	if (!rs) goto home_creat;
868 	failed:
869 	mem_free(home_links);
870 	mem_free(home);
871 	if (config_dir) mem_free(config_dir);
872 	return NULL;
873 
874 	home_ok:
875 	if (n) *n = 0;
876 	if ((st.st_mode & 07777) != 0700) {
877 		home_creat:
878 #ifdef HAVE_CHMOD
879 		EINTRLOOP(rs, chmod(cast_const_char home_links, 0700));
880 #endif
881 	}
882 	add_to_strn(&home_links, cast_uchar "/");
883 	mem_free(home);
884 	if (config_dir) mem_free(config_dir);
885 	return home_links;
886 }
887 
init_home(void)888 void init_home(void)
889 {
890 	get_system_name();
891 	get_compiler_name();
892 	links_home = get_home(&first_use);
893 	if (!links_home) {
894 		fprintf(stderr, "Unable to find or create links config directory. Please check, that you have $HOME variable set correctly and that you have write permission to your home directory.\n");
895 		portable_sleep(3000);
896 		return;
897 	}
898 }
899 
900 /* prefix: directory
901  * name: name of the configuration file (typ. links.cfg)
902  */
write_config_data(unsigned char * prefix,unsigned char * name,struct option * o,struct terminal * term)903 static int write_config_data(unsigned char *prefix, unsigned char *name, struct option *o, struct terminal *term)
904 {
905 	int err;
906 	unsigned char *c, *config_file;
907 	if (!(c = create_config_string(o))) return -1;
908 	config_file = stracpy(prefix);
909 	if (!config_file) {
910 		mem_free(c);
911 		if (term) msg_box(term, NULL, TEXT_(T_CONFIG_ERROR), AL_CENTER, TEXT_(T_UNABLE_TO_WRITE_TO_CONFIG_FILE), cast_uchar ": ", TEXT_(T_HOME_DIRECTORY_INACCESSIBLE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
912 		return -1;
913 	}
914 	add_to_strn(&config_file, name);
915 	if ((err = write_to_config_file(config_file, c, 1))) {
916 		if (term) msg_box(term, NULL, TEXT_(T_CONFIG_ERROR), AL_CENTER, TEXT_(T_UNABLE_TO_WRITE_TO_CONFIG_FILE), cast_uchar ": ", get_err_msg(err, term), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
917 		mem_free(c);
918 		mem_free(config_file);
919 		return -1;
920 	}
921 	mem_free(c);
922 	mem_free(config_file);
923 	return 0;
924 }
925 
add_nm(struct option * o,unsigned char ** s,int * l)926 static void add_nm(struct option *o, unsigned char **s, int *l)
927 {
928 	if (*l) add_to_str(s, l, cast_uchar NEWLINE);
929 	add_to_str(s, l, cast_uchar o->cfg_name);
930 	add_chr_to_str(s, l, ' ');
931 }
932 
add_quoted_to_str(unsigned char ** s,int * l,unsigned char * q)933 void add_quoted_to_str(unsigned char **s, int *l, unsigned char *q)
934 {
935 	add_chr_to_str(s, l, '"');
936 	while (*q) {
937 		if (*q == '"' || *q == '\\') add_chr_to_str(s, l, '\\');
938 		add_chr_to_str(s, l, *q);
939 		q++;
940 	}
941 	add_chr_to_str(s, l, '"');
942 }
943 
num_rd(struct option * o,unsigned char * c)944 static unsigned char *num_rd(struct option *o, unsigned char *c)
945 {
946 	unsigned char *tok = get_token(&c);
947 	unsigned char *end;
948 	long l;
949 	if (!tok) return cast_uchar "Missing argument";
950 	l = strtolx(tok, &end);
951 	if (*end) {
952 		mem_free(tok);
953 		return cast_uchar "Number expected";
954 	}
955 	if (l < o->min || l > o->max || l != (long)(int)l) {
956 		mem_free(tok);
957 		return cast_uchar "Out of range";
958 	}
959 	*(int *)o->ptr = (int)l;
960 	mem_free(tok);
961 	return NULL;
962 }
963 
num_wr(struct option * o,unsigned char ** s,int * l)964 static void num_wr(struct option *o, unsigned char **s, int *l)
965 {
966 	add_nm(o, s, l);
967 	add_knum_to_str(s, l, *(int *)o->ptr);
968 }
969 
dbl_rd(struct option * o,unsigned char * c)970 static unsigned char *dbl_rd(struct option *o, unsigned char *c)
971 {
972 	unsigned char *tok = get_token(&c);
973 	char *end;
974 	double d;
975 
976 	if (!tok) return cast_uchar "Missing argument";
977 
978 	if (strlen(cast_const_char tok) >= 1000) {
979 		mem_free(tok);
980 		return cast_uchar "Number is too long";
981 	}
982 
983 	d = strtod(cast_const_char tok, &end);
984 
985 	if (*end || tok[strspn(cast_const_char tok, "0123456789.eE+-")]) {
986 		mem_free(tok);
987 		return cast_uchar "Number expected";
988 	}
989 	if (d < 0 || d > o->max || 100 * d < o->min || 100 * d > o->max) {
990 		mem_free(tok);
991 		return cast_uchar "Out of range";
992 	}
993 	*(double *)o->ptr = d;
994 	mem_free(tok);
995 	return NULL;
996 }
997 
dbl_wr(struct option * o,unsigned char ** s,int * l)998 static void dbl_wr(struct option *o, unsigned char **s, int *l)
999 {
1000 	unsigned char number[80];
1001 	snprintf(cast_char number, sizeof number, "%.6f", *(double*)o->ptr);
1002 
1003 	add_nm(o, s, l);
1004 	add_to_str(s, l, number);
1005 }
1006 
str_rd(struct option * o,unsigned char * c)1007 static unsigned char *str_rd(struct option *o, unsigned char *c)
1008 {
1009 	unsigned char *tok = get_token(&c);
1010 	unsigned char *e = NULL;
1011 	if (!tok) tok = stracpy(cast_uchar "");
1012 	if (strlen(cast_const_char tok) + 1 > (size_t)o->max) e = cast_uchar "String too long";
1013 	else strcpy(cast_char o->ptr, cast_const_char tok);
1014 	mem_free(tok);
1015 	return e;
1016 }
1017 
str_wr(struct option * o,unsigned char ** s,int * l)1018 static void str_wr(struct option *o, unsigned char **s, int *l)
1019 {
1020 	add_nm(o, s, l);
1021 	if (strlen(cast_const_char o->ptr) + 1 > (size_t)o->max) {
1022 		unsigned char *s1 = init_str();
1023 		int l1 = 0;
1024 		add_bytes_to_str(&s1, &l1, o->ptr, o->max - 1);
1025 		add_quoted_to_str(s, l, s1);
1026 		mem_free(s1);
1027 	}
1028 	else add_quoted_to_str(s, l, o->ptr);
1029 }
1030 
cp_rd(struct option * o,unsigned char * c)1031 static unsigned char *cp_rd(struct option *o, unsigned char *c)
1032 {
1033 	unsigned char *tok = get_token(&c);
1034 	unsigned char *e = NULL;
1035 	int i;
1036 	if (!tok) return cast_uchar "Missing argument";
1037 	if ((i = get_cp_index(tok)) == -1) e = cast_uchar "Unknown codepage";
1038 #ifndef ENABLE_UTF8
1039 	else if (o->min == 1 && i == utf8_table) e = cast_uchar "UTF-8 can't be here";
1040 #endif
1041 	else *(int *)o->ptr = i;
1042 	mem_free(tok);
1043 	return e;
1044 }
1045 
cp_wr(struct option * o,unsigned char ** s,int * l)1046 static void cp_wr(struct option *o, unsigned char **s, int *l)
1047 {
1048 	unsigned char *n = get_cp_mime_name(*(int *)o->ptr);
1049 	add_nm(o, s, l);
1050 	add_to_str(s, l, n);
1051 }
1052 
lang_rd(struct option * o,unsigned char * c)1053 static unsigned char *lang_rd(struct option *o, unsigned char *c)
1054 {
1055 	int i;
1056 	unsigned char *tok = get_token(&c);
1057 	if (!tok) return cast_uchar "Missing argument";
1058 	for (i = -1; i < n_languages(); i++)
1059 		if (!(casestrcmp(language_name(i), tok))) {
1060 			set_language(i);
1061 			mem_free(tok);
1062 			return NULL;
1063 		}
1064 	mem_free(tok);
1065 	return cast_uchar "Unknown language";
1066 }
1067 
lang_wr(struct option * o,unsigned char ** s,int * l)1068 static void lang_wr(struct option *o, unsigned char **s, int *l)
1069 {
1070 	add_nm(o, s, l);
1071 	add_quoted_to_str(s, l, language_name(current_language));
1072 }
1073 
getnum(unsigned char * s,int * n,int r1,int r2)1074 static int getnum(unsigned char *s, int *n, int r1, int r2)
1075 {
1076 	char *e;
1077 	long l = strtol(cast_const_char s, &e, 10);
1078 	if (*e || !*s) return -1;
1079 	if (l < r1 || l >= r2) return -1;
1080 	*n = (int)l;
1081 	return 0;
1082 }
1083 
type_rd(struct option * o,unsigned char * c)1084 static unsigned char *type_rd(struct option *o, unsigned char *c)
1085 {
1086 	unsigned char *err = cast_uchar "Error reading association specification";
1087 	struct assoc neww;
1088 	unsigned char *w;
1089 	int n = 0;	/* against warning */
1090 	memset(&neww, 0, sizeof(struct assoc));
1091 	if (!(neww.label = get_token(&c))) goto err;
1092 	if (!(neww.ct = get_token(&c))) goto err;
1093 	if (!(neww.prog = get_token(&c))) goto err;
1094 	if (!(w = get_token(&c))) goto err;
1095 	if (getnum(w, &n, 0, 128)) goto err_f;
1096 	mem_free(w);
1097 	neww.cons = !!(n & 1);
1098 	neww.xwin = !!(n & 2);
1099 	neww.ask = !!(n & 4);
1100 	if ((n & 8) || (n & 16)) neww.block = !!(n & 16);
1101 	else neww.block = !neww.xwin || neww.cons;
1102 	neww.accept_http = !!(n & 32);
1103 	neww.accept_ftp = !!(n & 64);
1104 	if (!(w = get_token(&c))) goto err;
1105 	if (getnum(w, &neww.system, 0, 256)) goto err_f;
1106 	mem_free(w);
1107 	update_assoc(&neww);
1108 	err = NULL;
1109 	err:
1110 	if (neww.label) mem_free(neww.label);
1111 	if (neww.ct) mem_free(neww.ct);
1112 	if (neww.prog) mem_free(neww.prog);
1113 	return err;
1114 	err_f:
1115 	mem_free(w);
1116 	goto err;
1117 }
1118 
block_rd(struct option * o,unsigned char * c)1119 static unsigned char *block_rd(struct option *o, unsigned char *c)
1120 {
1121 	unsigned char *err = cast_uchar "Error reading image block specification";
1122 	unsigned char* url;
1123 
1124 	if (!(url = get_token(&c)))
1125 		return err;
1126 
1127 	block_url_add(NULL, url);
1128 
1129 	mem_free(url);
1130 
1131 	return NULL;
1132 }
1133 
block_wr(struct option * o,unsigned char ** s,int * l)1134 static void block_wr(struct option *o, unsigned char **s, int *l)
1135 {
1136 	struct list *a;
1137 	struct list_head *la;
1138 	foreachback(struct list, a, la, blocks.list_entry) {
1139 		struct block *b = get_struct(a, struct block, head);
1140 		add_nm(o, s, l);
1141 		add_quoted_to_str(s, l, b->url);
1142 	}
1143 }
1144 
type_wr(struct option * o,unsigned char ** s,int * l)1145 static void type_wr(struct option *o, unsigned char **s, int *l)
1146 {
1147 	struct list *a;
1148 	struct list_head *la;
1149 	foreachback(struct list, a, la, assoc.list_entry) {
1150 		struct assoc *as = get_struct(a, struct assoc, head);
1151 		add_nm(o, s, l);
1152 		add_quoted_to_str(s, l, as->label);
1153 		add_chr_to_str(s, l, ' ');
1154 		add_quoted_to_str(s, l, as->ct);
1155 		add_chr_to_str(s, l, ' ');
1156 		add_quoted_to_str(s, l, as->prog);
1157 		add_chr_to_str(s, l, ' ');
1158 		add_num_to_str(s, l, (!!as->cons) + (!!as->xwin) * 2 + (!!as->ask) * 4 + (!as->block) * 8 + (!!as->block) * 16 + (!!as->accept_http) * 32 + (!!as->accept_ftp) * 64);
1159 		add_chr_to_str(s, l, ' ');
1160 		add_num_to_str(s, l, as->system);
1161 	}
1162 }
1163 
ext_rd(struct option * o,unsigned char * c)1164 static unsigned char *ext_rd(struct option *o, unsigned char *c)
1165 {
1166 	unsigned char *err = cast_uchar "Error reading extension specification";
1167 	struct extension neww;
1168 	memset(&neww, 0, sizeof(struct extension));
1169 	if (!(neww.ext = get_token(&c))) goto err;
1170 	if (!(neww.ct = get_token(&c))) goto err;
1171 	update_ext(&neww);
1172 	err = NULL;
1173 	err:
1174 	if (neww.ext) mem_free(neww.ext);
1175 	if (neww.ct) mem_free(neww.ct);
1176 	return err;
1177 }
1178 
ext_wr(struct option * o,unsigned char ** s,int * l)1179 static void ext_wr(struct option *o, unsigned char **s, int *l)
1180 {
1181 	struct list *a;
1182 	struct list_head *la;
1183 	foreachback(struct list, a, la, extensions.list_entry) {
1184 		struct extension *e = get_struct(a, struct extension, head);
1185 		add_nm(o, s, l);
1186 		add_quoted_to_str(s, l, e->ext);
1187 		add_chr_to_str(s, l, ' ');
1188 		add_quoted_to_str(s, l, e->ct);
1189 	}
1190 }
1191 
prog_rd(struct option * o,unsigned char * c)1192 static unsigned char *prog_rd(struct option *o, unsigned char *c)
1193 {
1194 	unsigned char *err = cast_uchar "Error reading program specification";
1195 	unsigned char *prog, *w;
1196 	int n;
1197 	if (!(prog = get_token(&c))) goto err_1;
1198 	if (!(w = get_token(&c))) goto err_2;
1199 	if (getnum(w, &n, 0, 256)) goto err_3;
1200 	update_prog(o->ptr, prog, n);
1201 	err = NULL;
1202 	err_3:
1203 	mem_free(w);
1204 	err_2:
1205 	mem_free(prog);
1206 	err_1:
1207 	return err;
1208 }
1209 
prog_wr(struct option * o,unsigned char ** s,int * l)1210 static void prog_wr(struct option *o, unsigned char **s, int *l)
1211 {
1212 	struct protocol_program *a;
1213 	struct list_head *la;
1214 	foreachback(struct protocol_program, a, la, *(struct list_head *)o->ptr) {
1215 		if (!*a->prog) continue;
1216 		add_nm(o, s, l);
1217 		add_quoted_to_str(s, l, a->prog);
1218 		add_chr_to_str(s, l, ' ');
1219 		add_num_to_str(s, l, a->system);
1220 	}
1221 }
1222 
term_rd(struct option * o,unsigned char * c)1223 static unsigned char *term_rd(struct option *o, unsigned char *c)
1224 {
1225 	struct term_spec *ts;
1226 	unsigned char *w;
1227 	int i, r;
1228 	if (!(w = get_token(&c))) goto err;
1229 	ts = new_term_spec(w);
1230 	mem_free(w);
1231 	if (!(w = get_token(&c))) goto err;
1232 	if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '5') goto err_f;
1233 	ts->mode = w[0] - '0';
1234 	mem_free(w);
1235 	if (!(w = get_token(&c))) goto err;
1236 	if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '3') goto err_f;
1237 	ts->m11_hack = (w[0] - '0') & 1;
1238 	ts->braille = !!((w[0] - '0') & 2);
1239 	mem_free(w);
1240 	if (!(w = get_token(&c))) goto err;
1241 	if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '7') goto err_f;
1242 	ts->col = (w[0] - '0') & 1;
1243 	ts->restrict_852 = !!((w[0] - '0') & 2);
1244 	ts->block_cursor = !!((w[0] - '0') & 4);
1245 	mem_free(w);
1246 	if (!(w = get_token(&c))) goto err;
1247 	if (!casestrcmp(w, cast_uchar "default")) {
1248 		i = -1;
1249 	} else {
1250 		if ((i = get_cp_index(w)) == -1) goto err_f;
1251 	}
1252 #ifndef ENABLE_UTF8
1253 	if (i == utf8_table) {
1254 		i = 0;
1255 	}
1256 #endif
1257 	ts->character_set = i;
1258 	mem_free(w);
1259 	r = get_token_num(&c, 0, 999, &ts->left_margin);
1260 	if (r == -1) goto ret;
1261 	if (r < 0) goto err;
1262 	r = get_token_num(&c, 0, 999, &ts->right_margin);
1263 	if (r < 0) goto err;
1264 	r = get_token_num(&c, 0, 999, &ts->top_margin);
1265 	if (r < 0) goto err;
1266 	r = get_token_num(&c, 0, 999, &ts->bottom_margin);
1267 	if (r < 0) goto err;
1268 ret:
1269 	return NULL;
1270 err_f:
1271 	mem_free(w);
1272 err:
1273 	return cast_uchar "Error reading terminal specification";
1274 }
1275 
term2_rd(struct option * o,unsigned char * c)1276 static unsigned char *term2_rd(struct option *o, unsigned char *c)
1277 {
1278 	struct term_spec *ts;
1279 	unsigned char *w;
1280 	int i;
1281 	if (!(w = get_token(&c))) goto err;
1282 	ts = new_term_spec(w);
1283 	mem_free(w);
1284 	if (!(w = get_token(&c))) goto err;
1285 	if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '3') goto err_f;
1286 	ts->mode = w[0] - '0';
1287 	mem_free(w);
1288 	if (!(w = get_token(&c))) goto err;
1289 	if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
1290 	ts->m11_hack = w[0] - '0';
1291 	mem_free(w);
1292 	if (!(w = get_token(&c))) goto err;
1293 	if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
1294 	ts->restrict_852 = w[0] - '0';
1295 	mem_free(w);
1296 	if (!(w = get_token(&c))) goto err;
1297 	if (strlen(cast_const_char w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
1298 	ts->col = w[0] - '0';
1299 	mem_free(w);
1300 	if (!(w = get_token(&c))) goto err;
1301 	if (!casestrcmp(w, cast_uchar "default")) {
1302 		i = -1;
1303 	} else {
1304 		if ((i = get_cp_index(w)) == -1) goto err_f;
1305 	}
1306 #ifndef ENABLE_UTF8
1307 	if (i == utf8_table) {
1308 		i = 0;
1309 	}
1310 #endif
1311 	ts->character_set = i;
1312 	mem_free(w);
1313 	return NULL;
1314 	err_f:
1315 	mem_free(w);
1316 	err:
1317 	return cast_uchar "Error reading terminal specification";
1318 }
1319 
term_wr(struct option * o,unsigned char ** s,int * l)1320 static void term_wr(struct option *o, unsigned char **s, int *l)
1321 {
1322 	struct term_spec *ts;
1323 	struct list_head *lts;
1324 	foreachback(struct term_spec, ts, lts, term_specs) {
1325 		add_nm(o, s, l);
1326 		add_quoted_to_str(s, l, ts->term);
1327 		add_chr_to_str(s, l, ' ');
1328 		add_num_to_str(s, l, ts->mode);
1329 		add_chr_to_str(s, l, ' ');
1330 		add_num_to_str(s, l, !!ts->m11_hack + !!ts->braille * 2);
1331 		add_chr_to_str(s, l, ' ');
1332 		add_num_to_str(s, l, !!ts->col + !!ts->restrict_852 * 2 + !!ts->block_cursor * 4);
1333 		add_chr_to_str(s, l, ' ');
1334 		if (ts->character_set == -1) add_to_str(s, l, cast_uchar "default");
1335 		else add_to_str(s, l, get_cp_mime_name(ts->character_set));
1336 		if (ts->left_margin || ts->right_margin || ts->top_margin || ts->bottom_margin) {
1337 			add_chr_to_str(s, l, ' ');
1338 			add_num_to_str(s, l, ts->left_margin);
1339 			add_chr_to_str(s, l, ' ');
1340 			add_num_to_str(s, l, ts->right_margin);
1341 			add_chr_to_str(s, l, ' ');
1342 			add_num_to_str(s, l, ts->top_margin);
1343 			add_chr_to_str(s, l, ' ');
1344 			add_num_to_str(s, l, ts->bottom_margin);
1345 		}
1346 	}
1347 }
1348 
1349 static struct list_head driver_params = { &driver_params, &driver_params };
1350 
get_driver_param(unsigned char * n)1351 struct driver_param *get_driver_param(unsigned char *n)
1352 {
1353 	struct driver_param *dp;
1354 	size_t sl;
1355 	struct list_head *ldp;
1356 	foreach(struct driver_param, dp, ldp, driver_params) if (!casestrcmp(dp->name, n)) return dp;
1357 	sl = strlen(cast_const_char n);
1358 	if (sl > MAXINT - sizeof(struct driver_param)) overalloc();
1359 	dp = mem_calloc(sizeof(struct driver_param) + sl);
1360 	strcpy(cast_char dp->name, cast_const_char n);
1361 	dp->kbd_codepage = -1;
1362 	dp->palette_mode = 0;
1363 	dp->nosave = 1;
1364 	add_to_list(driver_params, dp);
1365 	return dp;
1366 }
1367 
dp_rd(struct option * o,unsigned char * c)1368 static unsigned char *dp_rd(struct option *o, unsigned char *c)
1369 {
1370 	int cc;
1371 	unsigned char *n, *param, *cp;
1372 	struct driver_param *dp;
1373 	if (!(n = get_token(&c))) {
1374 		goto err;
1375 	}
1376 	dp = get_driver_param(n);
1377 	mem_free(n);
1378 	if (!(param = get_token(&c))) {
1379 		goto err;
1380 	}
1381 	if (dp->param) mem_free(dp->param);
1382 	dp->param = param;
1383 	if (!(param = get_token(&c))){
1384 		goto err;
1385 	}
1386 	safe_strncpy(dp->shell_term, param, MAX_STR_LEN);
1387 	mem_free(param);
1388 	if (!(cp = get_token(&c))) {
1389 		goto err;
1390 	}
1391 	if (!casestrcmp(cp, cast_uchar "default")) {
1392 		cc = -1;
1393 	} else if ((cc = get_cp_index(cp)) == -1) {
1394 		mem_free(cp);
1395 		goto err;
1396 	}
1397 	mem_free(cp);
1398 	dp->kbd_codepage = cc;
1399 	cc = get_token_num(&c, 0, 1, &dp->palette_mode);
1400 	if (cc == -2) goto err;
1401 	dp->nosave = 0;
1402 	return NULL;
1403 err:
1404 	return cast_uchar "Error reading driver mode specification";
1405 }
1406 
dp_wr(struct option * o,unsigned char ** s,int * l)1407 static void dp_wr(struct option *o, unsigned char **s, int *l)
1408 {
1409 	struct driver_param *dp;
1410 	struct list_head *ldp;
1411 	foreachback(struct driver_param, dp, ldp, driver_params) {
1412 		if ((!dp->param || !*dp->param) && !*dp->shell_term && dp->kbd_codepage == -1 && !dp->palette_mode) continue;
1413 		if (dp->nosave) continue;
1414 		add_nm(o, s, l);
1415 		add_quoted_to_str(s, l, dp->name);
1416 		add_chr_to_str(s, l, ' ');
1417 		add_quoted_to_str(s, l, dp->param ? dp->param : (unsigned char*)"");
1418 		add_chr_to_str(s, l, ' ');
1419 		add_quoted_to_str(s, l, dp->shell_term);
1420 		add_chr_to_str(s, l, ' ');
1421 		if (dp->kbd_codepage == -1) add_to_str(s, l, cast_uchar "default");
1422 		else add_to_str(s, l, get_cp_mime_name(dp->kbd_codepage));
1423 		add_chr_to_str(s, l, ' ');
1424 		add_num_to_str(s, l, dp->palette_mode);
1425 		/* pokud se sem neco prida, opravit podminku na zacatku cyklu */
1426 	}
1427 }
1428 
ip_rd(struct option * o,unsigned char * c)1429 static unsigned char *ip_rd(struct option *o, unsigned char *c)
1430 {
1431 	unsigned char *e;
1432 	e = str_rd(o, c);
1433 	if (e) return e;
1434 	if (*(unsigned char *)o->ptr && numeric_ip_address(o->ptr, NULL) == -1) return cast_uchar "Invalid IP address";
1435 	return NULL;
1436 }
1437 
ipv6_rd(struct option * o,unsigned char * c)1438 static unsigned char *ipv6_rd(struct option *o, unsigned char *c)
1439 {
1440 	unsigned char *e;
1441 	e = str_rd(o, c);
1442 	if (e) return e;
1443 #ifdef SUPPORT_IPV6
1444 	if (*(unsigned char *)o->ptr && numeric_ipv6_address(o->ptr, NULL, NULL) == -1) return cast_uchar "Invalid IPv6 address";
1445 #endif
1446 	return NULL;
1447 }
1448 
gen_cmd(struct option * o,unsigned char *** argv,int * argc)1449 static unsigned char *gen_cmd(struct option *o, unsigned char ***argv, int *argc)
1450 {
1451 	unsigned char *e;
1452 	int l;
1453 	unsigned char *r;
1454 	if (!*argc) return cast_uchar "Parameter expected";
1455 	e = init_str();
1456 	l = 0;
1457 	add_quoted_to_str(&e, &l, **argv);
1458 	r = o->rd_cfg ? o->rd_cfg(o, e) : 0;
1459 	mem_free(e);
1460 	if (r) return r;
1461 	(*argv)++; (*argc)--;
1462 	return NULL;
1463 }
1464 
x_proxy_cmd(struct option * o,unsigned char *** argv,int * argc,int (* save)(int,unsigned char *,unsigned char *),unsigned char * err)1465 static unsigned char *x_proxy_cmd(struct option *o, unsigned char ***argv, int *argc, int (*save)(int, unsigned char *, unsigned char *), unsigned char *err)
1466 {
1467 	unsigned char **pass_argv;
1468 	unsigned char *result, *ret;
1469 	if (!*argc) return cast_uchar "Parameter expected";
1470 	result = mem_alloc(MAX_STR_LEN);
1471 	if (save(get_commandline_charset(), result, **argv)) {
1472 		mem_free(result);
1473 		return err;
1474 	}
1475 	pass_argv = &result;
1476 	ret = gen_cmd(o, &pass_argv, argc);
1477 	mem_free(result);
1478 	if (ret) return ret;
1479 	(*argv)++;
1480 	return NULL;
1481 }
1482 
proxy_cmd(struct option * o,unsigned char *** argv,int * argc)1483 static unsigned char *proxy_cmd(struct option *o, unsigned char ***argv, int *argc)
1484 {
1485 	return x_proxy_cmd(o, argv, argc, save_proxy, cast_uchar "Invalid proxy");
1486 }
1487 
noproxy_cmd(struct option * o,unsigned char *** argv,int * argc)1488 static unsigned char *noproxy_cmd(struct option *o, unsigned char ***argv, int *argc)
1489 {
1490 	return x_proxy_cmd(o, argv, argc, save_noproxy_list, cast_uchar "Invalid list of domains");
1491 }
1492 
lookup_cmd(struct option * o,unsigned char *** argv,int * argc)1493 static unsigned char *lookup_cmd(struct option *o, unsigned char ***argv, int *argc)
1494 {
1495 	int i;
1496 	struct lookup_result addr;
1497 	unsigned char *h, *h2, *h3;
1498 	if (!*argc) return cast_uchar "Parameter expected";
1499 	if (*argc >= 2) return cast_uchar "Too many parameters";
1500 	h = *(*argv)++;
1501 	(*argc)--;
1502 	h2 = convert(get_commandline_charset(), utf8_table, h, NULL);
1503 	h3 = idn_encode_host(h2, (int)strlen(cast_const_char h2), cast_uchar ".", 0);
1504 	if (!h3) h3 = stracpy(h2);
1505 	mem_free(h2);
1506 	do_real_lookup(h3, ipv6_options.addr_preference, &addr);
1507 	mem_free(h3);
1508 	if (!addr.n) {
1509 #if !defined(USE_GETADDRINFO) && defined(HAVE_GETHOSTBYNAME) && defined(HAVE_HERROR)
1510 		herror("error");
1511 #else
1512 		fprintf(stderr, "error: host not found\n");
1513 #endif
1514 		do_exit(RET_ERROR);
1515 		return NULL;
1516 	}
1517 	for (i = 0; i < addr.n; i++) {
1518 		unsigned char *a;
1519 		if ((a = print_address(&addr.a[i])))
1520 			printf("%s\n", a);
1521 	}
1522 	fflush(stdout);
1523 	do_exit(RET_OK);
1524 	return NULL;
1525 }
1526 
version_cmd(struct option * o,unsigned char *** argv,int * argc)1527 static unsigned char *version_cmd(struct option *o, unsigned char ***argv, int *argc)
1528 {
1529 	printf("Links " VERSION_STRING "\n");
1530 	fflush(stdout);
1531 	do_exit(RET_OK);
1532 	return NULL;
1533 }
1534 
set_cmd(struct option * o,unsigned char *** argv,int * argc)1535 static unsigned char *set_cmd(struct option *o, unsigned char ***argv, int *argc)
1536 {
1537 	*(int *)o->ptr = 1;
1538 	return NULL;
1539 }
1540 
unset_cmd(struct option * o,unsigned char *** argv,int * argc)1541 static unsigned char *unset_cmd(struct option *o, unsigned char ***argv, int *argc)
1542 {
1543 	*(int *)o->ptr = 0;
1544 	return NULL;
1545 }
1546 
setstr_cmd(struct option * o,unsigned char *** argv,int * argc)1547 static unsigned char *setstr_cmd(struct option *o, unsigned char ***argv, int *argc)
1548 {
1549 	if (!*argc) return cast_uchar "Parameter expected";
1550 	safe_strncpy(o->ptr, **argv, o->max);
1551 	(*argv)++; (*argc)--;
1552 	return NULL;
1553 }
1554 
dump_cmd(struct option * o,unsigned char *** argv,int * argc)1555 static unsigned char *dump_cmd(struct option *o, unsigned char ***argv, int *argc)
1556 {
1557 	if (dmp != o->min && dmp) return cast_uchar "Can't use both -dump and -source";
1558 	dmp = o->min;
1559 	no_connect = 1;
1560 	return NULL;
1561 }
1562 
printhelp_cmd(struct option * o,unsigned char *** argv,int * argc)1563 static unsigned char *printhelp_cmd(struct option *o, unsigned char ***argv, int *argc)
1564 {
1565 /* Changed and splited - translation is much easier.
1566  * Print to stdout instead stderr (,,links -help | more''
1567  * is much better than ,,links -help 2>&1 | more'').
1568  */
1569 fprintf(stdout, "%s%s%s%s%s%s\n",
1570 
1571 (
1572 "links [options] URL\n"
1573 "\n"
1574 "Options are:\n"
1575 "\n"
1576 " -help\n"
1577 "  Prints this help screen\n"
1578 "\n"
1579 " -version\n"
1580 "  Prints the links version number and exit.\n"
1581 "\n"
1582 " -lookup <hostname>\n"
1583 "  Does name lookup, like command \"host\".\n"
1584 "\n"
1585 " -g\n"
1586 "  Run in graphics mode.\n"
1587 "\n"
1588 " -no-g\n"
1589 "  Run in text mode (overrides previous -g).\n"
1590 "\n"
1591 " -driver <driver name>\n"
1592 "  Graphics driver to use. Drivers are: x, svgalib, fb, directfb, pmshell,\n"
1593 "    atheos.\n"
1594 "  List of drivers will be shown if you give it an unknown driver.\n"
1595 "  Available drivers depend on your operating system and available libraries.\n"
1596 "\n"
1597 " -mode <graphics mode>\n"
1598 "  Graphics mode. For SVGALIB it is in format COLUMNSxROWSxCOLORS --\n"
1599 "    for example 640x480x256, 800x600x64k, 960x720x16M, 1024x768x16M32\n"
1600 "    List of modes will be shown if you give it an unknown videomode.\n"
1601 "  For framebuffer it is number of pixels in border --- LEFT,TOP,RIGHT,BOTTOM\n"
1602 "    other 3 values are optional --- i.e. -mode 10 will set all borders to 10,\n"
1603 "    -mode 10,20 will set left & right border to 10 and top & bottom to 20.\n"
1604 "  For Xwindow it is size of a window in format WIDTHxHEIGHT.\n"
1605 "\n"
1606 " -display <x-display>\n"
1607 "  Set Xwindow display.\n"
1608 "\n"
1609 " -force-html\n"
1610 "  Treat files with unknown type as html rather than text.\n"
1611 "    (can be toggled with '\\' key)\n"
1612 "\n"
1613 " -source <url>\n"
1614 "  Write unformatted data stream to stdout.\n"
1615 "\n"
1616 " -dump <url>\n"
1617 "  Write formatted document to stdout.\n"
1618 "\n"
1619 " -width <number>\n"
1620 "  For dump, document will be formatted to this screen width (but it can still\n"
1621 "    exceed it if lines can't be broken).\n"
1622 "\n"
1623 " -codepage <codepage>\n"
1624 "  For dump, convert output to specified character set --\n"
1625 "    for eaxmple iso-8859-2, windows-1250.\n"
1626 "\n"
1627 " -anonymous\n"
1628 "  Restrict links so that it can run on an anonymous account.\n"
1629 "  No local file browsing. No downloads. Executing viewers\n"
1630 "    is allowed, but user can't add or modify entries in\n"
1631 "    association table.\n"
1632 "\n"
1633 " -no-connect\n"
1634 "  Runs links as a separate instance - instead of connecting to\n"
1635 "    existing instance.\n"
1636 "\n"
1637 " -download-dir <path>\n"
1638 "  Default download directory.\n"
1639 "    (default: actual dir)\n"
1640 "\n"
1641 " -language <language>\n"
1642 "  Set user interface language.\n"
1643 "\n"
1644 " -max-connections <max>\n"
1645 "  Maximum number of concurrent connections.\n"
1646 "    (default: 10)\n"
1647 "\n"),(
1648 " -max-connections-to-host <max>\n"
1649 "  Maximum number of concurrent connection to a given host.\n"
1650 "    (default: 2)\n"
1651 "\n"
1652 " -retries <retry>\n"
1653 "  Number of retries.\n"
1654 "    (default: 3)\n"
1655 "\n"
1656 " -receive-timeout <sec>\n"
1657 "  Timeout on receive.\n"
1658 "    (default: 120)\n"
1659 "\n"),(
1660 " -unrestartable-receive-timeout <sec>\n"
1661 "  Timeout on non restartable connections.\n"
1662 "    (default: 600)\n"
1663 "\n"
1664 " -timeout-when-trying-multiple-addresses <sec>\n"
1665 "  Timeout for connection when trying multiple addresses or keepalive connection.\n"
1666 "    (default: 3)\n"
1667 "\n"
1668 " -bind-address <ip address>\n"
1669 "  Use a specific local IP address.\n"
1670 "\n"
1671 " -bind-address-ipv6 <ipv6 address>\n"
1672 "  Use a specific local IPv6 address.\n"
1673 "\n"
1674 " -no-libevent\n"
1675 "  Don't use libevent library.\n"
1676 "\n"
1677 " -no-openmp\n"
1678 "  Don't use OpenMP.\n"
1679 "\n"
1680 " -async-dns <0>/<1>\n"
1681 "  Asynchronous DNS resolver on(1)/off(0).\n"
1682 "\n"
1683 " -download-utime <0>/<1>\n"
1684 "  Set time of downloaded files to last modification time reported by server.\n"
1685 "\n"
1686 " -format-cache-size <num>\n"
1687 "  Number of formatted document pages cached.\n"
1688 "    (default: 5)\n"
1689 "\n"
1690 " -memory-cache-size <bytes>\n"
1691 "  Cache memory in bytes.\n"
1692 "    (default: 1048576)\n"
1693 "\n"
1694 " -image-cache-size <bytes>\n"
1695 "  Image cache in bytes.\n"
1696 "    (default: 1048576)\n"
1697 "\n"
1698 " -font-cache-size <bytes>\n"
1699 "  Font cache in bytes.\n"
1700 "    (default: 2097152)\n"
1701 "\n"
1702 " -aggressive-cache <0>/<1>\n"
1703 "    (default 1)\n"
1704 "  Always cache everything regardless of server's caching recomendations.\n"
1705 "    Many servers deny caching even if their content is not changing\n"
1706 "    just to get more hits and more money from ads.\n"
1707 "\n"),(
1708 " -address-preference <0>/<1>/<2>/<3>/<4>\n"
1709 "    (default 0)\n"
1710 "  0 - use system default.\n"
1711 "  1 - prefer IPv4.\n"
1712 "  2 - prefer IPv6.\n"
1713 "  3 - use only IPv4.\n"
1714 "  4 - use only IPv6.\n"
1715 "\n"
1716 " -http-proxy <host:port>\n"
1717 "  Host and port number of the HTTP proxy, or blank.\n"
1718 "    (default: blank)\n"
1719 "\n"
1720 " -ftp-proxy <host:port>\n"
1721 "  Host and port number of the FTP proxy, or blank.\n"
1722 "    (default: blank)\n"
1723 "\n"
1724 " -https-proxy <host:port>\n"
1725 "  Host and port number of the HTTPS proxy, or blank.\n"
1726 "    (default: blank)\n"
1727 "\n"
1728 " -socks-proxy <user@host:port>\n"
1729 "  Userid, host and port of Socks4a, or blank.\n"
1730 "    (default: blank)\n"
1731 "\n"
1732 " -append-text-to-dns-lookups <text>\n"
1733 "  Append text to dns lookups. It is useful for specifying fixed\n"
1734 "    tor exit node.\n"
1735 "    (default: blank)\n"
1736 "\n"
1737 " -no-proxy-domains <domain,domain...>\n"
1738 "  No proxy for specified domains.\n"
1739 "    (default: blank)\n"
1740 "\n"
1741 " -only-proxies <0>/<1>\n"
1742 "    (default 0)\n"
1743 "  \"1\" causes that Links won't initiate any non-proxy connection.\n"
1744 "    It is useful for anonymization with tor or similar networks.\n"
1745 "\n"
1746 " -ssl.certificates <0>/<1>/<2>\n"
1747 "    (default 1)\n"
1748 "  0 - ignore invalid certificate\n"
1749 "  1 - warn on invalid certificate\n"
1750 "  2 - reject invalid certificate\n"
1751 "\n"
1752 " -ssl.builtin-certificates <0>/<1>\n"
1753 #if defined(DOS) || defined(OPENVMS)
1754 "    (default 1)\n"
1755 #else
1756 "    (default 0)\n"
1757 #endif
1758 "  Use built-in certificates instead of system certificates.\n"
1759 "\n"
1760 " -ssl.client-cert-key <filename>\n"
1761 "  Name of the PEM encoded file with the user private key\n"
1762 "  for client certificate authentication.\n"
1763 "\n"
1764 " -ssl.client-cert-crt <filename>\n"
1765 "  Name of the PEM encoded file with the user certificate\n"
1766 "  for client certificate authentication.\n"
1767 "\n"
1768 " -ssl.client-cert-password <text>\n"
1769 "  Password for the user private key.\n"
1770 "\n"),(
1771 " -http-bugs.http10 <0>/<1>\n"
1772 "    (default 0)\n"
1773 "  \"1\" forces using only HTTP/1.0 protocol. (useful for buggy servers\n"
1774 "    that claim to be HTTP/1.1 compliant but are not)\n"
1775 "  \"0\" use both HTTP/1.0 and HTTP/1.1.\n"
1776 "\n"
1777 " -http-bugs.allow-blacklist <0>/<1>\n"
1778 "    (default 1)\n"
1779 "  \"1\" defaults to using list of servers that have broken HTTP/1.1 support.\n"
1780 "     When links finds such server, it will retry the request with HTTP/1.0.\n"
1781 "\n"
1782 " -http-bugs.bug-no-accept-charset <0>/<1>\n"
1783 "    (default 0)\n"
1784 "  Do not send Accept-Charset field of HTTP header. Because it is too long\n"
1785 "    some servers will deny the request. Other servers will convert content\n"
1786 "    to plain ascii when Accept-Charset is missing.\n"
1787 "\n"
1788 " -http-bugs.no-compression <0>/<1>\n"
1789 "    (default 0)\n"
1790 "  \"1\" causes that links won't advertise HTTP compression support (but it\n"
1791 "    will still accept compressed data). Use it when you communicate with\n"
1792 "    server that has broken compression support.\n"
1793 "\n"
1794 " -http-bugs.retry-internal-errors <0>/<1>\n"
1795 "    (default 0)\n"
1796 "  Retry on internal server errors (50x).\n"
1797 "\n"
1798 " -http.fake-firefox <0>/<1>\n"
1799 "    (default 0)\n"
1800 "  Fake Firefox in the HTTP header.\n"
1801 "\n"
1802 " -http.do-not-track <0>/<1>\n"
1803 "    (default 0)\n"
1804 "  Send do not track request in the HTTP header.\n"
1805 "\n"
1806 " -http.referer <0>/<1>/<2>/<3>/<4>\n"
1807 "    (default 4)\n"
1808 "  0 - do not send referer.\n"
1809 "  1 - send the requested URL as referer.\n"
1810 "  2 - send fake referer.\n"
1811 "  3 - send real referer.\n"
1812 "  4 - send real referer only to the same server.\n"
1813 "\n"
1814 " -http.fake-referer <string>\n"
1815 "  Fake referer value.\n"
1816 "\n"
1817 " -http.fake-user-agent <string>\n"
1818 "  Fake user agent value.\n"
1819 "\n"
1820 " -http.extra-header <string>\n"
1821 "  Extra string added to HTTP header.\n"
1822 "\n"
1823 " -ftp.anonymous-password <string>\n"
1824 "  Password for anonymous ftp access.\n"
1825 "\n"
1826 " -ftp.use-passive <0>/<1>\n"
1827 "  Use ftp PASV command to bypass firewalls.\n"
1828 "\n"
1829 " -ftp.use-eprt-epsv <0>/<1>\n"
1830 "  Use EPRT and EPSV commands instead of PORT and PASV.\n"
1831 "\n"
1832 " -ftp.set-iptos <0>/<1>\n"
1833 "  Set IP Type-of-service to high throughput on ftp connections.\n"
1834 "\n"
1835 " -smb.allow-hyperlinks-to-smb <0>/<1>\n"
1836 "  Allow hyperlinks to SMB protocol.\n"
1837 "    Disabling this improves security, because internet sites cannot\n"
1838 "    exploit possible bugs in the SMB client.\n"
1839 "\n"
1840 " -menu-font-size <size>\n"
1841 "  Size of font in menu.\n"
1842 "\n"
1843 " -menu-background-color 0xRRGGBB\n"
1844 "  Set menu background color in graphics mode, RRGGBB are hex.\n"
1845 "\n"
1846 " -menu-foreground-color 0xRRGGBB\n"
1847 "  Set menu foreground color in graphics mode.\n"
1848 "\n"
1849 " -scroll-bar-area-color 0xRRGGBB\n"
1850 "  Set color of scroll bar area.\n"
1851 "\n"
1852 " -scroll-bar-bar-color 0xRRGGBB\n"
1853 "  Set color of scroll bar.\n"
1854 "\n"
1855 " -scroll-bar-frame-color 0xRRGGBB\n"
1856 "  Set color of scroll bar frame.\n"
1857 "\n"
1858 " -bookmarks-file <file>\n"
1859 "  File to store bookmarks.\n"
1860 "\n"
1861 " -bookmarks-codepage <codepage>\n"
1862 "  Character set of bookmarks file.\n"
1863 "\n"
1864 " -save-url-history <0>/<1>\n"
1865 "  Save URL history on exit.\n"
1866 "\n"
1867 " -enable-cookies <0>/<1>\n"
1868 "  Enable cookiest.\n"
1869 "\n"
1870 " -save-cookies <0>/<1>\n"
1871 "  Save cookies on exit.\n"
1872 "\n"
1873 " -max-cookie-age <fp-value>\n"
1874 "  Maximum cookie age in days. 0 - unlimited\n"
1875 "\n"
1876 " -display-red-gamma <fp-value>\n"
1877 "  Red gamma of display.\n"
1878 "    (default 2.2)\n"
1879 "\n"
1880 " -display-green-gamma <fp-value>\n"
1881 "  Green gamma of display.\n"
1882 "    (default 2.2)\n"
1883 "\n"
1884 " -display-blue-gamma <fp-value>\n"
1885 "  Blue gamma of display.\n"
1886 "    (default 2.2)\n"
1887 "\n"
1888 " -user-gamma <fp-value>\n"
1889 "  Additional gamma.\n"
1890 "    (default 1)\n"
1891 "\n"
1892 " -bfu-aspect <fp-value>\n"
1893 "  Display aspect ration.\n"
1894 "\n"
1895 " -dither-letters <0>/<1>\n"
1896 "  Do letter dithering.\n"
1897 "\n"
1898 " -dither-images <0>/<1>\n"
1899 "  Do image dithering.\n"
1900 "\n"
1901 " -display-optimize <0>/<1>/<2>\n"
1902 "  Optimize for CRT (0), LCD RGB (1), LCD BGR (2).\n"
1903 "\n"
1904 " -gamma-correction <0>/<1>/<2>\n"
1905 "  Type of gamma correction:\n"
1906 "    (default 2)\n"
1907 "  0 - 8-bit (fast).\n"
1908 "  1 - 16-bit (slow).\n"
1909 "  2 - automatically detect according to speed of FPU.\n"
1910 "\n"
1911 " -overwrite-instead-of-scroll <0>/<1>\n"
1912 "  Overwrite the screen instead of scrolling it\n"
1913 "    (valid for svgalib and framebuffer).\n"
1914 "    Overwriting may or may not be faster, depending on hardware.\n"
1915 "\n"
1916 #ifdef HAVE_FREETYPE
1917 " -font <file>\n"
1918 "  Font file for normal text\n"
1919 "\n"
1920 " -font-bold <file>\n"
1921 "  Font file for bold text\n"
1922 "\n"
1923 " -font-monospaced <file>\n"
1924 "  Font file for monospaced text\n"
1925 "\n"
1926 " -font-monospaced-bold <file>\n"
1927 "  Font file for monospaced bold text\n"
1928 "\n"
1929 #ifdef USE_ITALIC
1930 " -font-italic <file>\n"
1931 "  Font file for normal text\n"
1932 "\n"
1933 " -font-italic-bold <file>\n"
1934 "  Font file for bold text\n"
1935 "\n"
1936 " -font-monospaced-italic <file>\n"
1937 "  Font file for monospaced text\n"
1938 "\n"
1939 " -font-monospaced-italic-bold <file>\n"
1940 "  Font file for monospaced bold text\n"
1941 "\n"
1942 #endif
1943 #endif
1944 #ifdef JS
1945 " -enable-javascript <0>/<1>\n"
1946 "  Enable javascript.\n"
1947 "\n"
1948 " -js.verbose-errors <0>/<1>\n"
1949 "  Display javascript errors.\n"
1950 "\n"
1951 " -js.verbose-warnings <0>/<1>\n"
1952 "  Display javascript warnings.\n"
1953 "\n"
1954 " -js.enable-all-conversions <0>/<1>\n"
1955 "  Enable conversions between all types in javascript.\n"
1956 "\n"
1957 " -js.enable-global-resolution <0>/<1>\n"
1958 "  Resolve global names.\n"
1959 "\n"
1960 " -js.manual-confirmation <0>/<1>\n"
1961 "  Ask user to confirm potentially dangerous operations.\n"
1962 "    (opening windows, going to url etc.) Default 1.\n"
1963 "\n"
1964 " -js.recursion-depth <integer>\n"
1965 "  Depth of javascript call stack.\n"
1966 "\n"
1967 " -js.memory-limit <memory amount>\n"
1968 "  Amount of kilobytes the javascript may allocate.\n"
1969 "\n"
1970 #endif
1971 " -html-assume-codepage <codepage>\n"
1972 "  If server didn't specify document character set, assume this.\n"
1973 "\n"
1974 " -html-hard-assume <0>/<1>\n"
1975 "  Use always character set from \"-html-assume-codepage\" no matter\n"
1976 "    what server sent.\n"
1977 "\n"
1978 " -html-tables <0>/<1>\n"
1979 "  Render tables. (0) causes tables being rendered like in lynx.\n"
1980 "\n"
1981 " -html-frames <0>/<1>\n"
1982 "  Render frames. (0) causes frames  rendered like in lynx.\n"
1983 "\n"
1984 " -html-break-long-lines <0>/<1>\n"
1985 "  Break long lines in <pre> sections.\n"
1986 "\n"
1987 " -html-images <0>/<1>\n"
1988 "  Display links to unnamed images as [IMG].\n"
1989 "\n"
1990 " -html-image-names <0>/<1>\n"
1991 "  Display filename of an image instead of [IMG].\n"
1992 "\n"
1993 " -html-display-images <0>/<1>\n"
1994 "  Display images in graphics mode.\n"
1995 "\n"
1996 " -html-image-scale <percent>\n"
1997 "  Scale images in graphics mode.\n"
1998 "\n"
1999 " -html-bare-image-autoscale <0>/<1>\n"
2000 "  Autoscale images displayed on full screen.\n"
2001 "\n"
2002 " -html-numbered-links <0>/<1>\n"
2003 "  Number links in text mode. Allow quick link selection by typing\n"
2004 "    link number and enter.\n"
2005 "\n"
2006 " -html-table-order <0>/<1>\n"
2007 "  In text mode, walk through table by rows (0) or columns (1).\n"
2008 "\n"
2009 " -html-auto-refresh <0>/<1>\n"
2010 "  Process refresh to other page (1), or display link to that page (0).\n"
2011 "\n"
2012 " -html-target-in-new-window <0>/<1>\n"
2013 "  Allow opening new windows from html.\n"
2014 "\n"
2015 " -html-margin <number of spaces>\n"
2016 "  Margin in text mode.\n"
2017 "\n"
2018 " -html-user-font-size <size>\n"
2019 "  Size of font on pages in graphics mode.\n"
2020 "\n"
2021 " -html-text-color <0>-<15>\n"
2022 "  Text color in text mode.\n"
2023 "\n"
2024 " -html-link-color <0>-<15>\n"
2025 "  Link color in text mode.\n"
2026 "\n"
2027 " -html-background-color <0>-<7>\n"
2028 "  Background color in text mode.\n"
2029 "\n"
2030 " -html-ignore-document-color <0>/<1>\n"
2031 "  Ignore colors specified in html document in text mode.\n"
2032 "\n"
2033 " -html-g-text-color 0xRRGGBB\n"
2034 "  Text color in graphics mode.\n"
2035 "\n"
2036 " -html-g-link-color 0xRRGGBB\n"
2037 "  Link color in graphics mode.\n"
2038 "\n"
2039 " -html-g-background-color 0xRRGGBB\n"
2040 "  Background color in graphics mode.\n"
2041 "\n"
2042 " -html-g-ignore-document-color <0>/<1>\n"
2043 "  Ignore colors specified in html document in graphics mode.\n"
2044 "\n"),(
2045 "Keys:\n"
2046 "	ESC	  display menu\n"
2047 "	^C	  quit\n"
2048 "	^P	  scroll up\n"
2049 "	^N	  scroll down\n"
2050 "	[, ]	  scroll left, right\n"
2051 "	up, down  select link\n"
2052 "	->, enter follow link\n"
2053 "	<-, z	  go back\n"
2054 "	g	  go to url\n"
2055 "	G	  go to url based on current url\n"
2056 "	^G	  go to url based on current link\n"
2057 "	^R	  reload\n"
2058 "	/	  search\n"
2059 "	?	  search back\n"
2060 "	n	  find next\n"
2061 "	N	  find previous\n"
2062 "	=	  document info\n"
2063 "	\\	  document source\n"
2064 "	|	  HTTP header\n"
2065 "	*	  toggle displaying of image links (text mode)\n"
2066 "	d	  download\n"
2067 "	s	  bookmarks\n"
2068 "	q	  quit or close current window\n"
2069 "	^X	  cut to clipboard\n"
2070 "	^B	  copy to clipboard\n"
2071 "	^V	  paste from clipboard\n"
2072 "	^K	  cut line (in textarea) or text to the end (in field)\n"
2073 "	^U	  cut all text before cursor\n"
2074 "	^W	  autocomplete url\n"
2075 "	Alt-1 .. Alt-9\n"
2076 "		  switch virtual screens (svgalib and framebuffer)\n"
2077 "\n"
2078 "Keys for braille terminal:\n"
2079 "       arrows	  move the cursor\n"
2080 "       enter	  follow link\n"
2081 "	a	  cursor to status line\n"
2082 "	w	  cursor to title\n"
2083 "	^Y	  next link\n"
2084 "	^T	  previous link\n"
2085 "	y	  next word\n"
2086 "	t	  previous word\n"
2087 "	^O	  next form field entry\n"
2088 ));
2089 
2090 	fflush(stdout);
2091 	do_exit(RET_OK);
2092 	return NULL;
2093 }
2094 
end_config(void)2095 void end_config(void)
2096 {
2097 	struct driver_param *dp;
2098 	struct list_head *ldp;
2099 	foreach(struct driver_param, dp, ldp, driver_params) {
2100 		if (dp->param) mem_free(dp->param);
2101 	}
2102 	free_list(struct driver_param, driver_params);
2103 	if (links_home) mem_free(links_home);
2104 }
2105 
2106 int ggr = 0;
2107 int force_g = 0;
2108 unsigned char ggr_drv[MAX_STR_LEN] = "";
2109 unsigned char ggr_mode[MAX_STR_LEN] = "";
2110 unsigned char ggr_display[MAX_STR_LEN] = "";
2111 
2112 int anonymous = 0;
2113 
2114 unsigned char default_target[MAX_STR_LEN] ="";
2115 
2116 unsigned char *links_home = NULL;
2117 int first_use = 0;
2118 
2119 int disable_libevent = 0;
2120 int disable_openmp = 0;
2121 int no_connect = 0;
2122 int base_session = 0;
2123 int dmp = 0;
2124 int screen_width = 80;
2125 int dump_codepage = -1;
2126 int force_html = 0;
2127 
2128 #ifdef DOS
2129 /* DOS networking is slow with too many connections */
2130 int max_connections = 3;
2131 int max_connections_to_host = 2;
2132 #else
2133 int max_connections = 10;
2134 int max_connections_to_host = 8;
2135 #endif
2136 int max_tries = 3;
2137 int receive_timeout = 120;
2138 int unrestartable_receive_timeout = 600;
2139 int timeout_multiple_addresses = 3;
2140 unsigned char bind_ip_address[16] = "";
2141 unsigned char bind_ipv6_address[INET6_ADDRSTRLEN] = "";
2142 int async_lookup = 1;
2143 int download_utime = 0;
2144 
2145 int max_format_cache_entries = 5;
2146 int memory_cache_size = 4194304;
2147 int image_cache_size = 1048576;
2148 int font_cache_size = 2097152;
2149 int aggressive_cache = 1;
2150 
2151 struct ipv6_options ipv6_options = { ADDR_PREFERENCE_DEFAULT };
2152 struct proxies proxies = { "", "", "", "", "", "", 0 };
2153 struct ssl_options ssl_options = { SSL_WARN_ON_INVALID_CERTIFICATE,
2154 #if defined(DOS) || defined(OPENVMS)
2155 	1,
2156 #else
2157 	0,
2158 #endif
2159 	"", "", "" };
2160 struct http_options http_options = { 0, 1, 0, 0, 0, { 0, 0, REFERER_REAL_SAME_SERVER, "", "", "" } };
2161 struct ftp_options ftp_options = { "somebody@host.domain", 1, 0, 1 };
2162 struct smb_options smb_options = { 0 };
2163 
2164 unsigned char download_dir[MAX_STR_LEN] = "";
2165 
2166 int js_enable = 1;   /* 0=disable javascript */
2167 int js_verbose_errors = 0;   /* 1=create dialog on every javascript error, 0=be quiet and continue */
2168 int js_verbose_warnings = 0;   /* 1=create dialog on every javascript warning, 0=be quiet and continue */
2169 int js_all_conversions = 1;
2170 int js_global_resolve = 1;	/* resolvovani v globalnim adresnim prostoru, kdyz BFU vomitne document */
2171 int js_manual_confirmation = 1; /* !0==annoying dialog on every goto url etc. */
2172 int js_fun_depth = 100;
2173 int js_memory_limit = 5 * 1024;  /* in kilobytes, should be in range 1M-20M (1MB=1024*1024B) */
2174 
2175 double display_red_gamma = 2.2; /* Red gamma exponent of the display */
2176 double display_green_gamma = 2.2; /* Green gamma exponent of the display */
2177 double display_blue_gamma = 2.2; /* Blue gamma exponent of the display */
2178 double user_gamma = 1.0; /* 1.0 for 64 lx. This is the number user directly changes in the menu */
2179 double bfu_aspect = 1; /* 0.1 to 10.0, 1.0 default. >1 makes circle wider */
2180 int display_optimize = 0;	/*0=CRT, 1=LCD RGB, 2=LCD BGR */
2181 int dither_letters = 1;
2182 int dither_images = 1;
2183 int gamma_bits = 2;	/*0 --- 8, 1 --- 16, 2 --- auto */
2184 int overwrite_instead_of_scroll = 1;
2185 
2186 unsigned char font_file[MAX_STR_LEN] = "";
2187 unsigned char font_file_b[MAX_STR_LEN] = "";
2188 unsigned char font_file_m[MAX_STR_LEN] = "";
2189 unsigned char font_file_m_b[MAX_STR_LEN] = "";
2190 
2191 #ifdef USE_ITALIC
2192 unsigned char font_file_i[MAX_STR_LEN] = "";
2193 unsigned char font_file_i_b[MAX_STR_LEN] = "";
2194 unsigned char font_file_i_m[MAX_STR_LEN] = "";
2195 unsigned char font_file_i_m_b[MAX_STR_LEN] = "";
2196 #endif
2197 
2198 
2199 int menu_font_size = G_BFU_DEFAULT_FONT_SIZE;
2200 
2201 unsigned G_BFU_FG_COLOR = G_DEFAULT_BFU_FG_COLOR;
2202 unsigned G_BFU_BG_COLOR = G_DEFAULT_BFU_BG_COLOR;
2203 unsigned G_SCROLL_BAR_AREA_COLOR = G_DEFAULT_SCROLL_BAR_AREA_COLOR;
2204 unsigned G_SCROLL_BAR_BAR_COLOR = G_DEFAULT_SCROLL_BAR_BAR_COLOR;
2205 unsigned G_SCROLL_BAR_FRAME_COLOR = G_DEFAULT_SCROLL_BAR_FRAME_COLOR;
2206 
2207 unsigned char bookmarks_file[MAX_STR_LEN] = "";
2208 int bookmarks_codepage = 0; /* changed to utf-8 table in init_charset() */
2209 
2210 int save_history = 1;
2211 
2212 int enable_cookies = 1;
2213 int save_cookies = 1;
2214 double max_cookie_age = 0;
2215 
2216 struct document_setup dds = {
2217 	0, /* assumed codepage */
2218 	0, /* ignore codepage from server */
2219 	1, /* tables */
2220 	1, /* frames */
2221 	0, /* break_long_lines */
2222 	0, /* images */
2223 	0, /* image_names */
2224 	3, /* margin */
2225 	0, /* num_links */
2226 	0, /* table_order */
2227 	0, /* auto_refresh */
2228 	20, /* font_size */
2229 	1, /* display images */
2230 	100, /* image scale */
2231 	0, /* porn enable */
2232 	0, /* target in new window */
2233 	7, /* t text color */
2234 	3, /* t link color */
2235 	0, /* t background color */
2236 	0, /* t ignore document color */
2237 	0x000000, /* g text color */
2238 	0x0000ff, /* g link color */
2239 	0xc0c0c0, /* g background color */
2240 	0, /* g ignore document color */
2241 };
2242 
2243 static struct option links_options[] = {
2244 	{1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "?"},
2245 	{1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "h"},
2246 	{1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "help"},
2247 	{1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "-help"},
2248 	{1, version_cmd, NULL, NULL, 0, 0, NULL, NULL, "version"},
2249 	{1, lookup_cmd, NULL, NULL, 0, 0, NULL, NULL, "lookup"},
2250 	{1, set_cmd, NULL, NULL, 0, 0, &no_connect, NULL, "no-connect"},
2251 	{1, set_cmd, NULL, NULL, 0, 0, &anonymous, NULL, "anonymous"},
2252 	{1, set_cmd, NULL, NULL, 0, 0, &ggr, NULL, "g"},
2253 	{1, unset_cmd, NULL, NULL, 0, 0, &ggr, NULL, "no-g"},
2254 	{1, setstr_cmd, NULL, NULL, 0, MAX_STR_LEN, ggr_drv, NULL, "driver"},
2255 	{1, setstr_cmd, NULL, NULL, 0, MAX_STR_LEN, default_target, NULL, "target"},
2256 	{1, setstr_cmd, NULL, NULL, 0, MAX_STR_LEN, ggr_mode, NULL, "mode"},
2257 	{1, setstr_cmd, NULL, NULL, 0, MAX_STR_LEN, ggr_display, NULL, "display"},
2258 	{1, gen_cmd, num_rd, NULL, 0, MAXINT, &base_session, NULL, "base-session"},
2259 	{1, set_cmd, NULL, NULL, 0, 0, &force_html, NULL, "force-html"},
2260 	{1, dump_cmd, NULL, NULL, D_SOURCE, 0, NULL, NULL, "source"},
2261 	{1, dump_cmd, NULL, NULL, D_DUMP, 0, NULL, NULL, "dump"},
2262 	{1, gen_cmd, num_rd, NULL, 10, 512, &screen_width, "dump_width", "width" },
2263 	{1, gen_cmd, cp_rd, NULL, 1, 0, &dump_codepage, "dump_codepage", "codepage" },
2264 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, download_dir, "download_dir", "download-dir"},
2265 	{1, gen_cmd, lang_rd, lang_wr, 0, 0, &current_language, "language", "language"},
2266 	{1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections, "max_connections", "max-connections"},
2267 	{1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections_to_host, "max_connections_to_host", "max-connections-to-host"},
2268 	{1, gen_cmd, num_rd, num_wr, 0, 16, &max_tries, "retries", "retries"},
2269 	{1, gen_cmd, num_rd, num_wr, 1, 9999, &receive_timeout, "receive_timeout", "receive-timeout"},
2270 	{1, gen_cmd, num_rd, num_wr, 1, 9999, &unrestartable_receive_timeout, "unrestartable_receive_timeout", "unrestartable-receive-timeout"},
2271 	{1, gen_cmd, num_rd, num_wr, 1, 999, &timeout_multiple_addresses, "timeout_when_trying_multiple_addresses", "timeout-when-trying-multiple-addresses"},
2272 	{1, gen_cmd, ip_rd, str_wr, 0, 16, bind_ip_address, "bind_address", "bind-address"},
2273 	{1, gen_cmd, ipv6_rd, str_wr, 0, INET6_ADDRSTRLEN, bind_ipv6_address, "bind_address_ipv6", "bind-address-ipv6"},
2274 	{1, set_cmd, NULL, NULL, 0, 0, &disable_libevent, NULL, "no-libevent"},
2275 	{1, set_cmd, NULL, NULL, 0, 0, &disable_openmp, NULL, "no-openmp"},
2276 	{1, gen_cmd, num_rd, num_wr, 0, 1, &async_lookup, "async_dns", "async-dns"},
2277 	{1, gen_cmd, num_rd, num_wr, 0, 1, &download_utime, "download_utime", "download-utime"},
2278 	{1, gen_cmd, num_rd, num_wr, 0, 999, &max_format_cache_entries, "format_cache_size", "format-cache-size"},
2279 	{1, gen_cmd, num_rd, num_wr, 0, MAXINT, &memory_cache_size, "memory_cache_size", "memory-cache-size"},
2280 	{1, gen_cmd, num_rd, num_wr, 0, MAXINT, &image_cache_size, "image_cache_size", "image-cache-size"},
2281 	{1, gen_cmd, num_rd, num_wr, 0, MAXINT, &font_cache_size, "font_cache_size", "font-cache-size"},
2282 	{1, gen_cmd, num_rd, num_wr, 0, 1, &aggressive_cache, "http_bugs.aggressive_cache", "aggressive-cache"},
2283 	{1, gen_cmd, num_rd, num_wr, 0, 4, &ipv6_options.addr_preference, "ipv6.address_preference", "address-preference"},
2284 	{1, proxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.http_proxy, "http_proxy", "http-proxy"},
2285 	{1, proxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.ftp_proxy, "ftp_proxy", "ftp-proxy"},
2286 	{1, proxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.https_proxy, "https_proxy", "https-proxy"},
2287 	{1, proxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.socks_proxy, "socks_proxy", "socks-proxy"},
2288 	{1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, proxies.dns_append, "-append_text_to_dns_lookups", NULL}, /* old version incorrectly saved it with '-' */
2289 	{1, noproxy_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.no_proxy, "no_proxy_domains", "no-proxy-domains"},
2290 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, proxies.dns_append, "append_text_to_dns_lookups", "append-text-to-dns-lookups"},
2291 	{1, gen_cmd, num_rd, num_wr, 0, 1, &proxies.only_proxies, "only_proxies", "only-proxies"},
2292 	{1, gen_cmd, num_rd, num_wr, 0, 2, &ssl_options.certificates, "ssl.certificates", "ssl.certificates"},
2293 	{1, gen_cmd, num_rd, num_wr, 0, 1, &ssl_options.built_in_certificates, "ssl.builtin_certificates", "ssl.builtin-certificates"},
2294 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, &ssl_options.client_cert_key, "ssl.client_cert_key", "ssl.client-cert-key"},
2295 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, &ssl_options.client_cert_crt, "ssl.client_cert_crt", "ssl.client-cert-crt"},
2296 	{1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, &ssl_options.client_cert_password, NULL, "ssl.client-cert-password"},
2297 	{1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, &ssl_options.client_cert_key, "client_cert_key", "http.client_cert_key"}, /* backward compatibility with Debian patches */
2298 	{1, gen_cmd, str_rd, NULL, 0, MAX_STR_LEN, &ssl_options.client_cert_crt, "client_cert_crt", "http.client_cert_crt"}, /* backward compatibility with Debian patches */
2299 	{1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.http10, "http_bugs.http10", "http-bugs.http10"},
2300 	{1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.allow_blacklist, "http_bugs.allow_blacklist", "http-bugs.allow-blacklist"},
2301 	{1, gen_cmd, NULL, NULL, 0, 1, NULL, "http_bugs.bug_302_redirect", NULL},
2302 	{1, gen_cmd, NULL, NULL, 0, 1, NULL, "http_bugs.bug_post_no_keepalive", NULL},
2303 	{1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.no_accept_charset, "http_bugs.no_accept_charset", "http-bugs.bug-no-accept-charset"},
2304 	{1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.no_compression, "http_bugs.no_compression", "http-bugs.no-compression"},
2305 	{1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.retry_internal_errors, "http_bugs.retry_internal_errors", "http-bugs.retry-internal-errors"},
2306 	{1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.header.fake_firefox, "fake_firefox", "http.fake-firefox"},
2307 	{1, gen_cmd, num_rd, num_wr, 0, 1, &http_options.header.do_not_track, "http_do_not_track", "http.do-not-track"},
2308 	{1, gen_cmd, num_rd, num_wr, 0, 4, &http_options.header.referer, "http_referer", "http.referer"},
2309 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, &http_options.header.fake_referer, "fake_referer", "http.fake-referer"},
2310 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, &http_options.header.fake_useragent, "fake_useragent", "http.fake-user-agent"},
2311 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, &http_options.header.extra_header, "http.extra_header", "http.extra-header"},
2312 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, ftp_options.anon_pass, "ftp.anonymous_password", "ftp.anonymous-password"},
2313 	{1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.passive_ftp, "ftp.use_passive", "ftp.use-passive"},
2314 	{1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.eprt_epsv, "ftp.use_eprt_epsv", "ftp.use-eprt-epsv"},
2315 	{1, gen_cmd, NULL, NULL, 0, 1, NULL, "ftp.fast", NULL},
2316 	{1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.set_tos, "ftp.set_iptos", "ftp.set-iptos"},
2317 	{1, gen_cmd, num_rd, num_wr, 0, 1, &smb_options.allow_hyperlinks_to_smb, "smb.allow_hyperlinks_to_smb", "smb.allow-hyperlinks-to-smb"},
2318 	{1, gen_cmd, num_rd, num_wr, 1, MAX_FONT_SIZE, &menu_font_size, "menu_font_size", "menu-font-size"},
2319 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &G_BFU_BG_COLOR, "background_color", "menu-background-color"},
2320 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &G_BFU_FG_COLOR, "foreground_color", "menu-foreground-color"},
2321 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &G_SCROLL_BAR_AREA_COLOR, "scroll_bar_area_color", "scroll-bar-area-color"},
2322 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &G_SCROLL_BAR_BAR_COLOR, "scroll_bar_bar_color", "scroll-bar-bar-color"},
2323 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &G_SCROLL_BAR_FRAME_COLOR, "scroll_bar_frame_color", "scroll-bar-frame-color"},
2324 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, bookmarks_file, "bookmarks_file", "bookmarks-file"},
2325 	{1, gen_cmd, cp_rd, cp_wr, 0, 0, &bookmarks_codepage, "bookmarks_codepage", "bookmarks-codepage"},
2326 	{1, gen_cmd, num_rd, num_wr, 0, 1, &save_history, "save_url_history", "save-url-history"},
2327 	{1, gen_cmd, num_rd, num_wr, 0, 1, &enable_cookies, "enable_cookies", "enable-cookies"},
2328 	{1, gen_cmd, num_rd, num_wr, 0, 1, &save_cookies, "save_cookies", "save-cookies"},
2329 	{1, gen_cmd, dbl_rd, dbl_wr, 0, 999999900, &max_cookie_age, "max_cookie_age", "max-cookie-age"},
2330 	{1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &display_red_gamma, "display_red_gamma", "display-red-gamma"},
2331 	{1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &display_green_gamma, "display_green_gamma", "display-green-gamma"},
2332 	{1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &display_blue_gamma, "display_blue_gamma", "display-blue-gamma"},
2333 	{1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &user_gamma, "user_gamma", "user-gamma"},
2334 	{1, gen_cmd, dbl_rd, dbl_wr, 25, 400, &bfu_aspect, "bfu_aspect", "bfu-aspect"},
2335 	{1, gen_cmd, NULL, NULL, 0, 1, NULL, "aspect_on", NULL},
2336 	{1, gen_cmd, num_rd, num_wr, 0, 2, &display_optimize, "display_optimize", "display-optimize"},
2337 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dither_letters, "dither_letters", "dither-letters"},
2338 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dither_images, "dither_images", "dither-images"},
2339 	{1, gen_cmd, num_rd, num_wr, 0, 2, &gamma_bits, "gamma_correction", "gamma-correction"},
2340 	{1, gen_cmd, num_rd, num_wr, 0, 1, &overwrite_instead_of_scroll, "overwrite_instead_of_scroll", "overwrite-instead-of-scroll"},
2341 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file, "font", "font"},
2342 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file_b, "font_bold", "font-bold"},
2343 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file_m, "font_monospaced", "font-monospaced"},
2344 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file_m_b, "font_monospaced_bold", "font-monospaced-bold"},
2345 #ifdef USE_ITALIC
2346 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file_i, "font_italic", "font-italic"},
2347 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file_i_b, "font_italic_bold", "font-italic-bold"},
2348 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file_i_m, "font_monospaced_italic", "font-monospaced-italic"},
2349 	{1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, font_file_i_m_b, "font_monospaced_italic_bold", "font-monospaced-italic-bold"},
2350 #endif
2351 	{1, gen_cmd, num_rd, NULL, 0, 1, &js_enable, "enable_javascript", NULL},
2352 	{1, gen_cmd, num_rd, NULL, 0, 1, &js_verbose_errors, "verbose_javascript_errors", NULL},
2353 	{1, gen_cmd, num_rd, NULL, 0, 1, &js_verbose_warnings, "verbose_javascript_warnings", NULL},
2354 	{1, gen_cmd, num_rd, NULL, 0, 1, &js_all_conversions, "enable_all_conversions", NULL},
2355 	{1, gen_cmd, num_rd, NULL, 0, 1, &js_global_resolve, "enable_global_resolution", NULL},
2356 	{1, gen_cmd, num_rd, NULL, 0, 1, &js_manual_confirmation, "javascript_manual_confirmation", NULL},
2357 	{1, gen_cmd, num_rd, NULL, 0, 999999, &js_fun_depth, "js_recursion_depth", NULL},
2358 	{1, gen_cmd, num_rd, NULL, 1024, 30*1024, &js_memory_limit, "js_memory_limit", NULL},
2359 	{1, gen_cmd, cp_rd, NULL, 0, 0, &dds.assume_cp, "assume_codepage", NULL},
2360 	{1, NULL, term_rd, term_wr, 0, 0, NULL, "terminal", NULL},
2361 	{1, NULL, term2_rd, NULL, 0, 0, NULL, "terminal2", NULL},
2362 	{1, NULL, type_rd, type_wr, 0, 0, NULL, "association", NULL},
2363 	{1, NULL, ext_rd, ext_wr, 0, 0, NULL, "extension", NULL},
2364 	{1, NULL, prog_rd, prog_wr, 0, 0, &mailto_prog, "mailto", NULL},
2365 	{1, NULL, prog_rd, prog_wr, 0, 0, &telnet_prog, "telnet", NULL},
2366 	{1, NULL, prog_rd, prog_wr, 0, 0, &tn3270_prog, "tn3270", NULL},
2367 	{1, NULL, prog_rd, prog_wr, 0, 0, &mms_prog, "mms", NULL},
2368 	{1, NULL, prog_rd, prog_wr, 0, 0, &magnet_prog, "magnet", NULL},
2369 	{1, NULL, block_rd, block_wr, 0, 0, NULL, "imageblock", NULL},
2370 	{1, NULL, dp_rd, dp_wr, 0, 0, NULL, "video_driver", NULL},
2371 	{0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL},
2372 };
2373 
2374 static struct option html_options[] = {
2375 	{1, gen_cmd, cp_rd, cp_wr, 0, 0, &dds.assume_cp, "html_assume_codepage", "html-assume-codepage"},
2376 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.hard_assume, "html_hard_assume", "html-hard-assume"},
2377 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.tables, "html_tables", "html-tables"},
2378 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.frames, "html_frames", "html-frames"},
2379 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.break_long_lines, "html_break_long_lines", "html-break-long-lines"},
2380 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.images, "html_images", "html-images"},
2381 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.image_names, "html_image_names", "html-image-names"},
2382 	{1, gen_cmd, num_rd, num_wr, 0, 9, &dds.margin, "html_margin", "html-margin"},
2383 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.num_links, "html_numbered_links", "html-numbered-links"},
2384 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.table_order, "html_table_order", "html-table-order"},
2385 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.auto_refresh, "html_auto_refresh", "html-auto-refresh"},
2386 	{1, gen_cmd, num_rd, num_wr, 1, MAX_FONT_SIZE, &dds.font_size, "html_font_size", "html-user-font-size"},
2387 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.display_images, "html_display_images", "html-display-images"},
2388 	{1, gen_cmd, num_rd, num_wr, 1, 999, &dds.image_scale, "html_image_scale", "html-image-scale"},
2389 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.porn_enable, "html_bare_image_autoscale", "html-bare-image-autoscale"},
2390 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.target_in_new_window, "html_target_in_new_window", "html-target-in-new-window"},
2391 	{1, gen_cmd, num_rd, num_wr, 0, 15, &dds.t_text_color, "html_text_color", "html-text-color"},
2392 	{1, gen_cmd, num_rd, num_wr, 0, 15, &dds.t_link_color, "html_link_color", "html-link-color"},
2393 	{1, gen_cmd, num_rd, num_wr, 0, 7, &dds.t_background_color, "html_background_color", "html-background-color"},
2394 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.t_ignore_document_color, "html_ignore_document_color", "html-ignore-document-color"},
2395 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &dds.g_text_color, "html_g_text_color", "html-g-text-color"},
2396 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &dds.g_link_color, "html_g_link_color", "html-g-link-color"},
2397 	{1, gen_cmd, num_rd, num_wr, 0, 0xffffff, &dds.g_background_color, "html_g_background_color", "html-g-background-color"},
2398 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dds.g_ignore_document_color, "html_g_ignore_document_color", "html-g-ignore-document-color"},
2399 	{0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL},
2400 };
2401 
2402 static struct option *all_options[] = { links_options, html_options, NULL, };
2403 
parse_options(int argc,char * argv[])2404 unsigned char *parse_options(int argc, char *argv[])
2405 {
2406 	int i;
2407 	unsigned char **u_argv, *ret;
2408 	if ((unsigned)argc > MAXINT / sizeof(unsigned char *)) overalloc();
2409 	u_argv = mem_alloc(argc * sizeof(unsigned char *));
2410 	for (i = 0; i < argc; i++)
2411 		u_argv[i] = cast_uchar argv[i];
2412 	ret = p_arse_options(argc, u_argv, all_options);
2413 	mem_free(u_argv);
2414 	return ret;
2415 }
2416 
load_config_file(unsigned char * prefix,unsigned char * name)2417 static void load_config_file(unsigned char *prefix, unsigned char *name)
2418 {
2419 	unsigned char *c, *config_file;
2420 	config_file = stracpy(prefix);
2421 	if (!config_file) return;
2422 	add_to_strn(&config_file, name);
2423 	if ((c = read_config_file(config_file))) goto ok;
2424 	mem_free(config_file);
2425 	config_file = stracpy(prefix);
2426 	if (!config_file) return;
2427 	add_to_strn(&config_file, cast_uchar ".");
2428 	add_to_strn(&config_file, name);
2429 	if ((c = read_config_file(config_file))) goto ok;
2430 	mem_free(config_file);
2431 	return;
2432 	ok:
2433 	parse_config_file(config_file, c, all_options);
2434 	mem_free(c);
2435 	mem_free(config_file);
2436 }
2437 
load_config(void)2438 void load_config(void)
2439 {
2440 #ifdef SHARED_CONFIG_DIR
2441 	load_config_file(cast_uchar SHARED_CONFIG_DIR, cast_uchar "links.cfg");
2442 #endif
2443 	load_config_file(links_home, cast_uchar "links.cfg");
2444 	load_config_file(links_home, cast_uchar "html.cfg");
2445 	load_config_file(links_home, cast_uchar "user.cfg");
2446 }
2447 
write_config(struct terminal * term)2448 void write_config(struct terminal *term)
2449 {
2450 #ifdef G
2451 	if (F) update_driver_param();
2452 #endif
2453 	write_config_data(links_home, cast_uchar "links.cfg", links_options, term);
2454 }
2455 
write_html_config(struct terminal * term)2456 void write_html_config(struct terminal *term)
2457 {
2458 	write_config_data(links_home, cast_uchar "html.cfg", html_options, term);
2459 }
2460 
load_url_history(void)2461 void load_url_history(void)
2462 {
2463 	unsigned char *history_file, *hs;
2464 	unsigned char *hsp;
2465 
2466 	if (anonymous) return;
2467 	/* Must have been called after init_home */
2468 	if (!links_home) return;
2469 	history_file = stracpy(links_home);
2470 	add_to_strn(&history_file, cast_uchar "links.his");
2471 	hs = read_config_file(history_file);
2472 	mem_free(history_file);
2473 	if (!hs) return;
2474 	for (hsp = hs; *hsp; ) {
2475 		unsigned char *hsl, *hsc;
2476 		for (hsl = hsp; *hsl && *hsl != 10 && *hsl != 13; hsl++)
2477 			;
2478 		hsc = memacpy(hsp, hsl - hsp);
2479 		add_to_history(NULL, &goto_url_history, hsc);
2480 		mem_free(hsc);
2481 		hsp = hsl;
2482 		while (*hsp == 10 || *hsp == 13) hsp++;
2483 	}
2484 	mem_free(hs);
2485 }
2486 
save_url_history(void)2487 void save_url_history(void)
2488 {
2489 	struct history_item *hi;
2490 	struct list_head *lhi;
2491 	unsigned char *history_file;
2492 	unsigned char *hs;
2493 	int hsl = 0;
2494 	if (anonymous || !save_history || proxies.only_proxies) return;
2495 
2496 	/* Must have been called after init_home */
2497 	if (!links_home) return;
2498 	history_file = stracpy(links_home);
2499 	add_to_strn(&history_file, cast_uchar "links.his");
2500 	hs = init_str();
2501 	hsl = 0;
2502 	foreachback(struct history_item, hi, lhi, goto_url_history.items) {
2503 		if (!*hi->str || hi->str[0] == ' ' || strchr(cast_const_char hi->str, 10) || strchr(cast_const_char hi->str, 13)) continue;
2504 		if (!url_not_saveable(hi->str)) {
2505 			add_to_str(&hs, &hsl, hi->str);
2506 			add_to_str(&hs, &hsl, cast_uchar NEWLINE);
2507 		}
2508 	}
2509 	write_to_config_file(history_file, hs, 0);
2510 	mem_free(history_file);
2511 	mem_free(hs);
2512 }
2513 
2514