]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/printers.c
printer-more-info attribute is now set to the first printer-uri-supported
[thirdparty/cups.git] / scheduler / printers.c
1 /*
2 * "$Id: printers.c,v 1.61 2000/04/19 15:18:55 mike Exp $"
3 *
4 * Printer routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2000 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-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * AddPrinter() - Add a printer to the system.
27 * DeleteAllPrinters() - Delete all printers from the system.
28 * DeletePrinter() - Delete a printer from the system.
29 * FindPrinter() - Find a printer in the list.
30 * LoadAllPrinters() - Load printers from the printers.conf file.
31 * SaveAllPrinters() - Save all printer definitions to the printers.conf
32 * SetPrinterAttrs() - Set printer attributes based upon the PPD file.
33 * SetPrinterState() - Update the current state of a printer.
34 * SortPrinters() - Sort the printer list when a printer name is
35 * changed.
36 * StopPrinter() - Stop a printer from printing any jobs...
37 * write_printcap() - Write a pseudo-printcap file for older applications
38 * that need it...
39 */
40
41 /*
42 * Include necessary headers...
43 */
44
45 #include "cupsd.h"
46
47
48 /*
49 * Local functions...
50 */
51
52 static void write_printcap(void);
53
54
55 /*
56 * 'AddPrinter()' - Add a printer to the system.
57 */
58
59 printer_t * /* O - New printer */
60 AddPrinter(const char *name) /* I - Name of printer */
61 {
62 printer_t *p, /* New printer */
63 *current, /* Current printer in list */
64 *prev; /* Previous printer in list */
65
66
67 DEBUG_printf(("AddPrinter(\"%s\")\n", name));
68
69 /*
70 * Range check input...
71 */
72
73 if (name == NULL)
74 return (NULL);
75
76 /*
77 * Create a new printer entity...
78 */
79
80 if ((p = calloc(sizeof(printer_t), 1)) == NULL)
81 return (NULL);
82
83 strcpy(p->name, name);
84 strcpy(p->hostname, ServerName);
85 sprintf(p->uri, "ipp://%s:%d/printers/%s", ServerName,
86 ntohs(Listeners[0].address.sin_port), name);
87 strcpy(p->more_info, p->uri);
88
89 p->state = IPP_PRINTER_STOPPED;
90 p->accepting = 0;
91 p->filetype = mimeAddType(MimeDatabase, "printer", name);
92
93 strcpy(p->job_sheets[0], "none");
94 strcpy(p->job_sheets[1], "none");
95
96 /*
97 * Setup required filters and IPP attributes...
98 */
99
100 SetPrinterAttrs(p);
101
102 /*
103 * Insert the printer in the printer list alphabetically...
104 */
105
106 for (prev = NULL, current = Printers;
107 current != NULL;
108 prev = current, current = current->next)
109 if (strcasecmp(p->name, current->name) < 0)
110 break;
111
112 /*
113 * Insert this printer before the current one...
114 */
115
116 if (prev == NULL)
117 Printers = p;
118 else
119 prev->next = p;
120
121 p->next = current;
122
123 /*
124 * Write a new /etc/printcap or /var/spool/lp/pstatus file.
125 */
126
127 write_printcap();
128
129 return (p);
130 }
131
132
133 /*
134 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
135 */
136
137 void
138 AddPrinterFilter(printer_t *p, /* I - Printer to add to */
139 char *filter) /* I - Filter to add */
140 {
141 int i; /* Looping var */
142 char super[MIME_MAX_SUPER], /* Super-type for filter */
143 type[MIME_MAX_TYPE], /* Type for filter */
144 program[1024]; /* Program/filter name */
145 int cost; /* Cost of filter */
146 mime_type_t **temptype; /* MIME type looping var */
147
148
149 /*
150 * Range check input...
151 */
152
153 if (p == NULL || filter == NULL)
154 return;
155
156 /*
157 * Parse the filter string; it should be in the following format:
158 *
159 * super/type cost program
160 */
161
162 if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4)
163 {
164 LogMessage(L_ERROR, "AddPrinterFilter: Invalid filter string \"%s\"!",
165 filter);
166 return;
167 }
168
169 /*
170 * Add the filter to the MIME database, supporting wildcards as needed...
171 */
172
173 for (temptype = MimeDatabase->types, i = MimeDatabase->num_types;
174 i > 0;
175 i --, temptype ++)
176 if (((super[0] == '*' && strcmp((*temptype)->super, "printer") != 0) ||
177 strcmp((*temptype)->super, super) == 0) &&
178 (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
179 {
180 LogMessage(L_DEBUG, "Adding filter %s/%s %s/%s %d %s",
181 (*temptype)->super, (*temptype)->type,
182 p->filetype->super, p->filetype->type,
183 cost, program);
184 mimeAddFilter(MimeDatabase, *temptype, p->filetype, cost, program);
185 }
186 }
187
188
189 /*
190 * 'DeleteAllPrinters()' - Delete all printers from the system.
191 */
192
193 void
194 DeleteAllPrinters(void)
195 {
196 printer_t *p, /* Pointer to current printer/class */
197 *next; /* Pointer to next printer in list */
198
199
200 for (p = Printers; p != NULL; p = next)
201 {
202 next = p->next;
203
204 if (!(p->type & CUPS_PRINTER_CLASS))
205 DeletePrinter(p);
206 }
207 }
208
209
210 /*
211 * 'DeletePrinter()' - Delete a printer from the system.
212 */
213
214 void
215 DeletePrinter(printer_t *p) /* I - Printer to delete */
216 {
217 printer_t *current, /* Current printer in list */
218 *prev; /* Previous printer in list */
219 #ifdef __sgi
220 char filename[1024]; /* Interface script filename */
221 #endif /* __sgi */
222
223
224 DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p, p->name));
225
226 /*
227 * Range check input...
228 */
229
230 if (p == NULL)
231 return;
232
233 /*
234 * Stop printing on this printer...
235 */
236
237 StopPrinter(p);
238
239 /*
240 * Remove the printer from the list...
241 */
242
243 for (prev = NULL, current = Printers;
244 current != NULL;
245 prev = current, current = current->next)
246 if (p == current)
247 break;
248
249 if (current == NULL)
250 {
251 LogMessage(L_ERROR, "Tried to delete a non-existent printer %s!\n",
252 p->name);
253 return;
254 }
255
256 if (prev == NULL)
257 Printers = p->next;
258 else
259 prev->next = p->next;
260
261 if (p->printers != NULL)
262 free(p->printers);
263
264 ippDelete(p->attrs);
265
266 free(p);
267
268 /*
269 * If p is the default printer, assign the next one...
270 */
271
272 if (p == DefaultPrinter)
273 DefaultPrinter = Printers;
274
275 /*
276 * Write a new /etc/printcap file, and delete the dummy interface and GUI
277 * scripts to fool SGI's stupid printing tools.
278 */
279
280 write_printcap();
281
282 #ifdef __sgi
283 sprintf(filename, "/var/spool/lp/interface/%s", p->name);
284 unlink(filename);
285
286 sprintf(filename, "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
287 unlink(filename);
288
289 sprintf(filename, "/var/spool/lp/activeicons/%s", p->name);
290 unlink(filename);
291 #endif /* __sgi */
292 }
293
294
295 /*
296 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
297 */
298
299 void
300 DeletePrinterFilters(printer_t *p) /* I - Printer to remove from */
301 {
302 int i; /* Looping var */
303 mime_filter_t *filter; /* MIME filter looping var */
304
305
306 /*
307 * Range check input...
308 */
309
310 if (p == NULL)
311 return;
312
313 /*
314 * Remove all filters from the MIME database that have a destination
315 * type == printer...
316 */
317
318 for (filter = MimeDatabase->filters, i = MimeDatabase->num_filters;
319 i > 0;
320 i --, filter ++)
321 if (filter->dst == p->filetype)
322 {
323 /*
324 * Delete the current filter...
325 */
326
327 MimeDatabase->num_filters --;
328
329 if (i > 1)
330 memcpy(filter, filter + 1, sizeof(mime_filter_t) * (i - 1));
331
332 filter --;
333 }
334 }
335
336
337 /*
338 * 'FindPrinter()' - Find a printer in the list.
339 */
340
341 printer_t * /* O - Printer in list */
342 FindPrinter(const char *name) /* I - Name of printer to find */
343 {
344 printer_t *p; /* Current printer */
345
346
347 for (p = Printers; p != NULL; p = p->next)
348 switch (strcasecmp(name, p->name))
349 {
350 case 0 : /* name == p->name */
351 if (!(p->type & CUPS_PRINTER_CLASS))
352 return (p);
353 case 1 : /* name > p->name */
354 break;
355 case -1 : /* name < p->name */
356 return (NULL);
357 }
358
359 return (NULL);
360 }
361
362
363 /*
364 * 'LoadAllPrinters()' - Load printers from the printers.conf file.
365 */
366
367 void
368 LoadAllPrinters(void)
369 {
370 FILE *fp; /* printers.conf file */
371 int linenum; /* Current line number */
372 int len; /* Length of line */
373 char line[1024], /* Line from file */
374 name[256], /* Parameter name */
375 *nameptr, /* Pointer into name */
376 *value, /* Pointer to value */
377 *valueptr; /* Pointer into value */
378 printer_t *p; /* Current printer */
379
380
381 /*
382 * Open the printer.conf file...
383 */
384
385 sprintf(line, "%s/printers.conf", ServerRoot);
386 if ((fp = fopen(line, "r")) == NULL)
387 return;
388
389 /*
390 * Read printer configurations until we hit EOF...
391 */
392
393 linenum = 0;
394 p = NULL;
395
396 while (fgets(line, sizeof(line), fp) != NULL)
397 {
398 linenum ++;
399
400 /*
401 * Skip comment lines...
402 */
403
404 if (line[0] == '#')
405 continue;
406
407 /*
408 * Strip trailing newline, if any...
409 */
410
411 len = strlen(line);
412
413 if (line[len - 1] == '\n')
414 {
415 len --;
416 line[len] = '\0';
417 }
418
419 /*
420 * Extract the name from the beginning of the line...
421 */
422
423 for (value = line; isspace(*value); value ++);
424
425 for (nameptr = name; *value != '\0' && !isspace(*value);)
426 *nameptr++ = *value++;
427 *nameptr = '\0';
428
429 while (isspace(*value))
430 value ++;
431
432 if (name[0] == '\0')
433 continue;
434
435 /*
436 * Decode the directive...
437 */
438
439 if (strcmp(name, "<Printer") == 0 ||
440 strcmp(name, "<DefaultPrinter") == 0)
441 {
442 /*
443 * <Printer name> or <DefaultPrinter name>
444 */
445
446 if (line[len - 1] == '>' && p == NULL)
447 {
448 /*
449 * Add the printer and a base file type...
450 */
451
452 line[len - 1] = '\0';
453
454 p = AddPrinter(value);
455 p->accepting = 1;
456 p->state = IPP_PRINTER_IDLE;
457
458 /*
459 * Set the default printer as needed...
460 */
461
462 if (strcmp(name, "<DefaultPrinter") == 0)
463 DefaultPrinter = p;
464 }
465 else
466 {
467 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
468 linenum);
469 return;
470 }
471 }
472 else if (strcmp(name, "</Printer>") == 0)
473 {
474 if (p != NULL)
475 {
476 SetPrinterAttrs(p);
477 p = NULL;
478 }
479 else
480 {
481 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
482 linenum);
483 return;
484 }
485 }
486 else if (p == NULL)
487 {
488 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
489 linenum);
490 return;
491 }
492
493 else if (strcmp(name, "Info") == 0)
494 strncpy(p->info, value, sizeof(p->info) - 1);
495 else if (strcmp(name, "Location") == 0)
496 strncpy(p->location, value, sizeof(p->location) - 1);
497 else if (strcmp(name, "DeviceURI") == 0)
498 strncpy(p->device_uri, value, sizeof(p->device_uri) - 1);
499 else if (strcmp(name, "State") == 0)
500 {
501 /*
502 * Set the initial queue state...
503 */
504
505 if (strcasecmp(value, "idle") == 0)
506 p->state = IPP_PRINTER_IDLE;
507 else if (strcasecmp(value, "stopped") == 0)
508 p->state = IPP_PRINTER_STOPPED;
509 }
510 else if (strcmp(name, "StateMessage") == 0)
511 {
512 /*
513 * Set the initial queue state message...
514 */
515
516 while (isspace(*value))
517 value ++;
518
519 strcpy(p->state_message, value);
520 }
521 else if (strcmp(name, "Accepting") == 0)
522 {
523 /*
524 * Set the initial accepting state...
525 */
526
527 if (strcasecmp(value, "yes") == 0)
528 p->accepting = 1;
529 else
530 p->accepting = 0;
531 }
532 else if (strcmp(name, "JobSheets") == 0)
533 {
534 /*
535 * Set the initial job sheets...
536 */
537
538 for (valueptr = value; *valueptr && !isspace(*valueptr); valueptr ++);
539
540 if (*valueptr)
541 *valueptr++ = '\0';
542
543 strncpy(p->job_sheets[0], value, sizeof(p->job_sheets[0]) - 1);
544
545 while (isspace(*valueptr))
546 valueptr ++;
547
548 if (*valueptr)
549 {
550 for (value = valueptr; *valueptr && !isspace(*valueptr); valueptr ++);
551
552 if (*valueptr)
553 *valueptr++ = '\0';
554
555 strncpy(p->job_sheets[1], value, sizeof(p->job_sheets[1]) - 1);
556 }
557 }
558 else
559 {
560 /*
561 * Something else we don't understand...
562 */
563
564 LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of printers.conf.",
565 name, linenum);
566 }
567 }
568
569 fclose(fp);
570 }
571
572
573 /*
574 * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf
575 * file.
576 */
577
578 void
579 SaveAllPrinters(void)
580 {
581 FILE *fp; /* printers.conf file */
582 char temp[1024]; /* Temporary string */
583 printer_t *printer; /* Current printer class */
584 time_t curtime; /* Current time */
585 struct tm *curdate; /* Current date */
586
587
588 /*
589 * Create the printers.conf file...
590 */
591
592 sprintf(temp, "%s/printers.conf", ServerRoot);
593 if ((fp = fopen(temp, "w")) == NULL)
594 {
595 LogMessage(L_ERROR, "Unable to save printers.conf - %s", strerror(errno));
596 return;
597 }
598 else
599 LogMessage(L_INFO, "Saving printers.conf...");
600
601 /*
602 * Write a small header to the file...
603 */
604
605 curtime = time(NULL);
606 curdate = gmtime(&curtime);
607 strftime(temp, sizeof(temp) - 1, "# Written by cupsd on %c\n", curdate);
608
609 fputs("# Printer configuration file for " CUPS_SVERSION "\n", fp);
610 fputs(temp, fp);
611
612 /*
613 * Write each local printer known to the system...
614 */
615
616 for (printer = Printers; printer != NULL; printer = printer->next)
617 {
618 /*
619 * Skip remote destinations and printer classes...
620 */
621
622 if ((printer->type & CUPS_PRINTER_REMOTE) ||
623 (printer->type & CUPS_PRINTER_CLASS))
624 continue;
625
626 /*
627 * Write printers as needed...
628 */
629
630 if (printer == DefaultPrinter)
631 fprintf(fp, "<DefaultPrinter %s>\n", printer->name);
632 else
633 fprintf(fp, "<Printer %s>\n", printer->name);
634
635 if (printer->info[0])
636 fprintf(fp, "Info %s\n", printer->info);
637 if (printer->more_info[0])
638 fprintf(fp, "Location %s\n", printer->location);
639 if (printer->device_uri[0])
640 fprintf(fp, "DeviceURI %s\n", printer->device_uri);
641 if (printer->state == IPP_PRINTER_STOPPED)
642 {
643 fputs("State Stopped\n", fp);
644 fprintf(fp, "StateMessage %s\n", printer->state_message);
645 }
646 else
647 fputs("State Idle\n", fp);
648 if (printer->accepting)
649 fputs("Accepting Yes\n", fp);
650 else
651 fputs("Accepting No\n", fp);
652 fprintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
653 printer->job_sheets[1]);
654
655 fputs("</Printer>\n", fp);
656 }
657
658 fclose(fp);
659 }
660
661
662 /*
663 * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file.
664 */
665
666 void
667 SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
668 {
669 char uri[HTTP_MAX_URI]; /* URI for printer */
670 char method[HTTP_MAX_URI], /* Method portion of URI */
671 username[HTTP_MAX_URI], /* Username portion of URI */
672 host[HTTP_MAX_URI], /* Host portion of URI */
673 resource[HTTP_MAX_URI]; /* Resource portion of URI */
674 int port; /* Port portion of URI */
675 int i; /* Looping var */
676 char filename[1024]; /* Name of PPD file */
677 int num_media; /* Number of media options */
678 location_t *auth; /* Pointer to authentication element */
679 int auth_len; /* Length of class or printer resource */
680 const char *auth_supported; /* Authentication supported */
681 ppd_file_t *ppd; /* PPD file data */
682 ppd_option_t *input_slot, /* InputSlot options */
683 *media_type, /* MediaType options */
684 *page_size; /* PageSize options */
685 ipp_attribute_t *attr; /* Attribute data */
686 ipp_value_t *val; /* Attribute value */
687 int nups[3] = /* number-up-supported values */
688 { 1, 2, 4 };
689 ipp_orient_t orients[4] = /* orientation-requested-supported values */
690 {
691 IPP_PORTRAIT,
692 IPP_LANDSCAPE,
693 IPP_REVERSE_LANDSCAPE,
694 IPP_REVERSE_PORTRAIT
695 };
696 const char *sides[3] = /* sides-supported values */
697 {
698 "one",
699 "two-long-edge",
700 "two-short-edge"
701 };
702 const char *versions[] = /* ipp-versions-supported values */
703 {
704 "1.0",
705 "1.1"
706 };
707 ipp_op_t ops[] = /* operations-supported values */
708 {
709 IPP_PRINT_JOB,
710 IPP_VALIDATE_JOB,
711 IPP_CREATE_JOB,
712 IPP_SEND_DOCUMENT,
713 IPP_CANCEL_JOB,
714 IPP_GET_JOB_ATTRIBUTES,
715 IPP_GET_JOBS,
716 IPP_GET_PRINTER_ATTRIBUTES,
717 IPP_HOLD_JOB,
718 IPP_RELEASE_JOB,
719 IPP_PAUSE_PRINTER,
720 IPP_RESUME_PRINTER,
721 IPP_PURGE_JOBS,
722 IPP_SET_JOB_ATTRIBUTES,
723 CUPS_GET_DEFAULT,
724 CUPS_GET_PRINTERS,
725 CUPS_ADD_PRINTER,
726 CUPS_DELETE_PRINTER,
727 CUPS_GET_CLASSES,
728 CUPS_ADD_CLASS,
729 CUPS_DELETE_CLASS,
730 CUPS_ACCEPT_JOBS,
731 CUPS_REJECT_JOBS,
732 CUPS_GET_DEVICES,
733 CUPS_GET_PPDS,
734 IPP_RESTART_JOB
735 };
736 const char *charsets[] = /* charset-supported values */
737 {
738 "us-ascii",
739 "iso-8859-1",
740 "iso-8859-2",
741 "iso-8859-3",
742 "iso-8859-4",
743 "iso-8859-5",
744 "iso-8859-6",
745 "iso-8859-7",
746 "iso-8859-8",
747 "iso-8859-9",
748 "iso-8859-10",
749 "utf-8"
750 };
751 int num_finishings;
752 ipp_finish_t finishings[5];
753 const char *multiple_document_handling[] =
754 {
755 "single-document",
756 "separate-documents-uncollated-copies",
757 "separate-documents-collated-copies",
758 "single-document-new-sheet"
759 };
760 #ifdef __sgi
761 FILE *fp; /* Interface script file */
762 #endif /* __sgi */
763
764
765 DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p->name,
766 p->type));
767
768 /*
769 * Clear out old filters and add a filter from application/vnd.cups-raw to
770 * printer/name to handle "raw" printing by users.
771 */
772
773 DeletePrinterFilters(p);
774 AddPrinterFilter(p, "application/vnd.cups-raw 0 -");
775
776 /*
777 * Figure out the authentication that is required for the printer.
778 */
779
780 auth_supported = "requesting-user-name";
781 if (!(p->type & CUPS_PRINTER_REMOTE))
782 {
783 if (p->type & CUPS_PRINTER_CLASS)
784 {
785 auth_len = 8;
786 sprintf(resource, "/classes/%s", p->name);
787 }
788 else
789 {
790 auth_len = 9;
791 sprintf(resource, "/printers/%s", p->name);
792 }
793
794 for (i = NumLocations, auth = Locations; i > 0; i --, auth ++)
795 if (strcmp(auth->location, resource) == 0)
796 {
797 /*
798 * Exact match...
799 */
800
801 if (auth->type == AUTH_BASIC)
802 auth_supported = "basic";
803 else if (auth->type == AUTH_DIGEST)
804 auth_supported = "digest";
805 break;
806 }
807 else if (strcmp(auth->location, "/") == 0 ||
808 (strncmp(auth->location, resource, auth_len) == 0 &&
809 (strlen(auth->location) == auth_len ||
810 strlen(auth->location) == (auth_len + 1))))
811 {
812 /*
813 * Matches base printer or class resources...
814 */
815
816 if (auth->type == AUTH_BASIC)
817 auth_supported = "basic";
818 else if (auth->type == AUTH_DIGEST)
819 auth_supported = "digest";
820 }
821 }
822
823 /*
824 * Create the required IPP attributes for a printer...
825 */
826
827 if (p->attrs)
828 ippDelete(p->attrs);
829
830 p->attrs = ippNew();
831
832 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported",
833 NULL, p->uri);
834 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
835 "uri-authentication-supported", NULL, auth_supported);
836 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
837 "uri-security-supported", NULL, "none");
838 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
839 p->name);
840 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
841 NULL, p->location);
842 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
843 NULL, p->info);
844 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
845 NULL, p->more_info);
846 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
847 "pdl-override-supported", NULL, "not-attempted");
848 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
849 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
850 NULL, versions);
851 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported",
852 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
853 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 1);
854 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
855 "multiple-document-handling-supported",
856 sizeof(multiple_document_handling) /
857 sizeof(multiple_document_handling[0]), NULL,
858 multiple_document_handling);
859 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-configured",
860 NULL, DefaultCharset);
861 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-supported",
862 sizeof(charsets) / sizeof(charsets[0]), NULL, charsets);
863 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
864 "natural-language-configured", NULL, DefaultLanguage);
865 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
866 "generated-natural-language-supported", NULL, DefaultLanguage);
867 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
868 "document-format-default", NULL, "application/octet-stream");
869 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
870 "document-format-supported", NULL, "application/octet-stream");
871 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
872 "compression-supported", NULL, "none");
873 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
874 "job-priority-supported", 100);
875 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
876 "job-priority-default", 50);
877 ippAddRange(p->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 65535);
878 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
879 "copies-default", 1);
880 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1);
881 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
882 "number-up-supported", 3, nups);
883 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
884 "number-up-default", 1);
885 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
886 "orientation-requested-supported", 4, (int *)orients);
887 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
888 "orientation-requested-default", IPP_PORTRAIT);
889
890 if (NumBanners > 0)
891 {
892 /*
893 * Setup the job-sheets-supported and job-sheets-default attributes...
894 */
895
896 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
897 "job-sheets-supported", NumBanners + 1, NULL, NULL);
898 attr->values[0].string.text = strdup("none");
899 for (i = 0; i < NumBanners; i ++)
900 attr->values[i + 1].string.text = strdup(Banners[i].name);
901
902 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
903 "job-sheets-default", 2, NULL, NULL);
904 attr->values[0].string.text = strdup(p->job_sheets[0]);
905 attr->values[1].string.text = strdup(p->job_sheets[1]);
906 }
907
908 if (p->type & CUPS_PRINTER_REMOTE)
909 {
910 /*
911 * Tell the client this is a remote printer of some type...
912 */
913
914 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
915 "printer-make-and-model", NULL, p->make_model);
916 }
917 else
918 {
919 /*
920 * Assign additional attributes depending on whether this is a printer
921 * or class...
922 */
923
924 p->type &= ~CUPS_PRINTER_OPTIONS;
925
926 if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
927 {
928 /*
929 * Add class-specific attributes...
930 */
931
932 if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0)
933 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
934 "printer-make-and-model", NULL, p->printers[0]->make_model);
935 else
936 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
937 "printer-make-and-model", NULL, "Local Printer Class");
938
939 if (p->num_printers > 0)
940 {
941 /*
942 * Add a list of member URIs and names...
943 */
944
945 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
946 "member-uris", p->num_printers, NULL, NULL);
947
948 p->type |= CUPS_PRINTER_OPTIONS;
949
950 for (i = 0; i < p->num_printers; i ++)
951 {
952 attr->values[i].string.text = strdup(p->printers[i]->uri);
953
954 p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
955 }
956
957 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
958 "member-names", p->num_printers, NULL, NULL);
959
960 for (i = 0; i < p->num_printers; i ++)
961 attr->values[i].string.text = strdup(p->printers[i]->name);
962 }
963 }
964 else
965 {
966 /*
967 * Add printer-specific attributes... Start by sanitizing the device
968 * URI so it doesn't have a username or password in it...
969 */
970
971 if (strstr(p->device_uri, "://") != NULL)
972 {
973 /*
974 * http://..., ipp://..., etc.
975 */
976
977 httpSeparate(p->device_uri, method, username, host, &port, resource);
978 if (port)
979 sprintf(uri, "%s://%s:%d%s", method, host, port, resource);
980 else
981 sprintf(uri, "%s://%s%s", method, host, resource);
982 }
983 else
984 {
985 /*
986 * file:..., serial:..., etc.
987 */
988
989 strcpy(uri, p->device_uri);
990 }
991
992 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
993 uri);
994
995 /*
996 * Assign additional attributes from the PPD file (if any)...
997 */
998
999 p->type |= CUPS_PRINTER_BW;
1000 finishings[0] = IPP_FINISH_NONE;
1001 num_finishings = 1;
1002
1003 sprintf(filename, "%s/ppd/%s.ppd", ServerRoot, p->name);
1004 if ((ppd = ppdOpenFile(filename)) != NULL)
1005 {
1006 /*
1007 * Add make/model and other various attributes...
1008 */
1009
1010 if (ppd->color_device)
1011 p->type |= CUPS_PRINTER_COLOR;
1012 if (ppd->variable_sizes)
1013 p->type |= CUPS_PRINTER_VARIABLE;
1014 if (!ppd->manual_copies)
1015 p->type |= CUPS_PRINTER_COPIES;
1016
1017 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
1018 ppd->color_device);
1019 if (ppd->throughput)
1020 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1021 "pages-per-minute", ppd->throughput);
1022 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1023 "printer-make-and-model", NULL, ppd->nickname);
1024
1025 strncpy(p->make_model, ppd->nickname, sizeof(p->make_model) - 1);
1026
1027 /*
1028 * Add media options from the PPD file...
1029 */
1030
1031 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
1032 num_media = input_slot->num_choices;
1033 else
1034 num_media = 0;
1035
1036 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
1037 num_media += media_type->num_choices;
1038
1039 if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
1040 num_media += page_size->num_choices;
1041
1042 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1043 "media-supported", num_media, NULL, NULL);
1044 val = attr->values;
1045
1046 if (input_slot != NULL)
1047 for (i = 0; i < input_slot->num_choices; i ++, val ++)
1048 val->string.text = strdup(input_slot->choices[i].choice);
1049
1050 if (media_type != NULL)
1051 for (i = 0; i < media_type->num_choices; i ++, val ++)
1052 val->string.text = strdup(media_type->choices[i].choice);
1053
1054 if (page_size != NULL)
1055 for (i = 0; i < page_size->num_choices; i ++, val ++)
1056 val->string.text = strdup(page_size->choices[i].choice);
1057
1058 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1059 NULL, page_size->defchoice);
1060
1061 if (ppdFindOption(ppd, "Duplex") != NULL)
1062 {
1063 p->type |= CUPS_PRINTER_DUPLEX;
1064
1065 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported",
1066 3, NULL, sides);
1067 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-default",
1068 NULL, "one");
1069 }
1070
1071 if (ppdFindOption(ppd, "Collate") != NULL)
1072 p->type |= CUPS_PRINTER_COLLATE;
1073
1074 if (ppdFindOption(ppd, "StapleLocation") != NULL)
1075 {
1076 p->type |= CUPS_PRINTER_STAPLE;
1077 finishings[num_finishings++] = IPP_FINISH_STAPLE;
1078 }
1079
1080 if (ppdFindOption(ppd, "BindEdge") != NULL)
1081 {
1082 p->type |= CUPS_PRINTER_BIND;
1083 finishings[num_finishings++] = IPP_FINISH_BIND;
1084 }
1085
1086 for (i = 0; i < ppd->num_sizes; i ++)
1087 if (ppd->sizes[i].length > 1728)
1088 p->type |= CUPS_PRINTER_LARGE;
1089 else if (ppd->sizes[i].length > 1008)
1090 p->type |= CUPS_PRINTER_MEDIUM;
1091 else
1092 p->type |= CUPS_PRINTER_SMALL;
1093
1094 /*
1095 * Add any filters in the PPD file...
1096 */
1097
1098 DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
1099 for (i = 0; i < ppd->num_filters; i ++)
1100 {
1101 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
1102 AddPrinterFilter(p, ppd->filters[i]);
1103 }
1104
1105 if (ppd->num_filters == 0)
1106 AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
1107
1108 ppdClose(ppd);
1109 }
1110 else if (access(filename, 0) == 0)
1111 {
1112 LogMessage(L_ERROR, "PPD file for %s cannot be loaded!", p->name);
1113
1114 AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
1115 }
1116 else
1117 {
1118 /*
1119 * If we have an interface script, add a filter entry for it...
1120 */
1121
1122 sprintf(filename, "%s/interfaces/%s", ServerRoot, p->name);
1123 if (access(filename, X_OK) == 0)
1124 {
1125 /*
1126 * Yes, we have a System V style interface script; use it!
1127 */
1128
1129 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1130 "printer-make-and-model", NULL, "Local System V Printer");
1131
1132 sprintf(filename, "*/* 0 %s/interfaces/%s", ServerRoot, p->name);
1133 AddPrinterFilter(p, filename);
1134 }
1135 else
1136 {
1137 /*
1138 * Otherwise we have neither - treat this as a "dumb" printer
1139 * with no PPD file...
1140 */
1141
1142 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1143 "printer-make-and-model", NULL, "Local Raw Printer");
1144
1145 AddPrinterFilter(p, "*/* 0 -");
1146 }
1147 }
1148
1149 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1150 "finishings-supported", num_finishings, (int *)finishings);
1151 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1152 "finishings-default", IPP_FINISH_NONE);
1153 }
1154 }
1155
1156 /*
1157 * Add the CUPS-specific printer-type attribute...
1158 */
1159
1160 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", p->type);
1161
1162 DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
1163 p->type));
1164
1165 #ifdef __sgi
1166 /*
1167 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
1168 * tools.
1169 */
1170
1171 sprintf(filename, "/var/spool/lp/interface/%s", p->name);
1172 if ((fp = fopen(filename, "w")) != NULL)
1173 {
1174 fputs("#!/bin/sh\n", fp);
1175
1176 if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
1177 IPP_TAG_TEXT)) != NULL)
1178 fprintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
1179 else if (p->type & CUPS_PRINTER_CLASS)
1180 fputs("NAME=\"Printer Class\"\n", fp);
1181 else
1182 fputs("NAME=\"Remote Destination\"\n", fp);
1183
1184 if (p->type & CUPS_PRINTER_COLOR)
1185 fputs("TYPE=ColorPostScript\n", fp);
1186 else
1187 fputs("TYPE=PostScript\n", fp);
1188
1189 fclose(fp);
1190 chmod(filename, 0755);
1191 }
1192
1193 sprintf(filename, "/var/spool/lp/member/%s", p->name);
1194 if ((fp = fopen(filename, "w")) != NULL)
1195 {
1196 fputs("/dev/null\n", fp);
1197 fclose(fp);
1198 chmod(filename, 0644);
1199 }
1200
1201 sprintf(filename, "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
1202 if ((fp = fopen(filename, "w")) != NULL)
1203 {
1204 fputs("#!/bin/sh\n", fp);
1205 fprintf(fp, "/usr/bin/glpoptions -d %s -o \"$3\"\n", p->name);
1206 fclose(fp);
1207 chmod(filename, 0755);
1208 }
1209
1210 sprintf(filename, "/var/spool/lp/activeicons/%s", p->name);
1211 if ((fp = fopen(filename, "w")) != NULL)
1212 {
1213 fputs("#!/bin/sh\n", fp);
1214 if (p->type & CUPS_PRINTER_COLOR)
1215 fputs("#Tag 66240\n", fp);
1216 else
1217 fputs("#Tag 66208\n", fp);
1218 fclose(fp);
1219 chmod(filename, 0755);
1220 }
1221 #endif /* __sgi */
1222 }
1223
1224
1225 /*
1226 * 'SetPrinterState()' - Update the current state of a printer.
1227 */
1228
1229 void
1230 SetPrinterState(printer_t *p, /* I - Printer to change */
1231 ipp_pstate_t s) /* I - New state */
1232 {
1233 ipp_pstate_t old_state; /* Old printer state */
1234
1235
1236 /*
1237 * Can't set status of remote printers...
1238 */
1239
1240 if (p->type & CUPS_PRINTER_REMOTE)
1241 return;
1242
1243 /*
1244 * Set the new state...
1245 */
1246
1247 old_state = p->state;
1248 p->state = s;
1249 p->state_time = time(NULL);
1250
1251 if (old_state != s)
1252 p->browse_time = 0;
1253
1254 /*
1255 * Save the printer configuration if a printer goes from idle or processing
1256 * to stopped (or visa-versa)...
1257 */
1258
1259 if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
1260 SaveAllPrinters();
1261
1262 /*
1263 * Check to see if any pending jobs can now be printed...
1264 */
1265
1266 CheckJobs();
1267 }
1268
1269
1270 /*
1271 * 'SortPrinters()' - Sort the printer list when a printer name is changed.
1272 */
1273
1274 void
1275 SortPrinters(void)
1276 {
1277 printer_t *current, /* Current printer */
1278 *prev, /* Previous printer */
1279 *next; /* Next printer */
1280 int did_swap; /* Non-zero if we did a swap */
1281
1282
1283 do
1284 {
1285 for (did_swap = 0, current = Printers, prev = NULL; current != NULL;)
1286 if (current->next == NULL)
1287 break;
1288 else if (strcasecmp(current->name, current->next->name) > 0)
1289 {
1290 DEBUG_printf(("Swapping %s and %s...\n", current->name,
1291 current->next->name));
1292
1293 /*
1294 * Need to swap these two printers...
1295 */
1296
1297 did_swap = 1;
1298
1299 if (prev == NULL)
1300 Printers = current->next;
1301 else
1302 prev->next = current->next;
1303
1304 /*
1305 * Yes, we can all get a headache from the next bunch of pointer
1306 * swapping...
1307 */
1308
1309 next = current->next;
1310 current->next = next->next;
1311 next->next = current;
1312 }
1313 else
1314 current = current->next;
1315 }
1316 while (did_swap);
1317 }
1318
1319
1320 /*
1321 * 'StopPrinter()' - Stop a printer from printing any jobs...
1322 */
1323
1324 void
1325 StopPrinter(printer_t *p) /* I - Printer to stop */
1326 {
1327 if (p->job)
1328 StopJob(((job_t *)p->job)->id);
1329
1330 p->state = IPP_PRINTER_STOPPED;
1331 }
1332
1333
1334 /*
1335 * 'write_printcap()' - Write a pseudo-printcap file for older applications
1336 * that need it...
1337 */
1338
1339 static void
1340 write_printcap(void)
1341 {
1342 FILE *fp; /* printcap file */
1343 printer_t *p; /* Current printer */
1344
1345
1346 /*
1347 * See if we have a printcap file; if not, don't bother writing it.
1348 */
1349
1350 if (!Printcap[0])
1351 return;
1352
1353 /*
1354 * Write a new printcap with the current list of printers. Each printer
1355 * is put in the file as:
1356 *
1357 * Printer1:
1358 * Printer2:
1359 * Printer3:
1360 * ...
1361 * PrinterN:
1362 */
1363
1364 if ((fp = fopen(Printcap, "w")) == NULL)
1365 return;
1366
1367 for (p = Printers; p != NULL; p = p->next)
1368 fprintf(fp, "%s:\n", p->name);
1369
1370 /*
1371 * Close the file...
1372 */
1373
1374 fclose(fp);
1375 }
1376
1377
1378 /*
1379 * End of "$Id: printers.c,v 1.61 2000/04/19 15:18:55 mike Exp $".
1380 */