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