1 #include "links.h"
2
3 unsigned char system_name[MAX_STR_LEN];
4
get_system_name()5 void get_system_name()
6 {
7 #ifdef OS2
8 if (!os_get_system_name(system_name))
9 return;
10 #endif
11 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
12 {
13 struct utsname name;
14 int rs;
15 memset(&name, 0, sizeof name);
16 EINTRLOOP(rs, uname(&name));
17 if (!rs) {
18 #ifdef OPENVMS
19 unsigned char * volatile p;
20 #endif
21 unsigned char *str = init_str();
22 int l = 0;
23 add_to_str(&str, &l, name.sysname);
24 add_to_str(&str, &l, " ");
25 #ifdef OPENVMS
26 add_to_str(&str, &l, name.version);
27 #else
28 add_to_str(&str, &l, name.release);
29 #endif
30 add_to_str(&str, &l, " ");
31 #ifdef OPENVMS
32 p = name.nodename + sizeof(name.nodename);
33 if ((unsigned char *)(&name + 1) - p >= 16 && memchr(p, 0, 16))
34 add_to_str(&str, &l, cast_uchar p);
35 else
36 #endif
37 add_to_str(&str, &l, name.machine);
38 safe_strncpy(system_name, str, MAX_STR_LEN);
39 mem_free(str);
40 return;
41 }
42 }
43 #endif
44 #ifdef HAVE_POPEN
45 if (0) {
46 FILE *f;
47 unsigned char *p;
48 memset(system_name, 0, MAX_STR_LEN);
49 ENULLLOOP(f, popen("uname -srm", "r"));
50 if (!f) goto fail;
51 if (fread(system_name, 1, MAX_STR_LEN - 1, f) <= 0) {
52 pclose(f);
53 goto fail;
54 }
55 pclose(f);
56 for (p = system_name; *p; p++) if (*p < ' ') {
57 *p = 0;
58 break;
59 }
60 if (system_name[0]) return;
61 }
62 fail:
63 #endif
64 strcpy(system_name, SYSTEM_NAME);
65 }
66
67 unsigned char compiler_name[MAX_STR_LEN];
68
get_compiler_name(void)69 static void get_compiler_name(void)
70 {
71 #if defined(__BORLANDC__)
72
73 int w = __BORLANDC__+0;
74 int v1 = w / 0x100;
75 int v2 = w / 0x10 % 0x10;
76 int v3 = w % 0x10;
77 if (v1 == 4 && v2 < 5) v1 = 3;
78 if (v1 == 4 && v2 == 5) v2 = 0;
79
80 if (!v3) sprintf(cast_char compiler_name, "Borland C %d.%d", v1, v2);
81 else sprintf(cast_char compiler_name, "Borland C %d.%d.%d", v1, v2, v3);
82
83 #elif defined(__clang__)
84
85 #if !defined(__clang_major__) || !defined(__clang_minor__)
86 sprintf(cast_char compiler_name, "LLVM/Clang");
87 #else
88 int v1 = __clang_major__+0;
89 int v2 = __clang_minor__+0;
90 #ifdef __clang_patchlevel__
91 int v3 = __clang_patchlevel__+0;
92 #else
93 int v3 = 0;
94 #endif
95 if (v3 > 0) sprintf(cast_char compiler_name, "LLVM/Clang %d.%d.%d", v1, v2, v3);
96 else sprintf(cast_char compiler_name, "LLVM/Clang %d.%d", v1, v2);
97 #endif
98
99 #elif defined(__COMO_VERSION__)
100
101 int w = __COMO_VERSION__+0;
102 int v1 = w / 100;
103 int v2 = w % 100;
104 if (!(v2 % 10)) sprintf(cast_char compiler_name, "Comeau C %d.%d", v1, v2 / 10);
105 else sprintf(cast_char compiler_name, "Comeau C %d.%02d", v1, v2);
106
107 #elif defined(__convexc__)
108
109 sprintf(cast_char compiler_name, "Convex C");
110
111 #elif defined(_CRAYC)
112
113 #if !defined(_RELEASE) || !defined(_RELEASE_MINOR)
114 sprintf(cast_char compiler_name, "Cray C");
115 #else
116 int v1 = _RELEASE+0;
117 int v2 = _RELEASE_MINOR+0;
118 sprintf(cast_char compiler_name, "Cray C %d.%d", v1, v2);
119 #endif
120
121 #elif defined(__DCC__)
122
123 #ifndef __VERSION_NUMBER__
124 sprintf(cast_char compiler_name, "Diab C");
125 #else
126 int w = __VERSION_NUMBER__+0;
127 int v1 = w / 1000;
128 int v2 = w / 100 % 10;
129 int v3 = w % 100;
130 sprintf(cast_char compiler_name, "Diab C %d.%d.%02d", v1, v2, v3);
131 #endif
132
133 #elif defined(__DMC__)
134
135 int w = __DMC__+0;
136 int v1 = w / 0x100;
137 int v2 = w / 0x10 % 0x10;
138 int v3 = w % 0x10;
139 if (!v3) sprintf(cast_char compiler_name, "Digital Mars C %d.%d", v1, v2);
140 else sprintf(cast_char compiler_name, "Digital Mars C %d.%d.%d", v1, v2, v3);
141
142 #elif defined(__DECC_VER)
143
144 int w = __DECC_VER+0;
145 int v1 = w / 10000000;
146 int v2 = w / 100000 % 100;
147 int v3 = w % 10000;
148 sprintf(cast_char compiler_name, "DEC C %d.%d-%03d", v1, v2, v3);
149
150 #elif defined(__ghs__)
151
152 #ifndef __GHS_VERSION_NUMBER__
153 sprintf(cast_char compiler_name, "Green Hill C");
154 #else
155 int w = __GHS_VERSION_NUMBER__+0;
156 int v1 = w / 100;
157 int v2 = w / 10 % 10;
158 int v3 = w % 10;
159 sprintf(cast_char compiler_name, "Green Hill C %d.%d.%d", v1, v2, v3);
160 #endif
161
162 #elif defined(__HIGHC__)
163
164 sprintf(cast_char compiler_name, "MetaWare High C");
165
166 #elif defined(__HP_cc)
167
168 int w = __HP_cc+0;
169 int v1 = w / 10000;
170 int v2 = w / 100 % 100;
171 int v3 = w % 100;
172 if (w <= 1) sprintf(cast_char compiler_name, "HP CC");
173 else sprintf(cast_char compiler_name, "HP CC %d.%02d.%02d", v1, v2, v3);
174
175 #elif defined(__xlc__)
176
177 int w = __xlc__+0;
178 int v1 = w / 0x100;
179 int v2 = w % 0x100;
180 sprintf(cast_char compiler_name, "IBM XL C %X.%X", v1, v2);
181
182 #elif defined(__IBMC__) && defined(__COMPILER_VER__)
183
184 unsigned w = __COMPILER_VER__+0;
185 int v0 = w / 0x10000000;
186 int v1 = w / 0x1000000 % 0x10;
187 int v2 = w / 0x10000 % 0x100;
188 int v3 = w % 0x10000;
189 unsigned char *os = !v0 ? "S/370" : v0 == 1 ? "OS/390" : v0 == 4 ? "z/OS" : "";
190 sprintf(cast_char compiler_name, "IBM%s%s XL C %X.%0X.%X", *os ? " " : "", os, v1, v2, v3);
191
192 #elif defined(__ICC)
193
194 int w = __ICC+0;
195 int v1 = w / 100;
196 int v2 = w % 100;
197 if (!(v2 % 10)) sprintf(cast_char compiler_name, "Intel C %d.%d", v1, v2 / 10);
198 else sprintf(cast_char compiler_name, "Intel C %d.%02d", v1, v2);
199
200 #elif defined(__LCC__)
201
202 sprintf(cast_char compiler_name, "LCC");
203
204 #elif defined(__NDPC__)
205
206 sprintf(cast_char compiler_name, "Microway NDP C");
207
208 #elif defined(_MSC_VER)
209
210 int w = _MSC_VER+0;
211 int v1 = w / 100;
212 int v2 = w % 100;
213 unsigned char *visual = cast_uchar "";
214 if (v1 >= 8) {
215 v1 -= 6;
216 if (v1 == 2) v1 = 1;
217 visual = cast_uchar "Visual ";
218 }
219 if (!(v2 % 10)) sprintf(cast_char compiler_name, "Microsoft %sC %d.%d", visual, v1, v2 / 10);
220 else sprintf(cast_char compiler_name, "Microsoft %sC %d.%02d", visual, v1, v2);
221
222 #elif defined(__MWERKS__)
223
224 int w = __MWERKS__+0;
225 int v1 = w / 0x1000;
226 int v2 = w / 0x100 % 0x10;
227 int v3 = w % 0x100;
228 if (w <= 1) sprintf(cast_char compiler_name, "Metrowerks CodeWarrior");
229 sprintf(cast_char compiler_name, "Metrowerks CodeWarrior %x.%x.%x", v1, v2, v3);
230
231 #elif defined(__NWCC__)
232
233 sprintf(cast_char compiler_name, "NWCC");
234
235 #elif defined(__OPEN64__)
236
237 unsigned char *n = cast_uchar "Open64 " __OPEN64__;
238 if (strlen(cast_const_char n) >= sizeof(cast_char compiler_name)) n = cast_uchar "Open64";
239 strcpy(cast_char compiler_name, cast_const_char n);
240
241 #elif defined(__PATHSCALE__)
242
243 unsigned char *n = cast_uchar "PathScale " __PATHSCALE__;
244 if (strlen(cast_const_char n) >= sizeof(cast_char compiler_name)) n = cast_uchar "PathScale";
245 strcpy(cast_char compiler_name, cast_const_char n);
246
247 #elif defined(__PCC__)
248
249 int v1 = __PCC__+0;
250 #ifdef __PCC_MINOR__
251 int v2 = __PCC_MINOR__+0;
252 #else
253 int v2 = 0;
254 #endif
255 #ifdef __PCC_MINORMINOR__
256 int v3 = __PCC_MINORMINOR__+0;
257 #else
258 int v3 = 0;
259 #endif
260 sprintf(cast_char compiler_name, "PCC %d.%d.%d", v1, v2, v3);
261
262 #elif defined(__PGI) || defined(__PGIC__)
263
264 #if !defined(__PGIC__) || !defined(__PGIC_MINOR__)
265 sprintf(cast_char compiler_name, "The Portland Group C");
266 #else
267 int v1 = __PGIC__+0;
268 int v2 = __PGIC_MINOR__+0;
269 #ifdef __PGIC_PATCHLEVEL__
270 int v3 = __PGIC_PATCHLEVEL__+0;
271 #else
272 int v3 = 0;
273 #endif
274 if (v3 > 0) sprintf(cast_char compiler_name, "The Portland Group C %d.%d.%d", v1, v2, v3);
275 else sprintf(cast_char compiler_name, "The Portland Group C %d.%d", v1, v2);
276 #endif
277
278 #elif defined(__SASC__)
279
280 int w = __SASC__+0;
281 int v1 = w / 100;
282 int v2 = w % 100;
283 sprintf(cast_char compiler_name, "SAS C %d.%02d", v1, v2);
284
285 #elif (defined(__sgi) && defined(_COMPILER_VERSION)) || defined(_SGI_COMPILER_VERSION)
286
287 #ifdef _SGI_COMPILER_VERSION
288 int w = _SGI_COMPILER_VERSION;
289 #else
290 int w = _COMPILER_VERSION;
291 #endif
292 int v1 = w / 100;
293 int v2 = w / 10 % 10;
294 int v3 = w % 10;
295 sprintf(cast_char compiler_name, "MIPSpro %d.%d.%d", v1, v2, v3);
296
297 #elif defined(__SUNPRO_C)
298
299 int w = __SUNPRO_C+0;
300 int div = w >= 0x1000 ? 0x1000 : 0x100;
301 int v2_digits = w >= 0x1000 ? 2 : 1;
302 int v1 = w / div;
303 int v2 = w % div / 0x10;
304 int v3 = w % 0x10;
305 if (!v3) sprintf(cast_char compiler_name, "Sun C %X.%0*X", v1, v2_digits, v2);
306 else sprintf(cast_char compiler_name, "Sun C %X.%0*X.%X", v1, v2_digits, v2, v3);
307
308 #elif defined(__SYSC__) && defined(__SYSC_VER__)
309
310 int w = __SYSC_VER__+0;
311 int v1 = w / 10000;
312 int v2 = w / 100 % 100;
313 int v3 = w % 100;
314 sprintf(cast_char compiler_name, "Dignus Systems C %d.%02d.%02d", v1, v2, v3);
315
316 #elif defined(__TenDRA__)
317
318 sprintf(cast_char compiler_name, "TenDRA C");
319
320 #elif defined(__TINYC__)
321
322 sprintf(cast_char compiler_name, "Tiny C");
323
324 #elif defined(_UCC)
325
326 #if !defined(_MAJOR_REV) || !defined(_MINOR_REV)
327 sprintf(cast_char compiler_name, "Ultimate C");
328 #else
329 int v1 = _MAJOR_REV+0;
330 int v2 = _MAJOR_REV+0;
331 sprintf(cast_char compiler_name, "Ultimate C %d.%d", v1, v2);
332 #endif
333
334 #elif defined(__USLC__)
335
336 sprintf(cast_char compiler_name, "USL C");
337
338 #elif defined(__VAXC)
339
340 sprintf(cast_char compiler_name, "VAX C");
341
342 #elif defined(__VOSC__)
343
344 sprintf(cast_char compiler_name, "Stratus VOS C");
345
346 #elif defined(__WATCOMC__)
347
348 int w = __WATCOMC__+0;
349 int v1 = w / 100;
350 int v2 = w % 100;
351 unsigned char *op = cast_uchar "";
352 if (v1 >= 12) {
353 v1 -= 11;
354 op = cast_uchar "Open";
355 }
356 if (!(v2 % 10)) sprintf(cast_char compiler_name, "%sWatcom C %d.%d", op, v1, v2 / 10);
357 else sprintf(cast_char compiler_name, "%sWatcom C %d.%02d", op, v1, v2);
358
359 #elif defined(__GNUC__)
360
361 int v1 = __GNUC__+0;
362 #ifdef __GNUC_MINOR__
363 int v2 = __GNUC_MINOR__+0;
364 #else
365 int v2 = -1;
366 #endif
367 #ifdef __GNUC_PATCHLEVEL__
368 int v3 = __GNUC_PATCHLEVEL__+0;
369 #else
370 int v3 = 0;
371 #endif
372 #if defined(__llvm__)
373 unsigned char *prefix = cast_uchar "LLVM/";
374 #else
375 unsigned char *prefix = cast_uchar "";
376 #endif
377 if (v1 == 2 && (v2 >= 90 && v2 <= 91)) sprintf(cast_char compiler_name, "%sEGCS 1.%d", prefix, v2 - 90);
378 else if (v3 > 0 && v2 >= 0) sprintf(cast_char compiler_name, "%sGNU C %d.%d.%d", prefix, v1, v2, v3);
379 else if (v2 >= 0) sprintf(cast_char compiler_name, "%sGNU C %d.%d", prefix, v1, v2);
380 else sprintf(cast_char compiler_name, "%sGNU C %d", prefix, v1);
381
382 #else
383
384 strcpy(cast_char compiler_name, "unknown compiler");
385
386 #endif
387 }
388
389 extern struct option links_options[];
390 extern struct option html_options[];
391
392 struct option *all_options[] = { links_options, html_options, NULL, };
393
p_arse_options(int argc,unsigned char * argv[],struct option ** opt)394 unsigned char *p_arse_options(int argc, unsigned char *argv[], struct option **opt)
395 {
396 unsigned char *e, *u = NULL;
397 int i;
398 for (i = 0; i < argc; i++) {
399 if (strlen(argv[i]) >= MAXINT) {
400 fprintf(stderr, "Too long parameter\n");
401 return NULL;
402 }
403 }
404 while (argc) {
405 argv++, argc--;
406 if (argv[-1][0] == '-') {
407 struct option *options;
408 struct option **op;
409 for (op = opt; (options = *op); op++) for (i = 0; options[i].p; i++)
410 if (options[i].rd_cmd && options[i].cmd_name &&
411 !strcasecmp(options[i].cmd_name, &argv[-1][1])) {
412 if ((e = options[i].rd_cmd(&options[i], &argv, &argc))) {
413 if (e[0]) fprintf(stderr, "Error parsing option %s: %s\n", argv[-1], e);
414 return NULL;
415 }
416 goto found;
417 }
418 uu:
419 fprintf(stderr, "Unknown option %s\n", argv[-1]);
420 return NULL;
421 } else if (!u) u = argv[-1];
422 else goto uu;
423 found:;
424 }
425 if (u) return u;
426 return "";
427 }
428
parse_options(int argc,unsigned char * argv[])429 unsigned char *parse_options(int argc, unsigned char *argv[])
430 {
431 return p_arse_options(argc, argv, all_options);
432 }
433
get_token(unsigned char ** line)434 unsigned char *get_token(unsigned char **line)
435 {
436 unsigned char *s = NULL;
437 int l = 0;
438 int escape = 0;
439 int quote = 0;
440
441 while (**line == ' ' || **line == 9) (*line)++;
442 if (**line) {
443 for (s = init_str(); **line; (*line)++) {
444 if (escape)
445 escape = 0;
446 else if (**line == '\\') {
447 escape = 1;
448 continue;
449 }
450 else if (**line == '"') {
451 quote = !quote;
452 continue;
453 }
454 else if ((**line == ' ' || **line == 9) && !quote)
455 break;
456 add_chr_to_str(&s, &l, **line);
457 }
458 }
459 return s;
460 }
461
parse_config_file(unsigned char * name,unsigned char * file,struct option ** opt)462 void parse_config_file(unsigned char *name, unsigned char *file, struct option **opt)
463 {
464 struct option *options;
465 struct option **op;
466 int err = 0;
467 int line = 0;
468 unsigned char *e;
469 int i;
470 unsigned char *n, *p;
471 unsigned char *tok;
472 int nl, pl;
473 while (file[0]) {
474 line++;
475 while (file[0] && (file[0] == ' ' || file[0] == 9)) file++;
476 n = file;
477 while (file[0] && file[0] > ' ') file++;
478 if (file == n) {
479 if (file[0]) file++;
480 continue;
481 }
482 nl = file - n;
483 while (file[0] == 9 || file[0] == ' ') file++;
484 p = file;
485 while (file[0] && file[0] != 10 && file[0] != 13) file++;
486 pl = file - p;
487 if (file[0]) {
488 if ((file[1] == 10 || file[1] == 13) && file[0] != file[1]) file++;
489 file++;
490 }
491 tok = NULL;
492 if (n[0] == '#') goto f;
493 if (!(tok = get_token(&n))) goto f;
494 nl = strlen(tok);
495 for (op = opt; (options = *op); op++)
496 for (i = 0; options[i].p; i++) if (options[i].cfg_name && (size_t)nl == strlen(options[i].cfg_name) && !casecmp(tok, options[i].cfg_name, nl)) {
497 unsigned char *o = memacpy(p, pl);
498 if ((e = options[i].rd_cfg(&options[i], o))) {
499 if (e[0]) fprintf(stderr, "Error parsing config file %s, line %d: %s\n", name, line, e), err = 1;
500 }
501 mem_free(o);
502 goto f;
503 }
504 fprintf(stderr, "Unknown option in config file %s, line %d\n", name, line);
505 err = 1;
506 f:
507 if (tok) mem_free(tok);
508 }
509 if (err) fprintf(stderr, "\007"), sleep(3);
510 }
511
create_config_string(struct option * options)512 unsigned char *create_config_string(struct option *options)
513 {
514 unsigned char *s = init_str();
515 int l = 0;
516 int i;
517 add_to_str(&s, &l, "# This file is automatically generated by Links -- please do not edit.");
518 for (i = 0; options[i].p; i++) if (options[i].wr_cfg)
519 options[i].wr_cfg(&options[i], &s, &l);
520 add_to_str(&s, &l, NEWLINE);
521 return s;
522 }
523
524 #define FILE_BUF 1024
525
526 unsigned char cfg_buffer[FILE_BUF];
527
read_config_file(unsigned char * name)528 unsigned char *read_config_file(unsigned char *name)
529 {
530 int h, r;
531 int l = 0;
532 unsigned char *s;
533 int rs;
534 EINTRLOOP(h, open(name, O_RDONLY | O_NOCTTY));
535 if (h == -1) return NULL;
536 set_bin(h);
537 s = init_str();
538 while ((r = hard_read(h, cfg_buffer, FILE_BUF)) > 0) {
539 int i;
540 for (i = 0; i < r; i++) if (!cfg_buffer[i]) cfg_buffer[i] = ' ';
541 add_bytes_to_str(&s, &l, cfg_buffer, r);
542 }
543 if (r == -1) mem_free(s), s = NULL;
544 EINTRLOOP(rs, close(h));
545 return s;
546 }
547
write_to_config_file(unsigned char * name,unsigned char * c)548 int write_to_config_file(unsigned char *name, unsigned char *c)
549 {
550 int rr;
551 int h, w;
552 int count = 0;
553 int tmp_namel;
554 unsigned char *tmp_name;
555 int rs, err;
556 try_new_count:
557 tmp_namel = 0;
558 tmp_name = init_str();
559 add_to_str(&tmp_name, &tmp_namel, name);
560 for (w = tmp_namel - 1; w >= 0; w--) {
561 if (dir_sep(tmp_name[w]))
562 break;
563 if (tmp_name[w] == '.') {
564 if (w <= tmp_namel - 2) {
565 tmp_name[w + 2] = 0;
566 tmp_namel = w + 2;
567 }
568 break;
569 }
570 }
571 add_num_to_str(&tmp_name, &tmp_namel, count);
572 EINTRLOOP(h, open(tmp_name, O_WRONLY | O_NOCTTY | O_CREAT | O_TRUNC | O_EXCL, 0600));
573 if (h == -1) {
574 if (errno == EEXIST && count < MAXINT) {
575 count++;
576 mem_free(tmp_name);
577 goto try_new_count;
578 }
579 mem_free(tmp_name);
580 return get_error_from_errno(errno);
581 }
582 set_bin(h);
583 rr = strlen(c);
584 if (hard_write(h, c, rr) != rr) {
585 err = errno;
586 EINTRLOOP(rs, close(h));
587 goto unlink_err;
588 }
589 EINTRLOOP(rs, close(h));
590 if (rs) {
591 err = errno;
592 goto unlink_err;
593 }
594 #if defined(OPENVMS)
595 /* delete all versions of the file */
596 count = 0;
597 do {
598 EINTRLOOP(rs, unlink(name));
599 } while (!rs && ++count < 65536);
600 #elif !defined(RENAME_OVER_EXISTING_FILES)
601 EINTRLOOP(rs, unlink(name));
602 #endif
603 EINTRLOOP(rs, rename(tmp_name, name));
604 if (rs) {
605 err = errno;
606 goto unlink_err;
607 }
608 mem_free(tmp_name);
609 return 0;
610
611 unlink_err:
612 EINTRLOOP(rs, unlink(cast_const_char tmp_name));
613 mem_free(tmp_name);
614 return get_error_from_errno(err);
615 }
616
617 #ifdef OPENVMS
translate_vms_to_unix(unsigned char ** str)618 void translate_vms_to_unix(unsigned char **str)
619 {
620 unsigned char *n;
621 if (!*str || strchr(cast_const_char *str, '/')) return;
622 n = cast_uchar decc$translate_vms(cast_const_char *str);
623 if (!n || (int)n == -1) return;
624 mem_free(*str);
625 *str = stracpy(n);
626 }
627 #endif
628
get_home(int * n)629 unsigned char *get_home(int *n)
630 {
631 struct stat st;
632 int rs;
633 unsigned char *home = NULL;
634 unsigned char *home_links;
635 unsigned char *config_dir = stracpy(getenv("CONFIG_DIR"));
636
637 if (n) *n = 1;
638 #ifdef WIN32
639 if (!home) {
640 home = stracpy(getenv("APPDATA"));
641 #ifdef HAVE_CYGWIN_CONV_PATH
642 /*
643 * Newer Cygwin complains about windows-style path, so
644 * we have to convert it.
645 */
646 if (home) {
647 unsigned char *new_path;
648 ssize_t sz = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, home, NULL, 0);
649 if (sz < 0)
650 goto skip_path_conv;
651 new_path = mem_alloc(sz);
652 sz = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, home, new_path, sz);
653 if (sz < 0) {
654 mem_free(new_path);
655 goto skip_path_conv;
656 }
657 mem_free(home);
658 home = new_path;
659 skip_path_conv:;
660 }
661 #endif
662 if (home) {
663 EINTRLOOP(rs, stat(home, &st));
664 if (rs || !S_ISDIR(st.st_mode)) {
665 mem_free(home);
666 home = NULL;
667 }
668 }
669 }
670 #endif
671 if (!home) home = stracpy(getenv("HOME"));
672 #ifdef WIN32
673 /* When we run in Cygwin without Cygwin environment, it reports home "/".
674 Unfortunatelly, it can't write anything to that directory */
675 if (home && !strcmp(home, "/")) {
676 mem_free(home);
677 home = NULL;
678 }
679 #endif
680 #ifdef OPENVMS
681 if (!home) home = stracpy(cast_uchar "/SYS$LOGIN");
682 translate_vms_to_unix(&home);
683 translate_vms_to_unix(&config_dir);
684 #endif
685 if (!home) {
686 int i;
687 home = stracpy(path_to_exe);
688 if (!home) {
689 if (config_dir) mem_free(config_dir);
690 return NULL;
691 }
692 for (i = strlen(home) - 1; i >= 0; i--) if (dir_sep(home[i])) {
693 home[i + 1] = 0;
694 goto br;
695 }
696 home[0] = 0;
697 br:;
698 }
699 while (home[0] && home[1] && dir_sep(home[strlen(home) - 1])) home[strlen(home) - 1] = 0;
700 if (home[0]) add_to_strn(&home, "/");
701 home_links = stracpy(home);
702 if (config_dir) {
703 add_to_strn(&home_links, config_dir);
704 while (home_links[0] && dir_sep(home_links[strlen(home_links) - 1])) home_links[strlen(home_links) - 1] = 0;
705 EINTRLOOP(rs, stat(home_links, &st));
706 if (!rs && S_ISDIR(st.st_mode)) {
707 add_to_strn(&home_links, "/links");
708 } else {
709 fprintf(stderr, "CONFIG_DIR set to %s. But directory %s doesn't exist.\n\007", config_dir, home_links);
710 sleep(3);
711 mem_free(home_links);
712 home_links = stracpy(home);
713 add_to_strn(&home_links, ".links");
714 }
715 } else add_to_strn(&home_links, ".links");
716 EINTRLOOP(rs, stat(home_links, &st));
717 if (rs) {
718 #ifdef HAVE_MKDIR
719 EINTRLOOP(rs, mkdir(home_links, 0700));
720 if (!rs) goto home_creat;
721 #ifdef OPENVMS
722 if (errno == EEXIST) goto home_ok;
723 #endif
724 #endif
725 if (config_dir) goto failed;
726 goto first_failed;
727 }
728 if (S_ISDIR(st.st_mode)) goto home_ok;
729 /* This is a Cygwin hack! Cygwin reports stat for "links" if no
730 "links" exists and only "links.exe" does. So try to create directory
731 anyway. */
732 #ifdef HAVE_MKDIR
733 EINTRLOOP(rs, mkdir(home_links, 0700));
734 if (!rs) goto home_creat;
735 #endif
736 first_failed:
737 mem_free(home_links);
738 home_links = stracpy(home);
739 #ifdef DOS
740 add_to_strn(&home_links, cast_uchar "links.cfg");
741 #else
742 add_to_strn(&home_links, cast_uchar "links");
743 #endif
744 EINTRLOOP(rs, stat(home_links, &st));
745 if (rs) {
746 #ifdef HAVE_MKDIR
747 EINTRLOOP(rs, mkdir(home_links, 0700));
748 if (!rs) goto home_creat;
749 #ifdef OPENVMS
750 if (errno == EEXIST) goto home_ok;
751 #endif
752 #else
753 mem_free(home_links);
754 home_links = stracpy(home);
755 goto home_ok;
756 #endif
757 goto failed;
758 }
759 if (S_ISDIR(st.st_mode)) goto home_ok;
760 #ifdef HAVE_MKDIR
761 EINTRLOOP(rs, mkdir(home_links, 0700));
762 if (!rs) goto home_creat;
763 #endif
764 failed:
765 mem_free(home_links);
766 mem_free(home);
767 if (config_dir) mem_free(config_dir);
768 return NULL;
769
770 home_ok:
771 if (n) *n = 0;
772 home_creat:
773 #ifdef HAVE_CHMOD
774 EINTRLOOP(rs, chmod(home_links, 0700));
775 #endif
776 add_to_strn(&home_links, "/");
777 mem_free(home);
778 if (config_dir) mem_free(config_dir);
779 return home_links;
780 }
781
init_home()782 void init_home()
783 {
784 get_system_name();
785 get_compiler_name();
786 links_home = get_home(&first_use);
787 if (!links_home) {
788 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");
789 sleep(3);
790 return;
791 }
792 }
793
load_config_file(unsigned char * prefix,unsigned char * name)794 void load_config_file(unsigned char *prefix, unsigned char *name)
795 {
796 unsigned char *c, *config_file;
797 config_file = stracpy(prefix);
798 if (!config_file) return;
799 add_to_strn(&config_file, name);
800 if ((c = read_config_file(config_file))) goto ok;
801 mem_free(config_file);
802 config_file = stracpy(prefix);
803 if (!config_file) return;
804 add_to_strn(&config_file, ".");
805 add_to_strn(&config_file, name);
806 if ((c = read_config_file(config_file))) goto ok;
807 mem_free(config_file);
808 return;
809 ok:
810 parse_config_file(config_file, c, all_options);
811 mem_free(c);
812 mem_free(config_file);
813 }
814
load_config()815 void load_config()
816 {
817 #ifdef SHARED_CONFIG_DIR
818 load_config_file(SHARED_CONFIG_DIR, "links.cfg");
819 #endif
820 load_config_file(links_home, "links.cfg");
821 load_config_file(links_home, "html.cfg");
822 load_config_file(links_home, "user.cfg");
823 }
824
write_config_data(unsigned char * prefix,unsigned char * name,struct option * o,struct terminal * term)825 int write_config_data(unsigned char *prefix, unsigned char *name, struct option *o, struct terminal *term)
826 {
827 int err;
828 unsigned char *c, *config_file;
829 if (!(c = create_config_string(o))) return -1;
830 config_file = stracpy(prefix);
831 if (!config_file) {
832 mem_free(c);
833 return -1;
834 }
835 add_to_strn(&config_file, name);
836 if ((err = write_to_config_file(config_file, c))) {
837 if (term) msg_box(term, NULL, TEXT_(T_CONFIG_ERROR), AL_CENTER | AL_EXTD_TEXT, TEXT_(T_UNABLE_TO_WRITE_TO_CONFIG_FILE), ": ", get_err_msg(err), NULL, NULL, 1, TEXT_(T_CANCEL), NULL, B_ENTER | B_ESC);
838 mem_free(c);
839 mem_free(config_file);
840 return -1;
841 }
842 mem_free(c);
843 mem_free(config_file);
844 return 0;
845 }
846
write_config(struct terminal * term)847 void write_config(struct terminal *term)
848 {
849 write_config_data(links_home, "links.cfg", links_options, term);
850 }
851
write_html_config(struct terminal * term)852 void write_html_config(struct terminal *term)
853 {
854 write_config_data(links_home, "html.cfg", html_options, term);
855 }
856
add_nm(struct option * o,unsigned char ** s,int * l)857 void add_nm(struct option *o, unsigned char **s, int *l)
858 {
859 if (*l) add_to_str(s, l, NEWLINE);
860 add_to_str(s, l, o->cfg_name);
861 add_to_str(s, l, " ");
862 }
863
add_quoted_to_str(unsigned char ** s,int * l,unsigned char * q)864 void add_quoted_to_str(unsigned char **s, int *l, unsigned char *q)
865 {
866 add_chr_to_str(s, l, '"');
867 while (*q) {
868 if (*q == '"' || *q == '\\') add_chr_to_str(s, l, '\\');
869 add_chr_to_str(s, l, *q);
870 q++;
871 }
872 add_chr_to_str(s, l, '"');
873 }
874
num_rd(struct option * o,unsigned char * c)875 unsigned char *num_rd(struct option *o, unsigned char *c)
876 {
877 unsigned char *tok = get_token(&c);
878 unsigned char *end;
879 long l;
880 if (!tok) return "Missing argument";
881 l = strtolx(tok, &end);
882 if (*end) {
883 mem_free(tok);
884 return "Number expected";
885 }
886 if (l < o->min || l > o->max) {
887 mem_free(tok);
888 return "Out of range";
889 }
890 *(int *)o->ptr = l;
891 mem_free(tok);
892 return NULL;
893 }
894
num_wr(struct option * o,unsigned char ** s,int * l)895 void num_wr(struct option *o, unsigned char **s, int *l)
896 {
897 add_nm(o, s, l);
898 add_knum_to_str(s, l, *(int *)o->ptr);
899 }
900
str_rd(struct option * o,unsigned char * c)901 unsigned char *str_rd(struct option *o, unsigned char *c)
902 {
903 unsigned char *tok = get_token(&c);
904 unsigned char *e = NULL;
905 if (!tok) tok = stracpy(cast_uchar "");
906 if (strlen(tok) + 1 > (size_t)o->max) e = "String too long";
907 else strcpy(o->ptr, tok);
908 mem_free(tok);
909 return e;
910 }
911
str_wr(struct option * o,unsigned char ** s,int * l)912 void str_wr(struct option *o, unsigned char **s, int *l)
913 {
914 add_nm(o, s, l);
915 if (strlen(o->ptr) + 1 > (size_t)o->max) {
916 unsigned char *s1 = init_str();
917 int l1 = 0;
918 add_bytes_to_str(&s1, &l1, o->ptr, o->max - 1);
919 add_quoted_to_str(s, l, s1);
920 mem_free(s1);
921 }
922 else add_quoted_to_str(s, l, o->ptr);
923 }
924
cp_rd(struct option * o,unsigned char * c)925 unsigned char *cp_rd(struct option *o, unsigned char *c)
926 {
927 unsigned char *tok = get_token(&c);
928 unsigned char *e = NULL;
929 int i;
930 if (!tok) return "Missing argument";
931 if ((i = get_cp_index(tok)) == -1) e = "Unknown codepage";
932 else if (o->min == 1 && is_cp_special(i)) e = "UTF-8 can't be here";
933 else *(int *)o->ptr = i;
934 mem_free(tok);
935 return e;
936 }
937
cp_wr(struct option * o,unsigned char ** s,int * l)938 void cp_wr(struct option *o, unsigned char **s, int *l)
939 {
940 unsigned char *n = get_cp_mime_name(*(int *)o->ptr);
941 add_nm(o, s, l);
942 add_to_str(s, l, n);
943 }
944
lang_rd(struct option * o,unsigned char * c)945 unsigned char *lang_rd(struct option *o, unsigned char *c)
946 {
947 int i;
948 unsigned char *tok = get_token(&c);
949 if (!tok) return "Missing argument";
950 for (i = 0; i < n_languages(); i++)
951 if (!(strcasecmp(language_name(i), tok))) {
952 set_language(i);
953 mem_free(tok);
954 return NULL;
955 }
956 mem_free(tok);
957 return "Unknown language";
958 }
959
lang_wr(struct option * o,unsigned char ** s,int * l)960 void lang_wr(struct option *o, unsigned char **s, int *l)
961 {
962 add_nm(o, s, l);
963 add_quoted_to_str(s, l, language_name(current_language));
964 }
965
getnum(unsigned char * s,int * n,int r1,int r2)966 int getnum(unsigned char *s, int *n, int r1, int r2)
967 {
968 unsigned char *e;
969 long l = strtol(s, (char **)(void *)&e, 10);
970 if (*e || !*s) return -1;
971 if (l < r1 || l >= r2) return -1;
972 *n = (int)l;
973 return 0;
974 }
975
type_rd(struct option * o,unsigned char * c)976 unsigned char *type_rd(struct option *o, unsigned char *c)
977 {
978 unsigned char *err = "Error reading association specification";
979 struct assoc neww;
980 unsigned char *w;
981 int n;
982 memset(&neww, 0, sizeof(struct assoc));
983 if (!(neww.label = get_token(&c))) goto err;
984 if (!(neww.ct = get_token(&c))) goto err;
985 if (!(neww.prog = get_token(&c))) goto err;
986 if (!(w = get_token(&c))) goto err;
987 if (getnum(w, &n, 0, 32)) goto err_f;
988 mem_free(w);
989 neww.cons = !!(n & 1);
990 neww.xwin = !!(n & 2);
991 neww.ask = !!(n & 4);
992 if ((n & 8) || (n & 16)) neww.block = !!(n & 16);
993 else neww.block = !neww.xwin || neww.cons;
994 if (!(w = get_token(&c))) goto err;
995 if (getnum(w, &neww.system, 0, 256)) goto err_f;
996 mem_free(w);
997 update_assoc(&neww);
998 err = NULL;
999 err:
1000 if (neww.label) mem_free(neww.label);
1001 if (neww.ct) mem_free(neww.ct);
1002 if (neww.prog) mem_free(neww.prog);
1003 return err;
1004 err_f:
1005 mem_free(w);
1006 goto err;
1007 }
1008
type_wr(struct option * o,unsigned char ** s,int * l)1009 void type_wr(struct option *o, unsigned char **s, int *l)
1010 {
1011 struct assoc *a;
1012 foreachback(a, assoc) {
1013 add_nm(o, s, l);
1014 add_quoted_to_str(s, l, a->label);
1015 add_to_str(s, l, " ");
1016 add_quoted_to_str(s, l, a->ct);
1017 add_to_str(s, l, " ");
1018 add_quoted_to_str(s, l, a->prog);
1019 add_to_str(s, l, " ");
1020 add_num_to_str(s, l, (!!a->cons) + (!!a->xwin) * 2 + (!!a->ask) * 4 + (!a->block) * 8 + (!!a->block) * 16);
1021 add_to_str(s, l, " ");
1022 add_num_to_str(s, l, a->system);
1023 }
1024 }
1025
ext_rd(struct option * o,unsigned char * c)1026 unsigned char *ext_rd(struct option *o, unsigned char *c)
1027 {
1028 unsigned char *err = "Error reading extension specification";
1029 struct extension neww;
1030 memset(&neww, 0, sizeof(struct extension));
1031 if (!(neww.ext = get_token(&c))) goto err;
1032 if (!(neww.ct = get_token(&c))) goto err;
1033 update_ext(&neww);
1034 err = NULL;
1035 err:
1036 if (neww.ext) mem_free(neww.ext);
1037 if (neww.ct) mem_free(neww.ct);
1038 return err;
1039 }
1040
ext_wr(struct option * o,unsigned char ** s,int * l)1041 void ext_wr(struct option *o, unsigned char **s, int *l)
1042 {
1043 struct extension *a;
1044 foreachback(a, extensions) {
1045 add_nm(o, s, l);
1046 add_quoted_to_str(s, l, a->ext);
1047 add_to_str(s, l, " ");
1048 add_quoted_to_str(s, l, a->ct);
1049 }
1050 }
1051
prog_rd(struct option * o,unsigned char * c)1052 unsigned char *prog_rd(struct option *o, unsigned char *c)
1053 {
1054 unsigned char *err = "Error reading program specification";
1055 unsigned char *prog, *w;
1056 int n;
1057 if (!(prog = get_token(&c))) goto err_1;
1058 if (!(w = get_token(&c))) goto err_2;
1059 if (getnum(w, &n, 0, 256)) goto err_3;
1060 update_prog(o->ptr, prog, n);
1061 err = NULL;
1062 err_3:
1063 mem_free(w);
1064 err_2:
1065 mem_free(prog);
1066 err_1:
1067 return err;
1068 }
1069
prog_wr(struct option * o,unsigned char ** s,int * l)1070 void prog_wr(struct option *o, unsigned char **s, int *l)
1071 {
1072 struct protocol_program *a;
1073 foreachback(a, *(struct list_head *)o->ptr) {
1074 if (!*a->prog) continue;
1075 add_nm(o, s, l);
1076 add_quoted_to_str(s, l, a->prog);
1077 add_to_str(s, l, " ");
1078 add_num_to_str(s, l, a->system);
1079 }
1080 }
1081
term_rd(struct option * o,unsigned char * c)1082 unsigned char *term_rd(struct option *o, unsigned char *c)
1083 {
1084 struct term_spec *ts;
1085 unsigned char *w;
1086 int i;
1087 if (!(w = get_token(&c))) goto err;
1088 if (!(ts = new_term_spec(w))) {
1089 mem_free(w);
1090 goto end;
1091 }
1092 mem_free(w);
1093 if (!(w = get_token(&c))) goto err;
1094 if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
1095 ts->mode = w[0] - '0';
1096 mem_free(w);
1097 if (!(w = get_token(&c))) goto err;
1098 if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
1099 ts->m11_hack = w[0] - '0';
1100 mem_free(w);
1101 if (!(w = get_token(&c))) goto err;
1102 if (strlen(w) != 1 || w[0] < '0' || w[0] > '7') goto err_f;
1103 ts->col = (w[0] - '0') & 1;
1104 ts->restrict_852 = !!((w[0] - '0') & 2);
1105 ts->block_cursor = !!((w[0] - '0') & 4);
1106 mem_free(w);
1107 if (!(w = get_token(&c))) goto err;
1108 if ((i = get_cp_index(w)) == -1 || is_cp_special(i)) goto err_f;
1109 ts->charset = i;
1110 mem_free(w);
1111 end:
1112 return NULL;
1113 err_f:
1114 mem_free(w);
1115 err:
1116 return "Error reading terminal specification";
1117 }
1118
term2_rd(struct option * o,unsigned char * c)1119 unsigned char *term2_rd(struct option *o, unsigned char *c)
1120 {
1121 struct term_spec *ts;
1122 unsigned char *w;
1123 int i;
1124 if (!(w = get_token(&c))) goto err;
1125 if (!(ts = new_term_spec(w))) {
1126 mem_free(w);
1127 goto end;
1128 }
1129 mem_free(w);
1130 if (!(w = get_token(&c))) goto err;
1131 if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
1132 ts->mode = w[0] - '0';
1133 mem_free(w);
1134 if (!(w = get_token(&c))) goto err;
1135 if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
1136 ts->m11_hack = w[0] - '0';
1137 mem_free(w);
1138 if (!(w = get_token(&c))) goto err;
1139 if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
1140 ts->restrict_852 = w[0] - '0';
1141 mem_free(w);
1142 if (!(w = get_token(&c))) goto err;
1143 if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
1144 ts->col = w[0] - '0';
1145 mem_free(w);
1146 if (!(w = get_token(&c))) goto err;
1147 if ((i = get_cp_index(w)) == -1 || is_cp_special(i)) goto err_f;
1148 ts->charset = i;
1149 mem_free(w);
1150 end:
1151 return NULL;
1152 err_f:
1153 mem_free(w);
1154 err:
1155 return "Error reading terminal specification";
1156 }
1157
term_wr(struct option * o,unsigned char ** s,int * l)1158 void term_wr(struct option *o, unsigned char **s, int *l)
1159 {
1160 struct term_spec *ts;
1161 foreachback(ts, term_specs) {
1162 add_nm(o, s, l);
1163 add_quoted_to_str(s, l, ts->term);
1164 add_to_str(s, l, " ");
1165 add_num_to_str(s, l, ts->mode);
1166 add_to_str(s, l, " ");
1167 add_num_to_str(s, l, ts->m11_hack);
1168 add_to_str(s, l, " ");
1169 add_num_to_str(s, l, !!ts->col + !!ts->restrict_852 * 2 + !!ts->block_cursor * 4);
1170 add_to_str(s, l, " ");
1171 add_to_str(s, l, get_cp_mime_name(ts->charset));
1172 }
1173 }
1174
gen_cmd(struct option * o,unsigned char *** argv,int * argc)1175 unsigned char *gen_cmd(struct option *o, unsigned char ***argv, int *argc)
1176 {
1177 unsigned char *e;
1178 int l;
1179 unsigned char *r;
1180 if (!*argc) return "Parameter expected";
1181 e = init_str();
1182 l = 0;
1183 add_quoted_to_str(&e, &l, **argv);
1184 r = o->rd_cfg(o, e);
1185 mem_free(e);
1186 if (r) return r;
1187 (*argv)++; (*argc)--;
1188 return NULL;
1189 }
1190
lookup_cmd(struct option * o,unsigned char *** argv,int * argc)1191 unsigned char *lookup_cmd(struct option *o, unsigned char ***argv, int *argc)
1192 {
1193 ip addr;
1194 unsigned char *p = (unsigned char *)&addr;
1195 if (!*argc) return "Parameter expected";
1196 if (*argc >= 2) return "Too many parameters";
1197 (*argv)++; (*argc)--;
1198 if (do_real_lookup(*(*argv - 1), &addr)) {
1199 #if defined(HAVE_GETHOSTBYNAME) && defined(HAVE_HERROR)
1200 herror("error");
1201 #else
1202 fprintf(stderr, "error: host not found\n");
1203 #endif
1204 exit(RET_ERROR);
1205 return "";
1206 }
1207 printf("%d.%d.%d.%d\n", (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
1208 fflush(stdout);
1209 exit(RET_OK);
1210 return "";
1211 }
1212
version_cmd(struct option * o,unsigned char *** argv,int * argc)1213 unsigned char *version_cmd(struct option *o, unsigned char ***argv, int *argc)
1214 {
1215 printf("Links " VERSION_STRING "\n");
1216 fflush(stdout);
1217 exit(RET_OK);
1218 return "";
1219 }
1220
no_connect_cmd(struct option * o,unsigned char *** argv,int * argc)1221 unsigned char *no_connect_cmd(struct option *o, unsigned char ***argv, int *argc)
1222 {
1223 no_connect = 1;
1224 return NULL;
1225 }
1226
anonymous_cmd(struct option * o,unsigned char *** argv,int * argc)1227 unsigned char *anonymous_cmd(struct option *o, unsigned char ***argv, int *argc)
1228 {
1229 anonymous = 1;
1230 return NULL;
1231 }
1232
force_html_cmd(struct option * o,unsigned char *** argv,int * argc)1233 unsigned char *force_html_cmd(struct option *o, unsigned char ***argv, int *argc)
1234 {
1235 force_html = 1;
1236 return NULL;
1237 }
1238
dump_cmd(struct option * o,unsigned char *** argv,int * argc)1239 unsigned char *dump_cmd(struct option *o, unsigned char ***argv, int *argc)
1240 {
1241 if (dmp != o->min && dmp) return "Can't use both -dump and -source";
1242 dmp = o->min;
1243 no_connect = 1;
1244 return NULL;
1245 }
1246
printhelp_cmd(struct option * o,unsigned char *** argv,int * argc)1247 unsigned char *printhelp_cmd(struct option *o, unsigned char ***argv, int *argc)
1248 {
1249 /* Changed and splited - translation is much easier.
1250 * Print to stdout instead stderr (,,links -help | more''
1251 * is much better than ,,links -help 2>&1 | more'').
1252 */
1253 fprintf(stdout, "%s%s%s%s%s%s\n",
1254
1255 ("links [options] URL\n\
1256 Options are:\n\
1257 \n\
1258 -async-dns <0>/<1>\n\
1259 Asynchronous DNS resolver on(1)/off(0).\n\
1260 \n\
1261 -download-utime <0>/<1>\n\
1262 Set time of downloaded files to time from server.\n\
1263 \n\
1264 -max-connections <max>\n\
1265 Maximum number of concurrent connections.\n\
1266 (default: 10)\n\
1267 \n"),
1268 (" -max-connections-to-host <max>\n\
1269 Maximum number of concurrent connection to a given host.\n\
1270 (default: 2)\n\
1271 \n\
1272 -retries <retry>\n\
1273 Number of retries.\n\
1274 (default: 3)\n\
1275 \n\
1276 -receive-timeout <sec>\n\
1277 Timeout on receive.\n\
1278 (default: 120)\n\
1279 \n"),
1280 (" -unrestartable-receive-timeout <sec>\n\
1281 Timeout on non restartable connections.\n\
1282 (default: 600)\n\
1283 \n\
1284 -format-cache-size <num>\n\
1285 Number of formatted document pages cached.\n\
1286 (default: 5)\n\
1287 \n\
1288 -memory-cache-size <Kbytes>\n\
1289 Cache memory in Kilobytes.\n\
1290 (default: 1024)\n\
1291 \n"),
1292 (" -http-proxy <host:port>\n\
1293 Host and port number of the HTTP proxy, or blank.\n\
1294 (default: blank)\n\
1295 \n\
1296 -ftp-proxy <host:port>\n\
1297 Host and port number of the FTP proxy, or blank.\n\
1298 (default: blank)\n\
1299 \n\
1300 -download-dir <path>\n\
1301 Default download directory.\n\
1302 (default: actual dir)\n\
1303 \n\
1304 -http-bugs.http10 <0>/<1>\n\
1305 \"1\" forces using only HTTP/1.0 protocol.\n\
1306 \n\
1307 -http-bugs.allow-blacklist <0>/<1>\n\
1308 \"1\" defaults to using list of servers that have broken HTTP/1.1 support.\n\
1309 When links finds such server, it will retry the request with HTTP/1.0.\n\
1310 \n\
1311 -http-bugs.bug-302-redirect <0>/<1>\n\
1312 Process 302 redirect in a way that is incompatible with RFC1945 and RFC2068,\n\
1313 but the same as Netscape and MSIE. Many pages depend on it.\n\
1314 \n\
1315 -http-bugs.bug-post-no-keepalive <0>/<1>\n\
1316 No keepalive connection after post requests. For some buggy servers.\n\
1317 \n\
1318 -http-bugs.bug-no-accept-charset <0>/<1>\n\
1319 Do not send Accept-Charset field of HTTP header.\n\
1320 \n\
1321 -ftp.anonymous-password <string>\n\
1322 Use ftp PASV command to bypass firewalls.\n\
1323 \n\
1324 -ftp.fast <0>/<1>\n\
1325 Send more ftp commands simultaneously. Faster response when\n\
1326 browsing ftp directories, but it is incompatible with RFC\n\
1327 and some servers don't like it.\n\
1328 \n\
1329 -ftp.set-iptos <0>/<1>\n\
1330 Set IP Type-of-service to high throughput on ftp connections.\n\
1331 \n"),
1332 (" -html-assume-codepage <codepage>\n\
1333 Use the given codepage when the webpage did not specify\n\
1334 its codepage. (default: ISO 8859-1)\n\
1335 \n\
1336 -html-tables <0>/<1>\n\
1337 Render tables.\n\
1338 \n\
1339 -html-frames <0>/<1>\n\
1340 Render frames.\n\
1341 \n\
1342 -html-images <0>/<1>\n\
1343 Display links to images.\n\
1344 \n\
1345 -html-numbered-links <0>/<1>\n\
1346 Link numbering.\n\
1347 \n\
1348 -html-table-order <0>/<1>\n\
1349 Walk table by rows (0) or columns (1).\n\
1350 \n\
1351 -html-margin <margin>\n\
1352 Text margin.\n\
1353 \n\
1354 -language <language>\n\
1355 User interface language.\n\
1356 \n\
1357 -anonymous\n\
1358 Restrict links so that it can run on an anonymous account.\n\
1359 No local file browsing. No downloads. Executing of viewers\n\
1360 is allowed, but user can't add or modify entries in\n\
1361 association table.\n\
1362 \n\
1363 -force-html\n\
1364 Treat file as if it had an .html extension.\n\
1365 \n\
1366 -source\n\
1367 Write the given HTML document in source form to stdout.\n\
1368 \n\
1369 -dump\n\
1370 Write a plain-text version of the given HTML document to\n\
1371 stdout.\n\
1372 \n\
1373 -width <size>\n\
1374 Size of screen in characters, used in combination with -dump.\n\
1375 \n\
1376 -codepage <codepage>\n\
1377 Character set of output of -dump.\n\
1378 \n\
1379 -no-connect\n\
1380 Runs links as a separate instance - instead of connecting to\n\
1381 existing instance.\n\
1382 \n\
1383 -lookup <host>\n\
1384 Do lookup like \"host\" command.\n\
1385 \n\
1386 -version\n\
1387 Prints the links version number and exit.\n\
1388 \n\
1389 -help\n\
1390 Prints this help screen\n\
1391 \n\
1392 \n"),
1393 ("Keys:\n\
1394 ESC display menu\n\
1395 ^C quit\n\
1396 ^P, ^N scroll up, down\n\
1397 [, ] scroll left, right\n\
1398 up, down select link\n\
1399 -> follow link\n\
1400 <- go back\n\
1401 g go to url\n\
1402 G go to url based on current url\n\
1403 ^R reload\n\
1404 / search\n\
1405 ? search back\n\
1406 n find next\n\
1407 N find previous\n\
1408 = document info\n\
1409 \\ document source\n\
1410 | HTTP header\n\
1411 * toggle displaying of image links\n\
1412 d download\n\
1413 s bookmarks\n\
1414 q quit\n"));
1415
1416 fflush(stdout);
1417 exit(RET_OK);
1418 return "";
1419 }
1420
end_config()1421 void end_config()
1422 {
1423 if (links_home) mem_free(links_home);
1424 }
1425
1426 int anonymous = 0;
1427
1428 unsigned char *links_home = NULL;
1429 int first_use = 0;
1430 int created_home = 0;
1431
1432 int no_connect = 0;
1433 int base_session = 0;
1434 int dmp = 0;
1435 int force_html = 0;
1436
1437 int async_lookup = 1;
1438 int download_utime = 0;
1439 #ifdef DOS
1440 /* DOS networking is slow with too many connections */
1441 int max_connections = 3;
1442 int max_connections_to_host = 2;
1443 #else
1444 int max_connections = 10;
1445 int max_connections_to_host = 2;
1446 #endif
1447 int max_tries = 3;
1448 int receive_timeout = 120;
1449 int unrestartable_receive_timeout = 600;
1450
1451 int screen_width = 80;
1452 int dump_codepage = -1;
1453
1454 int max_format_cache_entries = 5;
1455 int memory_cache_size = 1048576;
1456
1457 int enable_html_tables = 1;
1458 int enable_html_frames = 1;
1459 int display_images = 1;
1460
1461 struct document_setup dds = { 0, 0, 1, 1, 0, 3, 0, 0 };
1462
1463 struct rgb default_fg = { 191, 191, 191, 0 };
1464 struct rgb default_bg = { 0, 0, 0, 0 };
1465 struct rgb default_link = { 255, 255, 255, 0 };
1466 struct rgb default_vlink = { 255, 255, 0, 0 };
1467
1468 int default_left_margin = HTML_LEFT_MARGIN;
1469
1470 unsigned char http_proxy[MAX_STR_LEN] = "";
1471 unsigned char ftp_proxy[MAX_STR_LEN] = "";
1472
1473 unsigned char download_dir[MAX_STR_LEN] = "";
1474
1475 struct ftp_options ftp_options = { "somebody@host.domain", 0, 0, 1 };
1476
1477 /* These are workarounds for some CGI script bugs */
1478 struct http_bugs http_bugs = { 0, 1, 1, 0, 0 };
1479 /*int bug_302_redirect = 0;*/
1480 /* When got 301 or 302 from POST request, change it to GET
1481 - this violates RFC2068, but some buggy message board scripts rely on it */
1482 /*int bug_post_no_keepalive = 0;*/
1483 /* No keepalive connection after POST request. Some buggy PHP databases report bad
1484 results if GET wants to retreive data POSTed in the same connection */
1485
1486 struct option links_options[] = {
1487 { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "?" },
1488 { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "h" },
1489 { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "help" },
1490 { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "-help" },
1491 { 1, lookup_cmd, NULL, NULL, 0, 0, NULL, NULL, "lookup" },
1492 { 1, version_cmd, NULL, NULL, 0, 0, NULL, NULL, "version" },
1493 { 1, no_connect_cmd, NULL, NULL, 0, 0, NULL, NULL, "no-connect" },
1494 { 1, anonymous_cmd, NULL, NULL, 0, 0, NULL, NULL, "anonymous" },
1495 { 1, gen_cmd, num_rd, NULL, 0, MAXINT, &base_session, NULL, "base-session" },
1496 { 1, force_html_cmd, NULL, NULL, 0, 0, NULL, NULL, "force-html" },
1497 { 1, dump_cmd, NULL, NULL, D_SOURCE, 0, NULL, NULL, "source" },
1498 { 1, dump_cmd, NULL, NULL, D_DUMP, 0, NULL, NULL, "dump" },
1499 { 1, gen_cmd, num_rd, NULL, 10, 512, &screen_width, "dump_width", "width" },
1500 { 1, gen_cmd, cp_rd, NULL, 1, 0, &dump_codepage, "dump_codepage", "codepage" },
1501 { 1, gen_cmd, num_rd, num_wr, 0, 1, &async_lookup, "async_dns", "async-dns" },
1502 { 1, gen_cmd, num_rd, num_wr, 0, 1, &download_utime, "download_utime", "download-utime" },
1503 { 1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections, "max_connections", "max-connections" },
1504 { 1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections_to_host, "max_connections_to_host", "max-connections-to-host" },
1505 { 1, gen_cmd, num_rd, num_wr, 0, 16, &max_tries, "retries", "retries" },
1506 { 1, gen_cmd, num_rd, num_wr, 1, 1800, &receive_timeout, "receive_timeout", "receive-timeout" },
1507 { 1, gen_cmd, num_rd, num_wr, 1, 1800, &unrestartable_receive_timeout, "unrestartable_receive_timeout", "unrestartable-receive-timeout" },
1508 { 1, gen_cmd, num_rd, num_wr, 0, 256, &max_format_cache_entries, "format_cache_size", "format-cache-size" },
1509 { 1, gen_cmd, num_rd, num_wr, 0, MAXINT, &memory_cache_size, "memory_cache_size", "memory-cache-size" },
1510 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, http_proxy, "http_proxy", "http-proxy" },
1511 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, ftp_proxy, "ftp_proxy", "ftp-proxy" },
1512 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, download_dir, "download_dir", "download-dir" },
1513 { 1, gen_cmd, lang_rd, lang_wr, 0, 0, ¤t_language, "language", "language" },
1514 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.http10, "http_bugs.http10", "http-bugs.http10" },
1515 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.allow_blacklist, "http_bugs.allow_blacklist", "http-bugs.allow-blacklist" },
1516 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_302_redirect, "http_bugs.bug_302_redirect", "http-bugs.bug-302-redirect" },
1517 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_post_no_keepalive, "http_bugs.bug_post_no_keepalive", "http-bugs.bug-post-no-keepalive" },
1518 { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.no_accept_charset, "http_bugs.no_accept_charset", "http-bugs.bug-no-accept-charset" },
1519 { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, ftp_options.anon_pass, "ftp.anonymous_password", "ftp.anonymous-password" },
1520 { 1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.passive_ftp, "ftp.use_passive", "ftp.use-passive" },
1521 { 1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.fast_ftp, "ftp.fast", "ftp.fast" },
1522 { 1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.set_tos, "ftp.set_iptos", "ftp.set-iptos" },
1523 { 1, gen_cmd, cp_rd, NULL, 0, 0, &dds.assume_cp, "assume_codepage", "assume-codepage" },
1524 { 1, NULL, term_rd, term_wr, 0, 0, NULL, "terminal", NULL },
1525 { 1, NULL, term2_rd, NULL, 0, 0, NULL, "terminal2", NULL },
1526 { 1, NULL, type_rd, type_wr, 0, 0, NULL, "association", NULL },
1527 { 1, NULL, ext_rd, ext_wr, 0, 0, NULL, "extension", NULL },
1528 { 1, NULL, prog_rd, prog_wr, 0, 0, &mailto_prog, "mailto", NULL },
1529 { 1, NULL, prog_rd, prog_wr, 0, 0, &telnet_prog, "telnet", NULL },
1530 { 1, NULL, prog_rd, prog_wr, 0, 0, &tn3270_prog, "tn3270", NULL },
1531 { 1, NULL, prog_rd, prog_wr, 0, 0, &mms_prog, "mms", NULL },
1532 { 1, NULL, bind_rd, NULL, 0, 0, NULL, "bind", NULL },
1533 { 1, NULL, unbind_rd, NULL, 0, 0, NULL, "unbind", NULL },
1534 { 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL },
1535 };
1536
1537 struct option html_options[] = {
1538 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.hard_assume, "html_hard_assume", "html-hard-assume" },
1539 { 1, gen_cmd, cp_rd, cp_wr, 0, 0, &dds.assume_cp, "html_assume_codepage", "html-assume-codepage" },
1540 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.tables, "html_tables", "html-tables" },
1541 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.frames, "html_frames", "html-frames" },
1542 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.images, "html_images", "html-images" },
1543 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.num_links, "html_numbered_links", "html-numbered-links" },
1544 { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.table_order, "html_table_order", "html-table-order" },
1545 { 1, gen_cmd, num_rd, num_wr, 0, 9, &dds.margin, "html_margin", "html-margin" },
1546 { 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL },
1547 };
1548
load_url_history(void)1549 void load_url_history(void)
1550 {
1551 unsigned char *history_file, *hs;
1552 unsigned char *hsp;
1553
1554 if (anonymous) return;
1555 /* Must have been called after init_home */
1556 if (!links_home) return;
1557 history_file = stracpy(links_home);
1558 add_to_strn(&history_file, "links.his");
1559 hs = read_config_file(history_file);
1560 mem_free(history_file);
1561 if (!hs) return;
1562 for (hsp = hs; *hsp; ) {
1563 unsigned char *hsl, *hsc;
1564 for (hsl = hsp; *hsl && *hsl != 10 && *hsl != 13; hsl++) ;
1565 hsc = memacpy(hsp, hsl - hsp);
1566 add_to_history(&goto_url_history, hsc, 0);
1567 mem_free(hsc);
1568 hsp = hsl;
1569 while (*hsp == 10 || *hsp == 13) hsp++;
1570 }
1571 mem_free(hs);
1572 }
1573
save_url_history(void)1574 void save_url_history(void)
1575 {
1576 struct history_item *hi;
1577 unsigned char *history_file;
1578 unsigned char *hs;
1579 int hsl = 0;
1580 int i = 0;
1581 if (anonymous) return;
1582
1583 /* Must have been called after init_home */
1584 if (!links_home) return;
1585 history_file = stracpy(links_home);
1586 add_to_strn(&history_file, "links.his");
1587 hs = init_str();
1588 hsl = 0;
1589 foreachback(hi, goto_url_history.items) {
1590 if (!*hi->d || strchr(hi->d, 10) || strchr(hi->d, 13)) continue;
1591 if (!url_not_saveable(hi->d) && i++ <= MAX_HISTORY_ITEMS) {
1592 add_to_str(&hs, &hsl, hi->d);
1593 add_to_str(&hs, &hsl, NEWLINE);
1594 }
1595 }
1596 write_to_config_file(history_file, hs);
1597 mem_free(history_file);
1598 mem_free(hs);
1599 return;
1600 }
1601
1602