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