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