2 * "$Id: printers.c,v 1.61 2000/04/19 15:18:55 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...
37 * write_printcap() - Write a pseudo-printcap file for older applications
42 * Include necessary headers...
52 static void write_printcap(void);
56 * 'AddPrinter()' - Add a printer to the system.
59 printer_t
* /* O - New printer */
60 AddPrinter(const char *name
) /* I - Name of printer */
62 printer_t
*p
, /* New printer */
63 *current
, /* Current printer in list */
64 *prev
; /* Previous printer in list */
67 DEBUG_printf(("AddPrinter(\"%s\")\n", name
));
70 * Range check input...
77 * Create a new printer entity...
80 if ((p
= calloc(sizeof(printer_t
), 1)) == NULL
)
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
);
89 p
->state
= IPP_PRINTER_STOPPED
;
91 p
->filetype
= mimeAddType(MimeDatabase
, "printer", name
);
93 strcpy(p
->job_sheets
[0], "none");
94 strcpy(p
->job_sheets
[1], "none");
97 * Setup required filters and IPP attributes...
103 * Insert the printer in the printer list alphabetically...
106 for (prev
= NULL
, current
= Printers
;
108 prev
= current
, current
= current
->next
)
109 if (strcasecmp(p
->name
, current
->name
) < 0)
113 * Insert this printer before the current one...
124 * Write a new /etc/printcap or /var/spool/lp/pstatus file.
134 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
138 AddPrinterFilter(printer_t
*p
, /* I - Printer to add to */
139 char *filter
) /* I - Filter to add */
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 */
150 * Range check input...
153 if (p
== NULL
|| filter
== NULL
)
157 * Parse the filter string; it should be in the following format:
159 * super/type cost program
162 if (sscanf(filter
, "%15[^/]/%31s%d%1023s", super
, type
, &cost
, program
) != 4)
164 LogMessage(L_ERROR
, "AddPrinterFilter: Invalid filter string \"%s\"!",
170 * Add the filter to the MIME database, supporting wildcards as needed...
173 for (temptype
= MimeDatabase
->types
, i
= MimeDatabase
->num_types
;
176 if (((super
[0] == '*' && strcmp((*temptype
)->super
, "printer") != 0) ||
177 strcmp((*temptype
)->super
, super
) == 0) &&
178 (type
[0] == '*' || strcmp((*temptype
)->type
, type
) == 0))
180 LogMessage(L_DEBUG
, "Adding filter %s/%s %s/%s %d %s",
181 (*temptype
)->super
, (*temptype
)->type
,
182 p
->filetype
->super
, p
->filetype
->type
,
184 mimeAddFilter(MimeDatabase
, *temptype
, p
->filetype
, cost
, program
);
190 * 'DeleteAllPrinters()' - Delete all printers from the system.
194 DeleteAllPrinters(void)
196 printer_t
*p
, /* Pointer to current printer/class */
197 *next
; /* Pointer to next printer in list */
200 for (p
= Printers
; p
!= NULL
; p
= next
)
204 if (!(p
->type
& CUPS_PRINTER_CLASS
))
211 * 'DeletePrinter()' - Delete a printer from the system.
215 DeletePrinter(printer_t
*p
) /* I - Printer to delete */
217 printer_t
*current
, /* Current printer in list */
218 *prev
; /* Previous printer in list */
220 char filename
[1024]; /* Interface script filename */
224 DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p
, p
->name
));
227 * Range check input...
234 * Stop printing on this printer...
240 * Remove the printer from the list...
243 for (prev
= NULL
, current
= Printers
;
245 prev
= current
, current
= current
->next
)
251 LogMessage(L_ERROR
, "Tried to delete a non-existent printer %s!\n",
259 prev
->next
= p
->next
;
261 if (p
->printers
!= NULL
)
269 * If p is the default printer, assign the next one...
272 if (p
== DefaultPrinter
)
273 DefaultPrinter
= Printers
;
276 * Write a new /etc/printcap file, and delete the dummy interface and GUI
277 * scripts to fool SGI's stupid printing tools.
283 sprintf(filename
, "/var/spool/lp/interface/%s", p
->name
);
286 sprintf(filename
, "/var/spool/lp/gui_interface/ELF/%s.gui", p
->name
);
289 sprintf(filename
, "/var/spool/lp/activeicons/%s", p
->name
);
296 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
300 DeletePrinterFilters(printer_t
*p
) /* I - Printer to remove from */
302 int i
; /* Looping var */
303 mime_filter_t
*filter
; /* MIME filter looping var */
307 * Range check input...
314 * Remove all filters from the MIME database that have a destination
318 for (filter
= MimeDatabase
->filters
, i
= MimeDatabase
->num_filters
;
321 if (filter
->dst
== p
->filetype
)
324 * Delete the current filter...
327 MimeDatabase
->num_filters
--;
330 memcpy(filter
, filter
+ 1, sizeof(mime_filter_t
) * (i
- 1));
338 * 'FindPrinter()' - Find a printer in the list.
341 printer_t
* /* O - Printer in list */
342 FindPrinter(const char *name
) /* I - Name of printer to find */
344 printer_t
*p
; /* Current printer */
347 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
348 switch (strcasecmp(name
, p
->name
))
350 case 0 : /* name == p->name */
351 if (!(p
->type
& CUPS_PRINTER_CLASS
))
353 case 1 : /* name > p->name */
355 case -1 : /* name < p->name */
364 * 'LoadAllPrinters()' - Load printers from the printers.conf file.
368 LoadAllPrinters(void)
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 */
382 * Open the printer.conf file...
385 sprintf(line
, "%s/printers.conf", ServerRoot
);
386 if ((fp
= fopen(line
, "r")) == NULL
)
390 * Read printer configurations until we hit EOF...
396 while (fgets(line
, sizeof(line
), fp
) != NULL
)
401 * Skip comment lines...
408 * Strip trailing newline, if any...
413 if (line
[len
- 1] == '\n')
420 * Extract the name from the beginning of the line...
423 for (value
= line
; isspace(*value
); value
++);
425 for (nameptr
= name
; *value
!= '\0' && !isspace(*value
);)
426 *nameptr
++ = *value
++;
429 while (isspace(*value
))
436 * Decode the directive...
439 if (strcmp(name
, "<Printer") == 0 ||
440 strcmp(name
, "<DefaultPrinter") == 0)
443 * <Printer name> or <DefaultPrinter name>
446 if (line
[len
- 1] == '>' && p
== NULL
)
449 * Add the printer and a base file type...
452 line
[len
- 1] = '\0';
454 p
= AddPrinter(value
);
456 p
->state
= IPP_PRINTER_IDLE
;
459 * Set the default printer as needed...
462 if (strcmp(name
, "<DefaultPrinter") == 0)
467 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
472 else if (strcmp(name
, "</Printer>") == 0)
481 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
488 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
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)
502 * Set the initial queue state...
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
;
510 else if (strcmp(name
, "StateMessage") == 0)
513 * Set the initial queue state message...
516 while (isspace(*value
))
519 strcpy(p
->state_message
, value
);
521 else if (strcmp(name
, "Accepting") == 0)
524 * Set the initial accepting state...
527 if (strcasecmp(value
, "yes") == 0)
532 else if (strcmp(name
, "JobSheets") == 0)
535 * Set the initial job sheets...
538 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
); valueptr
++);
543 strncpy(p
->job_sheets
[0], value
, sizeof(p
->job_sheets
[0]) - 1);
545 while (isspace(*valueptr
))
550 for (value
= valueptr
; *valueptr
&& !isspace(*valueptr
); valueptr
++);
555 strncpy(p
->job_sheets
[1], value
, sizeof(p
->job_sheets
[1]) - 1);
561 * Something else we don't understand...
564 LogMessage(L_ERROR
, "Unknown configuration directive %s on line %d of printers.conf.",
574 * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf
579 SaveAllPrinters(void)
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 */
589 * Create the printers.conf file...
592 sprintf(temp
, "%s/printers.conf", ServerRoot
);
593 if ((fp
= fopen(temp
, "w")) == NULL
)
595 LogMessage(L_ERROR
, "Unable to save printers.conf - %s", strerror(errno
));
599 LogMessage(L_INFO
, "Saving printers.conf...");
602 * Write a small header to the file...
605 curtime
= time(NULL
);
606 curdate
= gmtime(&curtime
);
607 strftime(temp
, sizeof(temp
) - 1, "# Written by cupsd on %c\n", curdate
);
609 fputs("# Printer configuration file for " CUPS_SVERSION
"\n", fp
);
613 * Write each local printer known to the system...
616 for (printer
= Printers
; printer
!= NULL
; printer
= printer
->next
)
619 * Skip remote destinations and printer classes...
622 if ((printer
->type
& CUPS_PRINTER_REMOTE
) ||
623 (printer
->type
& CUPS_PRINTER_CLASS
))
627 * Write printers as needed...
630 if (printer
== DefaultPrinter
)
631 fprintf(fp
, "<DefaultPrinter %s>\n", printer
->name
);
633 fprintf(fp
, "<Printer %s>\n", printer
->name
);
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
)
643 fputs("State Stopped\n", fp
);
644 fprintf(fp
, "StateMessage %s\n", printer
->state_message
);
647 fputs("State Idle\n", fp
);
648 if (printer
->accepting
)
649 fputs("Accepting Yes\n", fp
);
651 fputs("Accepting No\n", fp
);
652 fprintf(fp
, "JobSheets %s %s\n", printer
->job_sheets
[0],
653 printer
->job_sheets
[1]);
655 fputs("</Printer>\n", fp
);
663 * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file.
667 SetPrinterAttrs(printer_t
*p
) /* I - Printer to setup */
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 */
689 ipp_orient_t orients
[4] = /* orientation-requested-supported values */
693 IPP_REVERSE_LANDSCAPE
,
696 const char *sides
[3] = /* sides-supported values */
702 const char *versions
[] = /* ipp-versions-supported values */
707 ipp_op_t ops
[] = /* operations-supported values */
714 IPP_GET_JOB_ATTRIBUTES
,
716 IPP_GET_PRINTER_ATTRIBUTES
,
722 IPP_SET_JOB_ATTRIBUTES
,
736 const char *charsets
[] = /* charset-supported values */
752 ipp_finish_t finishings
[5];
753 const char *multiple_document_handling
[] =
756 "separate-documents-uncollated-copies",
757 "separate-documents-collated-copies",
758 "single-document-new-sheet"
761 FILE *fp
; /* Interface script file */
765 DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p
->name
,
769 * Clear out old filters and add a filter from application/vnd.cups-raw to
770 * printer/name to handle "raw" printing by users.
773 DeletePrinterFilters(p
);
774 AddPrinterFilter(p
, "application/vnd.cups-raw 0 -");
777 * Figure out the authentication that is required for the printer.
780 auth_supported
= "requesting-user-name";
781 if (!(p
->type
& CUPS_PRINTER_REMOTE
))
783 if (p
->type
& CUPS_PRINTER_CLASS
)
786 sprintf(resource
, "/classes/%s", p
->name
);
791 sprintf(resource
, "/printers/%s", p
->name
);
794 for (i
= NumLocations
, auth
= Locations
; i
> 0; i
--, auth
++)
795 if (strcmp(auth
->location
, resource
) == 0)
801 if (auth
->type
== AUTH_BASIC
)
802 auth_supported
= "basic";
803 else if (auth
->type
== AUTH_DIGEST
)
804 auth_supported
= "digest";
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))))
813 * Matches base printer or class resources...
816 if (auth
->type
== AUTH_BASIC
)
817 auth_supported
= "basic";
818 else if (auth
->type
== AUTH_DIGEST
)
819 auth_supported
= "digest";
824 * Create the required IPP attributes for a printer...
832 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "printer-uri-supported",
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
,
840 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
842 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
844 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "printer-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]),
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
);
893 * Setup the job-sheets-supported and job-sheets-default attributes...
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
);
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]);
908 if (p
->type
& CUPS_PRINTER_REMOTE
)
911 * Tell the client this is a remote printer of some type...
914 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
915 "printer-make-and-model", NULL
, p
->make_model
);
920 * Assign additional attributes depending on whether this is a printer
924 p
->type
&= ~CUPS_PRINTER_OPTIONS
;
926 if (p
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
))
929 * Add class-specific attributes...
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
);
936 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
937 "printer-make-and-model", NULL
, "Local Printer Class");
939 if (p
->num_printers
> 0)
942 * Add a list of member URIs and names...
945 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
946 "member-uris", p
->num_printers
, NULL
, NULL
);
948 p
->type
|= CUPS_PRINTER_OPTIONS
;
950 for (i
= 0; i
< p
->num_printers
; i
++)
952 attr
->values
[i
].string
.text
= strdup(p
->printers
[i
]->uri
);
954 p
->type
&= ~CUPS_PRINTER_OPTIONS
| p
->printers
[i
]->type
;
957 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
958 "member-names", p
->num_printers
, NULL
, NULL
);
960 for (i
= 0; i
< p
->num_printers
; i
++)
961 attr
->values
[i
].string
.text
= strdup(p
->printers
[i
]->name
);
967 * Add printer-specific attributes... Start by sanitizing the device
968 * URI so it doesn't have a username or password in it...
971 if (strstr(p
->device_uri
, "://") != NULL
)
974 * http://..., ipp://..., etc.
977 httpSeparate(p
->device_uri
, method
, username
, host
, &port
, resource
);
979 sprintf(uri
, "%s://%s:%d%s", method
, host
, port
, resource
);
981 sprintf(uri
, "%s://%s%s", method
, host
, resource
);
986 * file:..., serial:..., etc.
989 strcpy(uri
, p
->device_uri
);
992 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri", NULL
,
996 * Assign additional attributes from the PPD file (if any)...
999 p
->type
|= CUPS_PRINTER_BW
;
1000 finishings
[0] = IPP_FINISH_NONE
;
1003 sprintf(filename
, "%s/ppd/%s.ppd", ServerRoot
, p
->name
);
1004 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1007 * Add make/model and other various attributes...
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
;
1017 ippAddBoolean(p
->attrs
, IPP_TAG_PRINTER
, "color-supported",
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
);
1025 strncpy(p
->make_model
, ppd
->nickname
, sizeof(p
->make_model
) - 1);
1028 * Add media options from the PPD file...
1031 if ((input_slot
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
1032 num_media
= input_slot
->num_choices
;
1036 if ((media_type
= ppdFindOption(ppd
, "MediaType")) != NULL
)
1037 num_media
+= media_type
->num_choices
;
1039 if ((page_size
= ppdFindOption(ppd
, "PageSize")) != NULL
)
1040 num_media
+= page_size
->num_choices
;
1042 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1043 "media-supported", num_media
, NULL
, NULL
);
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
);
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
);
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
);
1058 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "media-default",
1059 NULL
, page_size
->defchoice
);
1061 if (ppdFindOption(ppd
, "Duplex") != NULL
)
1063 p
->type
|= CUPS_PRINTER_DUPLEX
;
1065 ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "sides-supported",
1067 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "sides-default",
1071 if (ppdFindOption(ppd
, "Collate") != NULL
)
1072 p
->type
|= CUPS_PRINTER_COLLATE
;
1074 if (ppdFindOption(ppd
, "StapleLocation") != NULL
)
1076 p
->type
|= CUPS_PRINTER_STAPLE
;
1077 finishings
[num_finishings
++] = IPP_FINISH_STAPLE
;
1080 if (ppdFindOption(ppd
, "BindEdge") != NULL
)
1082 p
->type
|= CUPS_PRINTER_BIND
;
1083 finishings
[num_finishings
++] = IPP_FINISH_BIND
;
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
;
1092 p
->type
|= CUPS_PRINTER_SMALL
;
1095 * Add any filters in the PPD file...
1098 DEBUG_printf(("ppd->num_filters = %d\n", ppd
->num_filters
));
1099 for (i
= 0; i
< ppd
->num_filters
; i
++)
1101 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i
, ppd
->filters
[i
]));
1102 AddPrinterFilter(p
, ppd
->filters
[i
]);
1105 if (ppd
->num_filters
== 0)
1106 AddPrinterFilter(p
, "application/vnd.cups-postscript 0 -");
1110 else if (access(filename
, 0) == 0)
1112 LogMessage(L_ERROR
, "PPD file for %s cannot be loaded!", p
->name
);
1114 AddPrinterFilter(p
, "application/vnd.cups-postscript 0 -");
1119 * If we have an interface script, add a filter entry for it...
1122 sprintf(filename
, "%s/interfaces/%s", ServerRoot
, p
->name
);
1123 if (access(filename
, X_OK
) == 0)
1126 * Yes, we have a System V style interface script; use it!
1129 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1130 "printer-make-and-model", NULL
, "Local System V Printer");
1132 sprintf(filename
, "*/* 0 %s/interfaces/%s", ServerRoot
, p
->name
);
1133 AddPrinterFilter(p
, filename
);
1138 * Otherwise we have neither - treat this as a "dumb" printer
1139 * with no PPD file...
1142 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1143 "printer-make-and-model", NULL
, "Local Raw Printer");
1145 AddPrinterFilter(p
, "*/* 0 -");
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
);
1157 * Add the CUPS-specific printer-type attribute...
1160 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-type", p
->type
);
1162 DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p
->name
,
1167 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
1171 sprintf(filename
, "/var/spool/lp/interface/%s", p
->name
);
1172 if ((fp
= fopen(filename
, "w")) != NULL
)
1174 fputs("#!/bin/sh\n", fp
);
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
);
1182 fputs("NAME=\"Remote Destination\"\n", fp
);
1184 if (p
->type
& CUPS_PRINTER_COLOR
)
1185 fputs("TYPE=ColorPostScript\n", fp
);
1187 fputs("TYPE=PostScript\n", fp
);
1190 chmod(filename
, 0755);
1193 sprintf(filename
, "/var/spool/lp/member/%s", p
->name
);
1194 if ((fp
= fopen(filename
, "w")) != NULL
)
1196 fputs("/dev/null\n", fp
);
1198 chmod(filename
, 0644);
1201 sprintf(filename
, "/var/spool/lp/gui_interface/ELF/%s.gui", p
->name
);
1202 if ((fp
= fopen(filename
, "w")) != NULL
)
1204 fputs("#!/bin/sh\n", fp
);
1205 fprintf(fp
, "/usr/bin/glpoptions -d %s -o \"$3\"\n", p
->name
);
1207 chmod(filename
, 0755);
1210 sprintf(filename
, "/var/spool/lp/activeicons/%s", p
->name
);
1211 if ((fp
= fopen(filename
, "w")) != NULL
)
1213 fputs("#!/bin/sh\n", fp
);
1214 if (p
->type
& CUPS_PRINTER_COLOR
)
1215 fputs("#Tag 66240\n", fp
);
1217 fputs("#Tag 66208\n", fp
);
1219 chmod(filename
, 0755);
1226 * 'SetPrinterState()' - Update the current state of a printer.
1230 SetPrinterState(printer_t
*p
, /* I - Printer to change */
1231 ipp_pstate_t s
) /* I - New state */
1233 ipp_pstate_t old_state
; /* Old printer state */
1237 * Can't set status of remote printers...
1240 if (p
->type
& CUPS_PRINTER_REMOTE
)
1244 * Set the new state...
1247 old_state
= p
->state
;
1249 p
->state_time
= time(NULL
);
1255 * Save the printer configuration if a printer goes from idle or processing
1256 * to stopped (or visa-versa)...
1259 if ((old_state
== IPP_PRINTER_STOPPED
) != (s
== IPP_PRINTER_STOPPED
))
1263 * Check to see if any pending jobs can now be printed...
1271 * 'SortPrinters()' - Sort the printer list when a printer name is changed.
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 */
1285 for (did_swap
= 0, current
= Printers
, prev
= NULL
; current
!= NULL
;)
1286 if (current
->next
== NULL
)
1288 else if (strcasecmp(current
->name
, current
->next
->name
) > 0)
1290 DEBUG_printf(("Swapping %s and %s...\n", current
->name
,
1291 current
->next
->name
));
1294 * Need to swap these two printers...
1300 Printers
= current
->next
;
1302 prev
->next
= current
->next
;
1305 * Yes, we can all get a headache from the next bunch of pointer
1309 next
= current
->next
;
1310 current
->next
= next
->next
;
1311 next
->next
= current
;
1314 current
= current
->next
;
1321 * 'StopPrinter()' - Stop a printer from printing any jobs...
1325 StopPrinter(printer_t
*p
) /* I - Printer to stop */
1328 StopJob(((job_t
*)p
->job
)->id
);
1330 p
->state
= IPP_PRINTER_STOPPED
;
1335 * 'write_printcap()' - Write a pseudo-printcap file for older applications
1340 write_printcap(void)
1342 FILE *fp
; /* printcap file */
1343 printer_t
*p
; /* Current printer */
1347 * See if we have a printcap file; if not, don't bother writing it.
1354 * Write a new printcap with the current list of printers. Each printer
1355 * is put in the file as:
1364 if ((fp
= fopen(Printcap
, "w")) == NULL
)
1367 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
1368 fprintf(fp
, "%s:\n", p
->name
);
1379 * End of "$Id: printers.c,v 1.61 2000/04/19 15:18:55 mike Exp $".