]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/printers.c
Merge changes from CUPS 1.7svn-r10874.
[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 3783
a469f8a5
MS
3784 if (p->pc && p->pc->charge_info_uri)
3785 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
3786 "printer-charge-info-uri", NULL, p->pc->charge_info_uri);
3787
5a9febac
MS
3788 if (p->pc && p->pc->account_id)
3789 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "job-account-id-supported",
3790 1);
3791
3792 if (p->pc && p->pc->accounting_user_id)
3793 ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER,
3794 "job-accounting-user-id-supported", 1);
3795
3796 if (p->pc && p->pc->password)
3797 {
3798 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3799 "job-password-encryption-supported", NULL, "none");
3800 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3801 "job-password-supported", strlen(p->pc->password));
3802 }
3803
61cf44e2 3804 if (ppd->throughput)
ba55dc12 3805 {
61cf44e2
MS
3806 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3807 "pages-per-minute", ppd->throughput);
ba55dc12
MS
3808 if (ppd->color_device)
3809 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3810 "pages-per-minute-color", ppd->throughput);
3811 }
e60ec91f
MS
3812 else
3813 {
3814 /*
3815 * When there is no speed information, just say "1 page per minute".
3816 */
3817
3818 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3819 "pages-per-minute", 1);
3820 if (ppd->color_device)
3821 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3822 "pages-per-minute-color", 1);
3823 }
ba55dc12
MS
3824
3825 num_qualities = 0;
3826
3827 if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
3828 {
3829 if (ppdFindChoice(output_mode, "draft") ||
3830 ppdFindChoice(output_mode, "fast"))
3831 qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
f14324a7
MS
3832
3833 qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
3834
ba55dc12
MS
3835 if (ppdFindChoice(output_mode, "best") ||
3836 ppdFindChoice(output_mode, "high"))
3837 qualities[num_qualities ++] = IPP_QUALITY_HIGH;
3838 }
3839 else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
3840 {
3841 do
3842 {
3843 if (strstr(ppd_attr->spec, "draft") ||
3844 strstr(ppd_attr->spec, "Draft"))
3845 {
3846 qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
3847 break;
3848 }
3849 }
3850 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset",
3851 NULL)) != NULL);
3852
3853 qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
3854 qualities[num_qualities ++] = IPP_QUALITY_HIGH;
3855 }
f14324a7 3856 else
ba55dc12
MS
3857 qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
3858
3859 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
3860 "print-quality-supported", num_qualities, qualities);
61cf44e2
MS
3861
3862 if (ppd->nickname)
3863 {
3864 /*
3865 * The NickName can be localized in the character set specified
3866 * by the LanugageEncoding attribute. However, ppdOpen2() has
3867 * already converted the ppd->nickname member to UTF-8 for us
3868 * (the original attribute value is available separately)
3869 */
3870
3871 cupsdSetString(&p->make_model, ppd->nickname);
3872 }
3873 else if (ppd->modelname)
3874 {
3875 /*
3876 * Model name can only contain specific characters...
3877 */
3878
3879 cupsdSetString(&p->make_model, ppd->modelname);
3880 }
3881 else
3882 cupsdSetString(&p->make_model, "Bad PPD File");
3883
3884 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
3885 "printer-make-and-model", NULL, p->make_model);
3886
3887 /*
3888 * Add media options from the PPD file...
3889 */
3890
f14324a7 3891 if (ppd->num_sizes == 0 || !p->pc)
61cf44e2 3892 {
b9faaae1
MS
3893 if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
3894 cupsdLogMessage(CUPSD_LOG_CRIT,
3895 "The PPD file for printer %s contains no media "
3896 "options and is therefore invalid!", p->name);
3897
54afec33
MS
3898 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3899 "media-default", NULL, "unknown");
b9faaae1
MS
3900 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3901 "media-supported", NULL, "unknown");
61cf44e2
MS
3902 }
3903 else
3904 {
54afec33
MS
3905 /*
3906 * media-default
3907 */
c168a833 3908
54afec33 3909 if ((size = ppdPageSize(ppd, NULL)) != NULL)
f14324a7 3910 pwgsize = _ppdCacheGetSize(p->pc, size->name);
54afec33
MS
3911 else
3912 pwgsize = NULL;
3913
3914 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3915 "media-default", NULL,
3916 pwgsize ? pwgsize->map.pwg : "unknown");
3917
3918 /*
3919 * media-col-default
3920 */
3921
3922 if (pwgsize)
3923 {
aaf19ab0
MS
3924 ipp_t *col; /* Collection value */
3925
54afec33
MS
3926 input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
3927 media_type = ppdFindMarkedChoice(ppd, "MediaType");
aaf19ab0
MS
3928 col = new_media_col(pwgsize,
3929 input_slot ?
f14324a7
MS
3930 _ppdCacheGetSource(p->pc,
3931 input_slot->choice) :
aaf19ab0
MS
3932 NULL,
3933 media_type ?
f14324a7
MS
3934 _ppdCacheGetType(p->pc,
3935 media_type->choice) :
cc754834 3936 NULL);
54afec33
MS
3937
3938 ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
aaf19ab0
MS
3939 col);
3940 ippDelete(col);
54afec33
MS
3941 }
3942
3943 /*
3944 * media-supported
3945 */
3946
f14324a7
MS
3947 num_media = p->pc->num_sizes;
3948 if (p->pc->custom_min_keyword)
54afec33
MS
3949 num_media += 2;
3950
3951 if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3952 "media-supported", num_media, NULL,
3953 NULL)) != NULL)
61cf44e2
MS
3954 {
3955 val = attr->values;
3956
f14324a7 3957 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
54afec33
MS
3958 i > 0;
3959 i --, pwgsize ++, val ++)
3960 val->string.text = _cupsStrRetain(pwgsize->map.pwg);
3961
f14324a7 3962 if (p->pc->custom_min_keyword)
54afec33 3963 {
f14324a7 3964 val->string.text = _cupsStrRetain(p->pc->custom_min_keyword);
54afec33 3965 val ++;
f14324a7 3966 val->string.text = _cupsStrRetain(p->pc->custom_max_keyword);
54afec33
MS
3967 }
3968 }
3969
a29fd7dd
MS
3970 /*
3971 * media-size-supported
3972 */
3973
3974 num_media = p->pc->num_sizes;
3975 if (p->pc->custom_min_keyword)
3976 num_media ++;
3977
3978 if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
3979 "media-size-supported", num_media,
3980 NULL)) != NULL)
3981 {
3982 val = attr->values;
3983
3984 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
3985 i > 0;
3986 i --, pwgsize ++, val ++)
3987 {
3988 val->collection = ippNew();
3989 ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3990 "x-dimension", pwgsize->width);
3991 ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3992 "y-dimension", pwgsize->length);
3993 }
3994
3995 if (p->pc->custom_min_keyword)
3996 {
3997 val->collection = ippNew();
3998 ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension",
3999 p->pc->custom_min_width, p->pc->custom_max_width);
4000 ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension",
4001 p->pc->custom_min_length, p->pc->custom_max_length);
4002 }
4003 }
4004
54afec33
MS
4005 /*
4006 * media-source-supported
4007 */
4008
f14324a7 4009 if (p->pc->num_sources > 0 &&
54afec33 4010 (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4011 "media-source-supported", p->pc->num_sources,
54afec33
MS
4012 NULL, NULL)) != NULL)
4013 {
f14324a7 4014 for (i = p->pc->num_sources, pwgsource = p->pc->sources,
54afec33
MS
4015 val = attr->values;
4016 i > 0;
4017 i --, pwgsource ++, val ++)
4018 val->string.text = _cupsStrRetain(pwgsource->pwg);
4019 }
4020
4021 /*
4022 * media-type-supported
4023 */
4024
f14324a7 4025 if (p->pc->num_types > 0 &&
54afec33 4026 (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4027 "media-type-supported", p->pc->num_types,
54afec33
MS
4028 NULL, NULL)) != NULL)
4029 {
f14324a7 4030 for (i = p->pc->num_types, pwgtype = p->pc->types,
54afec33
MS
4031 val = attr->values;
4032 i > 0;
4033 i --, pwgtype ++, val ++)
4034 val->string.text = _cupsStrRetain(pwgtype->pwg);
4035 }
4036
4037 /*
4038 * media-*-margin-supported
4039 */
4040
f14324a7 4041 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4042 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4043 i --, pwgsize ++)
4044 {
4045 for (j = 0; j < num_margins; j ++)
4046 if (pwgsize->bottom == margins[j])
4047 break;
4048
4049 if (j >= num_margins)
4050 {
4051 margins[num_margins] = pwgsize->bottom;
4052 num_margins ++;
4053 }
4054 }
4055
4056 if (num_margins > 0)
4057 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4058 "media-bottom-margin-supported", num_margins, margins);
4059 else
4060 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4061 "media-bottom-margin-supported", 0);
4062
f14324a7 4063 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4064 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4065 i --, pwgsize ++)
4066 {
4067 for (j = 0; j < num_margins; j ++)
4068 if (pwgsize->left == margins[j])
4069 break;
4070
4071 if (j >= num_margins)
c168a833 4072 {
54afec33
MS
4073 margins[num_margins] = pwgsize->left;
4074 num_margins ++;
4075 }
4076 }
4077
4078 if (num_margins > 0)
4079 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4080 "media-left-margin-supported", num_margins, margins);
4081 else
4082 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4083 "media-left-margin-supported", 0);
4084
f14324a7 4085 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4086 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4087 i --, pwgsize ++)
4088 {
4089 for (j = 0; j < num_margins; j ++)
4090 if (pwgsize->right == margins[j])
4091 break;
4092
4093 if (j >= num_margins)
4094 {
4095 margins[num_margins] = pwgsize->right;
4096 num_margins ++;
4097 }
4098 }
4099
4100 if (num_margins > 0)
4101 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4102 "media-right-margin-supported", num_margins, margins);
4103 else
4104 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4105 "media-right-margin-supported", 0);
4106
f14324a7 4107 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
54afec33
MS
4108 i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
4109 i --, pwgsize ++)
4110 {
4111 for (j = 0; j < num_margins; j ++)
4112 if (pwgsize->top == margins[j])
4113 break;
4114
4115 if (j >= num_margins)
4116 {
4117 margins[num_margins] = pwgsize->top;
4118 num_margins ++;
4119 }
4120 }
4121
4122 if (num_margins > 0)
4123 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4124 "media-top-margin-supported", num_margins, margins);
4125 else
4126 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4127 "media-top-margin-supported", 0);
4128
4129 /*
4130 * media-col-database
4131 */
4132
f14324a7
MS
4133 num_media = p->pc->num_sizes;
4134 if (p->pc->num_sources)
54afec33 4135 {
f14324a7
MS
4136 if (p->pc->num_types > 0)
4137 num_media += p->pc->num_sizes * p->pc->num_sources *
4138 p->pc->num_types;
54afec33 4139 else
f14324a7 4140 num_media += p->pc->num_sizes * p->pc->num_sources;
54afec33 4141 }
f14324a7
MS
4142 else if (p->pc->num_types)
4143 num_media += p->pc->num_sizes * p->pc->num_types;
54afec33
MS
4144
4145 if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
4146 "media-col-database", num_media,
4147 NULL)) != NULL)
4148 {
f14324a7 4149 for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
54afec33
MS
4150 i > 0;
4151 i --, pwgsize ++)
4152 {
4153 /*
4154 * Start by adding the page size without source or type...
4155 */
4156
4157 ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd);
4158
4159 val->collection = new_media_col(pwgsize, NULL, NULL);
4160 val ++;
4161
4162 /*
4163 * Then add the specific, supported combinations of size, source, and
4164 * type...
4165 */
4166
f14324a7 4167 if (p->pc->num_sources > 0)
c168a833 4168 {
f14324a7 4169 for (j = p->pc->num_sources, pwgsource = p->pc->sources;
54afec33
MS
4170 j > 0;
4171 j --, pwgsource ++)
c168a833 4172 {
54afec33 4173 ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
61cf44e2 4174
f14324a7 4175 if (p->pc->num_types > 0)
54afec33 4176 {
f14324a7 4177 for (k = p->pc->num_types, pwgtype = p->pc->types;
54afec33
MS
4178 k > 0;
4179 k --, pwgtype ++)
4180 {
4181 if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
4182 {
4183 val->collection = new_media_col(pwgsize, pwgsource->pwg,
4184 pwgtype->pwg);
4185 val ++;
4186 }
4187 }
4188 }
4189 else if (!ppdConflicts(ppd))
4190 {
4191 val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL);
4192 val ++;
4193 }
4194 }
4195 }
f14324a7 4196 else if (p->pc->num_types > 0)
54afec33 4197 {
f14324a7 4198 for (j = p->pc->num_types, pwgtype = p->pc->types;
54afec33
MS
4199 j > 0;
4200 j --, pwgtype ++)
d2354e63 4201 {
54afec33
MS
4202 if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
4203 {
4204 val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
4205 val ++;
4206 }
d2354e63 4207 }
c168a833
MS
4208 }
4209 }
61cf44e2 4210
54afec33
MS
4211 /*
4212 * Update the number of media-col-database values...
4213 */
c168a833 4214
54afec33 4215 attr->num_values = val - attr->values;
61cf44e2
MS
4216 }
4217 }
4218
4219 /*
4220 * Output bin...
4221 */
4222
f14324a7 4223 if (p->pc && p->pc->num_bins > 0)
61cf44e2
MS
4224 {
4225 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4226 "output-bin-supported", p->pc->num_bins,
61cf44e2
MS
4227 NULL, NULL);
4228
4229 if (attr != NULL)
4230 {
4231 for (i = 0, val = attr->values;
f14324a7 4232 i < p->pc->num_bins;
61cf44e2 4233 i ++, val ++)
f14324a7 4234 val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg);
61cf44e2 4235 }
c168a833 4236
cc754834
MS
4237 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
4238 {
f14324a7
MS
4239 for (i = 0; i < p->pc->num_bins; i ++)
4240 if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice))
cc754834
MS
4241 break;
4242
f14324a7 4243 if (i >= p->pc->num_bins)
cc754834
MS
4244 i = 0;
4245
4246 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4247 "output-bin-default", NULL, p->pc->bins[i].pwg);
cc754834
MS
4248 }
4249 else
4250 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
f14324a7 4251 "output-bin-default", NULL, p->pc->bins[0].pwg);
cc754834 4252 }
4220952d 4253 else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
cc754834 4254 NULL)) != NULL &&
88f9aafc 4255 !_cups_strcasecmp(ppd_attr->value, "Reverse")) ||
7cf5915e 4256 (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */
88f9aafc
MS
4257 (!_cups_strcasecmp(ppd->manufacturer, "epson") ||
4258 !_cups_strcasecmp(ppd->manufacturer, "lexmark"))))
cc754834 4259 {
4220952d
MS
4260 /*
4261 * Report that this printer has a single output bin that leaves pages face
4262 * up.
4263 */
4264
e07d4801 4265 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
cc754834
MS
4266 "output-bin-supported", NULL, "face-up");
4267 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4268 "output-bin-default", NULL, "face-up");
4269 }
4270 else
4271 {
4272 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4273 "output-bin-supported", NULL, "face-down");
4274 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4275 "output-bin-default", NULL, "face-down");
61cf44e2
MS
4276 }
4277
7cf5915e 4278 /*
5a9febac 4279 * print-color-mode...
7cf5915e
MS
4280 */
4281
4282 if (ppd->color_device)
4283 {
5a9febac 4284 static const char * const color_modes[] =
7cf5915e
MS
4285 {
4286 "monochrome",
4287 "color"
4288 };
4289
4290 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
5a9febac 4291 "print-color-mode-supported", 2, NULL, color_modes);
f14324a7
MS
4292 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4293 "print-color-mode-default", NULL, "color");
7cf5915e
MS
4294 }
4295 else
4296 {
f14324a7
MS
4297 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4298 "print-color-mode-supported", NULL, "monochrome");
4299 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4300 "print-color-mode-default", NULL, "monochrome");
7cf5915e
MS
4301 }
4302
5a9febac
MS
4303 /*
4304 * Mandatory job attributes, if any...
4305 */
4306
4307 if (p->pc && cupsArrayCount(p->pc->mandatory) > 0)
4308 {
4309 int count = cupsArrayCount(p->pc->mandatory);
4310 /* Number of mandatory attributes */
4311
4312 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4313 "printer-mandatory-job-attributes", count, NULL,
4314 NULL);
4315
4316 for (val = attr->values,
4317 mandatory = (char *)cupsArrayFirst(p->pc->mandatory);
4318 mandatory;
4319 val ++, mandatory = (char *)cupsArrayNext(p->pc->mandatory))
4320 val->string.text = _cupsStrRetain(mandatory);
4321 }
4322
5a6b583a
MS
4323 /*
4324 * Printer resolutions...
4325 */
4326
4327 if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL)
4328 if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL)
4329 if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL)
4330 resolution = ppdFindOption(ppd, "CNRes_PGP");
4331
4332 if (resolution)
4333 {
4334 /*
4335 * Report all supported resolutions...
4336 */
4337
4338 attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER,
4339 "printer-resolution-supported",
4340 resolution->num_choices, IPP_RES_PER_INCH,
4341 NULL, NULL);
4342
4343 for (i = 0, choice = resolution->choices;
4344 i < resolution->num_choices;
4345 i ++, choice ++)
4346 {
aaf19ab0
MS
4347 xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10);
4348 if (resptr > choice->choice && xdpi > 0 && *resptr == 'x')
4349 ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
5a6b583a
MS
4350
4351 if (xdpi <= 0 || ydpi <= 0)
4352 {
4353 cupsdLogMessage(CUPSD_LOG_WARN,
4354 "Bad resolution \"%s\" for printer %s.",
4355 choice->choice, p->name);
7cf5915e 4356 xdpi = ydpi = 300;
5a6b583a
MS
4357 }
4358
4359 attr->values[i].resolution.xres = xdpi;
ba55dc12 4360 attr->values[i].resolution.yres = ydpi;
5a6b583a
MS
4361 attr->values[i].resolution.units = IPP_RES_PER_INCH;
4362
4363 if (choice->marked)
4364 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4365 "printer-resolution-default", IPP_RES_PER_INCH,
4366 xdpi, ydpi);
4367 }
4368 }
4369 else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
4370 ppd_attr->value)
4371 {
4372 /*
4373 * Just the DefaultResolution to report...
4374 */
4375
39ff2fe7 4376 xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
5a6b583a
MS
4377 if (resptr > ppd_attr->value && xdpi > 0)
4378 {
4379 if (*resptr == 'x')
4380 ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
4381 else
4382 ydpi = xdpi;
4383 }
4384
4385 if (xdpi <= 0 || ydpi <= 0)
4386 {
4387 cupsdLogMessage(CUPSD_LOG_WARN,
4388 "Bad default resolution \"%s\" for printer %s.",
4389 ppd_attr->value, p->name);
7cf5915e 4390 xdpi = ydpi = 300;
5a6b583a
MS
4391 }
4392
4393 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4394 "printer-resolution-default", IPP_RES_PER_INCH,
4395 xdpi, ydpi);
4396 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4397 "printer-resolution-supported", IPP_RES_PER_INCH,
4398 xdpi, ydpi);
4399 }
4400 else
4401 {
4402 /*
4403 * No resolutions in PPD - make one up...
4404 */
4405
4406 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4407 "printer-resolution-default", IPP_RES_PER_INCH,
7cf5915e 4408 300, 300);
5a6b583a
MS
4409 ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
4410 "printer-resolution-supported", IPP_RES_PER_INCH,
7cf5915e 4411 300, 300);
5a6b583a
MS
4412 }
4413
61cf44e2
MS
4414 /*
4415 * Duplexing, etc...
4416 */
4417
7cf5915e
MS
4418 ppdMarkDefaults(ppd);
4419
61cf44e2
MS
4420 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
4421 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
4422 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
4423 if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
4424 duplex = ppdFindOption(ppd, "JCLDuplex");
4425
4426 if (duplex && duplex->num_choices > 1 &&
4427 !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
4428 {
4429 p->type |= CUPS_PRINTER_DUPLEX;
4430
4431 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4432 "sides-supported", 3, NULL, sides);
4433
88f9aafc 4434 if (!_cups_strcasecmp(duplex->defchoice, "DuplexTumble"))
61cf44e2
MS
4435 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4436 "sides-default", NULL, "two-sided-short-edge");
88f9aafc 4437 else if (!_cups_strcasecmp(duplex->defchoice, "DuplexNoTumble"))
61cf44e2
MS
4438 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4439 "sides-default", NULL, "two-sided-long-edge");
4440 else
4441 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4442 "sides-default", NULL, "one-sided");
4443 }
cc754834
MS
4444 else
4445 {
4446 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4447 "sides-supported", NULL, "one-sided");
4448 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4449 "sides-default", NULL, "one-sided");
4450 }
61cf44e2
MS
4451
4452 if (ppdFindOption(ppd, "Collate") != NULL)
4453 p->type |= CUPS_PRINTER_COLLATE;
4454
4455 if (ppdFindOption(ppd, "StapleLocation") != NULL)
4456 {
4457 p->type |= CUPS_PRINTER_STAPLE;
4458 finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
4459 }
4460
4461 if (ppdFindOption(ppd, "BindEdge") != NULL)
4462 {
4463 p->type |= CUPS_PRINTER_BIND;
4464 finishings[num_finishings++] = IPP_FINISHINGS_BIND;
4465 }
4466
4467 for (i = 0; i < ppd->num_sizes; i ++)
4468 if (ppd->sizes[i].length > 1728)
4469 p->type |= CUPS_PRINTER_LARGE;
4470 else if (ppd->sizes[i].length > 1008)
4471 p->type |= CUPS_PRINTER_MEDIUM;
4472 else
4473 p->type |= CUPS_PRINTER_SMALL;
4474
b9faaae1 4475 if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL &&
88f9aafc 4476 ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
b9faaae1
MS
4477 {
4478 if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL &&
88f9aafc 4479 ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
b9faaae1
MS
4480 p->type |= CUPS_PRINTER_SCANNER;
4481 else
4482 p->type |= CUPS_PRINTER_MFP;
4483 }
4484
61cf44e2 4485 /*
f14324a7 4486 * Scan the filters in the PPD file...
61cf44e2
MS
4487 */
4488
f14324a7 4489 if (p->pc)
c8fef167 4490 {
f14324a7
MS
4491 for (filter = (const char *)cupsArrayFirst(p->pc->filters);
4492 filter;
4493 filter = (const char *)cupsArrayNext(p->pc->filters))
c8fef167 4494 {
88f9aafc 4495 if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
f14324a7
MS
4496 _cups_isspace(filter[28]))
4497 {
4498 p->type |= CUPS_PRINTER_COMMANDS;
61cf44e2 4499 break;
f14324a7 4500 }
61cf44e2
MS
4501 }
4502 }
4503
4504 if (p->type & CUPS_PRINTER_COMMANDS)
4505 {
4506 char *commands, /* Copy of commands */
4507 *start, /* Start of name */
4508 *end; /* End of name */
4509 int count; /* Number of commands */
4510
f14324a7 4511 if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL)
61cf44e2
MS
4512 {
4513 for (count = 0, start = ppd_attr->value; *start; count ++)
4514 {
f14324a7 4515 while (_cups_isspace(*start))
61cf44e2
MS
4516 start ++;
4517
4518 if (!*start)
4519 break;
4520
4521 while (*start && !isspace(*start & 255))
4522 start ++;
4523 }
4524 }
4525 else
4526 count = 0;
4527
4528 if (count > 0)
4529 {
4530 /*
0268488e
MS
4531 * Make a copy of the commands string and count how many commands there
4532 * are...
61cf44e2
MS
4533 */
4534
4535 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4536 "printer-commands", count, NULL, NULL);
4537
4538 commands = strdup(ppd_attr->value);
4539
4540 for (count = 0, start = commands; *start; count ++)
4541 {
4542 while (isspace(*start & 255))
4543 start ++;
4544
4545 if (!*start)
4546 break;
4547
4548 end = start;
4549 while (*end && !isspace(*end & 255))
4550 end ++;
4551
4552 if (*end)
4553 *end++ = '\0';
4554
4555 attr->values[count].string.text = _cupsStrAlloc(start);
4556
4557 start = end;
4558 }
4559
4560 free(commands);
4561 }
4562 else
4563 {
4564 /*
4565 * Add the standard list of commands...
4566 */
4567
4568 ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4569 "printer-commands",
4570 (int)(sizeof(standard_commands) /
4571 sizeof(standard_commands[0])), NULL,
4572 standard_commands);
4573 }
4574 }
4575 else
4576 {
4577 /*
4578 * No commands supported...
4579 */
4580
4581 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
4582 "printer-commands", NULL, "none");
4583 }
4584
4585 /*
4586 * Show current and available port monitors for this printer...
4587 */
4588
4589 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
4590 NULL, p->port_monitor ? p->port_monitor : "none");
4591
4592 for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
4593 ppd_attr;
4594 i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
4595
4596 if (ppd->protocols)
4597 {
4598 if (strstr(ppd->protocols, "TBCP"))
4599 i ++;
4600 else if (strstr(ppd->protocols, "BCP"))
4601 i ++;
4602 }
4603
4604 attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
4605 "port-monitor-supported", i, NULL, NULL);
4606
4607 attr->values[0].string.text = _cupsStrAlloc("none");
4608
4609 for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
4610 ppd_attr;
4611 i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
4612 attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value);
4613
4614 if (ppd->protocols)
4615 {
4616 if (strstr(ppd->protocols, "TBCP"))
4617 attr->values[i].string.text = _cupsStrAlloc("tbcp");
4618 else if (strstr(ppd->protocols, "BCP"))
4619 attr->values[i].string.text = _cupsStrAlloc("bcp");
4620 }
4621
61cf44e2
MS
4622 if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
4623 p->type |= CUPS_PRINTER_REMOTE;
4624
7cf5915e
MS
4625#ifdef HAVE_APPLICATIONSERVICES_H
4626 /*
4627 * Convert the file referenced in APPrinterIconPath to a 128x128 PNG
4628 * and save it as cacheDir/printername.png
4629 */
4630
4631 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
22c9029b
MS
4632 ppd_attr->value &&
4633 !_cupsFileCheck(ppd_attr->value, _CUPS_FILE_CHECK_FILE, !RunUser,
4634 cupsdLogFCMessage, p))
7cf5915e
MS
4635 {
4636 CGImageRef imageRef = NULL;/* Current icon image */
4637 CGImageRef biggestIconRef = NULL;
4638 /* Biggest icon image */
4639 CGImageRef closestTo128IconRef = NULL;
4640 /* Icon image closest to and >= 128 */
4641 CGImageSourceRef sourceRef; /* The file's image source */
4642 char outPath[HTTP_MAX_URI];
4643 /* The path to the PNG file */
4644 CFURLRef outUrl; /* The URL made from the outPath */
4645 CFURLRef icnsFileUrl; /* The URL of the original ICNS icon file */
4646 CGImageDestinationRef destRef; /* The image destination to write */
4647 size_t bytesPerRow; /* The bytes per row used for resizing */
4648 CGContextRef context; /* The CG context used for resizing */
4649
4650 snprintf(outPath, sizeof(outPath), "%s/%s.png", CacheDir, p->name);
4651 outUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
4652 (UInt8 *)outPath,
4653 strlen(outPath),
4654 FALSE);
4655 icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
4656 (UInt8 *)ppd_attr->value,
4657 strlen(ppd_attr->value),
4658 FALSE);
4659 if (outUrl && icnsFileUrl)
4660 {
4661 sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL);
4662 if (sourceRef)
4663 {
4664 for (i = 0; i < CGImageSourceGetCount(sourceRef); i ++)
4665 {
4666 imageRef = CGImageSourceCreateImageAtIndex(sourceRef, i, NULL);
c8fef167
MS
4667 if (!imageRef)
4668 continue;
4669
4670 if (CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef))
7cf5915e
MS
4671 {
4672 /*
4673 * Loop through remembering the icon closest to 128 but >= 128
4674 * and then remember the largest icon.
4675 */
4676
4677 if (CGImageGetWidth(imageRef) >= 128 &&
4678 (!closestTo128IconRef ||
4679 CGImageGetWidth(imageRef) <
4680 CGImageGetWidth(closestTo128IconRef)))
4681 {
4682 CGImageRelease(closestTo128IconRef);
4683 CGImageRetain(imageRef);
4684 closestTo128IconRef = imageRef;
4685 }
4686
4687 if (!biggestIconRef ||
4688 CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef))
4689 {
4690 CGImageRelease(biggestIconRef);
4691 CGImageRetain(imageRef);
4692 biggestIconRef = imageRef;
4693 }
c8fef167 4694 }
7cf5915e 4695
c8fef167 4696 CGImageRelease(imageRef);
7cf5915e
MS
4697 }
4698
4699 if (biggestIconRef)
4700 {
4701 /*
4702 * If biggestIconRef is NULL, we found no icons. Otherwise we first
4703 * want the closest to 128, but if none are larger than 128, we want
4704 * the largest icon available.
4705 */
4706
4707 imageRef = closestTo128IconRef ? closestTo128IconRef :
4708 biggestIconRef;
4709 CGImageRetain(imageRef);
4710 CGImageRelease(biggestIconRef);
c8fef167
MS
4711 if (closestTo128IconRef)
4712 CGImageRelease(closestTo128IconRef);
7cf5915e
MS
4713 destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1,
4714 NULL);
4715 if (destRef)
4716 {
4717 if (CGImageGetWidth(imageRef) != 128)
4718 {
4719 bytesPerRow = CGImageGetBytesPerRow(imageRef) /
4720 CGImageGetWidth(imageRef) * 128;
4721 context = CGBitmapContextCreate(NULL, 128, 128,
4722 CGImageGetBitsPerComponent(imageRef),
4723 bytesPerRow,
4724 CGImageGetColorSpace(imageRef),
4725 kCGImageAlphaPremultipliedFirst);
4726 if (context)
4727 {
4728 CGContextDrawImage(context, CGRectMake(0, 0, 128, 128),
4729 imageRef);
4730 CGImageRelease(imageRef);
4731 imageRef = CGBitmapContextCreateImage(context);
4732 CGContextRelease(context);
4733 }
4734 }
4735
4736 CGImageDestinationAddImage(destRef, imageRef, NULL);
4737 CGImageDestinationFinalize(destRef);
4738 CFRelease(destRef);
4739 }
4740
4741 CGImageRelease(imageRef);
c8fef167 4742 }
7cf5915e
MS
4743
4744 CFRelease(sourceRef);
7cf5915e 4745 }
e60ec91f 4746 }
7cf5915e 4747
e60ec91f 4748 if (outUrl)
7cf5915e 4749 CFRelease(outUrl);
e60ec91f
MS
4750
4751 if (icnsFileUrl)
4752 CFRelease(icnsFileUrl);
7cf5915e
MS
4753 }
4754#endif /* HAVE_APPLICATIONSERVICES_H */
4755
61cf44e2
MS
4756 /*
4757 * Close the PPD and set the type...
4758 */
4759
4760 ppdClose(ppd);
4761 }
4762 else if (!access(ppd_name, 0))
4763 {
4764 int pline; /* PPD line number */
4765 ppd_status_t pstatus; /* PPD load status */
4766
4767
4768 pstatus = ppdLastError(&pline);
4769
4770 cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
4771 p->name);
4772
4773 if (pstatus <= PPD_ALLOC_ERROR)
4774 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
4775 else
4776 cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
4777 ppdErrorString(pstatus), pline);
4778
4779 cupsdLogMessage(CUPSD_LOG_INFO,
4780 "Hint: Run \"cupstestppd %s\" and fix any errors.",
4781 ppd_name);
61cf44e2
MS
4782 }
4783 else
4784 {
4785 /*
4786 * If we have an interface script, add a filter entry for it...
4787 */
4788
4789 char interface[1024]; /* Interface script */
4790
4791
4792 snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
4793 p->name);
4794 if (!access(interface, X_OK))
4795 {
4796 /*
4797 * Yes, we have a System V style interface script; use it!
4798 */
4799
4800 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
4801 "printer-make-and-model", NULL,
4802 "Local System V Printer");
61cf44e2 4803 }
37e7e6e0
MS
4804 else if (((!strncmp(p->device_uri, "ipp://", 6) ||
4805 !strncmp(p->device_uri, "ipps://", 7)) &&
4806 (strstr(p->device_uri, "/printers/") != NULL ||
4807 strstr(p->device_uri, "/classes/") != NULL)) ||
4808 ((strstr(p->device_uri, "._ipp.") != NULL ||
4809 strstr(p->device_uri, "._ipps.") != NULL) &&
4810 !strcmp(p->device_uri + strlen(p->device_uri) - 5, "/cups")))
61cf44e2
MS
4811 {
4812 /*
4813 * Tell the client this is really a hard-wired remote printer.
4814 */
4815
4816 p->type |= CUPS_PRINTER_REMOTE;
4817
4818 /*
4819 * Point the printer-uri-supported attribute to the
4820 * remote printer...
4821 */
4822
0268488e
MS
4823 if (strchr(p->device_uri, '?'))
4824 {
4825 /*
4826 * Strip trailing "?options" from URI...
4827 */
4828
4829 char resource[HTTP_MAX_URI], /* New URI */
4830 *ptr; /* Pointer into URI */
4831
4832 strlcpy(resource, p->device_uri, sizeof(resource));
4833 if ((ptr = strchr(resource, '?')) != NULL)
4834 *ptr = '\0';
4835
4836 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
4837 "printer-uri-supported", NULL, resource);
4838 }
4839 else
4840 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
4841 "printer-uri-supported", NULL, p->device_uri);
61cf44e2
MS
4842
4843 /*
4844 * Then set the make-and-model accordingly...
4845 */
4846
4847 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
4848 "printer-make-and-model", NULL, "Remote Printer");
4849
4850 /*
4851 * Print all files directly...
4852 */
4853
4854 p->raw = 1;
4855 p->remote = 1;
4856 }
4857 else
4858 {
4859 /*
4860 * Otherwise we have neither - treat this as a "dumb" printer
4861 * with no PPD file...
4862 */
4863
4864 ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
4865 "printer-make-and-model", NULL, "Local Raw Printer");
4866
4867 p->raw = 1;
4868 }
4869 }
4870
4871 ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
4872 "finishings-supported", num_finishings, finishings);
4873 ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
4874 "finishings-default", IPP_FINISHINGS_NONE);
4875
f14324a7 4876 if (ppd && p->pc)
61cf44e2
MS
4877 {
4878 /*
4879 * Save cached PPD attributes to disk...
4880 */
4881
4882 cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name);
4883
f14324a7 4884 _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs);
61cf44e2 4885 }
54afec33 4886 else
61cf44e2
MS
4887 {
4888 /*
54afec33 4889 * Remove cache files...
61cf44e2
MS
4890 */
4891
54afec33
MS
4892 if (cache_info.st_mtime)
4893 unlink(cache_name);
61cf44e2
MS
4894 }
4895}
4896
4897
bd8b6777
MS
4898/*
4899 * 'log_ipp_conformance()' - Log an IPP conformance issue with a printer.
4900 */
4901
4902static void
4903log_ipp_conformance(
4904 cupsd_printer_t *p, /* I - Printer */
4905 const char *reason) /* I - Printer state reason */
4906{
4907 const char *message; /* Message to log */
4908#ifdef __APPLE__
4909 aslmsg aslm; /* Apple System Log message */
4910#endif /* __APPLE__ */
4911
4912
4913 /*
4914 * Strip the leading "cups-ipp-" from the reason and create a log message for
4915 * it...
4916 */
4917
4918 reason += 9;
4919 if (!strcmp(reason, "missing-cancel-job"))
4920 message = "Printer does not support REQUIRED Cancel-Job operation.";
4921 else if (!strcmp(reason, "missing-get-job-attributes"))
4922 message = "Printer does not support REQUIRED Get-Job-Attributes operation.";
4923 else if (!strcmp(reason, "missing-print-job"))
4924 message = "Printer does not support REQUIRED Print-Job operation.";
4925 else if (!strcmp(reason, "missing-validate-job"))
4926 message = "Printer does not support REQUIRED Validate-Job operation.";
4927 else if (!strcmp(reason, "missing-get-printer-attributes"))
4928 message = "Printer does not support REQUIRED Get-Printer-Attributes operation.";
a29fd7dd
MS
4929 else if (!strcmp(reason, "missing-send-document"))
4930 message = "Printer supports Create-Job but not Send-Document operation.";
bd8b6777
MS
4931 else if (!strcmp(reason, "missing-job-history"))
4932 message = "Printer does not provide REQUIRED job history.";
4933 else if (!strcmp(reason, "missing-job-id"))
4934 message = "Printer does not provide REQUIRED job-id attribute.";
4935 else if (!strcmp(reason, "missing-job-state"))
4936 message = "Printer does not provide REQUIRED job-state attribute.";
4937 else if (!strcmp(reason, "missing-operations-supported"))
4938 message = "Printer does not provide REQUIRED operations-supported "
4939 "attribute.";
4940 else if (!strcmp(reason, "missing-printer-is-accepting-jobs"))
4941 message = "Printer does not provide REQUIRED printer-is-accepting-jobs "
4942 "attribute.";
4943 else if (!strcmp(reason, "missing-printer-state-reasons"))
4944 message = "Printer does not provide REQUIRED printer-state-reasons "
4945 "attribute.";
4946 else if (!strcmp(reason, "wrong-http-version"))
4947 message = "Printer does not use REQUIRED HTTP/1.1 transport.";
4948 else
4949 message = "Unknown IPP conformance failure.";
4950
4951 cupsdLogMessage(CUPSD_LOG_WARN, "%s: %s", p->name, message);
4952
4953#ifdef __APPLE__
4954 /*
4955 * Report the failure information to Apple if the user opts into providing
4956 * feedback to Apple...
4957 */
4958
4959 aslm = asl_new(ASL_TYPE_MSG);
4960 if (aslm)
4961 {
4962 asl_set(aslm, "com.apple.message.domain", "com.apple.printing.ipp.conformance");
4963 asl_set(aslm, "com.apple.message.domain_scope", "com.apple.printing.ipp.conformance");
4964 asl_set(aslm, "com.apple.message.signature", reason);
4965 asl_set(aslm, "com.apple.message.signature2",
4966 p->make_model ? p->make_model : "Unknown");
4967 asl_log(NULL, aslm, ASL_LEVEL_NOTICE, "%s: %s",
4968 p->make_model ? p->make_model : "Unknown", message);
4969 asl_free(aslm);
4970 }
4971#endif /* __APPLE__ */
4972}
4973
4974
54afec33
MS
4975/*
4976 * 'new_media_col()' - Create a media-col collection value.
4977 */
4978
4979static ipp_t * /* O - Collection value */
4980new_media_col(_pwg_size_t *size, /* I - media-size/margin values */
4981 const char *source, /* I - media-source value */
4982 const char *type) /* I - media-type value */
4983{
4984 ipp_t *media_col, /* Collection value */
4985 *media_size; /* media-size value */
4986
4987
4988 media_col = ippNew();
4989
4990 media_size = ippNew();
4991 ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4992 "x-dimension", size->width);
4993 ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4994 "y-dimension", size->length);
54afec33 4995 ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size);
aaf19ab0
MS
4996 ippDelete(media_size);
4997
54afec33
MS
4998 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
4999 "media-bottom-margin", size->bottom);
5000 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5001 "media-left-margin", size->left);
5002 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5003 "media-right-margin", size->right);
5004 ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
5005 "media-top-margin", size->top);
5006
5007 if (source)
5008 ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source",
5009 NULL, source);
5010
5011 if (type)
5012 ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type",
5013 NULL, type);
5014
5015 return (media_col);
5016}
5017
5018
ef416fc2 5019/*
0af14961
MS
5020 * 'write_xml_string()' - Write a string with XML escaping.
5021 */
5022
5023static void
5024write_xml_string(cups_file_t *fp, /* I - File to write to */
5025 const char *s) /* I - String to write */
5026{
5027 const char *start; /* Start of current sequence */
5028
5029
5030 if (!s)
5031 return;
5032
5033 for (start = s; *s; s ++)
5034 {
5035 if (*s == '&')
5036 {
5037 if (s > start)
5038 cupsFileWrite(fp, start, s - start);
5039
5040 cupsFilePuts(fp, "&amp;");
5041 start = s + 1;
5042 }
5043 else if (*s == '<')
5044 {
5045 if (s > start)
5046 cupsFileWrite(fp, start, s - start);
5047
5048 cupsFilePuts(fp, "&lt;");
5049 start = s + 1;
5050 }
5051 }
5052
5053 if (s > start)
5054 cupsFilePuts(fp, start);
5055}
5056
5057
5058/*
5059 * End of "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $".
ef416fc2 5060 */