1/* 2 * "$Id: printers.c 11693 2014-03-11 01:24:45Z msweet $" 3 * 4 * Printer routines for the CUPS scheduler. 5 * 6 * Copyright 2007-2013 by Apple Inc. 7 * Copyright 1997-2007 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 "cupsd.h" 21#include <cups/dir.h> 22#ifdef HAVE_APPLICATIONSERVICES_H 23# include <ApplicationServices/ApplicationServices.h> 24#endif /* HAVE_APPLICATIONSERVICES_H */ 25#ifdef HAVE_SYS_MOUNT_H 26# include <sys/mount.h> 27#endif /* HAVE_SYS_MOUNT_H */ 28#ifdef HAVE_SYS_STATVFS_H 29# include <sys/statvfs.h> 30#elif defined(HAVE_SYS_STATFS_H) 31# include <sys/statfs.h> 32#endif /* HAVE_SYS_STATVFS_H */ 33#ifdef HAVE_SYS_VFS_H 34# include <sys/vfs.h> 35#endif /* HAVE_SYS_VFS_H */ 36#ifdef __APPLE__ 37# include <asl.h> 38#endif /* __APPLE__ */ 39 40 41/* 42 * Local functions... 43 */ 44 45static void add_printer_defaults(cupsd_printer_t *p); 46static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type, 47 const char *filter); 48static void add_printer_formats(cupsd_printer_t *p); 49static int compare_printers(void *first, void *second, void *data); 50static void delete_printer_filters(cupsd_printer_t *p); 51static void dirty_printer(cupsd_printer_t *p); 52static void load_ppd(cupsd_printer_t *p); 53static ipp_t *new_media_col(_pwg_size_t *size, const char *source, 54 const char *type); 55static void write_xml_string(cups_file_t *fp, const char *s); 56 57 58/* 59 * 'cupsdAddPrinter()' - Add a printer to the system. 60 */ 61 62cupsd_printer_t * /* O - New printer */ 63cupsdAddPrinter(const char *name) /* I - Name of printer */ 64{ 65 cupsd_printer_t *p; /* New printer */ 66 char uri[1024], /* Printer URI */ 67 uuid[64]; /* Printer UUID */ 68 69 70 /* 71 * Range check input... 72 */ 73 74 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name); 75 76 /* 77 * Create a new printer entity... 78 */ 79 80 if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL) 81 { 82 cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s", 83 strerror(errno)); 84 return (NULL); 85 } 86 87 cupsdSetString(&p->name, name); 88 cupsdSetString(&p->info, name); 89 cupsdSetString(&p->hostname, ServerName); 90 91 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 92 ServerName, RemotePort, "/printers/%s", name); 93 cupsdSetString(&p->uri, uri); 94 cupsdSetString(&p->uuid, _httpAssembleUUID(ServerName, RemotePort, name, 0, 95 uuid, sizeof(uuid))); 96 cupsdSetDeviceURI(p, "file:///dev/null"); 97 98 p->state = IPP_PRINTER_STOPPED; 99 p->state_time = time(NULL); 100 p->accepting = 0; 101 p->shared = DefaultShared; 102 p->filetype = mimeAddType(MimeDatabase, "printer", name); 103 104 cupsdSetString(&p->job_sheets[0], "none"); 105 cupsdSetString(&p->job_sheets[1], "none"); 106 107 cupsdSetString(&p->error_policy, ErrorPolicy); 108 cupsdSetString(&p->op_policy, DefaultPolicy); 109 110 p->op_policy_ptr = DefaultPolicyPtr; 111 112 /* 113 * Insert the printer in the printer list alphabetically... 114 */ 115 116 if (!Printers) 117 Printers = cupsArrayNew(compare_printers, NULL); 118 119 cupsdLogMessage(CUPSD_LOG_DEBUG2, 120 "cupsdAddPrinter: Adding %s to Printers", p->name); 121 cupsArrayAdd(Printers, p); 122 123 /* 124 * Return the new printer... 125 */ 126 127 return (p); 128} 129 130 131/* 132 * 'cupsdCreateCommonData()' - Create the common printer data. 133 */ 134 135void 136cupsdCreateCommonData(void) 137{ 138 int i; /* Looping var */ 139 ipp_attribute_t *attr; /* Attribute data */ 140 cups_dir_t *dir; /* Notifier directory */ 141 cups_dentry_t *dent; /* Notifier directory entry */ 142 cups_array_t *notifiers; /* Notifier array */ 143 char filename[1024], /* Filename */ 144 *notifier; /* Current notifier */ 145 cupsd_policy_t *p; /* Current policy */ 146 int k_supported; /* Maximum file size supported */ 147#ifdef HAVE_STATVFS 148 struct statvfs spoolinfo; /* FS info for spool directory */ 149 double spoolsize; /* FS size */ 150#elif defined(HAVE_STATFS) 151 struct statfs spoolinfo; /* FS info for spool directory */ 152 double spoolsize; /* FS size */ 153#endif /* HAVE_STATVFS */ 154 static const int nups[] = /* number-up-supported values */ 155 { 1, 2, 4, 6, 9, 16 }; 156 static const int orients[4] =/* orientation-requested-supported values */ 157 { 158 IPP_PORTRAIT, 159 IPP_LANDSCAPE, 160 IPP_REVERSE_LANDSCAPE, 161 IPP_REVERSE_PORTRAIT 162 }; 163 static const char * const holds[] = /* job-hold-until-supported values */ 164 { 165 "no-hold", 166 "indefinite", 167 "day-time", 168 "evening", 169 "night", 170 "second-shift", 171 "third-shift", 172 "weekend" 173 }; 174 static const char * const versions[] =/* ipp-versions-supported values */ 175 { 176 "1.0", 177 "1.1", 178 "2.0", 179 "2.1" 180 }; 181 static const int ops[] = /* operations-supported values */ 182 { 183 IPP_PRINT_JOB, 184 IPP_VALIDATE_JOB, 185 IPP_CREATE_JOB, 186 IPP_SEND_DOCUMENT, 187 IPP_CANCEL_JOB, 188 IPP_GET_JOB_ATTRIBUTES, 189 IPP_GET_JOBS, 190 IPP_GET_PRINTER_ATTRIBUTES, 191 IPP_HOLD_JOB, 192 IPP_RELEASE_JOB, 193 IPP_RESTART_JOB, 194 IPP_PAUSE_PRINTER, 195 IPP_RESUME_PRINTER, 196 IPP_PURGE_JOBS, 197 IPP_SET_PRINTER_ATTRIBUTES, 198 IPP_SET_JOB_ATTRIBUTES, 199 IPP_GET_PRINTER_SUPPORTED_VALUES, 200 IPP_CREATE_PRINTER_SUBSCRIPTION, 201 IPP_CREATE_JOB_SUBSCRIPTION, 202 IPP_GET_SUBSCRIPTION_ATTRIBUTES, 203 IPP_GET_SUBSCRIPTIONS, 204 IPP_RENEW_SUBSCRIPTION, 205 IPP_CANCEL_SUBSCRIPTION, 206 IPP_GET_NOTIFICATIONS, 207 IPP_ENABLE_PRINTER, 208 IPP_DISABLE_PRINTER, 209 IPP_HOLD_NEW_JOBS, 210 IPP_RELEASE_HELD_NEW_JOBS, 211 IPP_CANCEL_JOBS, 212 IPP_CANCEL_MY_JOBS, 213 IPP_CLOSE_JOB, 214 CUPS_GET_DEFAULT, 215 CUPS_GET_PRINTERS, 216 CUPS_ADD_PRINTER, 217 CUPS_DELETE_PRINTER, 218 CUPS_GET_CLASSES, 219 CUPS_ADD_CLASS, 220 CUPS_DELETE_CLASS, 221 CUPS_ACCEPT_JOBS, 222 CUPS_REJECT_JOBS, 223 CUPS_SET_DEFAULT, 224 CUPS_GET_DEVICES, 225 CUPS_GET_PPDS, 226 CUPS_MOVE_JOB, 227 CUPS_AUTHENTICATE_JOB, 228 CUPS_GET_PPD, 229 CUPS_GET_DOCUMENT, 230 IPP_RESTART_JOB 231 }; 232 static const char * const charsets[] =/* charset-supported values */ 233 { 234 "us-ascii", 235 "utf-8" 236 }; 237 static const char * const compressions[] = 238 { /* document-compression-supported values */ 239 "none" 240#ifdef HAVE_LIBZ 241 ,"gzip" 242#endif /* HAVE_LIBZ */ 243 }; 244 static const char * const media_col_supported[] = 245 { /* media-col-supported values */ 246 "media-bottom-margin", 247 "media-left-margin", 248 "media-right-margin", 249 "media-size", 250 "media-source", 251 "media-top-margin", 252 "media-type" 253 }; 254 static const char * const multiple_document_handling[] = 255 { /* multiple-document-handling-supported values */ 256 "separate-documents-uncollated-copies", 257 "separate-documents-collated-copies" 258 }; 259 static const char * const notify_attrs[] = 260 { /* notify-attributes-supported values */ 261 "printer-state-change-time", 262 "notify-lease-expiration-time", 263 "notify-subscriber-user-name" 264 }; 265 static const char * const notify_events[] = 266 { /* notify-events-supported values */ 267 "job-completed", 268 "job-config-changed", 269 "job-created", 270 "job-progress", 271 "job-state-changed", 272 "job-stopped", 273 "printer-added", 274 "printer-changed", 275 "printer-config-changed", 276 "printer-deleted", 277 "printer-finishings-changed", 278 "printer-media-changed", 279 "printer-modified", 280 "printer-restarted", 281 "printer-shutdown", 282 "printer-state-changed", 283 "printer-stopped", 284 "server-audit", 285 "server-restarted", 286 "server-started", 287 "server-stopped" 288 }; 289 static const char * const job_creation[] = 290 { /* job-creation-attributes-supported */ 291 "copies", 292 "finishings", 293 "ipp-attribute-fidelity", 294 "job-hold-until", 295 "job-name", 296 "job-priority", 297 "job-sheets", 298 "media", 299 "media-col", 300 "multiple-document-handling", 301 "number-up", 302 "output-bin", 303 "orientation-requested", 304 "page-ranges", 305 "print-color-mode", 306 "print-quality", 307 "printer-resolution", 308 "sides" 309 }; 310 static const char * const job_settable[] = 311 { /* job-settable-attributes-supported */ 312 "copies", 313 "finishings", 314 "job-hold-until", 315 "job-name", 316 "job-priority", 317 "media", 318 "media-col", 319 "multiple-document-handling", 320 "number-up", 321 "output-bin", 322 "orientation-requested", 323 "page-ranges", 324 "print-color-mode", 325 "print-quality", 326 "printer-resolution", 327 "sides" 328 }; 329 static const char * const pdf_versions[] = 330 { /* pdf-versions-supported */ 331 "adobe-1.2", 332 "adobe-1.3", 333 "adobe-1.4", 334 "adobe-1.5", 335 "adobe-1.6", 336 "adobe-1.7", 337 "iso-19005-1_2005", 338 "iso-32000-1_2008", 339 "pwg-5102.3" 340 }; 341 static const char * const printer_settable[] = 342 { /* printer-settable-attributes-supported */ 343 "printer-info", 344 "printer-location" 345 }; 346 static const char * const which_jobs[] = 347 { /* which-jobs-supported values */ 348 "completed", 349 "not-completed", 350 "aborted", 351 "all", 352 "canceled", 353 "pending", 354 "pending-held", 355 "processing", 356 "processing-stopped" 357 }; 358 359 360 if (CommonData) 361 ippDelete(CommonData); 362 363 CommonData = ippNew(); 364 365 /* 366 * Get the maximum spool size based on the size of the filesystem used for 367 * the RequestRoot directory. If the host OS doesn't support the statfs call 368 * or the filesystem is larger than 2TiB, always report INT_MAX. 369 */ 370 371#ifdef HAVE_STATVFS 372 if (statvfs(RequestRoot, &spoolinfo)) 373 k_supported = INT_MAX; 374 else if ((spoolsize = (double)spoolinfo.f_frsize * spoolinfo.f_blocks / 1024) > 375 INT_MAX) 376 k_supported = INT_MAX; 377 else 378 k_supported = (int)spoolsize; 379 380#elif defined(HAVE_STATFS) 381 if (statfs(RequestRoot, &spoolinfo)) 382 k_supported = INT_MAX; 383 else if ((spoolsize = (double)spoolinfo.f_bsize * spoolinfo.f_blocks / 1024) > 384 INT_MAX) 385 k_supported = INT_MAX; 386 else 387 k_supported = (int)spoolsize; 388 389#else 390 k_supported = INT_MAX; 391#endif /* HAVE_STATVFS */ 392 393 /* 394 * This list of attributes is sorted to improve performance when the 395 * client provides a requested-attributes attribute... 396 */ 397 398 /* charset-configured */ 399 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, 400 "charset-configured", NULL, "utf-8"); 401 402 /* charset-supported */ 403 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, 404 "charset-supported", sizeof(charsets) / sizeof(charsets[0]), 405 NULL, charsets); 406 407 /* compression-supported */ 408 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 409 "compression-supported", 410 sizeof(compressions) / sizeof(compressions[0]), 411 NULL, compressions); 412 413 /* copies-supported */ 414 ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies); 415 416 /* cups-version */ 417 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY, 418 "cups-version", NULL, CUPS_SVERSION + 6); 419 420 /* generated-natural-language-supported (no IPP_TAG_COPY) */ 421 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, 422 "generated-natural-language-supported", NULL, DefaultLanguage); 423 424 /* ipp-versions-supported */ 425 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 426 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), 427 NULL, versions); 428 429 /* ippget-event-life */ 430 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 431 "ippget-event-life", 15); 432 433 /* job-creation-attributes-supported */ 434 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 435 "job-creation-attributes-supported", 436 sizeof(job_creation) / sizeof(job_creation[0]), 437 NULL, job_creation); 438 439 /* job-hold-until-supported */ 440 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 441 "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]), 442 NULL, holds); 443 444 /* job-ids-supported */ 445 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "job-ids-supported", 1); 446 447 /* job-k-octets-supported */ 448 ippAddRange(CommonData, IPP_TAG_PRINTER, "job-k-octets-supported", 0, 449 k_supported); 450 451 /* job-priority-supported */ 452 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 453 "job-priority-supported", 100); 454 455 /* job-settable-attributes-supported */ 456 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 457 "job-settable-attributes-supported", 458 sizeof(job_settable) / sizeof(job_settable[0]), 459 NULL, job_settable); 460 461 /* job-sheets-supported */ 462 if (cupsArrayCount(Banners) > 0) 463 { 464 /* 465 * Setup the job-sheets-supported attribute... 466 */ 467 468 if (Classification && !ClassifyOverride) 469 attr = ippAddString(CommonData, IPP_TAG_PRINTER, 470 IPP_TAG_NAME | IPP_TAG_COPY, 471 "job-sheets-supported", NULL, Classification); 472 else 473 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, 474 IPP_TAG_NAME | IPP_TAG_COPY, 475 "job-sheets-supported", cupsArrayCount(Banners) + 1, 476 NULL, NULL); 477 478 if (attr == NULL) 479 cupsdLogMessage(CUPSD_LOG_EMERG, 480 "Unable to allocate memory for " 481 "job-sheets-supported attribute: %s!", strerror(errno)); 482 else if (!Classification || ClassifyOverride) 483 { 484 cupsd_banner_t *banner; /* Current banner */ 485 486 487 attr->values[0].string.text = _cupsStrAlloc("none"); 488 489 for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners); 490 banner; 491 i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners)) 492 attr->values[i].string.text = banner->name; 493 } 494 } 495 else 496 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, 497 "job-sheets-supported", NULL, "none"); 498 499 /* jpeg-k-octets-supported */ 500 ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-k-octets-supported", 0, 501 k_supported); 502 503 /* jpeg-x-dimension-supported */ 504 ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-x-dimension-supported", 0, 505 65535); 506 507 /* jpeg-y-dimension-supported */ 508 ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-y-dimension-supported", 1, 509 65535); 510 511 /* media-col-supported */ 512 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 513 "media-col-supported", 514 sizeof(media_col_supported) / 515 sizeof(media_col_supported[0]), NULL, 516 media_col_supported); 517 518 /* multiple-document-handling-supported */ 519 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 520 "multiple-document-handling-supported", 521 sizeof(multiple_document_handling) / 522 sizeof(multiple_document_handling[0]), NULL, 523 multiple_document_handling); 524 525 /* multiple-document-jobs-supported */ 526 ippAddBoolean(CommonData, IPP_TAG_PRINTER, 527 "multiple-document-jobs-supported", 1); 528 529 /* multiple-operation-time-out */ 530 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 531 "multiple-operation-time-out", MultipleOperationTimeout); 532 533 /* natural-language-configured (no IPP_TAG_COPY) */ 534 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, 535 "natural-language-configured", NULL, DefaultLanguage); 536 537 /* notify-attributes-supported */ 538 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 539 "notify-attributes-supported", 540 (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])), 541 NULL, notify_attrs); 542 543 /* notify-lease-duration-supported */ 544 ippAddRange(CommonData, IPP_TAG_PRINTER, 545 "notify-lease-duration-supported", 0, 546 MaxLeaseDuration ? MaxLeaseDuration : 2147483647); 547 548 /* notify-max-events-supported */ 549 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 550 "notify-max-events-supported", MaxEvents); 551 552 /* notify-events-supported */ 553 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 554 "notify-events-supported", 555 (int)(sizeof(notify_events) / sizeof(notify_events[0])), 556 NULL, notify_events); 557 558 /* notify-pull-method-supported */ 559 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 560 "notify-pull-method-supported", NULL, "ippget"); 561 562 /* notify-schemes-supported */ 563 snprintf(filename, sizeof(filename), "%s/notifier", ServerBin); 564 if ((dir = cupsDirOpen(filename)) != NULL) 565 { 566 notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL); 567 568 while ((dent = cupsDirRead(dir)) != NULL) 569 if (S_ISREG(dent->fileinfo.st_mode) && 570 (dent->fileinfo.st_mode & S_IXOTH) != 0) 571 cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename)); 572 573 if (cupsArrayCount(notifiers) > 0) 574 { 575 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 576 "notify-schemes-supported", 577 cupsArrayCount(notifiers), NULL, NULL); 578 579 for (i = 0, notifier = (char *)cupsArrayFirst(notifiers); 580 notifier; 581 i ++, notifier = (char *)cupsArrayNext(notifiers)) 582 attr->values[i].string.text = notifier; 583 } 584 585 cupsArrayDelete(notifiers); 586 cupsDirClose(dir); 587 } 588 589 /* number-up-supported */ 590 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 591 "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups); 592 593 /* operations-supported */ 594 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, 595 "operations-supported", sizeof(ops) / sizeof(ops[0]), ops); 596 597 /* orientation-requested-supported */ 598 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, 599 "orientation-requested-supported", 4, orients); 600 601 /* page-ranges-supported */ 602 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1); 603 604 /* pdf-k-octets-supported */ 605 ippAddRange(CommonData, IPP_TAG_PRINTER, "pdf-k-octets-supported", 0, 606 k_supported); 607 608 /* pdf-versions-supported */ 609 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 610 "pdf-versions-supported", 611 sizeof(pdf_versions) / sizeof(pdf_versions[0]), NULL, 612 pdf_versions); 613 614 /* pdl-override-supported */ 615 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 616 "pdl-override-supported", NULL, "attempted"); 617 618 /* printer-op-policy-supported */ 619 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, 620 "printer-op-policy-supported", cupsArrayCount(Policies), 621 NULL, NULL); 622 for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies); 623 p; 624 i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies)) 625 attr->values[i].string.text = p->name; 626 627 /* printer-settable-attributes-supported */ 628 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 629 "printer-settable-attributes-supported", 630 sizeof(printer_settable) / sizeof(printer_settable[0]), 631 NULL, printer_settable); 632 633 /* server-is-sharing-printers */ 634 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers", 635 BrowseLocalProtocols != 0 && Browsing); 636 637 /* which-jobs-supported */ 638 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY, 639 "which-jobs-supported", 640 sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs); 641} 642 643 644/* 645 * 'cupsdDeleteAllPrinters()' - Delete all printers from the system. 646 */ 647 648void 649cupsdDeleteAllPrinters(void) 650{ 651 cupsd_printer_t *p; /* Pointer to current printer/class */ 652 653 654 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); 655 p; 656 p = (cupsd_printer_t *)cupsArrayNext(Printers)) 657 { 658 p->op_policy_ptr = DefaultPolicyPtr; 659 cupsdDeletePrinter(p, 0); 660 } 661} 662 663 664/* 665 * 'cupsdDeletePrinter()' - Delete a printer from the system. 666 */ 667 668int /* O - 1 if classes affected, 0 otherwise */ 669cupsdDeletePrinter( 670 cupsd_printer_t *p, /* I - Printer to delete */ 671 int update) /* I - Update printers.conf? */ 672{ 673 int i, /* Looping var */ 674 changed = 0; /* Class changed? */ 675 676 677 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)", 678 p, p->name, update); 679 680 /* 681 * Save the current position in the Printers array... 682 */ 683 684 cupsArraySave(Printers); 685 686 /* 687 * Stop printing on this printer... 688 */ 689 690 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update); 691 692 p->state = IPP_PRINTER_STOPPED; /* Force for browsed printers */ 693 694 if (p->job) 695 cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE, 696 update ? "Job stopped due to printer being deleted." : 697 "Job stopped."); 698 699 /* 700 * Remove the printer from the list... 701 */ 702 703 cupsdLogMessage(CUPSD_LOG_DEBUG2, 704 "cupsdDeletePrinter: Removing %s from Printers", p->name); 705 cupsArrayRemove(Printers, p); 706 707 /* 708 * If p is the default printer, assign a different one... 709 */ 710 711 if (p == DefaultPrinter) 712 DefaultPrinter = NULL; 713 714 /* 715 * Remove this printer from any classes... 716 */ 717 718 changed = cupsdDeletePrinterFromClasses(p); 719 720 /* 721 * Deregister from any browse protocols... 722 */ 723 724 cupsdDeregisterPrinter(p, 1); 725 726 /* 727 * Free all memory used by the printer... 728 */ 729 730 if (p->printers != NULL) 731 free(p->printers); 732 733 delete_printer_filters(p); 734 735 for (i = 0; i < p->num_reasons; i ++) 736 _cupsStrFree(p->reasons[i]); 737 738 ippDelete(p->attrs); 739 ippDelete(p->ppd_attrs); 740 741 mimeDeleteType(MimeDatabase, p->filetype); 742 mimeDeleteType(MimeDatabase, p->prefiltertype); 743 744 cupsdFreeStrings(&(p->users)); 745 cupsdFreeQuotas(p); 746 747 cupsdClearString(&p->uri); 748 cupsdClearString(&p->hostname); 749 cupsdClearString(&p->name); 750 cupsdClearString(&p->location); 751 cupsdClearString(&p->make_model); 752 cupsdClearString(&p->info); 753 cupsdClearString(&p->job_sheets[0]); 754 cupsdClearString(&p->job_sheets[1]); 755 cupsdClearString(&p->device_uri); 756 cupsdClearString(&p->sanitized_device_uri); 757 cupsdClearString(&p->port_monitor); 758 cupsdClearString(&p->op_policy); 759 cupsdClearString(&p->error_policy); 760 761 cupsdClearString(&p->alert); 762 cupsdClearString(&p->alert_description); 763 764#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) 765 cupsdClearString(&p->pdl); 766 cupsdClearString(&p->reg_name); 767#endif /* HAVE_DNSSD || HAVE_AVAHI */ 768 769 cupsArrayDelete(p->filetypes); 770 771 cupsFreeOptions(p->num_options, p->options); 772 773 free(p); 774 775 /* 776 * Restore the previous position in the Printers array... 777 */ 778 779 cupsArrayRestore(Printers); 780 781 return (changed); 782} 783 784 785/* 786 * 'cupsdFindDest()' - Find a destination in the list. 787 */ 788 789cupsd_printer_t * /* O - Destination in list */ 790cupsdFindDest(const char *name) /* I - Name of printer or class to find */ 791{ 792 cupsd_printer_t key; /* Search key */ 793 794 795 key.name = (char *)name; 796 return ((cupsd_printer_t *)cupsArrayFind(Printers, &key)); 797} 798 799 800/* 801 * 'cupsdFindPrinter()' - Find a printer in the list. 802 */ 803 804cupsd_printer_t * /* O - Printer in list */ 805cupsdFindPrinter(const char *name) /* I - Name of printer to find */ 806{ 807 cupsd_printer_t *p; /* Printer in list */ 808 809 810 if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS)) 811 return (NULL); 812 else 813 return (p); 814} 815 816 817/* 818 * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file. 819 */ 820 821void 822cupsdLoadAllPrinters(void) 823{ 824 int i; /* Looping var */ 825 cups_file_t *fp; /* printers.conf file */ 826 int linenum; /* Current line number */ 827 char line[4096], /* Line from file */ 828 *value, /* Pointer to value */ 829 *valueptr; /* Pointer into value */ 830 cupsd_printer_t *p; /* Current printer */ 831 832 833 /* 834 * Open the printers.conf file... 835 */ 836 837 snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot); 838 if ((fp = cupsdOpenConfFile(line)) == NULL) 839 return; 840 841 /* 842 * Read printer configurations until we hit EOF... 843 */ 844 845 linenum = 0; 846 p = NULL; 847 848 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) 849 { 850 /* 851 * Decode the directive... 852 */ 853 854 if (!_cups_strcasecmp(line, "<Printer") || 855 !_cups_strcasecmp(line, "<DefaultPrinter")) 856 { 857 /* 858 * <Printer name> or <DefaultPrinter name> 859 */ 860 861 if (p == NULL && value) 862 { 863 /* 864 * Add the printer and a base file type... 865 */ 866 867 cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading printer %s...", value); 868 869 p = cupsdAddPrinter(value); 870 p->accepting = 1; 871 p->state = IPP_PRINTER_IDLE; 872 873 /* 874 * Set the default printer as needed... 875 */ 876 877 if (!_cups_strcasecmp(line, "<DefaultPrinter")) 878 DefaultPrinter = p; 879 } 880 else 881 cupsdLogMessage(CUPSD_LOG_ERROR, 882 "Syntax error on line %d of printers.conf.", linenum); 883 } 884 else if (!_cups_strcasecmp(line, "</Printer>")) 885 { 886 if (p != NULL) 887 { 888 /* 889 * Close out the current printer... 890 */ 891 892 cupsdSetPrinterAttrs(p); 893 894 if (strncmp(p->device_uri, "file:", 5) && 895 p->state != IPP_PRINTER_STOPPED) 896 { 897 /* 898 * See if the backend exists... 899 */ 900 901 snprintf(line, sizeof(line), "%s/backend/%s", ServerBin, 902 p->device_uri); 903 904 if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL) 905 *valueptr = '\0'; /* Chop everything but URI scheme */ 906 907 if (access(line, 0)) 908 { 909 /* 910 * Backend does not exist, stop printer... 911 */ 912 913 p->state = IPP_PRINTER_STOPPED; 914 snprintf(p->state_message, sizeof(p->state_message), 915 "Backend %s does not exist!", line); 916 } 917 } 918 919 p = NULL; 920 } 921 else 922 cupsdLogMessage(CUPSD_LOG_ERROR, 923 "Syntax error on line %d of printers.conf.", linenum); 924 } 925 else if (!p) 926 { 927 cupsdLogMessage(CUPSD_LOG_ERROR, 928 "Syntax error on line %d of printers.conf.", linenum); 929 } 930 else if (!_cups_strcasecmp(line, "UUID")) 931 { 932 if (value && !strncmp(value, "urn:uuid:", 9)) 933 cupsdSetString(&(p->uuid), value); 934 else 935 cupsdLogMessage(CUPSD_LOG_ERROR, 936 "Bad UUID on line %d of printers.conf.", linenum); 937 } 938 else if (!_cups_strcasecmp(line, "AuthInfoRequired")) 939 { 940 if (!cupsdSetAuthInfoRequired(p, value, NULL)) 941 cupsdLogMessage(CUPSD_LOG_ERROR, 942 "Bad AuthInfoRequired on line %d of printers.conf.", 943 linenum); 944 } 945 else if (!_cups_strcasecmp(line, "Info")) 946 { 947 if (value) 948 cupsdSetString(&p->info, value); 949 } 950 else if (!_cups_strcasecmp(line, "MakeModel")) 951 { 952 if (value) 953 cupsdSetString(&p->make_model, value); 954 } 955 else if (!_cups_strcasecmp(line, "Location")) 956 { 957 if (value) 958 cupsdSetString(&p->location, value); 959 } 960 else if (!_cups_strcasecmp(line, "DeviceURI")) 961 { 962 if (value) 963 cupsdSetDeviceURI(p, value); 964 else 965 cupsdLogMessage(CUPSD_LOG_ERROR, 966 "Syntax error on line %d of printers.conf.", linenum); 967 } 968 else if (!_cups_strcasecmp(line, "Option") && value) 969 { 970 /* 971 * Option name value 972 */ 973 974 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); 975 976 if (!*valueptr) 977 cupsdLogMessage(CUPSD_LOG_ERROR, 978 "Syntax error on line %d of printers.conf.", linenum); 979 else 980 { 981 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0'); 982 983 p->num_options = cupsAddOption(value, valueptr, p->num_options, 984 &(p->options)); 985 } 986 } 987 else if (!_cups_strcasecmp(line, "PortMonitor")) 988 { 989 if (value && strcmp(value, "none")) 990 cupsdSetString(&p->port_monitor, value); 991 else if (value) 992 cupsdClearString(&p->port_monitor); 993 else 994 cupsdLogMessage(CUPSD_LOG_ERROR, 995 "Syntax error on line %d of printers.conf.", linenum); 996 } 997 else if (!_cups_strcasecmp(line, "Reason")) 998 { 999 if (value && 1000 strcmp(value, "connecting-to-device") && 1001 strcmp(value, "cups-insecure-filter-warning") && 1002 strcmp(value, "cups-missing-filter-warning")) 1003 { 1004 for (i = 0 ; i < p->num_reasons; i ++) 1005 if (!strcmp(value, p->reasons[i])) 1006 break; 1007 1008 if (i >= p->num_reasons && 1009 p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) 1010 { 1011 p->reasons[p->num_reasons] = _cupsStrAlloc(value); 1012 p->num_reasons ++; 1013 } 1014 } 1015 else 1016 cupsdLogMessage(CUPSD_LOG_ERROR, 1017 "Syntax error on line %d of printers.conf.", linenum); 1018 } 1019 else if (!_cups_strcasecmp(line, "State")) 1020 { 1021 /* 1022 * Set the initial queue state... 1023 */ 1024 1025 if (value && !_cups_strcasecmp(value, "idle")) 1026 p->state = IPP_PRINTER_IDLE; 1027 else if (value && !_cups_strcasecmp(value, "stopped")) 1028 { 1029 p->state = IPP_PRINTER_STOPPED; 1030 1031 for (i = 0 ; i < p->num_reasons; i ++) 1032 if (!strcmp("paused", p->reasons[i])) 1033 break; 1034 1035 if (i >= p->num_reasons && 1036 p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) 1037 { 1038 p->reasons[p->num_reasons] = _cupsStrAlloc("paused"); 1039 p->num_reasons ++; 1040 } 1041 } 1042 else 1043 cupsdLogMessage(CUPSD_LOG_ERROR, 1044 "Syntax error on line %d of printers.conf.", linenum); 1045 } 1046 else if (!_cups_strcasecmp(line, "StateMessage")) 1047 { 1048 /* 1049 * Set the initial queue state message... 1050 */ 1051 1052 if (value) 1053 strlcpy(p->state_message, value, sizeof(p->state_message)); 1054 } 1055 else if (!_cups_strcasecmp(line, "StateTime")) 1056 { 1057 /* 1058 * Set the state time... 1059 */ 1060 1061 if (value) 1062 p->state_time = atoi(value); 1063 } 1064 else if (!_cups_strcasecmp(line, "Accepting")) 1065 { 1066 /* 1067 * Set the initial accepting state... 1068 */ 1069 1070 if (value && 1071 (!_cups_strcasecmp(value, "yes") || 1072 !_cups_strcasecmp(value, "on") || 1073 !_cups_strcasecmp(value, "true"))) 1074 p->accepting = 1; 1075 else if (value && 1076 (!_cups_strcasecmp(value, "no") || 1077 !_cups_strcasecmp(value, "off") || 1078 !_cups_strcasecmp(value, "false"))) 1079 p->accepting = 0; 1080 else 1081 cupsdLogMessage(CUPSD_LOG_ERROR, 1082 "Syntax error on line %d of printers.conf.", linenum); 1083 } 1084 else if (!_cups_strcasecmp(line, "Type")) 1085 { 1086 if (value) 1087 p->type = atoi(value); 1088 else 1089 cupsdLogMessage(CUPSD_LOG_ERROR, 1090 "Syntax error on line %d of printers.conf.", linenum); 1091 } 1092 else if (!_cups_strcasecmp(line, "Shared")) 1093 { 1094 /* 1095 * Set the initial shared state... 1096 */ 1097 1098 if (value && 1099 (!_cups_strcasecmp(value, "yes") || 1100 !_cups_strcasecmp(value, "on") || 1101 !_cups_strcasecmp(value, "true"))) 1102 p->shared = 1; 1103 else if (value && 1104 (!_cups_strcasecmp(value, "no") || 1105 !_cups_strcasecmp(value, "off") || 1106 !_cups_strcasecmp(value, "false"))) 1107 p->shared = 0; 1108 else 1109 cupsdLogMessage(CUPSD_LOG_ERROR, 1110 "Syntax error on line %d of printers.conf.", linenum); 1111 } 1112 else if (!_cups_strcasecmp(line, "JobSheets")) 1113 { 1114 /* 1115 * Set the initial job sheets... 1116 */ 1117 1118 if (value) 1119 { 1120 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); 1121 1122 if (*valueptr) 1123 *valueptr++ = '\0'; 1124 1125 cupsdSetString(&p->job_sheets[0], value); 1126 1127 while (isspace(*valueptr & 255)) 1128 valueptr ++; 1129 1130 if (*valueptr) 1131 { 1132 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++); 1133 1134 if (*valueptr) 1135 *valueptr = '\0'; 1136 1137 cupsdSetString(&p->job_sheets[1], value); 1138 } 1139 } 1140 else 1141 cupsdLogMessage(CUPSD_LOG_ERROR, 1142 "Syntax error on line %d of printers.conf.", linenum); 1143 } 1144 else if (!_cups_strcasecmp(line, "AllowUser")) 1145 { 1146 if (value) 1147 { 1148 p->deny_users = 0; 1149 cupsdAddString(&(p->users), value); 1150 } 1151 else 1152 cupsdLogMessage(CUPSD_LOG_ERROR, 1153 "Syntax error on line %d of printers.conf.", linenum); 1154 } 1155 else if (!_cups_strcasecmp(line, "DenyUser")) 1156 { 1157 if (value) 1158 { 1159 p->deny_users = 1; 1160 cupsdAddString(&(p->users), value); 1161 } 1162 else 1163 cupsdLogMessage(CUPSD_LOG_ERROR, 1164 "Syntax error on line %d of printers.conf.", linenum); 1165 } 1166 else if (!_cups_strcasecmp(line, "QuotaPeriod")) 1167 { 1168 if (value) 1169 p->quota_period = atoi(value); 1170 else 1171 cupsdLogMessage(CUPSD_LOG_ERROR, 1172 "Syntax error on line %d of printers.conf.", linenum); 1173 } 1174 else if (!_cups_strcasecmp(line, "PageLimit")) 1175 { 1176 if (value) 1177 p->page_limit = atoi(value); 1178 else 1179 cupsdLogMessage(CUPSD_LOG_ERROR, 1180 "Syntax error on line %d of printers.conf.", linenum); 1181 } 1182 else if (!_cups_strcasecmp(line, "KLimit")) 1183 { 1184 if (value) 1185 p->k_limit = atoi(value); 1186 else 1187 cupsdLogMessage(CUPSD_LOG_ERROR, 1188 "Syntax error on line %d of printers.conf.", linenum); 1189 } 1190 else if (!_cups_strcasecmp(line, "OpPolicy")) 1191 { 1192 if (value) 1193 { 1194 cupsd_policy_t *pol; /* Policy */ 1195 1196 1197 if ((pol = cupsdFindPolicy(value)) != NULL) 1198 { 1199 cupsdSetString(&p->op_policy, value); 1200 p->op_policy_ptr = pol; 1201 } 1202 else 1203 cupsdLogMessage(CUPSD_LOG_ERROR, 1204 "Bad policy \"%s\" on line %d of printers.conf", 1205 value, linenum); 1206 } 1207 else 1208 cupsdLogMessage(CUPSD_LOG_ERROR, 1209 "Syntax error on line %d of printers.conf.", linenum); 1210 } 1211 else if (!_cups_strcasecmp(line, "ErrorPolicy")) 1212 { 1213 if (value) 1214 cupsdSetString(&p->error_policy, value); 1215 else 1216 cupsdLogMessage(CUPSD_LOG_ERROR, 1217 "Syntax error on line %d of printers.conf.", linenum); 1218 } 1219 else if (!_cups_strcasecmp(line, "Attribute") && value) 1220 { 1221 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); 1222 1223 if (!*valueptr) 1224 cupsdLogMessage(CUPSD_LOG_ERROR, 1225 "Syntax error on line %d of printers.conf.", linenum); 1226 else 1227 { 1228 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0'); 1229 1230 if (!p->attrs) 1231 cupsdSetPrinterAttrs(p); 1232 1233 if (!strcmp(value, "marker-change-time")) 1234 p->marker_time = atoi(valueptr); 1235 else 1236 cupsdSetPrinterAttr(p, value, valueptr); 1237 } 1238 } 1239 else if (_cups_strcasecmp(line, "Filter") && 1240 _cups_strcasecmp(line, "Prefilter") && 1241 _cups_strcasecmp(line, "Product")) 1242 { 1243 /* 1244 * Something else we don't understand (and that wasn't used in a prior 1245 * release of CUPS... 1246 */ 1247 1248 cupsdLogMessage(CUPSD_LOG_ERROR, 1249 "Unknown configuration directive %s on line %d of " 1250 "printers.conf.", line, linenum); 1251 } 1252 } 1253 1254 cupsFileClose(fp); 1255} 1256 1257 1258/* 1259 * 'cupsdRenamePrinter()' - Rename a printer. 1260 */ 1261 1262void 1263cupsdRenamePrinter( 1264 cupsd_printer_t *p, /* I - Printer */ 1265 const char *name) /* I - New name */ 1266{ 1267 /* 1268 * Remove the printer from the array(s) first... 1269 */ 1270 1271 cupsdLogMessage(CUPSD_LOG_DEBUG2, 1272 "cupsdRenamePrinter: Removing %s from Printers", p->name); 1273 cupsArrayRemove(Printers, p); 1274 1275 /* 1276 * Rename the printer type... 1277 */ 1278 1279 mimeDeleteType(MimeDatabase, p->filetype); 1280 p->filetype = mimeAddType(MimeDatabase, "printer", name); 1281 1282 if (p->prefiltertype) 1283 { 1284 mimeDeleteType(MimeDatabase, p->prefiltertype); 1285 p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name); 1286 } 1287 1288 /* 1289 * Rename the printer... 1290 */ 1291 1292 cupsdSetString(&p->name, name); 1293 1294 /* 1295 * Reset printer attributes... 1296 */ 1297 1298 cupsdSetPrinterAttrs(p); 1299 1300 /* 1301 * Add the printer back to the printer array(s)... 1302 */ 1303 1304 cupsdLogMessage(CUPSD_LOG_DEBUG2, 1305 "cupsdRenamePrinter: Adding %s to Printers", p->name); 1306 cupsArrayAdd(Printers, p); 1307} 1308 1309 1310/* 1311 * 'cupsdSaveAllPrinters()' - Save all printer definitions to the printers.conf 1312 * file. 1313 */ 1314 1315void 1316cupsdSaveAllPrinters(void) 1317{ 1318 int i; /* Looping var */ 1319 cups_file_t *fp; /* printers.conf file */ 1320 char filename[1024], /* printers.conf filename */ 1321 temp[1024], /* Temporary string */ 1322 value[2048], /* Value string */ 1323 *ptr, /* Pointer into value */ 1324 *name; /* Current user/group name */ 1325 cupsd_printer_t *printer; /* Current printer class */ 1326 time_t curtime; /* Current time */ 1327 struct tm *curdate; /* Current date */ 1328 cups_option_t *option; /* Current option */ 1329 ipp_attribute_t *marker; /* Current marker attribute */ 1330 1331 1332 /* 1333 * Create the printers.conf file... 1334 */ 1335 1336 snprintf(filename, sizeof(filename), "%s/printers.conf", ServerRoot); 1337 1338 if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL) 1339 return; 1340 1341 cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf..."); 1342 1343 /* 1344 * Write a small header to the file... 1345 */ 1346 1347 curtime = time(NULL); 1348 curdate = localtime(&curtime); 1349 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); 1350 1351 cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n"); 1352 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); 1353 cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n"); 1354 1355 /* 1356 * Write each local printer known to the system... 1357 */ 1358 1359 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers); 1360 printer; 1361 printer = (cupsd_printer_t *)cupsArrayNext(Printers)) 1362 { 1363 /* 1364 * Skip printer classes... 1365 */ 1366 1367 if (printer->type & CUPS_PRINTER_CLASS) 1368 continue; 1369 1370 /* 1371 * Write printers as needed... 1372 */ 1373 1374 if (printer == DefaultPrinter) 1375 cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name); 1376 else 1377 cupsFilePrintf(fp, "<Printer %s>\n", printer->name); 1378 1379 cupsFilePrintf(fp, "UUID %s\n", printer->uuid); 1380 1381 if (printer->num_auth_info_required > 0) 1382 { 1383 switch (printer->num_auth_info_required) 1384 { 1385 case 1 : 1386 strlcpy(value, printer->auth_info_required[0], sizeof(value)); 1387 break; 1388 1389 case 2 : 1390 snprintf(value, sizeof(value), "%s,%s", 1391 printer->auth_info_required[0], 1392 printer->auth_info_required[1]); 1393 break; 1394 1395 case 3 : 1396 default : 1397 snprintf(value, sizeof(value), "%s,%s,%s", 1398 printer->auth_info_required[0], 1399 printer->auth_info_required[1], 1400 printer->auth_info_required[2]); 1401 break; 1402 } 1403 1404 cupsFilePutConf(fp, "AuthInfoRequired", value); 1405 } 1406 1407 if (printer->info) 1408 cupsFilePutConf(fp, "Info", printer->info); 1409 1410 if (printer->location) 1411 cupsFilePutConf(fp, "Location", printer->location); 1412 1413 if (printer->make_model) 1414 cupsFilePutConf(fp, "MakeModel", printer->make_model); 1415 1416 cupsFilePutConf(fp, "DeviceURI", printer->device_uri); 1417 1418 if (printer->port_monitor) 1419 cupsFilePutConf(fp, "PortMonitor", printer->port_monitor); 1420 1421 if (printer->state == IPP_PRINTER_STOPPED) 1422 { 1423 cupsFilePuts(fp, "State Stopped\n"); 1424 1425 if (printer->state_message) 1426 cupsFilePutConf(fp, "StateMessage", printer->state_message); 1427 } 1428 else 1429 cupsFilePuts(fp, "State Idle\n"); 1430 1431 cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time); 1432 1433 for (i = 0; i < printer->num_reasons; i ++) 1434 if (strcmp(printer->reasons[i], "connecting-to-device") && 1435 strcmp(printer->reasons[i], "cups-insecure-filter-warning") && 1436 strcmp(printer->reasons[i], "cups-missing-filter-warning")) 1437 cupsFilePutConf(fp, "Reason", printer->reasons[i]); 1438 1439 cupsFilePrintf(fp, "Type %d\n", printer->type); 1440 1441 if (printer->accepting) 1442 cupsFilePuts(fp, "Accepting Yes\n"); 1443 else 1444 cupsFilePuts(fp, "Accepting No\n"); 1445 1446 if (printer->shared) 1447 cupsFilePuts(fp, "Shared Yes\n"); 1448 else 1449 cupsFilePuts(fp, "Shared No\n"); 1450 1451 snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0], 1452 printer->job_sheets[1]); 1453 cupsFilePutConf(fp, "JobSheets", value); 1454 1455 cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period); 1456 cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit); 1457 cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit); 1458 1459 for (name = (char *)cupsArrayFirst(printer->users); 1460 name; 1461 name = (char *)cupsArrayNext(printer->users)) 1462 cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name); 1463 1464 if (printer->op_policy) 1465 cupsFilePutConf(fp, "OpPolicy", printer->op_policy); 1466 if (printer->error_policy) 1467 cupsFilePutConf(fp, "ErrorPolicy", printer->error_policy); 1468 1469 for (i = printer->num_options, option = printer->options; 1470 i > 0; 1471 i --, option ++) 1472 { 1473 snprintf(value, sizeof(value), "%s %s", option->name, option->value); 1474 cupsFilePutConf(fp, "Option", value); 1475 } 1476 1477 if ((marker = ippFindAttribute(printer->attrs, "marker-colors", 1478 IPP_TAG_NAME)) != NULL) 1479 { 1480 snprintf(value, sizeof(value), "%s ", marker->name); 1481 1482 for (i = 0, ptr = value + strlen(value); 1483 i < marker->num_values && ptr < (value + sizeof(value) - 1); 1484 i ++) 1485 { 1486 if (i) 1487 *ptr++ = ','; 1488 1489 strlcpy(ptr, marker->values[i].string.text, 1490 value + sizeof(value) - ptr); 1491 ptr += strlen(ptr); 1492 } 1493 1494 *ptr = '\0'; 1495 cupsFilePutConf(fp, "Attribute", value); 1496 } 1497 1498 if ((marker = ippFindAttribute(printer->attrs, "marker-levels", 1499 IPP_TAG_INTEGER)) != NULL) 1500 { 1501 cupsFilePrintf(fp, "Attribute %s %d", marker->name, 1502 marker->values[0].integer); 1503 for (i = 1; i < marker->num_values; i ++) 1504 cupsFilePrintf(fp, ",%d", marker->values[i].integer); 1505 cupsFilePuts(fp, "\n"); 1506 } 1507 1508 if ((marker = ippFindAttribute(printer->attrs, "marker-low-levels", 1509 IPP_TAG_INTEGER)) != NULL) 1510 { 1511 cupsFilePrintf(fp, "Attribute %s %d", marker->name, 1512 marker->values[0].integer); 1513 for (i = 1; i < marker->num_values; i ++) 1514 cupsFilePrintf(fp, ",%d", marker->values[i].integer); 1515 cupsFilePuts(fp, "\n"); 1516 } 1517 1518 if ((marker = ippFindAttribute(printer->attrs, "marker-high-levels", 1519 IPP_TAG_INTEGER)) != NULL) 1520 { 1521 cupsFilePrintf(fp, "Attribute %s %d", marker->name, 1522 marker->values[0].integer); 1523 for (i = 1; i < marker->num_values; i ++) 1524 cupsFilePrintf(fp, ",%d", marker->values[i].integer); 1525 cupsFilePuts(fp, "\n"); 1526 } 1527 1528 if ((marker = ippFindAttribute(printer->attrs, "marker-message", 1529 IPP_TAG_TEXT)) != NULL) 1530 { 1531 snprintf(value, sizeof(value), "%s %s", marker->name, 1532 marker->values[0].string.text); 1533 1534 cupsFilePutConf(fp, "Attribute", value); 1535 } 1536 1537 if ((marker = ippFindAttribute(printer->attrs, "marker-names", 1538 IPP_TAG_NAME)) != NULL) 1539 { 1540 snprintf(value, sizeof(value), "%s ", marker->name); 1541 1542 for (i = 0, ptr = value + strlen(value); 1543 i < marker->num_values && ptr < (value + sizeof(value) - 1); 1544 i ++) 1545 { 1546 if (i) 1547 *ptr++ = ','; 1548 1549 strlcpy(ptr, marker->values[i].string.text, 1550 value + sizeof(value) - ptr); 1551 ptr += strlen(ptr); 1552 } 1553 1554 *ptr = '\0'; 1555 cupsFilePutConf(fp, "Attribute", value); 1556 } 1557 1558 if ((marker = ippFindAttribute(printer->attrs, "marker-types", 1559 IPP_TAG_KEYWORD)) != NULL) 1560 { 1561 snprintf(value, sizeof(value), "%s ", marker->name); 1562 1563 for (i = 0, ptr = value + strlen(value); 1564 i < marker->num_values && ptr < (value + sizeof(value) - 1); 1565 i ++) 1566 { 1567 if (i) 1568 *ptr++ = ','; 1569 1570 strlcpy(ptr, marker->values[i].string.text, 1571 value + sizeof(value) - ptr); 1572 ptr += strlen(ptr); 1573 } 1574 1575 *ptr = '\0'; 1576 cupsFilePutConf(fp, "Attribute", value); 1577 } 1578 1579 if (printer->marker_time) 1580 cupsFilePrintf(fp, "Attribute marker-change-time %ld\n", 1581 (long)printer->marker_time); 1582 1583 cupsFilePuts(fp, "</Printer>\n"); 1584 } 1585 1586 cupsdCloseCreatedConfFile(fp, filename); 1587} 1588 1589 1590/* 1591 * 'cupsdSetAuthInfoRequired()' - Set the required authentication info. 1592 */ 1593 1594int /* O - 1 if value OK, 0 otherwise */ 1595cupsdSetAuthInfoRequired( 1596 cupsd_printer_t *p, /* I - Printer */ 1597 const char *values, /* I - Plain text value (or NULL) */ 1598 ipp_attribute_t *attr) /* I - IPP attribute value (or NULL) */ 1599{ 1600 int i; /* Looping var */ 1601 1602 1603 p->num_auth_info_required = 0; 1604 1605 /* 1606 * Do we have a plain text value? 1607 */ 1608 1609 if (values) 1610 { 1611 /* 1612 * Yes, grab the keywords... 1613 */ 1614 1615 const char *end; /* End of current value */ 1616 1617 1618 while (*values && p->num_auth_info_required < 4) 1619 { 1620 if ((end = strchr(values, ',')) == NULL) 1621 end = values + strlen(values); 1622 1623 if ((end - values) == 4 && !strncmp(values, "none", 4)) 1624 { 1625 if (p->num_auth_info_required != 0 || *end) 1626 return (0); 1627 1628 p->auth_info_required[p->num_auth_info_required] = "none"; 1629 p->num_auth_info_required ++; 1630 1631 return (1); 1632 } 1633 else if ((end - values) == 9 && !strncmp(values, "negotiate", 9)) 1634 { 1635 if (p->num_auth_info_required != 0 || *end) 1636 return (0); 1637 1638 p->auth_info_required[p->num_auth_info_required] = "negotiate"; 1639 p->num_auth_info_required ++; 1640 1641 /* 1642 * Don't allow sharing of queues that require Kerberos authentication. 1643 */ 1644 1645 if (p->shared) 1646 { 1647 cupsdDeregisterPrinter(p, 1); 1648 p->shared = 0; 1649 } 1650 } 1651 else if ((end - values) == 6 && !strncmp(values, "domain", 6)) 1652 { 1653 p->auth_info_required[p->num_auth_info_required] = "domain"; 1654 p->num_auth_info_required ++; 1655 } 1656 else if ((end - values) == 8 && !strncmp(values, "password", 8)) 1657 { 1658 p->auth_info_required[p->num_auth_info_required] = "password"; 1659 p->num_auth_info_required ++; 1660 } 1661 else if ((end - values) == 8 && !strncmp(values, "username", 8)) 1662 { 1663 p->auth_info_required[p->num_auth_info_required] = "username"; 1664 p->num_auth_info_required ++; 1665 } 1666 else 1667 return (0); 1668 1669 values = (*end) ? end + 1 : end; 1670 } 1671 1672 if (p->num_auth_info_required == 0) 1673 { 1674 p->auth_info_required[0] = "none"; 1675 p->num_auth_info_required = 1; 1676 } 1677 1678 /* 1679 * Update the printer-type value as needed... 1680 */ 1681 1682 if (p->num_auth_info_required > 1 || 1683 strcmp(p->auth_info_required[0], "none")) 1684 p->type |= CUPS_PRINTER_AUTHENTICATED; 1685 else 1686 p->type &= ~CUPS_PRINTER_AUTHENTICATED; 1687 1688 return (1); 1689 } 1690 1691 /* 1692 * Grab values from an attribute instead... 1693 */ 1694 1695 if (!attr || attr->num_values > 4) 1696 return (0); 1697 1698 for (i = 0; i < attr->num_values; i ++) 1699 { 1700 if (!strcmp(attr->values[i].string.text, "none")) 1701 { 1702 if (p->num_auth_info_required != 0 || attr->num_values != 1) 1703 return (0); 1704 1705 p->auth_info_required[p->num_auth_info_required] = "none"; 1706 p->num_auth_info_required ++; 1707 1708 return (1); 1709 } 1710 else if (!strcmp(attr->values[i].string.text, "negotiate")) 1711 { 1712 if (p->num_auth_info_required != 0 || attr->num_values != 1) 1713 return (0); 1714 1715 p->auth_info_required[p->num_auth_info_required] = "negotiate"; 1716 p->num_auth_info_required ++; 1717 1718 /* 1719 * Don't allow sharing of queues that require Kerberos authentication. 1720 */ 1721 1722 if (p->shared) 1723 { 1724 cupsdDeregisterPrinter(p, 1); 1725 p->shared = 0; 1726 } 1727 1728 return (1); 1729 } 1730 else if (!strcmp(attr->values[i].string.text, "domain")) 1731 { 1732 p->auth_info_required[p->num_auth_info_required] = "domain"; 1733 p->num_auth_info_required ++; 1734 } 1735 else if (!strcmp(attr->values[i].string.text, "password")) 1736 { 1737 p->auth_info_required[p->num_auth_info_required] = "password"; 1738 p->num_auth_info_required ++; 1739 } 1740 else if (!strcmp(attr->values[i].string.text, "username")) 1741 { 1742 p->auth_info_required[p->num_auth_info_required] = "username"; 1743 p->num_auth_info_required ++; 1744 } 1745 else 1746 return (0); 1747 } 1748 1749 return (1); 1750} 1751 1752 1753/* 1754 * 'cupsdSetDeviceURI()' - Set the device URI for a printer. 1755 */ 1756 1757void 1758cupsdSetDeviceURI(cupsd_printer_t *p, /* I - Printer */ 1759 const char *uri) /* I - Device URI */ 1760{ 1761 char buffer[1024], /* URI buffer */ 1762 *start, /* Start of data after scheme */ 1763 *slash, /* First slash after scheme:// */ 1764 *ptr; /* Pointer into user@host:port part */ 1765 1766 1767 /* 1768 * Set the full device URI.. 1769 */ 1770 1771 cupsdSetString(&(p->device_uri), uri); 1772 1773 /* 1774 * Copy the device URI to a temporary buffer so we can sanitize any auth 1775 * info in it... 1776 */ 1777 1778 strlcpy(buffer, uri, sizeof(buffer)); 1779 1780 /* 1781 * Find the end of the scheme:// part... 1782 */ 1783 1784 if ((ptr = strchr(buffer, ':')) != NULL) 1785 { 1786 for (start = ptr + 1; *start; start ++) 1787 if (*start != '/') 1788 break; 1789 1790 /* 1791 * Find the next slash (/) in the URI... 1792 */ 1793 1794 if ((slash = strchr(start, '/')) == NULL) 1795 slash = start + strlen(start); /* No slash, point to the end */ 1796 1797 /* 1798 * Check for an @ sign before the slash... 1799 */ 1800 1801 if ((ptr = strchr(start, '@')) != NULL && ptr < slash) 1802 { 1803 /* 1804 * Found an @ sign and it is before the resource part, so we have 1805 * an authentication string. Copy the remaining URI over the 1806 * authentication string... 1807 */ 1808 1809 _cups_strcpy(start, ptr + 1); 1810 } 1811 } 1812 1813 /* 1814 * Save the sanitized URI... 1815 */ 1816 1817 cupsdSetString(&(p->sanitized_device_uri), buffer); 1818} 1819 1820 1821/* 1822 * 'cupsdSetPrinterAttr()' - Set a printer attribute. 1823 */ 1824 1825void 1826cupsdSetPrinterAttr( 1827 cupsd_printer_t *p, /* I - Printer */ 1828 const char *name, /* I - Attribute name */ 1829 const char *value) /* I - Attribute value string */ 1830{ 1831 ipp_attribute_t *attr; /* Attribute */ 1832 int i, /* Looping var */ 1833 count; /* Number of values */ 1834 char *temp, /* Temporary copy of value string */ 1835 *ptr, /* Pointer into value */ 1836 *start, /* Start of value */ 1837 quote; /* Quote character */ 1838 ipp_tag_t value_tag; /* Value tag for this attribute */ 1839 1840 1841 /* 1842 * Don't allow empty values... 1843 */ 1844 1845 if (!*value && strcmp(name, "marker-message")) 1846 { 1847 cupsdLogMessage(CUPSD_LOG_ERROR, "Ignoring empty \"%s\" attribute", name); 1848 return; 1849 } 1850 1851 /* 1852 * Copy the value string so we can do what we want with it... 1853 */ 1854 1855 if ((temp = strdup(value)) == NULL) 1856 { 1857 cupsdLogMessage(CUPSD_LOG_ERROR, 1858 "Unable to duplicate value for \"%s\" attribute.", name); 1859 return; 1860 } 1861 1862 /* 1863 * Count the number of values... 1864 */ 1865 1866 for (count = 1, quote = '\0', ptr = temp; 1867 *ptr; 1868 ptr ++) 1869 { 1870 if (*ptr == quote) 1871 quote = '\0'; 1872 else if (quote) 1873 continue; 1874 else if (*ptr == '\\' && ptr[1]) 1875 ptr ++; 1876 else if (*ptr == '\'' || *ptr == '\"') 1877 quote = *ptr; 1878 else if (*ptr == ',') 1879 count ++; 1880 } 1881 1882 /* 1883 * Then add or update the attribute as needed... 1884 */ 1885 1886 if (!strcmp(name, "marker-levels") || !strcmp(name, "marker-low-levels") || 1887 !strcmp(name, "marker-high-levels")) 1888 { 1889 /* 1890 * Integer values... 1891 */ 1892 1893 if ((attr = ippFindAttribute(p->attrs, name, IPP_TAG_INTEGER)) != NULL && 1894 attr->num_values < count) 1895 { 1896 ippDeleteAttribute(p->attrs, attr); 1897 attr = NULL; 1898 } 1899 1900 if (attr) 1901 attr->num_values = count; 1902 else 1903 attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, name, 1904 count, NULL); 1905 1906 if (!attr) 1907 { 1908 free(temp); 1909 cupsdLogMessage(CUPSD_LOG_ERROR, 1910 "Unable to allocate memory for printer attribute " 1911 "(%d values)", count); 1912 return; 1913 } 1914 1915 for (i = 0, start = temp; i < count; i ++) 1916 { 1917 if ((ptr = strchr(start, ',')) != NULL) 1918 *ptr++ = '\0'; 1919 1920 attr->values[i].integer = strtol(start, NULL, 10); 1921 1922 if (ptr) 1923 start = ptr; 1924 } 1925 } 1926 else 1927 { 1928 /* 1929 * Name or keyword values... 1930 */ 1931 1932 if (!strcmp(name, "marker-types")) 1933 value_tag = IPP_TAG_KEYWORD; 1934 else if (!strcmp(name, "marker-message")) 1935 value_tag = IPP_TAG_TEXT; 1936 else 1937 value_tag = IPP_TAG_NAME; 1938 1939 if ((attr = ippFindAttribute(p->attrs, name, value_tag)) != NULL && 1940 attr->num_values < count) 1941 { 1942 ippDeleteAttribute(p->attrs, attr); 1943 attr = NULL; 1944 } 1945 1946 if (attr) 1947 { 1948 for (i = 0; i < attr->num_values; i ++) 1949 _cupsStrFree(attr->values[i].string.text); 1950 1951 attr->num_values = count; 1952 } 1953 else 1954 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, value_tag, name, 1955 count, NULL, NULL); 1956 1957 if (!attr) 1958 { 1959 free(temp); 1960 cupsdLogMessage(CUPSD_LOG_ERROR, 1961 "Unable to allocate memory for printer attribute " 1962 "(%d values)", count); 1963 return; 1964 } 1965 1966 for (i = 0, quote = '\0', ptr = temp; i < count; i ++) 1967 { 1968 for (start = ptr; *ptr; ptr ++) 1969 { 1970 if (*ptr == quote) 1971 *ptr = quote = '\0'; 1972 else if (quote) 1973 continue; 1974 else if (*ptr == '\\' && ptr[1]) 1975 _cups_strcpy(ptr, ptr + 1); 1976 else if (*ptr == '\'' || *ptr == '\"') 1977 { 1978 quote = *ptr; 1979 1980 if (ptr == start) 1981 start ++; 1982 else 1983 _cups_strcpy(ptr, ptr + 1); 1984 } 1985 else if (*ptr == ',') 1986 { 1987 *ptr++ = '\0'; 1988 break; 1989 } 1990 } 1991 1992 attr->values[i].string.text = _cupsStrAlloc(start); 1993 } 1994 } 1995 1996 free(temp); 1997} 1998 1999 2000/* 2001 * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file. 2002 */ 2003 2004void 2005cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ 2006{ 2007 int i; /* Looping var */ 2008 char resource[HTTP_MAX_URI]; /* Resource portion of URI */ 2009 cupsd_location_t *auth; /* Pointer to authentication element */ 2010 const char *auth_supported; /* Authentication supported */ 2011 ipp_t *oldattrs; /* Old printer attributes */ 2012 ipp_attribute_t *attr; /* Attribute data */ 2013 char *name, /* Current user/group name */ 2014 *filter; /* Current filter */ 2015 2016 2017 DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name, 2018 p->type)); 2019 2020 /* 2021 * Make sure that we have the common attributes defined... 2022 */ 2023 2024 if (!CommonData) 2025 cupsdCreateCommonData(); 2026 2027 /* 2028 * Clear out old filters, if any... 2029 */ 2030 2031 delete_printer_filters(p); 2032 2033 /* 2034 * Figure out the authentication that is required for the printer. 2035 */ 2036 2037 auth_supported = "requesting-user-name"; 2038 2039 if (p->type & CUPS_PRINTER_CLASS) 2040 snprintf(resource, sizeof(resource), "/classes/%s", p->name); 2041 else 2042 snprintf(resource, sizeof(resource), "/printers/%s", p->name); 2043 2044 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL || 2045 auth->type == CUPSD_AUTH_NONE) 2046 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB); 2047 2048 if (auth) 2049 { 2050 int auth_type; /* Authentication type */ 2051 2052 2053 if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT) 2054 auth_type = cupsdDefaultAuthType(); 2055 2056 if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST) 2057 auth_supported = "basic"; 2058 else if (auth_type == CUPSD_AUTH_DIGEST) 2059 auth_supported = "digest"; 2060#ifdef HAVE_GSSAPI 2061 else if (auth_type == CUPSD_AUTH_NEGOTIATE) 2062 auth_supported = "negotiate"; 2063#endif /* HAVE_GSSAPI */ 2064 2065 if (auth_type != CUPSD_AUTH_NONE) 2066 p->type |= CUPS_PRINTER_AUTHENTICATED; 2067 else 2068 p->type &= ~CUPS_PRINTER_AUTHENTICATED; 2069 } 2070 else 2071 p->type &= ~CUPS_PRINTER_AUTHENTICATED; 2072 2073 /* 2074 * Create the required IPP attributes for a printer... 2075 */ 2076 2077 oldattrs = p->attrs; 2078 p->attrs = ippNew(); 2079 2080 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 2081 "uri-authentication-supported", NULL, auth_supported); 2082 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 2083 "uri-security-supported", NULL, "none"); 2084 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL, 2085 p->name); 2086 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", 2087 NULL, p->location ? p->location : ""); 2088 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", 2089 NULL, p->info ? p->info : ""); 2090 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, 2091 p->uuid); 2092 2093 if (cupsArrayCount(p->users) > 0) 2094 { 2095 if (p->deny_users) 2096 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, 2097 "requesting-user-name-denied", 2098 cupsArrayCount(p->users), NULL, NULL); 2099 else 2100 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, 2101 "requesting-user-name-allowed", 2102 cupsArrayCount(p->users), NULL, NULL); 2103 2104 for (i = 0, name = (char *)cupsArrayFirst(p->users); 2105 name; 2106 i ++, name = (char *)cupsArrayNext(p->users)) 2107 attr->values[i].string.text = _cupsStrAlloc(name); 2108 } 2109 2110 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 2111 "job-quota-period", p->quota_period); 2112 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 2113 "job-k-limit", p->k_limit); 2114 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 2115 "job-page-limit", p->page_limit); 2116 if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none")) 2117 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 2118 "auth-info-required", p->num_auth_info_required, NULL, 2119 p->auth_info_required); 2120 2121 if (cupsArrayCount(Banners) > 0) 2122 { 2123 /* 2124 * Setup the job-sheets-default attribute... 2125 */ 2126 2127 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, 2128 "job-sheets-default", 2, NULL, NULL); 2129 2130 if (attr != NULL) 2131 { 2132 attr->values[0].string.text = _cupsStrAlloc(Classification ? 2133 Classification : p->job_sheets[0]); 2134 attr->values[1].string.text = _cupsStrAlloc(Classification ? 2135 Classification : p->job_sheets[1]); 2136 } 2137 } 2138 2139 p->raw = 0; 2140 p->remote = 0; 2141 2142 /* 2143 * Assign additional attributes depending on whether this is a printer 2144 * or class... 2145 */ 2146 2147 if (p->type & CUPS_PRINTER_CLASS) 2148 { 2149 p->raw = 1; 2150 p->type &= ~CUPS_PRINTER_OPTIONS; 2151 2152 /* 2153 * Add class-specific attributes... 2154 */ 2155 2156 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, 2157 "printer-make-and-model", NULL, "Local Printer Class"); 2158 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, 2159 "file:///dev/null"); 2160 2161 if (p->num_printers > 0) 2162 { 2163 /* 2164 * Add a list of member names; URIs are added in copy_printer_attrs... 2165 */ 2166 2167 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, 2168 "member-names", p->num_printers, NULL, NULL); 2169 p->type |= CUPS_PRINTER_OPTIONS; 2170 2171 for (i = 0; i < p->num_printers; i ++) 2172 { 2173 if (attr != NULL) 2174 attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name); 2175 2176 p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type; 2177 } 2178 } 2179 } 2180 else 2181 { 2182 /* 2183 * Add printer-specific attributes... 2184 */ 2185 2186 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, 2187 p->sanitized_device_uri); 2188 2189 /* 2190 * Assign additional attributes from the PPD file (if any)... 2191 */ 2192 2193 load_ppd(p); 2194 2195 /* 2196 * Add filters for printer... 2197 */ 2198 2199 cupsdSetPrinterReasons(p, "-cups-missing-filter-warning," 2200 "cups-insecure-filter-warning"); 2201 2202 if (p->pc && p->pc->filters) 2203 { 2204 for (filter = (char *)cupsArrayFirst(p->pc->filters); 2205 filter; 2206 filter = (char *)cupsArrayNext(p->pc->filters)) 2207 add_printer_filter(p, p->filetype, filter); 2208 } 2209 else if (!(p->type & CUPS_PRINTER_REMOTE)) 2210 { 2211 char interface[1024]; /* Interface script */ 2212 2213 2214 snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot, 2215 p->name); 2216 if (!access(interface, X_OK)) 2217 { 2218 /* 2219 * Yes, we have a System V style interface script; use it! 2220 */ 2221 2222 snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s", 2223 ServerRoot, p->name); 2224 add_printer_filter(p, p->filetype, interface); 2225 } 2226 else 2227 { 2228 /* 2229 * Add a filter from application/vnd.cups-raw to printer/name to 2230 * handle "raw" printing by users. 2231 */ 2232 2233 add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); 2234 2235 /* 2236 * Add a PostScript filter, since this is still possibly PS printer. 2237 */ 2238 2239 add_printer_filter(p, p->filetype, 2240 "application/vnd.cups-postscript 0 -"); 2241 } 2242 } 2243 2244 if (p->pc && p->pc->prefilters) 2245 { 2246 if (!p->prefiltertype) 2247 p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); 2248 2249 for (filter = (char *)cupsArrayFirst(p->pc->prefilters); 2250 filter; 2251 filter = (char *)cupsArrayNext(p->pc->prefilters)) 2252 add_printer_filter(p, p->prefiltertype, filter); 2253 } 2254 } 2255 2256 /* 2257 * Copy marker attributes as needed... 2258 */ 2259 2260 if (oldattrs) 2261 { 2262 ipp_attribute_t *oldattr; /* Old attribute */ 2263 2264 2265 if ((oldattr = ippFindAttribute(oldattrs, "marker-colors", 2266 IPP_TAG_NAME)) != NULL) 2267 { 2268 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, 2269 "marker-colors", oldattr->num_values, NULL, 2270 NULL)) != NULL) 2271 { 2272 for (i = 0; i < oldattr->num_values; i ++) 2273 attr->values[i].string.text = 2274 _cupsStrAlloc(oldattr->values[i].string.text); 2275 } 2276 } 2277 2278 if ((oldattr = ippFindAttribute(oldattrs, "marker-levels", 2279 IPP_TAG_INTEGER)) != NULL) 2280 { 2281 if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 2282 "marker-levels", oldattr->num_values, 2283 NULL)) != NULL) 2284 { 2285 for (i = 0; i < oldattr->num_values; i ++) 2286 attr->values[i].integer = oldattr->values[i].integer; 2287 } 2288 } 2289 2290 if ((oldattr = ippFindAttribute(oldattrs, "marker-message", 2291 IPP_TAG_TEXT)) != NULL) 2292 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "marker-message", 2293 NULL, oldattr->values[0].string.text); 2294 2295 if ((oldattr = ippFindAttribute(oldattrs, "marker-low-levels", 2296 IPP_TAG_INTEGER)) != NULL) 2297 { 2298 if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 2299 "marker-low-levels", oldattr->num_values, 2300 NULL)) != NULL) 2301 { 2302 for (i = 0; i < oldattr->num_values; i ++) 2303 attr->values[i].integer = oldattr->values[i].integer; 2304 } 2305 } 2306 2307 if ((oldattr = ippFindAttribute(oldattrs, "marker-high-levels", 2308 IPP_TAG_INTEGER)) != NULL) 2309 { 2310 if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 2311 "marker-high-levels", oldattr->num_values, 2312 NULL)) != NULL) 2313 { 2314 for (i = 0; i < oldattr->num_values; i ++) 2315 attr->values[i].integer = oldattr->values[i].integer; 2316 } 2317 } 2318 2319 if ((oldattr = ippFindAttribute(oldattrs, "marker-names", 2320 IPP_TAG_NAME)) != NULL) 2321 { 2322 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, 2323 "marker-names", oldattr->num_values, NULL, 2324 NULL)) != NULL) 2325 { 2326 for (i = 0; i < oldattr->num_values; i ++) 2327 attr->values[i].string.text = 2328 _cupsStrAlloc(oldattr->values[i].string.text); 2329 } 2330 } 2331 2332 if ((oldattr = ippFindAttribute(oldattrs, "marker-types", 2333 IPP_TAG_KEYWORD)) != NULL) 2334 { 2335 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 2336 "marker-types", oldattr->num_values, NULL, 2337 NULL)) != NULL) 2338 { 2339 for (i = 0; i < oldattr->num_values; i ++) 2340 attr->values[i].string.text = 2341 _cupsStrAlloc(oldattr->values[i].string.text); 2342 } 2343 } 2344 2345 ippDelete(oldattrs); 2346 } 2347 2348 /* 2349 * Force sharing off for remote queues... 2350 */ 2351 2352 if (p->type & CUPS_PRINTER_REMOTE) 2353 p->shared = 0; 2354 2355 /* 2356 * Populate the document-format-supported attribute... 2357 */ 2358 2359 add_printer_formats(p); 2360 2361 DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name, 2362 p->type)); 2363 2364 /* 2365 * Add name-default attributes... 2366 */ 2367 2368 add_printer_defaults(p); 2369 2370 /* 2371 * Let the browse protocols reflect the change 2372 */ 2373 2374 cupsdRegisterPrinter(p); 2375} 2376 2377 2378/* 2379 * 'cupsdSetPrinterReasons()' - Set/update the reasons strings. 2380 */ 2381 2382int /* O - 1 if something changed, 0 otherwise */ 2383cupsdSetPrinterReasons( 2384 cupsd_printer_t *p, /* I - Printer */ 2385 const char *s) /* I - Reasons strings */ 2386{ 2387 int i, /* Looping var */ 2388 changed = 0; /* Did something change? */ 2389 const char *sptr; /* Pointer into reasons */ 2390 char reason[255], /* Reason string */ 2391 *rptr; /* Pointer into reason */ 2392 2393 2394 cupsdLogMessage(CUPSD_LOG_DEBUG2, 2395 "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s); 2396 2397 if (s[0] == '-' || s[0] == '+') 2398 { 2399 /* 2400 * Add/remove reasons... 2401 */ 2402 2403 sptr = s + 1; 2404 } 2405 else 2406 { 2407 /* 2408 * Replace reasons... 2409 */ 2410 2411 sptr = s; 2412 2413 for (i = 0; i < p->num_reasons; i ++) 2414 _cupsStrFree(p->reasons[i]); 2415 2416 p->num_reasons = 0; 2417 changed = 1; 2418 2419 dirty_printer(p); 2420 } 2421 2422 if (!strcmp(s, "none")) 2423 return (changed); 2424 2425 /* 2426 * Loop through all of the reasons... 2427 */ 2428 2429 while (*sptr) 2430 { 2431 /* 2432 * Skip leading whitespace and commas... 2433 */ 2434 2435 while (isspace(*sptr & 255) || *sptr == ',') 2436 sptr ++; 2437 2438 for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++) 2439 if (rptr < (reason + sizeof(reason) - 1)) 2440 *rptr++ = *sptr; 2441 2442 if (rptr == reason) 2443 break; 2444 2445 *rptr = '\0'; 2446 2447 if (s[0] == '-') 2448 { 2449 /* 2450 * Remove reason... 2451 */ 2452 2453 for (i = 0; i < p->num_reasons; i ++) 2454 if (!strcmp(reason, p->reasons[i])) 2455 { 2456 /* 2457 * Found a match, so remove it... 2458 */ 2459 2460 p->num_reasons --; 2461 changed = 1; 2462 _cupsStrFree(p->reasons[i]); 2463 2464 if (i < p->num_reasons) 2465 memmove(p->reasons + i, p->reasons + i + 1, 2466 (p->num_reasons - i) * sizeof(char *)); 2467 2468 if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED) 2469 cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1); 2470 2471 if (strcmp(reason, "connecting-to-device")) 2472 dirty_printer(p); 2473 break; 2474 } 2475 } 2476 else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) 2477 { 2478 /* 2479 * Add reason... 2480 */ 2481 2482 for (i = 0; i < p->num_reasons; i ++) 2483 if (!strcmp(reason, p->reasons[i])) 2484 break; 2485 2486 if (i >= p->num_reasons) 2487 { 2488 if (i >= (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) 2489 { 2490 cupsdLogMessage(CUPSD_LOG_ALERT, 2491 "Too many printer-state-reasons values for %s (%d)", 2492 p->name, i + 1); 2493 return (changed); 2494 } 2495 2496 p->reasons[i] = _cupsStrAlloc(reason); 2497 p->num_reasons ++; 2498 changed = 1; 2499 2500 if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED) 2501 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1); 2502 2503 if (strcmp(reason, "connecting-to-device")) 2504 dirty_printer(p); 2505 } 2506 } 2507 } 2508 2509 return (changed); 2510} 2511 2512 2513/* 2514 * 'cupsdSetPrinterState()' - Update the current state of a printer. 2515 */ 2516 2517void 2518cupsdSetPrinterState( 2519 cupsd_printer_t *p, /* I - Printer to change */ 2520 ipp_pstate_t s, /* I - New state */ 2521 int update) /* I - Update printers.conf? */ 2522{ 2523 cupsd_job_t *job; /* Current job */ 2524 ipp_pstate_t old_state; /* Old printer state */ 2525 static const char * const printer_states[] = 2526 { /* State strings */ 2527 "idle", 2528 "processing", 2529 "stopped" 2530 }; 2531 2532 2533 /* 2534 * Set the new state... 2535 */ 2536 2537 old_state = p->state; 2538 p->state = s; 2539 2540 if (old_state != s) 2541 { 2542 cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED : 2543 CUPSD_EVENT_PRINTER_STATE, p, NULL, 2544 "%s \"%s\" state changed to %s.", 2545 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", 2546 p->name, printer_states[p->state - IPP_PRINTER_IDLE]); 2547 2548 /* 2549 * Let the browse code know this needs to be updated... 2550 */ 2551 2552 p->state_time = time(NULL); 2553 } 2554 2555 /* 2556 * Set/clear the paused reason as needed... 2557 */ 2558 2559 if (s == IPP_PRINTER_STOPPED) 2560 cupsdSetPrinterReasons(p, "+paused"); 2561 else 2562 cupsdSetPrinterReasons(p, "-paused"); 2563 2564 if (old_state != s) 2565 { 2566 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); 2567 job; 2568 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) 2569 if (job->reasons && job->state_value == IPP_JOB_PENDING && 2570 !_cups_strcasecmp(job->dest, p->name)) 2571 ippSetString(job->attrs, &job->reasons, 0, 2572 s == IPP_PRINTER_STOPPED ? "printer-stopped" : "none"); 2573 } 2574 2575 /* 2576 * Clear the message for the queue when going to processing... 2577 */ 2578 2579 if (s == IPP_PRINTER_PROCESSING) 2580 p->state_message[0] = '\0'; 2581 2582 /* 2583 * Let the browse protocols reflect the change... 2584 */ 2585 2586 if (update) 2587 cupsdRegisterPrinter(p); 2588 2589 /* 2590 * Save the printer configuration if a printer goes from idle or processing 2591 * to stopped (or visa-versa)... 2592 */ 2593 2594 if (update && 2595 (old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED)) 2596 dirty_printer(p); 2597} 2598 2599 2600/* 2601 * 'cupsdStopPrinter()' - Stop a printer from printing any jobs... 2602 */ 2603 2604void 2605cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */ 2606 int update)/* I - Update printers.conf? */ 2607{ 2608 /* 2609 * Set the printer state... 2610 */ 2611 2612 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update); 2613 2614 /* 2615 * See if we have a job printing on this printer... 2616 */ 2617 2618 if (p->job && p->job->state_value == IPP_JOB_PROCESSING) 2619 cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT, 2620 "Job stopped due to printer being paused."); 2621} 2622 2623 2624/* 2625 * 'cupsdUpdatePrinterPPD()' - Update keywords in a printer's PPD file. 2626 */ 2627 2628int /* O - 1 if successful, 0 otherwise */ 2629cupsdUpdatePrinterPPD( 2630 cupsd_printer_t *p, /* I - Printer */ 2631 int num_keywords, /* I - Number of keywords */ 2632 cups_option_t *keywords) /* I - Keywords */ 2633{ 2634 int i; /* Looping var */ 2635 cups_file_t *src, /* Original file */ 2636 *dst; /* New file */ 2637 char srcfile[1024], /* Original filename */ 2638 dstfile[1024], /* New filename */ 2639 line[1024], /* Line from file */ 2640 keystring[41]; /* Keyword from line */ 2641 cups_option_t *keyword; /* Current keyword */ 2642 2643 2644 cupsdLogMessage(CUPSD_LOG_INFO, "Updating keywords in PPD file for %s...", 2645 p->name); 2646 2647 /* 2648 * Get the old and new PPD filenames... 2649 */ 2650 2651 snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name); 2652 snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name); 2653 2654 /* 2655 * Rename the old file and open the old and new... 2656 */ 2657 2658 if (rename(dstfile, srcfile)) 2659 { 2660 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s", 2661 p->name, strerror(errno)); 2662 return (0); 2663 } 2664 2665 if ((src = cupsFileOpen(srcfile, "r")) == NULL) 2666 { 2667 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s", 2668 srcfile, strerror(errno)); 2669 rename(srcfile, dstfile); 2670 return (0); 2671 } 2672 2673 if ((dst = cupsFileOpen(dstfile, "w")) == NULL) 2674 { 2675 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s", 2676 dstfile, strerror(errno)); 2677 cupsFileClose(src); 2678 rename(srcfile, dstfile); 2679 return (0); 2680 } 2681 2682 /* 2683 * Copy the first line and then write out all of the keywords... 2684 */ 2685 2686 if (!cupsFileGets(src, line, sizeof(line))) 2687 { 2688 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s", 2689 srcfile, strerror(errno)); 2690 cupsFileClose(src); 2691 cupsFileClose(dst); 2692 rename(srcfile, dstfile); 2693 return (0); 2694 } 2695 2696 cupsFilePrintf(dst, "%s\n", line); 2697 2698 for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++) 2699 { 2700 cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value); 2701 cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value); 2702 } 2703 2704 /* 2705 * Then copy the rest of the PPD file, dropping any keywords we changed. 2706 */ 2707 2708 while (cupsFileGets(src, line, sizeof(line))) 2709 { 2710 /* 2711 * Skip keywords we've already set... 2712 */ 2713 2714 if (sscanf(line, "*%40[^:]:", keystring) == 1 && 2715 cupsGetOption(keystring, num_keywords, keywords)) 2716 continue; 2717 2718 /* 2719 * Otherwise write the line... 2720 */ 2721 2722 cupsFilePrintf(dst, "%s\n", line); 2723 } 2724 2725 /* 2726 * Close files and return... 2727 */ 2728 2729 cupsFileClose(src); 2730 cupsFileClose(dst); 2731 2732 return (1); 2733} 2734 2735 2736/* 2737 * 'cupsdUpdatePrinters()' - Update printers after a partial reload. 2738 */ 2739 2740void 2741cupsdUpdatePrinters(void) 2742{ 2743 cupsd_printer_t *p; /* Current printer */ 2744 2745 2746 /* 2747 * Loop through the printers and recreate the printer attributes 2748 * for any local printers since the policy and/or access control 2749 * stuff may have changed. Also, if browsing is disabled, remove 2750 * any remote printers... 2751 */ 2752 2753 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); 2754 p; 2755 p = (cupsd_printer_t *)cupsArrayNext(Printers)) 2756 { 2757 /* 2758 * Update the operation policy pointer... 2759 */ 2760 2761 if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL) 2762 p->op_policy_ptr = DefaultPolicyPtr; 2763 2764 /* 2765 * Update printer attributes... 2766 */ 2767 2768 cupsdSetPrinterAttrs(p); 2769 } 2770} 2771 2772 2773/* 2774 * 'cupsdValidateDest()' - Validate a printer/class destination. 2775 */ 2776 2777const char * /* O - Printer or class name */ 2778cupsdValidateDest( 2779 const char *uri, /* I - Printer URI */ 2780 cups_ptype_t *dtype, /* O - Type (printer or class) */ 2781 cupsd_printer_t **printer) /* O - Printer pointer */ 2782{ 2783 cupsd_printer_t *p; /* Current printer */ 2784 char localname[1024],/* Localized hostname */ 2785 *lptr, /* Pointer into localized hostname */ 2786 *sptr, /* Pointer into server name */ 2787 *rptr, /* Pointer into resource */ 2788 scheme[32], /* Scheme portion of URI */ 2789 username[64], /* Username portion of URI */ 2790 hostname[HTTP_MAX_HOST], 2791 /* Host portion of URI */ 2792 resource[HTTP_MAX_URI]; 2793 /* Resource portion of URI */ 2794 int port; /* Port portion of URI */ 2795 2796 2797 DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri, 2798 dtype, printer)); 2799 2800 /* 2801 * Initialize return values... 2802 */ 2803 2804 if (printer) 2805 *printer = NULL; 2806 2807 if (dtype) 2808 *dtype = (cups_ptype_t)0; 2809 2810 /* 2811 * Pull the hostname and resource from the URI... 2812 */ 2813 2814 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), 2815 username, sizeof(username), hostname, sizeof(hostname), 2816 &port, resource, sizeof(resource)); 2817 2818 /* 2819 * See if the resource is a class or printer... 2820 */ 2821 2822 if (!strncmp(resource, "/classes/", 9)) 2823 { 2824 /* 2825 * Class... 2826 */ 2827 2828 rptr = resource + 9; 2829 } 2830 else if (!strncmp(resource, "/printers/", 10)) 2831 { 2832 /* 2833 * Printer... 2834 */ 2835 2836 rptr = resource + 10; 2837 } 2838 else 2839 { 2840 /* 2841 * Bad resource name... 2842 */ 2843 2844 return (NULL); 2845 } 2846 2847 /* 2848 * See if the printer or class name exists... 2849 */ 2850 2851 p = cupsdFindDest(rptr); 2852 2853 if (p == NULL && strchr(rptr, '@') == NULL) 2854 return (NULL); 2855 else if (p != NULL) 2856 { 2857 if (printer) 2858 *printer = p; 2859 2860 if (dtype) 2861 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); 2862 2863 return (p->name); 2864 } 2865 2866 /* 2867 * Change localhost to the server name... 2868 */ 2869 2870 if (!_cups_strcasecmp(hostname, "localhost")) 2871 strlcpy(hostname, ServerName, sizeof(hostname)); 2872 2873 strlcpy(localname, hostname, sizeof(localname)); 2874 2875 if (!_cups_strcasecmp(hostname, ServerName)) 2876 { 2877 /* 2878 * Localize the hostname... 2879 */ 2880 2881 lptr = strchr(localname, '.'); 2882 sptr = strchr(ServerName, '.'); 2883 2884 if (sptr != NULL && lptr != NULL) 2885 { 2886 /* 2887 * Strip the common domain name components... 2888 */ 2889 2890 while (lptr != NULL) 2891 { 2892 if (!_cups_strcasecmp(lptr, sptr)) 2893 { 2894 *lptr = '\0'; 2895 break; 2896 } 2897 else 2898 lptr = strchr(lptr + 1, '.'); 2899 } 2900 } 2901 } 2902 2903 DEBUG_printf(("localized hostname is \"%s\"...\n", localname)); 2904 2905 /* 2906 * Find a matching printer or class... 2907 */ 2908 2909 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); 2910 p; 2911 p = (cupsd_printer_t *)cupsArrayNext(Printers)) 2912 if (!_cups_strcasecmp(p->hostname, localname) && 2913 !_cups_strcasecmp(p->name, rptr)) 2914 { 2915 if (printer) 2916 *printer = p; 2917 2918 if (dtype) 2919 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); 2920 2921 return (p->name); 2922 } 2923 2924 return (NULL); 2925} 2926 2927 2928/* 2929 * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications 2930 * that need it... 2931 */ 2932 2933void 2934cupsdWritePrintcap(void) 2935{ 2936 int i; /* Looping var */ 2937 cups_file_t *fp; /* Printcap file */ 2938 cupsd_printer_t *p; /* Current printer */ 2939 2940 2941 /* 2942 * See if we have a printcap file; if not, don't bother writing it. 2943 */ 2944 2945 if (!Printcap || !*Printcap) 2946 return; 2947 2948 cupsdLogMessage(CUPSD_LOG_INFO, "Generating printcap %s...", Printcap); 2949 2950 /* 2951 * Open the printcap file... 2952 */ 2953 2954 if ((fp = cupsFileOpen(Printcap, "w")) == NULL) 2955 return; 2956 2957 /* 2958 * Put a comment header at the top so that users will know where the 2959 * data has come from... 2960 */ 2961 2962 if (PrintcapFormat != PRINTCAP_PLIST) 2963 cupsFilePrintf(fp, "# This file was automatically generated by cupsd(8) " 2964 "from the\n" 2965 "# %s/printers.conf file. All changes to this file\n" 2966 "# will be lost.\n", ServerRoot); 2967 2968 /* 2969 * Write a new printcap with the current list of printers. 2970 */ 2971 2972 switch (PrintcapFormat) 2973 { 2974 case PRINTCAP_BSD : 2975 /* 2976 * Each printer is put in the file as: 2977 * 2978 * Printer1: 2979 * Printer2: 2980 * Printer3: 2981 * ... 2982 * PrinterN: 2983 */ 2984 2985 if (DefaultPrinter) 2986 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name, 2987 DefaultPrinter->info, ServerName, 2988 DefaultPrinter->name); 2989 2990 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); 2991 p; 2992 p = (cupsd_printer_t *)cupsArrayNext(Printers)) 2993 if (p != DefaultPrinter) 2994 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info, 2995 ServerName, p->name); 2996 break; 2997 2998 case PRINTCAP_PLIST : 2999 /* 3000 * Each printer is written as a dictionary in a plist file. 3001 * Currently the printer-name, printer-info, printer-is-accepting-jobs, 3002 * printer-location, printer-make-and-model, printer-state, 3003 * printer-state-reasons, printer-type, and (sanitized) device-uri. 3004 */ 3005 3006 cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 3007 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD " 3008 "PLIST 1.0//EN\" \"http://www.apple.com/DTDs/" 3009 "PropertyList-1.0.dtd\">\n" 3010 "<plist version=\"1.0\">\n" 3011 "<array>\n"); 3012 3013 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); 3014 p; 3015 p = (cupsd_printer_t *)cupsArrayNext(Printers)) 3016 { 3017 cupsFilePuts(fp, "\t<dict>\n" 3018 "\t\t<key>printer-name</key>\n" 3019 "\t\t<string>"); 3020 write_xml_string(fp, p->name); 3021 cupsFilePuts(fp, "</string>\n" 3022 "\t\t<key>printer-info</key>\n" 3023 "\t\t<string>"); 3024 write_xml_string(fp, p->info); 3025 cupsFilePrintf(fp, "</string>\n" 3026 "\t\t<key>printer-is-accepting-jobs</key>\n" 3027 "\t\t<%s/>\n" 3028 "\t\t<key>printer-location</key>\n" 3029 "\t\t<string>", p->accepting ? "true" : "false"); 3030 write_xml_string(fp, p->location); 3031 cupsFilePuts(fp, "</string>\n" 3032 "\t\t<key>printer-make-and-model</key>\n" 3033 "\t\t<string>"); 3034 write_xml_string(fp, p->make_model); 3035 cupsFilePrintf(fp, "</string>\n" 3036 "\t\t<key>printer-state</key>\n" 3037 "\t\t<integer>%d</integer>\n" 3038 "\t\t<key>printer-state-reasons</key>\n" 3039 "\t\t<array>\n", p->state); 3040 for (i = 0; i < p->num_reasons; i ++) 3041 { 3042 cupsFilePuts(fp, "\t\t\t<string>"); 3043 write_xml_string(fp, p->reasons[i]); 3044 cupsFilePuts(fp, "</string>\n"); 3045 } 3046 cupsFilePrintf(fp, "\t\t</array>\n" 3047 "\t\t<key>printer-type</key>\n" 3048 "\t\t<integer>%d</integer>\n" 3049 "\t\t<key>device-uri</key>\n" 3050 "\t\t<string>", p->type); 3051 write_xml_string(fp, p->sanitized_device_uri); 3052 cupsFilePuts(fp, "</string>\n" 3053 "\t</dict>\n"); 3054 } 3055 cupsFilePuts(fp, "</array>\n" 3056 "</plist>\n"); 3057 break; 3058 3059 case PRINTCAP_SOLARIS : 3060 /* 3061 * Each printer is put in the file as: 3062 * 3063 * _all:all=Printer1,Printer2,Printer3,...,PrinterN 3064 * _default:use=DefaultPrinter 3065 * Printer1:\ 3066 * :bsdaddr=ServerName,Printer1:\ 3067 * :description=Description: 3068 * Printer2: 3069 * :bsdaddr=ServerName,Printer2:\ 3070 * :description=Description: 3071 * Printer3: 3072 * :bsdaddr=ServerName,Printer3:\ 3073 * :description=Description: 3074 * ... 3075 * PrinterN: 3076 * :bsdaddr=ServerName,PrinterN:\ 3077 * :description=Description: 3078 */ 3079 3080 cupsFilePuts(fp, "_all:all="); 3081 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); 3082 p; 3083 p = (cupsd_printer_t *)cupsArrayCurrent(Printers)) 3084 cupsFilePrintf(fp, "%s%c", p->name, 3085 cupsArrayNext(Printers) ? ',' : '\n'); 3086 3087 if (DefaultPrinter) 3088 cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name); 3089 3090 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); 3091 p; 3092 p = (cupsd_printer_t *)cupsArrayNext(Printers)) 3093 cupsFilePrintf(fp, "%s:\\\n" 3094 "\t:bsdaddr=%s,%s:\\\n" 3095 "\t:description=%s:\n", 3096 p->name, ServerName, p->name, 3097 p->info ? p->info : ""); 3098 break; 3099 } 3100 3101 /* 3102 * Close the file... 3103 */ 3104 3105 cupsFileClose(fp); 3106} 3107 3108 3109/* 3110 * 'add_printer_defaults()' - Add name-default attributes to the printer attributes. 3111 */ 3112 3113static void 3114add_printer_defaults(cupsd_printer_t *p)/* I - Printer */ 3115{ 3116 int i; /* Looping var */ 3117 int num_options; /* Number of default options */ 3118 cups_option_t *options, /* Default options */ 3119 *option; /* Current option */ 3120 char name[256]; /* name-default */ 3121 3122 3123 /* 3124 * Maintain a common array of default attribute names... 3125 */ 3126 3127 if (!CommonDefaults) 3128 { 3129 CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL); 3130 3131 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default")); 3132 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default")); 3133 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default")); 3134 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-account-id-default")); 3135 cupsArrayAdd(CommonDefaults, 3136 _cupsStrAlloc("job-accounting-user-id-default")); 3137 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default")); 3138 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default")); 3139 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default")); 3140 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default")); 3141 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default")); 3142 cupsArrayAdd(CommonDefaults, 3143 _cupsStrAlloc("orientation-requested-default")); 3144 } 3145 3146 /* 3147 * Add all of the default options from the .conf files... 3148 */ 3149 3150 for (num_options = 0, options = NULL, i = p->num_options, option = p->options; 3151 i > 0; 3152 i --, option ++) 3153 { 3154 if (strcmp(option->name, "ipp-options") && 3155 strcmp(option->name, "job-sheets") && 3156 strcmp(option->name, "lease-duration")) 3157 { 3158 snprintf(name, sizeof(name), "%s-default", option->name); 3159 num_options = cupsAddOption(name, option->value, num_options, &options); 3160 3161 if (!cupsArrayFind(CommonDefaults, name)) 3162 cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name)); 3163 } 3164 } 3165 3166 /* 3167 * Convert options to IPP attributes... 3168 */ 3169 3170 cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER); 3171 cupsFreeOptions(num_options, options); 3172 3173 /* 3174 * Add standard -default attributes as needed... 3175 */ 3176 3177 if (!cupsGetOption("copies", p->num_options, p->options)) 3178 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 3179 1); 3180 3181 if (!cupsGetOption("document-format", p->num_options, p->options)) 3182 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, 3183 "document-format-default", NULL, "application/octet-stream"); 3184 3185 if (!cupsGetOption("job-hold-until", p->num_options, p->options)) 3186 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3187 "job-hold-until-default", NULL, "no-hold"); 3188 3189 if (!cupsGetOption("job-priority", p->num_options, p->options)) 3190 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3191 "job-priority-default", 50); 3192 3193 if (!cupsGetOption("number-up", p->num_options, p->options)) 3194 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3195 "number-up-default", 1); 3196 3197 if (!cupsGetOption("notify-lease-duration", p->num_options, p->options)) 3198 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3199 "notify-lease-duration-default", DefaultLeaseDuration); 3200 3201 if (!cupsGetOption("notify-events", p->num_options, p->options)) 3202 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3203 "notify-events-default", NULL, "job-completed"); 3204 3205 if (!cupsGetOption("orientation-requested", p->num_options, p->options)) 3206 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, 3207 "orientation-requested-default", NULL, NULL); 3208 3209 if (!cupsGetOption("print-quality", p->num_options, p->options)) 3210 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, 3211 "print-quality-default", IPP_QUALITY_NORMAL); 3212} 3213 3214 3215/* 3216 * 'add_printer_filter()' - Add a MIME filter for a printer. 3217 */ 3218 3219static void 3220add_printer_filter( 3221 cupsd_printer_t *p, /* I - Printer to add to */ 3222 mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ 3223 const char *filter) /* I - Filter to add */ 3224{ 3225 char super[MIME_MAX_SUPER], /* Super-type for filter */ 3226 type[MIME_MAX_TYPE], /* Type for filter */ 3227 dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */ 3228 dtype[MIME_MAX_TYPE], /* Destination type for filter */ 3229 dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2], 3230 /* Destination super/type */ 3231 program[1024]; /* Program/filter name */ 3232 int cost; /* Cost of filter */ 3233 size_t maxsize = 0; /* Maximum supported file size */ 3234 mime_type_t *temptype, /* MIME type looping var */ 3235 *desttype; /* Destination MIME type */ 3236 mime_filter_t *filterptr; /* MIME filter */ 3237 char filename[1024]; /* Full filter filename */ 3238 3239 3240 cupsdLogMessage(CUPSD_LOG_DEBUG2, 3241 "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), " 3242 "filter=\"%s\")", p, p->name, filtertype, filtertype->super, 3243 filtertype->type, filter); 3244 3245 /* 3246 * Parse the filter string; it should be in one of the following formats: 3247 * 3248 * source/type cost program 3249 * source/type cost maxsize(nnnn) program 3250 * source/type dest/type cost program 3251 * source/type dest/type cost maxsize(nnnn) program 3252 */ 3253 3254 if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", 3255 super, type, dsuper, dtype, &cost, program) == 6) 3256 { 3257 snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype); 3258 3259 if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL) 3260 { 3261 desttype = mimeAddType(MimeDatabase, "printer", dest); 3262 if (!p->dest_types) 3263 p->dest_types = cupsArrayNew(NULL, NULL); 3264 3265 cupsArrayAdd(p->dest_types, desttype); 3266 } 3267 3268 } 3269 else 3270 { 3271 if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, 3272 program) == 4) 3273 { 3274 desttype = filtertype; 3275 } 3276 else 3277 { 3278 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", 3279 p->name, filter); 3280 return; 3281 } 3282 } 3283 3284 if (!strncmp(program, "maxsize(", 8)) 3285 { 3286 char *ptr; /* Pointer into maxsize(nnnn) program */ 3287 3288 maxsize = strtoll(program + 8, &ptr, 10); 3289 3290 if (*ptr != ')') 3291 { 3292 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!", 3293 p->name, filter); 3294 return; 3295 } 3296 3297 ptr ++; 3298 while (_cups_isspace(*ptr)) 3299 ptr ++; 3300 3301 _cups_strcpy(program, ptr); 3302 } 3303 3304 /* 3305 * Check permissions on the filter and its containing directory... 3306 */ 3307 3308 if (strcmp(program, "-")) 3309 { 3310 if (program[0] == '/') 3311 strlcpy(filename, program, sizeof(filename)); 3312 else 3313 snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program); 3314 3315 _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser, 3316 cupsdLogFCMessage, p); 3317 } 3318 3319 /* 3320 * Add the filter to the MIME database, supporting wildcards as needed... 3321 */ 3322 3323 for (temptype = mimeFirstType(MimeDatabase); 3324 temptype; 3325 temptype = mimeNextType(MimeDatabase)) 3326 if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || 3327 !_cups_strcasecmp(temptype->super, super)) && 3328 (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) 3329 { 3330 if (desttype != filtertype) 3331 { 3332 cupsdLogMessage(CUPSD_LOG_DEBUG2, 3333 "add_printer_filter: %s: adding filter %s/%s %s/%s %d " 3334 "%s", p->name, temptype->super, temptype->type, 3335 desttype->super, desttype->type, 3336 cost, program); 3337 filterptr = mimeAddFilter(MimeDatabase, temptype, desttype, cost, 3338 program); 3339 3340 if (!mimeFilterLookup(MimeDatabase, desttype, filtertype)) 3341 { 3342 cupsdLogMessage(CUPSD_LOG_DEBUG2, 3343 "add_printer_filter: %s: adding filter %s/%s %s/%s " 3344 "0 -", p->name, desttype->super, desttype->type, 3345 filtertype->super, filtertype->type); 3346 mimeAddFilter(MimeDatabase, desttype, filtertype, 0, "-"); 3347 } 3348 } 3349 else 3350 { 3351 cupsdLogMessage(CUPSD_LOG_DEBUG2, 3352 "add_printer_filter: %s: adding filter %s/%s %s/%s %d " 3353 "%s", p->name, temptype->super, temptype->type, 3354 filtertype->super, filtertype->type, 3355 cost, program); 3356 filterptr = mimeAddFilter(MimeDatabase, temptype, filtertype, cost, 3357 program); 3358 } 3359 3360 if (filterptr) 3361 filterptr->maxsize = maxsize; 3362 } 3363} 3364 3365 3366/* 3367 * 'add_printer_formats()' - Add document-format-supported values for a printer. 3368 */ 3369 3370static void 3371add_printer_formats(cupsd_printer_t *p) /* I - Printer */ 3372{ 3373 int i; /* Looping var */ 3374 mime_type_t *type; /* Current MIME type */ 3375 cups_array_t *filters; /* Filters */ 3376 ipp_attribute_t *attr; /* document-format-supported attribute */ 3377 char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2]; 3378 /* MIME type name */ 3379 3380 3381 /* 3382 * Raw (and remote) queues advertise all of the supported MIME 3383 * types... 3384 */ 3385 3386 cupsArrayDelete(p->filetypes); 3387 p->filetypes = NULL; 3388 3389 if (p->raw) 3390 { 3391 ippAddStrings(p->attrs, IPP_TAG_PRINTER, 3392 (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY), 3393 "document-format-supported", NumMimeTypes, NULL, MimeTypes); 3394 return; 3395 } 3396 3397 /* 3398 * Otherwise, loop through the supported MIME types and see if there 3399 * are filters for them... 3400 */ 3401 3402 cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters", 3403 mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase)); 3404 3405 p->filetypes = cupsArrayNew(NULL, NULL); 3406 3407 for (type = mimeFirstType(MimeDatabase); 3408 type; 3409 type = mimeNextType(MimeDatabase)) 3410 { 3411 if (!_cups_strcasecmp(type->super, "printer")) 3412 continue; 3413 3414 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); 3415 3416 if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL) 3417 { 3418 cupsdLogMessage(CUPSD_LOG_DEBUG2, 3419 "add_printer_formats: %s: %s needs %d filters", 3420 p->name, mimetype, cupsArrayCount(filters)); 3421 3422 cupsArrayDelete(filters); 3423 cupsArrayAdd(p->filetypes, type); 3424 } 3425 else 3426 cupsdLogMessage(CUPSD_LOG_DEBUG2, 3427 "add_printer_formats: %s: %s not supported", 3428 p->name, mimetype); 3429 } 3430 3431 /* 3432 * Add the file formats that can be filtered... 3433 */ 3434 3435 if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL || 3436 !cupsArrayFind(p->filetypes, type)) 3437 i = 1; 3438 else 3439 i = 0; 3440 3441 cupsdLogMessage(CUPSD_LOG_DEBUG2, 3442 "add_printer_formats: %s: %d supported types", 3443 p->name, cupsArrayCount(p->filetypes) + i); 3444 3445 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, 3446 "document-format-supported", 3447 cupsArrayCount(p->filetypes) + i, NULL, NULL); 3448 3449 if (i) 3450 attr->values[0].string.text = _cupsStrAlloc("application/octet-stream"); 3451 3452 for (type = (mime_type_t *)cupsArrayFirst(p->filetypes); 3453 type; 3454 i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes)) 3455 { 3456 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); 3457 3458 attr->values[i].string.text = _cupsStrAlloc(mimetype); 3459 } 3460 3461#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) 3462 { 3463 char pdl[1024]; /* Buffer to build pdl list */ 3464 mime_filter_t *filter; /* MIME filter looping var */ 3465 3466 3467 /* 3468 * We only support raw printing if this is not a Tioga PrintJobMgr based 3469 * queue and if application/octet-stream is a known type... 3470 */ 3471 3472 for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters); 3473 filter; 3474 filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters)) 3475 { 3476 if (filter->dst == p->filetype && filter->filter && 3477 strstr(filter->filter, "PrintJobMgr")) 3478 break; 3479 } 3480 3481 pdl[0] = '\0'; 3482 3483 if (!filter && mimeType(MimeDatabase, "application", "octet-stream")) 3484 strlcat(pdl, "application/octet-stream,", sizeof(pdl)); 3485 3486 /* 3487 * Then list a bunch of formats that are supported by the printer... 3488 */ 3489 3490 for (type = (mime_type_t *)cupsArrayFirst(p->filetypes); 3491 type; 3492 type = (mime_type_t *)cupsArrayNext(p->filetypes)) 3493 { 3494 if (!_cups_strcasecmp(type->super, "application")) 3495 { 3496 if (!_cups_strcasecmp(type->type, "pdf")) 3497 strlcat(pdl, "application/pdf,", sizeof(pdl)); 3498 else if (!_cups_strcasecmp(type->type, "postscript")) 3499 strlcat(pdl, "application/postscript,", sizeof(pdl)); 3500 } 3501 else if (!_cups_strcasecmp(type->super, "image")) 3502 { 3503 if (!_cups_strcasecmp(type->type, "jpeg")) 3504 strlcat(pdl, "image/jpeg,", sizeof(pdl)); 3505 else if (!_cups_strcasecmp(type->type, "png")) 3506 strlcat(pdl, "image/png,", sizeof(pdl)); 3507 else if (!_cups_strcasecmp(type->type, "pwg-raster")) 3508 strlcat(pdl, "image/pwg-raster,", sizeof(pdl)); 3509 } 3510 } 3511 3512 if (pdl[0]) 3513 pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */ 3514 3515 cupsdSetString(&p->pdl, pdl); 3516 } 3517#endif /* HAVE_DNSSD || HAVE_AVAHI */ 3518} 3519 3520 3521/* 3522 * 'compare_printers()' - Compare two printers. 3523 */ 3524 3525static int /* O - Result of comparison */ 3526compare_printers(void *first, /* I - First printer */ 3527 void *second, /* I - Second printer */ 3528 void *data) /* I - App data (not used) */ 3529{ 3530 (void)data; 3531 3532 return (_cups_strcasecmp(((cupsd_printer_t *)first)->name, 3533 ((cupsd_printer_t *)second)->name)); 3534} 3535 3536 3537/* 3538 * 'delete_printer_filters()' - Delete all MIME filters for a printer. 3539 */ 3540 3541static void 3542delete_printer_filters( 3543 cupsd_printer_t *p) /* I - Printer to remove from */ 3544{ 3545 mime_filter_t *filter; /* MIME filter looping var */ 3546 mime_type_t *type; /* Destination types for filters */ 3547 3548 3549 /* 3550 * Range check input... 3551 */ 3552 3553 if (p == NULL) 3554 return; 3555 3556 /* 3557 * Remove all filters from the MIME database that have a destination 3558 * type == printer... 3559 */ 3560 3561 for (filter = mimeFirstFilter(MimeDatabase); 3562 filter; 3563 filter = mimeNextFilter(MimeDatabase)) 3564 if (filter->dst == p->filetype || filter->dst == p->prefiltertype || 3565 cupsArrayFind(p->dest_types, filter->dst)) 3566 { 3567 /* 3568 * Delete the current filter... 3569 */ 3570 3571 mimeDeleteFilter(MimeDatabase, filter); 3572 } 3573 3574 for (type = (mime_type_t *)cupsArrayFirst(p->dest_types); 3575 type; 3576 type = (mime_type_t *)cupsArrayNext(p->dest_types)) 3577 mimeDeleteType(MimeDatabase, type); 3578 3579 cupsArrayDelete(p->dest_types); 3580 p->dest_types = NULL; 3581 3582 cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning" 3583 ",cups-missing-filter-warning"); 3584} 3585 3586 3587/* 3588 * 'dirty_printer()' - Mark config and state files dirty for the specified 3589 * printer. 3590 */ 3591 3592static void 3593dirty_printer(cupsd_printer_t *p) /* I - Printer */ 3594{ 3595 if (p->type & CUPS_PRINTER_CLASS) 3596 cupsdMarkDirty(CUPSD_DIRTY_CLASSES); 3597 else 3598 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); 3599 3600 if (PrintcapFormat == PRINTCAP_PLIST) 3601 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); 3602} 3603 3604 3605/* 3606 * 'load_ppd()' - Load a cached PPD file, updating the cache as needed. 3607 */ 3608 3609static void 3610load_ppd(cupsd_printer_t *p) /* I - Printer */ 3611{ 3612 int i, j, k; /* Looping vars */ 3613 char cache_name[1024]; /* Cache filename */ 3614 struct stat cache_info; /* Cache file info */ 3615 ppd_file_t *ppd; /* PPD file */ 3616 char ppd_name[1024]; /* PPD filename */ 3617 struct stat ppd_info; /* PPD file info */ 3618 int num_media; /* Number of media options */ 3619 ppd_size_t *size; /* Current PPD size */ 3620 ppd_option_t *duplex, /* Duplex option */ 3621 *output_bin, /* OutputBin option */ 3622 *output_mode, /* OutputMode option */ 3623 *resolution; /* (Set|JCL|)Resolution option */ 3624 ppd_choice_t *choice, /* Current PPD choice */ 3625 *input_slot, /* Current input slot */ 3626 *media_type; /* Current media type */ 3627 ppd_attr_t *ppd_attr; /* PPD attribute */ 3628 int xdpi, /* Horizontal resolution */ 3629 ydpi; /* Vertical resolution */ 3630 const char *resptr; /* Pointer into resolution keyword */ 3631 _pwg_size_t *pwgsize; /* Current PWG size */ 3632 _pwg_map_t *pwgsource, /* Current PWG source */ 3633 *pwgtype; /* Current PWG type */ 3634 ipp_attribute_t *attr; /* Attribute data */ 3635 _ipp_value_t *val; /* Attribute value */ 3636 int num_finishings, /* Number of finishings */ 3637 finishings[5]; /* finishings-supported values */ 3638 int num_qualities, /* Number of print-quality values */ 3639 qualities[3]; /* print-quality values */ 3640 int num_margins, /* Number of media-*-margin-supported values */ 3641 margins[16]; /* media-*-margin-supported values */ 3642 const char *filter, /* Current filter */ 3643 *mandatory; /* Current mandatory attribute */ 3644 static const char * const sides[3] = /* sides-supported values */ 3645 { 3646 "one-sided", 3647 "two-sided-long-edge", 3648 "two-sided-short-edge" 3649 }; 3650 static const char * const standard_commands[] = 3651 { /* Standard CUPS commands */ 3652 "AutoConfigure", 3653 "Clean", 3654 "PrintSelfTestPage" 3655 }; 3656 3657 3658 /* 3659 * Check to see if the cache is up-to-date... 3660 */ 3661 3662 snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name); 3663 if (stat(cache_name, &cache_info)) 3664 cache_info.st_mtime = 0; 3665 3666 snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name); 3667 if (stat(ppd_name, &ppd_info)) 3668 ppd_info.st_mtime = 1; 3669 3670 ippDelete(p->ppd_attrs); 3671 p->ppd_attrs = NULL; 3672 3673 _ppdCacheDestroy(p->pc); 3674 p->pc = NULL; 3675 3676 cupsdClearString(&(p->make_model)); 3677 3678 if (cache_info.st_mtime >= ppd_info.st_mtime) 3679 { 3680 cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name); 3681 3682 if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL && 3683 p->ppd_attrs) 3684 { 3685 /* 3686 * Loaded successfully! 3687 */ 3688 3689 return; 3690 } 3691 } 3692 3693 /* 3694 * Reload PPD attributes from disk... 3695 */ 3696 3697 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); 3698 3699 cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name); 3700 3701 p->type &= ~CUPS_PRINTER_OPTIONS; 3702 p->type |= CUPS_PRINTER_BW; 3703 3704 finishings[0] = IPP_FINISHINGS_NONE; 3705 num_finishings = 1; 3706 3707 p->ppd_attrs = ippNew(); 3708 3709 if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL) 3710 { 3711 /* 3712 * Add make/model and other various attributes... 3713 */ 3714 3715 p->pc = _ppdCacheCreateWithPPD(ppd); 3716 3717 if (!p->pc) 3718 cupsdLogMessage(CUPSD_LOG_WARN, "Unable to create cache of \"%s\": %s", 3719 ppd_name, cupsLastErrorString()); 3720 3721 ppdMarkDefaults(ppd); 3722 3723 if (ppd->color_device) 3724 p->type |= CUPS_PRINTER_COLOR; 3725 if (ppd->variable_sizes) 3726 p->type |= CUPS_PRINTER_VARIABLE; 3727 if (!ppd->manual_copies) 3728 p->type |= CUPS_PRINTER_COPIES; 3729 if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL) 3730 if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true")) 3731 p->type |= CUPS_PRINTER_FAX; 3732 3733 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported", 3734 ppd->color_device); 3735 3736 if (p->pc && p->pc->charge_info_uri) 3737 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_URI, 3738 "printer-charge-info-uri", NULL, p->pc->charge_info_uri); 3739 3740 if (p->pc && p->pc->account_id) 3741 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "job-account-id-supported", 3742 1); 3743 3744 if (p->pc && p->pc->accounting_user_id) 3745 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, 3746 "job-accounting-user-id-supported", 1); 3747 3748 if (p->pc && p->pc->password) 3749 { 3750 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3751 "job-password-encryption-supported", NULL, "none"); 3752 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3753 "job-password-supported", strlen(p->pc->password)); 3754 } 3755 3756 if (ppd->throughput) 3757 { 3758 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3759 "pages-per-minute", ppd->throughput); 3760 if (ppd->color_device) 3761 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3762 "pages-per-minute-color", ppd->throughput); 3763 } 3764 else 3765 { 3766 /* 3767 * When there is no speed information, just say "1 page per minute". 3768 */ 3769 3770 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3771 "pages-per-minute", 1); 3772 if (ppd->color_device) 3773 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3774 "pages-per-minute-color", 1); 3775 } 3776 3777 num_qualities = 0; 3778 3779 if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL) 3780 { 3781 if (ppdFindChoice(output_mode, "draft") || 3782 ppdFindChoice(output_mode, "fast")) 3783 qualities[num_qualities ++] = IPP_QUALITY_DRAFT; 3784 3785 qualities[num_qualities ++] = IPP_QUALITY_NORMAL; 3786 3787 if (ppdFindChoice(output_mode, "best") || 3788 ppdFindChoice(output_mode, "high")) 3789 qualities[num_qualities ++] = IPP_QUALITY_HIGH; 3790 } 3791 else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL) 3792 { 3793 do 3794 { 3795 if (strstr(ppd_attr->spec, "draft") || 3796 strstr(ppd_attr->spec, "Draft")) 3797 { 3798 qualities[num_qualities ++] = IPP_QUALITY_DRAFT; 3799 break; 3800 } 3801 } 3802 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", 3803 NULL)) != NULL); 3804 3805 qualities[num_qualities ++] = IPP_QUALITY_NORMAL; 3806 qualities[num_qualities ++] = IPP_QUALITY_HIGH; 3807 } 3808 else 3809 qualities[num_qualities ++] = IPP_QUALITY_NORMAL; 3810 3811 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, 3812 "print-quality-supported", num_qualities, qualities); 3813 3814 if (ppd->nickname) 3815 { 3816 /* 3817 * The NickName can be localized in the character set specified 3818 * by the LanugageEncoding attribute. However, ppdOpen2() has 3819 * already converted the ppd->nickname member to UTF-8 for us 3820 * (the original attribute value is available separately) 3821 */ 3822 3823 cupsdSetString(&p->make_model, ppd->nickname); 3824 } 3825 else if (ppd->modelname) 3826 { 3827 /* 3828 * Model name can only contain specific characters... 3829 */ 3830 3831 cupsdSetString(&p->make_model, ppd->modelname); 3832 } 3833 else 3834 cupsdSetString(&p->make_model, "Bad PPD File"); 3835 3836 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, 3837 "printer-make-and-model", NULL, p->make_model); 3838 3839 /* 3840 * Add media options from the PPD file... 3841 */ 3842 3843 if (ppd->num_sizes == 0 || !p->pc) 3844 { 3845 if (!ppdFindAttr(ppd, "APScannerOnly", NULL)) 3846 cupsdLogMessage(CUPSD_LOG_CRIT, 3847 "The PPD file for printer %s contains no media " 3848 "options and is therefore invalid!", p->name); 3849 3850 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3851 "media-default", NULL, "unknown"); 3852 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3853 "media-supported", NULL, "unknown"); 3854 } 3855 else 3856 { 3857 /* 3858 * media-default 3859 */ 3860 3861 if ((size = ppdPageSize(ppd, NULL)) != NULL) 3862 pwgsize = _ppdCacheGetSize(p->pc, size->name); 3863 else 3864 pwgsize = NULL; 3865 3866 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3867 "media-default", NULL, 3868 pwgsize ? pwgsize->map.pwg : "unknown"); 3869 3870 /* 3871 * media-col-default 3872 */ 3873 3874 if (pwgsize) 3875 { 3876 ipp_t *col; /* Collection value */ 3877 3878 input_slot = ppdFindMarkedChoice(ppd, "InputSlot"); 3879 media_type = ppdFindMarkedChoice(ppd, "MediaType"); 3880 col = new_media_col(pwgsize, 3881 input_slot ? 3882 _ppdCacheGetSource(p->pc, 3883 input_slot->choice) : 3884 NULL, 3885 media_type ? 3886 _ppdCacheGetType(p->pc, 3887 media_type->choice) : 3888 NULL); 3889 3890 ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", 3891 col); 3892 ippDelete(col); 3893 } 3894 3895 /* 3896 * media-supported 3897 */ 3898 3899 num_media = p->pc->num_sizes; 3900 if (p->pc->custom_min_keyword) 3901 num_media += 2; 3902 3903 if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3904 "media-supported", num_media, NULL, 3905 NULL)) != NULL) 3906 { 3907 val = attr->values; 3908 3909 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes; 3910 i > 0; 3911 i --, pwgsize ++, val ++) 3912 val->string.text = _cupsStrAlloc(pwgsize->map.pwg); 3913 3914 if (p->pc->custom_min_keyword) 3915 { 3916 val->string.text = _cupsStrAlloc(p->pc->custom_min_keyword); 3917 val ++; 3918 val->string.text = _cupsStrAlloc(p->pc->custom_max_keyword); 3919 } 3920 } 3921 3922 /* 3923 * media-size-supported 3924 */ 3925 3926 num_media = p->pc->num_sizes; 3927 if (p->pc->custom_min_keyword) 3928 num_media ++; 3929 3930 if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, 3931 "media-size-supported", num_media, 3932 NULL)) != NULL) 3933 { 3934 val = attr->values; 3935 3936 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes; 3937 i > 0; 3938 i --, pwgsize ++, val ++) 3939 { 3940 val->collection = ippNew(); 3941 ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3942 "x-dimension", pwgsize->width); 3943 ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 3944 "y-dimension", pwgsize->length); 3945 } 3946 3947 if (p->pc->custom_min_keyword) 3948 { 3949 val->collection = ippNew(); 3950 ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension", 3951 p->pc->custom_min_width, p->pc->custom_max_width); 3952 ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension", 3953 p->pc->custom_min_length, p->pc->custom_max_length); 3954 } 3955 } 3956 3957 /* 3958 * media-source-supported 3959 */ 3960 3961 if (p->pc->num_sources > 0 && 3962 (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3963 "media-source-supported", p->pc->num_sources, 3964 NULL, NULL)) != NULL) 3965 { 3966 for (i = p->pc->num_sources, pwgsource = p->pc->sources, 3967 val = attr->values; 3968 i > 0; 3969 i --, pwgsource ++, val ++) 3970 val->string.text = _cupsStrAlloc(pwgsource->pwg); 3971 } 3972 3973 /* 3974 * media-type-supported 3975 */ 3976 3977 if (p->pc->num_types > 0 && 3978 (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 3979 "media-type-supported", p->pc->num_types, 3980 NULL, NULL)) != NULL) 3981 { 3982 for (i = p->pc->num_types, pwgtype = p->pc->types, 3983 val = attr->values; 3984 i > 0; 3985 i --, pwgtype ++, val ++) 3986 val->string.text = _cupsStrAlloc(pwgtype->pwg); 3987 } 3988 3989 /* 3990 * media-*-margin-supported 3991 */ 3992 3993 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; 3994 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); 3995 i --, pwgsize ++) 3996 { 3997 for (j = 0; j < num_margins; j ++) 3998 if (pwgsize->bottom == margins[j]) 3999 break; 4000 4001 if (j >= num_margins) 4002 { 4003 margins[num_margins] = pwgsize->bottom; 4004 num_margins ++; 4005 } 4006 } 4007 4008 if (num_margins > 0) 4009 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4010 "media-bottom-margin-supported", num_margins, margins); 4011 else 4012 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4013 "media-bottom-margin-supported", 0); 4014 4015 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; 4016 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); 4017 i --, pwgsize ++) 4018 { 4019 for (j = 0; j < num_margins; j ++) 4020 if (pwgsize->left == margins[j]) 4021 break; 4022 4023 if (j >= num_margins) 4024 { 4025 margins[num_margins] = pwgsize->left; 4026 num_margins ++; 4027 } 4028 } 4029 4030 if (num_margins > 0) 4031 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4032 "media-left-margin-supported", num_margins, margins); 4033 else 4034 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4035 "media-left-margin-supported", 0); 4036 4037 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; 4038 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); 4039 i --, pwgsize ++) 4040 { 4041 for (j = 0; j < num_margins; j ++) 4042 if (pwgsize->right == margins[j]) 4043 break; 4044 4045 if (j >= num_margins) 4046 { 4047 margins[num_margins] = pwgsize->right; 4048 num_margins ++; 4049 } 4050 } 4051 4052 if (num_margins > 0) 4053 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4054 "media-right-margin-supported", num_margins, margins); 4055 else 4056 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4057 "media-right-margin-supported", 0); 4058 4059 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0; 4060 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0])); 4061 i --, pwgsize ++) 4062 { 4063 for (j = 0; j < num_margins; j ++) 4064 if (pwgsize->top == margins[j]) 4065 break; 4066 4067 if (j >= num_margins) 4068 { 4069 margins[num_margins] = pwgsize->top; 4070 num_margins ++; 4071 } 4072 } 4073 4074 if (num_margins > 0) 4075 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4076 "media-top-margin-supported", num_margins, margins); 4077 else 4078 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4079 "media-top-margin-supported", 0); 4080 4081 /* 4082 * media-col-database 4083 */ 4084 4085 num_media = p->pc->num_sizes; 4086 if (p->pc->num_sources) 4087 { 4088 if (p->pc->num_types > 0) 4089 num_media += p->pc->num_sizes * p->pc->num_sources * 4090 p->pc->num_types; 4091 else 4092 num_media += p->pc->num_sizes * p->pc->num_sources; 4093 } 4094 else if (p->pc->num_types) 4095 num_media += p->pc->num_sizes * p->pc->num_types; 4096 4097 if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, 4098 "media-col-database", num_media, 4099 NULL)) != NULL) 4100 { 4101 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values; 4102 i > 0; 4103 i --, pwgsize ++) 4104 { 4105 /* 4106 * Start by adding the page size without source or type... 4107 */ 4108 4109 ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd); 4110 4111 val->collection = new_media_col(pwgsize, NULL, NULL); 4112 val ++; 4113 4114 /* 4115 * Then add the specific, supported combinations of size, source, and 4116 * type... 4117 */ 4118 4119 if (p->pc->num_sources > 0) 4120 { 4121 for (j = p->pc->num_sources, pwgsource = p->pc->sources; 4122 j > 0; 4123 j --, pwgsource ++) 4124 { 4125 ppdMarkOption(ppd, "InputSlot", pwgsource->ppd); 4126 4127 if (p->pc->num_types > 0) 4128 { 4129 for (k = p->pc->num_types, pwgtype = p->pc->types; 4130 k > 0; 4131 k --, pwgtype ++) 4132 { 4133 if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd)) 4134 { 4135 val->collection = new_media_col(pwgsize, pwgsource->pwg, 4136 pwgtype->pwg); 4137 val ++; 4138 } 4139 } 4140 } 4141 else if (!ppdConflicts(ppd)) 4142 { 4143 val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL); 4144 val ++; 4145 } 4146 } 4147 } 4148 else if (p->pc->num_types > 0) 4149 { 4150 for (j = p->pc->num_types, pwgtype = p->pc->types; 4151 j > 0; 4152 j --, pwgtype ++) 4153 { 4154 if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd)) 4155 { 4156 val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg); 4157 val ++; 4158 } 4159 } 4160 } 4161 } 4162 4163 /* 4164 * Update the number of media-col-database values... 4165 */ 4166 4167 attr->num_values = val - attr->values; 4168 } 4169 } 4170 4171 /* 4172 * Output bin... 4173 */ 4174 4175 if (p->pc && p->pc->num_bins > 0) 4176 { 4177 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4178 "output-bin-supported", p->pc->num_bins, 4179 NULL, NULL); 4180 4181 if (attr != NULL) 4182 { 4183 for (i = 0, val = attr->values; 4184 i < p->pc->num_bins; 4185 i ++, val ++) 4186 val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg); 4187 } 4188 4189 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL) 4190 { 4191 for (i = 0; i < p->pc->num_bins; i ++) 4192 if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice)) 4193 break; 4194 4195 if (i >= p->pc->num_bins) 4196 i = 0; 4197 4198 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4199 "output-bin-default", NULL, p->pc->bins[i].pwg); 4200 } 4201 else 4202 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4203 "output-bin-default", NULL, p->pc->bins[0].pwg); 4204 } 4205 else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder", 4206 NULL)) != NULL && 4207 !_cups_strcasecmp(ppd_attr->value, "Reverse")) || 4208 (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */ 4209 (!_cups_strcasecmp(ppd->manufacturer, "epson") || 4210 !_cups_strcasecmp(ppd->manufacturer, "lexmark")))) 4211 { 4212 /* 4213 * Report that this printer has a single output bin that leaves pages face 4214 * up. 4215 */ 4216 4217 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4218 "output-bin-supported", NULL, "face-up"); 4219 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4220 "output-bin-default", NULL, "face-up"); 4221 } 4222 else 4223 { 4224 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4225 "output-bin-supported", NULL, "face-down"); 4226 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4227 "output-bin-default", NULL, "face-down"); 4228 } 4229 4230 /* 4231 * print-color-mode... 4232 */ 4233 4234 if (ppd->color_device) 4235 { 4236 static const char * const color_modes[] = 4237 { 4238 "monochrome", 4239 "color" 4240 }; 4241 4242 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4243 "print-color-mode-supported", 2, NULL, color_modes); 4244 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4245 "print-color-mode-default", NULL, "color"); 4246 } 4247 else 4248 { 4249 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4250 "print-color-mode-supported", NULL, "monochrome"); 4251 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4252 "print-color-mode-default", NULL, "monochrome"); 4253 } 4254 4255 /* 4256 * Mandatory job attributes, if any... 4257 */ 4258 4259 if (p->pc && cupsArrayCount(p->pc->mandatory) > 0) 4260 { 4261 int count = cupsArrayCount(p->pc->mandatory); 4262 /* Number of mandatory attributes */ 4263 4264 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4265 "printer-mandatory-job-attributes", count, NULL, 4266 NULL); 4267 4268 for (val = attr->values, 4269 mandatory = (char *)cupsArrayFirst(p->pc->mandatory); 4270 mandatory; 4271 val ++, mandatory = (char *)cupsArrayNext(p->pc->mandatory)) 4272 val->string.text = _cupsStrAlloc(mandatory); 4273 } 4274 4275 /* 4276 * Printer resolutions... 4277 */ 4278 4279 if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL) 4280 if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL) 4281 if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL) 4282 resolution = ppdFindOption(ppd, "CNRes_PGP"); 4283 4284 if (resolution) 4285 { 4286 /* 4287 * Report all supported resolutions... 4288 */ 4289 4290 attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER, 4291 "printer-resolution-supported", 4292 resolution->num_choices, IPP_RES_PER_INCH, 4293 NULL, NULL); 4294 4295 for (i = 0, choice = resolution->choices; 4296 i < resolution->num_choices; 4297 i ++, choice ++) 4298 { 4299 xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10); 4300 if (resptr > choice->choice && xdpi > 0 && *resptr == 'x') 4301 ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10); 4302 4303 if (xdpi <= 0 || ydpi <= 0) 4304 { 4305 cupsdLogMessage(CUPSD_LOG_WARN, 4306 "Bad resolution \"%s\" for printer %s.", 4307 choice->choice, p->name); 4308 xdpi = ydpi = 300; 4309 } 4310 4311 attr->values[i].resolution.xres = xdpi; 4312 attr->values[i].resolution.yres = ydpi; 4313 attr->values[i].resolution.units = IPP_RES_PER_INCH; 4314 4315 if (choice->marked) 4316 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, 4317 "printer-resolution-default", IPP_RES_PER_INCH, 4318 xdpi, ydpi); 4319 } 4320 } 4321 else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL && 4322 ppd_attr->value) 4323 { 4324 /* 4325 * Just the DefaultResolution to report... 4326 */ 4327 4328 xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10); 4329 if (resptr > ppd_attr->value && xdpi > 0) 4330 { 4331 if (*resptr == 'x') 4332 ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10); 4333 else 4334 ydpi = xdpi; 4335 } 4336 4337 if (xdpi <= 0 || ydpi <= 0) 4338 { 4339 cupsdLogMessage(CUPSD_LOG_WARN, 4340 "Bad default resolution \"%s\" for printer %s.", 4341 ppd_attr->value, p->name); 4342 xdpi = ydpi = 300; 4343 } 4344 4345 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, 4346 "printer-resolution-default", IPP_RES_PER_INCH, 4347 xdpi, ydpi); 4348 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, 4349 "printer-resolution-supported", IPP_RES_PER_INCH, 4350 xdpi, ydpi); 4351 } 4352 else 4353 { 4354 /* 4355 * No resolutions in PPD - make one up... 4356 */ 4357 4358 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, 4359 "printer-resolution-default", IPP_RES_PER_INCH, 4360 300, 300); 4361 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, 4362 "printer-resolution-supported", IPP_RES_PER_INCH, 4363 300, 300); 4364 } 4365 4366 /* 4367 * Duplexing, etc... 4368 */ 4369 4370 ppdMarkDefaults(ppd); 4371 4372 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL) 4373 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL) 4374 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL) 4375 if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL) 4376 duplex = ppdFindOption(ppd, "JCLDuplex"); 4377 4378 if (duplex && duplex->num_choices > 1 && 4379 !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble")) 4380 { 4381 p->type |= CUPS_PRINTER_DUPLEX; 4382 4383 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4384 "sides-supported", 3, NULL, sides); 4385 4386 if (!_cups_strcasecmp(duplex->defchoice, "DuplexTumble")) 4387 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4388 "sides-default", NULL, "two-sided-short-edge"); 4389 else if (!_cups_strcasecmp(duplex->defchoice, "DuplexNoTumble")) 4390 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4391 "sides-default", NULL, "two-sided-long-edge"); 4392 else 4393 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4394 "sides-default", NULL, "one-sided"); 4395 } 4396 else 4397 { 4398 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4399 "sides-supported", NULL, "one-sided"); 4400 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4401 "sides-default", NULL, "one-sided"); 4402 } 4403 4404 if (ppdFindOption(ppd, "Collate") != NULL) 4405 p->type |= CUPS_PRINTER_COLLATE; 4406 4407 if (ppdFindOption(ppd, "StapleLocation") != NULL) 4408 { 4409 p->type |= CUPS_PRINTER_STAPLE; 4410 finishings[num_finishings++] = IPP_FINISHINGS_STAPLE; 4411 } 4412 4413 if (ppdFindOption(ppd, "BindEdge") != NULL) 4414 { 4415 p->type |= CUPS_PRINTER_BIND; 4416 finishings[num_finishings++] = IPP_FINISHINGS_BIND; 4417 } 4418 4419 for (i = 0; i < ppd->num_sizes; i ++) 4420 if (ppd->sizes[i].length > 1728) 4421 p->type |= CUPS_PRINTER_LARGE; 4422 else if (ppd->sizes[i].length > 1008) 4423 p->type |= CUPS_PRINTER_MEDIUM; 4424 else 4425 p->type |= CUPS_PRINTER_SMALL; 4426 4427 if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL && 4428 ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true")) 4429 { 4430 if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL && 4431 ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true")) 4432 p->type |= CUPS_PRINTER_SCANNER; 4433 else 4434 p->type |= CUPS_PRINTER_MFP; 4435 } 4436 4437 /* 4438 * Scan the filters in the PPD file... 4439 */ 4440 4441 if (p->pc) 4442 { 4443 for (filter = (const char *)cupsArrayFirst(p->pc->filters); 4444 filter; 4445 filter = (const char *)cupsArrayNext(p->pc->filters)) 4446 { 4447 if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) && 4448 _cups_isspace(filter[28])) 4449 { 4450 p->type |= CUPS_PRINTER_COMMANDS; 4451 break; 4452 } 4453 } 4454 } 4455 4456 if (p->type & CUPS_PRINTER_COMMANDS) 4457 { 4458 char *commands, /* Copy of commands */ 4459 *start, /* Start of name */ 4460 *end; /* End of name */ 4461 int count; /* Number of commands */ 4462 4463 if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL) 4464 { 4465 for (count = 0, start = ppd_attr->value; *start; count ++) 4466 { 4467 while (_cups_isspace(*start)) 4468 start ++; 4469 4470 if (!*start) 4471 break; 4472 4473 while (*start && !isspace(*start & 255)) 4474 start ++; 4475 } 4476 } 4477 else 4478 count = 0; 4479 4480 if (count > 0) 4481 { 4482 /* 4483 * Make a copy of the commands string and count how many commands there 4484 * are... 4485 */ 4486 4487 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4488 "printer-commands", count, NULL, NULL); 4489 4490 commands = strdup(ppd_attr->value); 4491 4492 for (count = 0, start = commands; *start; count ++) 4493 { 4494 while (isspace(*start & 255)) 4495 start ++; 4496 4497 if (!*start) 4498 break; 4499 4500 end = start; 4501 while (*end && !isspace(*end & 255)) 4502 end ++; 4503 4504 if (*end) 4505 *end++ = '\0'; 4506 4507 attr->values[count].string.text = _cupsStrAlloc(start); 4508 4509 start = end; 4510 } 4511 4512 free(commands); 4513 } 4514 else 4515 { 4516 /* 4517 * Add the standard list of commands... 4518 */ 4519 4520 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4521 "printer-commands", 4522 (int)(sizeof(standard_commands) / 4523 sizeof(standard_commands[0])), NULL, 4524 standard_commands); 4525 } 4526 } 4527 else 4528 { 4529 /* 4530 * No commands supported... 4531 */ 4532 4533 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, 4534 "printer-commands", NULL, "none"); 4535 } 4536 4537 /* 4538 * Show current and available port monitors for this printer... 4539 */ 4540 4541 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor", 4542 NULL, p->port_monitor ? p->port_monitor : "none"); 4543 4544 for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); 4545 ppd_attr; 4546 i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)); 4547 4548 if (ppd->protocols) 4549 { 4550 if (strstr(ppd->protocols, "TBCP")) 4551 i ++; 4552 else if (strstr(ppd->protocols, "BCP")) 4553 i ++; 4554 } 4555 4556 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, 4557 "port-monitor-supported", i, NULL, NULL); 4558 4559 attr->values[0].string.text = _cupsStrAlloc("none"); 4560 4561 for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); 4562 ppd_attr; 4563 i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)) 4564 attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value); 4565 4566 if (ppd->protocols) 4567 { 4568 if (strstr(ppd->protocols, "TBCP")) 4569 attr->values[i].string.text = _cupsStrAlloc("tbcp"); 4570 else if (strstr(ppd->protocols, "BCP")) 4571 attr->values[i].string.text = _cupsStrAlloc("bcp"); 4572 } 4573 4574 if (ppdFindAttr(ppd, "APRemoteQueueID", NULL)) 4575 p->type |= CUPS_PRINTER_REMOTE; 4576 4577#ifdef HAVE_APPLICATIONSERVICES_H 4578 /* 4579 * Convert the file referenced in APPrinterIconPath to a 128x128 PNG 4580 * and save it as cacheDir/printername.png 4581 */ 4582 4583 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL && 4584 ppd_attr->value && 4585 !_cupsFileCheck(ppd_attr->value, _CUPS_FILE_CHECK_FILE, !RunUser, 4586 cupsdLogFCMessage, p)) 4587 { 4588 CGImageRef imageRef = NULL;/* Current icon image */ 4589 CGImageRef biggestIconRef = NULL; 4590 /* Biggest icon image */ 4591 CGImageRef closestTo128IconRef = NULL; 4592 /* Icon image closest to and >= 128 */ 4593 CGImageSourceRef sourceRef; /* The file's image source */ 4594 char outPath[HTTP_MAX_URI]; 4595 /* The path to the PNG file */ 4596 CFURLRef outUrl; /* The URL made from the outPath */ 4597 CFURLRef icnsFileUrl; /* The URL of the original ICNS icon file */ 4598 CGImageDestinationRef destRef; /* The image destination to write */ 4599 size_t bytesPerRow; /* The bytes per row used for resizing */ 4600 CGContextRef context; /* The CG context used for resizing */ 4601 4602 snprintf(outPath, sizeof(outPath), "%s/%s.png", CacheDir, p->name); 4603 outUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 4604 (UInt8 *)outPath, 4605 strlen(outPath), 4606 FALSE); 4607 icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 4608 (UInt8 *)ppd_attr->value, 4609 strlen(ppd_attr->value), 4610 FALSE); 4611 if (outUrl && icnsFileUrl) 4612 { 4613 sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL); 4614 if (sourceRef) 4615 { 4616 for (i = 0; i < CGImageSourceGetCount(sourceRef); i ++) 4617 { 4618 imageRef = CGImageSourceCreateImageAtIndex(sourceRef, i, NULL); 4619 if (!imageRef) 4620 continue; 4621 4622 if (CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef)) 4623 { 4624 /* 4625 * Loop through remembering the icon closest to 128 but >= 128 4626 * and then remember the largest icon. 4627 */ 4628 4629 if (CGImageGetWidth(imageRef) >= 128 && 4630 (!closestTo128IconRef || 4631 CGImageGetWidth(imageRef) < 4632 CGImageGetWidth(closestTo128IconRef))) 4633 { 4634 CGImageRelease(closestTo128IconRef); 4635 CGImageRetain(imageRef); 4636 closestTo128IconRef = imageRef; 4637 } 4638 4639 if (!biggestIconRef || 4640 CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef)) 4641 { 4642 CGImageRelease(biggestIconRef); 4643 CGImageRetain(imageRef); 4644 biggestIconRef = imageRef; 4645 } 4646 } 4647 4648 CGImageRelease(imageRef); 4649 } 4650 4651 if (biggestIconRef) 4652 { 4653 /* 4654 * If biggestIconRef is NULL, we found no icons. Otherwise we first 4655 * want the closest to 128, but if none are larger than 128, we want 4656 * the largest icon available. 4657 */ 4658 4659 imageRef = closestTo128IconRef ? closestTo128IconRef : 4660 biggestIconRef; 4661 CGImageRetain(imageRef); 4662 CGImageRelease(biggestIconRef); 4663 if (closestTo128IconRef) 4664 CGImageRelease(closestTo128IconRef); 4665 destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1, 4666 NULL); 4667 if (destRef) 4668 { 4669 if (CGImageGetWidth(imageRef) != 128) 4670 { 4671 bytesPerRow = CGImageGetBytesPerRow(imageRef) / 4672 CGImageGetWidth(imageRef) * 128; 4673 context = CGBitmapContextCreate(NULL, 128, 128, 4674 CGImageGetBitsPerComponent(imageRef), 4675 bytesPerRow, 4676 CGImageGetColorSpace(imageRef), 4677 kCGImageAlphaPremultipliedFirst); 4678 if (context) 4679 { 4680 CGContextDrawImage(context, CGRectMake(0, 0, 128, 128), 4681 imageRef); 4682 CGImageRelease(imageRef); 4683 imageRef = CGBitmapContextCreateImage(context); 4684 CGContextRelease(context); 4685 } 4686 } 4687 4688 CGImageDestinationAddImage(destRef, imageRef, NULL); 4689 CGImageDestinationFinalize(destRef); 4690 CFRelease(destRef); 4691 } 4692 4693 CGImageRelease(imageRef); 4694 } 4695 4696 CFRelease(sourceRef); 4697 } 4698 } 4699 4700 if (outUrl) 4701 CFRelease(outUrl); 4702 4703 if (icnsFileUrl) 4704 CFRelease(icnsFileUrl); 4705 } 4706#endif /* HAVE_APPLICATIONSERVICES_H */ 4707 4708 /* 4709 * Close the PPD and set the type... 4710 */ 4711 4712 ppdClose(ppd); 4713 } 4714 else if (!access(ppd_name, 0)) 4715 { 4716 int pline; /* PPD line number */ 4717 ppd_status_t pstatus; /* PPD load status */ 4718 4719 4720 pstatus = ppdLastError(&pline); 4721 4722 cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!", 4723 p->name); 4724 4725 if (pstatus <= PPD_ALLOC_ERROR) 4726 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno)); 4727 else 4728 cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.", 4729 ppdErrorString(pstatus), pline); 4730 4731 cupsdLogMessage(CUPSD_LOG_INFO, 4732 "Hint: Run \"cupstestppd %s\" and fix any errors.", 4733 ppd_name); 4734 } 4735 else 4736 { 4737 /* 4738 * If we have an interface script, add a filter entry for it... 4739 */ 4740 4741 char interface[1024]; /* Interface script */ 4742 4743 4744 snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot, 4745 p->name); 4746 if (!access(interface, X_OK)) 4747 { 4748 /* 4749 * Yes, we have a System V style interface script; use it! 4750 */ 4751 4752 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, 4753 "printer-make-and-model", NULL, 4754 "Local System V Printer"); 4755 } 4756 else if (((!strncmp(p->device_uri, "ipp://", 6) || 4757 !strncmp(p->device_uri, "ipps://", 7)) && 4758 (strstr(p->device_uri, "/printers/") != NULL || 4759 strstr(p->device_uri, "/classes/") != NULL)) || 4760 ((strstr(p->device_uri, "._ipp.") != NULL || 4761 strstr(p->device_uri, "._ipps.") != NULL) && 4762 !strcmp(p->device_uri + strlen(p->device_uri) - 5, "/cups"))) 4763 { 4764 /* 4765 * Tell the client this is really a hard-wired remote printer. 4766 */ 4767 4768 p->type |= CUPS_PRINTER_REMOTE; 4769 4770 /* 4771 * Point the printer-uri-supported attribute to the 4772 * remote printer... 4773 */ 4774 4775 if (strchr(p->device_uri, '?')) 4776 { 4777 /* 4778 * Strip trailing "?options" from URI... 4779 */ 4780 4781 char resource[HTTP_MAX_URI], /* New URI */ 4782 *ptr; /* Pointer into URI */ 4783 4784 strlcpy(resource, p->device_uri, sizeof(resource)); 4785 if ((ptr = strchr(resource, '?')) != NULL) 4786 *ptr = '\0'; 4787 4788 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, 4789 "printer-uri-supported", NULL, resource); 4790 } 4791 else 4792 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, 4793 "printer-uri-supported", NULL, p->device_uri); 4794 4795 /* 4796 * Then set the make-and-model accordingly... 4797 */ 4798 4799 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, 4800 "printer-make-and-model", NULL, "Remote Printer"); 4801 4802 /* 4803 * Print all files directly... 4804 */ 4805 4806 p->raw = 1; 4807 p->remote = 1; 4808 } 4809 else 4810 { 4811 /* 4812 * Otherwise we have neither - treat this as a "dumb" printer 4813 * with no PPD file... 4814 */ 4815 4816 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, 4817 "printer-make-and-model", NULL, "Local Raw Printer"); 4818 4819 p->raw = 1; 4820 } 4821 } 4822 4823 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, 4824 "finishings-supported", num_finishings, finishings); 4825 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, 4826 "finishings-default", IPP_FINISHINGS_NONE); 4827 4828 if (ppd && p->pc) 4829 { 4830 /* 4831 * Save cached PPD attributes to disk... 4832 */ 4833 4834 cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name); 4835 4836 _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs); 4837 } 4838 else 4839 { 4840 /* 4841 * Remove cache files... 4842 */ 4843 4844 if (cache_info.st_mtime) 4845 unlink(cache_name); 4846 } 4847} 4848 4849 4850/* 4851 * 'new_media_col()' - Create a media-col collection value. 4852 */ 4853 4854static ipp_t * /* O - Collection value */ 4855new_media_col(_pwg_size_t *size, /* I - media-size/margin values */ 4856 const char *source, /* I - media-source value */ 4857 const char *type) /* I - media-type value */ 4858{ 4859 ipp_t *media_col, /* Collection value */ 4860 *media_size; /* media-size value */ 4861 4862 4863 media_col = ippNew(); 4864 4865 media_size = ippNew(); 4866 ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4867 "x-dimension", size->width); 4868 ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4869 "y-dimension", size->length); 4870 ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); 4871 ippDelete(media_size); 4872 4873 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4874 "media-bottom-margin", size->bottom); 4875 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4876 "media-left-margin", size->left); 4877 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4878 "media-right-margin", size->right); 4879 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, 4880 "media-top-margin", size->top); 4881 4882 if (source) 4883 ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source", 4884 NULL, source); 4885 4886 if (type) 4887 ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type", 4888 NULL, type); 4889 4890 return (media_col); 4891} 4892 4893 4894/* 4895 * 'write_xml_string()' - Write a string with XML escaping. 4896 */ 4897 4898static void 4899write_xml_string(cups_file_t *fp, /* I - File to write to */ 4900 const char *s) /* I - String to write */ 4901{ 4902 const char *start; /* Start of current sequence */ 4903 4904 4905 if (!s) 4906 return; 4907 4908 for (start = s; *s; s ++) 4909 { 4910 if (*s == '&') 4911 { 4912 if (s > start) 4913 cupsFileWrite(fp, start, s - start); 4914 4915 cupsFilePuts(fp, "&"); 4916 start = s + 1; 4917 } 4918 else if (*s == '<') 4919 { 4920 if (s > start) 4921 cupsFileWrite(fp, start, s - start); 4922 4923 cupsFilePuts(fp, "<"); 4924 start = s + 1; 4925 } 4926 } 4927 4928 if (s > start) 4929 cupsFilePuts(fp, start); 4930} 4931 4932 4933/* 4934 * End of "$Id: printers.c 11693 2014-03-11 01:24:45Z msweet $". 4935 */ 4936