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