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