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