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