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