1 
2 /* Functions to translate and determine MIME types */
3 
4 extern "C" {
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <errno.h>
10 }
11 #include "hash.tmpl"
12 #include "mimetype.h"
13 
14 /* A standard set of MIME types... */
15 #ifndef MIMETYPE_FILE
16 #define MIMETYPE_FILE	"/usr/local/lib/netscape/mime.types"
17 #endif
18 static char *std_mimetypes[] = {
19 	"application/pdf                pdf",
20 	"application/postscript         eps ps       ",
21 	"application/rtf                rtf             ",
22 	"application/x-csh              csh             ",
23 	"application/x-dvi              dvi             ",
24 	"application/x-latex            latex           ",
25 	"application/x-sh               sh              ",
26 	"application/x-tcl              tcl             ",
27 	"application/x-tk               tk              ",
28 	"application/x-tex              tex             ",
29 	"application/x-texinfo          texinfo texi   ",
30 	"application/x-troff            t tr roff       ",
31 	"application/x-troff-man        man             ",
32 	"application/x-troff-me         me              ",
33 	"application/x-troff-ms         ms              ",
34 	"application/zip                zip             ",
35 	"application/x-cpio             cpio            ",
36 	"application/x-shar             shar            ",
37 	"application/x-tar              tar             ",
38 	"application/x-compressed-gzip  gz              ",
39 	"audio/basic                    au snd          ",
40 	"audio/x-aiff                   aif aiff aifc",
41 	"audio/x-wav                    wav             ",
42 	"image/gif                      gif             ",
43 	"image/jpeg                     jpeg jpg jpe",
44 	"image/tiff                     tiff tif        ",
45 	"image/x-portable-anymap        pnm             ",
46 	"image/x-portable-bitmap        pbm             ",
47 	"image/x-portable-graymap       pgm             ",
48 	"image/x-portable-pixmap        ppm             ",
49 	"image/x-rgb                    rgb",
50 	"image/x-xbitmap                xbm             ",
51 	"image/x-xpixmap                xpm             ",
52 	"image/x-xwindowdump            xwd             ",
53 	"text/html                      html htm",
54 	"text/plain                     txt",
55 	"text/richtext                  rtx             ",
56 	"video/mpeg                     mpeg mpg mpe    ",
57 	"video/quicktime                qt mov          ",
58 	"video/x-msvideo                avi             ",
59 	"video/x-sgi-movie              movie           ",
60 	NULL,
61 };
62 static char **mime_types = NULL;
63 static Hash<char *>  *mimetype_hash = NULL;
64 
65 /* Convert a line into white-space delimited tokens */
StrTOK(char * line,char ** & tokens)66 static int StrTOK(char *line, char **&tokens)
67 {
68 	char *word, *ptr;
69 	int   n, len;
70 	int   nwords;
71 
72 	/* Figure out how many words to allocate */
73 	nwords = 0;
74 	ptr = line;
75 	while ( *ptr ) {
76 		while ( *ptr && isspace(*ptr) ) ++ptr;
77 		if ( *ptr ) {
78 			++nwords;
79 			while ( *ptr && !isspace(*ptr) ) ++ptr;
80 		}
81 	}
82 
83 	/* Allocate the words */
84 	tokens = new char *[nwords+1];
85 	for ( n=0, ptr=line; *ptr; ) {
86 		while ( *ptr && isspace(*ptr) ) ++ptr;
87 		if ( *ptr ) {
88 			word = ptr;
89 			while ( *ptr && !isspace(*ptr) ) ++ptr;
90 			len = (ptr-word);
91 			tokens[n] = new char[len+1];
92 			memcpy(tokens[n], word, len);
93 			tokens[n][len] = '\0';
94 			++n;
95 		}
96 	}
97 	tokens[n] = NULL;
98 	return(nwords);
99 }
100 
101 /* Initialize mime_types */
Init_MIMEtypes(const char * mimefile)102 void Init_MIMEtypes(const char *mimefile)
103 {
104 	FILE *mimetype_fp;
105 
106 	/* Reload? */
107 	if ( mime_types != NULL )
108 		Quit_MIMEtypes();
109 
110 	if ( mimefile == NULL )
111 		mimefile = MIMETYPE_FILE;
112 
113 	mimetype_hash = new Hash<char *>(32);
114 	if ( (mimetype_fp=fopen(mimefile, "r")) ) {
115 		char   line[BUFSIZ];
116 		char **tokens;
117 		int    n, m, i, j;
118 
119 		for ( n=0; fgets(line, BUFSIZ-1, mimetype_fp); ) {
120 			if ( line[0] && (line[0] != '#') )
121 				++n;
122 		}
123 		rewind(mimetype_fp);
124 		mime_types = new char *[n+1];
125 		for ( n=0, i=0; fgets(line, BUFSIZ-1, mimetype_fp); ++i ) {
126 			if ( ! line[0] || (line[0] == '#') )
127 				continue;
128 			m = StrTOK(line, tokens);
129 			mime_types[n++] = tokens[0];
130 			for ( j=1; j<m; ++j ) {
131 				mimetype_hash->Add(tokens[j], tokens[0]);
132 				delete[] tokens[j];
133 			}
134 			delete[] tokens;
135 		}
136 		mime_types[n] = NULL;
137 	} else {
138 		char **tokens;
139 		int    n, m, i, j;
140 
141 		for ( n=0; std_mimetypes[n]; ++n );
142 		mime_types = new char *[n+1];
143 		for ( n=0, i=0; std_mimetypes[i]; ++i ) {
144 			m = StrTOK(std_mimetypes[i], tokens);
145 			mime_types[n++] = tokens[0];
146 			for ( j=1; j<m; ++j ) {
147 				mimetype_hash->Add(tokens[j], tokens[0]);
148 				delete[] tokens[j];
149 			}
150 			delete[] tokens;
151 		}
152 		mime_types[n] = NULL;
153 	}
154 }
155 /* Free mime_types memory */
Quit_MIMEtypes(void)156 void Quit_MIMEtypes(void)
157 {
158 	if ( ! mime_types )
159 		return;
160 
161 	for ( int i=0; mime_types[i]; ++i )
162 		delete[] mime_types[i];
163 	delete[] mime_types;
164 	mime_types = NULL;
165 
166 	delete mimetype_hash;
167 	mimetype_hash = NULL;
168 }
169 
170 /* Given a filename, return an appropriate MIME type */
MIME_Type(const char * filename)171 char * MIME_Type(const char *filename)
172 {
173 	const char *extension;
174 	char **type;
175 
176 	/* Grab the extension */
177 	if ( (extension=strrchr(filename, '.')) == NULL )
178 		return(NULL);
179 	++extension;
180 	if ( (type=mimetype_hash->Search(extension)) )
181 		return(*type);
182 	return(NULL);
183 }
184 
185 /* Given a filename, return an appropriate MIME encoding */
186 /*
187    Rules:
188 	7-bit non-control-char text is encoded as 7bit
189 	8-bit non-control-char text is encoded as quoted-printable
190 	data with nulls or control characters is encoded as base64
191 */
192 #define control(c)	((c < ' ') && ((c!='\t')&&(c!='\n')&&(c!='\n')))
193 #define sevenbit(c)	(!control(c) && ((c&0x80) == 0))
194 #define eightbit(c)	(!control(c))
195 
MIME_Encoding(const char * filename)196 char * MIME_Encoding(const char *filename)
197 {
198 	char *encodings[] = {
199 		"7bit", "quoted-printable", "base64", NULL
200 	};
201 	int state = SEVEN_BIT;
202 
203 	struct stat sb;
204 	FILE *input;
205 	int   len;
206 	/* This must be an UNSIGNED character buffer to evaluate properly */
207 	unsigned char  buffer[BUFSIZ];
208 
209 	if ( (stat(filename, &sb) < 0) ||
210 		(!S_ISREG(sb.st_mode) && (errno = EISDIR)) ||
211 					(input=fopen(filename, "r")) == NULL )
212 		return(NULL);
213 
214 	while ( (state != BASE64) &&
215 				((len=fread(buffer, 1, BUFSIZ, input)) > 0) ) {
216 		for ( int i=0; i<len; ++i ) {
217 			switch (state) {
218 				case SEVEN_BIT:
219 					if ( ! sevenbit(buffer[i]) ) {
220 #ifdef DEBUG
221 	if ( control(buffer[i]) )
222 		printf("7->other: Offending character is ^%c\n", buffer[i]+'@');
223 	else
224 		printf("7->other: Offending character is %c\n", buffer[i]);
225 #endif
226 						if ( eightbit(buffer[i]) )
227 							state = QUOTE_PRT;
228 						else
229 							state = BASE64;
230 					}
231 					break;
232 				case QUOTE_PRT:
233 					if ( ! eightbit(buffer[i]) ) {
234 #ifdef DEBUG
235 	printf("8->Base64: Offending character is ^%c\n", buffer[i]+'@');
236 #endif
237 						state = BASE64;
238 					}
239 					break;
240 				case BASE64:
241 					/* We're done checking! */
242 					break;
243 			}
244 		}
245 	}
246 	fclose(input);
247 	return(encodings[state]);
248 }
249