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