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