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