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