1 /*
2 * $LynxId: HTInit.c,v 1.92 2020/01/21 22:20:09 tom Exp $
3 *
4 * Configuration-specific Initialization HTInit.c
5 * ----------------------------------------
6 */
7
8 /* Define a basic set of suffixes and presentations
9 * ------------------------------------------------
10 */
11
12 #include <HTUtils.h>
13
14 /* Implements:
15 */
16 #include <HTInit.h>
17
18 #include <HTML.h>
19 #include <HTPlain.h>
20 #include <HTMLGen.h>
21 #include <HTFile.h>
22 #include <HTFormat.h>
23 #include <HTMIME.h>
24 #include <HTWSRC.h>
25
26 #include <HTSaveToFile.h> /* LJM */
27 #include <LYStrings.h>
28 #include <LYUtils.h>
29 #include <LYGlobalDefs.h>
30
31 #include <LYexit.h>
32 #include <LYLeaks.h>
33
34 #define CTrace(p) CTRACE2(TRACE_CFG, p)
35
36 static int HTLoadTypesConfigFile(char *fn, AcceptMedia media);
37 static int HTLoadExtensionsConfigFile(char *fn);
38
39 #define SET_SUFFIX1(suffix, description, type) \
40 HTSetSuffix(suffix, description, type, 1.0)
41
42 #define SET_SUFFIX5(suffix, mimetype, type, description) \
43 HTSetSuffix5(suffix, mimetype, type, description, 1.0)
44
45 #define SET_PRESENT(mimetype, command, quality, delay) \
46 HTSetPresentation(mimetype, command, 0, quality, delay, 0.0, 0L, media)
47
48 #define SET_EXTERNL(rep_in, rep_out, command, quality) \
49 HTSetConversion(rep_in, rep_out, command, quality, 3.0, 0.0, 0L, mediaEXT)
50
51 #define SET_INTERNL(rep_in, rep_out, command, quality) \
52 HTSetConversion(rep_in, rep_out, command, quality, 0.0, 0.0, 0L, mediaINT)
53
HTFormatInit(void)54 void HTFormatInit(void)
55 {
56 AcceptMedia media = mediaEXT;
57
58 CTrace((tfp, "HTFormatInit\n"));
59 #ifdef NeXT
60 SET_PRESENT("application/postscript", "open %s", 1.0, 2.0);
61 SET_PRESENT("image/x-tiff", "open %s", 2.0, 2.0);
62 SET_PRESENT("image/tiff", "open %s", 1.0, 2.0);
63 SET_PRESENT("audio/basic", "open %s", 1.0, 2.0);
64 SET_PRESENT("*", "open %s", 1.0, 0.0);
65 #else
66 if (LYgetXDisplay() != 0) { /* Must have X11 */
67 SET_PRESENT("application/postscript", "ghostview %s&", 1.0, 3.0);
68 if (non_empty(XLoadImageCommand)) {
69 /* *INDENT-OFF* */
70 SET_PRESENT("image/gif", XLoadImageCommand, 1.0, 3.0);
71 SET_PRESENT("image/x-xbm", XLoadImageCommand, 1.0, 3.0);
72 SET_PRESENT("image/x-xbitmap", XLoadImageCommand, 1.0, 3.0);
73 SET_PRESENT("image/x-png", XLoadImageCommand, 2.0, 3.0);
74 SET_PRESENT("image/png", XLoadImageCommand, 1.0, 3.0);
75 SET_PRESENT("image/x-rgb", XLoadImageCommand, 1.0, 3.0);
76 SET_PRESENT("image/x-tiff", XLoadImageCommand, 2.0, 3.0);
77 SET_PRESENT("image/tiff", XLoadImageCommand, 1.0, 3.0);
78 SET_PRESENT("image/jpeg", XLoadImageCommand, 1.0, 3.0);
79 /* *INDENT-ON* */
80
81 }
82 SET_PRESENT("video/mpeg", "mpeg_play %s &", 1.0, 3.0);
83
84 }
85 #endif
86
87 #ifdef EXEC_SCRIPTS
88 /* set quality to 999.0 for protected exec applications */
89 #ifndef VMS
90 SET_PRESENT("application/x-csh", "csh %s", 999.0, 3.0);
91 SET_PRESENT("application/x-sh", "sh %s", 999.0, 3.0);
92 SET_PRESENT("application/x-ksh", "ksh %s", 999.0, 3.0);
93 #else
94 SET_PRESENT("application/x-VMS_script", "@%s", 999.0, 3.0);
95 #endif /* not VMS */
96 #endif /* EXEC_SCRIPTS */
97
98 /*
99 * Add our header handlers.
100 */
101 SET_INTERNL("message/x-http-redirection", "*", HTMIMERedirect, 2.0);
102 SET_INTERNL("message/x-http-redirection", "www/present", HTMIMERedirect, 2.0);
103 SET_INTERNL("message/x-http-redirection", "www/debug", HTMIMERedirect, 1.0);
104 SET_INTERNL("www/mime", "www/present", HTMIMEConvert, 1.0);
105 SET_INTERNL("www/mime", "www/download", HTMIMEConvert, 1.0);
106 SET_INTERNL("www/mime", "www/source", HTMIMEConvert, 1.0);
107 SET_INTERNL("www/mime", "www/dump", HTMIMEConvert, 1.0);
108
109 /*
110 * Add our compressed file handlers.
111 */
112 SET_INTERNL("www/compressed", "www/download", HTCompressed, 1.0);
113 SET_INTERNL("www/compressed", "www/present", HTCompressed, 1.0);
114 SET_INTERNL("www/compressed", "www/source", HTCompressed, 1.0);
115 SET_INTERNL("www/compressed", "www/dump", HTCompressed, 1.0);
116
117 /*
118 * The following support some content types seen here/there:
119 */
120 SET_INTERNL("application/html", "text/x-c", HTMLToC, 0.5);
121 SET_INTERNL("application/html", STR_PLAINTEXT, HTMLToPlain, 0.5);
122 SET_INTERNL("application/html", "www/present", HTMLPresent, 2.0);
123 SET_INTERNL("application/html", "www/source", HTPlainPresent, 1.0);
124 SET_INTERNL("application/xml", "www/present", HTMLPresent, 2.0);
125 SET_INTERNL("application/x-wais-source", "www/source", HTPlainPresent, 1.0);
126 SET_INTERNL("application/x-wais-source", "www/present", HTWSRCConvert, 2.0);
127 SET_INTERNL("application/x-wais-source", "www/download", HTWSRCConvert, 1.0);
128 SET_INTERNL("application/x-wais-source", "www/dump", HTWSRCConvert, 1.0);
129
130 /*
131 * Save all unknown mime types to disk.
132 */
133 SET_EXTERNL("www/source", "www/present", HTSaveToFile, 1.0);
134 SET_EXTERNL("www/source", "www/source", HTSaveToFile, 1.0);
135 SET_EXTERNL("www/source", "www/download", HTSaveToFile, 1.0);
136 SET_EXTERNL("www/source", "*", HTSaveToFile, 1.0);
137
138 /*
139 * Output all www/dump presentations to stdout.
140 */
141 SET_EXTERNL("www/source", "www/dump", HTDumpToStdout, 1.0);
142
143 /*
144 * Other internal types, which must precede the "www/present" entries
145 * below (otherwise, they will be filtered out in HTFilterPresentations()).
146 */
147 SET_INTERNL("text/css", STR_PLAINTEXT, HTMLToPlain, 0.5);
148 SET_INTERNL(STR_HTML, STR_PLAINTEXT, HTMLToPlain, 0.5);
149 SET_INTERNL(STR_HTML, "text/x-c", HTMLToC, 0.5);
150 SET_INTERNL(STR_HTML, "www/source", HTPlainPresent, 1.0);
151 SET_INTERNL(STR_PLAINTEXT, "www/source", HTPlainPresent, 1.0);
152 SET_INTERNL("text/sgml", "www/source", HTPlainPresent, 1.0);
153 SET_INTERNL("text/x-sgml", "www/source", HTPlainPresent, 1.0);
154
155 /*
156 * Now add our basic conversions. These include the types which will
157 * be listed in a "Accept:" line sent to a server. These criteria are
158 * used in HTFilterPresentations() to select acceptable types:
159 *
160 * a) input is not "www/mime" or "www/compressed"
161 * b) output is "www/present"
162 * c) quality is in the range 0.0 to 1.0, i.e., excludes the 2.0's.
163 *
164 * For reference:
165 * RFC 1874 - text/sgml
166 * RFC 2046 - text/plain
167 * RFC 2318 - text/css
168 * RFC 3023 - text/xml
169 * obsolete - text/x-sgml
170 *
171 * as well as
172 * http://www.iana.org/assignments/media-types/media-types.xhtml
173 *
174 * and
175 * http://www.w3.org/TR/xhtml-media-types/
176 *
177 * which describes
178 * application/xhtml+xml
179 * text/html
180 */
181 SET_INTERNL("application/xhtml+xml", "www/present", HTMLPresent, 1.0);
182 SET_INTERNL("application/xhtml+xml", "www/source", HTPlainPresent, 1.0);
183 SET_INTERNL("text/css", "www/present", HTPlainPresent, 1.0);
184 SET_INTERNL(STR_HTML, "www/present", HTMLPresent, 1.0);
185 SET_INTERNL(STR_PLAINTEXT, "www/present", HTPlainPresent, 1.0);
186 SET_INTERNL("text/sgml", "www/present", HTMLPresent, 1.0);
187 SET_INTERNL("text/x-sgml", "www/present", HTMLPresent, 2.0);
188 SET_INTERNL("text/xml", "www/present", HTMLPresent, 2.0);
189
190 if (LYisAbsPath(global_type_map)) {
191 /* These should override the default types as necessary. */
192 HTLoadTypesConfigFile(global_type_map, mediaSYS);
193 }
194
195 /*
196 * Load the local maps.
197 */
198 if (IsOurFile(LYAbsOrHomePath(&personal_type_map))
199 && LYCanReadFile(personal_type_map)) {
200 /* These should override everything else. */
201 HTLoadTypesConfigFile(personal_type_map, mediaUSR);
202 }
203
204 /*
205 * Put text/html and text/plain at beginning of list. - kw
206 */
207 HTReorderPresentation(WWW_PLAINTEXT, WWW_PRESENT);
208 HTReorderPresentation(WWW_HTML, WWW_PRESENT);
209
210 /*
211 * Analyze the list, and set 'get_accept' for those whose representations
212 * are not redundant.
213 */
214 HTFilterPresentations();
215 }
216
HTPreparsedFormatInit(void)217 void HTPreparsedFormatInit(void)
218 {
219 CTrace((tfp, "HTPreparsedFormatInit\n"));
220 if (LYPreparsedSource) {
221 SET_INTERNL(STR_HTML, "www/source", HTMLParsedPresent, 1.0);
222 SET_INTERNL(STR_HTML, "www/dump", HTMLParsedPresent, 1.0);
223 }
224 }
225
226 /* Some of the following is taken from: */
227
228 /*
229 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
230
231 Permission to use, copy, modify, and distribute this material
232 for any purpose and without fee is hereby granted, provided
233 that the above copyright notice and this permission notice
234 appear in all copies, and that the name of Bellcore not be
235 used in advertising or publicity pertaining to this
236 material without the specific, prior written permission
237 of an authorized representative of Bellcore. BELLCORE
238 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
239 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
240 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
241 */
242 /******************************************************
243 Metamail -- A tool to help diverse mail readers
244 cope with diverse multimedia mail formats.
245
246 Author: Nathaniel S. Borenstein, Bellcore
247
248 ******************************************************* */
249
250 struct MailcapEntry {
251 char *contenttype;
252 char *command;
253 char *testcommand;
254 int needsterminal;
255 int copiousoutput;
256 int needtofree;
257 char *label;
258 char *printcommand;
259 char *nametemplate;
260 float quality;
261 long int maxbytes;
262 };
263
264 static int ExitWithError(const char *txt);
265 static int PassesTest(struct MailcapEntry *mc);
266
GetCommand(char * s,char ** t)267 static char *GetCommand(char *s, char **t)
268 {
269 char *s2;
270 int quoted = 0;
271
272 s = LYSkipBlanks(s);
273 /* marca -- added + 1 for error case -- oct 24, 1993. */
274 s2 = typeMallocn(char, strlen(s) * 2 + 1); /* absolute max, if all % signs */
275
276 if (!s2)
277 ExitWithError(MEMORY_EXHAUSTED_ABORT);
278
279 *t = s2;
280 while (non_empty(s)) {
281 if (quoted) {
282 if (*s == '%')
283 *s2++ = '%'; /* Quote through next level, ugh! */
284
285 *s2++ = *s++;
286 quoted = 0;
287 } else {
288 if (*s == ';') {
289 *s2 = '\0';
290 return (++s);
291 }
292 if (*s == ESCAPE) {
293 quoted = 1;
294 ++s;
295 } else {
296 *s2++ = *s++;
297 }
298 }
299 }
300 *s2 = '\0';
301 return (NULL);
302 }
303
304 /* no leading or trailing space, all lower case */
Cleanse(char * s)305 static char *Cleanse(char *s)
306 {
307 LYTrimLeading(s);
308 LYTrimTrailing(s);
309 LYLowerCase(s);
310 return (s);
311 }
312
313 /* remove unnecessary (unquoted) blanks in a shell command */
TrimCommand(char * command)314 static void TrimCommand(char *command)
315 {
316 LYTrimTrailing(command);
317 #ifdef UNIX
318 {
319 char *s = command;
320 char *d = command;
321 int ch;
322 int c0 = ' ';
323 BOOL escape = FALSE;
324 BOOL dquote = FALSE;
325 BOOL squote = FALSE;
326
327 while ((ch = *s++) != '\0') {
328 if (escape) {
329 escape = FALSE;
330 } else if (squote) {
331 if (ch == SQUOTE)
332 squote = FALSE;
333 } else if (dquote) {
334 switch (ch) {
335 case DQUOTE:
336 dquote = FALSE;
337 break;
338 case ESCAPE:
339 escape = TRUE;
340 break;
341 }
342 } else {
343 switch (ch) {
344 case DQUOTE:
345 dquote = TRUE;
346 break;
347 case SQUOTE:
348 squote = TRUE;
349 break;
350 }
351 }
352 if (!escape && !dquote && !squote) {
353 if (ch == '\t')
354 ch = ' ';
355 if (ch == ' ') {
356 if (c0 == ' ')
357 continue;
358 }
359 }
360 *d++ = (char) ch;
361 c0 = ch;
362 }
363 *d = '\0';
364 }
365 #endif
366 }
367
ProcessMailcapEntry(FILE * fp,struct MailcapEntry * mc,AcceptMedia media)368 static int ProcessMailcapEntry(FILE *fp, struct MailcapEntry *mc, AcceptMedia media)
369 {
370 size_t rawentryalloc = 2000, len, need;
371 char *rawentry, *s, *t;
372 char *LineBuf = NULL;
373
374 rawentry = (char *) malloc(rawentryalloc);
375 if (!rawentry)
376 ExitWithError(MEMORY_EXHAUSTED_ABORT);
377
378 *rawentry = '\0';
379 while (LYSafeGets(&LineBuf, fp) != 0) {
380 LYTrimNewline(LineBuf);
381 if (LineBuf[0] == '#' || LineBuf[0] == '\0')
382 continue;
383 len = strlen(LineBuf);
384 need = len + strlen(rawentry) + 1;
385 if (need > rawentryalloc) {
386 rawentryalloc += (2000 + need);
387 rawentry = typeRealloc(char, rawentry, rawentryalloc);
388
389 if (!rawentry)
390 ExitWithError(MEMORY_EXHAUSTED_ABORT);
391 }
392 if (len > 0 && LineBuf[len - 1] == ESCAPE) {
393 LineBuf[len - 1] = '\0';
394 strcat(rawentry, LineBuf);
395 } else {
396 strcat(rawentry, LineBuf);
397 break;
398 }
399 }
400 FREE(LineBuf);
401
402 t = s = LYSkipBlanks(rawentry);
403 if (!*s) {
404 /* totally blank entry -- quietly ignore */
405 FREE(rawentry);
406 return (0);
407 }
408 s = StrChr(rawentry, ';');
409 if (s == NULL) {
410 CTrace((tfp,
411 "ProcessMailcapEntry: Ignoring invalid mailcap entry: %s\n",
412 rawentry));
413 FREE(rawentry);
414 return (0);
415 }
416 *s++ = '\0';
417 if (!strncasecomp(t, STR_HTML, 9) ||
418 !strncasecomp(t, STR_PLAINTEXT, 10)) {
419 --s;
420 *s = ';';
421 CTrace((tfp, "ProcessMailcapEntry: Ignoring mailcap entry: %s\n",
422 rawentry));
423 FREE(rawentry);
424 return (0);
425 }
426 LYRemoveBlanks(rawentry);
427 LYLowerCase(rawentry);
428
429 mc->needsterminal = 0;
430 mc->copiousoutput = 0;
431 mc->needtofree = 1;
432 mc->testcommand = NULL;
433 mc->label = NULL;
434 mc->printcommand = NULL;
435 mc->contenttype = NULL;
436 StrAllocCopy(mc->contenttype, rawentry);
437 mc->quality = (float) 1.0;
438 mc->maxbytes = 0;
439 t = GetCommand(s, &mc->command);
440 if (!t) {
441 goto assign_presentation;
442 }
443 s = LYSkipBlanks(t);
444 while (s) {
445 char *arg, *eq, *mallocd_string;
446
447 t = GetCommand(s, &mallocd_string);
448 arg = mallocd_string;
449 eq = StrChr(arg, '=');
450 if (eq) {
451 *eq++ = '\0';
452 eq = LYSkipBlanks(eq);
453 }
454 if (non_empty(arg)) {
455 arg = Cleanse(arg);
456 if (!strcmp(arg, "needsterminal")) {
457 mc->needsterminal = 1;
458 } else if (!strcmp(arg, "copiousoutput")) {
459 mc->copiousoutput = 1;
460 } else if (eq && !strcmp(arg, "test")) {
461 mc->testcommand = NULL;
462 StrAllocCopy(mc->testcommand, eq);
463 TrimCommand(mc->testcommand);
464 CTrace((tfp, "ProcessMailcapEntry: Found testcommand:%s\n",
465 mc->testcommand));
466 } else if (eq && !strcmp(arg, "description")) {
467 mc->label = eq; /* ignored */
468 } else if (eq && !strcmp(arg, "label")) {
469 mc->label = eq; /* ignored: bogus old name for description */
470 } else if (eq && !strcmp(arg, "print")) {
471 mc->printcommand = eq; /* ignored */
472 } else if (eq && !strcmp(arg, "textualnewlines")) {
473 /* no support for now. What does this do anyways? */
474 /* ExceptionalNewline(mc->contenttype, atoi(eq)); */
475 } else if (eq && !strcmp(arg, "q")) {
476 mc->quality = (float) atof(eq);
477 if (mc->quality > 0.000 && mc->quality < 0.001)
478 mc->quality = (float) 0.001;
479 } else if (eq && !strcmp(arg, "mxb")) {
480 mc->maxbytes = atol(eq);
481 if (mc->maxbytes < 0)
482 mc->maxbytes = 0;
483 } else if (strcmp(arg, "notes")) { /* IGNORE notes field */
484 if (*arg)
485 CTrace((tfp,
486 "ProcessMailcapEntry: Ignoring mailcap flag '%s'.\n",
487 arg));
488 }
489
490 }
491 FREE(mallocd_string);
492 s = t;
493 }
494
495 assign_presentation:
496 FREE(rawentry);
497
498 if (PassesTest(mc)) {
499 CTrace((tfp, "ProcessMailcapEntry Setting up conversion %s : %s\n",
500 mc->contenttype, mc->command));
501 HTSetPresentation(mc->contenttype,
502 mc->command,
503 mc->testcommand,
504 mc->quality,
505 3.0, 0.0, mc->maxbytes, media);
506 }
507 FREE(mc->command);
508 FREE(mc->testcommand);
509 FREE(mc->contenttype);
510
511 return (1);
512 }
513
514 #define L_CURL '{'
515 #define R_CURL '}'
516
LYSkipQuoted(const char * s)517 static const char *LYSkipQuoted(const char *s)
518 {
519 int escaped = 0;
520
521 ++s; /* skip first quote */
522 while (*s != 0) {
523 if (escaped) {
524 escaped = 0;
525 } else if (*s == ESCAPE) {
526 escaped = 1;
527 } else if (*s == DQUOTE) {
528 ++s;
529 break;
530 }
531 ++s;
532 }
533 return s;
534 }
535
536 /*
537 * Note: the tspecials[] here are those defined for Content-Type header, so
538 * this function is not really general-purpose.
539 */
LYSkipToken(const char * s)540 static const char *LYSkipToken(const char *s)
541 {
542 static const char tspecials[] = "\"()<>@,;:\\/[]?.=";
543
544 while (*s != '\0' && !WHITE(*s) && StrChr(tspecials, *s) == 0) {
545 ++s;
546 }
547 return s;
548 }
549
LYSkipValue(const char * s)550 static const char *LYSkipValue(const char *s)
551 {
552 if (*s == DQUOTE)
553 s = LYSkipQuoted(s);
554 else
555 s = LYSkipToken(s);
556 return s;
557 }
558
559 /*
560 * Copy the value from the source, dequoting if needed.
561 */
LYCopyValue(const char * s)562 static char *LYCopyValue(const char *s)
563 {
564 const char *t;
565 char *result = 0;
566 int j, k;
567
568 if (*s == DQUOTE) {
569 t = LYSkipQuoted(s);
570 StrAllocCopy(result, s + 1);
571 result[t - s - 2] = '\0';
572 for (j = k = 0;; ++j, ++k) {
573 if (result[j] == ESCAPE) {
574 ++j;
575 }
576 if ((result[k] = result[j]) == '\0')
577 break;
578 }
579 } else {
580 t = LYSkipToken(s);
581 StrAllocCopy(result, s);
582 result[t - s] = '\0';
583 }
584 return result;
585 }
586
587 /*
588 * The "Content-Type:" field, contains zero or more parameters after a ';'.
589 * Return the value of the named parameter, or null.
590 */
LYGetContentType(const char * name,const char * params)591 static char *LYGetContentType(const char *name,
592 const char *params)
593 {
594 char *result = 0;
595
596 if (params != 0) {
597 if (name != 0) {
598 size_t length = strlen(name);
599 const char *test = StrChr(params, ';'); /* skip type/subtype */
600 const char *next;
601
602 while (test != 0) {
603 BOOL found = FALSE;
604
605 ++test; /* skip the ';' */
606 test = LYSkipCBlanks(test);
607 next = LYSkipToken(test);
608 if ((next - test) == (int) length
609 && !StrNCmp(test, name, length)) {
610 found = TRUE;
611 }
612 test = LYSkipCBlanks(next);
613 if (*test == '=') {
614 ++test;
615 test = LYSkipCBlanks(test);
616 if (found) {
617 result = LYCopyValue(test);
618 break;
619 } else {
620 test = LYSkipValue(test);
621 }
622 test = LYSkipCBlanks(test);
623 }
624 if (*test != ';') {
625 break; /* we're lost */
626 }
627 }
628 } else { /* return the content-type */
629 StrAllocCopy(result, params);
630 *LYSkipNonBlanks(result) = '\0';
631 }
632 }
633 return result;
634 }
635
636 /*
637 * Check if the command uses a "%s" substitution. We need to know this, to
638 * decide when to create temporary files, etc.
639 */
LYMailcapUsesPctS(const char * controlstring)640 BOOL LYMailcapUsesPctS(const char *controlstring)
641 {
642 BOOL result = FALSE;
643 const char *from;
644 const char *next;
645 int prefixed = 0;
646 int escaped = 0;
647
648 for (from = controlstring; *from != '\0'; from++) {
649 if (escaped) {
650 escaped = 0;
651 } else if (*from == ESCAPE) {
652 escaped = 1;
653 } else if (prefixed) {
654 prefixed = 0;
655 switch (*from) {
656 case '%': /* not defined */
657 case 'n':
658 case 'F':
659 case 't':
660 break;
661 case 's':
662 result = TRUE;
663 break;
664 case L_CURL:
665 next = StrChr(from, R_CURL);
666 if (next != 0) {
667 from = next;
668 break;
669 }
670 /* FALLTHRU */
671 default:
672 break;
673 }
674 } else if (*from == '%') {
675 prefixed = 1;
676 }
677 }
678 return result;
679 }
680
681 /*
682 * Build the command string for testing or executing a mailcap entry.
683 * If a substitution from the Content-Type header is requested but no
684 * parameters are available, return -1, otherwise 0.
685 *
686 * This does not support multipart %n or %F (does this apply to lynx?)
687 */
BuildCommand(HTChunk * cmd,const char * controlstring,const char * TmpFileName,const char * params)688 static int BuildCommand(HTChunk *cmd,
689 const char *controlstring,
690 const char *TmpFileName,
691 const char *params)
692 {
693 int result = 0;
694 size_t TmpFileLen = strlen(TmpFileName);
695 const char *from;
696 const char *next;
697 char *name, *value;
698 int prefixed = 0;
699 int escaped = 0;
700
701 for (from = controlstring; *from != '\0'; from++) {
702 if (escaped) {
703 escaped = 0;
704 HTChunkPutc(cmd, UCH(*from));
705 } else if (*from == ESCAPE) {
706 escaped = 1;
707 } else if (prefixed) {
708 prefixed = 0;
709 switch (*from) {
710 case '%': /* not defined */
711 HTChunkPutc(cmd, UCH(*from));
712 break;
713 case 'n':
714 /* FALLTHRU */
715 case 'F':
716 CTrace((tfp, "BuildCommand: Bad mailcap \"test\" clause: %s\n",
717 controlstring));
718 break;
719 case 't':
720 if ((value = LYGetContentType(NULL, params)) != 0) {
721 HTChunkPuts(cmd, value);
722 FREE(value);
723 }
724 break;
725 case 's':
726 if (TmpFileLen) {
727 HTChunkPuts(cmd, TmpFileName);
728 }
729 break;
730 case L_CURL:
731 next = StrChr(from, R_CURL);
732 if (next != 0) {
733 if (params != 0) {
734 ++from;
735 name = 0;
736 HTSprintf0(&name, "%.*s", (int) (next - from), from);
737 if ((value = LYGetContentType(name, params)) != 0) {
738 HTChunkPuts(cmd, value);
739 FREE(value);
740 } else if (name) {
741 if (!strcmp(name, "charset")) {
742 HTChunkPuts(cmd, "ISO-8859-1");
743 } else {
744 CTrace((tfp, "BuildCommand no value for %s\n", name));
745 }
746 }
747 FREE(name);
748 } else {
749 result = -1;
750 }
751 from = next;
752 break;
753 }
754 /* FALLTHRU */
755 default:
756 CTrace((tfp,
757 "BuildCommand: Ignoring unrecognized format code in mailcap file '%%%c'.\n",
758 *from));
759 break;
760 }
761 } else if (*from == '%') {
762 prefixed = 1;
763 } else {
764 HTChunkPutc(cmd, UCH(*from));
765 }
766 }
767 HTChunkTerminate(cmd);
768 return result;
769 }
770
771 /*
772 * Build the mailcap test-command and execute it. This is only invoked when
773 * we cannot tell just by looking at the command if it would succeed.
774 *
775 * Returns 0 for success, -1 for error and 1 for deferred.
776 */
LYTestMailcapCommand(const char * testcommand,const char * params)777 int LYTestMailcapCommand(const char *testcommand,
778 const char *params)
779 {
780 int result;
781 char TmpFileName[LY_MAXPATH];
782 HTChunk *expanded = 0;
783
784 if (LYMailcapUsesPctS(testcommand)) {
785 if (LYOpenTemp(TmpFileName, HTML_SUFFIX, "w") == 0)
786 ExitWithError(CANNOT_OPEN_TEMP);
787 LYCloseTemp(TmpFileName);
788 } else {
789 /* We normally don't need a temp file name - kw */
790 TmpFileName[0] = '\0';
791 }
792 expanded = HTChunkCreate(1024);
793 if (BuildCommand(expanded, testcommand, TmpFileName, params) != 0) {
794 result = 1;
795 CTrace((tfp, "PassesTest: Deferring test command: %s\n", expanded->data));
796 } else {
797 CTrace((tfp, "PassesTest: Executing test command: %s\n", expanded->data));
798 if ((result = LYSystem(expanded->data)) != 0) {
799 result = -1;
800 CTrace((tfp, "PassesTest: Test failed!\n"));
801 } else {
802 CTrace((tfp, "PassesTest: Test passed!\n"));
803 }
804 }
805
806 HTChunkFree(expanded);
807 (void) LYRemoveTemp(TmpFileName);
808
809 return result;
810 }
811
LYMakeMailcapCommand(const char * command,const char * params,const char * filename)812 char *LYMakeMailcapCommand(const char *command,
813 const char *params,
814 const char *filename)
815 {
816 HTChunk *expanded = 0;
817 char *result = 0;
818
819 expanded = HTChunkCreate(1024);
820 BuildCommand(expanded, command, filename, params);
821 StrAllocCopy(result, expanded->data);
822 HTChunkFree(expanded);
823 return result;
824 }
825
826 #define RTR_forget 0
827 #define RTR_lookup 1
828 #define RTR_add 2
829
RememberTestResult(int mode,char * cmd,int result)830 static int RememberTestResult(int mode, char *cmd, int result)
831 {
832 struct cmdlist_s {
833 char *cmd;
834 int result;
835 struct cmdlist_s *next;
836 };
837 static struct cmdlist_s *cmdlist = NULL;
838 struct cmdlist_s *cur;
839
840 switch (mode) {
841 case RTR_forget:
842 while (cmdlist) {
843 cur = cmdlist->next;
844 FREE(cmdlist->cmd);
845 FREE(cmdlist);
846 cmdlist = cur;
847 }
848 break;
849 case RTR_lookup:
850 for (cur = cmdlist; cur; cur = cur->next)
851 if (!strcmp(cmd, cur->cmd))
852 return cur->result;
853 return -1;
854 case RTR_add:
855 cur = typecalloc(struct cmdlist_s);
856
857 if (cur == NULL)
858 outofmem(__FILE__, "RememberTestResult");
859
860 cur->next = cmdlist;
861 StrAllocCopy(cur->cmd, cmd);
862 cur->result = result;
863 cmdlist = cur;
864 break;
865 }
866 return 0;
867 }
868
869 /* FIXME: this sometimes used caseless comparison, e.g., strcasecomp */
870 #define SameCommand(tst,ref) !strcmp(tst,ref)
871
PassesTest(struct MailcapEntry * mc)872 static int PassesTest(struct MailcapEntry *mc)
873 {
874 int result;
875
876 /*
877 * Make sure we have a command
878 */
879 if (!mc->testcommand)
880 return (1);
881
882 /*
883 * Save overhead of system() calls by faking these. - FM
884 */
885 if (SameCommand(mc->testcommand, "test \"$DISPLAY\"") ||
886 SameCommand(mc->testcommand, "test \"$DISPLAY\" != \"\"") ||
887 SameCommand(mc->testcommand, "test -n \"$DISPLAY\"")) {
888 FREE(mc->testcommand);
889 CTrace((tfp, "PassesTest: Testing for XWINDOWS environment.\n"));
890 if (LYgetXDisplay() != NULL) {
891 CTrace((tfp, "PassesTest: Test passed!\n"));
892 return (0 == 0);
893 } else {
894 CTrace((tfp, "PassesTest: Test failed!\n"));
895 return (-1 == 0);
896 }
897 }
898 if (SameCommand(mc->testcommand, "test -z \"$DISPLAY\"")) {
899 FREE(mc->testcommand);
900 CTrace((tfp, "PassesTest: Testing for NON_XWINDOWS environment.\n"));
901 if (LYgetXDisplay() == NULL) {
902 CTrace((tfp, "PassesTest: Test passed!\n"));
903 return (0 == 0);
904 } else {
905 CTrace((tfp, "PassesTest: Test failed!\n"));
906 return (-1 == 0);
907 }
908 }
909
910 /*
911 * Why do anything but return success for this one! - FM
912 */
913 if (SameCommand(mc->testcommand, "test -n \"$LYNX_VERSION\"")) {
914 FREE(mc->testcommand);
915 CTrace((tfp, "PassesTest: Testing for LYNX environment.\n"));
916 CTrace((tfp, "PassesTest: Test passed!\n"));
917 return (0 == 0);
918 } else
919 /*
920 * ... or failure for this one! - FM
921 */
922 if (SameCommand(mc->testcommand, "test -z \"$LYNX_VERSION\"")) {
923 FREE(mc->testcommand);
924 CTrace((tfp, "PassesTest: Testing for non-LYNX environment.\n"));
925 CTrace((tfp, "PassesTest: Test failed!\n"));
926 return (-1 == 0);
927 }
928
929 result = RememberTestResult(RTR_lookup, mc->testcommand, 0);
930 if (result == -1) {
931 result = LYTestMailcapCommand(mc->testcommand, NULL);
932 RememberTestResult(RTR_add, mc->testcommand, result ? 1 : 0);
933 }
934
935 /*
936 * Free the test command as well since
937 * we won't be needing it anymore.
938 */
939 if (result != 1)
940 FREE(mc->testcommand);
941
942 if (result < 0) {
943 CTrace((tfp, "PassesTest: Test failed!\n"));
944 } else if (result == 0) {
945 CTrace((tfp, "PassesTest: Test passed!\n"));
946 }
947
948 return (result >= 0);
949 }
950
ProcessMailcapFile(char * file,AcceptMedia media)951 static int ProcessMailcapFile(char *file, AcceptMedia media)
952 {
953 struct MailcapEntry mc;
954 FILE *fp;
955
956 CTrace((tfp, "ProcessMailcapFile: Loading file '%s'.\n",
957 file));
958 if ((fp = fopen(file, TXT_R)) == NULL) {
959 CTrace((tfp, "ProcessMailcapFile: Could not open '%s'.\n",
960 file));
961 return (-1 == 0);
962 }
963
964 while (fp && !feof(fp)) {
965 ProcessMailcapEntry(fp, &mc, media);
966 }
967 LYCloseInput(fp);
968 RememberTestResult(RTR_forget, NULL, 0);
969 return (0 == 0);
970 }
971
ExitWithError(const char * txt)972 static int ExitWithError(const char *txt)
973 {
974 if (txt)
975 fprintf(tfp, "Lynx: %s\n", txt);
976 exit_immediately(EXIT_FAILURE);
977 return (-1);
978 }
979
980 /* Reverse the entries from each mailcap after it has been read, so that
981 * earlier entries have precedence. Set to 0 to get traditional lynx
982 * behavior, which means that the last match wins. - kw */
983 static int reverse_mailcap = 1;
984
HTLoadTypesConfigFile(char * fn,AcceptMedia media)985 static int HTLoadTypesConfigFile(char *fn, AcceptMedia media)
986 {
987 int result = 0;
988 HTList *saved = HTPresentations;
989
990 if (reverse_mailcap) { /* temporarily hide existing list */
991 HTPresentations = NULL;
992 }
993
994 result = ProcessMailcapFile(fn, media);
995
996 if (reverse_mailcap) {
997 if (result && HTPresentations) {
998 HTList_reverse(HTPresentations);
999 HTList_appendList(HTPresentations, saved);
1000 FREE(saved);
1001 } else {
1002 HTPresentations = saved;
1003 }
1004 }
1005 return result;
1006 }
1007
1008 /* ------------------------------------------------------------------------ */
1009 /* ------------------------------------------------------------------------ */
1010 /* ------------------------------------------------------------------------ */
1011
1012 /* Define a basic set of suffixes
1013 * ------------------------------
1014 *
1015 * The LAST suffix for a type is that used for temporary files
1016 * of that type.
1017 * The quality is an apriori bias as to whether the file should be
1018 * used. Not that different suffixes can be used to represent files
1019 * which are of the same format but are originals or regenerated,
1020 * with different values.
1021 */
1022 /*
1023 * Additional notes: the encoding parameter may be taken into account when
1024 * looking for a match; for that purpose "7bit", "8bit", and "binary" are
1025 * equivalent.
1026 *
1027 * Use of mixed case and of pseudo MIME types with embedded spaces should be
1028 * avoided. It was once necessary for getting the fancy strings into type
1029 * labels in FTP directory listings, but that can now be done with the
1030 * description field (using HTSetSuffix5). AFAIK the only effect of such
1031 * "fancy" (and mostly invalid) types that cannot be reproduced by using a
1032 * description fields is some statusline messages in SaveToFile (HTFWriter.c).
1033 * And showing the user an invalid MIME type as the 'Content-type:' is not such
1034 * a hot idea anyway, IMO. Still, if you want it, it is still possible (even
1035 * in lynx.cfg now), but use of it in the defaults below has been reduced.
1036 *
1037 * Case variations rely on peculiar behavior of HTAtom.c for matching. They
1038 * lead to surprising behavior, Lynx retains the case of a string in the form
1039 * first encountered after starting up. So while later suffix rules generally
1040 * override or modify earlier ones, the case used for a MIME time is determined
1041 * by the first suffix rule (or other occurrence). Matching in HTAtom_for is
1042 * effectively case insensitive, except for the first character of the string
1043 * which is treated as case-sensitive by the hash function there; best not to
1044 * rely on that, rather convert MIME types to lowercase on input as is already
1045 * done in most places (And HTAtom could become consistently case-sensitive, as
1046 * in newer W3C libwww).
1047 * - kw 1999-10-12
1048 */
HTFileInit(void)1049 void HTFileInit(void)
1050 {
1051 #ifdef BUILTIN_SUFFIX_MAPS
1052 if (LYUseBuiltinSuffixes) {
1053 CTrace((tfp, "HTFileInit: Loading default (HTInit) extension maps.\n"));
1054
1055 /* default suffix interpretation */
1056 SET_SUFFIX1("*", STR_PLAINTEXT, "8bit");
1057 SET_SUFFIX1("*.*", STR_PLAINTEXT, "8bit");
1058
1059 #ifdef EXEC_SCRIPTS
1060 /*
1061 * define these extensions for exec scripts.
1062 */
1063 #ifndef VMS
1064 /* for csh exec links */
1065 HTSetSuffix(".csh", "application/x-csh", "8bit", 0.8);
1066 HTSetSuffix(".sh", "application/x-sh", "8bit", 0.8);
1067 HTSetSuffix(".ksh", "application/x-ksh", "8bit", 0.8);
1068 #else
1069 HTSetSuffix(".com", "application/x-VMS_script", "8bit", 0.8);
1070 #endif /* !VMS */
1071 #endif /* EXEC_SCRIPTS */
1072
1073 /*
1074 * Some of the old incarnation of the mappings is preserved and can be had
1075 * by defining TRADITIONAL_SUFFIXES. This is for some cases where I felt
1076 * the old rules might be preferred by someone, for some reason. It's not
1077 * done consistently. A lot more of this stuff could probably be changed
1078 * too or omitted, now that nearly the equivalent functionality is
1079 * available in lynx.cfg. - kw 1999-10-12
1080 */
1081 /* *INDENT-OFF* */
1082 SET_SUFFIX1(".saveme", "application/x-Binary", "binary");
1083 SET_SUFFIX1(".dump", "application/x-Binary", "binary");
1084 SET_SUFFIX1(".bin", "application/x-Binary", "binary");
1085
1086 SET_SUFFIX1(".arc", "application/x-Compressed", "binary");
1087
1088 SET_SUFFIX1(".alpha-exe", "application/x-Executable", "binary");
1089 SET_SUFFIX1(".alpha_exe", "application/x-Executable", "binary");
1090 SET_SUFFIX1(".AXP-exe", "application/x-Executable", "binary");
1091 SET_SUFFIX1(".AXP_exe", "application/x-Executable", "binary");
1092 SET_SUFFIX1(".VAX-exe", "application/x-Executable", "binary");
1093 SET_SUFFIX1(".VAX_exe", "application/x-Executable", "binary");
1094 SET_SUFFIX5(".exe", STR_BINARY, "binary", "Executable");
1095
1096 #ifdef TRADITIONAL_SUFFIXES
1097 SET_SUFFIX1(".exe.Z", "application/x-Comp. Executable", "binary");
1098 SET_SUFFIX1(".Z", "application/UNIX Compressed", "binary");
1099 SET_SUFFIX1(".tar_Z", "application/UNIX Compr. Tar", "binary");
1100 SET_SUFFIX1(".tar.Z", "application/UNIX Compr. Tar", "binary");
1101 #else
1102 SET_SUFFIX5(".Z", "application/x-compress", "binary", "UNIX Compressed");
1103 SET_SUFFIX5(".Z", NULL, "compress", "UNIX Compressed");
1104 SET_SUFFIX5(".exe.Z", STR_BINARY, "compress", "Executable");
1105 SET_SUFFIX5(".tar_Z", "application/x-tar", "compress", "UNIX Compr. Tar");
1106 SET_SUFFIX5(".tar.Z", "application/x-tar", "compress", "UNIX Compr. Tar");
1107 #endif
1108
1109 #ifdef TRADITIONAL_SUFFIXES
1110 SET_SUFFIX1("-gz", "application/GNU Compressed", "binary");
1111 SET_SUFFIX1("_gz", "application/GNU Compressed", "binary");
1112 SET_SUFFIX1(".gz", "application/GNU Compressed", "binary");
1113
1114 SET_SUFFIX5(".tar.gz", "application/x-tar", "binary", "GNU Compr. Tar");
1115 SET_SUFFIX5(".tgz", "application/x-tar", "gzip", "GNU Compr. Tar");
1116 #else
1117 SET_SUFFIX5("-gz", "application/x-gzip", "binary", "GNU Compressed");
1118 SET_SUFFIX5("_gz", "application/x-gzip", "binary", "GNU Compressed");
1119 SET_SUFFIX5(".gz", "application/x-gzip", "binary", "GNU Compressed");
1120 SET_SUFFIX5("-gz", NULL, "gzip", "GNU Compressed");
1121 SET_SUFFIX5("_gz", NULL, "gzip", "GNU Compressed");
1122 SET_SUFFIX5(".gz", NULL, "gzip", "GNU Compressed");
1123
1124 SET_SUFFIX5(".tar.gz", "application/x-tar", "gzip", "GNU Compr. Tar");
1125 SET_SUFFIX5(".tgz", "application/x-tar", "gzip", "GNU Compr. Tar");
1126 #endif
1127
1128 #ifdef TRADITIONAL_SUFFIXES
1129 SET_SUFFIX1(".src", "application/x-WAIS-source", "8bit");
1130 SET_SUFFIX1(".wsrc", "application/x-WAIS-source", "8bit");
1131 #else
1132 SET_SUFFIX5(".wsrc", "application/x-wais-source", "8bit", "WAIS-source");
1133 #endif
1134
1135 SET_SUFFIX5(".zip", "application/zip", "binary", "Zip File");
1136
1137 SET_SUFFIX1(".zz", "application/x-deflate", "binary");
1138 SET_SUFFIX1(".zz", "application/deflate", "binary");
1139
1140 SET_SUFFIX1(".bz2", "application/x-bzip2", "binary");
1141 SET_SUFFIX1(".bz2", "application/bzip2", "binary");
1142
1143 #ifdef TRADITIONAL_SUFFIXES
1144 SET_SUFFIX1(".uu", "application/x-UUencoded", "8bit");
1145
1146 SET_SUFFIX1(".hqx", "application/x-Binhex", "8bit");
1147
1148 SET_SUFFIX1(".o", "application/x-Prog. Object", "binary");
1149 SET_SUFFIX1(".a", "application/x-Prog. Library", "binary");
1150 #else
1151 SET_SUFFIX5(".uu", "application/x-uuencoded", "7bit", "UUencoded");
1152
1153 SET_SUFFIX5(".hqx", "application/mac-binhex40", "8bit", "Mac BinHex");
1154
1155 HTSetSuffix5(".o", STR_BINARY, "binary", "Prog. Object", 0.5);
1156 HTSetSuffix5(".a", STR_BINARY, "binary", "Prog. Library", 0.5);
1157 HTSetSuffix5(".so", STR_BINARY, "binary", "Shared Lib", 0.5);
1158 #endif
1159
1160 SET_SUFFIX5(".oda", "application/oda", "binary", "ODA");
1161
1162 SET_SUFFIX5(".pdf", "application/pdf", "binary", "PDF");
1163
1164 SET_SUFFIX5(".eps", "application/postscript", "8bit", "Postscript");
1165 SET_SUFFIX5(".ai", "application/postscript", "8bit", "Postscript");
1166 SET_SUFFIX5(".ps", "application/postscript", "8bit", "Postscript");
1167
1168 SET_SUFFIX5(".rtf", "application/rtf", "8bit", "RTF");
1169
1170 SET_SUFFIX5(".dvi", "application/x-dvi", "8bit", "DVI");
1171
1172 SET_SUFFIX5(".hdf", "application/x-hdf", "8bit", "HDF");
1173
1174 SET_SUFFIX1(".cdf", "application/x-netcdf", "8bit");
1175 SET_SUFFIX1(".nc", "application/x-netcdf", "8bit");
1176
1177 #ifdef TRADITIONAL_SUFFIXES
1178 SET_SUFFIX1(".latex", "application/x-Latex", "8bit");
1179 SET_SUFFIX1(".tex", "application/x-Tex", "8bit");
1180 SET_SUFFIX1(".texinfo", "application/x-Texinfo", "8bit");
1181 SET_SUFFIX1(".texi", "application/x-Texinfo", "8bit");
1182 #else
1183 SET_SUFFIX5(".latex", "application/x-latex", "8bit", "LaTeX");
1184 SET_SUFFIX5(".tex", "text/x-tex", "8bit", "TeX");
1185 SET_SUFFIX5(".texinfo", "application/x-texinfo", "8bit", "Texinfo");
1186 SET_SUFFIX5(".texi", "application/x-texinfo", "8bit", "Texinfo");
1187 #endif
1188
1189 #ifdef TRADITIONAL_SUFFIXES
1190 SET_SUFFIX1(".t", "application/x-Troff", "8bit");
1191 SET_SUFFIX1(".tr", "application/x-Troff", "8bit");
1192 SET_SUFFIX1(".roff", "application/x-Troff", "8bit");
1193
1194 SET_SUFFIX1(".man", "application/x-Troff-man", "8bit");
1195 SET_SUFFIX1(".me", "application/x-Troff-me", "8bit");
1196 SET_SUFFIX1(".ms", "application/x-Troff-ms", "8bit");
1197 #else
1198 SET_SUFFIX5(".t", "application/x-troff", "8bit", "Troff");
1199 SET_SUFFIX5(".tr", "application/x-troff", "8bit", "Troff");
1200 SET_SUFFIX5(".roff", "application/x-troff", "8bit", "Troff");
1201
1202 SET_SUFFIX5(".man", "application/x-troff-man", "8bit", "Man Page");
1203 SET_SUFFIX5(".me", "application/x-troff-me", "8bit", "Troff me");
1204 SET_SUFFIX5(".ms", "application/x-troff-ms", "8bit", "Troff ms");
1205 #endif
1206
1207 SET_SUFFIX1(".zoo", "application/x-Zoo File", "binary");
1208
1209 #if defined(TRADITIONAL_SUFFIXES) || defined(VMS)
1210 SET_SUFFIX1(".bak", "application/x-VMS BAK File", "binary");
1211 SET_SUFFIX1(".bkp", "application/x-VMS BAK File", "binary");
1212 SET_SUFFIX1(".bck", "application/x-VMS BAK File", "binary");
1213
1214 SET_SUFFIX5(".bkp_gz", STR_BINARY, "gzip", "GNU BAK File");
1215 SET_SUFFIX5(".bkp-gz", STR_BINARY, "gzip", "GNU BAK File");
1216 SET_SUFFIX5(".bck_gz", STR_BINARY, "gzip", "GNU BAK File");
1217 SET_SUFFIX5(".bck-gz", STR_BINARY, "gzip", "GNU BAK File");
1218
1219 SET_SUFFIX5(".bkp-Z", STR_BINARY, "compress", "Comp. BAK File");
1220 SET_SUFFIX5(".bkp_Z", STR_BINARY, "compress", "Comp. BAK File");
1221 SET_SUFFIX5(".bck-Z", STR_BINARY, "compress", "Comp. BAK File");
1222 SET_SUFFIX5(".bck_Z", STR_BINARY, "compress", "Comp. BAK File");
1223 #else
1224 HTSetSuffix5(".bak", NULL, "binary", "Backup", 0.5);
1225 SET_SUFFIX5(".bkp", STR_BINARY, "binary", "VMS BAK File");
1226 SET_SUFFIX5(".bck", STR_BINARY, "binary", "VMS BAK File");
1227 #endif
1228
1229 #if defined(TRADITIONAL_SUFFIXES) || defined(VMS)
1230 SET_SUFFIX1(".hlb", "application/x-VMS Help Libr.", "binary");
1231 SET_SUFFIX1(".olb", "application/x-VMS Obj. Libr.", "binary");
1232 SET_SUFFIX1(".tlb", "application/x-VMS Text Libr.", "binary");
1233 SET_SUFFIX1(".obj", "application/x-VMS Prog. Obj.", "binary");
1234 SET_SUFFIX1(".decw$book", "application/x-DEC BookReader", "binary");
1235 SET_SUFFIX1(".mem", "application/x-RUNOFF-MANUAL", "8bit");
1236 #else
1237 SET_SUFFIX5(".hlb", STR_BINARY, "binary", "VMS Help Libr.");
1238 SET_SUFFIX5(".olb", STR_BINARY, "binary", "VMS Obj. Libr.");
1239 SET_SUFFIX5(".tlb", STR_BINARY, "binary", "VMS Text Libr.");
1240 SET_SUFFIX5(".obj", STR_BINARY, "binary", "Prog. Object");
1241 SET_SUFFIX5(".decw$book", STR_BINARY, "binary", "DEC BookReader");
1242 SET_SUFFIX5(".mem", "text/x-runoff-manual", "8bit", "RUNOFF-MANUAL");
1243 #endif
1244
1245 SET_SUFFIX1(".vsd", "application/visio", "binary");
1246
1247 SET_SUFFIX5(".lha", "application/x-lha", "binary", "lha File");
1248 SET_SUFFIX5(".lzh", "application/x-lzh", "binary", "lzh File");
1249 SET_SUFFIX5(".sea", "application/x-sea", "binary", "sea File");
1250 #ifdef TRADITIONAL_SUFFIXES
1251 SET_SUFFIX5(".sit", "application/x-sit", "binary", "sit File");
1252 #else
1253 SET_SUFFIX5(".sit", "application/x-stuffit", "binary", "StuffIt");
1254 #endif
1255 SET_SUFFIX5(".dms", "application/x-dms", "binary", "dms File");
1256 SET_SUFFIX5(".iff", "application/x-iff", "binary", "iff File");
1257
1258 SET_SUFFIX1(".bcpio", "application/x-bcpio", "binary");
1259 SET_SUFFIX1(".cpio", "application/x-cpio", "binary");
1260
1261 #ifdef TRADITIONAL_SUFFIXES
1262 SET_SUFFIX1(".gtar", "application/x-gtar", "binary");
1263 #endif
1264
1265 SET_SUFFIX1(".shar", "application/x-shar", "8bit");
1266 SET_SUFFIX1(".share", "application/x-share", "8bit");
1267
1268 #ifdef TRADITIONAL_SUFFIXES
1269 SET_SUFFIX1(".sh", "application/x-sh", "8bit"); /* xtra */
1270 #endif
1271
1272 SET_SUFFIX1(".sv4cpio", "application/x-sv4cpio", "binary");
1273 SET_SUFFIX1(".sv4crc", "application/x-sv4crc", "binary");
1274
1275 SET_SUFFIX5(".tar", "application/x-tar", "binary", "Tar File");
1276 SET_SUFFIX1(".ustar", "application/x-ustar", "binary");
1277
1278 SET_SUFFIX1(".snd", "audio/basic", "binary");
1279 SET_SUFFIX1(".au", "audio/basic", "binary");
1280
1281 SET_SUFFIX1(".aifc", "audio/x-aiff", "binary");
1282 SET_SUFFIX1(".aif", "audio/x-aiff", "binary");
1283 SET_SUFFIX1(".aiff", "audio/x-aiff", "binary");
1284 SET_SUFFIX1(".wav", "audio/x-wav", "binary");
1285 SET_SUFFIX1(".midi", "audio/midi", "binary");
1286 SET_SUFFIX1(".mod", "audio/mod", "binary");
1287
1288 SET_SUFFIX1(".gif", "image/gif", "binary");
1289 SET_SUFFIX1(".ief", "image/ief", "binary");
1290 SET_SUFFIX1(".jfif", "image/jpeg", "binary"); /* xtra */
1291 SET_SUFFIX1(".jfif-tbnl", "image/jpeg", "binary"); /* xtra */
1292 SET_SUFFIX1(".jpe", "image/jpeg", "binary");
1293 SET_SUFFIX1(".jpg", "image/jpeg", "binary");
1294 SET_SUFFIX1(".jpeg", "image/jpeg", "binary");
1295 SET_SUFFIX1(".tif", "image/tiff", "binary");
1296 SET_SUFFIX1(".tiff", "image/tiff", "binary");
1297 SET_SUFFIX1(".ham", "image/ham", "binary");
1298 SET_SUFFIX1(".ras", "image/x-cmu-rast", "binary");
1299 SET_SUFFIX1(".pnm", "image/x-portable-anymap", "binary");
1300 SET_SUFFIX1(".pbm", "image/x-portable-bitmap", "binary");
1301 SET_SUFFIX1(".pgm", "image/x-portable-graymap", "binary");
1302 SET_SUFFIX1(".ppm", "image/x-portable-pixmap", "binary");
1303 SET_SUFFIX1(".png", "image/png", "binary");
1304 SET_SUFFIX1(".rgb", "image/x-rgb", "binary");
1305 SET_SUFFIX1(".xbm", "image/x-xbitmap", "binary");
1306 SET_SUFFIX1(".xpm", "image/x-xpixmap", "binary");
1307 SET_SUFFIX1(".xwd", "image/x-xwindowdump", "binary");
1308
1309 SET_SUFFIX1(".rtx", "text/richtext", "8bit");
1310 SET_SUFFIX1(".tsv", "text/tab-separated-values", "8bit");
1311 SET_SUFFIX1(".etx", "text/x-setext", "8bit");
1312
1313 SET_SUFFIX1(".mpg", "video/mpeg", "binary");
1314 SET_SUFFIX1(".mpe", "video/mpeg", "binary");
1315 SET_SUFFIX1(".mpeg", "video/mpeg", "binary");
1316 SET_SUFFIX1(".mov", "video/quicktime", "binary");
1317 SET_SUFFIX1(".qt", "video/quicktime", "binary");
1318 SET_SUFFIX1(".avi", "video/x-msvideo", "binary");
1319 SET_SUFFIX1(".movie", "video/x-sgi-movie", "binary");
1320 SET_SUFFIX1(".mv", "video/x-sgi-movie", "binary");
1321
1322 SET_SUFFIX1(".mime", "message/rfc822", "8bit");
1323
1324 SET_SUFFIX1(".c", STR_PLAINTEXT, "8bit");
1325 SET_SUFFIX1(".cc", STR_PLAINTEXT, "8bit");
1326 SET_SUFFIX1(".c++", STR_PLAINTEXT, "8bit");
1327 SET_SUFFIX1(".css", STR_PLAINTEXT, "8bit");
1328 SET_SUFFIX1(".h", STR_PLAINTEXT, "8bit");
1329 SET_SUFFIX1(".pl", STR_PLAINTEXT, "8bit");
1330 SET_SUFFIX1(".text", STR_PLAINTEXT, "8bit");
1331 SET_SUFFIX1(".txt", STR_PLAINTEXT, "8bit");
1332
1333 SET_SUFFIX1(".php", STR_HTML, "8bit");
1334 SET_SUFFIX1(".php3", STR_HTML, "8bit");
1335 SET_SUFFIX1(".html3", STR_HTML, "8bit");
1336 SET_SUFFIX1(".ht3", STR_HTML, "8bit");
1337 SET_SUFFIX1(".phtml", STR_HTML, "8bit");
1338 SET_SUFFIX1(".shtml", STR_HTML, "8bit");
1339 SET_SUFFIX1(".sht", STR_HTML, "8bit");
1340 SET_SUFFIX1(".htmlx", STR_HTML, "8bit");
1341 SET_SUFFIX1(".htm", STR_HTML, "8bit");
1342 SET_SUFFIX1(".html", STR_HTML, "8bit");
1343 /* *INDENT-ON* */
1344
1345 } else { /* LYSuffixRules */
1346 /*
1347 * Note that even .html -> text/html, .htm -> text/html are omitted if
1348 * default maps are compiled in but then skipped because of a
1349 * configuration file directive. Whoever changes the config file in
1350 * this way can easily also add the SUFFIX rules there. - kw
1351 */
1352 CTrace((tfp,
1353 "HTFileInit: Skipping all default (HTInit) extension maps!\n"));
1354 } /* LYSuffixRules */
1355
1356 #else /* BUILTIN_SUFFIX_MAPS */
1357
1358 CTrace((tfp,
1359 "HTFileInit: Default (HTInit) extension maps not compiled in.\n"));
1360 /*
1361 * The following two are still used if BUILTIN_SUFFIX_MAPS was undefined.
1362 * Without one of them, lynx would always need to have a mapping specified
1363 * in a lynx.cfg or mime.types file to be usable for local HTML files at
1364 * all. That includes many of the generated user interface pages. - kw
1365 */
1366 SET_SUFFIX1(".htm", STR_HTML, "8bit");
1367 SET_SUFFIX1(".html", STR_HTML, "8bit");
1368 #endif /* BUILTIN_SUFFIX_MAPS */
1369
1370 if (LYisAbsPath(global_extension_map)) {
1371 /* These should override the default extensions as necessary. */
1372 HTLoadExtensionsConfigFile(global_extension_map);
1373 }
1374
1375 /*
1376 * Load the local maps.
1377 */
1378 if (IsOurFile(LYAbsOrHomePath(&personal_extension_map))
1379 && LYCanReadFile(personal_extension_map)) {
1380 /* These should override everything else. */
1381 HTLoadExtensionsConfigFile(personal_extension_map);
1382 }
1383 }
1384
1385 /* -------------------- Extension config file reading --------------------- */
1386
1387 /*
1388 * The following is lifted from NCSA httpd 1.0a1, by Rob McCool;
1389 * NCSA httpd is in the public domain, as is this code.
1390 *
1391 * Modified Oct 97 - KW
1392 */
1393
1394 #define MAX_STRING_LEN 256
1395
HTGetLine(char * s,int n,FILE * f)1396 static int HTGetLine(char *s, int n, FILE *f)
1397 {
1398 register int i = 0, r;
1399
1400 if (!f)
1401 return (1);
1402
1403 while (1) {
1404 r = fgetc(f);
1405 s[i] = (char) r;
1406
1407 if (s[i] == CR) {
1408 r = fgetc(f);
1409 if (r == LF)
1410 s[i] = (char) r;
1411 else if (r != EOF)
1412 ungetc(r, f);
1413 }
1414
1415 if ((r == EOF) || (s[i] == LF) || (s[i] == CR) || (i == (n - 1))) {
1416 s[i] = '\0';
1417 return (feof(f) ? 1 : 0);
1418 }
1419 ++i;
1420 }
1421 }
1422
HTGetWord(char * word,char * line,int stop,int stop2)1423 static void HTGetWord(char *word, char *line, int stop, int stop2)
1424 {
1425 int x = 0, y;
1426
1427 for (x = 0; (line[x]
1428 && UCH(line[x]) != UCH(stop)
1429 && UCH(line[x]) != UCH(stop2)); x++) {
1430 word[x] = line[x];
1431 }
1432
1433 word[x] = '\0';
1434 if (line[x])
1435 ++x;
1436 y = 0;
1437
1438 while ((line[y++] = line[x++])) {
1439 ;
1440 }
1441
1442 return;
1443 }
1444
HTLoadExtensionsConfigFile(char * fn)1445 static int HTLoadExtensionsConfigFile(char *fn)
1446 {
1447 char line[MAX_STRING_LEN];
1448 char word[MAX_STRING_LEN];
1449 char *ct;
1450 FILE *f;
1451 int count = 0;
1452
1453 CTrace((tfp, "HTLoadExtensionsConfigFile: Loading file '%s'.\n", fn));
1454
1455 if ((f = fopen(fn, TXT_R)) == NULL) {
1456 CTrace((tfp, "HTLoadExtensionsConfigFile: Could not open '%s'.\n", fn));
1457 return count;
1458 }
1459
1460 while (!(HTGetLine(line, (int) sizeof(line), f))) {
1461 HTGetWord(word, line, ' ', '\t');
1462 if (line[0] == '\0' || word[0] == '#')
1463 continue;
1464 ct = NULL;
1465 StrAllocCopy(ct, word);
1466 LYLowerCase(ct);
1467
1468 while (line[0]) {
1469 HTGetWord(word, line, ' ', '\t');
1470 if (word[0] && (word[0] != ' ')) {
1471 char *ext = NULL;
1472
1473 HTSprintf0(&ext, ".%s", word);
1474 LYLowerCase(ext);
1475
1476 CTrace((tfp, "setting suffix '%s' to '%s'.\n", ext, ct));
1477
1478 if (strstr(ct, "tex") != NULL ||
1479 strstr(ct, "postscript") != NULL ||
1480 strstr(ct, "sh") != NULL ||
1481 strstr(ct, "troff") != NULL ||
1482 strstr(ct, "rtf") != NULL)
1483 SET_SUFFIX1(ext, ct, "8bit");
1484 else
1485 SET_SUFFIX1(ext, ct, "binary");
1486 count++;
1487
1488 FREE(ext);
1489 }
1490 }
1491 FREE(ct);
1492 }
1493 LYCloseInput(f);
1494
1495 return count;
1496 }
1497