]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/printers.c
b3d5081e041087c2cbe7a02c06b290b6d611ecf1
[thirdparty/cups.git] / scheduler / printers.c
1 /*
2 * "$Id: printers.c 11623 2014-02-19 20:18:10Z 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
45 static void add_printer_defaults(cupsd_printer_t *p);
46 static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
47 const char *filter);
48 static void add_printer_formats(cupsd_printer_t *p);
49 static int compare_printers(void *first, void *second, void *data);
50 static void delete_printer_filters(cupsd_printer_t *p);
51 static void dirty_printer(cupsd_printer_t *p);
52 static void load_ppd(cupsd_printer_t *p);
53 static ipp_t *new_media_col(_pwg_size_t *size, const char *source,
54 const char *type);
55 static void write_xml_string(cups_file_t *fp, const char *s);
56
57
58 /*
59 * 'cupsdAddPrinter()' - Add a printer to the system.
60 */
61
62 cupsd_printer_t * /* O - New printer */
63 cupsdAddPrinter(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
135 void
136 cupsdCreateCommonData(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
648 void
649 cupsdDeleteAllPrinters(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
668 int /* O - 1 if classes affected, 0 otherwise */
669 cupsdDeletePrinter(
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
789 cupsd_printer_t * /* O - Destination in list */
790 cupsdFindDest(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
804 cupsd_printer_t * /* O - Printer in list */
805 cupsdFindPrinter(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
821 void
822 cupsdLoadAllPrinters(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
1262 void
1263 cupsdRenamePrinter(
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
1315 void
1316 cupsdSaveAllPrinters(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
1594 int /* O - 1 if value OK, 0 otherwise */
1595 cupsdSetAuthInfoRequired(
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
1757 void
1758 cupsdSetDeviceURI(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
1825 void
1826 cupsdSetPrinterAttr(
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
2004 void
2005 cupsdSetPrinterAttrs(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
2382 int /* O - 1 if something changed, 0 otherwise */
2383 cupsdSetPrinterReasons(
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
2517 void
2518 cupsdSetPrinterState(
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
2604 void
2605 cupsdStopPrinter(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
2628 int /* O - 1 if successful, 0 otherwise */
2629 cupsdUpdatePrinterPPD(
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
2740 void
2741 cupsdUpdatePrinters(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
2777 const char * /* O - Printer or class name */
2778 cupsdValidateDest(
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
2933 void
2934 cupsdWritePrintcap(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
3113 static void
3114 add_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
3219 static void
3220 add_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
3370 static void
3371 add_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
3525 static int /* O - Result of comparison */
3526 compare_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
3541 static void
3542 delete_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
3592 static void
3593 dirty_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
3609 static void
3610 load_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
4854 static ipp_t * /* O - Collection value */
4855 new_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
4898 static void
4899 write_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, "&amp;");
4916 start = s + 1;
4917 }
4918 else if (*s == '<')
4919 {
4920 if (s > start)
4921 cupsFileWrite(fp, start, s - start);
4922
4923 cupsFilePuts(fp, "&lt;");
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 11623 2014-02-19 20:18:10Z msweet $".
4935 */