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