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