1/* 2 * "$Id: testmime.c 11560 2014-02-06 20:10:19Z msweet $" 3 * 4 * MIME test program for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2006 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 */ 15 16/* 17 * Include necessary headers... 18 */ 19 20#include <cups/string-private.h> 21#include <cups/dir.h> 22#include <cups/debug-private.h> 23#include <cups/ppd-private.h> 24#include "mime.h" 25 26 27/* 28 * Local functions... 29 */ 30 31static void add_ppd_filter(mime_t *mime, mime_type_t *filtertype, 32 const char *filter); 33static void add_ppd_filters(mime_t *mime, ppd_file_t *ppd); 34static void print_rules(mime_magic_t *rules); 35static void type_dir(mime_t *mime, const char *dirname); 36 37 38/* 39 * 'main()' - Main entry for the test program. 40 */ 41 42int /* O - Exit status */ 43main(int argc, /* I - Number of command-line args */ 44 char *argv[]) /* I - Command-line arguments */ 45{ 46 int i; /* Looping vars */ 47 const char *filter_path; /* Filter path */ 48 char super[MIME_MAX_SUPER], /* Super-type name */ 49 type[MIME_MAX_TYPE]; /* Type name */ 50 int compression; /* Compression of file */ 51 int cost; /* Cost of filters */ 52 mime_t *mime; /* MIME database */ 53 mime_type_t *src, /* Source type */ 54 *dst; /* Destination type */ 55 struct stat srcinfo; /* Source information */ 56 ppd_file_t *ppd; /* PPD file */ 57 cups_array_t *filters; /* Filters for the file */ 58 mime_filter_t *filter; /* Current filter */ 59 60 61 mime = NULL; 62 src = NULL; 63 dst = NULL; 64 ppd = NULL; 65 filter_path = "../filter:" CUPS_SERVERBIN "/filter"; 66 67 srcinfo.st_size = 0; 68 69 for (i = 1; i < argc; i ++) 70 if (!strcmp(argv[i], "-d")) 71 { 72 i ++; 73 74 if (i < argc) 75 { 76 mime = mimeLoad(argv[i], filter_path); 77 78 if (ppd) 79 add_ppd_filters(mime, ppd); 80 } 81 } 82 else if (!strcmp(argv[i], "-f")) 83 { 84 i ++; 85 86 if (i < argc) 87 filter_path = argv[i]; 88 } 89 else if (!strcmp(argv[i], "-p")) 90 { 91 i ++; 92 93 if (i < argc) 94 { 95 ppd = ppdOpenFile(argv[i]); 96 97 if (mime) 98 add_ppd_filters(mime, ppd); 99 } 100 } 101 else if (!src) 102 { 103 if (!mime) 104 mime = mimeLoad("../conf", filter_path); 105 106 if (ppd) 107 add_ppd_filters(mime, ppd); 108 109 src = mimeFileType(mime, argv[i], NULL, &compression); 110 stat(argv[i], &srcinfo); 111 112 if (src) 113 printf("%s: %s/%s%s\n", argv[i], src->super, src->type, 114 compression ? " (gzipped)" : ""); 115 else if ((src = mimeType(mime, "application", "octet-stream")) != NULL) 116 printf("%s: application/octet-stream\n", argv[i]); 117 else 118 { 119 printf("%s: unknown\n", argv[i]); 120 if (mime) 121 mimeDelete(mime); 122 return (1); 123 } 124 } 125 else 126 { 127 sscanf(argv[i], "%15[^/]/%255s", super, type); 128 dst = mimeType(mime, super, type); 129 130 filters = mimeFilter2(mime, src, (size_t)srcinfo.st_size, dst, &cost); 131 132 if (!filters) 133 { 134 printf("No filters to convert from %s/%s to %s.\n", src->super, 135 src->type, argv[i]); 136 } 137 else 138 { 139 int first = 1; /* First filter shown? */ 140 141 printf("Filter cost = %d\n", cost); 142 143 for (filter = (mime_filter_t *)cupsArrayFirst(filters); 144 filter; 145 filter = (mime_filter_t *)cupsArrayNext(filters)) 146 { 147 if (!strcmp(filter->filter, "-")) 148 continue; 149 150 if (first) 151 { 152 first = 0; 153 fputs(filter->filter, stdout); 154 } 155 else 156 printf(" | %s", filter->filter); 157 } 158 159 putchar('\n'); 160 161 cupsArrayDelete(filters); 162 } 163 } 164 165 if (!mime) 166 { 167 mime = mimeLoad("../conf", filter_path); 168 if (ppd) 169 add_ppd_filters(mime, ppd); 170 } 171 172 if (!src) 173 { 174 puts("MIME database types:"); 175 for (src = mimeFirstType(mime); src; src = mimeNextType(mime)) 176 { 177 printf("\t%s/%s (%d):\n", src->super, src->type, src->priority); 178 print_rules(src->rules); 179 puts(""); 180 } 181 182 puts(""); 183 184 puts("MIME database filters:"); 185 for (filter = mimeFirstFilter(mime); filter; filter = mimeNextFilter(mime)) 186 printf("\t%s/%s to %s/%s: %s (%d)\n", 187 filter->src->super, filter->src->type, 188 filter->dst->super, filter->dst->type, 189 filter->filter, filter->cost); 190 191 type_dir(mime, "../doc"); 192 } 193 194 return (0); 195} 196 197 198/* 199 * 'add_printer_filter()' - Add a printer filter from a PPD. 200 */ 201 202static void 203add_ppd_filter(mime_t *mime, /* I - MIME database */ 204 mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ 205 const char *filter) /* I - Filter to add */ 206{ 207 char super[MIME_MAX_SUPER], /* Super-type for filter */ 208 type[MIME_MAX_TYPE], /* Type for filter */ 209 dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */ 210 dtype[MIME_MAX_TYPE], /* Destination type for filter */ 211 dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2], 212 /* Destination super/type */ 213 program[1024]; /* Program/filter name */ 214 int cost; /* Cost of filter */ 215 size_t maxsize = 0; /* Maximum supported file size */ 216 mime_type_t *temptype, /* MIME type looping var */ 217 *desttype; /* Destination MIME type */ 218 mime_filter_t *filterptr; /* MIME filter */ 219 220 221 DEBUG_printf(("add_ppd_filter(mime=%p, filtertype=%p(%s/%s), filter=\"%s\")", 222 mime, filtertype, filtertype->super, filtertype->type, filter)); 223 224 /* 225 * Parse the filter string; it should be in one of the following formats: 226 * 227 * source/type cost program 228 * source/type cost maxsize(nnnn) program 229 * source/type dest/type cost program 230 * source/type dest/type cost maxsize(nnnn) program 231 */ 232 233 if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", 234 super, type, dsuper, dtype, &cost, program) == 6) 235 { 236 snprintf(dest, sizeof(dest), "test/%s/%s", dsuper, dtype); 237 238 if ((desttype = mimeType(mime, "printer", dest)) == NULL) 239 desttype = mimeAddType(mime, "printer", dest); 240 } 241 else 242 { 243 if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, 244 program) == 4) 245 { 246 desttype = filtertype; 247 } 248 else 249 { 250 printf("testmime: Invalid filter string \"%s\".\n", filter); 251 return; 252 } 253 } 254 255 if (!strncmp(program, "maxsize(", 8)) 256 { 257 char *ptr; /* Pointer into maxsize(nnnn) program */ 258 259 maxsize = (size_t)strtoll(program + 8, &ptr, 10); 260 261 if (*ptr != ')') 262 { 263 printf("testmime: Invalid filter string \"%s\".\n", filter); 264 return; 265 } 266 267 ptr ++; 268 while (_cups_isspace(*ptr)) 269 ptr ++; 270 271 _cups_strcpy(program, ptr); 272 } 273 274 /* 275 * Add the filter to the MIME database, supporting wildcards as needed... 276 */ 277 278 for (temptype = mimeFirstType(mime); 279 temptype; 280 temptype = mimeNextType(mime)) 281 if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || 282 !_cups_strcasecmp(temptype->super, super)) && 283 (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) 284 { 285 if (desttype != filtertype) 286 { 287 DEBUG_printf(("add_ppd_filter: Adding filter %s/%s %s/%s %d %s", 288 temptype->super, temptype->type, desttype->super, 289 desttype->type, cost, program)); 290 filterptr = mimeAddFilter(mime, temptype, desttype, cost, program); 291 292 if (!mimeFilterLookup(mime, desttype, filtertype)) 293 { 294 DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s 0 -", 295 desttype->super, desttype->type, filtertype->super, 296 filtertype->type)); 297 mimeAddFilter(mime, desttype, filtertype, 0, "-"); 298 } 299 } 300 else 301 { 302 DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s %d %s", 303 temptype->super, temptype->type, filtertype->super, 304 filtertype->type, cost, program)); 305 filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program); 306 } 307 308 if (filterptr) 309 filterptr->maxsize = maxsize; 310 } 311} 312 313 314/* 315 * 'add_ppd_filters()' - Add all filters from a PPD. 316 */ 317 318static void 319add_ppd_filters(mime_t *mime, /* I - MIME database */ 320 ppd_file_t *ppd) /* I - PPD file */ 321{ 322 _ppd_cache_t *pc; /* Cache data for PPD */ 323 const char *value; /* Filter definition value */ 324 mime_type_t *filter, /* Filter type */ 325 *prefilter; /* Pre-filter type */ 326 327 328 pc = _ppdCacheCreateWithPPD(ppd); 329 if (!pc) 330 return; 331 332 filter = mimeAddType(mime, "printer", "test"); 333 334 if (pc->filters) 335 { 336 for (value = (const char *)cupsArrayFirst(pc->filters); 337 value; 338 value = (const char *)cupsArrayNext(pc->filters)) 339 add_ppd_filter(mime, filter, value); 340 } 341 else 342 { 343 add_ppd_filter(mime, filter, "application/vnd.cups-raw 0 -"); 344 add_ppd_filter(mime, filter, "application/vnd.cups-postscript 0 -"); 345 } 346 347 if (pc->prefilters) 348 { 349 prefilter = mimeAddType(mime, "prefilter", "test"); 350 351 for (value = (const char *)cupsArrayFirst(pc->prefilters); 352 value; 353 value = (const char *)cupsArrayNext(pc->prefilters)) 354 add_ppd_filter(mime, prefilter, value); 355 } 356} 357 358 359/* 360 * 'print_rules()' - Print the rules for a file type... 361 */ 362 363static void 364print_rules(mime_magic_t *rules) /* I - Rules to print */ 365{ 366 int i; /* Looping var */ 367 static char indent[255] = "\t"; /* Indentation for rules */ 368 369 370 if (rules == NULL) 371 return; 372 373 while (rules != NULL) 374 { 375 printf("%s[%p] ", indent, rules); 376 377 if (rules->invert) 378 printf("NOT "); 379 380 switch (rules->op) 381 { 382 case MIME_MAGIC_MATCH : 383 printf("match(%s)", rules->value.matchv); 384 break; 385 case MIME_MAGIC_LOCALE : 386 printf("locale(%s)", rules->value.localev); 387 break; 388 case MIME_MAGIC_ASCII : 389 printf("ascii(%d,%d)", rules->offset, rules->length); 390 break; 391 case MIME_MAGIC_PRINTABLE : 392 printf("printable(%d,%d)", rules->offset, rules->length); 393 break; 394 case MIME_MAGIC_STRING : 395 printf("string(%d,", rules->offset); 396 for (i = 0; i < rules->length; i ++) 397 if (rules->value.stringv[i] < ' ' || 398 rules->value.stringv[i] > 126) 399 printf("<%02X>", rules->value.stringv[i]); 400 else 401 putchar(rules->value.stringv[i]); 402 putchar(')'); 403 break; 404 case MIME_MAGIC_CHAR : 405 printf("char(%d,%d)", rules->offset, rules->value.charv); 406 break; 407 case MIME_MAGIC_SHORT : 408 printf("short(%d,%d)", rules->offset, rules->value.shortv); 409 break; 410 case MIME_MAGIC_INT : 411 printf("int(%d,%d)", rules->offset, rules->value.intv); 412 break; 413 case MIME_MAGIC_CONTAINS : 414 printf("contains(%d,%d,", rules->offset, rules->region); 415 for (i = 0; i < rules->length; i ++) 416 if (rules->value.stringv[i] < ' ' || 417 rules->value.stringv[i] > 126) 418 printf("<%02X>", rules->value.stringv[i]); 419 else 420 putchar(rules->value.stringv[i]); 421 putchar(')'); 422 break; 423 default : 424 break; 425 } 426 427 if (rules->child != NULL) 428 { 429 if (rules->op == MIME_MAGIC_OR) 430 puts("OR ("); 431 else 432 puts("AND ("); 433 434 strcat(indent, "\t"); 435 print_rules(rules->child); 436 indent[strlen(indent) - 1] = '\0'; 437 printf("%s)\n", indent); 438 } 439 else 440 putchar('\n'); 441 442 rules = rules->next; 443 } 444} 445 446 447/* 448 * 'type_dir()' - Show the MIME types for a given directory. 449 */ 450 451static void 452type_dir(mime_t *mime, /* I - MIME database */ 453 const char *dirname) /* I - Directory */ 454{ 455 cups_dir_t *dir; /* Directory */ 456 cups_dentry_t *dent; /* Directory entry */ 457 char filename[1024]; /* File to type */ 458 mime_type_t *filetype; /* File type */ 459 int compression; /* Compressed file? */ 460 mime_type_t *pstype; /* application/vnd.cups-postscript */ 461 cups_array_t *filters; /* Filters to pstype */ 462 mime_filter_t *filter; /* Current filter */ 463 int cost; /* Filter cost */ 464 465 466 dir = cupsDirOpen(dirname); 467 if (!dir) 468 return; 469 470 pstype = mimeType(mime, "application", "vnd.cups-postscript"); 471 472 while ((dent = cupsDirRead(dir)) != NULL) 473 { 474 if (dent->filename[0] == '.') 475 continue; 476 477 snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->filename); 478 479 if (S_ISDIR(dent->fileinfo.st_mode)) 480 type_dir(mime, filename); 481 482 if (!S_ISREG(dent->fileinfo.st_mode)) 483 continue; 484 485 filetype = mimeFileType(mime, filename, NULL, &compression); 486 487 if (filetype) 488 { 489 printf("%s: %s/%s%s\n", filename, filetype->super, filetype->type, 490 compression ? " (compressed)" : ""); 491 492 filters = mimeFilter(mime, filetype, pstype, &cost); 493 494 if (!filters) 495 puts(" No filters to convert application/vnd.cups-postscript."); 496 else 497 { 498 printf(" Filter cost = %d\n", cost); 499 500 filter = (mime_filter_t *)cupsArrayFirst(filters); 501 printf(" %s", filter->filter); 502 503 for (filter = (mime_filter_t *)cupsArrayNext(filters); 504 filter; 505 filter = (mime_filter_t *)cupsArrayNext(filters)) 506 printf(" | %s", filter->filter); 507 508 putchar('\n'); 509 510 cupsArrayDelete(filters); 511 } 512 } 513 else 514 printf("%s: unknown%s\n", filename, compression ? " (compressed)" : ""); 515 } 516 517 cupsDirClose(dir); 518} 519 520 521/* 522 * End of "$Id: testmime.c 11560 2014-02-06 20:10:19Z msweet $". 523 */ 524