2 * "$Id: printers.c,v 1.50 2000/01/20 13:05:41 mike Exp $"
4 * Printer routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2000 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
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
36 * StopPrinter() - Stop a printer from printing any jobs...
40 * Include necessary headers...
50 static void write_printcap(void);
54 * 'AddPrinter()' - Add a printer to the system.
57 printer_t
* /* O - New printer */
58 AddPrinter(const char *name
) /* I - Name of printer */
60 printer_t
*p
, /* New printer */
61 *current
, /* Current printer in list */
62 *prev
; /* Previous printer in list */
65 DEBUG_printf(("AddPrinter(\"%s\")\n", name
));
68 * Range check input...
75 * Create a new printer entity...
78 if ((p
= calloc(sizeof(printer_t
), 1)) == NULL
)
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
);
86 p
->state
= IPP_PRINTER_STOPPED
;
88 p
->filetype
= mimeAddType(MimeDatabase
, "printer", name
);
91 * Setup required filters and IPP attributes...
97 * Insert the printer in the printer list alphabetically...
100 for (prev
= NULL
, current
= Printers
;
102 prev
= current
, current
= current
->next
)
103 if (strcasecmp(p
->name
, current
->name
) < 0)
107 * Insert this printer before the current one...
118 * Write a new /etc/printcap or /var/spool/lp/pstatus file.
128 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
132 AddPrinterFilter(printer_t
*p
, /* I - Printer to add to */
133 char *filter
) /* I - Filter to add */
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 */
144 * Range check input...
147 if (p
== NULL
|| filter
== NULL
)
151 * Parse the filter string; it should be in the following format:
153 * super/type cost program
156 if (sscanf(filter
, "%15[^/]/%31s%d%1023s", super
, type
, &cost
, program
) != 4)
158 LogMessage(LOG_ERROR
, "AddPrinterFilter: Invalid filter string \"%s\"!",
164 * Add the filter to the MIME database, supporting wildcards as needed...
167 for (temptype
= MimeDatabase
->types
, i
= MimeDatabase
->num_types
;
170 if (((super
[0] == '*' && strcmp((*temptype
)->super
, "printer") != 0) ||
171 strcmp((*temptype
)->super
, super
) == 0) &&
172 (type
[0] == '*' || strcmp((*temptype
)->type
, type
) == 0))
174 LogMessage(LOG_DEBUG
, "Adding filter %s/%s %s/%s %d %s",
175 (*temptype
)->super
, (*temptype
)->type
,
176 p
->filetype
->super
, p
->filetype
->type
,
178 mimeAddFilter(MimeDatabase
, *temptype
, p
->filetype
, cost
, program
);
184 * 'DeleteAllPrinters()' - Delete all printers from the system.
188 DeleteAllPrinters(void)
190 printer_t
*p
, /* Pointer to current printer/class */
191 *next
; /* Pointer to next printer in list */
194 for (p
= Printers
; p
!= NULL
; p
= next
)
198 if (!(p
->type
& CUPS_PRINTER_CLASS
))
205 * 'DeletePrinter()' - Delete a printer from the system.
209 DeletePrinter(printer_t
*p
) /* I - Printer to delete */
211 int i
; /* Looping var */
212 printer_t
*current
, /* Current printer in list */
213 *prev
; /* Previous printer in list */
215 char filename
[1024]; /* Interface script filename */
219 DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p
, p
->name
));
222 * Range check input...
229 * Stop printing on this printer...
235 * Remove the printer from the list...
238 for (prev
= NULL
, current
= Printers
;
240 prev
= current
, current
= current
->next
)
246 LogMessage(LOG_ERROR
, "Tried to delete a non-existent printer %s!\n",
254 prev
->next
= p
->next
;
256 if (p
->printers
!= NULL
)
264 * If p is the default printer, assign the next one...
267 if (p
== DefaultPrinter
)
268 DefaultPrinter
= Printers
;
271 * Write a new /etc/printcap file, and delete the dummy interface and GUI
272 * scripts to fool SGI's stupid printing tools.
278 sprintf(filename
, "/var/spool/lp/interface/%s", p
->name
);
281 sprintf(filename
, "/var/spool/lp/gui_interface/ELF/%s.gui", p
->name
);
284 sprintf(filename
, "/var/spool/lp/activeicons/%s", p
->name
);
291 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
295 DeletePrinterFilters(printer_t
*p
) /* I - Printer to remove from */
297 int i
; /* Looping var */
298 mime_filter_t
*filter
; /* MIME filter looping var */
302 * Range check input...
309 * Remove all filters from the MIME database that have a destination
313 for (filter
= MimeDatabase
->filters
, i
= MimeDatabase
->num_filters
;
316 if (filter
->dst
== p
->filetype
)
319 * Delete the current filter...
322 MimeDatabase
->num_filters
--;
325 memcpy(filter
, filter
+ 1, sizeof(mime_filter_t
) * (i
- 1));
333 * 'FindPrinter()' - Find a printer in the list.
336 printer_t
* /* O - Printer in list */
337 FindPrinter(const char *name
) /* I - Name of printer to find */
339 printer_t
*p
; /* Current printer */
342 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
343 switch (strcasecmp(name
, p
->name
))
345 case 0 : /* name == p->name */
346 if (!(p
->type
& CUPS_PRINTER_CLASS
))
348 case 1 : /* name > p->name */
350 case -1 : /* name < p->name */
359 * 'LoadAllPrinters()' - Load printers from the printers.conf file.
363 LoadAllPrinters(void)
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 */
379 * Open the printer.conf file...
382 sprintf(line
, "%s/printers.conf", ServerRoot
);
383 if ((fp
= fopen(line
, "r")) == NULL
)
387 * Read printer configurations until we hit EOF...
393 while (fgets(line
, sizeof(line
), fp
) != NULL
)
398 * Skip comment lines...
405 * Strip trailing newline, if any...
410 if (line
[len
- 1] == '\n')
417 * Extract the name from the beginning of the line...
420 for (value
= line
; isspace(*value
); value
++);
422 for (nameptr
= name
; *value
!= '\0' && !isspace(*value
);)
423 *nameptr
++ = *value
++;
426 while (isspace(*value
))
433 * Decode the directive...
436 if (strcmp(name
, "<Printer") == 0 ||
437 strcmp(name
, "<DefaultPrinter") == 0)
440 * <Printer name> or <DefaultPrinter name>
443 if (line
[len
- 1] == '>' && p
== NULL
)
446 * Add the printer and a base file type...
449 line
[len
- 1] = '\0';
451 p
= AddPrinter(value
);
453 p
->state
= IPP_PRINTER_IDLE
;
456 * Set the default printer as needed...
459 if (strcmp(name
, "<DefaultPrinter") == 0)
464 LogMessage(LOG_ERROR
, "Syntax error on line %d of printers.conf.",
469 else if (strcmp(name
, "</Printer>") == 0)
478 LogMessage(LOG_ERROR
, "Syntax error on line %d of printers.conf.",
485 LogMessage(LOG_ERROR
, "Syntax error on line %d of printers.conf.",
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)
501 * Set the initial queue state...
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
;
509 else if (strcmp(name
, "Accepting") == 0)
512 * Set the initial accepting state...
515 if (strcasecmp(value
, "yes") == 0)
523 * Something else we don't understand...
526 LogMessage(LOG_ERROR
, "Unknown configuration directive %s on line %d of printers.conf.",
536 * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf
541 SaveAllPrinters(void)
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 */
552 * Create the printers.conf file...
555 sprintf(temp
, "%s/printers.conf", ServerRoot
);
556 if ((fp
= fopen(temp
, "w")) == NULL
)
558 LogMessage(LOG_ERROR
, "Unable to save printers.conf - %s", strerror(errno
));
562 LogMessage(LOG_INFO
, "Saving printers.conf...");
565 * Write a small header to the file...
568 curtime
= time(NULL
);
569 curdate
= gmtime(&curtime
);
570 strftime(temp
, sizeof(temp
) - 1, "# Written by cupsd on %c\n", curdate
);
572 fputs("# Printer configuration file for " CUPS_SVERSION
"\n", fp
);
576 * Write each local printer known to the system...
579 for (printer
= Printers
; printer
!= NULL
; printer
= printer
->next
)
582 * Skip remote destinations and printer classes...
585 if ((printer
->type
& CUPS_PRINTER_REMOTE
) ||
586 (printer
->type
& CUPS_PRINTER_CLASS
))
590 * Write printers as needed...
593 if (printer
== DefaultPrinter
)
594 fprintf(fp
, "<DefaultPrinter %s>\n", printer
->name
);
596 fprintf(fp
, "<Printer %s>\n", printer
->name
);
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
);
609 fputs("State Idle\n", fp
);
610 if (printer
->accepting
)
611 fputs("Accepting Yes\n", fp
);
613 fputs("Accepting No\n", fp
);
615 fputs("</Printer>\n", fp
);
623 * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file.
627 SetPrinterAttrs(printer_t
*p
) /* I - Printer to setup */
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 */
646 ipp_orient_t orients
[4] = /* orientation-requested-supported values */
650 IPP_REVERSE_LANDSCAPE
,
653 const char *sides
[3] = /* sides-supported values */
659 ipp_op_t ops
[] = /* operations-supported values */
666 IPP_GET_JOB_ATTRIBUTES
,
668 IPP_GET_PRINTER_ATTRIBUTES
,
686 const char *charsets
[] = /* charset-supported values */
702 ipp_finish_t finishings
[5];
704 FILE *fp
; /* Interface script file */
708 DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p
->name
,
712 * Clear out old filters and add a filter from application/vnd.cups-raw to
713 * printer/name to handle "raw" printing by users.
716 DeletePrinterFilters(p
);
717 AddPrinterFilter(p
, "application/vnd.cups-raw 0 -");
720 * Create the required IPP attributes for a printer...
728 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "printer-uri-supported",
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
,
734 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
736 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
738 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "printer-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
);
773 if (p
->type
& CUPS_PRINTER_REMOTE
)
776 * Tell the client this is a remote printer of some type...
779 if (p
->type
& CUPS_PRINTER_CLASS
)
780 snprintf(filename
, sizeof(filename
), "Remote Printer Class on %s",
783 snprintf(filename
, sizeof(filename
), "Remote Printer on %s", p
->hostname
);
785 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
786 "printer-make-and-model", NULL
, filename
);
791 * Assign additional attributes depending on whether this is a printer
795 p
->type
&= ~CUPS_PRINTER_OPTIONS
;
797 if (p
->type
& CUPS_PRINTER_CLASS
)
800 * Add class-specific attributes...
803 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
804 "printer-make-and-model", NULL
, "Local Printer Class");
806 if (p
->num_printers
> 0)
809 * Add a list of member URIs and names...
812 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
813 "member-uris", p
->num_printers
, NULL
, NULL
);
815 p
->type
|= CUPS_PRINTER_OPTIONS
;
817 for (i
= 0; i
< p
->num_printers
; i
++)
819 attr
->values
[i
].string
.text
= strdup(p
->printers
[i
]->uri
);
821 p
->type
&= ~CUPS_PRINTER_OPTIONS
| p
->printers
[i
]->type
;
824 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
825 "member-names", p
->num_printers
, NULL
, NULL
);
827 for (i
= 0; i
< p
->num_printers
; i
++)
828 attr
->values
[i
].string
.text
= strdup(p
->printers
[i
]->name
);
834 * Add printer-specific attributes... Start by sanitizing the device
835 * URI so it doesn't have a username or password in it...
838 if (strstr(p
->device_uri
, "://") != NULL
)
841 * http://..., ipp://..., etc.
844 httpSeparate(p
->device_uri
, method
, username
, host
, &port
, resource
);
846 sprintf(uri
, "%s://%s:%d%s", method
, host
, port
, resource
);
848 sprintf(uri
, "%s://%s%s", method
, host
, resource
);
853 * file:..., serial:..., etc.
856 strcpy(uri
, p
->device_uri
);
859 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri", NULL
,
863 * Assign additional attributes from the PPD file (if any)...
866 p
->type
|= CUPS_PRINTER_BW
;
867 finishings
[0] = IPP_FINISH_NONE
;
870 sprintf(filename
, "%s/ppd/%s.ppd", ServerRoot
, p
->name
);
871 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
874 * Add make/model and other various attributes...
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
;
884 ippAddBoolean(p
->attrs
, IPP_TAG_PRINTER
, "color-supported",
886 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
887 "printer-make-and-model", NULL
, ppd
->nickname
);
890 * Add media options from the PPD file...
893 if ((input_slot
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
894 num_media
= input_slot
->num_choices
;
898 if ((media_type
= ppdFindOption(ppd
, "MediaType")) != NULL
)
899 num_media
+= media_type
->num_choices
;
901 if ((page_size
= ppdFindOption(ppd
, "PageSize")) != NULL
)
902 num_media
+= page_size
->num_choices
;
904 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
905 "media-supported", num_media
, NULL
, NULL
);
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
);
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
);
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
);
920 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "media-default",
921 NULL
, page_size
->defchoice
);
923 if (ppdFindOption(ppd
, "Duplex") != NULL
)
925 p
->type
|= CUPS_PRINTER_DUPLEX
;
927 ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "sides-supported",
929 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "sides-default",
933 if (ppdFindOption(ppd
, "Collate") != NULL
)
934 p
->type
|= CUPS_PRINTER_COLLATE
;
936 if (ppdFindOption(ppd
, "StapleLocation") != NULL
)
938 p
->type
|= CUPS_PRINTER_STAPLE
;
939 finishings
[num_finishings
++] = IPP_FINISH_STAPLE
;
942 if (ppdFindOption(ppd
, "BindEdge") != NULL
)
944 p
->type
|= CUPS_PRINTER_BIND
;
945 finishings
[num_finishings
++] = IPP_FINISH_BIND
;
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
;
954 p
->type
|= CUPS_PRINTER_SMALL
;
957 * Add any filters in the PPD file...
960 DEBUG_printf(("ppd->num_filters = %d\n", ppd
->num_filters
));
961 for (i
= 0; i
< ppd
->num_filters
; i
++)
963 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i
, ppd
->filters
[i
]));
964 AddPrinterFilter(p
, ppd
->filters
[i
]);
967 if (ppd
->num_filters
== 0)
968 AddPrinterFilter(p
, "application/vnd.cups-postscript 0 -");
972 else if (access(filename
, 0) == 0)
974 LogMessage(LOG_ERROR
, "PPD file for %s cannot be loaded!", p
->name
);
976 AddPrinterFilter(p
, "application/vnd.cups-postscript 0 -");
981 * If we have an interface script, add a filter entry for it...
984 sprintf(filename
, "%s/interfaces/%s", ServerRoot
, p
->name
);
985 if (access(filename
, X_OK
) == 0)
988 * Yes, we have a System V style interface script; use it!
991 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
992 "printer-make-and-model", NULL
, "Local System V Printer");
994 sprintf(filename
, "*/* 0 %s/interfaces/%s", ServerRoot
, p
->name
);
995 AddPrinterFilter(p
, filename
);
1000 * Otherwise we have neither - treat this as a "dumb" printer
1001 * with no PPD file...
1004 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1005 "printer-make-and-model", NULL
, "Local Raw Printer");
1007 AddPrinterFilter(p
, "*/* 0 -");
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
);
1019 * Add the CUPS-specific printer-type attribute...
1022 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-type", p
->type
);
1024 DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p
->name
,
1029 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
1033 sprintf(filename
, "/var/spool/lp/interface/%s", p
->name
);
1034 if ((fp
= fopen(filename
, "w")) != NULL
)
1036 fputs("#!/bin/sh\n", fp
);
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
);
1044 fputs("NAME=\"Remote Destination\"\n", fp
);
1046 if (p
->type
& CUPS_PRINTER_COLOR
)
1047 fputs("TYPE=ColorPostScript\n", fp
);
1049 fputs("TYPE=PostScript\n", fp
);
1052 chmod(filename
, 0755);
1055 sprintf(filename
, "/var/spool/lp/member/%s", p
->name
);
1056 if ((fp
= fopen(filename
, "w")) != NULL
)
1058 fputs("/dev/null\n", fp
);
1060 chmod(filename
, 0644);
1063 sprintf(filename
, "/var/spool/lp/gui_interface/ELF/%s.gui", p
->name
);
1064 if ((fp
= fopen(filename
, "w")) != NULL
)
1066 fputs("#!/bin/sh\n", fp
);
1067 fprintf(fp
, "/usr/bin/glpoptions -d %s -o \"$3\"\n", p
->name
);
1069 chmod(filename
, 0755);
1072 sprintf(filename
, "/var/spool/lp/activeicons/%s", p
->name
);
1073 if ((fp
= fopen(filename
, "w")) != NULL
)
1075 fputs("#!/bin/sh\n", fp
);
1076 if (p
->type
& CUPS_PRINTER_COLOR
)
1077 fputs("#Tag 66240\n", fp
);
1079 fputs("#Tag 66208\n", fp
);
1081 chmod(filename
, 0755);
1088 * 'SetPrinterState()' - Update the current state of a printer.
1092 SetPrinterState(printer_t
*p
, /* I - Printer to change */
1093 ipp_pstate_t s
) /* I - New state */
1095 ipp_pstate_t old_state
; /* Old printer state */
1099 * Can't set status of remote printers...
1102 if (p
->type
& CUPS_PRINTER_REMOTE
)
1106 * Set the new state...
1109 old_state
= p
->state
;
1111 p
->state_time
= time(NULL
);
1117 * Save the printer configuration if a printer goes from idle or processing
1118 * to stopped (or visa-versa)...
1121 if ((old_state
== IPP_PRINTER_STOPPED
) != (s
== IPP_PRINTER_STOPPED
))
1125 * Check to see if any pending jobs can now be printed...
1133 * 'SortPrinters()' - Sort the printer list when a printer name is changed.
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 */
1148 for (did_swap
= 0, current
= Printers
, prev
= NULL
; current
!= NULL
;)
1149 if (current
->next
== NULL
)
1151 else if (strcasecmp(current
->name
, current
->next
->name
) > 0)
1153 DEBUG_printf(("Swapping %s and %s...\n", current
->name
,
1154 current
->next
->name
));
1157 * Need to swap these two printers...
1163 Printers
= current
->next
;
1165 prev
->next
= current
->next
;
1168 * Yes, we can all get a headache from the next bunch of pointer
1172 next
= current
->next
;
1173 current
->next
= next
->next
;
1174 next
->next
= current
;
1177 current
= current
->next
;
1184 * 'StopPrinter()' - Stop a printer from printing any jobs...
1188 StopPrinter(printer_t
*p
) /* I - Printer to stop */
1191 StopJob(((job_t
*)p
->job
)->id
);
1193 p
->state
= IPP_PRINTER_STOPPED
;
1198 * 'write_printcap()' - Write a pseudo-printcap file to /etc/printcap for
1199 * older applications that need it...
1203 write_printcap(void)
1205 FILE *fp
; /* printcap file */
1206 printer_t
*p
; /* Current printer */
1210 * See if we have a printcap file; if not, don't bother writing it.
1213 if (access("/etc/printcap", 0))
1217 * Write a new /etc/printcap with the current list of printers. Each printer
1218 * is put in the file as:
1227 if ((fp
= fopen("/etc/printcap", "w")) == NULL
)
1230 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
1231 fprintf(fp
, "%s:\n", p
->name
);
1242 * End of "$Id: printers.c,v 1.50 2000/01/20 13:05:41 mike Exp $".