]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/printers.c
Add missing DNSSD.LIB functions.
[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
2263 DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
2264 p->type));
2265
2266 /*
2267 * Make sure that we have the common attributes defined...
2268 */
2269
2270 if (!CommonData)
2271 cupsdCreateCommonData();
2272
95ece0cb
MS
2273 _cupsRWLockWrite(&p->lock);
2274
ef416fc2 2275 /*
2276 * Clear out old filters, if any...
2277 */
2278
e1d6a774 2279 delete_printer_filters(p);
ef416fc2 2280
2281 /*
2282 * Figure out the authentication that is required for the printer.
2283 */
2284
2285 auth_supported = "requesting-user-name";
ef416fc2 2286
178cb736
MS
2287 if (p->type & CUPS_PRINTER_CLASS)
2288 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
2289 else
2290 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
ef416fc2 2291
178cb736
MS
2292 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
2293 auth->type == CUPSD_AUTH_NONE)
2294 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
9a4f8274 2295
178cb736
MS
2296 if (auth)
2297 {
2298 int auth_type; /* Authentication type */
9a4f8274 2299
9a4f8274 2300
178cb736 2301 if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
dcb445bc 2302 auth_type = cupsdDefaultAuthType();
178cb736 2303
e0660879 2304 if (auth_type == CUPSD_AUTH_BASIC)
178cb736 2305 auth_supported = "basic";
f899b121 2306#ifdef HAVE_GSSAPI
178cb736
MS
2307 else if (auth_type == CUPSD_AUTH_NEGOTIATE)
2308 auth_supported = "negotiate";
f899b121 2309#endif /* HAVE_GSSAPI */
ef416fc2 2310
a2326b5b
MS
2311 if (auth_type != CUPSD_AUTH_NONE)
2312 p->type |= CUPS_PRINTER_AUTHENTICATED;
2313 else
7e86f2f6 2314 p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED;
bc44d920 2315 }
a2326b5b 2316 else
7e86f2f6 2317 p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED;
ef416fc2 2318
2319 /*
2320 * Create the required IPP attributes for a printer...
2321 */
2322
8922323b 2323 oldattrs = p->attrs;
ef416fc2 2324 p->attrs = ippNew();
2325
2326 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2327 "uri-authentication-supported", NULL, auth_supported);
2328 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2329 "uri-security-supported", NULL, "none");
409f5497
MS
2330 if (p->printer_id)
2331 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-id", p->printer_id);
ef416fc2 2332 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
2333 p->name);
2334 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
2335 NULL, p->location ? p->location : "");
9b4bd602
MS
2336 if (p->geo_location)
2337 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-geo-location", NULL, p->geo_location);
2338 else
2339 ippAddOutOfBand(p->attrs, IPP_TAG_PRINTER, IPP_TAG_UNKNOWN, "printer-geo-location");
ef416fc2 2340 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
2341 NULL, p->info ? p->info : "");
9b4bd602
MS
2342 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-organization", NULL, p->organization ? p->organization : "");
2343 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-organizational-unit", NULL, p->organizational_unit ? p->organizational_unit : "");
2344 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, p->uuid);
ef416fc2 2345
10d09e33 2346 if (cupsArrayCount(p->users) > 0)
ef416fc2 2347 {
2348 if (p->deny_users)
10d09e33
MS
2349 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2350 "requesting-user-name-denied",
2351 cupsArrayCount(p->users), NULL, NULL);
ef416fc2 2352 else
10d09e33
MS
2353 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2354 "requesting-user-name-allowed",
2355 cupsArrayCount(p->users), NULL, NULL);
2356
2357 for (i = 0, name = (char *)cupsArrayFirst(p->users);
2358 name;
2359 i ++, name = (char *)cupsArrayNext(p->users))
6961465f 2360 attr->values[i].string.text = _cupsStrAlloc(name);
ef416fc2 2361 }
2362
2363 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2364 "job-quota-period", p->quota_period);
2365 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2366 "job-k-limit", p->k_limit);
2367 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2368 "job-page-limit", p->page_limit);
cb7f98ee
MS
2369 if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
2370 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2371 "auth-info-required", p->num_auth_info_required, NULL,
2372 p->auth_info_required);
ef416fc2 2373
a2326b5b 2374 if (cupsArrayCount(Banners) > 0)
ef416fc2 2375 {
2376 /*
2377 * Setup the job-sheets-default attribute...
2378 */
2379
2380 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2381 "job-sheets-default", 2, NULL, NULL);
2382
2383 if (attr != NULL)
2384 {
757d2cad 2385 attr->values[0].string.text = _cupsStrAlloc(Classification ?
ef416fc2 2386 Classification : p->job_sheets[0]);
757d2cad 2387 attr->values[1].string.text = _cupsStrAlloc(Classification ?
ef416fc2 2388 Classification : p->job_sheets[1]);
2389 }
2390 }
2391
d09495fa 2392 p->raw = 0;
2393 p->remote = 0;
ef416fc2 2394
a2326b5b
MS
2395 /*
2396 * Assign additional attributes depending on whether this is a printer
2397 * or class...
2398 */
2399
2400 if (p->type & CUPS_PRINTER_CLASS)
ef416fc2 2401 {
a2326b5b 2402 p->raw = 1;
7e86f2f6 2403 p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS;
a2326b5b 2404
ef416fc2 2405 /*
a2326b5b 2406 * Add class-specific attributes...
ef416fc2 2407 */
2408
a2326b5b
MS
2409 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2410 "printer-make-and-model", NULL, "Local Printer Class");
2411 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
2412 "file:///dev/null");
2413
2414 if (p->num_printers > 0)
0268488e
MS
2415 {
2416 /*
a2326b5b 2417 * Add a list of member names; URIs are added in copy_printer_attrs...
0268488e
MS
2418 */
2419
a2326b5b
MS
2420 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2421 "member-names", p->num_printers, NULL, NULL);
2422 p->type |= CUPS_PRINTER_OPTIONS;
0268488e 2423
a2326b5b
MS
2424 for (i = 0; i < p->num_printers; i ++)
2425 {
2426 if (attr != NULL)
6961465f 2427 attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name);
0268488e 2428
7e86f2f6 2429 p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
a2326b5b 2430 }
0268488e 2431 }
ef416fc2 2432 }
2433 else
2434 {
2435 /*
a2326b5b 2436 * Add printer-specific attributes...
ef416fc2 2437 */
2438
a2326b5b
MS
2439 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
2440 p->sanitized_device_uri);
ef416fc2 2441
a2326b5b
MS
2442 /*
2443 * Assign additional attributes from the PPD file (if any)...
2444 */
fa73b229 2445
a2326b5b 2446 load_ppd(p);
ef416fc2 2447
a2326b5b
MS
2448 /*
2449 * Add filters for printer...
2450 */
ef416fc2 2451
a2326b5b
MS
2452 cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
2453 "cups-insecure-filter-warning");
ef416fc2 2454
a2326b5b
MS
2455 if (p->pc && p->pc->filters)
2456 {
2457 for (filter = (char *)cupsArrayFirst(p->pc->filters);
2458 filter;
2459 filter = (char *)cupsArrayNext(p->pc->filters))
2460 add_printer_filter(p, p->filetype, filter);
ef416fc2 2461 }
a2326b5b 2462 else if (!(p->type & CUPS_PRINTER_REMOTE))
ef416fc2 2463 {
e67e2f9e
MS
2464 /*
2465 * Add a filter from application/vnd.cups-raw to printer/name to
2466 * handle "raw" printing by users.
2467 */
f14324a7 2468
e67e2f9e 2469 add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
ef416fc2 2470
e67e2f9e
MS
2471 /*
2472 * Add a PostScript filter, since this is still possibly PS printer.
2473 */
f14324a7 2474
e67e2f9e
MS
2475 add_printer_filter(p, p->filetype,
2476 "application/vnd.cups-postscript 0 -");
a2326b5b 2477 }
f14324a7 2478
a2326b5b
MS
2479 if (p->pc && p->pc->prefilters)
2480 {
2481 if (!p->prefiltertype)
2482 p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
ef416fc2 2483
a2326b5b
MS
2484 for (filter = (char *)cupsArrayFirst(p->pc->prefilters);
2485 filter;
2486 filter = (char *)cupsArrayNext(p->pc->prefilters))
2487 add_printer_filter(p, p->prefiltertype, filter);
ef416fc2 2488 }
2489 }
2490
8922323b
MS
2491 /*
2492 * Copy marker attributes as needed...
2493 */
2494
2495 if (oldattrs)
2496 {
2497 ipp_attribute_t *oldattr; /* Old attribute */
2498
2499
2500 if ((oldattr = ippFindAttribute(oldattrs, "marker-colors",
2501 IPP_TAG_NAME)) != NULL)
2502 {
2503 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2504 "marker-colors", oldattr->num_values, NULL,
2505 NULL)) != NULL)
2506 {
2507 for (i = 0; i < oldattr->num_values; i ++)
2508 attr->values[i].string.text =
6961465f 2509 _cupsStrAlloc(oldattr->values[i].string.text);
8922323b
MS
2510 }
2511 }
2512
2513 if ((oldattr = ippFindAttribute(oldattrs, "marker-levels",
2514 IPP_TAG_INTEGER)) != NULL)
2515 {
2516 if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2517 "marker-levels", oldattr->num_values,
2518 NULL)) != NULL)
2519 {
2520 for (i = 0; i < oldattr->num_values; i ++)
2521 attr->values[i].integer = oldattr->values[i].integer;
2522 }
2523 }
2524
94da7e34
MS
2525 if ((oldattr = ippFindAttribute(oldattrs, "marker-message",
2526 IPP_TAG_TEXT)) != NULL)
2527 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "marker-message",
2528 NULL, oldattr->values[0].string.text);
2529
b9faaae1
MS
2530 if ((oldattr = ippFindAttribute(oldattrs, "marker-low-levels",
2531 IPP_TAG_INTEGER)) != NULL)
2532 {
2533 if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2534 "marker-low-levels", oldattr->num_values,
2535 NULL)) != NULL)
2536 {
2537 for (i = 0; i < oldattr->num_values; i ++)
2538 attr->values[i].integer = oldattr->values[i].integer;
2539 }
2540 }
2541
2542 if ((oldattr = ippFindAttribute(oldattrs, "marker-high-levels",
2543 IPP_TAG_INTEGER)) != NULL)
2544 {
2545 if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2546 "marker-high-levels", oldattr->num_values,
2547 NULL)) != NULL)
2548 {
2549 for (i = 0; i < oldattr->num_values; i ++)
2550 attr->values[i].integer = oldattr->values[i].integer;
2551 }
2552 }
2553
8922323b
MS
2554 if ((oldattr = ippFindAttribute(oldattrs, "marker-names",
2555 IPP_TAG_NAME)) != NULL)
2556 {
2557 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2558 "marker-names", oldattr->num_values, NULL,
2559 NULL)) != NULL)
2560 {
2561 for (i = 0; i < oldattr->num_values; i ++)
2562 attr->values[i].string.text =
6961465f 2563 _cupsStrAlloc(oldattr->values[i].string.text);
8922323b
MS
2564 }
2565 }
2566
2567 if ((oldattr = ippFindAttribute(oldattrs, "marker-types",
2568 IPP_TAG_KEYWORD)) != NULL)
2569 {
2570 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2571 "marker-types", oldattr->num_values, NULL,
2572 NULL)) != NULL)
2573 {
2574 for (i = 0; i < oldattr->num_values; i ++)
2575 attr->values[i].string.text =
6961465f 2576 _cupsStrAlloc(oldattr->values[i].string.text);
8922323b
MS
2577 }
2578 }
2579
2580 ippDelete(oldattrs);
2581 }
2582
b423cd4c 2583 /*
bc44d920 2584 * Force sharing off for remote queues...
b423cd4c 2585 */
2586
a2326b5b 2587 if (p->type & CUPS_PRINTER_REMOTE)
bc44d920 2588 p->shared = 0;
b423cd4c 2589
bd7854cb 2590 /*
2591 * Populate the document-format-supported attribute...
2592 */
2593
2594 add_printer_formats(p);
2595
ef416fc2 2596 DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
2597 p->type));
2598
b423cd4c 2599 /*
2600 * Add name-default attributes...
2601 */
2602
2603 add_printer_defaults(p);
2604
95ece0cb
MS
2605 _cupsRWUnlock(&p->lock);
2606
f7deaa1a 2607 /*
2608 * Let the browse protocols reflect the change
2609 */
2610
2611 cupsdRegisterPrinter(p);
ef416fc2 2612}
2613
2614
2615/*
2616 * 'cupsdSetPrinterReasons()' - Set/update the reasons strings.
2617 */
2618
e07d4801 2619int /* O - 1 if something changed, 0 otherwise */
ef416fc2 2620cupsdSetPrinterReasons(
c7017ecc
MS
2621 cupsd_printer_t *p, /* I - Printer */
2622 const char *s) /* I - Reasons strings */
ef416fc2 2623{
e07d4801
MS
2624 int i, /* Looping var */
2625 changed = 0; /* Did something change? */
ef416fc2 2626 const char *sptr; /* Pointer into reasons */
2627 char reason[255], /* Reason string */
2628 *rptr; /* Pointer into reason */
2629
2630
b9faaae1
MS
2631 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2632 "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s);
d1c13e16 2633
ef416fc2 2634 if (s[0] == '-' || s[0] == '+')
2635 {
2636 /*
2637 * Add/remove reasons...
2638 */
2639
2640 sptr = s + 1;
2641 }
2642 else
2643 {
2644 /*
2645 * Replace reasons...
2646 */
2647
2648 sptr = s;
2649
2650 for (i = 0; i < p->num_reasons; i ++)
0af14961 2651 _cupsStrFree(p->reasons[i]);
ef416fc2 2652
2653 p->num_reasons = 0;
e07d4801 2654 changed = 1;
0af14961 2655
0268488e 2656 dirty_printer(p);
ef416fc2 2657 }
2658
bc44d920 2659 if (!strcmp(s, "none"))
e07d4801 2660 return (changed);
bc44d920 2661
ef416fc2 2662 /*
2663 * Loop through all of the reasons...
2664 */
2665
2666 while (*sptr)
2667 {
2668 /*
2669 * Skip leading whitespace and commas...
2670 */
2671
2672 while (isspace(*sptr & 255) || *sptr == ',')
2673 sptr ++;
2674
2675 for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
2676 if (rptr < (reason + sizeof(reason) - 1))
2677 *rptr++ = *sptr;
2678
2679 if (rptr == reason)
2680 break;
2681
2682 *rptr = '\0';
2683
2684 if (s[0] == '-')
2685 {
2686 /*
2687 * Remove reason...
2688 */
2689
2690 for (i = 0; i < p->num_reasons; i ++)
d1c13e16 2691 if (!strcmp(reason, p->reasons[i]))
ef416fc2 2692 {
2693 /*
2694 * Found a match, so remove it...
2695 */
2696
2697 p->num_reasons --;
e07d4801 2698 changed = 1;
1f6f3dbc 2699 _cupsStrFree(p->reasons[i]);
ef416fc2 2700
2701 if (i < p->num_reasons)
7e86f2f6 2702 memmove(p->reasons + i, p->reasons + i + 1, (size_t)(p->num_reasons - i) * sizeof(char *));
ef416fc2 2703
c0e1af83 2704 if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED)
2705 cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
0af14961 2706
1e3e80bb 2707 if (!strcmp(reason, "cups-waiting-for-job-completed") && p->job)
581dae2d
MS
2708 p->job->completed = 0;
2709
e6013cfa 2710 if (strcmp(reason, "connecting-to-device"))
0268488e 2711 dirty_printer(p);
581dae2d 2712
d1c13e16 2713 break;
ef416fc2 2714 }
2715 }
2716 else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
2717 {
2718 /*
2719 * Add reason...
2720 */
2721
2722 for (i = 0; i < p->num_reasons; i ++)
d1c13e16 2723 if (!strcmp(reason, p->reasons[i]))
ef416fc2 2724 break;
2725
2726 if (i >= p->num_reasons)
2727 {
d1c13e16
MS
2728 if (i >= (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
2729 {
2730 cupsdLogMessage(CUPSD_LOG_ALERT,
2731 "Too many printer-state-reasons values for %s (%d)",
2732 p->name, i + 1);
e07d4801 2733 return (changed);
d1c13e16
MS
2734 }
2735
0af14961 2736 p->reasons[i] = _cupsStrAlloc(reason);
ef416fc2 2737 p->num_reasons ++;
e07d4801 2738 changed = 1;
c0e1af83 2739
2740 if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
2741 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
0af14961 2742
1e3e80bb 2743 if (!strcmp(reason, "cups-waiting-for-job-completed") && p->job)
581dae2d
MS
2744 p->job->completed = 1;
2745
e6013cfa 2746 if (strcmp(reason, "connecting-to-device"))
0268488e 2747 dirty_printer(p);
ef416fc2 2748 }
2749 }
2750 }
e07d4801
MS
2751
2752 return (changed);
ef416fc2 2753}
2754
2755
2756/*
2757 * 'cupsdSetPrinterState()' - Update the current state of a printer.
2758 */
2759
2760void
2761cupsdSetPrinterState(
2762 cupsd_printer_t *p, /* I - Printer to change */
2763 ipp_pstate_t s, /* I - New state */
2764 int update) /* I - Update printers.conf? */
2765{
12f89d24 2766 cupsd_job_t *job; /* Current job */
ef416fc2 2767 ipp_pstate_t old_state; /* Old printer state */
f8b3a85b
MS
2768 static const char * const printer_states[] =
2769 { /* State strings */
2770 "idle",
2771 "processing",
2772 "stopped"
2773 };
ef416fc2 2774
2775
ef416fc2 2776 /*
2777 * Set the new state...
2778 */
2779
2780 old_state = p->state;
2781 p->state = s;
2782
2783 if (old_state != s)
2784 {
0a682745 2785 cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED :
d9bca400 2786 CUPSD_EVENT_PRINTER_STATE, p, NULL,
f8b3a85b 2787 "%s \"%s\" state changed to %s.",
e53920b9 2788 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
0268488e 2789 p->name, printer_states[p->state - IPP_PRINTER_IDLE]);
e53920b9 2790
ef416fc2 2791 /*
2792 * Let the browse code know this needs to be updated...
2793 */
2794
a2326b5b 2795 p->state_time = time(NULL);
ef416fc2 2796 }
2797
b9faaae1
MS
2798 /*
2799 * Set/clear the paused reason as needed...
2800 */
2801
745129be
MS
2802 if (s == IPP_PRINTER_STOPPED)
2803 cupsdSetPrinterReasons(p, "+paused");
2804 else
2805 cupsdSetPrinterReasons(p, "-paused");
2806
12f89d24
MS
2807 if (old_state != s)
2808 {
2809 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
2810 job;
2811 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
2812 if (job->reasons && job->state_value == IPP_JOB_PENDING &&
2813 !_cups_strcasecmp(job->dest, p->name))
2814 ippSetString(job->attrs, &job->reasons, 0,
2815 s == IPP_PRINTER_STOPPED ? "printer-stopped" : "none");
2816 }
2817
b9faaae1
MS
2818 /*
2819 * Clear the message for the queue when going to processing...
2820 */
2821
2822 if (s == IPP_PRINTER_PROCESSING)
2823 p->state_message[0] = '\0';
2824
f7deaa1a 2825 /*
2826 * Let the browse protocols reflect the change...
2827 */
2828
7a14d768
MS
2829 if (update)
2830 cupsdRegisterPrinter(p);
f7deaa1a 2831
ef416fc2 2832 /*
2833 * Save the printer configuration if a printer goes from idle or processing
2834 * to stopped (or visa-versa)...
2835 */
2836
b9faaae1
MS
2837 if (update &&
2838 (old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
0268488e 2839 dirty_printer(p);
ef416fc2 2840}
2841
2842
2843/*
2844 * 'cupsdStopPrinter()' - Stop a printer from printing any jobs...
2845 */
2846
2847void
2848cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */
2849 int update)/* I - Update printers.conf? */
2850{
ef416fc2 2851 /*
2852 * Set the printer state...
2853 */
2854
2855 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
2856
2857 /*
2858 * See if we have a job printing on this printer...
2859 */
2860
f11a948a 2861 if (p->job && p->job->state_value == IPP_JOB_PROCESSING)
b9faaae1
MS
2862 cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
2863 "Job stopped due to printer being paused.");
ef416fc2 2864}
2865
2866
c9fc04c6
MS
2867/*
2868 * 'cupsdUpdatePrinterPPD()' - Update keywords in a printer's PPD file.
2869 */
2870
2871int /* O - 1 if successful, 0 otherwise */
2872cupsdUpdatePrinterPPD(
2873 cupsd_printer_t *p, /* I - Printer */
2874 int num_keywords, /* I - Number of keywords */
2875 cups_option_t *keywords) /* I - Keywords */
2876{
2877 int i; /* Looping var */
2878 cups_file_t *src, /* Original file */
2879 *dst; /* New file */
2880 char srcfile[1024], /* Original filename */
2881 dstfile[1024], /* New filename */
2882 line[1024], /* Line from file */
2883 keystring[41]; /* Keyword from line */
2884 cups_option_t *keyword; /* Current keyword */
2885
2886
2887 cupsdLogMessage(CUPSD_LOG_INFO, "Updating keywords in PPD file for %s...",
2888 p->name);
2889
2890 /*
2891 * Get the old and new PPD filenames...
2892 */
2893
2894 snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name);
2895 snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
2896
2897 /*
2898 * Rename the old file and open the old and new...
2899 */
2900
2901 if (rename(dstfile, srcfile))
2902 {
2903 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s",
2904 p->name, strerror(errno));
2905 return (0);
2906 }
2907
2908 if ((src = cupsFileOpen(srcfile, "r")) == NULL)
2909 {
2910 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s",
2911 srcfile, strerror(errno));
2912 rename(srcfile, dstfile);
2913 return (0);
2914 }
2915
2916 if ((dst = cupsFileOpen(dstfile, "w")) == NULL)
2917 {
2918 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s",
2919 dstfile, strerror(errno));
2920 cupsFileClose(src);
2921 rename(srcfile, dstfile);
2922 return (0);
2923 }
2924
2925 /*
2926 * Copy the first line and then write out all of the keywords...
2927 */
2928
2929 if (!cupsFileGets(src, line, sizeof(line)))
2930 {
2931 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s",
2932 srcfile, strerror(errno));
2933 cupsFileClose(src);
2934 cupsFileClose(dst);
2935 rename(srcfile, dstfile);
2936 return (0);
2937 }
2938
2939 cupsFilePrintf(dst, "%s\n", line);
2940
2941 for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++)
2942 {
2943 cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value);
2944 cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value);
2945 }
2946
2947 /*
2948 * Then copy the rest of the PPD file, dropping any keywords we changed.
2949 */
2950
2951 while (cupsFileGets(src, line, sizeof(line)))
2952 {
2953 /*
2954 * Skip keywords we've already set...
2955 */
2956
2957 if (sscanf(line, "*%40[^:]:", keystring) == 1 &&
2958 cupsGetOption(keystring, num_keywords, keywords))
2959 continue;
2960
2961 /*
2962 * Otherwise write the line...
2963 */
2964
2965 cupsFilePrintf(dst, "%s\n", line);
2966 }
2967
2968 /*
2969 * Close files and return...
2970 */
2971
2972 cupsFileClose(src);
2973 cupsFileClose(dst);
2974
2975 return (1);
2976}
2977
2978
ef416fc2 2979/*
2980 * 'cupsdUpdatePrinters()' - Update printers after a partial reload.
2981 */
2982
2983void
2984cupsdUpdatePrinters(void)
2985{
2986 cupsd_printer_t *p; /* Current printer */
2987
2988
2989 /*
2990 * Loop through the printers and recreate the printer attributes
2991 * for any local printers since the policy and/or access control
2992 * stuff may have changed. Also, if browsing is disabled, remove
2993 * any remote printers...
2994 */
2995
2996 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2997 p;
2998 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2999 {
ef416fc2 3000 /*
3001 * Update the operation policy pointer...
3002 */
3003
3004 if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
3005 p->op_policy_ptr = DefaultPolicyPtr;
07725fee 3006
3007 /*
a2326b5b 3008 * Update printer attributes...
07725fee 3009 */
3010
a2326b5b 3011 cupsdSetPrinterAttrs(p);
ef416fc2 3012 }
3013}
3014
3015
3016/*
3017 * 'cupsdValidateDest()' - Validate a printer/class destination.
3018 */
3019
3020const char * /* O - Printer or class name */
3021cupsdValidateDest(
f7deaa1a 3022 const char *uri, /* I - Printer URI */
ef416fc2 3023 cups_ptype_t *dtype, /* O - Type (printer or class) */
3024 cupsd_printer_t **printer) /* O - Printer pointer */
3025{
3026 cupsd_printer_t *p; /* Current printer */
3027 char localname[1024],/* Localized hostname */
3028 *lptr, /* Pointer into localized hostname */
f7deaa1a 3029 *sptr, /* Pointer into server name */
3030 *rptr, /* Pointer into resource */
3031 scheme[32], /* Scheme portion of URI */
3032 username[64], /* Username portion of URI */
3033 hostname[HTTP_MAX_HOST],
3034 /* Host portion of URI */
3035 resource[HTTP_MAX_URI];
3036 /* Resource portion of URI */
3037 int port; /* Port portion of URI */
3038
3039
3040 DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
ef416fc2 3041 dtype, printer));
3042
3043 /*
3044 * Initialize return values...
3045 */
3046
3047 if (printer)
3048 *printer = NULL;
3049
f7deaa1a 3050 if (dtype)
3051 *dtype = (cups_ptype_t)0;
3052
3053 /*
3054 * Pull the hostname and resource from the URI...
3055 */
3056
3057 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
3058 username, sizeof(username), hostname, sizeof(hostname),
3059 &port, resource, sizeof(resource));
ef416fc2 3060
3061 /*
3062 * See if the resource is a class or printer...
3063 */
3064
3065 if (!strncmp(resource, "/classes/", 9))
3066 {
3067 /*
3068 * Class...
3069 */
3070
f7deaa1a 3071 rptr = resource + 9;
ef416fc2 3072 }
3073 else if (!strncmp(resource, "/printers/", 10))
3074 {
3075 /*
3076 * Printer...
3077 */
3078
f7deaa1a 3079 rptr = resource + 10;
ef416fc2 3080 }
3081 else
3082 {
3083 /*
3084 * Bad resource name...
3085 */
3086
3087 return (NULL);
3088 }
3089
3090 /*
3091 * See if the printer or class name exists...
3092 */
3093
f7deaa1a 3094 p = cupsdFindDest(rptr);
ef416fc2 3095
f7deaa1a 3096 if (p == NULL && strchr(rptr, '@') == NULL)
ef416fc2 3097 return (NULL);
3098 else if (p != NULL)
3099 {
3100 if (printer)
3101 *printer = p;
3102
f7deaa1a 3103 if (dtype)
a2326b5b 3104 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
f7deaa1a 3105
ef416fc2 3106 return (p->name);
3107 }
3108
3109 /*
3110 * Change localhost to the server name...
3111 */
3112
88f9aafc 3113 if (!_cups_strcasecmp(hostname, "localhost"))
f7deaa1a 3114 strlcpy(hostname, ServerName, sizeof(hostname));
ef416fc2 3115
3116 strlcpy(localname, hostname, sizeof(localname));
3117
88f9aafc 3118 if (!_cups_strcasecmp(hostname, ServerName))
ef416fc2 3119 {
3120 /*
3121 * Localize the hostname...
3122 */
3123
3124 lptr = strchr(localname, '.');
3125 sptr = strchr(ServerName, '.');
3126
3127 if (sptr != NULL && lptr != NULL)
3128 {
3129 /*
3130 * Strip the common domain name components...
3131 */
3132
3133 while (lptr != NULL)
3134 {
88f9aafc 3135 if (!_cups_strcasecmp(lptr, sptr))
ef416fc2 3136 {
3137 *lptr = '\0';
3138 break;
3139 }
3140 else
3141 lptr = strchr(lptr + 1, '.');
3142 }
3143 }
3144 }
3145
3146 DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
3147
3148 /*
3149 * Find a matching printer or class...
3150 */
3151
3152 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3153 p;
3154 p = (cupsd_printer_t *)cupsArrayNext(Printers))
88f9aafc
MS
3155 if (!_cups_strcasecmp(p->hostname, localname) &&
3156 !_cups_strcasecmp(p->name, rptr))
ef416fc2 3157 {
3158 if (printer)
3159 *printer = p;
3160
f7deaa1a 3161 if (dtype)
a2326b5b 3162 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
f7deaa1a 3163
ef416fc2 3164 return (p->name);
3165 }
3166
3167 return (NULL);
3168}
3169
3170
3171/*
3172 * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications
3173 * that need it...
3174 */
3175
3176void
3177cupsdWritePrintcap(void)
3178{
0af14961
MS
3179 int i; /* Looping var */
3180 cups_file_t *fp; /* Printcap file */
ef416fc2 3181 cupsd_printer_t *p; /* Current printer */
3182
3183
ef416fc2 3184 /*
3185 * See if we have a printcap file; if not, don't bother writing it.
3186 */
3187
3188 if (!Printcap || !*Printcap)
3189 return;
3190
68b10830
MS
3191 cupsdLogMessage(CUPSD_LOG_INFO, "Generating printcap %s...", Printcap);
3192
ef416fc2 3193 /*
3194 * Open the printcap file...
3195 */
3196
3197 if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
3198 return;
3199
3200 /*
3201 * Put a comment header at the top so that users will know where the
3202 * data has come from...
3203 */
3204
0af14961
MS
3205 if (PrintcapFormat != PRINTCAP_PLIST)
3206 cupsFilePrintf(fp, "# This file was automatically generated by cupsd(8) "
3207 "from the\n"
3208 "# %s/printers.conf file. All changes to this file\n"
3209 "# will be lost.\n", ServerRoot);
ef416fc2 3210
d1c13e16
MS
3211 /*
3212 * Write a new printcap with the current list of printers.
3213 */
3214
3215 switch (PrintcapFormat)
ef416fc2 3216 {
d1c13e16
MS
3217 case PRINTCAP_BSD :
3218 /*
3219 * Each printer is put in the file as:
3220 *
3221 * Printer1:
3222 * Printer2:
3223 * Printer3:
3224 * ...
3225 * PrinterN:
3226 */
ef416fc2 3227
d1c13e16
MS
3228 if (DefaultPrinter)
3229 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
3230 DefaultPrinter->info, ServerName,
3231 DefaultPrinter->name);
ef416fc2 3232
d1c13e16
MS
3233 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3234 p;
3235 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3236 if (p != DefaultPrinter)
3237 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
3238 ServerName, p->name);
3239 break;
0af14961 3240
d1c13e16
MS
3241 case PRINTCAP_PLIST :
3242 /*
3243 * Each printer is written as a dictionary in a plist file.
3244 * Currently the printer-name, printer-info, printer-is-accepting-jobs,
3245 * printer-location, printer-make-and-model, printer-state,
3246 * printer-state-reasons, printer-type, and (sanitized) device-uri.
3247 */
0af14961 3248
d1c13e16
MS
3249 cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
3250 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD "
3251 "PLIST 1.0//EN\" \"http://www.apple.com/DTDs/"
3252 "PropertyList-1.0.dtd\">\n"
3253 "<plist version=\"1.0\">\n"
3254 "<array>\n");
ef416fc2 3255
d1c13e16
MS
3256 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3257 p;
3258 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3259 {
3260 cupsFilePuts(fp, "\t<dict>\n"
3261 "\t\t<key>printer-name</key>\n"
3262 "\t\t<string>");
3263 write_xml_string(fp, p->name);
3264 cupsFilePuts(fp, "</string>\n"
3265 "\t\t<key>printer-info</key>\n"
3266 "\t\t<string>");
3267 write_xml_string(fp, p->info);
3268 cupsFilePrintf(fp, "</string>\n"
3269 "\t\t<key>printer-is-accepting-jobs</key>\n"
3270 "\t\t<%s/>\n"
3271 "\t\t<key>printer-location</key>\n"
3272 "\t\t<string>", p->accepting ? "true" : "false");
3273 write_xml_string(fp, p->location);
3274 cupsFilePuts(fp, "</string>\n"
3275 "\t\t<key>printer-make-and-model</key>\n"
3276 "\t\t<string>");
3277 write_xml_string(fp, p->make_model);
3278 cupsFilePrintf(fp, "</string>\n"
3279 "\t\t<key>printer-state</key>\n"
3280 "\t\t<integer>%d</integer>\n"
3281 "\t\t<key>printer-state-reasons</key>\n"
3282 "\t\t<array>\n", p->state);
3283 for (i = 0; i < p->num_reasons; i ++)
3284 {
3285 cupsFilePuts(fp, "\t\t\t<string>");
3286 write_xml_string(fp, p->reasons[i]);
3287 cupsFilePuts(fp, "</string>\n");
3288 }
3289 cupsFilePrintf(fp, "\t\t</array>\n"
3290 "\t\t<key>printer-type</key>\n"
3291 "\t\t<integer>%d</integer>\n"
3292 "\t\t<key>device-uri</key>\n"
3293 "\t\t<string>", p->type);
3294 write_xml_string(fp, p->sanitized_device_uri);
3295 cupsFilePuts(fp, "</string>\n"
3296 "\t</dict>\n");
3297 }
3298 cupsFilePuts(fp, "</array>\n"
3299 "</plist>\n");
3300 break;
3301
3302 case PRINTCAP_SOLARIS :
3303 /*
3304 * Each printer is put in the file as:
3305 *
3306 * _all:all=Printer1,Printer2,Printer3,...,PrinterN
3307 * _default:use=DefaultPrinter
3308 * Printer1:\
3309 * :bsdaddr=ServerName,Printer1:\
3310 * :description=Description:
3311 * Printer2:
3312 * :bsdaddr=ServerName,Printer2:\
3313 * :description=Description:
3314 * Printer3:
3315 * :bsdaddr=ServerName,Printer3:\
3316 * :description=Description:
3317 * ...
3318 * PrinterN:
3319 * :bsdaddr=ServerName,PrinterN:\
3320 * :description=Description:
3321 */
3322
3323 cupsFilePuts(fp, "_all:all=");
3324 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3325 p;
3326 p = (cupsd_printer_t *)cupsArrayCurrent(Printers))
3327 cupsFilePrintf(fp, "%s%c", p->name,
3328 cupsArrayNext(Printers) ? ',' : '\n');
3329
3330 if (DefaultPrinter)
3331 cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
3332
3333 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3334 p;
3335 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3336 cupsFilePrintf(fp, "%s:\\\n"
3337 "\t:bsdaddr=%s,%s:\\\n"
3338 "\t:description=%s:\n",
3339 p->name, ServerName, p->name,
3340 p->info ? p->info : "");
3341 break;
ef416fc2 3342 }
3343
3344 /*
3345 * Close the file...
3346 */
3347
3348 cupsFileClose(fp);
3349}
3350
3351
b423cd4c 3352/*
3353 * 'add_printer_defaults()' - Add name-default attributes to the printer attributes.
3354 */
3355
3356static void
3357add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
3358{
3359 int i; /* Looping var */
3360 int num_options; /* Number of default options */
3361 cups_option_t *options, /* Default options */
3362 *option; /* Current option */
3363 char name[256]; /* name-default */
3364
3365
f7deaa1a 3366 /*
3367 * Maintain a common array of default attribute names...
3368 */
3369
3370 if (!CommonDefaults)
3371 {
3372 CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL);
3373
3374 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
3375 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
3376 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
5a9febac 3377 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-account-id-default"));
40cc612a 3378 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-accounting-user-id-default"));
ebaac3df 3379 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-cancel-after-default"));
f7deaa1a 3380 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
3381 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
3382 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
54afec33 3383 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default"));
40cc612a
MS
3384 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("notify-lease-duration-default"));
3385 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("notify-events-default"));
f7deaa1a 3386 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
40cc612a
MS
3387 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("orientation-requested-default"));
3388 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("print-quality-default"));
f7deaa1a 3389 }
3390
b423cd4c 3391 /*
3392 * Add all of the default options from the .conf files...
3393 */
3394
1f0275e3 3395 for (num_options = 0, options = NULL, i = p->num_options, option = p->options;
b423cd4c 3396 i > 0;
3397 i --, option ++)
3398 {
3399 if (strcmp(option->name, "ipp-options") &&
3400 strcmp(option->name, "job-sheets") &&
3401 strcmp(option->name, "lease-duration"))
3402 {
3403 snprintf(name, sizeof(name), "%s-default", option->name);
3404 num_options = cupsAddOption(name, option->value, num_options, &options);
f7deaa1a 3405
3406 if (!cupsArrayFind(CommonDefaults, name))
3407 cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name));
b423cd4c 3408 }
3409 }
3410
3411 /*
3412 * Convert options to IPP attributes...
3413 */
3414
3415 cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER);
3416 cupsFreeOptions(num_options, options);
3417
3418 /*
3419 * Add standard -default attributes as needed...
3420 */
3421
3422 if (!cupsGetOption("copies", p->num_options, p->options))
3423 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
3424 1);
3425
f7deaa1a 3426 if (!cupsGetOption("document-format", p->num_options, p->options))
c934a06c 3427 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
f7deaa1a 3428 "document-format-default", NULL, "application/octet-stream");
3429
ebaac3df
MS
3430 if (!cupsGetOption("job-cancel-after", p->num_options, p->options))
3431 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3432 "job-cancel-after-default", MaxJobTime);
3433
b423cd4c 3434 if (!cupsGetOption("job-hold-until", p->num_options, p->options))
3435 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3436 "job-hold-until-default", NULL, "no-hold");
3437
3438 if (!cupsGetOption("job-priority", p->num_options, p->options))
3439 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3440 "job-priority-default", 50);
3441
3442 if (!cupsGetOption("number-up", p->num_options, p->options))
3443 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3444 "number-up-default", 1);
3445
f7deaa1a 3446 if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
3447 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3448 "notify-lease-duration-default", DefaultLeaseDuration);
3449
3450 if (!cupsGetOption("notify-events", p->num_options, p->options))
3451 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3452 "notify-events-default", NULL, "job-completed");
ba55dc12
MS
3453
3454 if (!cupsGetOption("orientation-requested", p->num_options, p->options))
3455 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
3456 "orientation-requested-default", NULL, NULL);
3457
3458 if (!cupsGetOption("print-quality", p->num_options, p->options))
3459 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
3460 "print-quality-default", IPP_QUALITY_NORMAL);
b423cd4c 3461}
3462
3463
bd7854cb 3464/*
3465 * 'add_printer_filter()' - Add a MIME filter for a printer.
3466 */
3467
3468static void
3469add_printer_filter(
3470 cupsd_printer_t *p, /* I - Printer to add to */
f7deaa1a 3471 mime_type_t *filtertype, /* I - Filter or prefilter MIME type */
bd7854cb 3472 const char *filter) /* I - Filter to add */
3473{
3474 char super[MIME_MAX_SUPER], /* Super-type for filter */
3475 type[MIME_MAX_TYPE], /* Type for filter */
c8fef167
MS
3476 dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
3477 dtype[MIME_MAX_TYPE], /* Destination type for filter */
3478 dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
3479 /* Destination super/type */
bd7854cb 3480 program[1024]; /* Program/filter name */
3481 int cost; /* Cost of filter */
07ed0e9a 3482 size_t maxsize = 0; /* Maximum supported file size */
c8fef167
MS
3483 mime_type_t *temptype, /* MIME type looping var */
3484 *desttype; /* Destination MIME type */
22c9029b
MS
3485 mime_filter_t *filterptr; /* MIME filter */
3486 char filename[1024]; /* Full filter filename */
bd7854cb 3487
3488
f14324a7
MS
3489 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3490 "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), "
3491 "filter=\"%s\")", p, p->name, filtertype, filtertype->super,
3492 filtertype->type, filter);
3493
bd7854cb 3494 /*
c8fef167 3495 * Parse the filter string; it should be in one of the following formats:
bd7854cb 3496 *
c8fef167 3497 * source/type cost program
07ed0e9a 3498 * source/type cost maxsize(nnnn) program
c8fef167 3499 * source/type dest/type cost program
07ed0e9a 3500 * source/type dest/type cost maxsize(nnnn) program
bd7854cb 3501 */
3502
c8fef167
MS
3503 if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3504 super, type, dsuper, dtype, &cost, program) == 6)
bd7854cb 3505 {
f14324a7
MS
3506 snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype);
3507
3508 if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL)
3509 {
3510 desttype = mimeAddType(MimeDatabase, "printer", dest);
3511 if (!p->dest_types)
3512 p->dest_types = cupsArrayNew(NULL, NULL);
3513
3514 cupsArrayAdd(p->dest_types, desttype);
3515 }
3516
c8fef167
MS
3517 }
3518 else
3519 {
3520 if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
3521 program) == 4)
3522 {
f14324a7 3523 desttype = filtertype;
c8fef167
MS
3524 }
3525 else
3526 {
3527 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
3528 p->name, filter);
3529 return;
3530 }
bd7854cb 3531 }
3532
07ed0e9a
MS
3533 if (!strncmp(program, "maxsize(", 8))
3534 {
3535 char *ptr; /* Pointer into maxsize(nnnn) program */
3536
7e86f2f6 3537 maxsize = (size_t)strtoll(program + 8, &ptr, 10);
07ed0e9a
MS
3538
3539 if (*ptr != ')')
3540 {
3541 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
3542 p->name, filter);
3543 return;
3544 }
3545
3546 ptr ++;
3547 while (_cups_isspace(*ptr))
3548 ptr ++;
3549
3550 _cups_strcpy(program, ptr);
3551 }
3552
bd7854cb 3553 /*
22c9029b 3554 * Check permissions on the filter and its containing directory...
bd7854cb 3555 */
3556
ecdc0628 3557 if (strcmp(program, "-"))
bd7854cb 3558 {
ecdc0628 3559 if (program[0] == '/')
3560 strlcpy(filename, program, sizeof(filename));
3561 else
3562 snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
3563
88f9aafc
MS
3564 _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
3565 cupsdLogFCMessage, p);
bd7854cb 3566 }
3567
3568 /*
3569 * Add the filter to the MIME database, supporting wildcards as needed...
3570 */
3571
3572 for (temptype = mimeFirstType(MimeDatabase);
3573 temptype;
3574 temptype = mimeNextType(MimeDatabase))
88f9aafc
MS
3575 if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
3576 !_cups_strcasecmp(temptype->super, super)) &&
3577 (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
bd7854cb 3578 {
c8fef167
MS
3579 if (desttype != filtertype)
3580 {
3581 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3582 "add_printer_filter: %s: adding filter %s/%s %s/%s %d "
3583 "%s", p->name, temptype->super, temptype->type,
3584 desttype->super, desttype->type,
3585 cost, program);
22c9029b
MS
3586 filterptr = mimeAddFilter(MimeDatabase, temptype, desttype, cost,
3587 program);
c8fef167
MS
3588
3589 if (!mimeFilterLookup(MimeDatabase, desttype, filtertype))
3590 {
3591 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3592 "add_printer_filter: %s: adding filter %s/%s %s/%s "
3593 "0 -", p->name, desttype->super, desttype->type,
3594 filtertype->super, filtertype->type);
771bd8cb 3595 mimeAddFilter(MimeDatabase, desttype, filtertype, 0, "-");
c8fef167
MS
3596 }
3597 }
3598 else
3599 {
3600 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3601 "add_printer_filter: %s: adding filter %s/%s %s/%s %d "
3602 "%s", p->name, temptype->super, temptype->type,
3603 filtertype->super, filtertype->type,
3604 cost, program);
22c9029b
MS
3605 filterptr = mimeAddFilter(MimeDatabase, temptype, filtertype, cost,
3606 program);
c8fef167 3607 }
22c9029b
MS
3608
3609 if (filterptr)
3610 filterptr->maxsize = maxsize;
bd7854cb 3611 }
3612}
3613
3614
3615/*
3616 * 'add_printer_formats()' - Add document-format-supported values for a printer.
3617 */
3618
3619static void
3620add_printer_formats(cupsd_printer_t *p) /* I - Printer */
3621{
3622 int i; /* Looping var */
3623 mime_type_t *type; /* Current MIME type */
3624 cups_array_t *filters; /* Filters */
80ca4592 3625 ipp_attribute_t *attr; /* document-format-supported attribute */
bd7854cb 3626 char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
3627 /* MIME type name */
3628
3629
3630 /*
3631 * Raw (and remote) queues advertise all of the supported MIME
3632 * types...
3633 */
3634
80ca4592 3635 cupsArrayDelete(p->filetypes);
3636 p->filetypes = NULL;
3637
bd7854cb 3638 if (p->raw)
3639 {
3640 ippAddStrings(p->attrs, IPP_TAG_PRINTER,
3641 (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
3642 "document-format-supported", NumMimeTypes, NULL, MimeTypes);
3643 return;
3644 }
3645
3646 /*
3647 * Otherwise, loop through the supported MIME types and see if there
3648 * are filters for them...
3649 */
3650
bd7854cb 3651 cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
3652 mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
3653
80ca4592 3654 p->filetypes = cupsArrayNew(NULL, NULL);
bd7854cb 3655
80ca4592 3656 for (type = mimeFirstType(MimeDatabase);
bd7854cb 3657 type;
3658 type = mimeNextType(MimeDatabase))
3659 {
88f9aafc 3660 if (!_cups_strcasecmp(type->super, "printer"))
c8fef167
MS
3661 continue;
3662
bd7854cb 3663 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
3664
3665 if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
3666 {
3667 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3668 "add_printer_formats: %s: %s needs %d filters",
3669 p->name, mimetype, cupsArrayCount(filters));
3670
3671 cupsArrayDelete(filters);
80ca4592 3672 cupsArrayAdd(p->filetypes, type);
bd7854cb 3673 }
3674 else
3675 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3676 "add_printer_formats: %s: %s not supported",
3677 p->name, mimetype);
3678 }
3679
bd7854cb 3680 /*
3681 * Add the file formats that can be filtered...
3682 */
3683
f301802f 3684 if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
3685 !cupsArrayFind(p->filetypes, type))
3686 i = 1;
3687 else
3688 i = 0;
bd7854cb 3689
7a0cbd5e
MS
3690 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3691 "add_printer_formats: %s: %d supported types",
3692 p->name, cupsArrayCount(p->filetypes) + i);
3693
80ca4592 3694 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
3695 "document-format-supported",
7a0cbd5e 3696 cupsArrayCount(p->filetypes) + i, NULL, NULL);
80ca4592 3697
f301802f 3698 if (i)
3699 attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
bd7854cb 3700
f301802f 3701 for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
80ca4592 3702 type;
3703 i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
3704 {
3705 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
bd7854cb 3706
80ca4592 3707 attr->values[i].string.text = _cupsStrAlloc(mimetype);
3708 }
f7deaa1a 3709
f3c17241 3710#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
f7deaa1a 3711 {
3712 char pdl[1024]; /* Buffer to build pdl list */
3713 mime_filter_t *filter; /* MIME filter looping var */
3714
3715
f7deaa1a 3716 /*
ba55dc12
MS
3717 * We only support raw printing if this is not a Tioga PrintJobMgr based
3718 * queue and if application/octet-stream is a known type...
f7deaa1a 3719 */
3720
3721 for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
3722 filter;
3723 filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
3724 {
c8fdb001 3725 if (filter->dst == p->filetype && strstr(filter->filter, "PrintJobMgr"))
f7deaa1a 3726 break;
3727 }
3728
ba55dc12 3729 pdl[0] = '\0';
f7deaa1a 3730
3731 if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
3732 strlcat(pdl, "application/octet-stream,", sizeof(pdl));
3733
ba55dc12
MS
3734 /*
3735 * Then list a bunch of formats that are supported by the printer...
3736 */
3737
3738 for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
3739 type;
3740 type = (mime_type_t *)cupsArrayNext(p->filetypes))
3741 {
88f9aafc 3742 if (!_cups_strcasecmp(type->super, "application"))
ba55dc12 3743 {
88f9aafc 3744 if (!_cups_strcasecmp(type->type, "pdf"))
ba55dc12 3745 strlcat(pdl, "application/pdf,", sizeof(pdl));
88f9aafc 3746 else if (!_cups_strcasecmp(type->type, "postscript"))
ba55dc12
MS
3747 strlcat(pdl, "application/postscript,", sizeof(pdl));
3748 }
88f9aafc 3749 else if (!_cups_strcasecmp(type->super, "image"))
ba55dc12 3750 {
88f9aafc 3751 if (!_cups_strcasecmp(type->type, "jpeg"))
ba55dc12 3752 strlcat(pdl, "image/jpeg,", sizeof(pdl));
88f9aafc 3753 else if (!_cups_strcasecmp(type->type, "png"))
ba55dc12 3754 strlcat(pdl, "image/png,", sizeof(pdl));
88f9aafc 3755 else if (!_cups_strcasecmp(type->type, "pwg-raster"))
c8fef167 3756 strlcat(pdl, "image/pwg-raster,", sizeof(pdl));
ba55dc12
MS
3757 }
3758 }
f7deaa1a 3759
3760 if (pdl[0])
3761 pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */
3762
3763 cupsdSetString(&p->pdl, pdl);
3764 }
f3c17241 3765#endif /* HAVE_DNSSD || HAVE_AVAHI */
bd7854cb 3766}
3767
3768
ef416fc2 3769/*
3770 * 'compare_printers()' - Compare two printers.
3771 */
3772
3773static int /* O - Result of comparison */
3774compare_printers(void *first, /* I - First printer */
3775 void *second, /* I - Second printer */
3776 void *data) /* I - App data (not used) */
3777{
321d8d57
MS
3778 (void)data;
3779
88f9aafc 3780 return (_cups_strcasecmp(((cupsd_printer_t *)first)->name,
ef416fc2 3781 ((cupsd_printer_t *)second)->name));
3782}
3783
3784
bd7854cb 3785/*
e1d6a774 3786 * 'delete_printer_filters()' - Delete all MIME filters for a printer.
bd7854cb 3787 */
3788
3789static void
e1d6a774 3790delete_printer_filters(
3791 cupsd_printer_t *p) /* I - Printer to remove from */
bd7854cb 3792{
e1d6a774 3793 mime_filter_t *filter; /* MIME filter looping var */
c8fef167 3794 mime_type_t *type; /* Destination types for filters */
bd7854cb 3795
bd7854cb 3796
3797 /*
e1d6a774 3798 * Range check input...
bd7854cb 3799 */
3800
e1d6a774 3801 if (p == NULL)
3802 return;
bd7854cb 3803
3804 /*
e1d6a774 3805 * Remove all filters from the MIME database that have a destination
3806 * type == printer...
bd7854cb 3807 */
3808
e1d6a774 3809 for (filter = mimeFirstFilter(MimeDatabase);
3810 filter;
3811 filter = mimeNextFilter(MimeDatabase))
c8fef167
MS
3812 if (filter->dst == p->filetype || filter->dst == p->prefiltertype ||
3813 cupsArrayFind(p->dest_types, filter->dst))
e1d6a774 3814 {
3815 /*
3816 * Delete the current filter...
3817 */
bd7854cb 3818
e1d6a774 3819 mimeDeleteFilter(MimeDatabase, filter);
3820 }
b9faaae1 3821
c8fef167
MS
3822 for (type = (mime_type_t *)cupsArrayFirst(p->dest_types);
3823 type;
3824 type = (mime_type_t *)cupsArrayNext(p->dest_types))
3825 mimeDeleteType(MimeDatabase, type);
3826
3827 cupsArrayDelete(p->dest_types);
3828 p->dest_types = NULL;
3829
38e73f87
MS
3830 cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning"
3831 ",cups-missing-filter-warning");
bd7854cb 3832}
3833
3834
0268488e
MS
3835/*
3836 * 'dirty_printer()' - Mark config and state files dirty for the specified
3837 * printer.
3838 */
3839
3840static void
3841dirty_printer(cupsd_printer_t *p) /* I - Printer */
3842{
a2326b5b 3843 if (p->type & CUPS_PRINTER_CLASS)
0268488e
MS
3844 cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
3845 else
3846 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
3847
3848 if (PrintcapFormat == PRINTCAP_PLIST)
3849 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
3850}
3851
3852
61cf44e2
MS
3853/*
3854 * 'load_ppd()' - Load a cached PPD file, updating the cache as needed.
3855 */
3856
3857static void
3858load_ppd(cupsd_printer_t *p) /* I - Printer */
3859{
54afec33 3860 int i, j, k; /* Looping vars */
f14324a7
MS
3861 char cache_name[1024]; /* Cache filename */
3862 struct stat cache_info; /* Cache file info */
61cf44e2
MS
3863 ppd_file_t *ppd; /* PPD file */
3864 char ppd_name[1024]; /* PPD filename */
3865 struct stat ppd_info; /* PPD file info */
2fa1ba3c 3866 char strings_name[1024]; /* Strings filename */
61cf44e2 3867 int num_media; /* Number of media options */
54afec33 3868 ppd_size_t *size; /* Current PPD size */
5a6b583a
MS
3869 ppd_option_t *duplex, /* Duplex option */
3870 *output_bin, /* OutputBin option */
ba55dc12 3871 *output_mode, /* OutputMode option */
5a6b583a 3872 *resolution; /* (Set|JCL|)Resolution option */
54afec33
MS
3873 ppd_choice_t *choice, /* Current PPD choice */
3874 *input_slot, /* Current input slot */
3875 *media_type; /* Current media type */
61cf44e2 3876 ppd_attr_t *ppd_attr; /* PPD attribute */
5a6b583a
MS
3877 int xdpi, /* Horizontal resolution */
3878 ydpi; /* Vertical resolution */
3879 const char *resptr; /* Pointer into resolution keyword */
788d7a15
MS
3880 pwg_size_t *pwgsize; /* Current PWG size */
3881 pwg_map_t *pwgsource, /* Current PWG source */
54afec33 3882 *pwgtype; /* Current PWG type */
61cf44e2 3883 ipp_attribute_t *attr; /* Attribute data */
a2326b5b 3884 _ipp_value_t *val; /* Attribute value */
ba55dc12 3885 int num_finishings, /* Number of finishings */
84e3828d 3886 finishings[100]; /* finishings-supported values */
ba55dc12
MS
3887 int num_qualities, /* Number of print-quality values */
3888 qualities[3]; /* print-quality values */
54afec33
MS
3889 int num_margins, /* Number of media-*-margin-supported values */
3890 margins[16]; /* media-*-margin-supported values */
5a9febac
MS
3891 const char *filter, /* Current filter */
3892 *mandatory; /* Current mandatory attribute */
71d227bf
MS
3893 static const char * const pwg_raster_document_types[] =
3894 {
3895 "black_1",
3896 "sgray_8",
3897 "srgb_8"
3898 };
61cf44e2
MS
3899 static const char * const sides[3] = /* sides-supported values */
3900 {
3901 "one-sided",
3902 "two-sided-long-edge",
3903 "two-sided-short-edge"
3904 };
3905 static const char * const standard_commands[] =
3906 { /* Standard CUPS commands */
3907 "AutoConfigure",
3908 "Clean",
c168a833 3909 "PrintSelfTestPage"
61cf44e2
MS
3910 };
3911
3912
3913 /*
3914 * Check to see if the cache is up-to-date...
3915 */
3916
f14324a7 3917 snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name);
61cf44e2
MS
3918 if (stat(cache_name, &cache_info))
3919 cache_info.st_mtime = 0;
3920
3921 snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name);
3922 if (stat(ppd_name, &ppd_info))
3923 ppd_info.st_mtime = 1;
3924
2fa1ba3c
MS
3925 snprintf(strings_name, sizeof(strings_name), "%s/%s.strings", CacheDir, p->name);
3926
61cf44e2 3927 ippDelete(p->ppd_attrs);
22c9029b 3928 p->ppd_attrs = NULL;
61cf44e2 3929
f14324a7
MS
3930 _ppdCacheDestroy(p->pc);
3931 p->pc = NULL;
54afec33 3932
f14324a7 3933 if (cache_info.st_mtime >= ppd_info.st_mtime)
61cf44e2 3934 {
61cf44e2
MS
3935 cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
3936
f14324a7
MS
3937 if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL &&
3938 p->ppd_attrs)
61cf44e2 3939 {
f14324a7
MS
3940 /*
3941 * Loaded successfully!
3942 */
3943
61cf44e2
MS
3944 return;
3945 }
61cf44e2
MS
3946 }
3947
3948 /*
3949 * Reload PPD attributes from disk...
3950 */
3951
8b450588
MS
3952 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
3953
61cf44e2
MS
3954 cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
3955
caff6dba
MS
3956 cupsdClearString(&(p->make_model));
3957
7e86f2f6 3958 p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS;
61cf44e2
MS
3959 p->type |= CUPS_PRINTER_BW;
3960
3961 finishings[0] = IPP_FINISHINGS_NONE;
3962 num_finishings = 1;
3963
22c9029b
MS
3964 p->ppd_attrs = ippNew();
3965
9c80ffa2 3966 if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL)
61cf44e2
MS
3967 {
3968 /*
3969 * Add make/model and other various attributes...
3970 */
3971
f14324a7 3972 p->pc = _ppdCacheCreateWithPPD(ppd);
54afec33 3973
5a9febac
MS
3974 if (!p->pc)
3975 cupsdLogMessage(CUPSD_LOG_WARN, "Unable to create cache of \"%s\": %s",
3976 ppd_name, cupsLastErrorString());
3977
c168a833
MS
3978 ppdMarkDefaults(ppd);
3979
61cf44e2
MS
3980 if (ppd->color_device)
3981 p->type |= CUPS_PRINTER_COLOR;
3982 if (ppd->variable_sizes)
3983 p->type |= CUPS_PRINTER_VARIABLE;
3984 if (!ppd->manual_copies)
3985 p->type |= CUPS_PRINTER_COPIES;
3986 if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
88f9aafc 3987 if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
61cf44e2
MS
3988 p->type |= CUPS_PRINTER_FAX;
3989
7e86f2f6 3990 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported", (char)ppd->color_device);
5a9febac 3991
a469f8a5
MS
3992 if (p->pc && p->pc->charge_info_uri)
3993 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
3994 "printer-charge-info-uri", NULL, p->pc->charge_info_uri);
3995
5a9febac
MS
3996 if (p->pc && p->pc->account_id)
3997 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "job-account-id-supported",
3998 1);
3999
4000 if (p->pc && p->pc->accounting_user_id)
4001 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER,
4002 "job-accounting-user-id-supported", 1);
4003
4004 if (p->pc && p->pc->password)
4005 {
4006 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4007 "job-password-encryption-supported", NULL, "none");
4008 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
7e86f2f6 4009 "job-password-supported", (int)strlen(p->pc->password));
5a9febac
MS
4010 }
4011
61cf44e2 4012 if (ppd->throughput)
ba55dc12 4013 {
61cf44e2
MS
4014 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4015 "pages-per-minute", ppd->throughput);
ba55dc12
MS
4016 if (ppd->color_device)
4017 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4018 "pages-per-minute-color", ppd->throughput);
4019 }
e60ec91f
MS
4020 else
4021 {
4022 /*
4023 * When there is no speed information, just say "1 page per minute".
4024 */
4025
4026 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4027 "pages-per-minute", 1);
4028 if (ppd->color_device)
4029 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4030 "pages-per-minute-color", 1);
4031 }
ba55dc12 4032
9b4bd602
MS
4033 if ((ppd_attr = ppdFindAttr(ppd, "1284DeviceId", NULL)) != NULL)
4034 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, ppd_attr->value);
4035
ba55dc12
MS
4036 num_qualities = 0;
4037
4038 if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
4039 {
4040 if (ppdFindChoice(output_mode, "draft") ||
4041 ppdFindChoice(output_mode, "fast"))
4042 qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
f14324a7
MS
4043
4044 qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
4045
ba55dc12
MS
4046 if (ppdFindChoice(output_mode, "best") ||
4047 ppdFindChoice(output_mode, "high"))
4048 qualities[num_qualities ++] = IPP_QUALITY_HIGH;
4049 }
4050 else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
4051 {
4052 do
4053 {
4054 if (strstr(ppd_attr->spec, "draft") ||
4055 strstr(ppd_attr->spec, "Draft"))
4056 {
4057 qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
4058 break;
4059 }
4060 }
4061 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset",
4062 NULL)) != NULL);
4063
4064 qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
4065 qualities[num_qualities ++] = IPP_QUALITY_HIGH;
4066 }
f14324a7 4067 else
ba55dc12
MS
4068 qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
4069
4070 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
4071 "print-quality-supported", num_qualities, qualities);
61cf44e2
MS
4072
4073 if (ppd->nickname)
4074 {
4075 /*
4076 * The NickName can be localized in the character set specified
4077 * by the LanugageEncoding attribute. However, ppdOpen2() has
4078 * already converted the ppd->nickname member to UTF-8 for us
4079 * (the original attribute value is available separately)
4080 */
4081
4082 cupsdSetString(&p->make_model, ppd->nickname);
4083 }
4084 else if (ppd->modelname)
4085 {
4086 /*
4087 * Model name can only contain specific characters...
4088 */
4089
4090 cupsdSetString(&p->make_model, ppd->modelname);
4091 }
4092 else
4093 cupsdSetString(&p->make_model, "Bad PPD File");
4094
4095 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
4096 "printer-make-and-model", NULL, p->make_model);
4097
2fa1ba3c
MS
4098 if (p->pc && p->pc->strings)
4099 _cupsMessageSave(strings_name, _CUPS_MESSAGE_STRINGS, p->pc->strings);
4100
4101 if (!access(strings_name, R_OK))
4102 cupsdSetString(&p->strings, strings_name);
4103 else
4104 cupsdClearString(&p->strings);
4f98c13c 4105
61cf44e2
MS
4106 /*
4107 * Add media options from the PPD file...
4108 */
4109
f14324a7 4110 if (ppd->num_sizes == 0 || !p->pc)
61cf44e2 4111 {
5a08320a 4112 if (!ppdFindAttr(ppd, "APScannerOnly", NULL) && !ppdFindAttr(ppd, "cups3D", NULL))
b9faaae1
MS
4113 cupsdLogMessage(CUPSD_LOG_CRIT,
4114 "The PPD file for printer %s contains no media "
5a08320a 4115 "options and is therefore invalid.", p->name);
b9faaae1 4116
54afec33
MS
4117 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4118 "media-default", NULL, "unknown");
b9faaae1
MS
4119 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4120 "media-supported", NULL, "unknown");
61cf44e2
MS
4121 }
4122 else
4123 {
54afec33
MS
4124 /*
4125 * media-default
4126 */
c168a833 4127
54afec33 4128 if ((size = ppdPageSize(ppd, NULL)) != NULL)
f14324a7 4129 pwgsize = _ppdCacheGetSize(p->pc, size->name);
54afec33
MS
4130 else
4131 pwgsize = NULL;
4132
4133 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4134 "media-default", NULL,
4135 pwgsize ? pwgsize->map.pwg : "unknown");
4136
4137 /*
4138 * media-col-default
4139 */
4140
4141 if (pwgsize)
4142 {
aaf19ab0
MS
4143 ipp_t *col; /* Collection value */
4144
54afec33
MS
4145 input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
4146 media_type = ppdFindMarkedChoice(ppd, "MediaType");
aaf19ab0 4147 col = new_media_col(pwgsize,
4f63d6cd
MS
4148 input_slot ? _ppdCacheGetSource(p->pc, input_slot->choice) : NULL,
4149 media_type ? _ppdCacheGetType(p->pc, media_type->choice) : NULL);
4150
4151 ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", col);
aaf19ab0 4152 ippDelete(col);
54afec33
MS
4153 }
4154
4155 /*
4156 * media-supported
4157 */
4158
f14324a7
MS
4159 num_media = p->pc->num_sizes;
4160 if (p->pc->custom_min_keyword)
54afec33
MS
4161 num_media += 2;
4162
4163 if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4164 "media-supported", num_media, NULL,
4165 NULL)) != NULL)
61cf44e2
MS
4166 {
4167 val = attr->values;
4168
f14324a7 4169 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
54afec33
MS
4170 i > 0;
4171 i --, pwgsize ++, val ++)
6961465f 4172 val->string.text = _cupsStrAlloc(pwgsize->map.pwg);
54afec33 4173
f14324a7 4174 if (p->pc->custom_min_keyword)
54afec33 4175 {
6961465f 4176 val->string.text = _cupsStrAlloc(p->pc->custom_min_keyword);
54afec33 4177 val ++;
6961465f 4178 val->string.text = _cupsStrAlloc(p->pc->custom_max_keyword);
54afec33
MS
4179 }
4180 }
4181
a29fd7dd
MS
4182 /*
4183 * media-size-supported
4184 */
4185
4186 num_media = p->pc->num_sizes;
4187 if (p->pc->custom_min_keyword)
4188 num_media ++;
4189
4190 if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
4191 "media-size-supported", num_media,
4192 NULL)) != NULL)
4193 {
4194 val = attr->values;
4195
4196 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
4197 i > 0;
4198 i --, pwgsize ++, val ++)
4199 {
4200 val->collection = ippNew();
4201 ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4202 "x-dimension", pwgsize->width);
4203 ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4204 "y-dimension", pwgsize->length);
4205 }
4206
4207 if (p->pc->custom_min_keyword)
4208 {
4209 val->collection = ippNew();
4210 ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension",
4211 p->pc->custom_min_width, p->pc->custom_max_width);
4212 ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension",
4213 p->pc->custom_min_length, p->pc->custom_max_length);
4214 }
4215 }
4216
54afec33
MS
4217 /*
4218 * media-source-supported
4219 */
4220
f14324a7 4221 if (p->pc->num_sources > 0 &&
54afec33 4222 (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4223 "media-source-supported", p->pc->num_sources,
54afec33
MS
4224 NULL, NULL)) != NULL)
4225 {
f14324a7 4226 for (i = p->pc->num_sources, pwgsource = p->pc->sources,
54afec33
MS
4227 val = attr->values;
4228 i > 0;
4229 i --, pwgsource ++, val ++)
6961465f 4230 val->string.text = _cupsStrAlloc(pwgsource->pwg);
54afec33
MS
4231 }
4232
4233 /*
4234 * media-type-supported
4235 */
4236
f14324a7 4237 if (p->pc->num_types > 0 &&
54afec33 4238 (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4239 "media-type-supported", p->pc->num_types,
54afec33
MS
4240 NULL, NULL)) != NULL)
4241 {
f14324a7 4242 for (i = p->pc->num_types, pwgtype = p->pc->types,
54afec33
MS
4243 val = attr->values;
4244 i > 0;
4245 i --, pwgtype ++, val ++)
6961465f 4246 val->string.text = _cupsStrAlloc(pwgtype->pwg);
54afec33
MS
4247 }
4248
4249 /*
4250 * media-*-margin-supported
4251 */
4252
f14324a7 4253 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4254 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4255 i --, pwgsize ++)
4256 {
4257 for (j = 0; j < num_margins; j ++)
4258 if (pwgsize->bottom == margins[j])
4259 break;
4260
4261 if (j >= num_margins)
4262 {
4263 margins[num_margins] = pwgsize->bottom;
4264 num_margins ++;
4265 }
4266 }
4267
4268 if (num_margins > 0)
4269 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4270 "media-bottom-margin-supported", num_margins, margins);
4271 else
4272 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4273 "media-bottom-margin-supported", 0);
4274
f14324a7 4275 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4276 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4277 i --, pwgsize ++)
4278 {
4279 for (j = 0; j < num_margins; j ++)
4280 if (pwgsize->left == margins[j])
4281 break;
4282
4283 if (j >= num_margins)
c168a833 4284 {
54afec33
MS
4285 margins[num_margins] = pwgsize->left;
4286 num_margins ++;
4287 }
4288 }
4289
4290 if (num_margins > 0)
4291 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4292 "media-left-margin-supported", num_margins, margins);
4293 else
4294 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4295 "media-left-margin-supported", 0);
4296
f14324a7 4297 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4298 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4299 i --, pwgsize ++)
4300 {
4301 for (j = 0; j < num_margins; j ++)
4302 if (pwgsize->right == margins[j])
4303 break;
4304
4305 if (j >= num_margins)
4306 {
4307 margins[num_margins] = pwgsize->right;
4308 num_margins ++;
4309 }
4310 }
4311
4312 if (num_margins > 0)
4313 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4314 "media-right-margin-supported", num_margins, margins);
4315 else
4316 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4317 "media-right-margin-supported", 0);
4318
f14324a7 4319 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4320 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4321 i --, pwgsize ++)
4322 {
4323 for (j = 0; j < num_margins; j ++)
4324 if (pwgsize->top == margins[j])
4325 break;
4326
4327 if (j >= num_margins)
4328 {
4329 margins[num_margins] = pwgsize->top;
4330 num_margins ++;
4331 }
4332 }
4333
4334 if (num_margins > 0)
4335 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4336 "media-top-margin-supported", num_margins, margins);
4337 else
4338 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4339 "media-top-margin-supported", 0);
4340
4341 /*
4342 * media-col-database
4343 */
4344
f14324a7
MS
4345 num_media = p->pc->num_sizes;
4346 if (p->pc->num_sources)
54afec33 4347 {
f14324a7
MS
4348 if (p->pc->num_types > 0)
4349 num_media += p->pc->num_sizes * p->pc->num_sources *
4350 p->pc->num_types;
54afec33 4351 else
f14324a7 4352 num_media += p->pc->num_sizes * p->pc->num_sources;
54afec33 4353 }
f14324a7
MS
4354 else if (p->pc->num_types)
4355 num_media += p->pc->num_sizes * p->pc->num_types;
54afec33
MS
4356
4357 if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
4358 "media-col-database", num_media,
4359 NULL)) != NULL)
4360 {
f14324a7 4361 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
54afec33
MS
4362 i > 0;
4363 i --, pwgsize ++)
4364 {
4365 /*
4366 * Start by adding the page size without source or type...
4367 */
4368
4369 ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd);
4370
4371 val->collection = new_media_col(pwgsize, NULL, NULL);
4372 val ++;
4373
4374 /*
4375 * Then add the specific, supported combinations of size, source, and
4376 * type...
4377 */
4378
f14324a7 4379 if (p->pc->num_sources > 0)
c168a833 4380 {
f14324a7 4381 for (j = p->pc->num_sources, pwgsource = p->pc->sources;
54afec33
MS
4382 j > 0;
4383 j --, pwgsource ++)
c168a833 4384 {
54afec33 4385 ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
61cf44e2 4386
f14324a7 4387 if (p->pc->num_types > 0)
54afec33 4388 {
f14324a7 4389 for (k = p->pc->num_types, pwgtype = p->pc->types;
54afec33
MS
4390 k > 0;
4391 k --, pwgtype ++)
4392 {
4393 if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
4394 {
4395 val->collection = new_media_col(pwgsize, pwgsource->pwg,
4396 pwgtype->pwg);
4397 val ++;
4398 }
4399 }
4400 }
4401 else if (!ppdConflicts(ppd))
4402 {
4403 val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL);
4404 val ++;
4405 }
4406 }
4407 }
f14324a7 4408 else if (p->pc->num_types > 0)
54afec33 4409 {
f14324a7 4410 for (j = p->pc->num_types, pwgtype = p->pc->types;
54afec33
MS
4411 j > 0;
4412 j --, pwgtype ++)
d2354e63 4413 {
54afec33
MS
4414 if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
4415 {
4416 val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
4417 val ++;
4418 }
d2354e63 4419 }
c168a833
MS
4420 }
4421 }
61cf44e2 4422
54afec33
MS
4423 /*
4424 * Update the number of media-col-database values...
4425 */
c168a833 4426
54afec33 4427 attr->num_values = val - attr->values;
61cf44e2
MS
4428 }
4429 }
4430
4431 /*
4432 * Output bin...
4433 */
4434
f14324a7 4435 if (p->pc && p->pc->num_bins > 0)
61cf44e2
MS
4436 {
4437 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4438 "output-bin-supported", p->pc->num_bins,
61cf44e2
MS
4439 NULL, NULL);
4440
4441 if (attr != NULL)
4442 {
4443 for (i = 0, val = attr->values;
f14324a7 4444 i < p->pc->num_bins;
61cf44e2 4445 i ++, val ++)
f14324a7 4446 val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg);
61cf44e2 4447 }
c168a833 4448
cc754834
MS
4449 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
4450 {
f14324a7
MS
4451 for (i = 0; i < p->pc->num_bins; i ++)
4452 if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice))
cc754834
MS
4453 break;
4454
f14324a7 4455 if (i >= p->pc->num_bins)
cc754834
MS
4456 i = 0;
4457
4458 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4459 "output-bin-default", NULL, p->pc->bins[i].pwg);
cc754834
MS
4460 }
4461 else
4462 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4463 "output-bin-default", NULL, p->pc->bins[0].pwg);
cc754834 4464 }
4220952d 4465 else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
cc754834 4466 NULL)) != NULL &&
88f9aafc 4467 !_cups_strcasecmp(ppd_attr->value, "Reverse")) ||
7cf5915e 4468 (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */
88f9aafc
MS
4469 (!_cups_strcasecmp(ppd->manufacturer, "epson") ||
4470 !_cups_strcasecmp(ppd->manufacturer, "lexmark"))))
cc754834 4471 {
4220952d
MS
4472 /*
4473 * Report that this printer has a single output bin that leaves pages face
4474 * up.
4475 */
4476
e07d4801 4477 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
cc754834
MS
4478 "output-bin-supported", NULL, "face-up");
4479 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4480 "output-bin-default", NULL, "face-up");
4481 }
4482 else
4483 {
4484 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4485 "output-bin-supported", NULL, "face-down");
4486 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4487 "output-bin-default", NULL, "face-down");
61cf44e2
MS
4488 }
4489
7cf5915e 4490 /*
5a9febac 4491 * print-color-mode...
7cf5915e
MS
4492 */
4493
4494 if (ppd->color_device)
4495 {
5a9febac 4496 static const char * const color_modes[] =
7cf5915e
MS
4497 {
4498 "monochrome",
4499 "color"
4500 };
4501
4502 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
5a9febac 4503 "print-color-mode-supported", 2, NULL, color_modes);
f14324a7
MS
4504 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4505 "print-color-mode-default", NULL, "color");
71d227bf 4506 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 3, NULL, pwg_raster_document_types);
7cf5915e
MS
4507 }
4508 else
4509 {
f14324a7
MS
4510 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4511 "print-color-mode-supported", NULL, "monochrome");
4512 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4513 "print-color-mode-default", NULL, "monochrome");
71d227bf 4514 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 2, NULL, pwg_raster_document_types);
7cf5915e
MS
4515 }
4516
5a9febac
MS
4517 /*
4518 * Mandatory job attributes, if any...
4519 */
4520
4521 if (p->pc && cupsArrayCount(p->pc->mandatory) > 0)
4522 {
4523 int count = cupsArrayCount(p->pc->mandatory);
4524 /* Number of mandatory attributes */
4525
4526 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4527 "printer-mandatory-job-attributes", count, NULL,
4528 NULL);
4529
4530 for (val = attr->values,
4531 mandatory = (char *)cupsArrayFirst(p->pc->mandatory);
4532 mandatory;
4533 val ++, mandatory = (char *)cupsArrayNext(p->pc->mandatory))
6961465f 4534 val->string.text = _cupsStrAlloc(mandatory);
5a9febac
MS
4535 }
4536
5a6b583a
MS
4537 /*
4538 * Printer resolutions...
4539 */
4540
4541 if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL)
4542 if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL)
4543 if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL)
4544 resolution = ppdFindOption(ppd, "CNRes_PGP");
4545
4546 if (resolution)
4547 {
4548 /*
4549 * Report all supported resolutions...
4550 */
4551
71d227bf 4552 attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER, "printer-resolution-supported", resolution->num_choices, IPP_RES_PER_INCH, NULL, NULL);
5a6b583a
MS
4553
4554 for (i = 0, choice = resolution->choices;
4555 i < resolution->num_choices;
4556 i ++, choice ++)
4557 {
aaf19ab0
MS
4558 xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10);
4559 if (resptr > choice->choice && xdpi > 0 && *resptr == 'x')
4560 ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
5a6b583a
MS
4561
4562 if (xdpi <= 0 || ydpi <= 0)
4563 {
4564 cupsdLogMessage(CUPSD_LOG_WARN,
4565 "Bad resolution \"%s\" for printer %s.",
4566 choice->choice, p->name);
7cf5915e 4567 xdpi = ydpi = 300;
5a6b583a
MS
4568 }
4569
4570 attr->values[i].resolution.xres = xdpi;
ba55dc12 4571 attr->values[i].resolution.yres = ydpi;
5a6b583a
MS
4572 attr->values[i].resolution.units = IPP_RES_PER_INCH;
4573
4574 if (choice->marked)
71d227bf
MS
4575 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, xdpi, ydpi);
4576
4577 if (i == 0)
4578 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi);
5a6b583a
MS
4579 }
4580 }
4581 else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
4582 ppd_attr->value)
4583 {
4584 /*
4585 * Just the DefaultResolution to report...
4586 */
4587
39ff2fe7 4588 xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
5a6b583a
MS
4589 if (resptr > ppd_attr->value && xdpi > 0)
4590 {
4591 if (*resptr == 'x')
4592 ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
4593 else
4594 ydpi = xdpi;
4595 }
4596
4597 if (xdpi <= 0 || ydpi <= 0)
4598 {
4599 cupsdLogMessage(CUPSD_LOG_WARN,
4600 "Bad default resolution \"%s\" for printer %s.",
4601 ppd_attr->value, p->name);
7cf5915e 4602 xdpi = ydpi = 300;
5a6b583a
MS
4603 }
4604
4605 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4606 "printer-resolution-default", IPP_RES_PER_INCH,
4607 xdpi, ydpi);
4608 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4609 "printer-resolution-supported", IPP_RES_PER_INCH,
4610 xdpi, ydpi);
71d227bf 4611 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi);
5a6b583a
MS
4612 }
4613 else
4614 {
4615 /*
4616 * No resolutions in PPD - make one up...
4617 */
4618
4619 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4620 "printer-resolution-default", IPP_RES_PER_INCH,
7cf5915e 4621 300, 300);
5a6b583a
MS
4622 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4623 "printer-resolution-supported", IPP_RES_PER_INCH,
7cf5915e 4624 300, 300);
71d227bf 4625 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, 300, 300);
5a6b583a
MS
4626 }
4627
61cf44e2
MS
4628 /*
4629 * Duplexing, etc...
4630 */
4631
7cf5915e
MS
4632 ppdMarkDefaults(ppd);
4633
61cf44e2
MS
4634 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
4635 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
4636 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
4637 if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
4638 duplex = ppdFindOption(ppd, "JCLDuplex");
4639
4640 if (duplex && duplex->num_choices > 1 &&
4641 !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
4642 {
4643 p->type |= CUPS_PRINTER_DUPLEX;
4644
71d227bf
MS
4645 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-sheet-back", NULL, "normal");
4646
61cf44e2
MS
4647 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4648 "sides-supported", 3, NULL, sides);
4649
88f9aafc 4650 if (!_cups_strcasecmp(duplex->defchoice, "DuplexTumble"))
61cf44e2
MS
4651 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4652 "sides-default", NULL, "two-sided-short-edge");
88f9aafc 4653 else if (!_cups_strcasecmp(duplex->defchoice, "DuplexNoTumble"))
61cf44e2
MS
4654 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4655 "sides-default", NULL, "two-sided-long-edge");
4656 else
4657 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4658 "sides-default", NULL, "one-sided");
4659 }
cc754834
MS
4660 else
4661 {
4662 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4663 "sides-supported", NULL, "one-sided");
4664 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4665 "sides-default", NULL, "one-sided");
4666 }
61cf44e2
MS
4667
4668 if (ppdFindOption(ppd, "Collate") != NULL)
4669 p->type |= CUPS_PRINTER_COLLATE;
4670
30be6424 4671 if (p->pc && p->pc->finishings)
61cf44e2 4672 {
30be6424 4673 _pwg_finishings_t *fin; /* Current finishing value */
61cf44e2 4674
30be6424
MS
4675 for (fin = (_pwg_finishings_t *)cupsArrayFirst(p->pc->finishings); fin; fin = (_pwg_finishings_t *)cupsArrayNext(p->pc->finishings))
4676 {
4677 if (num_finishings < (int)(sizeof(finishings) / sizeof(finishings[0])))
4678 finishings[num_finishings++] = fin->value;
4679
4680 switch (fin->value)
4681 {
4682 case IPP_FINISHINGS_BIND :
4683 case IPP_FINISHINGS_BIND_LEFT :
4684 case IPP_FINISHINGS_BIND_TOP :
4685 case IPP_FINISHINGS_BIND_RIGHT :
4686 case IPP_FINISHINGS_BIND_BOTTOM :
4687 case IPP_FINISHINGS_EDGE_STITCH :
4688 case IPP_FINISHINGS_EDGE_STITCH_LEFT :
4689 case IPP_FINISHINGS_EDGE_STITCH_TOP :
4690 case IPP_FINISHINGS_EDGE_STITCH_RIGHT :
4691 case IPP_FINISHINGS_EDGE_STITCH_BOTTOM :
4692 p->type |= CUPS_PRINTER_BIND;
4693 break;
4694
4695 case IPP_FINISHINGS_COVER :
4696 p->type |= CUPS_PRINTER_COVER;
4697 break;
4698
4699 case IPP_FINISHINGS_PUNCH :
4700 case IPP_FINISHINGS_PUNCH_TOP_LEFT :
4701 case IPP_FINISHINGS_PUNCH_BOTTOM_LEFT :
4702 case IPP_FINISHINGS_PUNCH_TOP_RIGHT :
4703 case IPP_FINISHINGS_PUNCH_BOTTOM_RIGHT :
4704 case IPP_FINISHINGS_PUNCH_DUAL_LEFT :
4705 case IPP_FINISHINGS_PUNCH_DUAL_TOP :
4706 case IPP_FINISHINGS_PUNCH_DUAL_RIGHT :
4707 case IPP_FINISHINGS_PUNCH_DUAL_BOTTOM :
4708 case IPP_FINISHINGS_PUNCH_TRIPLE_LEFT :
4709 case IPP_FINISHINGS_PUNCH_TRIPLE_TOP :
4710 case IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT :
4711 case IPP_FINISHINGS_PUNCH_TRIPLE_BOTTOM :
4712 case IPP_FINISHINGS_PUNCH_QUAD_LEFT :
4713 case IPP_FINISHINGS_PUNCH_QUAD_TOP :
4714 case IPP_FINISHINGS_PUNCH_QUAD_RIGHT :
4715 case IPP_FINISHINGS_PUNCH_QUAD_BOTTOM :
4716 p->type |= CUPS_PRINTER_PUNCH;
4717 break;
4718
4719 case IPP_FINISHINGS_STAPLE :
4720 case IPP_FINISHINGS_STAPLE_TOP_LEFT :
4721 case IPP_FINISHINGS_STAPLE_BOTTOM_LEFT :
4722 case IPP_FINISHINGS_STAPLE_TOP_RIGHT :
4723 case IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT :
4724 case IPP_FINISHINGS_STAPLE_DUAL_LEFT :
4725 case IPP_FINISHINGS_STAPLE_DUAL_TOP :
4726 case IPP_FINISHINGS_STAPLE_DUAL_RIGHT :
4727 case IPP_FINISHINGS_STAPLE_DUAL_BOTTOM :
4728 case IPP_FINISHINGS_STAPLE_TRIPLE_LEFT :
4729 case IPP_FINISHINGS_STAPLE_TRIPLE_TOP :
4730 case IPP_FINISHINGS_STAPLE_TRIPLE_RIGHT :
4731 case IPP_FINISHINGS_STAPLE_TRIPLE_BOTTOM :
4732 p->type |= CUPS_PRINTER_STAPLE;
4733 break;
4734
4735 default :
4736 break;
4737 }
4738 }
61cf44e2
MS
4739 }
4740
4f63d6cd
MS
4741 if (p->pc && p->pc->templates)
4742 {
4743 const char *template; /* Finishing template */
4744 ipp_attribute_t *fin_col_db; /* finishings-col-database attribute */
4745 ipp_t *fin_col; /* finishings-col value */
4746
4747 fin_col_db = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, "finishings-col-database", cupsArrayCount(p->pc->templates), NULL);
4748 for (i = 0, template = (const char *)cupsArrayFirst(p->pc->templates); template; i ++, template = (const char *)cupsArrayNext(p->pc->templates))
4749 {
4750 fin_col = ippNew();
4751 ippAddString(fin_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, template);
4752 ippSetCollection(p->ppd_attrs, &fin_col_db, i, fin_col);
4753 ippDelete(fin_col);
4754 }
4755 }
4756
61cf44e2
MS
4757 for (i = 0; i < ppd->num_sizes; i ++)
4758 if (ppd->sizes[i].length > 1728)
4759 p->type |= CUPS_PRINTER_LARGE;
4760 else if (ppd->sizes[i].length > 1008)
4761 p->type |= CUPS_PRINTER_MEDIUM;
4762 else
4763 p->type |= CUPS_PRINTER_SMALL;
4764
b9faaae1 4765 if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL &&
88f9aafc 4766 ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
b9faaae1
MS
4767 {
4768 if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL &&
88f9aafc 4769 ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
b9faaae1
MS
4770 p->type |= CUPS_PRINTER_SCANNER;
4771 else
4772 p->type |= CUPS_PRINTER_MFP;
4773 }
4774
61cf44e2 4775 /*
f14324a7 4776 * Scan the filters in the PPD file...
61cf44e2
MS
4777 */
4778
f14324a7 4779 if (p->pc)
c8fef167 4780 {
f14324a7
MS
4781 for (filter = (const char *)cupsArrayFirst(p->pc->filters);
4782 filter;
4783 filter = (const char *)cupsArrayNext(p->pc->filters))
c8fef167 4784 {
88f9aafc 4785 if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
f14324a7
MS
4786 _cups_isspace(filter[28]))
4787 {
4788 p->type |= CUPS_PRINTER_COMMANDS;
61cf44e2 4789 break;
f14324a7 4790 }
61cf44e2
MS
4791 }
4792 }
4793
4794 if (p->type & CUPS_PRINTER_COMMANDS)
4795 {
4796 char *commands, /* Copy of commands */
4797 *start, /* Start of name */
4798 *end; /* End of name */
4799 int count; /* Number of commands */
4800
f14324a7 4801 if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL)
61cf44e2
MS
4802 {
4803 for (count = 0, start = ppd_attr->value; *start; count ++)
4804 {
f14324a7 4805 while (_cups_isspace(*start))
61cf44e2
MS
4806 start ++;
4807
4808 if (!*start)
4809 break;
4810
4811 while (*start && !isspace(*start & 255))
4812 start ++;
4813 }
4814 }
4815 else
4816 count = 0;
4817
4818 if (count > 0)
4819 {
4820 /*
0268488e
MS
4821 * Make a copy of the commands string and count how many commands there
4822 * are...
61cf44e2
MS
4823 */
4824
4825 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4826 "printer-commands", count, NULL, NULL);
4827
4828 commands = strdup(ppd_attr->value);
4829
4830 for (count = 0, start = commands; *start; count ++)
4831 {
4832 while (isspace(*start & 255))
4833 start ++;
4834
4835 if (!*start)
4836 break;
4837
4838 end = start;
4839 while (*end && !isspace(*end & 255))
4840 end ++;
4841
4842 if (*end)
4843 *end++ = '\0';
4844
4845 attr->values[count].string.text = _cupsStrAlloc(start);
4846
4847 start = end;
4848 }
4849
4850 free(commands);
4851 }
4852 else
4853 {
4854 /*
4855 * Add the standard list of commands...
4856 */
4857
4858 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4859 "printer-commands",
4860 (int)(sizeof(standard_commands) /
4861 sizeof(standard_commands[0])), NULL,
4862 standard_commands);
4863 }
4864 }
4865 else
4866 {
4867 /*
4868 * No commands supported...
4869 */
4870
4871 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4872 "printer-commands", NULL, "none");
4873 }
4874
4875 /*
4876 * Show current and available port monitors for this printer...
4877 */
4878
4879 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
4880 NULL, p->port_monitor ? p->port_monitor : "none");
4881
4882 for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
4883 ppd_attr;
4884 i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
4885
4886 if (ppd->protocols)
4887 {
4888 if (strstr(ppd->protocols, "TBCP"))
4889 i ++;
4890 else if (strstr(ppd->protocols, "BCP"))
4891 i ++;
4892 }
4893
4894 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
4895 "port-monitor-supported", i, NULL, NULL);
4896
4897 attr->values[0].string.text = _cupsStrAlloc("none");
4898
4899 for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
4900 ppd_attr;
4901 i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
4902 attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value);
4903
4904 if (ppd->protocols)
4905 {
4906 if (strstr(ppd->protocols, "TBCP"))
4907 attr->values[i].string.text = _cupsStrAlloc("tbcp");
4908 else if (strstr(ppd->protocols, "BCP"))
4909 attr->values[i].string.text = _cupsStrAlloc("bcp");
4910 }
4911
61cf44e2
MS
4912 if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
4913 p->type |= CUPS_PRINTER_REMOTE;
4914
7cf5915e
MS
4915#ifdef HAVE_APPLICATIONSERVICES_H
4916 /*
4917 * Convert the file referenced in APPrinterIconPath to a 128x128 PNG
4918 * and save it as cacheDir/printername.png
4919 */
4920
4921 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
22c9029b
MS
4922 ppd_attr->value &&
4923 !_cupsFileCheck(ppd_attr->value, _CUPS_FILE_CHECK_FILE, !RunUser,
4924 cupsdLogFCMessage, p))
7cf5915e
MS
4925 {
4926 CGImageRef imageRef = NULL;/* Current icon image */
4927 CGImageRef biggestIconRef = NULL;
4928 /* Biggest icon image */
4929 CGImageRef closestTo128IconRef = NULL;
4930 /* Icon image closest to and >= 128 */
4931 CGImageSourceRef sourceRef; /* The file's image source */
4932 char outPath[HTTP_MAX_URI];
4933 /* The path to the PNG file */
4934 CFURLRef outUrl; /* The URL made from the outPath */
4935 CFURLRef icnsFileUrl; /* The URL of the original ICNS icon file */
4936 CGImageDestinationRef destRef; /* The image destination to write */
4937 size_t bytesPerRow; /* The bytes per row used for resizing */
4938 CGContextRef context; /* The CG context used for resizing */
4939
4940 snprintf(outPath, sizeof(outPath), "%s/%s.png", CacheDir, p->name);
7e86f2f6
MS
4941 outUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)outPath, (CFIndex)strlen(outPath), FALSE);
4942 icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)ppd_attr->value, (CFIndex)strlen(ppd_attr->value), FALSE);
7cf5915e
MS
4943 if (outUrl && icnsFileUrl)
4944 {
4945 sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL);
4946 if (sourceRef)
4947 {
7e86f2f6 4948 for (i = 0; i < (int)CGImageSourceGetCount(sourceRef); i ++)
7cf5915e 4949 {
7e86f2f6 4950 imageRef = CGImageSourceCreateImageAtIndex(sourceRef, (size_t)i, NULL);
c8fef167
MS
4951 if (!imageRef)
4952 continue;
4953
4954 if (CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef))
7cf5915e
MS
4955 {
4956 /*
4957 * Loop through remembering the icon closest to 128 but >= 128
4958 * and then remember the largest icon.
4959 */
4960
4961 if (CGImageGetWidth(imageRef) >= 128 &&
4962 (!closestTo128IconRef ||
4963 CGImageGetWidth(imageRef) <
4964 CGImageGetWidth(closestTo128IconRef)))
4965 {
4966 CGImageRelease(closestTo128IconRef);
4967 CGImageRetain(imageRef);
4968 closestTo128IconRef = imageRef;
4969 }
4970
4971 if (!biggestIconRef ||
4972 CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef))
4973 {
4974 CGImageRelease(biggestIconRef);
4975 CGImageRetain(imageRef);
4976 biggestIconRef = imageRef;
4977 }
c8fef167 4978 }
7cf5915e 4979
c8fef167 4980 CGImageRelease(imageRef);
7cf5915e
MS
4981 }
4982
4983 if (biggestIconRef)
4984 {
4985 /*
4986 * If biggestIconRef is NULL, we found no icons. Otherwise we first
4987 * want the closest to 128, but if none are larger than 128, we want
4988 * the largest icon available.
4989 */
4990
4991 imageRef = closestTo128IconRef ? closestTo128IconRef :
4992 biggestIconRef;
4993 CGImageRetain(imageRef);
4994 CGImageRelease(biggestIconRef);
c8fef167
MS
4995 if (closestTo128IconRef)
4996 CGImageRelease(closestTo128IconRef);
7cf5915e
MS
4997 destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1,
4998 NULL);
4999 if (destRef)
5000 {
5001 if (CGImageGetWidth(imageRef) != 128)
5002 {
5003 bytesPerRow = CGImageGetBytesPerRow(imageRef) /
5004 CGImageGetWidth(imageRef) * 128;
5005 context = CGBitmapContextCreate(NULL, 128, 128,
5006 CGImageGetBitsPerComponent(imageRef),
5007 bytesPerRow,
5008 CGImageGetColorSpace(imageRef),
5009 kCGImageAlphaPremultipliedFirst);
5010 if (context)
5011 {
5012 CGContextDrawImage(context, CGRectMake(0, 0, 128, 128),
5013 imageRef);
5014 CGImageRelease(imageRef);
5015 imageRef = CGBitmapContextCreateImage(context);
5016 CGContextRelease(context);
5017 }
5018 }
5019
5020 CGImageDestinationAddImage(destRef, imageRef, NULL);
5021 CGImageDestinationFinalize(destRef);
5022 CFRelease(destRef);
5023 }
5024
5025 CGImageRelease(imageRef);
c8fef167 5026 }
7cf5915e
MS
5027
5028 CFRelease(sourceRef);
7cf5915e 5029 }
e60ec91f 5030 }
7cf5915e 5031
e60ec91f 5032 if (outUrl)
7cf5915e 5033 CFRelease(outUrl);
e60ec91f
MS
5034
5035 if (icnsFileUrl)
5036 CFRelease(icnsFileUrl);
7cf5915e
MS
5037 }
5038#endif /* HAVE_APPLICATIONSERVICES_H */
5039
61cf44e2
MS
5040 /*
5041 * Close the PPD and set the type...
5042 */
5043
5044 ppdClose(ppd);
5045 }
5046 else if (!access(ppd_name, 0))
5047 {
5048 int pline; /* PPD line number */
5049 ppd_status_t pstatus; /* PPD load status */
5050
5051
5052 pstatus = ppdLastError(&pline);
5053
c07e5e20 5054 cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded.", p->name);
61cf44e2
MS
5055
5056 if (pstatus <= PPD_ALLOC_ERROR)
c07e5e20 5057 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", ppd_name, strerror(errno));
61cf44e2 5058 else
c07e5e20 5059 cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d of %s.", ppdErrorString(pstatus), pline, ppd_name);
61cf44e2
MS
5060
5061 cupsdLogMessage(CUPSD_LOG_INFO,
5062 "Hint: Run \"cupstestppd %s\" and fix any errors.",
5063 ppd_name);
61cf44e2
MS
5064 }
5065 else
5066 {
e67e2f9e
MS
5067 if (((!strncmp(p->device_uri, "ipp://", 6) ||
5068 !strncmp(p->device_uri, "ipps://", 7)) &&
5069 (strstr(p->device_uri, "/printers/") != NULL ||
5070 strstr(p->device_uri, "/classes/") != NULL)) ||
5071 ((strstr(p->device_uri, "._ipp.") != NULL ||
5072 strstr(p->device_uri, "._ipps.") != NULL) &&
5073 !strcmp(p->device_uri + strlen(p->device_uri) - 5, "/cups")))
61cf44e2
MS
5074 {
5075 /*
5076 * Tell the client this is really a hard-wired remote printer.
5077 */
5078
5079 p->type |= CUPS_PRINTER_REMOTE;
5080
61cf44e2
MS
5081 /*
5082 * Then set the make-and-model accordingly...
5083 */
5084
5085 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
5086 "printer-make-and-model", NULL, "Remote Printer");
5087
5088 /*
5089 * Print all files directly...
5090 */
5091
5092 p->raw = 1;
5093 p->remote = 1;
5094 }
5095 else
5096 {
5097 /*
5098 * Otherwise we have neither - treat this as a "dumb" printer
5099 * with no PPD file...
5100 */
5101
5102 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
5103 "printer-make-and-model", NULL, "Local Raw Printer");
5104
5105 p->raw = 1;
5106 }
5107 }
5108
5109 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
5110 "finishings-supported", num_finishings, finishings);
5111 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
5112 "finishings-default", IPP_FINISHINGS_NONE);
5113
f14324a7 5114 if (ppd && p->pc)
61cf44e2
MS
5115 {
5116 /*
5117 * Save cached PPD attributes to disk...
5118 */
5119
5120 cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name);
5121
f14324a7 5122 _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs);
61cf44e2 5123 }
54afec33 5124 else
61cf44e2
MS
5125 {
5126 /*
54afec33 5127 * Remove cache files...
61cf44e2
MS
5128 */
5129
54afec33
MS
5130 if (cache_info.st_mtime)
5131 unlink(cache_name);
61cf44e2
MS
5132 }
5133}
5134
5135
54afec33
MS
5136/*
5137 * 'new_media_col()' - Create a media-col collection value.
5138 */
5139
5140static ipp_t * /* O - Collection value */
788d7a15 5141new_media_col(pwg_size_t *size, /* I - media-size/margin values */
54afec33
MS
5142 const char *source, /* I - media-source value */
5143 const char *type) /* I - media-type value */
5144{
5145 ipp_t *media_col, /* Collection value */
5146 *media_size; /* media-size value */
5147
5148
5149 media_col = ippNew();
5150
5151 media_size = ippNew();
5152 ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5153 "x-dimension", size->width);
5154 ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5155 "y-dimension", size->length);
54afec33 5156 ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size);
aaf19ab0
MS
5157 ippDelete(media_size);
5158
54afec33
MS
5159 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5160 "media-bottom-margin", size->bottom);
5161 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5162 "media-left-margin", size->left);
5163 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5164 "media-right-margin", size->right);
5165 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5166 "media-top-margin", size->top);
5167
5168 if (source)
5169 ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source",
5170 NULL, source);
5171
5172 if (type)
5173 ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type",
5174 NULL, type);
5175
5176 return (media_col);
5177}
5178
5179
ef416fc2 5180/*
0af14961
MS
5181 * 'write_xml_string()' - Write a string with XML escaping.
5182 */
5183
5184static void
5185write_xml_string(cups_file_t *fp, /* I - File to write to */
5186 const char *s) /* I - String to write */
5187{
5188 const char *start; /* Start of current sequence */
5189
5190
5191 if (!s)
5192 return;
5193
5194 for (start = s; *s; s ++)
5195 {
5196 if (*s == '&')
5197 {
5198 if (s > start)
7e86f2f6 5199 cupsFileWrite(fp, start, (size_t)(s - start));
0af14961
MS
5200
5201 cupsFilePuts(fp, "&amp;");
5202 start = s + 1;
5203 }
5204 else if (*s == '<')
5205 {
5206 if (s > start)
7e86f2f6 5207 cupsFileWrite(fp, start, (size_t)(s - start));
0af14961
MS
5208
5209 cupsFilePuts(fp, "&lt;");
5210 start = s + 1;
5211 }
5212 }
5213
5214 if (s > start)
5215 cupsFilePuts(fp, start);
5216}