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