]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/type.c
37841cb95ff220ec6e9588efe2f24d4eb24c3795
[thirdparty/cups.git] / scheduler / type.c
1 /*
2 * "$Id: type.c,v 1.15 2002/05/14 01:14:30 mike Exp $"
3 *
4 * MIME typing routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2002 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 * mimeAddType() - Add a MIME type to a database.
27 * mimeAddRule() - Add a detection rule for a file type.
28 * mimeFileType() - Determine the type of a file.
29 * mimeType() - Lookup a file type.
30 * compare() - Compare two MIME super/type names.
31 * checkrules() - Check each rule in a list.
32 * patmatch() - Pattern matching...
33 */
34
35 /*
36 * Include necessary headers...
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42 #include <locale.h>
43
44 #include <cups/string.h>
45 #include "mime.h"
46 #include <cups/debug.h>
47
48
49 /*
50 * Local functions...
51 */
52
53 static int compare(mime_type_t **, mime_type_t **);
54 static int checkrules(const char *, FILE *, mime_magic_t *);
55 static int patmatch(const char *, const char *);
56
57
58 /*
59 * 'mimeAddType()' - Add a MIME type to a database.
60 */
61
62 mime_type_t * /* O - New (or existing) MIME type */
63 mimeAddType(mime_t *mime, /* I - MIME database */
64 const char *super, /* I - Super-type name */
65 const char *type) /* I - Type name */
66 {
67 mime_type_t *temp, /* New MIME type */
68 **types; /* New MIME types array */
69
70
71 /*
72 * Range check input...
73 */
74
75 if (mime == NULL || super == NULL || type == NULL)
76 return (NULL);
77
78 if (strlen(super) > (MIME_MAX_SUPER - 1) ||
79 strlen(type) > (MIME_MAX_TYPE - 1))
80 return (NULL);
81
82 /*
83 * See if the type already exists; if so, return the existing type...
84 */
85
86 if ((temp = mimeType(mime, super, type)) != NULL)
87 return (temp);
88
89 /*
90 * The type doesn't exist; add it...
91 */
92
93 if ((temp = calloc(1, sizeof(mime_type_t))) == NULL)
94 return (NULL);
95
96 if (mime->num_types == 0)
97 types = (mime_type_t **)malloc(sizeof(mime_type_t *));
98 else
99 types = (mime_type_t **)realloc(mime->types, sizeof(mime_type_t *) * (mime->num_types + 1));
100
101 if (types == NULL)
102 {
103 free(temp);
104 return (NULL);
105 }
106
107 mime->types = types;
108 types += mime->num_types;
109 mime->num_types ++;
110
111 *types = temp;
112 strncpy(temp->super, super, sizeof(temp->super) - 1);
113 if ((temp->type = strdup(type)) == NULL)
114 {
115 mime->num_types --;
116 return (NULL);
117 }
118
119 if (mime->num_types > 1)
120 qsort(mime->types, mime->num_types, sizeof(mime_type_t *),
121 (int (*)(const void *, const void *))compare);
122
123 return (temp);
124 }
125
126
127 /*
128 * 'mimeAddRule()' - Add a detection rule for a file type.
129 */
130
131 int /* O - 0 on success, -1 on failure */
132 mimeAddTypeRule(mime_type_t *mt, /* I - Type to add to */
133 const char *rule) /* I - Rule to add */
134 {
135 int num_values, /* Number of values seen */
136 op, /* Operation code */
137 logic, /* Logic for next rule */
138 invert; /* Invert following rule? */
139 char name[255], /* Name in rule string */
140 value[3][255], /* Value in rule string */
141 *ptr, /* Position in name or value */
142 quote; /* Quote character */
143 int length[3]; /* Length of each parameter */
144 mime_magic_t *temp, /* New rule */
145 *current; /* Current rule */
146
147
148 /*
149 * Range check input...
150 */
151
152 if (mt == NULL || rule == NULL)
153 return (-1);
154
155 /*
156 * Find the last rule in the top-level of the rules tree.
157 */
158
159 for (current = mt->rules; current != NULL; current = current->next)
160 if (current->next == NULL)
161 break;
162
163 /*
164 * Parse the rules string. Most rules are either a file extension or a
165 * comparison function:
166 *
167 * extension
168 * function(parameters)
169 */
170
171 logic = MIME_MAGIC_NOP;
172 invert = 0;
173
174 DEBUG_printf(("%s/%s: %s\n", mt->super, mt->type, rule));
175
176 while (*rule != '\0')
177 {
178 while (isspace(*rule))
179 rule ++;
180
181 if (*rule == '(')
182 {
183 DEBUG_puts("new parenthesis group");
184 logic = MIME_MAGIC_NOP;
185 rule ++;
186 }
187 else if (*rule == ')')
188 {
189 DEBUG_puts("close paren...");
190 if (current == NULL || current->parent == NULL)
191 return (-1);
192
193 current = current->parent;
194
195 if (current->parent == NULL)
196 logic = MIME_MAGIC_OR;
197 else
198 logic = current->parent->op;
199
200 rule ++;
201 }
202 else if (*rule == '+' && current != NULL)
203 {
204 if (logic != MIME_MAGIC_AND &&
205 current != NULL && current->prev != NULL && current->prev->prev != NULL)
206 {
207 /*
208 * OK, we have more than 1 rule in the current tree level... Make a
209 * new group tree and move the previous rule to it...
210 */
211
212 if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
213 return (-1);
214
215 temp->op = MIME_MAGIC_AND;
216 temp->child = current;
217 temp->parent = current->parent;
218 current->prev->next = temp;
219 temp->prev = current->prev;
220
221 current->prev = NULL;
222 current->parent = temp;
223
224 DEBUG_printf(("creating new AND group %p...\n", temp));
225 }
226 else
227 {
228 DEBUG_printf(("setting group %p op to AND...\n", current->parent));
229 current->parent->op = MIME_MAGIC_AND;
230 }
231
232 logic = MIME_MAGIC_AND;
233 rule ++;
234 }
235 else if (*rule == ',')
236 {
237 if (logic != MIME_MAGIC_OR && current != NULL)
238 {
239 /*
240 * OK, we have two possibilities; either this is the top-level rule or
241 * we have a bunch of AND rules at this level.
242 */
243
244 if (current->parent == NULL)
245 {
246 /*
247 * This is the top-level rule; we have to move *all* of the AND rules
248 * down a level, as AND has precedence over OR.
249 */
250
251 if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
252 return (-1);
253
254 DEBUG_printf(("creating new AND group %p inside OR group\n", temp));
255
256 while (current->prev != NULL)
257 {
258 current->parent = temp;
259 current = current->prev;
260 }
261
262 current->parent = temp;
263 temp->op = MIME_MAGIC_AND;
264 temp->child = current;
265
266 mt->rules = current = temp;
267 }
268 else
269 {
270 /*
271 * This isn't the top rule, so go up one level...
272 */
273
274 DEBUG_puts("going up one level");
275 current = current->parent;
276 }
277 }
278
279 logic = MIME_MAGIC_OR;
280 rule ++;
281 }
282 else if (*rule == '!')
283 {
284 DEBUG_puts("NOT");
285 invert = 1;
286 rule ++;
287 }
288 else if (isalnum(*rule))
289 {
290 /*
291 * Read an extension name or a function...
292 */
293
294 for (ptr = name; isalnum(*rule) && (ptr - name) < (sizeof(name) - 1);)
295 *ptr++ = *rule++;
296
297 *ptr = '\0';
298 num_values = 0;
299
300 if (*rule == '(')
301 {
302 /*
303 * Read function parameters...
304 */
305
306 rule ++;
307 for (num_values = 0;
308 num_values < (sizeof(value) / sizeof(value[0]));
309 num_values ++)
310 {
311 ptr = value[num_values];
312
313 while ((ptr - value[num_values]) < (sizeof(value[0]) - 1) &&
314 *rule != '\0' && *rule != ',' && *rule != ')')
315 {
316 if (isspace(*rule))
317 {
318 /*
319 * Ignore whitespace...
320 */
321
322 rule ++;
323 continue;
324 }
325 else if (*rule == '\"' || *rule == '\'')
326 {
327 /*
328 * Copy quoted strings literally...
329 */
330
331 quote = *rule++;
332
333 while (*rule != '\0' && *rule != quote &&
334 (ptr - value[num_values]) < (sizeof(value[0]) - 1))
335 *ptr++ = *rule++;
336
337 if (*rule == quote)
338 rule ++;
339 else
340 return (-1);
341 }
342 else if (*rule == '<')
343 {
344 rule ++;
345
346 while (*rule != '>' && *rule != '\0' &&
347 (ptr - value[num_values]) < (sizeof(value[0]) - 1))
348 {
349 if (isxdigit(rule[0]) && isxdigit(rule[1]))
350 {
351 if (isdigit(*rule))
352 *ptr = (*rule++ - '0') << 4;
353 else
354 *ptr = (tolower(*rule++) - 'a' + 10) << 4;
355
356 if (isdigit(*rule))
357 *ptr++ |= *rule++ - '0';
358 else
359 *ptr++ |= tolower(*rule++) - 'a' + 10;
360 }
361 else
362 return (-1);
363 }
364
365 if (*rule == '>')
366 rule ++;
367 else
368 return (-1);
369 }
370 else
371 *ptr++ = *rule++;
372 }
373
374 *ptr = '\0';
375 length[num_values] = ptr - value[num_values];
376
377 if (*rule != ',')
378 break;
379
380 rule ++;
381 }
382
383 if (*rule != ')')
384 return (-1);
385
386 rule ++;
387
388 /*
389 * Figure out the function...
390 */
391
392 if (strcmp(name, "match") == 0)
393 op = MIME_MAGIC_MATCH;
394 else if (strcmp(name, "ascii") == 0)
395 op = MIME_MAGIC_ASCII;
396 else if (strcmp(name, "printable") == 0)
397 op = MIME_MAGIC_PRINTABLE;
398 else if (strcmp(name, "string") == 0)
399 op = MIME_MAGIC_STRING;
400 else if (strcmp(name, "char") == 0)
401 op = MIME_MAGIC_CHAR;
402 else if (strcmp(name, "short") == 0)
403 op = MIME_MAGIC_SHORT;
404 else if (strcmp(name, "int") == 0)
405 op = MIME_MAGIC_INT;
406 else if (strcmp(name, "locale") == 0)
407 op = MIME_MAGIC_LOCALE;
408 else if (strcmp(name, "contains") == 0)
409 op = MIME_MAGIC_CONTAINS;
410 else
411 return (-1);
412 }
413 else
414 {
415 /*
416 * This is just a filename match on the extension...
417 */
418
419 snprintf(value[0], sizeof(value[0]), "*.%s", name);
420 length[0] = strlen(value[0]);
421 num_values = 1;
422 op = MIME_MAGIC_MATCH;
423 }
424
425 /*
426 * Add a rule for this operation.
427 */
428
429 if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
430 return (-1);
431
432 temp->invert = invert;
433 if (current != NULL)
434 {
435 temp->parent = current->parent;
436 current->next = temp;
437 }
438 else
439 mt->rules = temp;
440
441 temp->prev = current;
442
443 if (logic == MIME_MAGIC_NOP)
444 {
445 /*
446 * Add parenthetical grouping...
447 */
448
449 DEBUG_printf(("making new OR group %p for parenthesis...\n", temp));
450
451 temp->op = MIME_MAGIC_OR;
452
453 if ((temp->child = calloc(1, sizeof(mime_magic_t))) == NULL)
454 return (-1);
455
456 temp->child->parent = temp;
457
458 temp = temp->child;
459 logic = MIME_MAGIC_OR;
460 }
461
462 DEBUG_printf(("adding %p: %s, op = %d, logic = %d, invert = %d\n",
463 temp, name, op, logic, invert));
464
465 /*
466 * Fill in data for the rule...
467 */
468
469 current = temp;
470 temp->op = op;
471 invert = 0;
472
473 switch (op)
474 {
475 case MIME_MAGIC_MATCH :
476 if (length[0] > (sizeof(temp->value.matchv) - 1))
477 return (-1);
478 strcpy(temp->value.matchv, value[0]);
479 break;
480 case MIME_MAGIC_ASCII :
481 case MIME_MAGIC_PRINTABLE :
482 temp->offset = strtol(value[0], NULL, 0);
483 temp->length = strtol(value[1], NULL, 0);
484 if (temp->length > MIME_MAX_BUFFER)
485 temp->length = MIME_MAX_BUFFER;
486 break;
487 case MIME_MAGIC_STRING :
488 temp->offset = strtol(value[0], NULL, 0);
489 if (length[1] > sizeof(temp->value.stringv))
490 return (-1);
491 temp->length = length[1];
492 memcpy(temp->value.stringv, value[1], length[1]);
493 break;
494 case MIME_MAGIC_CHAR :
495 temp->offset = strtol(value[0], NULL, 0);
496 if (length[1] == 1)
497 temp->value.charv = value[1][0];
498 else
499 temp->value.charv = strtol(value[1], NULL, 0);
500 break;
501 case MIME_MAGIC_SHORT :
502 temp->offset = strtol(value[0], NULL, 0);
503 temp->value.shortv = strtol(value[1], NULL, 0);
504 break;
505 case MIME_MAGIC_INT :
506 temp->offset = strtol(value[0], NULL, 0);
507 temp->value.intv = strtol(value[1], NULL, 0);
508 break;
509 case MIME_MAGIC_LOCALE :
510 if (length[0] > (sizeof(temp->value.localev) - 1))
511 return (-1);
512
513 strcpy(temp->value.localev, value[0]);
514 break;
515 case MIME_MAGIC_CONTAINS :
516 temp->offset = strtol(value[0], NULL, 0);
517 temp->region = strtol(value[1], NULL, 0);
518 if (length[2] > sizeof(temp->value.stringv))
519 return (-1);
520 temp->length = length[2];
521 memcpy(temp->value.stringv, value[2], length[2]);
522 break;
523 }
524 }
525 else
526 break;
527 }
528
529 return (0);
530 }
531
532
533 /*
534 * 'mimeFileType()' - Determine the type of a file.
535 */
536
537 mime_type_t * /* O - Type of file */
538 mimeFileType(mime_t *mime, /* I - MIME database */
539 const char *pathname) /* I - Name of file to check */
540 {
541 int i; /* Looping var */
542 FILE *fp; /* File pointer */
543 mime_type_t **types; /* File types */
544 const char *filename; /* Base filename of file */
545
546
547 /*
548 * Range check input parameters...
549 */
550
551 if (mime == NULL || pathname == NULL)
552 return (NULL);
553
554 /*
555 * Try to open the file...
556 */
557
558 if ((fp = fopen(pathname, "r")) == NULL)
559 return (NULL);
560
561 /*
562 * Figure out the filename (without directory portion)...
563 */
564
565 if ((filename = strrchr(pathname, '/')) != NULL)
566 filename ++;
567 else
568 filename = pathname;
569
570 /*
571 * Then check it against all known types...
572 */
573
574 for (i = mime->num_types, types = mime->types; i > 0; i --, types ++)
575 if (checkrules(filename, fp, (*types)->rules))
576 break;
577
578 /*
579 * Finally, close the file and return a match (if any)...
580 */
581
582 fclose(fp);
583
584 if (i > 0)
585 return (*types);
586 else
587 return (NULL);
588 }
589
590
591 /*
592 * 'mimeType()' - Lookup a file type.
593 */
594
595 mime_type_t * /* O - Matching file type definition */
596 mimeType(mime_t *mime, /* I - MIME database */
597 const char *super, /* I - Super-type name */
598 const char *type) /* I - Type name */
599 {
600 mime_type_t key, /* MIME type search key*/
601 *keyptr, /* Key pointer... */
602 **match; /* Matching pointer */
603
604 /*
605 * Range check input...
606 */
607
608 if (mime == NULL || super == NULL || type == NULL)
609 return (NULL);
610
611 if (strlen(super) > (MIME_MAX_SUPER - 1) ||
612 strlen(type) > (MIME_MAX_TYPE - 1))
613 return (NULL);
614
615 if (mime->num_types == 0)
616 return (NULL);
617
618 /*
619 * Lookup the type in the array...
620 */
621
622 strncpy(key.super, super, sizeof(key.super) - 1);
623 key.super[sizeof(key.super) - 1] = '\0';
624 key.type = (char *)type;
625
626 keyptr = &key;
627
628 match = (mime_type_t **)bsearch(&keyptr, mime->types, mime->num_types,
629 sizeof(mime_type_t *),
630 (int (*)(const void *, const void *))compare);
631
632 if (match == NULL)
633 return (NULL);
634 else
635 return (*match);
636 }
637
638
639 /*
640 * 'compare()' - Compare two MIME super/type names.
641 */
642
643 static int /* O - Result of comparison */
644 compare(mime_type_t **t0, /* I - First type */
645 mime_type_t **t1) /* I - Second type */
646 {
647 int i; /* Result of comparison */
648
649
650 if ((i = strcasecmp((*t0)->super, (*t1)->super)) == 0)
651 i = strcasecmp((*t0)->type, (*t1)->type);
652
653 return (i);
654 }
655
656
657 /*
658 * 'checkrules()' - Check each rule in a list.
659 */
660
661 static int /* O - 1 if match, 0 if no match */
662 checkrules(const char *filename, /* I - Filename */
663 FILE *fp, /* I - File to check */
664 mime_magic_t *rules) /* I - Rules to check */
665 {
666 int n; /* Looping var */
667 int region; /* Region to look at */
668 int logic, /* Logic to apply */
669 result, /* Result of test */
670 intv; /* Integer value */
671 short shortv; /* Short value */
672 unsigned char buffer[MIME_MAX_BUFFER],/* Input buffer */
673 *bufptr; /* Current buffer position */
674 int bufoffset, /* Offset in file for buffer */
675 buflength; /* Length of data in buffer */
676
677
678 if (rules == NULL)
679 return (0);
680
681 if (rules->parent == NULL)
682 logic = MIME_MAGIC_OR;
683 else
684 logic = rules->parent->op;
685
686 bufoffset = -1;
687 buflength = 0;
688 result = 0;
689
690 while (rules != NULL)
691 {
692 /*
693 * Compute the result of this rule...
694 */
695
696 switch (rules->op)
697 {
698 case MIME_MAGIC_MATCH :
699 result = patmatch(filename, rules->value.matchv);
700 break;
701
702 case MIME_MAGIC_ASCII :
703 /*
704 * Load the buffer if necessary...
705 */
706
707 if (bufoffset < 0 || rules->offset < bufoffset ||
708 (rules->offset + rules->length) > (bufoffset + buflength))
709 {
710 /*
711 * Reload file buffer...
712 */
713
714 fseek(fp, rules->offset, SEEK_SET);
715 buflength = fread(buffer, 1, sizeof(buffer), fp);
716 bufoffset = rules->offset;
717 }
718
719 /*
720 * Test for ASCII printable characters plus standard control chars.
721 */
722
723 if ((rules->offset + rules->length) > (bufoffset + buflength))
724 n = bufoffset + buflength - rules->offset;
725 else
726 n = rules->length;
727
728 bufptr = buffer + rules->offset - bufoffset;
729 while (n > 0)
730 if ((*bufptr >= 32 && *bufptr <= 126) ||
731 (*bufptr >= 8 && *bufptr <= 13) ||
732 *bufptr == 26 || *bufptr == 27)
733 {
734 n --;
735 bufptr ++;
736 }
737 else
738 break;
739
740 result = (n == 0);
741 break;
742
743 case MIME_MAGIC_PRINTABLE :
744 /*
745 * Load the buffer if necessary...
746 */
747
748 if (bufoffset < 0 || rules->offset < bufoffset ||
749 (rules->offset + rules->length) > (bufoffset + buflength))
750 {
751 /*
752 * Reload file buffer...
753 */
754
755 fseek(fp, rules->offset, SEEK_SET);
756 buflength = fread(buffer, 1, sizeof(buffer), fp);
757 bufoffset = rules->offset;
758 }
759
760 /*
761 * Test for 8-bit printable characters plus standard control chars.
762 */
763
764 if ((rules->offset + rules->length) > (bufoffset + buflength))
765 n = bufoffset + buflength - rules->offset;
766 else
767 n = rules->length;
768
769 bufptr = buffer + rules->offset - bufoffset;
770
771 while (n > 0)
772 if (*bufptr >= 128 ||
773 (*bufptr >= 32 && *bufptr <= 126) ||
774 (*bufptr >= 8 && *bufptr <= 13) ||
775 *bufptr == 26 || *bufptr == 27)
776 {
777 n --;
778 bufptr ++;
779 }
780 else
781 break;
782
783 result = (n == 0);
784 break;
785
786 case MIME_MAGIC_STRING :
787 /*
788 * Load the buffer if necessary...
789 */
790
791 if (bufoffset < 0 || rules->offset < bufoffset ||
792 (rules->offset + rules->length) > (bufoffset + buflength))
793 {
794 /*
795 * Reload file buffer...
796 */
797
798 fseek(fp, rules->offset, SEEK_SET);
799 buflength = fread(buffer, 1, sizeof(buffer), fp);
800 bufoffset = rules->offset;
801 }
802
803 /*
804 * Compare the buffer against the string. If the file is too
805 * short then don't compare - it can't match...
806 */
807
808 if ((rules->offset + rules->length) > (bufoffset + buflength))
809 result = 0;
810 else
811 result = (memcmp(buffer + rules->offset - bufoffset,
812 rules->value.stringv, rules->length) == 0);
813 break;
814
815 case MIME_MAGIC_CHAR :
816 /*
817 * Load the buffer if necessary...
818 */
819
820 if (bufoffset < 0 || rules->offset < bufoffset)
821 {
822 /*
823 * Reload file buffer...
824 */
825
826 fseek(fp, rules->offset, SEEK_SET);
827 buflength = fread(buffer, 1, sizeof(buffer), fp);
828 bufoffset = rules->offset;
829 }
830
831 /*
832 * Compare the character values; if the file is too short, it
833 * can't match...
834 */
835
836 if (buflength < 1)
837 result = 0;
838 else
839 result = (buffer[rules->offset - bufoffset] == rules->value.charv);
840 break;
841
842 case MIME_MAGIC_SHORT :
843 /*
844 * Load the buffer if necessary...
845 */
846
847 if (bufoffset < 0 || rules->offset < bufoffset ||
848 (rules->offset + 2) > (bufoffset + buflength))
849 {
850 /*
851 * Reload file buffer...
852 */
853
854 fseek(fp, rules->offset, SEEK_SET);
855 buflength = fread(buffer, 1, sizeof(buffer), fp);
856 bufoffset = rules->offset;
857 }
858
859 /*
860 * Compare the short values; if the file is too short, it
861 * can't match...
862 */
863
864 if (buflength < 2)
865 result = 0;
866 else
867 {
868 bufptr = buffer + rules->offset - bufoffset;
869 shortv = (bufptr[0] << 8) | bufptr[1];
870 result = (shortv == rules->value.shortv);
871 }
872 break;
873
874 case MIME_MAGIC_INT :
875 /*
876 * Load the buffer if necessary...
877 */
878
879 if (bufoffset < 0 || rules->offset < bufoffset ||
880 (rules->offset + 4) > (bufoffset + buflength))
881 {
882 /*
883 * Reload file buffer...
884 */
885
886 fseek(fp, rules->offset, SEEK_SET);
887 buflength = fread(buffer, 1, sizeof(buffer), fp);
888 bufoffset = rules->offset;
889 }
890
891 /*
892 * Compare the int values; if the file is too short, it
893 * can't match...
894 */
895
896 if (buflength < 4)
897 result = 0;
898 else
899 {
900 bufptr = buffer + rules->offset - bufoffset;
901 intv = (((((bufptr[0] << 8) | bufptr[1]) << 8) | bufptr[2]) << 8) |
902 bufptr[3];;
903 result = (intv == rules->value.intv);
904 }
905 break;
906
907 case MIME_MAGIC_LOCALE :
908 #ifdef __APPLE__
909 result = (strcmp(rules->value.localev, setlocale(LC_ALL, NULL)) == 0);
910 #else
911 result = (strcmp(rules->value.localev, setlocale(LC_MESSAGES, NULL)) == 0);
912 #endif /* __APPLE__ */
913 break;
914
915 case MIME_MAGIC_CONTAINS :
916 /*
917 * Load the buffer if necessary...
918 */
919
920 if (bufoffset < 0 || rules->offset < bufoffset ||
921 (rules->offset + rules->region) > (bufoffset + buflength))
922 {
923 /*
924 * Reload file buffer...
925 */
926
927 fseek(fp, rules->offset, SEEK_SET);
928 buflength = fread(buffer, 1, sizeof(buffer), fp);
929 bufoffset = rules->offset;
930 }
931
932 /*
933 * Compare the buffer against the string. If the file is too
934 * short then don't compare - it can't match...
935 */
936
937 if ((rules->offset + rules->length) > (bufoffset + buflength))
938 result = 0;
939 else
940 {
941 if (buflength > rules->region)
942 region = rules->region - rules->length;
943 else
944 region = buflength - rules->length;
945
946 for (n = 0; n < region; n ++)
947 if ((result = (memcmp(buffer + rules->offset - bufoffset + n,
948 rules->value.stringv, rules->length) == 0)) != 0)
949 break;
950 }
951 break;
952
953 default :
954 if (rules->child != NULL)
955 result = checkrules(filename, fp, rules->child);
956 else
957 result = 0;
958 break;
959 }
960
961 /*
962 * If the logic is inverted, invert the result...
963 */
964
965 if (rules->invert)
966 result = !result;
967
968 /*
969 * OK, now if the current logic is OR and this result is true, the this
970 * rule set is true. If the current logic is AND and this result is false,
971 * the the rule set is false...
972 */
973
974 DEBUG_printf(("result of test %p is %d\n", rules, result));
975
976 if ((result && logic == MIME_MAGIC_OR) ||
977 (!result && logic == MIME_MAGIC_AND))
978 return (result);
979
980 /*
981 * Otherwise the jury is still out on this one, so move to the next rule.
982 */
983
984 rules = rules->next;
985 }
986
987 return (result);
988 }
989
990
991 /*
992 * 'patmatch()' - Pattern matching...
993 */
994
995 static int /* O - 1 if match, 0 if no match */
996 patmatch(const char *s, /* I - String to match against */
997 const char *pat) /* I - Pattern to match against */
998 {
999 /*
1000 * Range check the input...
1001 */
1002
1003 if (s == NULL || pat == NULL)
1004 return (0);
1005
1006 /*
1007 * Loop through the pattern and match strings, and stop if we come to a
1008 * point where the strings don't match or we find a complete match.
1009 */
1010
1011 while (*s != '\0' && *pat != '\0')
1012 {
1013 if (*pat == '*')
1014 {
1015 /*
1016 * Wildcard - 0 or more characters...
1017 */
1018
1019 pat ++;
1020 if (*pat == '\0')
1021 return (1); /* Last pattern char is *, so everything matches now... */
1022
1023 /*
1024 * Test all remaining combinations until we get to the end of the string.
1025 */
1026
1027 while (*s != '\0')
1028 {
1029 if (patmatch(s, pat))
1030 return (1);
1031
1032 s ++;
1033 }
1034 }
1035 else if (*pat == '?')
1036 {
1037 /*
1038 * Wildcard - 1 character...
1039 */
1040
1041 pat ++;
1042 s ++;
1043 continue;
1044 }
1045 else if (*pat == '[')
1046 {
1047 /*
1048 * Match a character from the input set [chars]...
1049 */
1050
1051 pat ++;
1052 while (*pat != ']' && *pat != '\0')
1053 if (*s == *pat)
1054 break;
1055 else
1056 pat ++;
1057
1058 if (*pat == ']' || *pat == '\0')
1059 return (0);
1060
1061 while (*pat != ']' && *pat != '\0')
1062 pat ++;
1063
1064 if (*pat == ']')
1065 pat ++;
1066
1067 continue;
1068 }
1069 else if (*pat == '\\')
1070 {
1071 /*
1072 * Handle quoted characters...
1073 */
1074
1075 pat ++;
1076 }
1077
1078 /*
1079 * Stop if the pattern and string don't match...
1080 */
1081
1082 if (*pat++ != *s++)
1083 return (0);
1084 }
1085
1086 /*
1087 * Done parsing the pattern and string; return 1 if the last character matches
1088 * and 0 otherwise...
1089 */
1090
1091 return (*s == *pat);
1092 }
1093
1094
1095 /*
1096 * End of "$Id: type.c,v 1.15 2002/05/14 01:14:30 mike Exp $".
1097 */