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