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