]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/printers.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / printers.c
CommitLineData
ef416fc2 1/*
3d8365b8 2 * "$Id: printers.c 6539 2007-05-23 15:08:29Z mike $"
ef416fc2 3 *
4 * Printer routines for the Common UNIX Printing System (CUPS).
5 *
f7deaa1a 6 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * cupsdAddPrinter() - Add a printer to the system.
ef416fc2 27 * cupsdAddPrinterHistory() - Add the current printer state to the history.
28 * cupsdAddPrinterUser() - Add a user to the ACL.
b94498cf 29 * cupsdCreateCommonData() - Create the common printer data.
ef416fc2 30 * cupsdDeleteAllPrinters() - Delete all printers from the system.
31 * cupsdDeletePrinter() - Delete a printer from the system.
ef416fc2 32 * cupsdFindPrinter() - Find a printer in the list.
33 * cupsdFreePrinterUsers() - Free allow/deny users.
34 * cupsdLoadAllPrinters() - Load printers from the printers.conf file.
b423cd4c 35 * cupsdRenamePrinter() - Rename a printer.
fa73b229 36 * cupsdSaveAllPrinters() - Save all printer definitions to the
37 * printers.conf file.
38 * cupsdSetPrinterAttrs() - Set printer attributes based upon the PPD
39 * file.
ef416fc2 40 * cupsdSetPrinterReasons() - Set/update the reasons strings.
41 * cupsdSetPrinterState() - Update the current state of a printer.
42 * cupsdStopPrinter() - Stop a printer from printing any jobs...
43 * cupsdUpdatePrinters() - Update printers after a partial reload.
44 * cupsdValidateDest() - Validate a printer/class destination.
45 * cupsdWritePrintcap() - Write a pseudo-printcap file for older
46 * applications that need it...
47 * cupsdSanitizeURI() - Sanitize a device URI...
b423cd4c 48 * add_printer_defaults() - Add name-default attributes to the printer
49 * attributes.
bd7854cb 50 * add_printer_filter() - Add a MIME filter for a printer.
51 * add_printer_formats() - Add document-format-supported values for
52 * a printer.
ef416fc2 53 * compare_printers() - Compare two printers.
e1d6a774 54 * delete_printer_filters() - Delete all MIME filters for a printer.
ef416fc2 55 * write_irix_config() - Update the config files used by the IRIX
56 * desktop tools.
fa73b229 57 * write_irix_state() - Update the status files used by IRIX
58 * printing desktop tools.
ef416fc2 59 */
60
61/*
62 * Include necessary headers...
63 */
64
65#include "cupsd.h"
ed486911 66#include <cups/dir.h>
ef416fc2 67
68
3d8365b8 69/*
70 * Currently Bonjour printers that are shared by CUPS servers are added
71 * manually by the user on Mac OS X systems. While these printers *are*
72 * remote queues, the current print dialog will not show them if they
73 * (correctly) have the CUPS_PRINTER_REMOTE bit set. This may change
74 * in future releases, however the code to do this is currently disabled.
75 *
76 * Define BONJOUR_IS_REMOTE to 1 to get the correct behavior...
77 */
78
79#define BONJOUR_IS_REMOTE 0
80
81
ef416fc2 82/*
83 * Local functions...
84 */
85
b423cd4c 86static void add_printer_defaults(cupsd_printer_t *p);
f7deaa1a 87static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
88 const char *filter);
bd7854cb 89static void add_printer_formats(cupsd_printer_t *p);
ef416fc2 90static int compare_printers(void *first, void *second, void *data);
e1d6a774 91static void delete_printer_filters(cupsd_printer_t *p);
ef416fc2 92#ifdef __sgi
93static void write_irix_config(cupsd_printer_t *p);
94static void write_irix_state(cupsd_printer_t *p);
95#endif /* __sgi */
96
97
98/*
99 * 'cupsdAddPrinter()' - Add a printer to the system.
100 */
101
102cupsd_printer_t * /* O - New printer */
103cupsdAddPrinter(const char *name) /* I - Name of printer */
104{
105 cupsd_printer_t *p; /* New printer */
106
107
108 /*
109 * Range check input...
110 */
111
112 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name);
113
114 /*
115 * Create a new printer entity...
116 */
117
118 if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL)
119 {
120 cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s",
121 strerror(errno));
122 return (NULL);
123 }
124
125 cupsdSetString(&p->name, name);
126 cupsdSetString(&p->info, name);
127 cupsdSetString(&p->hostname, ServerName);
128
129 cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, LocalPort, name);
130 cupsdSetStringf(&p->device_uri, "file:/dev/null");
131
132 p->state = IPP_PRINTER_STOPPED;
133 p->state_time = time(NULL);
134 p->accepting = 0;
fa73b229 135 p->shared = DefaultShared;
ef416fc2 136 p->filetype = mimeAddType(MimeDatabase, "printer", name);
137
138 cupsdSetString(&p->job_sheets[0], "none");
139 cupsdSetString(&p->job_sheets[1], "none");
140
323c5de1 141 cupsdSetString(&p->error_policy, ErrorPolicy);
ef416fc2 142 cupsdSetString(&p->op_policy, DefaultPolicy);
143
144 p->op_policy_ptr = DefaultPolicyPtr;
145
146 if (MaxPrinterHistory)
147 p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
148
149 /*
150 * Insert the printer in the printer list alphabetically...
151 */
152
153 if (!Printers)
154 Printers = cupsArrayNew(compare_printers, NULL);
155
156 cupsArrayAdd(Printers, p);
157
158 if (!ImplicitPrinters)
159 ImplicitPrinters = cupsArrayNew(compare_printers, NULL);
160
161 /*
162 * Return the new printer...
163 */
164
165 return (p);
166}
167
168
ef416fc2 169/*
170 * 'cupsdAddPrinterHistory()' - Add the current printer state to the history.
171 */
172
173void
174cupsdAddPrinterHistory(
175 cupsd_printer_t *p) /* I - Printer */
176{
177 ipp_t *history; /* History collection */
178
179
180 /*
181 * Stop early if we aren't keeping history data...
182 */
183
184 if (MaxPrinterHistory <= 0)
185 return;
186
187 /*
188 * Retire old history data as needed...
189 */
190
191 p->sequence_number ++;
192
193 if (p->num_history >= MaxPrinterHistory)
194 {
195 p->num_history --;
196 ippDelete(p->history[0]);
197 memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *));
198 }
199
200 /*
201 * Create a collection containing the current printer-state, printer-up-time,
202 * printer-state-message, and printer-state-reasons attributes.
203 */
204
205 history = ippNew();
206 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
207 p->state);
208 ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
209 p->accepting);
fa73b229 210 ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
ef416fc2 211 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
212 NULL, p->state_message);
e00b005a 213#ifdef __APPLE__
214 if (p->recoverable)
215 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT,
216 "com.apple.print.recoverable-message", NULL, p->recoverable);
217#endif /* __APPLE__ */
ef416fc2 218 if (p->num_reasons == 0)
219 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
220 "printer-state-reasons", NULL,
221 p->state == IPP_PRINTER_STOPPED ? "paused" : "none");
222 else
223 ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
224 "printer-state-reasons", p->num_reasons, NULL,
225 (const char * const *)p->reasons);
226 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
227 "printer-state-change-time", p->state_time);
228 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
229 "printer-state-sequence-number", p->sequence_number);
230
231 p->history[p->num_history] = history;
232 p->num_history ++;
233}
234
235
236/*
237 * 'cupsdAddPrinterUser()' - Add a user to the ACL.
238 */
239
240void
241cupsdAddPrinterUser(
242 cupsd_printer_t *p, /* I - Printer */
243 const char *username) /* I - User */
244{
245 const char **temp; /* Temporary array pointer */
246
247
248 if (!p || !username)
249 return;
250
251 if (p->num_users == 0)
252 temp = malloc(sizeof(char **));
253 else
254 temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
255
256 if (!temp)
257 return;
258
259 p->users = temp;
260 temp += p->num_users;
261
262 if ((*temp = strdup(username)) != NULL)
263 p->num_users ++;
264}
265
266
267/*
268 * 'cupsdCreateCommonData()' - Create the common printer data.
269 */
270
271void
272cupsdCreateCommonData(void)
273{
274 int i; /* Looping var */
275 ipp_attribute_t *attr; /* Attribute data */
ed486911 276 cups_dir_t *dir; /* Notifier directory */
277 cups_dentry_t *dent; /* Notifier directory entry */
278 cups_array_t *notifiers; /* Notifier array */
279 char filename[1024], /* Filename */
280 *notifier; /* Current notifier */
ef416fc2 281 static const int nups[] = /* number-up-supported values */
282 { 1, 2, 4, 6, 9, 16 };
b94498cf 283 static const int orients[4] =/* orientation-requested-supported values */
ef416fc2 284 {
285 IPP_PORTRAIT,
286 IPP_LANDSCAPE,
287 IPP_REVERSE_LANDSCAPE,
288 IPP_REVERSE_PORTRAIT
289 };
290 static const char * const holds[] = /* job-hold-until-supported values */
291 {
292 "no-hold",
293 "indefinite",
294 "day-time",
295 "evening",
296 "night",
297 "second-shift",
298 "third-shift",
299 "weekend"
300 };
301 static const char * const versions[] =/* ipp-versions-supported values */
302 {
303 "1.0",
304 "1.1"
305 };
b94498cf 306 static const int ops[] = /* operations-supported values */
ef416fc2 307 {
308 IPP_PRINT_JOB,
309 IPP_VALIDATE_JOB,
310 IPP_CREATE_JOB,
311 IPP_SEND_DOCUMENT,
312 IPP_CANCEL_JOB,
313 IPP_GET_JOB_ATTRIBUTES,
314 IPP_GET_JOBS,
315 IPP_GET_PRINTER_ATTRIBUTES,
316 IPP_HOLD_JOB,
317 IPP_RELEASE_JOB,
318 IPP_PAUSE_PRINTER,
319 IPP_RESUME_PRINTER,
320 IPP_PURGE_JOBS,
321 IPP_SET_JOB_ATTRIBUTES,
322 IPP_CREATE_PRINTER_SUBSCRIPTION,
323 IPP_CREATE_JOB_SUBSCRIPTION,
324 IPP_GET_SUBSCRIPTION_ATTRIBUTES,
325 IPP_GET_SUBSCRIPTIONS,
326 IPP_RENEW_SUBSCRIPTION,
327 IPP_CANCEL_SUBSCRIPTION,
328 IPP_GET_NOTIFICATIONS,
329 IPP_ENABLE_PRINTER,
330 IPP_DISABLE_PRINTER,
331 CUPS_GET_DEFAULT,
332 CUPS_GET_PRINTERS,
333 CUPS_ADD_PRINTER,
334 CUPS_DELETE_PRINTER,
335 CUPS_GET_CLASSES,
336 CUPS_ADD_CLASS,
337 CUPS_DELETE_CLASS,
338 CUPS_ACCEPT_JOBS,
339 CUPS_REJECT_JOBS,
340 CUPS_SET_DEFAULT,
341 CUPS_GET_DEVICES,
342 CUPS_GET_PPDS,
343 CUPS_MOVE_JOB,
344 CUPS_AUTHENTICATE_JOB,
345 IPP_RESTART_JOB
346 };
347 static const char * const charsets[] =/* charset-supported values */
348 {
349 "us-ascii",
350 "utf-8"
351 };
352 static const char * const compressions[] =
353 { /* document-compression-supported values */
354 "none"
355#ifdef HAVE_LIBZ
356 ,"gzip"
357#endif /* HAVE_LIBZ */
358 };
359 static const char * const multiple_document_handling[] =
360 { /* multiple-document-handling-supported values */
361 "separate-documents-uncollated-copies",
362 "separate-documents-collated-copies"
363 };
364 static const char * const errors[] = /* printer-error-policy-supported values */
365 {
366 "abort-job",
367 "retry-job",
368 "stop-printer"
369 };
370 static const char * const notify_attrs[] =
371 { /* notify-attributes-supported values */
372 "printer-state-change-time",
373 "notify-lease-expiration-time",
374 "notify-subscriber-user-name"
375 };
376 static const char * const notify_events[] =
377 { /* notify-events-supported values */
378 "job-completed",
379 "job-config-changed",
380 "job-created",
381 "job-progress",
382 "job-state-changed",
383 "job-stopped",
384 "printer-added",
385 "printer-changed",
386 "printer-config-changed",
387 "printer-deleted",
388 "printer-finishings-changed",
389 "printer-media-changed",
390 "printer-modified",
391 "printer-restarted",
392 "printer-shutdown",
393 "printer-state-changed",
394 "printer-stopped",
395 "server-audit",
396 "server-restarted",
397 "server-started",
398 "server-stopped"
399 };
400
401
402 if (CommonData)
403 ippDelete(CommonData);
404
405 CommonData = ippNew();
406
407 /*
408 * This list of attributes is sorted to improve performance when the
409 * client provides a requested-attributes attribute...
410 */
411
412 /* charset-configured */
413 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET,
414 "charset-configured", NULL, DefaultCharset);
415
416 /* charset-supported */
417 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET,
418 "charset-supported", sizeof(charsets) / sizeof(charsets[0]),
419 NULL, charsets);
420
421 /* compression-supported */
422 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
423 "compression-supported",
424 sizeof(compressions) / sizeof(compressions[0]),
425 NULL, compressions);
426
ef416fc2 427 /* copies-supported */
428 ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
429
b94498cf 430 /* cups-version */
431 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT, "cups-version",
432 NULL, CUPS_SVERSION + 6);
433
ef416fc2 434 /* generated-natural-language-supported */
435 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
436 "generated-natural-language-supported", NULL, DefaultLanguage);
437
438 /* ipp-versions-supported */
439 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
440 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
441 NULL, versions);
442
ef416fc2 443 /* job-hold-until-supported */
444 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
445 "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
446 NULL, holds);
447
ef416fc2 448 /* job-priority-supported */
449 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
450 "job-priority-supported", 100);
451
452 /* job-sheets-supported */
fa73b229 453 if (cupsArrayCount(Banners) > 0)
ef416fc2 454 {
455 /*
456 * Setup the job-sheets-supported attribute...
457 */
458
459 if (Classification && !ClassifyOverride)
460 attr = ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
461 "job-sheets-supported", NULL, Classification);
462 else
463 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
fa73b229 464 "job-sheets-supported", cupsArrayCount(Banners) + 1,
465 NULL, NULL);
ef416fc2 466
467 if (attr == NULL)
468 cupsdLogMessage(CUPSD_LOG_EMERG,
bd7854cb 469 "Unable to allocate memory for "
ef416fc2 470 "job-sheets-supported attribute: %s!", strerror(errno));
471 else if (!Classification || ClassifyOverride)
472 {
fa73b229 473 cupsd_banner_t *banner; /* Current banner */
474
475
757d2cad 476 attr->values[0].string.text = _cupsStrAlloc("none");
ef416fc2 477
fa73b229 478 for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners);
479 banner;
480 i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners))
757d2cad 481 attr->values[i].string.text = _cupsStrAlloc(banner->name);
ef416fc2 482 }
483 }
484 else
485 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
486 "job-sheets-supported", NULL, "none");
487
488 /* multiple-document-handling-supported */
489 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
490 "multiple-document-handling-supported",
491 sizeof(multiple_document_handling) /
492 sizeof(multiple_document_handling[0]), NULL,
493 multiple_document_handling);
494
495 /* multiple-document-jobs-supported */
496 ippAddBoolean(CommonData, IPP_TAG_PRINTER,
497 "multiple-document-jobs-supported", 1);
498
499 /* multiple-operation-time-out */
500 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
501 "multiple-operation-time-out", 60);
502
503 /* natural-language-configured */
504 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
505 "natural-language-configured", NULL, DefaultLanguage);
506
507 /* notify-attributes-supported */
508 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
509 "notify-attributes-supported",
510 (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])),
511 NULL, notify_attrs);
512
ef416fc2 513 /* notify-lease-duration-supported */
514 ippAddRange(CommonData, IPP_TAG_PRINTER,
515 "notify-lease-duration-supported", 0,
516 MaxLeaseDuration ? MaxLeaseDuration : 2147483647);
517
518 /* notify-max-events-supported */
519 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
520 "notify-max-events-supported", MaxEvents);
521
ed486911 522 /* notify-events-supported */
ef416fc2 523 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
524 "notify-events-supported",
525 (int)(sizeof(notify_events) / sizeof(notify_events[0])),
526 NULL, notify_events);
527
528 /* notify-pull-method-supported */
529 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
530 "notify-pull-method-supported", NULL, "ippget");
531
ef416fc2 532 /* notify-schemes-supported */
ed486911 533 snprintf(filename, sizeof(filename), "%s/notifier", ServerBin);
534 if ((dir = cupsDirOpen(filename)) != NULL)
535 {
536 notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL);
537
538 while ((dent = cupsDirRead(dir)) != NULL)
539 if (S_ISREG(dent->fileinfo.st_mode) &&
540 (dent->fileinfo.st_mode & S_IXOTH) != 0)
541 cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename));
542
543 if (cupsArrayCount(notifiers) > 0)
544 {
545 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
546 "notify-schemes-supported",
547 cupsArrayCount(notifiers), NULL, NULL);
548
549 for (i = 0, notifier = (char *)cupsArrayFirst(notifiers);
550 notifier;
551 i ++, notifier = (char *)cupsArrayNext(notifiers))
552 attr->values[i].string.text = notifier;
553 }
554
555 cupsArrayDelete(notifiers);
8ca02f3c 556 cupsDirClose(dir);
ed486911 557 }
ef416fc2 558
ef416fc2 559 /* number-up-supported */
560 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
561 "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
562
563 /* operations-supported */
564 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
565 "operations-supported",
b94498cf 566 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops);
ef416fc2 567
ef416fc2 568 /* orientation-requested-supported */
569 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
b94498cf 570 "orientation-requested-supported", 4, orients);
ef416fc2 571
572 /* page-ranges-supported */
573 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
574
575 /* pdf-override-supported */
576 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
577 "pdl-override-supported", NULL, "not-attempted");
578
579 /* printer-error-policy-supported */
580 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
581 "printer-error-policy-supported",
582 sizeof(errors) / sizeof(errors[0]), NULL, errors);
583
584 /* printer-op-policy-supported */
585 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
586 "printer-op-policy-supported", NumPolicies, NULL, NULL);
587 for (i = 0; i < NumPolicies; i ++)
757d2cad 588 attr->values[i].string.text = _cupsStrAlloc(Policies[i]->name);
ef416fc2 589}
590
591
592/*
593 * 'cupsdDeleteAllPrinters()' - Delete all printers from the system.
594 */
595
596void
597cupsdDeleteAllPrinters(void)
598{
599 cupsd_printer_t *p; /* Pointer to current printer/class */
600
601
602 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
603 p;
604 p = (cupsd_printer_t *)cupsArrayNext(Printers))
605 if (!(p->type & CUPS_PRINTER_CLASS))
606 cupsdDeletePrinter(p, 0);
607}
608
609
610/*
611 * 'cupsdDeletePrinter()' - Delete a printer from the system.
612 */
613
614void
615cupsdDeletePrinter(
616 cupsd_printer_t *p, /* I - Printer to delete */
617 int update) /* I - Update printers.conf? */
618{
619 int i; /* Looping var */
620#ifdef __sgi
621 char filename[1024]; /* Interface script filename */
622#endif /* __sgi */
623
624
625 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)",
626 p, p->name, update);
627
628 /*
629 * Save the current position in the Printers array...
630 */
631
632 cupsArraySave(Printers);
633
634 /*
635 * Stop printing on this printer...
636 */
637
638 cupsdStopPrinter(p, update);
639
640 /*
641 * If this printer is the next for browsing, point to the next one...
642 */
643
644 if (p == BrowseNext)
645 {
646 cupsArrayFind(Printers, p);
647 BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers);
648 }
649
650 /*
651 * Remove the printer from the list...
652 */
653
654 cupsArrayRemove(Printers, p);
655
8ca02f3c 656 if (p->type & CUPS_PRINTER_IMPLICIT)
657 cupsArrayRemove(ImplicitPrinters, p);
658
ef416fc2 659 /*
660 * Remove the dummy interface/icon/option files under IRIX...
661 */
662
663#ifdef __sgi
664 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
665 unlink(filename);
666
667 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
668 p->name);
669 unlink(filename);
670
671 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
672 unlink(filename);
673
674 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
675 unlink(filename);
676
677 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
678 unlink(filename);
679
680 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
681 unlink(filename);
682#endif /* __sgi */
683
684 /*
e00b005a 685 * If p is the default printer, assign a different one...
ef416fc2 686 */
687
688 if (p == DefaultPrinter)
e00b005a 689 {
690 DefaultPrinter = NULL;
691
692 if (UseNetworkDefault)
693 {
694 /*
695 * Find the first network default printer and use it...
696 */
697
698 cupsd_printer_t *dp; /* New default printer */
699
700
701 for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers);
702 dp;
703 dp = (cupsd_printer_t *)cupsArrayNext(Printers))
704 if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT))
705 {
ed486911 706 DefaultPrinter = dp;
e00b005a 707 break;
708 }
709 }
710 }
ef416fc2 711
712 /*
f7deaa1a 713 * Remove this printer from any classes...
ef416fc2 714 */
715
716 if (!(p->type & CUPS_PRINTER_IMPLICIT))
717 {
718 cupsdDeletePrinterFromClasses(p);
f7deaa1a 719
720 /*
721 * Deregister from any browse protocols...
722 */
723
724 cupsdDeregisterPrinter(p, 1);
ef416fc2 725 }
726
727 /*
728 * Free all memory used by the printer...
729 */
730
731 if (p->printers != NULL)
732 free(p->printers);
733
734 if (MaxPrinterHistory)
735 {
736 for (i = 0; i < p->num_history; i ++)
737 ippDelete(p->history[i]);
738
739 free(p->history);
740 }
741
742 for (i = 0; i < p->num_reasons; i ++)
743 free(p->reasons[i]);
744
745 ippDelete(p->attrs);
746
e1d6a774 747 delete_printer_filters(p);
ef416fc2 748
fa73b229 749 mimeDeleteType(MimeDatabase, p->filetype);
f7deaa1a 750 mimeDeleteType(MimeDatabase, p->prefiltertype);
fa73b229 751
ef416fc2 752 cupsdFreePrinterUsers(p);
753 cupsdFreeQuotas(p);
754
755 cupsdClearString(&p->uri);
756 cupsdClearString(&p->hostname);
757 cupsdClearString(&p->name);
758 cupsdClearString(&p->location);
759 cupsdClearString(&p->make_model);
760 cupsdClearString(&p->info);
761 cupsdClearString(&p->job_sheets[0]);
762 cupsdClearString(&p->job_sheets[1]);
763 cupsdClearString(&p->device_uri);
764 cupsdClearString(&p->port_monitor);
765 cupsdClearString(&p->op_policy);
766 cupsdClearString(&p->error_policy);
767
323c5de1 768 cupsdClearString(&p->alert);
769 cupsdClearString(&p->alert_description);
770
f7deaa1a 771#ifdef HAVE_DNSSD
772 cupsdClearString(&p->product);
773 cupsdClearString(&p->pdl);
774#endif /* HAVE_DNSSD */
775
80ca4592 776 cupsArrayDelete(p->filetypes);
777
b423cd4c 778 if (p->browse_attrs)
779 free(p->browse_attrs);
780
e00b005a 781#ifdef __APPLE__
782 cupsdClearString(&p->recoverable);
783#endif /* __APPLE__ */
784
b423cd4c 785 cupsFreeOptions(p->num_options, p->options);
786
ef416fc2 787 free(p);
788
789 /*
790 * Restore the previous position in the Printers array...
791 */
792
793 cupsArrayRestore(Printers);
794}
795
796
ef416fc2 797/*
798 * 'cupsdFindDest()' - Find a destination in the list.
799 */
800
801cupsd_printer_t * /* O - Destination in list */
802cupsdFindDest(const char *name) /* I - Name of printer or class to find */
803{
804 cupsd_printer_t key; /* Search key */
805
806
807 key.name = (char *)name;
808 return ((cupsd_printer_t *)cupsArrayFind(Printers, &key));
809}
810
811
812/*
813 * 'cupsdFindPrinter()' - Find a printer in the list.
814 */
815
816cupsd_printer_t * /* O - Printer in list */
817cupsdFindPrinter(const char *name) /* I - Name of printer to find */
818{
819 cupsd_printer_t *p; /* Printer in list */
820
821
822 if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS))
823 return (NULL);
824 else
825 return (p);
826}
827
828
829/*
830 * 'cupsdFreePrinterUsers()' - Free allow/deny users.
831 */
832
833void
834cupsdFreePrinterUsers(
835 cupsd_printer_t *p) /* I - Printer */
836{
837 int i; /* Looping var */
838
839
840 if (!p || !p->num_users)
841 return;
842
843 for (i = 0; i < p->num_users; i ++)
844 free((void *)p->users[i]);
845
846 free(p->users);
847
848 p->num_users = 0;
849 p->users = NULL;
850}
851
852
853/*
854 * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file.
855 */
856
857void
858cupsdLoadAllPrinters(void)
859{
860 cups_file_t *fp; /* printers.conf file */
861 int linenum; /* Current line number */
862 char line[1024], /* Line from file */
863 *value, /* Pointer to value */
864 *valueptr; /* Pointer into value */
865 cupsd_printer_t *p; /* Current printer */
866
867
868 /*
869 * Open the printers.conf file...
870 */
871
872 snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
873 if ((fp = cupsFileOpen(line, "r")) == NULL)
874 {
fa73b229 875 if (errno != ENOENT)
bd7854cb 876 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line,
fa73b229 877 strerror(errno));
ef416fc2 878 return;
879 }
880
881 /*
882 * Read printer configurations until we hit EOF...
883 */
884
885 linenum = 0;
886 p = NULL;
887
888 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
889 {
890 /*
891 * Decode the directive...
892 */
893
894 if (!strcasecmp(line, "<Printer") ||
895 !strcasecmp(line, "<DefaultPrinter"))
896 {
897 /*
898 * <Printer name> or <DefaultPrinter name>
899 */
900
901 if (p == NULL && value)
902 {
903 /*
904 * Add the printer and a base file type...
905 */
906
bd7854cb 907 cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading printer %s...", value);
ef416fc2 908
909 p = cupsdAddPrinter(value);
910 p->accepting = 1;
911 p->state = IPP_PRINTER_IDLE;
912
913 /*
914 * Set the default printer as needed...
915 */
916
917 if (!strcasecmp(line, "<DefaultPrinter"))
918 DefaultPrinter = p;
919 }
920 else
921 {
922 cupsdLogMessage(CUPSD_LOG_ERROR,
923 "Syntax error on line %d of printers.conf.", linenum);
924 return;
925 }
926 }
927 else if (!strcasecmp(line, "</Printer>"))
928 {
929 if (p != NULL)
930 {
931 /*
932 * Close out the current printer...
933 */
934
935 cupsdSetPrinterAttrs(p);
936 cupsdAddPrinterHistory(p);
937
938 if (p->device_uri && strncmp(p->device_uri, "file:", 5) &&
939 p->state != IPP_PRINTER_STOPPED)
940 {
941 /*
942 * See if the backend exists...
943 */
944
945 snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
946 p->device_uri);
947
948 if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
949 *valueptr = '\0'; /* Chop everything but URI scheme */
950
951 if (access(line, 0))
952 {
953 /*
954 * Backend does not exist, stop printer...
955 */
956
957 p->state = IPP_PRINTER_STOPPED;
958 snprintf(p->state_message, sizeof(p->state_message),
959 "Backend %s does not exist!", line);
960 }
961 }
962
963 p = NULL;
964 }
965 else
966 {
967 cupsdLogMessage(CUPSD_LOG_ERROR,
968 "Syntax error on line %d of printers.conf.", linenum);
969 return;
970 }
971 }
972 else if (!p)
973 {
974 cupsdLogMessage(CUPSD_LOG_ERROR,
975 "Syntax error on line %d of printers.conf.", linenum);
976 return;
977 }
f7deaa1a 978 else if (!strcasecmp(line, "AuthInfoRequired"))
979 {
980 if (!cupsdSetAuthInfoRequired(p, value, NULL))
981 cupsdLogMessage(CUPSD_LOG_ERROR,
982 "Bad AuthInfoRequired on line %d of printers.conf.",
983 linenum);
984 }
ef416fc2 985 else if (!strcasecmp(line, "Info"))
986 {
987 if (value)
988 cupsdSetString(&p->info, value);
989 }
990 else if (!strcasecmp(line, "Location"))
991 {
992 if (value)
993 cupsdSetString(&p->location, value);
994 }
995 else if (!strcasecmp(line, "DeviceURI"))
996 {
997 if (value)
998 cupsdSetString(&p->device_uri, value);
999 else
1000 {
1001 cupsdLogMessage(CUPSD_LOG_ERROR,
1002 "Syntax error on line %d of printers.conf.", linenum);
1003 return;
1004 }
1005 }
b423cd4c 1006 else if (!strcasecmp(line, "Option") && value)
1007 {
1008 /*
1009 * Option name value
1010 */
1011
1012 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1013
1014 if (!*valueptr)
1015 cupsdLogMessage(CUPSD_LOG_ERROR,
1016 "Syntax error on line %d of printers.conf.", linenum);
1017 else
1018 {
1019 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
1020
1021 p->num_options = cupsAddOption(value, valueptr, p->num_options,
1022 &(p->options));
1023 }
1024 }
ef416fc2 1025 else if (!strcasecmp(line, "PortMonitor"))
1026 {
1027 if (value && strcmp(value, "none"))
1028 cupsdSetString(&p->port_monitor, value);
1029 else if (value)
1030 cupsdClearString(&p->port_monitor);
1031 else
1032 {
1033 cupsdLogMessage(CUPSD_LOG_ERROR,
1034 "Syntax error on line %d of printers.conf.", linenum);
1035 return;
1036 }
1037 }
1038 else if (!strcasecmp(line, "State"))
1039 {
1040 /*
1041 * Set the initial queue state...
1042 */
1043
1044 if (value && !strcasecmp(value, "idle"))
1045 p->state = IPP_PRINTER_IDLE;
1046 else if (value && !strcasecmp(value, "stopped"))
1047 p->state = IPP_PRINTER_STOPPED;
1048 else
1049 {
1050 cupsdLogMessage(CUPSD_LOG_ERROR,
1051 "Syntax error on line %d of printers.conf.", linenum);
1052 return;
1053 }
1054 }
1055 else if (!strcasecmp(line, "StateMessage"))
1056 {
1057 /*
1058 * Set the initial queue state message...
1059 */
1060
1061 if (value)
1062 strlcpy(p->state_message, value, sizeof(p->state_message));
1063 }
1064 else if (!strcasecmp(line, "StateTime"))
1065 {
1066 /*
1067 * Set the state time...
1068 */
1069
1070 if (value)
1071 p->state_time = atoi(value);
1072 }
1073 else if (!strcasecmp(line, "Accepting"))
1074 {
1075 /*
1076 * Set the initial accepting state...
1077 */
1078
1079 if (value &&
1080 (!strcasecmp(value, "yes") ||
1081 !strcasecmp(value, "on") ||
1082 !strcasecmp(value, "true")))
1083 p->accepting = 1;
1084 else if (value &&
1085 (!strcasecmp(value, "no") ||
1086 !strcasecmp(value, "off") ||
1087 !strcasecmp(value, "false")))
1088 p->accepting = 0;
1089 else
1090 {
1091 cupsdLogMessage(CUPSD_LOG_ERROR,
1092 "Syntax error on line %d of printers.conf.", linenum);
1093 return;
1094 }
1095 }
1096 else if (!strcasecmp(line, "Shared"))
1097 {
1098 /*
1099 * Set the initial shared state...
1100 */
1101
1102 if (value &&
1103 (!strcasecmp(value, "yes") ||
1104 !strcasecmp(value, "on") ||
1105 !strcasecmp(value, "true")))
1106 p->shared = 1;
1107 else if (value &&
1108 (!strcasecmp(value, "no") ||
1109 !strcasecmp(value, "off") ||
1110 !strcasecmp(value, "false")))
1111 p->shared = 0;
1112 else
1113 {
1114 cupsdLogMessage(CUPSD_LOG_ERROR,
1115 "Syntax error on line %d of printers.conf.", linenum);
1116 return;
1117 }
1118 }
1119 else if (!strcasecmp(line, "JobSheets"))
1120 {
1121 /*
1122 * Set the initial job sheets...
1123 */
1124
1125 if (value)
1126 {
1127 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1128
1129 if (*valueptr)
1130 *valueptr++ = '\0';
1131
1132 cupsdSetString(&p->job_sheets[0], value);
1133
1134 while (isspace(*valueptr & 255))
1135 valueptr ++;
1136
1137 if (*valueptr)
1138 {
1139 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1140
1141 if (*valueptr)
1142 *valueptr++ = '\0';
1143
1144 cupsdSetString(&p->job_sheets[1], value);
1145 }
1146 }
1147 else
1148 {
1149 cupsdLogMessage(CUPSD_LOG_ERROR,
1150 "Syntax error on line %d of printers.conf.", linenum);
1151 return;
1152 }
1153 }
1154 else if (!strcasecmp(line, "AllowUser"))
1155 {
1156 if (value)
1157 {
1158 p->deny_users = 0;
1159 cupsdAddPrinterUser(p, value);
1160 }
1161 else
1162 {
1163 cupsdLogMessage(CUPSD_LOG_ERROR,
1164 "Syntax error on line %d of printers.conf.", linenum);
1165 return;
1166 }
1167 }
1168 else if (!strcasecmp(line, "DenyUser"))
1169 {
1170 if (value)
1171 {
1172 p->deny_users = 1;
1173 cupsdAddPrinterUser(p, value);
1174 }
1175 else
1176 {
1177 cupsdLogMessage(CUPSD_LOG_ERROR,
1178 "Syntax error on line %d of printers.conf.", linenum);
1179 return;
1180 }
1181 }
1182 else if (!strcasecmp(line, "QuotaPeriod"))
1183 {
1184 if (value)
1185 p->quota_period = atoi(value);
1186 else
1187 {
1188 cupsdLogMessage(CUPSD_LOG_ERROR,
1189 "Syntax error on line %d of printers.conf.", linenum);
1190 return;
1191 }
1192 }
1193 else if (!strcasecmp(line, "PageLimit"))
1194 {
1195 if (value)
1196 p->page_limit = atoi(value);
1197 else
1198 {
1199 cupsdLogMessage(CUPSD_LOG_ERROR,
1200 "Syntax error on line %d of printers.conf.", linenum);
1201 return;
1202 }
1203 }
1204 else if (!strcasecmp(line, "KLimit"))
1205 {
1206 if (value)
1207 p->k_limit = atoi(value);
1208 else
1209 {
1210 cupsdLogMessage(CUPSD_LOG_ERROR,
1211 "Syntax error on line %d of printers.conf.", linenum);
1212 return;
1213 }
1214 }
1215 else if (!strcasecmp(line, "OpPolicy"))
1216 {
1217 if (value)
c0e1af83 1218 {
1219 cupsd_policy_t *pol; /* Policy */
1220
1221
1222 if ((pol = cupsdFindPolicy(value)) != NULL)
1223 {
1224 cupsdSetString(&p->op_policy, value);
1225 p->op_policy_ptr = pol;
1226 }
1227 else
1228 cupsdLogMessage(CUPSD_LOG_ERROR,
1229 "Bad policy \"%s\" on line %d of printers.conf",
1230 value, linenum);
1231 }
ef416fc2 1232 else
1233 {
1234 cupsdLogMessage(CUPSD_LOG_ERROR,
1235 "Syntax error on line %d of printers.conf.", linenum);
1236 return;
1237 }
1238 }
1239 else if (!strcasecmp(line, "ErrorPolicy"))
1240 {
1241 if (value)
1242 cupsdSetString(&p->error_policy, value);
1243 else
1244 {
1245 cupsdLogMessage(CUPSD_LOG_ERROR,
1246 "Syntax error on line %d of printers.conf.", linenum);
1247 return;
1248 }
1249 }
1250 else
1251 {
1252 /*
1253 * Something else we don't understand...
1254 */
1255
1256 cupsdLogMessage(CUPSD_LOG_ERROR,
1257 "Unknown configuration directive %s on line %d of printers.conf.",
1258 line, linenum);
1259 }
1260 }
1261
1262 cupsFileClose(fp);
1263}
1264
1265
b423cd4c 1266/*
1267 * 'cupsdRenamePrinter()' - Rename a printer.
1268 */
1269
1270void
1271cupsdRenamePrinter(
1272 cupsd_printer_t *p, /* I - Printer */
1273 const char *name) /* I - New name */
1274{
1275 /*
1276 * Remove the printer from the array(s) first...
1277 */
1278
1279 cupsArrayRemove(Printers, p);
1280
1281 if (p->type & CUPS_PRINTER_IMPLICIT)
1282 cupsArrayRemove(ImplicitPrinters, p);
1283
1284 /*
1285 * Rename the printer type...
1286 */
1287
1288 mimeDeleteType(MimeDatabase, p->filetype);
1289 p->filetype = mimeAddType(MimeDatabase, "printer", name);
1290
f7deaa1a 1291 mimeDeleteType(MimeDatabase, p->prefiltertype);
1292 p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
1293
b423cd4c 1294 /*
1295 * Rename the printer...
1296 */
1297
a74454a7 1298 cupsdSetString(&p->name, name);
b423cd4c 1299
1300 /*
1301 * Reset printer attributes...
1302 */
1303
1304 cupsdSetPrinterAttrs(p);
1305
1306 /*
1307 * Add the printer back to the printer array(s)...
1308 */
1309
1310 cupsArrayAdd(Printers, p);
8ca02f3c 1311
b423cd4c 1312 if (p->type & CUPS_PRINTER_IMPLICIT)
1313 cupsArrayAdd(ImplicitPrinters, p);
1314}
1315
1316
ef416fc2 1317/*
1318 * 'cupsdSaveAllPrinters()' - Save all printer definitions to the printers.conf
1319 * file.
1320 */
1321
1322void
1323cupsdSaveAllPrinters(void)
1324{
1325 int i; /* Looping var */
1326 cups_file_t *fp; /* printers.conf file */
1327 char temp[1024]; /* Temporary string */
1328 char backup[1024]; /* printers.conf.O file */
1329 cupsd_printer_t *printer; /* Current printer class */
1330 time_t curtime; /* Current time */
1331 struct tm *curdate; /* Current date */
b423cd4c 1332 cups_option_t *option; /* Current option */
f7deaa1a 1333 const char *ptr; /* Pointer into info/location */
ef416fc2 1334
1335
1336 /*
1337 * Create the printers.conf file...
1338 */
1339
1340 snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
1341 snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
1342
1343 if (rename(temp, backup))
1344 {
1345 if (errno != ENOENT)
1346 cupsdLogMessage(CUPSD_LOG_ERROR,
1347 "Unable to backup printers.conf - %s", strerror(errno));
1348 }
1349
1350 if ((fp = cupsFileOpen(temp, "w")) == NULL)
1351 {
1352 cupsdLogMessage(CUPSD_LOG_ERROR,
1353 "Unable to save printers.conf - %s", strerror(errno));
1354
1355 if (rename(backup, temp))
1356 cupsdLogMessage(CUPSD_LOG_ERROR,
1357 "Unable to restore printers.conf - %s", strerror(errno));
1358 return;
1359 }
1360 else
1361 cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
1362
1363 /*
1364 * Restrict access to the file...
1365 */
1366
1367 fchown(cupsFileNumber(fp), getuid(), Group);
fa73b229 1368 fchmod(cupsFileNumber(fp), 0600);
ef416fc2 1369
1370 /*
1371 * Write a small header to the file...
1372 */
1373
1374 curtime = time(NULL);
1375 curdate = localtime(&curtime);
1376 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
1377
1378 cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
1379 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
1380
1381 /*
1382 * Write each local printer known to the system...
1383 */
1384
1385 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
1386 printer;
1387 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
1388 {
1389 /*
1390 * Skip remote destinations and printer classes...
1391 */
1392
1393 if ((printer->type & CUPS_PRINTER_REMOTE) ||
1394 (printer->type & CUPS_PRINTER_CLASS) ||
1395 (printer->type & CUPS_PRINTER_IMPLICIT))
1396 continue;
1397
1398 /*
1399 * Write printers as needed...
1400 */
1401
1402 if (printer == DefaultPrinter)
1403 cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
1404 else
1405 cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
1406
f7deaa1a 1407 if (printer->num_auth_info_required > 0)
1408 {
1409 cupsFilePrintf(fp, "AuthInfoRequired %s", printer->auth_info_required[0]);
1410 for (i = 1; i < printer->num_auth_info_required; i ++)
1411 cupsFilePrintf(fp, ",%s", printer->auth_info_required[i]);
1412 cupsFilePutChar(fp, '\n');
1413 }
1414
ef416fc2 1415 if (printer->info)
f7deaa1a 1416 {
1417 if ((ptr = strchr(printer->info, '#')) != NULL)
1418 {
1419 /*
1420 * Need to quote the first # in the info string...
1421 */
1422
1423 cupsFilePuts(fp, "Info ");
1424 cupsFileWrite(fp, printer->info, ptr - printer->info);
1425 cupsFilePutChar(fp, '\\');
1426 cupsFilePuts(fp, ptr);
1427 cupsFilePutChar(fp, '\n');
1428 }
1429 else
1430 cupsFilePrintf(fp, "Info %s\n", printer->info);
1431 }
ef416fc2 1432
1433 if (printer->location)
f7deaa1a 1434 {
1435 if ((ptr = strchr(printer->info, '#')) != NULL)
1436 {
1437 /*
1438 * Need to quote the first # in the location string...
1439 */
ef416fc2 1440
f7deaa1a 1441 cupsFilePuts(fp, "Location ");
1442 cupsFileWrite(fp, printer->location, ptr - printer->location);
1443 cupsFilePutChar(fp, '\\');
1444 cupsFilePuts(fp, ptr);
1445 cupsFilePutChar(fp, '\n');
1446 }
1447 else
1448 cupsFilePrintf(fp, "Location %s\n", printer->location);
1449 }
ef416fc2 1450 if (printer->device_uri)
1451 cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
1452
1453 if (printer->port_monitor)
1454 cupsFilePrintf(fp, "PortMonitor %s\n", printer->port_monitor);
1455
1456 if (printer->state == IPP_PRINTER_STOPPED)
1457 {
1458 cupsFilePuts(fp, "State Stopped\n");
1459 cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
1460 }
1461 else
1462 cupsFilePuts(fp, "State Idle\n");
1463
1464 cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
1465
1466 if (printer->accepting)
1467 cupsFilePuts(fp, "Accepting Yes\n");
1468 else
1469 cupsFilePuts(fp, "Accepting No\n");
1470
1471 if (printer->shared)
1472 cupsFilePuts(fp, "Shared Yes\n");
1473 else
1474 cupsFilePuts(fp, "Shared No\n");
1475
1476 cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
1477 printer->job_sheets[1]);
1478
1479 cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
1480 cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
1481 cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
1482
1483 for (i = 0; i < printer->num_users; i ++)
1484 cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
1485 printer->users[i]);
1486
1487 if (printer->op_policy)
1488 cupsFilePrintf(fp, "OpPolicy %s\n", printer->op_policy);
1489 if (printer->error_policy)
1490 cupsFilePrintf(fp, "ErrorPolicy %s\n", printer->error_policy);
1491
b423cd4c 1492 for (i = printer->num_options, option = printer->options;
1493 i > 0;
1494 i --, option ++)
1495 cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
1496
ef416fc2 1497 cupsFilePuts(fp, "</Printer>\n");
1498
1499#ifdef __sgi
1500 /*
1501 * Make IRIX desktop & printer status happy
1502 */
1503
1504 write_irix_state(printer);
1505#endif /* __sgi */
1506 }
1507
1508 cupsFileClose(fp);
1509}
1510
1511
f7deaa1a 1512/*
1513 * 'cupsdSetAuthInfoRequired()' - Set the required authentication info.
1514 */
1515
1516int /* O - 1 if value OK, 0 otherwise */
1517cupsdSetAuthInfoRequired(
1518 cupsd_printer_t *p, /* I - Printer */
1519 const char *values, /* I - Plain text value (or NULL) */
1520 ipp_attribute_t *attr) /* I - IPP attribute value (or NULL) */
1521{
1522 int i; /* Looping var */
1523
1524
1525 p->num_auth_info_required = 0;
1526
1527 /*
1528 * Do we have a plain text value?
1529 */
1530
1531 if (values)
1532 {
1533 /*
1534 * Yes, grab the keywords...
1535 */
1536
1537 const char *end; /* End of current value */
1538
1539
1540 while (*values && p->num_auth_info_required < 4)
1541 {
1542 if ((end = strchr(values, ',')) == NULL)
1543 end = values + strlen(values);
1544
f899b121 1545 if ((end - values) == 4 && !strncmp(values, "none", 4))
f7deaa1a 1546 {
1547 if (p->num_auth_info_required != 0 || *end)
1548 return (0);
1549
1550 p->auth_info_required[p->num_auth_info_required] = "none";
1551 p->num_auth_info_required ++;
1552
1553 return (1);
1554 }
f899b121 1555 else if ((end - values) == 9 && !strncmp(values, "negotiate", 9))
1556 {
1557 if (p->num_auth_info_required != 0 || *end)
1558 return (0);
1559
1560 p->auth_info_required[p->num_auth_info_required] = "negotiate";
1561 p->num_auth_info_required ++;
1562
1563 return (1);
1564 }
1565 else if ((end - values) == 6 && !strncmp(values, "domain", 6))
f7deaa1a 1566 {
1567 p->auth_info_required[p->num_auth_info_required] = "domain";
1568 p->num_auth_info_required ++;
1569 }
f899b121 1570 else if ((end - values) == 8 && !strncmp(values, "password", 8))
f7deaa1a 1571 {
1572 p->auth_info_required[p->num_auth_info_required] = "password";
1573 p->num_auth_info_required ++;
1574 }
f899b121 1575 else if ((end - values) == 8 && !strncmp(values, "username", 8))
f7deaa1a 1576 {
1577 p->auth_info_required[p->num_auth_info_required] = "username";
1578 p->num_auth_info_required ++;
1579 }
1580 else
1581 return (0);
1582 }
1583
1584 if (p->num_auth_info_required == 0)
1585 {
1586 p->auth_info_required[0] = "none";
1587 p->num_auth_info_required = 1;
1588 }
1589
1590 return (1);
1591 }
1592
1593 /*
1594 * Grab values from an attribute instead...
1595 */
1596
1597 if (!attr || attr->num_values > 4)
1598 return (0);
1599
1600 for (i = 0; i < attr->num_values; i ++)
1601 {
1602 if (!strcmp(attr->values[i].string.text, "none"))
1603 {
1604 if (p->num_auth_info_required != 0 || attr->num_values != 1)
1605 return (0);
1606
1607 p->auth_info_required[p->num_auth_info_required] = "none";
1608 p->num_auth_info_required ++;
1609
1610 return (1);
1611 }
f899b121 1612 else if (!strcmp(attr->values[i].string.text, "negotiate"))
1613 {
1614 if (p->num_auth_info_required != 0 || attr->num_values != 1)
1615 return (0);
1616
1617 p->auth_info_required[p->num_auth_info_required] = "negotiate";
1618 p->num_auth_info_required ++;
1619
1620 return (1);
1621 }
f7deaa1a 1622 else if (!strcmp(attr->values[i].string.text, "domain"))
1623 {
1624 p->auth_info_required[p->num_auth_info_required] = "domain";
1625 p->num_auth_info_required ++;
1626 }
1627 else if (!strcmp(attr->values[i].string.text, "password"))
1628 {
1629 p->auth_info_required[p->num_auth_info_required] = "password";
1630 p->num_auth_info_required ++;
1631 }
1632 else if (!strcmp(attr->values[i].string.text, "username"))
1633 {
1634 p->auth_info_required[p->num_auth_info_required] = "username";
1635 p->num_auth_info_required ++;
1636 }
1637 else
1638 return (0);
1639 }
1640
1641 return (1);
1642}
1643
1644
ef416fc2 1645/*
1646 * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file.
1647 */
1648
1649void
1650cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
1651{
b423cd4c 1652 int i, /* Looping var */
1653 length; /* Length of browse attributes */
1654 char uri[HTTP_MAX_URI]; /* URI for printer */
1655 char resource[HTTP_MAX_URI]; /* Resource portion of URI */
1656 char filename[1024]; /* Name of PPD file */
1657 int num_media; /* Number of media options */
1658 cupsd_location_t *auth; /* Pointer to authentication element */
1659 const char *auth_supported; /* Authentication supported */
1660 cups_ptype_t printer_type; /* Printer type data */
1661 ppd_file_t *ppd; /* PPD file data */
1662 ppd_option_t *input_slot, /* InputSlot options */
1663 *media_type, /* MediaType options */
1664 *page_size, /* PageSize options */
1665 *output_bin, /* OutputBin options */
1666 *media_quality, /* EFMediaQualityMode options */
1667 *duplex; /* Duplex options */
1668 ppd_attr_t *ppdattr; /* PPD attribute */
1669 ipp_attribute_t *attr; /* Attribute data */
1670 ipp_value_t *val; /* Attribute value */
1671 int num_finishings; /* Number of finishings */
b94498cf 1672 int finishings[5]; /* finishings-supported values */
b423cd4c 1673 cups_option_t *option; /* Current printer option */
ef416fc2 1674 static const char * const sides[3] = /* sides-supported values */
1675 {
b423cd4c 1676 "one-sided",
1677 "two-sided-long-edge",
1678 "two-sided-short-edge"
ef416fc2 1679 };
1680
1681
1682 DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
1683 p->type));
1684
1685 /*
1686 * Make sure that we have the common attributes defined...
1687 */
1688
1689 if (!CommonData)
1690 cupsdCreateCommonData();
1691
1692 /*
1693 * Clear out old filters, if any...
1694 */
1695
e1d6a774 1696 delete_printer_filters(p);
ef416fc2 1697
1698 /*
1699 * Figure out the authentication that is required for the printer.
1700 */
1701
1702 auth_supported = "requesting-user-name";
1703 if (!(p->type & CUPS_PRINTER_REMOTE))
1704 {
1705 if (p->type & CUPS_PRINTER_CLASS)
1706 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
1707 else
1708 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
1709
d09495fa 1710 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
1711 auth->type == AUTH_NONE)
ef416fc2 1712 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
1713
1714 if (auth)
1715 {
1716 if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST)
f899b121 1717 {
ef416fc2 1718 auth_supported = "basic";
f899b121 1719 cupsdSetAuthInfoRequired(p, "username,password", NULL);
1720 }
ef416fc2 1721 else if (auth->type == AUTH_DIGEST)
f899b121 1722 {
ef416fc2 1723 auth_supported = "digest";
f899b121 1724 cupsdSetAuthInfoRequired(p, "username,password", NULL);
1725 }
1726#ifdef HAVE_GSSAPI
1727 else if (auth->type == AUTH_NEGOTIATE)
1728 {
1729 auth_supported = "negotiate";
1730 cupsdSetAuthInfoRequired(p, "negotiate", NULL);
1731 }
1732#endif /* HAVE_GSSAPI */
ef416fc2 1733
1734 if (auth->type != AUTH_NONE)
1735 p->type |= CUPS_PRINTER_AUTHENTICATED;
1736 else
1737 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
1738 }
1739 else
1740 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
1741 }
1742
1743 /*
1744 * Create the required IPP attributes for a printer...
1745 */
1746
1747 if (p->attrs)
1748 ippDelete(p->attrs);
1749
1750 p->attrs = ippNew();
1751
1752 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1753 "uri-authentication-supported", NULL, auth_supported);
1754 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1755 "uri-security-supported", NULL, "none");
1756 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
1757 p->name);
1758 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1759 NULL, p->location ? p->location : "");
1760 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1761 NULL, p->info ? p->info : "");
1762 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
1763 NULL, p->uri);
1764
1765 if (p->num_users)
1766 {
1767 if (p->deny_users)
1768 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1769 "requesting-user-name-denied", p->num_users, NULL,
1770 p->users);
1771 else
1772 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1773 "requesting-user-name-allowed", p->num_users, NULL,
1774 p->users);
1775 }
1776
1777 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1778 "job-quota-period", p->quota_period);
1779 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1780 "job-k-limit", p->k_limit);
1781 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1782 "job-page-limit", p->page_limit);
f7deaa1a 1783 if (p->num_auth_info_required)
1784 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1785 "auth-info-required", p->num_auth_info_required,
1786 NULL, p->auth_info_required);
1787 else
1788 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1789 "auth-info-required", NULL, "none");
ef416fc2 1790
fa73b229 1791 if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_REMOTE))
ef416fc2 1792 {
1793 /*
1794 * Setup the job-sheets-default attribute...
1795 */
1796
1797 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1798 "job-sheets-default", 2, NULL, NULL);
1799
1800 if (attr != NULL)
1801 {
757d2cad 1802 attr->values[0].string.text = _cupsStrAlloc(Classification ?
ef416fc2 1803 Classification : p->job_sheets[0]);
757d2cad 1804 attr->values[1].string.text = _cupsStrAlloc(Classification ?
ef416fc2 1805 Classification : p->job_sheets[1]);
1806 }
1807 }
1808
e00b005a 1809 printer_type = p->type;
ef416fc2 1810
d09495fa 1811 p->raw = 0;
1812 p->remote = 0;
ef416fc2 1813
1814 if (p->type & CUPS_PRINTER_REMOTE)
1815 {
1816 /*
1817 * Tell the client this is a remote printer of some type...
1818 */
1819
1820 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1821 "printer-uri-supported", NULL, p->uri);
1822
1823 if (p->make_model)
1824 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1825 "printer-make-and-model", NULL, p->make_model);
1826
fa73b229 1827 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1828 p->uri);
1829
d09495fa 1830 p->raw = 1;
1831 p->remote = 1;
ef416fc2 1832 }
1833 else
1834 {
1835 /*
1836 * Assign additional attributes depending on whether this is a printer
1837 * or class...
1838 */
1839
1840 p->type &= ~CUPS_PRINTER_OPTIONS;
1841
1842 if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
1843 {
1844 p->raw = 1;
1845
1846 /*
1847 * Add class-specific attributes...
1848 */
1849
1850 if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 &&
1851 p->printers[0]->make_model)
1852 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1853 "printer-make-and-model", NULL, p->printers[0]->make_model);
1854 else
1855 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1856 "printer-make-and-model", NULL, "Local Printer Class");
1857
fa73b229 1858 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1859 "file:///dev/null");
1860
ef416fc2 1861 if (p->num_printers > 0)
1862 {
1863 /*
1864 * Add a list of member URIs and names...
1865 */
1866
1867 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1868 "member-uris", p->num_printers, NULL, NULL);
1869 p->type |= CUPS_PRINTER_OPTIONS;
1870
1871 for (i = 0; i < p->num_printers; i ++)
1872 {
1873 if (attr != NULL)
757d2cad 1874 attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->uri);
ef416fc2 1875
1876 p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
1877 }
1878
1879 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1880 "member-names", p->num_printers, NULL, NULL);
1881
1882 if (attr != NULL)
1883 {
1884 for (i = 0; i < p->num_printers; i ++)
757d2cad 1885 attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name);
ef416fc2 1886 }
1887 }
1888 }
1889 else
1890 {
1891 /*
1892 * Add printer-specific attributes... Start by sanitizing the device
1893 * URI so it doesn't have a username or password in it...
1894 */
1895
1896 if (!p->device_uri)
1897 strcpy(uri, "file:/dev/null");
1898 else if (strstr(p->device_uri, "://") != NULL)
1899 {
1900 /*
1901 * http://..., ipp://..., etc.
1902 */
1903
1904 cupsdSanitizeURI(p->device_uri, uri, sizeof(uri));
1905 }
1906 else
1907 {
1908 /*
1909 * file:..., serial:..., etc.
1910 */
1911
1912 strlcpy(uri, p->device_uri, sizeof(uri));
1913 }
1914
1915 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1916 uri);
1917
1918 /*
1919 * Assign additional attributes from the PPD file (if any)...
1920 */
1921
1922 p->type |= CUPS_PRINTER_BW;
1923 finishings[0] = IPP_FINISHINGS_NONE;
1924 num_finishings = 1;
1925
1926 snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
1927 p->name);
1928
1929 if ((ppd = ppdOpenFile(filename)) != NULL)
1930 {
1931 /*
1932 * Add make/model and other various attributes...
1933 */
1934
1935 if (ppd->color_device)
1936 p->type |= CUPS_PRINTER_COLOR;
1937 if (ppd->variable_sizes)
1938 p->type |= CUPS_PRINTER_VARIABLE;
1939 if (!ppd->manual_copies)
1940 p->type |= CUPS_PRINTER_COPIES;
1941 if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
1942 if (ppdattr->value && !strcasecmp(ppdattr->value, "true"))
1943 p->type |= CUPS_PRINTER_FAX;
1944
1945 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
1946 ppd->color_device);
1947 if (ppd->throughput)
1948 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1949 "pages-per-minute", ppd->throughput);
1950
1951 if (ppd->nickname)
bd7854cb 1952 {
1953 /*
1954 * The NickName can be localized in the character set specified
e1d6a774 1955 * by the LanugageEncoding attribute. However, ppdOpen2() has
1956 * already converted the ppd->nickname member to UTF-8 for us
1957 * (the original attribute value is available separately)
bd7854cb 1958 */
1959
e1d6a774 1960 cupsdSetString(&p->make_model, ppd->nickname);
bd7854cb 1961 }
ef416fc2 1962 else if (ppd->modelname)
e1d6a774 1963 {
1964 /*
1965 * Model name can only contain specific characters...
1966 */
1967
ef416fc2 1968 cupsdSetString(&p->make_model, ppd->modelname);
e1d6a774 1969 }
ef416fc2 1970 else
1971 cupsdSetString(&p->make_model, "Bad PPD File");
1972
bd7854cb 1973 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1974 "printer-make-and-model", NULL, p->make_model);
ef416fc2 1975
1976 /*
1977 * Add media options from the PPD file...
1978 */
1979
1980 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
1981 num_media = input_slot->num_choices;
1982 else
1983 num_media = 0;
1984
1985 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
1986 num_media += media_type->num_choices;
1987
1988 if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
1989 num_media += page_size->num_choices;
1990
1991 if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL)
1992 num_media += media_quality->num_choices;
1993
1994 if (num_media == 0)
1995 {
bd7854cb 1996 cupsdLogMessage(CUPSD_LOG_CRIT,
b423cd4c 1997 "The PPD file for printer %s contains no media "
1998 "options and is therefore invalid!", p->name);
ef416fc2 1999 }
2000 else
2001 {
2002 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2003 "media-supported", num_media, NULL, NULL);
2004 if (attr != NULL)
2005 {
2006 val = attr->values;
2007
2008 if (input_slot != NULL)
2009 for (i = 0; i < input_slot->num_choices; i ++, val ++)
757d2cad 2010 val->string.text = _cupsStrAlloc(input_slot->choices[i].choice);
ef416fc2 2011
2012 if (media_type != NULL)
2013 for (i = 0; i < media_type->num_choices; i ++, val ++)
757d2cad 2014 val->string.text = _cupsStrAlloc(media_type->choices[i].choice);
ef416fc2 2015
2016 if (media_quality != NULL)
2017 for (i = 0; i < media_quality->num_choices; i ++, val ++)
757d2cad 2018 val->string.text = _cupsStrAlloc(media_quality->choices[i].choice);
ef416fc2 2019
2020 if (page_size != NULL)
2021 {
2022 for (i = 0; i < page_size->num_choices; i ++, val ++)
757d2cad 2023 val->string.text = _cupsStrAlloc(page_size->choices[i].choice);
ef416fc2 2024
b423cd4c 2025 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2026 "media-default", NULL, page_size->defchoice);
ef416fc2 2027 }
2028 else if (input_slot != NULL)
b423cd4c 2029 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2030 "media-default", NULL, input_slot->defchoice);
ef416fc2 2031 else if (media_type != NULL)
b423cd4c 2032 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2033 "media-default", NULL, media_type->defchoice);
ef416fc2 2034 else if (media_quality != NULL)
b423cd4c 2035 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2036 "media-default", NULL, media_quality->defchoice);
ef416fc2 2037 else
b423cd4c 2038 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2039 "media-default", NULL, "none");
ef416fc2 2040 }
2041 }
2042
2043 /*
2044 * Output bin...
2045 */
2046
2047 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
2048 {
2049 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2050 "output-bin-supported", output_bin->num_choices,
2051 NULL, NULL);
2052
2053 if (attr != NULL)
2054 {
2055 for (i = 0, val = attr->values;
2056 i < output_bin->num_choices;
2057 i ++, val ++)
757d2cad 2058 val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
ef416fc2 2059 }
2060 }
2061
2062 /*
2063 * Duplexing, etc...
2064 */
2065
b423cd4c 2066 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
2067 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
2068 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
2069 if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
2070 duplex = ppdFindOption(ppd, "JCLDuplex");
2071
2072 if (duplex && duplex->num_choices > 1)
ef416fc2 2073 {
2074 p->type |= CUPS_PRINTER_DUPLEX;
2075
b423cd4c 2076 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2077 "sides-supported", 3, NULL, sides);
2078
2079 if (!strcasecmp(duplex->defchoice, "DuplexTumble"))
2080 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2081 "sides-default", NULL, "two-sided-short-edge");
2082 else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble"))
2083 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2084 "sides-default", NULL, "two-sided-long-edge");
2085 else
2086 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2087 "sides-default", NULL, "one-sided");
ef416fc2 2088 }
2089
2090 if (ppdFindOption(ppd, "Collate") != NULL)
2091 p->type |= CUPS_PRINTER_COLLATE;
2092
2093 if (ppdFindOption(ppd, "StapleLocation") != NULL)
2094 {
2095 p->type |= CUPS_PRINTER_STAPLE;
2096 finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
2097 }
2098
2099 if (ppdFindOption(ppd, "BindEdge") != NULL)
2100 {
2101 p->type |= CUPS_PRINTER_BIND;
2102 finishings[num_finishings++] = IPP_FINISHINGS_BIND;
2103 }
2104
2105 for (i = 0; i < ppd->num_sizes; i ++)
2106 if (ppd->sizes[i].length > 1728)
2107 p->type |= CUPS_PRINTER_LARGE;
2108 else if (ppd->sizes[i].length > 1008)
2109 p->type |= CUPS_PRINTER_MEDIUM;
2110 else
2111 p->type |= CUPS_PRINTER_SMALL;
2112
2113 /*
2114 * Add a filter from application/vnd.cups-raw to printer/name to
2115 * handle "raw" printing by users.
2116 */
2117
f7deaa1a 2118 add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
2119
2120 /*
2121 * Add any pre-filters in the PPD file...
2122 */
2123
2124 if ((ppdattr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
2125 {
2126 p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
2127
2128 for (; ppdattr; ppdattr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
2129 if (ppdattr->value)
2130 add_printer_filter(p, p->prefiltertype, ppdattr->value);
2131 }
ef416fc2 2132
2133 /*
2134 * Add any filters in the PPD file...
2135 */
2136
2137 DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
2138 for (i = 0; i < ppd->num_filters; i ++)
2139 {
2140 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
f7deaa1a 2141 add_printer_filter(p, p->filetype, ppd->filters[i]);
ef416fc2 2142 }
2143
2144 if (ppd->num_filters == 0)
2145 {
2146 /*
2147 * If there are no filters, add a PostScript printing filter.
2148 */
2149
f7deaa1a 2150 add_printer_filter(p, p->filetype,
2151 "application/vnd.cups-postscript 0 -");
ef416fc2 2152 }
2153
2154 /*
2155 * Show current and available port monitors for this printer...
2156 */
2157
2158 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "port-monitor",
2159 NULL, p->port_monitor ? p->port_monitor : "none");
2160
2161
2162 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
2163 ppdattr;
2164 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
2165
2166 if (ppd->protocols)
2167 {
2168 if (strstr(ppd->protocols, "TBCP"))
2169 i ++;
2170 else if (strstr(ppd->protocols, "BCP"))
2171 i ++;
2172 }
2173
2174 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2175 "port-monitor-supported", i, NULL, NULL);
2176
757d2cad 2177 attr->values[0].string.text = _cupsStrAlloc("none");
ef416fc2 2178
2179 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
2180 ppdattr;
2181 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
757d2cad 2182 attr->values[i].string.text = _cupsStrAlloc(ppdattr->value);
ef416fc2 2183
2184 if (ppd->protocols)
2185 {
2186 if (strstr(ppd->protocols, "TBCP"))
757d2cad 2187 attr->values[i].string.text = _cupsStrAlloc("tbcp");
ef416fc2 2188 else if (strstr(ppd->protocols, "BCP"))
757d2cad 2189 attr->values[i].string.text = _cupsStrAlloc("bcp");
ef416fc2 2190 }
2191
f7deaa1a 2192#ifdef HAVE_DNSSD
2193 cupsdSetString(&p->product, ppd->product);
2194#endif /* HAVE_DNSSD */
2195
3d8365b8 2196#if BONJOUR_IS_REMOTE
2197 ppdattr = ppdFindAttr(ppd, "APRemoteQueueID", NULL);
2198#endif /* BONJOUR_IS_REMOTE */
2199
ef416fc2 2200 /*
2201 * Close the PPD and set the type...
2202 */
2203
2204 ppdClose(ppd);
2205
e00b005a 2206 printer_type = p->type;
3d8365b8 2207
2208#if BONJOUR_IS_REMOTE
2209 if (ppdattr)
2210 {
2211 /*
2212 * This is a shared Bonjour printer...
2213 */
2214
2215 printer_type |= CUPS_PRINTER_REMOTE;
2216 }
2217#endif /* BONJOUR_IS_REMOTE */
ef416fc2 2218 }
2219 else if (!access(filename, 0))
2220 {
2221 int pline; /* PPD line number */
2222 ppd_status_t pstatus; /* PPD load status */
2223
2224
2225 pstatus = ppdLastError(&pline);
2226
b423cd4c 2227 cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
2228 p->name);
ef416fc2 2229
2230 if (pstatus <= PPD_ALLOC_ERROR)
2231 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
2232 else
b423cd4c 2233 cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
2234 ppdErrorString(pstatus), pline);
ef416fc2 2235
b423cd4c 2236 cupsdLogMessage(CUPSD_LOG_INFO,
2237 "Hint: Run \"cupstestppd %s\" and fix any errors.",
2238 filename);
ef416fc2 2239
2240 /*
2241 * Add a filter from application/vnd.cups-raw to printer/name to
2242 * handle "raw" printing by users.
2243 */
2244
f7deaa1a 2245 add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
ef416fc2 2246
2247 /*
2248 * Add a PostScript filter, since this is still possibly PS printer.
2249 */
2250
f7deaa1a 2251 add_printer_filter(p, p->filetype,
2252 "application/vnd.cups-postscript 0 -");
ef416fc2 2253 }
2254 else
2255 {
2256 /*
2257 * If we have an interface script, add a filter entry for it...
2258 */
2259
2260 snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
2261 p->name);
b423cd4c 2262 if (!access(filename, X_OK))
ef416fc2 2263 {
2264 /*
2265 * Yes, we have a System V style interface script; use it!
2266 */
2267
2268 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
f7deaa1a 2269 "printer-make-and-model", NULL,
2270 "Local System V Printer");
ef416fc2 2271
2272 snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
2273 ServerRoot, p->name);
f7deaa1a 2274 add_printer_filter(p, p->filetype, filename);
ef416fc2 2275 }
2276 else if (p->device_uri &&
2277 !strncmp(p->device_uri, "ipp://", 6) &&
2278 (strstr(p->device_uri, "/printers/") != NULL ||
2279 strstr(p->device_uri, "/classes/") != NULL))
2280 {
2281 /*
2282 * Tell the client this is really a hard-wired remote printer.
2283 */
2284
e00b005a 2285 printer_type |= CUPS_PRINTER_REMOTE;
ef416fc2 2286
2287 /*
2288 * Point the printer-uri-supported attribute to the
2289 * remote printer...
2290 */
2291
2292 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
2293 "printer-uri-supported", NULL, p->device_uri);
2294
2295 /*
2296 * Then set the make-and-model accordingly...
2297 */
2298
2299 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2300 "printer-make-and-model", NULL, "Remote Printer");
2301
2302 /*
2303 * Print all files directly...
2304 */
2305
d09495fa 2306 p->raw = 1;
2307 p->remote = 1;
ef416fc2 2308 }
2309 else
2310 {
2311 /*
2312 * Otherwise we have neither - treat this as a "dumb" printer
2313 * with no PPD file...
2314 */
2315
2316 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2317 "printer-make-and-model", NULL, "Local Raw Printer");
2318
2319 p->raw = 1;
2320 }
2321 }
2322
2323 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
b94498cf 2324 "finishings-supported", num_finishings, finishings);
ef416fc2 2325 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
2326 "finishings-default", IPP_FINISHINGS_NONE);
2327 }
2328 }
2329
3d8365b8 2330 /*
2331 * Save the local printer type value, which may have the CUPS_PRINTER_REMOTE
2332 * bit set. We use this value when sending the printer-type attribute to
2333 * clients so they know whether the printer is really remote. Doing it
2334 * this way prevents the browsing code from timing out hardwired remote
2335 * printers...
2336 */
2337
2338 p->external_type = printer_type;
2339
b423cd4c 2340 /*
2341 * Copy the printer options into a browse attributes string we can re-use.
2342 */
2343
3d8365b8 2344 if (!(printer_type & CUPS_PRINTER_REMOTE))
b423cd4c 2345 {
2346 const char *valptr; /* Pointer into value */
2347 char *attrptr; /* Pointer into attribute string */
2348
2349
2350 /*
2351 * Free the old browse attributes as needed...
2352 */
2353
2354 if (p->browse_attrs)
2355 free(p->browse_attrs);
2356
2357 /*
2358 * Compute the length of all attributes + job-sheets, lease-duration,
2359 * and BrowseLocalOptions.
2360 */
2361
2362 for (length = 1, i = p->num_options, option = p->options;
2363 i > 0;
2364 i --, option ++)
2365 {
2366 length += strlen(option->name) + 2;
2367
2368 if (option->value)
2369 {
2370 for (valptr = option->value; *valptr; valptr ++)
2371 if (strchr(" \"\'\\", *valptr))
2372 length += 2;
2373 else
2374 length ++;
2375 }
2376 }
2377
2378 length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]);
2379 length += 32;
2380 if (BrowseLocalOptions)
f7deaa1a 2381 length += 12 + strlen(BrowseLocalOptions);
b423cd4c 2382
7594b224 2383 if (p->num_auth_info_required > 0)
2384 {
2385 length += 18; /* auth-info-required */
2386
2387 for (i = 0; i < p->num_auth_info_required; i ++)
2388 length += strlen(p->auth_info_required[i]) + 1;
2389 }
2390
b423cd4c 2391 /*
2392 * Allocate the new string...
2393 */
f7deaa1a 2394
b423cd4c 2395 if ((p->browse_attrs = calloc(1, length)) == NULL)
2396 cupsdLogMessage(CUPSD_LOG_ERROR,
2397 "Unable to allocate %d bytes for browse data!",
2398 length);
2399 else
2400 {
2401 /*
2402 * Got the allocated string, now copy the options and attributes over...
2403 */
2404
2405 sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d",
2406 p->job_sheets[0], p->job_sheets[1], BrowseTimeout);
2407 attrptr = p->browse_attrs + strlen(p->browse_attrs);
2408
2409 if (BrowseLocalOptions)
2410 {
2411 sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions);
2412 attrptr += strlen(attrptr);
2413 }
2414
2415 for (i = p->num_options, option = p->options;
2416 i > 0;
2417 i --, option ++)
2418 {
2419 *attrptr++ = ' ';
2420 strcpy(attrptr, option->name);
2421 attrptr += strlen(attrptr);
2422
2423 if (option->value)
2424 {
2425 *attrptr++ = '=';
2426
2427 for (valptr = option->value; *valptr; valptr ++)
2428 {
2429 if (strchr(" \"\'\\", *valptr))
2430 *attrptr++ = '\\';
2431
2432 *attrptr++ = *valptr;
2433 }
2434 }
2435 }
2436
7594b224 2437 if (p->num_auth_info_required > 0)
2438 {
2439 strcpy(attrptr, "auth-info-required");
2440 attrptr += 18;
2441
2442 for (i = 0; i < p->num_auth_info_required; i ++)
2443 {
2444 *attrptr++ = i ? ',' : '=';
2445 strcpy(attrptr, p->auth_info_required[i]);
2446 attrptr += strlen(attrptr);
2447 }
2448 }
2449 else
2450 *attrptr = '\0';
b423cd4c 2451 }
2452 }
2453
bd7854cb 2454 /*
2455 * Populate the document-format-supported attribute...
2456 */
2457
2458 add_printer_formats(p);
2459
ef416fc2 2460 DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
2461 p->type));
2462
b423cd4c 2463 /*
2464 * Add name-default attributes...
2465 */
2466
2467 add_printer_defaults(p);
2468
ef416fc2 2469#ifdef __sgi
2470 /*
2471 * Write the IRIX printer config and status files...
2472 */
2473
2474 write_irix_config(p);
2475 write_irix_state(p);
2476#endif /* __sgi */
f7deaa1a 2477
2478 /*
2479 * Let the browse protocols reflect the change
2480 */
2481
2482 cupsdRegisterPrinter(p);
ef416fc2 2483}
2484
2485
2486/*
2487 * 'cupsdSetPrinterReasons()' - Set/update the reasons strings.
2488 */
2489
2490void
2491cupsdSetPrinterReasons(
2492 cupsd_printer_t *p, /* I - Printer */
2493 const char *s) /* I - Reasons strings */
2494{
2495 int i; /* Looping var */
2496 const char *sptr; /* Pointer into reasons */
2497 char reason[255], /* Reason string */
2498 *rptr; /* Pointer into reason */
2499
2500
2501 if (s[0] == '-' || s[0] == '+')
2502 {
2503 /*
2504 * Add/remove reasons...
2505 */
2506
2507 sptr = s + 1;
2508 }
2509 else
2510 {
2511 /*
2512 * Replace reasons...
2513 */
2514
2515 sptr = s;
2516
2517 for (i = 0; i < p->num_reasons; i ++)
2518 free(p->reasons[i]);
2519
2520 p->num_reasons = 0;
2521 }
2522
2523 /*
2524 * Loop through all of the reasons...
2525 */
2526
2527 while (*sptr)
2528 {
2529 /*
2530 * Skip leading whitespace and commas...
2531 */
2532
2533 while (isspace(*sptr & 255) || *sptr == ',')
2534 sptr ++;
2535
2536 for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
2537 if (rptr < (reason + sizeof(reason) - 1))
2538 *rptr++ = *sptr;
2539
2540 if (rptr == reason)
2541 break;
2542
2543 *rptr = '\0';
2544
2545 if (s[0] == '-')
2546 {
2547 /*
2548 * Remove reason...
2549 */
2550
2551 for (i = 0; i < p->num_reasons; i ++)
2552 if (!strcasecmp(reason, p->reasons[i]))
2553 {
2554 /*
2555 * Found a match, so remove it...
2556 */
2557
2558 p->num_reasons --;
2559 free(p->reasons[i]);
2560
2561 if (i < p->num_reasons)
2562 memmove(p->reasons + i, p->reasons + i + 1,
2563 (p->num_reasons - i) * sizeof(char *));
2564
2565 i --;
c0e1af83 2566
2567 if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED)
2568 cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
ef416fc2 2569 }
2570 }
2571 else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
2572 {
2573 /*
2574 * Add reason...
2575 */
2576
2577 for (i = 0; i < p->num_reasons; i ++)
2578 if (!strcasecmp(reason, p->reasons[i]))
2579 break;
2580
2581 if (i >= p->num_reasons)
2582 {
2583 p->reasons[i] = strdup(reason);
2584 p->num_reasons ++;
c0e1af83 2585
2586 if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
2587 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
ef416fc2 2588 }
2589 }
2590 }
2591}
2592
2593
2594/*
2595 * 'cupsdSetPrinterState()' - Update the current state of a printer.
2596 */
2597
2598void
2599cupsdSetPrinterState(
2600 cupsd_printer_t *p, /* I - Printer to change */
2601 ipp_pstate_t s, /* I - New state */
2602 int update) /* I - Update printers.conf? */
2603{
2604 ipp_pstate_t old_state; /* Old printer state */
2605
2606
2607 /*
2608 * Can't set status of remote printers...
2609 */
2610
2611 if (p->type & CUPS_PRINTER_REMOTE)
2612 return;
2613
2614 /*
2615 * Set the new state...
2616 */
2617
2618 old_state = p->state;
2619 p->state = s;
2620
2621 if (old_state != s)
2622 {
e53920b9 2623 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE_CHANGED, p, NULL,
2624 "%s \"%s\" state changed.",
2625 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
2626 p->name);
2627
ef416fc2 2628 /*
2629 * Let the browse code know this needs to be updated...
2630 */
2631
2632 BrowseNext = p;
2633 p->state_time = time(NULL);
2634 p->browse_time = 0;
2635
2636#ifdef __sgi
2637 write_irix_state(p);
2638#endif /* __sgi */
2639 }
2640
2641 cupsdAddPrinterHistory(p);
2642
f7deaa1a 2643 /*
2644 * Let the browse protocols reflect the change...
2645 */
2646
2647 cupsdRegisterPrinter(p);
2648
ef416fc2 2649 /*
2650 * Save the printer configuration if a printer goes from idle or processing
2651 * to stopped (or visa-versa)...
2652 */
2653
2654 if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED) &&
2655 update)
2656 {
2657 if (p->type & CUPS_PRINTER_CLASS)
2658 cupsdSaveAllClasses();
2659 else
2660 cupsdSaveAllPrinters();
2661 }
2662}
2663
2664
2665/*
2666 * 'cupsdStopPrinter()' - Stop a printer from printing any jobs...
2667 */
2668
2669void
2670cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */
2671 int update)/* I - Update printers.conf? */
2672{
2673 cupsd_job_t *job; /* Active print job */
2674
2675
2676 /*
2677 * Set the printer state...
2678 */
2679
2680 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
2681
2682 /*
2683 * See if we have a job printing on this printer...
2684 */
2685
2686 if (p->job)
2687 {
2688 /*
2689 * Get pointer to job...
2690 */
2691
2692 job = (cupsd_job_t *)p->job;
2693
2694 /*
2695 * Stop it...
2696 */
2697
2698 cupsdStopJob(job, 0);
2699
2700 /*
2701 * Reset the state to pending...
2702 */
2703
2704 job->state->values[0].integer = IPP_JOB_PENDING;
bd7854cb 2705 job->state_value = IPP_JOB_PENDING;
ef416fc2 2706
2707 cupsdSaveJob(job);
07725fee 2708
2709 cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
2710 "Job stopped due to printer being paused");
ef416fc2 2711 }
2712}
2713
2714
2715/*
2716 * 'cupsdUpdatePrinters()' - Update printers after a partial reload.
2717 */
2718
2719void
2720cupsdUpdatePrinters(void)
2721{
2722 cupsd_printer_t *p; /* Current printer */
2723
2724
2725 /*
2726 * Loop through the printers and recreate the printer attributes
2727 * for any local printers since the policy and/or access control
2728 * stuff may have changed. Also, if browsing is disabled, remove
2729 * any remote printers...
2730 */
2731
2732 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2733 p;
2734 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2735 {
07725fee 2736 /*
2737 * Remove remote printers if we are no longer browsing...
2738 */
2739
ef416fc2 2740 if (!Browsing && (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_REMOTE)))
2741 {
2742 if (p->type & CUPS_PRINTER_IMPLICIT)
2743 cupsArrayRemove(ImplicitPrinters, p);
2744
2745 cupsArraySave(Printers);
2746 cupsdDeletePrinter(p, 0);
2747 cupsArrayRestore(Printers);
2748 continue;
2749 }
ef416fc2 2750
2751 /*
2752 * Update the operation policy pointer...
2753 */
2754
2755 if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
2756 p->op_policy_ptr = DefaultPolicyPtr;
07725fee 2757
2758 /*
2759 * Update printer attributes as needed...
2760 */
2761
2762 if (!(p->type & CUPS_PRINTER_REMOTE))
2763 cupsdSetPrinterAttrs(p);
ef416fc2 2764 }
2765}
2766
2767
2768/*
2769 * 'cupsdValidateDest()' - Validate a printer/class destination.
2770 */
2771
2772const char * /* O - Printer or class name */
2773cupsdValidateDest(
f7deaa1a 2774 const char *uri, /* I - Printer URI */
ef416fc2 2775 cups_ptype_t *dtype, /* O - Type (printer or class) */
2776 cupsd_printer_t **printer) /* O - Printer pointer */
2777{
2778 cupsd_printer_t *p; /* Current printer */
2779 char localname[1024],/* Localized hostname */
2780 *lptr, /* Pointer into localized hostname */
f7deaa1a 2781 *sptr, /* Pointer into server name */
2782 *rptr, /* Pointer into resource */
2783 scheme[32], /* Scheme portion of URI */
2784 username[64], /* Username portion of URI */
2785 hostname[HTTP_MAX_HOST],
2786 /* Host portion of URI */
2787 resource[HTTP_MAX_URI];
2788 /* Resource portion of URI */
2789 int port; /* Port portion of URI */
2790
2791
2792 DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
ef416fc2 2793 dtype, printer));
2794
2795 /*
2796 * Initialize return values...
2797 */
2798
2799 if (printer)
2800 *printer = NULL;
2801
f7deaa1a 2802 if (dtype)
2803 *dtype = (cups_ptype_t)0;
2804
2805 /*
2806 * Pull the hostname and resource from the URI...
2807 */
2808
2809 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
2810 username, sizeof(username), hostname, sizeof(hostname),
2811 &port, resource, sizeof(resource));
ef416fc2 2812
2813 /*
2814 * See if the resource is a class or printer...
2815 */
2816
2817 if (!strncmp(resource, "/classes/", 9))
2818 {
2819 /*
2820 * Class...
2821 */
2822
f7deaa1a 2823 rptr = resource + 9;
ef416fc2 2824 }
2825 else if (!strncmp(resource, "/printers/", 10))
2826 {
2827 /*
2828 * Printer...
2829 */
2830
f7deaa1a 2831 rptr = resource + 10;
ef416fc2 2832 }
2833 else
2834 {
2835 /*
2836 * Bad resource name...
2837 */
2838
2839 return (NULL);
2840 }
2841
2842 /*
2843 * See if the printer or class name exists...
2844 */
2845
f7deaa1a 2846 p = cupsdFindDest(rptr);
ef416fc2 2847
f7deaa1a 2848 if (p == NULL && strchr(rptr, '@') == NULL)
ef416fc2 2849 return (NULL);
2850 else if (p != NULL)
2851 {
2852 if (printer)
2853 *printer = p;
2854
f7deaa1a 2855 if (dtype)
2856 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
2857 CUPS_PRINTER_REMOTE);
2858
ef416fc2 2859 return (p->name);
2860 }
2861
2862 /*
2863 * Change localhost to the server name...
2864 */
2865
2866 if (!strcasecmp(hostname, "localhost"))
f7deaa1a 2867 strlcpy(hostname, ServerName, sizeof(hostname));
ef416fc2 2868
2869 strlcpy(localname, hostname, sizeof(localname));
2870
2871 if (!strcasecmp(hostname, ServerName))
2872 {
2873 /*
2874 * Localize the hostname...
2875 */
2876
2877 lptr = strchr(localname, '.');
2878 sptr = strchr(ServerName, '.');
2879
2880 if (sptr != NULL && lptr != NULL)
2881 {
2882 /*
2883 * Strip the common domain name components...
2884 */
2885
2886 while (lptr != NULL)
2887 {
2888 if (!strcasecmp(lptr, sptr))
2889 {
2890 *lptr = '\0';
2891 break;
2892 }
2893 else
2894 lptr = strchr(lptr + 1, '.');
2895 }
2896 }
2897 }
2898
2899 DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
2900
2901 /*
2902 * Find a matching printer or class...
2903 */
2904
2905 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2906 p;
2907 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2908 if (!strcasecmp(p->hostname, localname) &&
f7deaa1a 2909 !strcasecmp(p->name, rptr))
ef416fc2 2910 {
2911 if (printer)
2912 *printer = p;
2913
f7deaa1a 2914 if (dtype)
2915 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
2916 CUPS_PRINTER_REMOTE);
2917
ef416fc2 2918 return (p->name);
2919 }
2920
2921 return (NULL);
2922}
2923
2924
2925/*
2926 * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications
2927 * that need it...
2928 */
2929
2930void
2931cupsdWritePrintcap(void)
2932{
2933 cups_file_t *fp; /* printcap file */
2934 cupsd_printer_t *p; /* Current printer */
2935
2936
2937#ifdef __sgi
2938 /*
2939 * Update the IRIX printer state for the default printer; if
2940 * no printers remain, then the default printer file will be
2941 * removed...
2942 */
2943
2944 write_irix_state(DefaultPrinter);
2945#endif /* __sgi */
2946
2947 /*
2948 * See if we have a printcap file; if not, don't bother writing it.
2949 */
2950
2951 if (!Printcap || !*Printcap)
2952 return;
2953
2954 /*
2955 * Open the printcap file...
2956 */
2957
2958 if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
2959 return;
2960
2961 /*
2962 * Put a comment header at the top so that users will know where the
2963 * data has come from...
2964 */
2965
2966 cupsFilePuts(fp, "# This file was automatically generated by cupsd(8) from the\n");
2967 cupsFilePrintf(fp, "# %s/printers.conf file. All changes to this file\n",
2968 ServerRoot);
2969 cupsFilePuts(fp, "# will be lost.\n");
2970
2971 if (Printers)
2972 {
2973 /*
2974 * Write a new printcap with the current list of printers.
2975 */
2976
2977 switch (PrintcapFormat)
2978 {
2979 case PRINTCAP_BSD:
2980 /*
2981 * Each printer is put in the file as:
2982 *
2983 * Printer1:
2984 * Printer2:
2985 * Printer3:
2986 * ...
2987 * PrinterN:
2988 */
2989
2990 if (DefaultPrinter)
2991 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
2992 DefaultPrinter->info, ServerName, DefaultPrinter->name);
2993
2994 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2995 p;
2996 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2997 if (p != DefaultPrinter)
2998 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
2999 ServerName, p->name);
3000 break;
3001
3002 case PRINTCAP_SOLARIS:
3003 /*
3004 * Each printer is put in the file as:
3005 *
3006 * _all:all=Printer1,Printer2,Printer3,...,PrinterN
3007 * _default:use=DefaultPrinter
3008 * Printer1:\
3009 * :bsdaddr=ServerName,Printer1:\
3010 * :description=Description:
3011 * Printer2:
3012 * :bsdaddr=ServerName,Printer2:\
3013 * :description=Description:
3014 * Printer3:
3015 * :bsdaddr=ServerName,Printer3:\
3016 * :description=Description:
3017 * ...
3018 * PrinterN:
3019 * :bsdaddr=ServerName,PrinterN:\
3020 * :description=Description:
3021 */
3022
3023 cupsFilePuts(fp, "_all:all=");
3024 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3025 p;
3026 p = (cupsd_printer_t *)cupsArrayCurrent(Printers))
3027 cupsFilePrintf(fp, "%s%c", p->name,
3028 cupsArrayNext(Printers) ? ',' : '\n');
3029
3030 if (DefaultPrinter)
3031 cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
3032
3033 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3034 p;
3035 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3036 cupsFilePrintf(fp, "%s:\\\n"
3037 "\t:bsdaddr=%s,%s:\\\n"
3038 "\t:description=%s:\n",
3039 p->name, ServerName, p->name, p->info ? p->info : "");
3040 break;
3041 }
3042 }
3043
3044 /*
3045 * Close the file...
3046 */
3047
3048 cupsFileClose(fp);
3049}
3050
3051
3052/*
3053 * 'cupsdSanitizeURI()' - Sanitize a device URI...
3054 */
3055
3056char * /* O - New device URI */
3057cupsdSanitizeURI(const char *uri, /* I - Original device URI */
3058 char *buffer, /* O - New device URI */
3059 int buflen) /* I - Size of new device URI buffer */
3060{
3061 char *start, /* Start of data after scheme */
3062 *slash, /* First slash after scheme:// */
3063 *ptr; /* Pointer into user@host:port part */
3064
3065
3066 /*
3067 * Range check input...
3068 */
3069
3070 if (!uri || !buffer || buflen < 2)
3071 return (NULL);
3072
3073 /*
3074 * Copy the device URI to the new buffer...
3075 */
3076
3077 strlcpy(buffer, uri, buflen);
3078
3079 /*
3080 * Find the end of the scheme:// part...
3081 */
3082
3083 if ((ptr = strchr(buffer, ':')) == NULL)
3084 return (buffer); /* No scheme: part... */
3085
3086 for (start = ptr + 1; *start; start ++)
3087 if (*start != '/')
3088 break;
3089
3090 /*
3091 * Find the next slash (/) in the URI...
3092 */
3093
3094 if ((slash = strchr(start, '/')) == NULL)
3095 slash = start + strlen(start); /* No slash, point to the end */
3096
3097 /*
3098 * Check for an @ sign before the slash...
3099 */
3100
3101 if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
3102 {
3103 /*
3104 * Found an @ sign and it is before the resource part, so we have
3105 * an authentication string. Copy the remaining URI over the
3106 * authentication string...
3107 */
3108
3109 _cups_strcpy(start, ptr + 1);
3110 }
3111
3112 /*
3113 * Return the new device URI...
3114 */
3115
3116 return (buffer);
3117}
3118
3119
b423cd4c 3120/*
3121 * 'add_printer_defaults()' - Add name-default attributes to the printer attributes.
3122 */
3123
3124static void
3125add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
3126{
3127 int i; /* Looping var */
3128 int num_options; /* Number of default options */
3129 cups_option_t *options, /* Default options */
3130 *option; /* Current option */
3131 char name[256]; /* name-default */
3132
3133
f7deaa1a 3134 /*
3135 * Maintain a common array of default attribute names...
3136 */
3137
3138 if (!CommonDefaults)
3139 {
3140 CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL);
3141
3142 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
3143 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
3144 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
3145 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
3146 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
3147 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
3148 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-default"));
3149 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
3150 cupsArrayAdd(CommonDefaults,
3151 _cupsStrAlloc("orientation-requested-default"));
3152 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default"));
3153 }
3154
b423cd4c 3155 /*
3156 * Add all of the default options from the .conf files...
3157 */
3158
3159 for (num_options = 0, i = p->num_options, option = p->options;
3160 i > 0;
3161 i --, option ++)
3162 {
3163 if (strcmp(option->name, "ipp-options") &&
3164 strcmp(option->name, "job-sheets") &&
3165 strcmp(option->name, "lease-duration"))
3166 {
3167 snprintf(name, sizeof(name), "%s-default", option->name);
3168 num_options = cupsAddOption(name, option->value, num_options, &options);
f7deaa1a 3169
3170 if (!cupsArrayFind(CommonDefaults, name))
3171 cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name));
b423cd4c 3172 }
3173 }
3174
3175 /*
3176 * Convert options to IPP attributes...
3177 */
3178
3179 cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER);
3180 cupsFreeOptions(num_options, options);
3181
3182 /*
3183 * Add standard -default attributes as needed...
3184 */
3185
3186 if (!cupsGetOption("copies", p->num_options, p->options))
3187 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
3188 1);
3189
f7deaa1a 3190 if (!cupsGetOption("document-format", p->num_options, p->options))
3191 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
3192 "document-format-default", NULL, "application/octet-stream");
3193
b423cd4c 3194 if (!cupsGetOption("job-hold-until", p->num_options, p->options))
3195 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3196 "job-hold-until-default", NULL, "no-hold");
3197
3198 if (!cupsGetOption("job-priority", p->num_options, p->options))
3199 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3200 "job-priority-default", 50);
3201
3202 if (!cupsGetOption("number-up", p->num_options, p->options))
3203 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3204 "number-up-default", 1);
3205
3206 if (!cupsGetOption("orientation-requested", p->num_options, p->options))
3207 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
3208 "orientation-requested-default", IPP_PORTRAIT);
f7deaa1a 3209
3210 if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
3211 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3212 "notify-lease-duration-default", DefaultLeaseDuration);
3213
3214 if (!cupsGetOption("notify-events", p->num_options, p->options))
3215 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3216 "notify-events-default", NULL, "job-completed");
b423cd4c 3217}
3218
3219
bd7854cb 3220/*
3221 * 'add_printer_filter()' - Add a MIME filter for a printer.
3222 */
3223
3224static void
3225add_printer_filter(
3226 cupsd_printer_t *p, /* I - Printer to add to */
f7deaa1a 3227 mime_type_t *filtertype, /* I - Filter or prefilter MIME type */
bd7854cb 3228 const char *filter) /* I - Filter to add */
3229{
3230 char super[MIME_MAX_SUPER], /* Super-type for filter */
3231 type[MIME_MAX_TYPE], /* Type for filter */
3232 program[1024]; /* Program/filter name */
3233 int cost; /* Cost of filter */
3234 mime_type_t *temptype; /* MIME type looping var */
3235 char filename[1024]; /* Full filter filename */
3236
3237
3238 /*
3239 * Parse the filter string; it should be in the following format:
3240 *
3241 * super/type cost program
3242 */
3243
3244 if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4)
3245 {
3246 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
3247 p->name, filter);
3248 return;
3249 }
3250
3251 /*
3252 * See if the filter program exists; if not, stop the printer and flag
3253 * the error!
3254 */
3255
ecdc0628 3256 if (strcmp(program, "-"))
bd7854cb 3257 {
ecdc0628 3258 if (program[0] == '/')
3259 strlcpy(filename, program, sizeof(filename));
3260 else
3261 snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
3262
3263 if (access(filename, X_OK))
3264 {
3265 snprintf(p->state_message, sizeof(p->state_message),
3266 "Filter \"%s\" for printer \"%s\" not available: %s",
3267 program, p->name, strerror(errno));
ecdc0628 3268 cupsdSetPrinterReasons(p, "+cups-missing-filter-error");
07725fee 3269 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 0);
ecdc0628 3270
3271 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
3272 }
bd7854cb 3273 }
3274
b423cd4c 3275 /*
3276 * Mark the CUPS_PRINTER_COMMANDS bit if we have a filter for
3277 * application/vnd.cups-command...
3278 */
3279
3280 if (!strcasecmp(super, "application") &&
3281 !strcasecmp(type, "vnd.cups-command"))
3282 p->type |= CUPS_PRINTER_COMMANDS;
3283
bd7854cb 3284 /*
3285 * Add the filter to the MIME database, supporting wildcards as needed...
3286 */
3287
3288 for (temptype = mimeFirstType(MimeDatabase);
3289 temptype;
3290 temptype = mimeNextType(MimeDatabase))
3291 if (((super[0] == '*' && strcasecmp(temptype->super, "printer")) ||
3292 !strcasecmp(temptype->super, super)) &&
3293 (type[0] == '*' || !strcasecmp(temptype->type, type)))
3294 {
3295 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3296 "add_printer_filter: %s: adding filter %s/%s %s/%s %d %s",
3297 p->name, temptype->super, temptype->type,
f7deaa1a 3298 filtertype->super, filtertype->type,
bd7854cb 3299 cost, program);
f7deaa1a 3300 mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program);
bd7854cb 3301 }
3302}
3303
3304
3305/*
3306 * 'add_printer_formats()' - Add document-format-supported values for a printer.
3307 */
3308
3309static void
3310add_printer_formats(cupsd_printer_t *p) /* I - Printer */
3311{
3312 int i; /* Looping var */
3313 mime_type_t *type; /* Current MIME type */
3314 cups_array_t *filters; /* Filters */
80ca4592 3315 ipp_attribute_t *attr; /* document-format-supported attribute */
bd7854cb 3316 char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
3317 /* MIME type name */
3318
3319
3320 /*
3321 * Raw (and remote) queues advertise all of the supported MIME
3322 * types...
3323 */
3324
80ca4592 3325 cupsArrayDelete(p->filetypes);
3326 p->filetypes = NULL;
3327
bd7854cb 3328 if (p->raw)
3329 {
3330 ippAddStrings(p->attrs, IPP_TAG_PRINTER,
3331 (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
3332 "document-format-supported", NumMimeTypes, NULL, MimeTypes);
3333 return;
3334 }
3335
3336 /*
3337 * Otherwise, loop through the supported MIME types and see if there
3338 * are filters for them...
3339 */
3340
bd7854cb 3341 cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
3342 mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
3343
80ca4592 3344 p->filetypes = cupsArrayNew(NULL, NULL);
bd7854cb 3345
80ca4592 3346 for (type = mimeFirstType(MimeDatabase);
bd7854cb 3347 type;
3348 type = mimeNextType(MimeDatabase))
3349 {
bd7854cb 3350 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
3351
3352 if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
3353 {
3354 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3355 "add_printer_formats: %s: %s needs %d filters",
3356 p->name, mimetype, cupsArrayCount(filters));
3357
3358 cupsArrayDelete(filters);
80ca4592 3359 cupsArrayAdd(p->filetypes, type);
bd7854cb 3360 }
3361 else
3362 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3363 "add_printer_formats: %s: %s not supported",
3364 p->name, mimetype);
3365 }
3366
3367 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3368 "add_printer_formats: %s: %d supported types",
80ca4592 3369 p->name, cupsArrayCount(p->filetypes) + 1);
bd7854cb 3370
3371 /*
3372 * Add the file formats that can be filtered...
3373 */
3374
f301802f 3375 if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
3376 !cupsArrayFind(p->filetypes, type))
3377 i = 1;
3378 else
3379 i = 0;
bd7854cb 3380
80ca4592 3381 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
3382 "document-format-supported",
3383 cupsArrayCount(p->filetypes) + 1, NULL, NULL);
3384
f301802f 3385 if (i)
3386 attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
bd7854cb 3387
f301802f 3388 for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
80ca4592 3389 type;
3390 i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
3391 {
3392 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
bd7854cb 3393
80ca4592 3394 attr->values[i].string.text = _cupsStrAlloc(mimetype);
3395 }
f7deaa1a 3396
3397#ifdef HAVE_DNSSD
3398 {
3399 char pdl[1024]; /* Buffer to build pdl list */
3400 mime_filter_t *filter; /* MIME filter looping var */
3401
3402
3403 pdl[0] = '\0';
3404
3405 if (mimeType(MimeDatabase, "application", "pdf"))
3406 strlcat(pdl, "application/pdf,", sizeof(pdl));
3407
3408 if (mimeType(MimeDatabase, "application", "postscript"))
3409 strlcat(pdl, "application/postscript,", sizeof(pdl));
3410
3411 if (mimeType(MimeDatabase, "application", "vnd.cups-raster"))
3412 strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl));
3413
3414 /*
3415 * Determine if this is a Tioga PrintJobMgr based queue...
3416 */
3417
3418 for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
3419 filter;
3420 filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
3421 {
3422 if (filter->dst == p->filetype && filter->filter &&
3423 strstr(filter->filter, "PrintJobMgr"))
3424 break;
3425 }
3426
3427 /*
3428 * We only support raw printing if this is not a Tioga PrintJobMgr based
3429 * queue and if application/octet-stream is a known conversion...
3430 */
3431
3432 if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
3433 strlcat(pdl, "application/octet-stream,", sizeof(pdl));
3434
3435 if (mimeType(MimeDatabase, "image", "png"))
3436 strlcat(pdl, "image/png,", sizeof(pdl));
3437
3438 if (pdl[0])
3439 pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */
3440
3441 cupsdSetString(&p->pdl, pdl);
3442 }
3443#endif /* HAVE_DNSSD */
bd7854cb 3444}
3445
3446
ef416fc2 3447/*
3448 * 'compare_printers()' - Compare two printers.
3449 */
3450
3451static int /* O - Result of comparison */
3452compare_printers(void *first, /* I - First printer */
3453 void *second, /* I - Second printer */
3454 void *data) /* I - App data (not used) */
3455{
3456 return (strcasecmp(((cupsd_printer_t *)first)->name,
3457 ((cupsd_printer_t *)second)->name));
3458}
3459
3460
bd7854cb 3461/*
e1d6a774 3462 * 'delete_printer_filters()' - Delete all MIME filters for a printer.
bd7854cb 3463 */
3464
3465static void
e1d6a774 3466delete_printer_filters(
3467 cupsd_printer_t *p) /* I - Printer to remove from */
bd7854cb 3468{
e1d6a774 3469 mime_filter_t *filter; /* MIME filter looping var */
bd7854cb 3470
bd7854cb 3471
3472 /*
e1d6a774 3473 * Range check input...
bd7854cb 3474 */
3475
e1d6a774 3476 if (p == NULL)
3477 return;
bd7854cb 3478
3479 /*
e1d6a774 3480 * Remove all filters from the MIME database that have a destination
3481 * type == printer...
bd7854cb 3482 */
3483
e1d6a774 3484 for (filter = mimeFirstFilter(MimeDatabase);
3485 filter;
3486 filter = mimeNextFilter(MimeDatabase))
3487 if (filter->dst == p->filetype)
3488 {
3489 /*
3490 * Delete the current filter...
3491 */
bd7854cb 3492
e1d6a774 3493 mimeDeleteFilter(MimeDatabase, filter);
3494 }
bd7854cb 3495}
3496
3497
ef416fc2 3498#ifdef __sgi
3499/*
3500 * 'write_irix_config()' - Update the config files used by the IRIX
3501 * desktop tools.
3502 */
3503
3504static void
3505write_irix_config(cupsd_printer_t *p) /* I - Printer to update */
3506{
3507 char filename[1024]; /* Interface script filename */
3508 cups_file_t *fp; /* Interface script file */
f301802f 3509 ipp_attribute_t *attr; /* Attribute data */
ef416fc2 3510
3511
3512 /*
3513 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
3514 * tools. First the interface script that tells the tools what kind of
3515 * printer we have...
3516 */
3517
3518 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
3519
3520 if (p->type & CUPS_PRINTER_CLASS)
3521 unlink(filename);
3522 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3523 {
3524 cupsFilePuts(fp, "#!/bin/sh\n");
3525
3526 if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
3527 IPP_TAG_TEXT)) != NULL)
3528 cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
3529 else if (p->type & CUPS_PRINTER_CLASS)
3530 cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
3531 else
3532 cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
3533
3534 if (p->type & CUPS_PRINTER_COLOR)
3535 cupsFilePuts(fp, "TYPE=ColorPostScript\n");
3536 else
3537 cupsFilePuts(fp, "TYPE=MonoPostScript\n");
3538
3539 cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
3540 cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
3541
3542 cupsFileClose(fp);
3543
3544 chmod(filename, 0755);
3545 chown(filename, User, Group);
3546 }
3547
3548 /*
3549 * Then the member file that tells which device file the queue is connected
3550 * to... Networked printers use "/dev/null" in this file, so that's what
3551 * we use (the actual device URI can confuse some apps...)
3552 */
3553
3554 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
3555
3556 if (p->type & CUPS_PRINTER_CLASS)
3557 unlink(filename);
3558 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3559 {
3560 cupsFilePuts(fp, "/dev/null\n");
3561
3562 cupsFileClose(fp);
3563
3564 chmod(filename, 0644);
3565 chown(filename, User, Group);
3566 }
3567
3568 /*
3569 * The gui_interface file is a script or program that launches a GUI
3570 * option panel for the printer, using options specified on the
3571 * command-line in the third argument. The option panel must send
3572 * any printing options to stdout on a single line when the user
3573 * accepts them, or nothing if the user cancels the dialog.
3574 *
3575 * The default options panel program is /usr/bin/glpoptions, from
3576 * the ESP Print Pro software. You can select another using the
3577 * PrintcapGUI option.
3578 */
3579
3580 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
3581
3582 if (p->type & CUPS_PRINTER_CLASS)
3583 unlink(filename);
3584 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3585 {
3586 cupsFilePuts(fp, "#!/bin/sh\n");
3587 cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
3588
3589 cupsFileClose(fp);
3590
3591 chmod(filename, 0755);
3592 chown(filename, User, Group);
3593 }
3594
3595 /*
3596 * The POD config file is needed by the printstatus command to show
3597 * the printer location and device.
3598 */
3599
3600 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
3601
3602 if (p->type & CUPS_PRINTER_CLASS)
3603 unlink(filename);
3604 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3605 {
3606 cupsFilePrintf(fp, "Printer Class | %s\n",
3607 (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
3608 cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : "");
3609 cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : "");
3610 cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : "");
3611 cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri ? p->device_uri : "");
3612 cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
3613 cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
3614 cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
3615
3616 cupsFileClose(fp);
3617
3618 chmod(filename, 0664);
3619 chown(filename, User, Group);
3620 }
3621}
3622
3623
3624/*
3625 * 'write_irix_state()' - Update the status files used by IRIX printing
3626 * desktop tools.
3627 */
3628
3629static void
3630write_irix_state(cupsd_printer_t *p) /* I - Printer to update */
3631{
3632 char filename[1024]; /* Interface script filename */
3633 cups_file_t *fp; /* Interface script file */
3634 int tag; /* Status tag value */
3635
3636
3637 if (p)
3638 {
3639 /*
3640 * The POD status file is needed for the printstatus window to
3641 * provide the current status of the printer.
3642 */
3643
3644 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
3645
3646 if (p->type & CUPS_PRINTER_CLASS)
3647 unlink(filename);
3648 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3649 {
3650 cupsFilePrintf(fp, "Operational Status | %s\n",
3651 (p->state == IPP_PRINTER_IDLE) ? "Idle" :
3652 (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
3653 "Faulted");
3654 cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
3655 cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n",
3656 p->device_uri ? p->device_uri : "");
3657 cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n",
3658 p->accepting ? "Accepting" : "Not accepting");
3659 cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
3660
3661 cupsFileClose(fp);
3662
3663 chmod(filename, 0664);
3664 chown(filename, User, Group);
3665 }
3666
3667 /*
3668 * The activeicons file is needed to provide desktop icons for printers:
3669 *
3670 * [ quoted from /usr/lib/print/tagit ]
3671 *
3672 * --- Type of printer tags (base values)
3673 *
3674 * Dumb=66048 # 0x10200
3675 * DumbColor=66080 # 0x10220
3676 * Raster=66112 # 0x10240
3677 * ColorRaster=66144 # 0x10260
3678 * Plotter=66176 # 0x10280
3679 * PostScript=66208 # 0x102A0
3680 * ColorPostScript=66240 # 0x102C0
3681 * MonoPostScript=66272 # 0x102E0
3682 *
3683 * --- Printer state modifiers for local printers
3684 *
3685 * Idle=0 # 0x0
3686 * Busy=1 # 0x1
3687 * Faulted=2 # 0x2
3688 * Unknown=3 # 0x3 (Faulted due to unknown reason)
3689 *
3690 * --- Printer state modifiers for network printers
3691 *
3692 * NetIdle=8 # 0x8
3693 * NetBusy=9 # 0x9
3694 * NetFaulted=10 # 0xA
3695 * NetUnknown=11 # 0xB (Faulted due to unknown reason)
3696 */
3697
3698 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
3699
3700 if (p->type & CUPS_PRINTER_CLASS)
3701 unlink(filename);
3702 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3703 {
3704 if (p->type & CUPS_PRINTER_COLOR)
3705 tag = 66240;
3706 else
3707 tag = 66272;
3708
3709 if (p->type & CUPS_PRINTER_REMOTE)
3710 tag |= 8;
3711
3712 if (p->state == IPP_PRINTER_PROCESSING)
3713 tag |= 1;
3714
3715 else if (p->state == IPP_PRINTER_STOPPED)
3716 tag |= 2;
3717
3718 cupsFilePuts(fp, "#!/bin/sh\n");
3719 cupsFilePrintf(fp, "#Tag %d\n", tag);
3720
3721 cupsFileClose(fp);
3722
3723 chmod(filename, 0755);
3724 chown(filename, User, Group);
3725 }
3726 }
3727
3728 /*
3729 * The default file is needed by the printers window to show
3730 * the default printer.
3731 */
3732
3733 snprintf(filename, sizeof(filename), "/var/spool/lp/default");
3734
3735 if (DefaultPrinter != NULL)
3736 {
3737 if ((fp = cupsFileOpen(filename, "w")) != NULL)
3738 {
3739 cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
3740
3741 cupsFileClose(fp);
3742
3743 chmod(filename, 0644);
3744 chown(filename, User, Group);
3745 }
3746 }
3747 else
3748 unlink(filename);
3749}
3750#endif /* __sgi */
3751
3752
3753/*
3d8365b8 3754 * End of "$Id: printers.c 6539 2007-05-23 15:08:29Z mike $".
ef416fc2 3755 */