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