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