]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/mime.c
2e4e0b76ce851968d9247dc4a0cc1e6b2f3c39e0
[thirdparty/cups.git] / scheduler / mime.c
1 /*
2 * "$Id: mime.c,v 1.7 2001/01/22 15:04:01 mike Exp $"
3 *
4 * MIME database file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2001 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * mimeDelete() - Delete (free) a MIME database.
27 * mimeMerge() - Merge a MIME database from disk with the current one.
28 * mimeNew() - Create a new, empty MIME database.
29 * load_types() - Load a xyz.types file...
30 * delete_rules() - Free all memory for the given rule tree.
31 * load_convs() - Load a xyz.convs file...
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <ctype.h>
41
42 #include <cups/string.h>
43 #include "mime.h"
44
45 #if defined(WIN32) || defined(__EMX__)
46 # include <windows.h>
47 #elif HAVE_DIRENT_H
48 # include <dirent.h>
49 typedef struct dirent DIRENT;
50 # define NAMLEN(dirent) strlen((dirent)->d_name)
51 #else
52 # if HAVE_SYS_NDIR_H
53 # include <sys/ndir.h>
54 # endif
55 # if HAVE_SYS_DIR_H
56 # include <sys/dir.h>
57 # endif
58 # if HAVE_NDIR_H
59 # include <ndir.h>
60 # endif
61 typedef struct direct DIRENT;
62 # define NAMLEN(dirent) (dirent)->d_namlen
63 #endif
64
65
66 /*
67 * Local functions...
68 */
69
70 static void load_types(mime_t *mime, char *filename);
71 static void load_convs(mime_t *mime, char *filename);
72 static void delete_rules(mime_magic_t *rules);
73
74
75 /*
76 * 'mimeDelete()' - Delete (free) a MIME database.
77 */
78
79 void
80 mimeDelete(mime_t *mime) /* I - MIME database */
81 {
82 int i; /* Looping var */
83
84
85 if (mime == NULL)
86 return;
87
88 /*
89 * Loop through the file types and delete any rules...
90 */
91
92 for (i = 0; i < mime->num_types; i ++)
93 {
94 delete_rules(mime->types[i]->rules);
95 free(mime->types[i]);
96 }
97
98 /*
99 * Free the types and filters arrays, and then the MIME database structure.
100 */
101
102 free(mime->types);
103 free(mime->filters);
104 free(mime);
105 }
106
107
108 /*
109 * 'mimeMerge()' - Merge a MIME database from disk with the current one.
110 */
111
112 mime_t * /* O - Updated MIME database */
113 mimeMerge(mime_t *mime, /* I - MIME database to add to */
114 const char *pathname) /* I - Directory to load */
115 {
116 #if defined(WIN32) || defined(__EMX__)
117 HANDLE dir; /* Directory handle */
118 WIN32_FIND_DATA dent; /* Directory entry */
119 char filename[1024], /* Full filename of types/converts file */
120 *pathsep; /* Last character in path */
121
122
123 /*
124 * First open the directory specified by pathname... Return NULL if nothing
125 * was read or if the pathname is NULL...
126 */
127
128 if (pathname == NULL)
129 return (NULL);
130
131 strncpy(filename, pathname, sizeof(filename) - 1);
132 filename[sizeof(filename) - 1] = '\0';
133
134 pathsep = filename + strlen(filename);
135 if ((pathsep - filename + 9) > sizeof(filename))
136 return (NULL);
137
138 if (pathsep == filename ||
139 (pathsep[-1] != '/' && pathsep[-1] != '\\'))
140 {
141 strcpy(pathsep, "/");
142 pathsep ++;
143 }
144
145 strcpy(pathsep, "*.types");
146
147 if ((dir = FindFirstFile(filename, &dent)) == 0)
148 return (NULL);
149
150 /*
151 * If "mime" is NULL, make a new, blank database...
152 */
153
154 if (mime == NULL)
155 if ((mime = mimeNew()) == NULL)
156 return (NULL);
157
158 /*
159 * Read all the .types files...
160 */
161
162 do
163 {
164 /*
165 * Load a mime.types file...
166 */
167
168 if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
169 continue;
170
171 strcpy(pathsep, dent.cFileName);
172 load_types(mime, filename);
173 }
174 while (FindNextFile(dir, &dent));
175
176 FindClose(dir);
177
178 /*
179 * Read all the .convs files...
180 */
181
182 strcpy(pathsep, "*.convs");
183
184 if ((dir = FindFirstFile(filename, &dent)) == 0)
185 return (mime);
186
187 do
188 {
189 /*
190 * Load a mime.convs file...
191 */
192
193 if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
194 continue;
195
196 strcpy(pathsep, dent.cFileName);
197 load_convs(mime, filename);
198 }
199 while (FindNextFile(dir, &dent));
200
201 FindClose(dir);
202
203 return (mime);
204 #else
205 DIR *dir; /* Directory */
206 DIRENT *dent; /* Directory entry */
207 char filename[1024]; /* Full filename of types/converts file */
208
209
210 /*
211 * First open the directory specified by pathname... Return NULL if nothing
212 * was read or if the pathname is NULL...
213 */
214
215 if (pathname == NULL)
216 return (NULL);
217
218 if ((dir = opendir(pathname)) == NULL)
219 return (NULL);
220
221 /*
222 * If "mime" is NULL, make a new, blank database...
223 */
224
225 if (mime == NULL)
226 if ((mime = mimeNew()) == NULL)
227 return (NULL);
228
229 /*
230 * Read all the .types files...
231 */
232
233 while ((dent = readdir(dir)) != NULL)
234 {
235 if (NAMLEN(dent) > 6 &&
236 strcmp(dent->d_name + NAMLEN(dent) - 6, ".types") == 0)
237 {
238 /*
239 * Load a mime.types file...
240 */
241
242 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
243 load_types(mime, filename);
244 }
245 }
246
247 rewinddir(dir);
248
249 /*
250 * Read all the .convs files...
251 */
252
253 while ((dent = readdir(dir)) != NULL)
254 {
255 if (NAMLEN(dent) > 6 &&
256 strcmp(dent->d_name + NAMLEN(dent) - 6, ".convs") == 0)
257 {
258 /*
259 * Load a mime.convs file...
260 */
261
262 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
263 load_convs(mime, filename);
264 }
265 }
266
267 closedir(dir);
268
269 return (mime);
270 #endif /* WIN32 || __EMX__ */
271 }
272
273
274 /*
275 * 'mimeNew()' - Create a new, empty MIME database.
276 */
277
278 mime_t * /* O - MIME database */
279 mimeNew(void)
280 {
281 return ((mime_t *)calloc(1, sizeof(mime_t)));
282 }
283
284
285 /*
286 * 'load_types()' - Load a xyz.types file...
287 */
288
289 static void
290 load_types(mime_t *mime, /* I - MIME database */
291 char *filename) /* I - Types file to load */
292 {
293 FILE *fp; /* Types file */
294 int linelen; /* Length of line */
295 char line[65536], /* Input line from file */
296 *lineptr, /* Current position in line */
297 super[MIME_MAX_SUPER], /* Super-type name */
298 type[MIME_MAX_TYPE], /* Type name */
299 *temp; /* Temporary pointer */
300 mime_type_t *typeptr; /* New MIME type */
301
302
303 /*
304 * First try to open the file...
305 */
306
307 if ((fp = fopen(filename, "r")) == NULL)
308 return;
309
310 /*
311 * Then read each line from the file, skipping any comments in the file...
312 */
313
314 while (fgets(line, sizeof(line), fp) != NULL)
315 {
316 linelen = strlen(line);
317
318 /*
319 * While the last character in the line is a backslash, continue on to the
320 * next line (and the next, etc.)
321 */
322
323 if (line[linelen - 1] == '\n')
324 {
325 line[linelen - 1] = '\0';
326 linelen --;
327 }
328
329 while (line[linelen - 1] == '\\')
330 {
331 linelen --;
332
333 if (fgets(line + linelen, sizeof(line) - linelen, fp) == NULL)
334 line[linelen] = '\0';
335 else
336 {
337 linelen += strlen(line + linelen);
338 if (line[linelen - 1] == '\n')
339 {
340 line[linelen - 1] = '\0';
341 linelen --;
342 }
343 }
344 }
345
346 /*
347 * Skip blank lines and lines starting with a #...
348 */
349
350 if (line[0] == '\n' || line[0] == '#')
351 continue;
352
353 /*
354 * Extract the super-type and type names from the beginning of the line.
355 */
356
357 lineptr = line;
358 temp = super;
359
360 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
361 (temp - super + 1) < MIME_MAX_SUPER)
362 *temp++ = tolower(*lineptr++);
363
364 *temp = '\0';
365
366 if (*lineptr != '/')
367 continue;
368
369 lineptr ++;
370 temp = type;
371
372 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
373 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
374 *temp++ = tolower(*lineptr++);
375
376 *temp = '\0';
377
378 /*
379 * Add the type and rules to the MIME database...
380 */
381
382 typeptr = mimeAddType(mime, super, type);
383 mimeAddTypeRule(typeptr, lineptr);
384 }
385
386 fclose(fp);
387 }
388
389
390 /*
391 * 'load_convs()' - Load a xyz.convs file...
392 */
393
394 static void
395 load_convs(mime_t *mime, /* I - MIME database */
396 char *filename) /* I - Convs file to load */
397 {
398 int i; /* Looping var */
399 FILE *fp; /* Convs file */
400 char line[1024], /* Input line from file */
401 *lineptr, /* Current position in line */
402 super[MIME_MAX_SUPER], /* Super-type name */
403 type[MIME_MAX_TYPE], /* Type name */
404 *temp, /* Temporary pointer */
405 *filter; /* Filter program */
406 mime_type_t **temptype, /* MIME type looping var */
407 *dsttype; /* Destination MIME type */
408 int cost; /* Cost of filter */
409
410
411 /*
412 * First try to open the file...
413 */
414
415 if ((fp = fopen(filename, "r")) == NULL)
416 return;
417
418 /*
419 * Then read each line from the file, skipping any comments in the file...
420 */
421
422 while (fgets(line, sizeof(line), fp) != NULL)
423 {
424 /*
425 * Skip blank lines and lines starting with a #...
426 */
427
428 if (line[0] == '\n' || line[0] == '#')
429 continue;
430
431 /*
432 * Extract the destination super-type and type names from the middle of
433 * the line.
434 */
435
436 lineptr = line;
437 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
438 lineptr ++;
439
440 while (*lineptr == ' ' || *lineptr == '\t')
441 lineptr ++;
442
443 temp = super;
444
445 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
446 (temp - super + 1) < MIME_MAX_SUPER)
447 *temp++ = tolower(*lineptr++);
448
449 *temp = '\0';
450
451 if (*lineptr != '/')
452 continue;
453
454 lineptr ++;
455 temp = type;
456
457 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
458 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
459 *temp++ = tolower(*lineptr++);
460
461 *temp = '\0';
462
463 if (*lineptr == '\0' || *lineptr == '\n')
464 continue;
465
466 if ((dsttype = mimeType(mime, super, type)) == NULL)
467 continue;
468
469 /*
470 * Then get the cost and filter program...
471 */
472
473 while (*lineptr == ' ' || *lineptr == '\t')
474 lineptr ++;
475
476 if (*lineptr < '0' || *lineptr > '9')
477 continue;
478
479 cost = atoi(lineptr);
480
481 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
482 lineptr ++;
483 while (*lineptr == ' ' || *lineptr == '\t')
484 lineptr ++;
485
486 if (*lineptr == '\0' || *lineptr == '\n')
487 continue;
488
489 filter = lineptr;
490 if (filter[strlen(filter) - 1] == '\n')
491 filter[strlen(filter) - 1] = '\0';
492
493 /*
494 * Finally, get the source super-type and type names from the beginning of
495 * the line. We do it here so we can support wildcards...
496 */
497
498 lineptr = line;
499 temp = super;
500
501 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
502 (temp - super + 1) < MIME_MAX_SUPER)
503 *temp++ = tolower(*lineptr++);
504
505 *temp = '\0';
506
507 if (*lineptr != '/')
508 continue;
509
510 lineptr ++;
511 temp = type;
512
513 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
514 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
515 *temp++ = tolower(*lineptr++);
516
517 *temp = '\0';
518
519 if (strcmp(super, "*") == 0 && strcmp(type, "*") == 0)
520 {
521 /*
522 * Force * / * to be "application/octet-stream"...
523 */
524
525 strcpy(super, "application");
526 strcpy(type, "octet-stream");
527 }
528
529 /*
530 * Add the filter to the MIME database, supporting wildcards as needed...
531 */
532
533 for (temptype = mime->types, i = 0; i < mime->num_types; i ++, temptype ++)
534 if ((super[0] == '*' || strcmp((*temptype)->super, super) == 0) &&
535 (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
536 mimeAddFilter(mime, *temptype, dsttype, cost, filter);
537 }
538
539 fclose(fp);
540 }
541
542
543 /*
544 * 'delete_rules()' - Free all memory for the given rule tree.
545 */
546
547 static void
548 delete_rules(mime_magic_t *rules) /* I - Rules to free */
549 {
550 mime_magic_t *next; /* Next rule to free */
551
552
553 /*
554 * Free the rules list, descending recursively to free any child rules.
555 */
556
557 while (rules != NULL)
558 {
559 next = rules->next;
560
561 if (rules->child != NULL)
562 delete_rules(rules->child);
563
564 free(rules);
565 rules = next;
566 }
567 }
568
569
570 /*
571 * End of "$Id: mime.c,v 1.7 2001/01/22 15:04:01 mike Exp $".
572 */