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