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