]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/mime.c
Fixed all constant arrays to use "const" modifier.
[thirdparty/cups.git] / cups / mime.c
1 /*
2 * "$Id: mime.c,v 1.14 1999/07/12 16:09:38 mike Exp $"
3 *
4 * MIME database file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-1999 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 * Revision History:
34 *
35 * $Log: mime.c,v $
36 * Revision 1.14 1999/07/12 16:09:38 mike
37 * Fixed all constant arrays to use "const" modifier.
38 *
39 * Revision 1.13 1999/06/18 18:36:10 mike
40 * Fixed address to 44141 Airport View Drive...
41 *
42 * Revision 1.12 1999/04/21 21:19:33 mike
43 * Changes for HP-UX.
44 *
45 * Revision 1.11 1999/04/21 19:31:29 mike
46 * Changed the directory header stuff to use the autoconf-recommended
47 * sequence of #ifdef's.
48 *
49 * Changed the language routines to look for the LOCALEDIR environment
50 * variable, and if it is not defined to use the LOCALEDIR string defined
51 * in config.h.
52 *
53 * Revision 1.10 1999/03/01 20:51:53 mike
54 * Code cleanup - removed extraneous semi-colons...
55 *
56 * Revision 1.9 1999/02/26 22:00:51 mike
57 * Added more debug statements.
58 *
59 * Fixed bugs in cupsPrintFile() - wasn't setting the IPP_TAG_MIMETYPE
60 * value tag for the file type.
61 *
62 * Updated conversion filter code to handle wildcards for super-type.
63 *
64 * Revision 1.8 1999/02/20 16:04:38 mike
65 * Updated mime.c to scan directories under WIN32.
66 *
67 * Fixed some compiler warnings under WIN32.
68 *
69 * Updated VC++ project files.
70 *
71 * Updated mime.types and mime.convs files for actual registered
72 * MIME type names.
73 *
74 * Revision 1.7 1999/02/05 17:40:53 mike
75 * Added IPP client read/write code.
76 *
77 * Added string functions missing from some UNIXs.
78 *
79 * Added option parsing functions.
80 *
81 * Added IPP convenience functions (not implemented yet).
82 *
83 * Updated source files to use local string.h as needed (for
84 * missing string functions)
85 *
86 * Revision 1.6 1999/02/01 22:08:39 mike
87 * Restored original directory-scanning functionality of mimeLoad().
88 *
89 * Revision 1.4 1999/01/27 18:31:56 mike
90 * Updated PPD routines to handle emulations and patch files.
91 *
92 * Added DSC comments to emit output as appropriate.
93 *
94 * Revision 1.3 1999/01/24 14:18:43 mike
95 * Check-in prior to CVS use.
96 *
97 * Revision 1.2 1998/08/06 14:38:38 mike
98 * Finished coding and testing for CUPS 1.0.
99 *
100 * Revision 1.1 1998/06/11 20:50:53 mike
101 * Initial revision
102 */
103
104 /*
105 * Include necessary headers...
106 */
107
108 #include <stdio.h>
109 #include <stdlib.h>
110 #include <ctype.h>
111
112 #include "string.h"
113 #include "mime.h"
114
115 #if defined(WIN32) || defined(__EMX__)
116 # include <windows.h>
117 #elif HAVE_DIRENT_H
118 # include <dirent.h>
119 typedef struct dirent DIRENT;
120 # define NAMLEN(dirent) strlen((dirent)->d_name)
121 #else
122 # if HAVE_SYS_NDIR_H
123 # include <sys/ndir.h>
124 # endif
125 # if HAVE_SYS_DIR_H
126 # include <sys/dir.h>
127 # endif
128 # if HAVE_NDIR_H
129 # include <ndir.h>
130 # endif
131 typedef struct direct DIRENT;
132 # define NAMLEN(dirent) (dirent)->d_namlen
133 #endif
134
135
136 /*
137 * Local functions...
138 */
139
140 static void load_types(mime_t *mime, char *filename);
141 static void load_convs(mime_t *mime, char *filename);
142 static void delete_rules(mime_magic_t *rules);
143
144
145 /*
146 * 'mimeDelete()' - Delete (free) a MIME database.
147 */
148
149 void
150 mimeDelete(mime_t *mime) /* I - MIME database */
151 {
152 int i; /* Looping var */
153
154
155 if (mime == NULL)
156 return;
157
158 /*
159 * Loop through the file types and delete any rules...
160 */
161
162 for (i = 0; i < mime->num_types; i ++)
163 {
164 delete_rules(mime->types[i]->rules);
165 free(mime->types[i]);
166 }
167
168 /*
169 * Free the types and filters arrays, and then the MIME database structure.
170 */
171
172 free(mime->types);
173 free(mime->filters);
174 free(mime);
175 }
176
177
178 /*
179 * 'mimeMerge()' - Merge a MIME database from disk with the current one.
180 */
181
182 mime_t * /* O - Updated MIME database */
183 mimeMerge(mime_t *mime, /* I - MIME database to add to */
184 const char *pathname) /* I - Directory to load */
185 {
186 #if defined(WIN32) || defined(__EMX__)
187 HANDLE dir; /* Directory handle */
188 WIN32_FIND_DATA dent; /* Directory entry */
189 char filename[1024], /* Full filename of types/converts file */
190 *pathsep; /* Last character in path */
191
192
193 /*
194 * First open the directory specified by pathname... Return NULL if nothing
195 * was read or if the pathname is NULL...
196 */
197
198 if (pathname == NULL)
199 return (NULL);
200
201 strcpy(filename, pathname);
202 pathsep = filename + strlen(filename);
203 if (pathsep == filename ||
204 (pathsep[-1] != '/' && pathsep[-1] != '\\'))
205 {
206 strcpy(pathsep, "/");
207 pathsep ++;
208 }
209
210 strcpy(pathsep, "*.types");
211
212 if ((dir = FindFirstFile(filename, &dent)) == 0)
213 return (NULL);
214
215 /*
216 * If "mime" is NULL, make a new, blank database...
217 */
218
219 if (mime == NULL)
220 if ((mime = mimeNew()) == NULL)
221 return (NULL);
222
223 /*
224 * Read all the .types files...
225 */
226
227 do
228 {
229 /*
230 * Load a mime.types file...
231 */
232
233 strcpy(pathsep, dent.cFileName);
234 load_types(mime, filename);
235 }
236 while (FindNextFile(dir, &dent));
237
238 FindClose(dir);
239
240 /*
241 * Read all the .convs files...
242 */
243
244 strcpy(pathsep, "*.convs");
245
246 if ((dir = FindFirstFile(filename, &dent)) == 0)
247 return (mime);
248
249 do
250 {
251 /*
252 * Load a mime.convs file...
253 */
254
255 strcpy(pathsep, dent.cFileName);
256 load_convs(mime, filename);
257 }
258 while (FindNextFile(dir, &dent));
259
260 FindClose(dir);
261
262 return (mime);
263 #else
264 DIR *dir; /* Directory */
265 DIRENT *dent; /* Directory entry */
266 char filename[1024]; /* Full filename of types/converts file */
267
268
269 /*
270 * First open the directory specified by pathname... Return NULL if nothing
271 * was read or if the pathname is NULL...
272 */
273
274 if (pathname == NULL)
275 return (NULL);
276
277 if ((dir = opendir(pathname)) == NULL)
278 return (NULL);
279
280 /*
281 * If "mime" is NULL, make a new, blank database...
282 */
283
284 if (mime == NULL)
285 if ((mime = mimeNew()) == NULL)
286 return (NULL);
287
288 /*
289 * Read all the .types files...
290 */
291
292 while ((dent = readdir(dir)) != NULL)
293 {
294 if (NAMLEN(dent) > 6 &&
295 strcmp(dent->d_name + NAMLEN(dent) - 6, ".types") == 0)
296 {
297 /*
298 * Load a mime.types file...
299 */
300
301 sprintf(filename, "%s/%s", pathname, dent->d_name);
302 load_types(mime, filename);
303 }
304 }
305
306 rewinddir(dir);
307
308 /*
309 * Read all the .convs files...
310 */
311
312 while ((dent = readdir(dir)) != NULL)
313 {
314 if (NAMLEN(dent) > 6 &&
315 strcmp(dent->d_name + NAMLEN(dent) - 6, ".convs") == 0)
316 {
317 /*
318 * Load a mime.convs file...
319 */
320
321 sprintf(filename, "%s/%s", pathname, dent->d_name);
322 load_convs(mime, filename);
323 }
324 }
325
326 closedir(dir);
327
328 return (mime);
329 #endif /* WIN32 || __EMX__ */
330 }
331
332
333 /*
334 * 'mimeNew()' - Create a new, empty MIME database.
335 */
336
337 mime_t * /* O - MIME database */
338 mimeNew(void)
339 {
340 return ((mime_t *)calloc(1, sizeof(mime_t)));
341 }
342
343
344 /*
345 * 'load_types()' - Load a xyz.types file...
346 */
347
348 static void
349 load_types(mime_t *mime, /* I - MIME database */
350 char *filename) /* I - Types file to load */
351 {
352 FILE *fp; /* Types file */
353 int linelen; /* Length of line */
354 char line[65536], /* Input line from file */
355 *lineptr, /* Current position in line */
356 super[MIME_MAX_SUPER], /* Super-type name */
357 type[MIME_MAX_TYPE], /* Type name */
358 *temp; /* Temporary pointer */
359 mime_type_t *typeptr; /* New MIME type */
360
361
362 /*
363 * First try to open the file...
364 */
365
366 if ((fp = fopen(filename, "r")) == NULL)
367 return;
368
369 /*
370 * Then read each line from the file, skipping any comments in the file...
371 */
372
373 while (fgets(line, sizeof(line), fp) != NULL)
374 {
375 linelen = strlen(line);
376
377 /*
378 * While the last character in the line is a backslash, continue on to the
379 * next line (and the next, etc.)
380 */
381
382 if (line[linelen - 1] == '\n')
383 {
384 line[linelen - 1] = '\0';
385 linelen --;
386 }
387
388 while (line[linelen - 1] == '\\')
389 {
390 linelen --;
391
392 if (fgets(line + linelen, sizeof(line) - linelen, fp) == NULL)
393 line[linelen] = '\0';
394 else
395 {
396 linelen += strlen(line + linelen);
397 if (line[linelen - 1] == '\n')
398 {
399 line[linelen - 1] = '\0';
400 linelen --;
401 }
402 }
403 }
404
405 /*
406 * Skip blank lines and lines starting with a #...
407 */
408
409 if (line[0] == '\n' || line[0] == '#')
410 continue;
411
412 /*
413 * Extract the super-type and type names from the beginning of the line.
414 */
415
416 lineptr = line;
417 temp = super;
418
419 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
420 (temp - super + 1) < MIME_MAX_SUPER)
421 *temp++ = tolower(*lineptr++);
422
423 *temp = '\0';
424
425 if (*lineptr != '/')
426 continue;
427
428 lineptr ++;
429 temp = type;
430
431 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
432 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
433 *temp++ = tolower(*lineptr++);
434
435 *temp = '\0';
436
437 /*
438 * Add the type and rules to the MIME database...
439 */
440
441 typeptr = mimeAddType(mime, super, type);
442 mimeAddTypeRule(typeptr, lineptr);
443 }
444 }
445
446
447 /*
448 * 'load_convs()' - Load a xyz.convs file...
449 */
450
451 static void
452 load_convs(mime_t *mime, /* I - MIME database */
453 char *filename) /* I - Convs file to load */
454 {
455 int i; /* Looping var */
456 FILE *fp; /* Convs file */
457 char line[1024], /* Input line from file */
458 *lineptr, /* Current position in line */
459 super[MIME_MAX_SUPER], /* Super-type name */
460 type[MIME_MAX_TYPE], /* Type name */
461 *temp, /* Temporary pointer */
462 *filter; /* Filter program */
463 mime_type_t **temptype, /* MIME type looping var */
464 *dsttype; /* Destination MIME type */
465 int cost; /* Cost of filter */
466
467
468 /*
469 * First try to open the file...
470 */
471
472 if ((fp = fopen(filename, "r")) == NULL)
473 return;
474
475 /*
476 * Then read each line from the file, skipping any comments in the file...
477 */
478
479 while (fgets(line, sizeof(line), fp) != NULL)
480 {
481 /*
482 * Skip blank lines and lines starting with a #...
483 */
484
485 if (line[0] == '\n' || line[0] == '#')
486 continue;
487
488 /*
489 * Extract the destination super-type and type names from the middle of
490 * the line.
491 */
492
493 lineptr = line;
494 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
495 lineptr ++;
496
497 while (*lineptr == ' ' || *lineptr == '\t')
498 lineptr ++;
499
500 temp = super;
501
502 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
503 (temp - super + 1) < MIME_MAX_SUPER)
504 *temp++ = tolower(*lineptr++);
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++);
517
518 *temp = '\0';
519
520 if (*lineptr == '\0' || *lineptr == '\n')
521 continue;
522
523 if ((dsttype = mimeType(mime, super, type)) == NULL)
524 continue;
525
526 /*
527 * Then get the cost and filter program...
528 */
529
530 while (*lineptr == ' ' || *lineptr == '\t')
531 lineptr ++;
532
533 if (*lineptr < '0' || *lineptr > '9')
534 continue;
535
536 cost = atoi(lineptr);
537
538 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
539 lineptr ++;
540 while (*lineptr == ' ' || *lineptr == '\t')
541 lineptr ++;
542
543 if (*lineptr == '\0' || *lineptr == '\n')
544 continue;
545
546 filter = lineptr;
547 if (filter[strlen(filter) - 1] == '\n')
548 filter[strlen(filter) - 1] = '\0';
549
550 /*
551 * Finally, get the source super-type and type names from the beginning of
552 * the line. We do it here so we can support wildcards...
553 */
554
555 lineptr = line;
556 temp = super;
557
558 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
559 (temp - super + 1) < MIME_MAX_SUPER)
560 *temp++ = tolower(*lineptr++);
561
562 *temp = '\0';
563
564 if (*lineptr != '/')
565 continue;
566
567 lineptr ++;
568 temp = type;
569
570 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
571 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
572 *temp++ = tolower(*lineptr++);
573
574 *temp = '\0';
575
576 /*
577 * Add the filter to the MIME database, supporting wildcards as needed...
578 */
579
580 for (temptype = mime->types, i = 0; i < mime->num_types; i ++, temptype ++)
581 if ((super[0] == '*' || strcmp((*temptype)->super, super) == 0) &&
582 (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
583 mimeAddFilter(mime, *temptype, dsttype, cost, filter);
584 }
585 }
586
587
588 /*
589 * 'delete_rules()' - Free all memory for the given rule tree.
590 */
591
592 static void
593 delete_rules(mime_magic_t *rules) /* I - Rules to free */
594 {
595 mime_magic_t *next; /* Next rule to free */
596
597
598 /*
599 * Free the rules list, descending recursively to free any child rules.
600 */
601
602 while (rules != NULL)
603 {
604 next = rules->next;
605
606 if (rules->child != NULL)
607 delete_rules(rules->child);
608
609 free(rules);
610 rules = next;
611 }
612 }
613
614
615 /*
616 * End of "$Id: mime.c,v 1.14 1999/07/12 16:09:38 mike Exp $".
617 */