]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/type.c
Added job-sheets-xyz attribute support.
[thirdparty/cups.git] / scheduler / type.c
CommitLineData
79df52e3 1/*
d21a7597 2 * "$Id: type.c,v 1.2 2000/03/21 04:03:36 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
68edc300 44#include <cups/string.h>
3b960317 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;
d21a7597 650 buflength = 0;
0b74af7d 651
652 while (rules != NULL)
653 {
654 /*
655 * Compute the result of this rule...
656 */
657
658 switch (rules->op)
659 {
660 case MIME_MAGIC_MATCH :
661 result = patmatch(filename, rules->value.matchv);
662 break;
663
664 case MIME_MAGIC_ASCII :
665 /*
666 * Load the buffer if necessary...
667 */
668
669 if (bufoffset < 0 || rules->offset < bufoffset ||
670 (rules->offset + rules->length) > (bufoffset + buflength))
671 {
672 /*
673 * Reload file buffer...
674 */
675
676 fseek(fp, rules->offset, SEEK_SET);
677 buflength = fread(buffer, 1, sizeof(buffer), fp);
678 bufoffset = rules->offset;
e8fda7b9 679 }
0b74af7d 680
681 /*
682 * Test for ASCII printable characters plus standard control chars.
683 */
684
685 if ((rules->offset + rules->length) > (bufoffset + buflength))
686 n = bufoffset + buflength - rules->offset;
687 else
688 n = rules->length;
689
690 bufptr = buffer + rules->offset - bufoffset;
691 while (n > 0)
692 if ((*bufptr >= 32 && *bufptr <= 126) ||
45011ac7 693 (*bufptr >= 8 && *bufptr <= 13) ||
694 *bufptr == 26 || *bufptr == 27)
0b74af7d 695 {
696 n --;
697 bufptr ++;
698 }
699 else
700 break;
701
702 result = (n == 0);
703 break;
704
705 case MIME_MAGIC_PRINTABLE :
706 /*
707 * Load the buffer if necessary...
708 */
709
710 if (bufoffset < 0 || rules->offset < bufoffset ||
711 (rules->offset + rules->length) > (bufoffset + buflength))
712 {
713 /*
714 * Reload file buffer...
715 */
716
717 fseek(fp, rules->offset, SEEK_SET);
718 buflength = fread(buffer, 1, sizeof(buffer), fp);
719 bufoffset = rules->offset;
e8fda7b9 720 }
0b74af7d 721
722 /*
723 * Test for ASCII printable characters plus standard control chars.
724 */
725
726 if ((rules->offset + rules->length) > (bufoffset + buflength))
727 n = bufoffset + buflength - rules->offset;
728 else
729 n = rules->length;
730
5081f753 731 bufptr = buffer + rules->offset - bufoffset;
0b74af7d 732
733 while (n > 0)
734 if ((*bufptr >= 160 && *bufptr <= 254) ||
735 (*bufptr >= 32 && *bufptr <= 126) ||
45011ac7 736 (*bufptr >= 8 && *bufptr <= 13) ||
737 *bufptr == 26 || *bufptr == 27)
0b74af7d 738 {
0b74af7d 739 n --;
740 bufptr ++;
741 }
742 else
743 break;
744
5081f753 745 result = (n == 0);
0b74af7d 746 break;
747
748 case MIME_MAGIC_STRING :
749 /*
750 * Load the buffer if necessary...
751 */
752
753 if (bufoffset < 0 || rules->offset < bufoffset ||
754 (rules->offset + rules->length) > (bufoffset + buflength))
755 {
756 /*
757 * Reload file buffer...
758 */
759
760 fseek(fp, rules->offset, SEEK_SET);
761 buflength = fread(buffer, 1, sizeof(buffer), fp);
762 bufoffset = rules->offset;
e8fda7b9 763 }
0b74af7d 764
765 /*
766 * Compare the buffer against the string. If the file is too
767 * short then don't compare - it can't match...
768 */
769
770 if ((rules->offset + rules->length) > (bufoffset + buflength))
771 result = 0;
772 else
773 result = (memcmp(buffer + rules->offset - bufoffset,
774 rules->value.stringv, rules->length) == 0);
775 break;
776
777 case MIME_MAGIC_CHAR :
778 /*
779 * Load the buffer if necessary...
780 */
781
782 if (bufoffset < 0 || rules->offset < bufoffset)
783 {
784 /*
785 * Reload file buffer...
786 */
787
788 fseek(fp, rules->offset, SEEK_SET);
789 buflength = fread(buffer, 1, sizeof(buffer), fp);
790 bufoffset = rules->offset;
e8fda7b9 791 }
0b74af7d 792
793 /*
794 * Compare the character values; if the file is too short, it
795 * can't match...
796 */
797
798 if (buflength < 1)
799 result = 0;
800 else
801 result = (buffer[rules->offset - bufoffset] == rules->value.charv);
802 break;
803
804 case MIME_MAGIC_SHORT :
805 /*
806 * Load the buffer if necessary...
807 */
808
809 if (bufoffset < 0 || rules->offset < bufoffset ||
810 (rules->offset + 2) > (bufoffset + buflength))
811 {
812 /*
813 * Reload file buffer...
814 */
815
816 fseek(fp, rules->offset, SEEK_SET);
817 buflength = fread(buffer, 1, sizeof(buffer), fp);
818 bufoffset = rules->offset;
e8fda7b9 819 }
0b74af7d 820
821 /*
822 * Compare the short values; if the file is too short, it
823 * can't match...
824 */
825
826 if (buflength < 2)
827 result = 0;
828 else
829 {
830 bufptr = buffer + rules->offset - bufoffset;
831 shortv = (bufptr[0] << 8) | bufptr[1];
832 result = (shortv == rules->value.shortv);
e8fda7b9 833 }
0b74af7d 834 break;
835
836 case MIME_MAGIC_INT :
837 /*
838 * Load the buffer if necessary...
839 */
840
841 if (bufoffset < 0 || rules->offset < bufoffset ||
842 (rules->offset + 4) > (bufoffset + buflength))
843 {
844 /*
845 * Reload file buffer...
846 */
847
848 fseek(fp, rules->offset, SEEK_SET);
849 buflength = fread(buffer, 1, sizeof(buffer), fp);
850 bufoffset = rules->offset;
e8fda7b9 851 }
0b74af7d 852
853 /*
854 * Compare the int values; if the file is too short, it
855 * can't match...
856 */
857
858 if (buflength < 4)
859 result = 0;
860 else
861 {
862 bufptr = buffer + rules->offset - bufoffset;
863 intv = (((((bufptr[0] << 8) | bufptr[1]) << 8) | bufptr[2]) << 8) |
864 bufptr[3];;
865 result = (intv == rules->value.intv);
e8fda7b9 866 }
0b74af7d 867 break;
868
869 case MIME_MAGIC_LOCALE :
870 result = (strcmp(rules->value.localev, setlocale(LC_ALL, NULL)) == 0);
871 break;
872
873 default :
874 if (rules->child != NULL)
875 result = checkrules(filename, fp, rules->child);
876 else
877 result = 0;
878 break;
e8fda7b9 879 }
0b74af7d 880
881 /*
882 * If the logic is inverted, invert the result...
883 */
884
885 if (rules->invert)
886 result = !result;
887
888 /*
889 * OK, now if the current logic is OR and this result is true, the this
890 * rule set is true. If the current logic is AND and this result is false,
891 * the the rule set is false...
892 */
893
894 if ((result && logic == MIME_MAGIC_OR) ||
895 (!result && logic == MIME_MAGIC_AND))
896 return (result);
897
898 /*
899 * Otherwise the jury is still out on this one, so move to the next rule.
900 */
901
902 rules = rules->next;
e8fda7b9 903 }
0b74af7d 904
905 return (result);
906}
907
908
909/*
910 * 'patmatch()' - Pattern matching...
911 */
912
063e1ac7 913static int /* O - 1 if match, 0 if no match */
914patmatch(const char *s, /* I - String to match against */
915 const char *pat) /* I - Pattern to match against */
0b74af7d 916{
917 /*
918 * Range check the input...
919 */
920
921 if (s == NULL || pat == NULL)
922 return (0);
923
924 /*
925 * Loop through the pattern and match strings, and stop if we come to a
926 * point where the strings don't match or we find a complete match.
927 */
928
929 while (*s != '\0' && *pat != '\0')
930 {
931 if (*pat == '*')
932 {
933 /*
934 * Wildcard - 0 or more characters...
935 */
936
937 pat ++;
938 if (*pat == '\0')
939 return (1); /* Last pattern char is *, so everything matches now... */
940
941 /*
942 * Test all remaining combinations until we get to the end of the string.
943 */
944
945 while (*s != '\0')
946 {
947 if (patmatch(s, pat))
948 return (1);
949
950 s ++;
e8fda7b9 951 }
0b74af7d 952 }
953 else if (*pat == '?')
954 {
955 /*
956 * Wildcard - 1 character...
957 */
958
959 pat ++;
960 s ++;
961 continue;
962 }
963 else if (*pat == '[')
964 {
965 /*
966 * Match a character from the input set [chars]...
967 */
968
969 pat ++;
970 while (*pat != ']' && *pat != '\0')
971 if (*s == *pat)
972 break;
973 else
974 pat ++;
975
976 if (*pat == ']' || *pat == '\0')
977 return (0);
978
979 while (*pat != ']' && *pat != '\0')
980 pat ++;
981
982 if (*pat == ']')
983 pat ++;
984
985 continue;
986 }
987 else if (*pat == '\\')
988 {
989 /*
990 * Handle quoted characters...
991 */
992
993 pat ++;
e8fda7b9 994 }
0b74af7d 995
996 /*
997 * Stop if the pattern and string don't match...
998 */
999
1000 if (*pat++ != *s++)
1001 return (0);
e8fda7b9 1002 }
0b74af7d 1003
1004 /*
1005 * Done parsing the pattern and string; return 1 if the last character matches
1006 * and 0 otherwise...
1007 */
1008
1009 return (*s == *pat);
1010}
79df52e3 1011
1012
1013/*
d21a7597 1014 * End of "$Id: type.c,v 1.2 2000/03/21 04:03:36 mike Exp $".
79df52e3 1015 */