4 * Printer routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2005 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 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * AddPrinter() - Add a printer to the system.
27 * AddPrinterFilter() - Add a MIME filter for a printer.
28 * AddPrinterHistory() - Add the current printer state to the history.
29 * AddPrinterUser() - Add a user to the ACL.
30 * DeleteAllPrinters() - Delete all printers from the system.
31 * DeletePrinter() - Delete a printer from the system.
32 * DeletePrinterFilters() - Delete all MIME filters for a printer.
33 * FindPrinter() - Find a printer in the list.
34 * FreePrinterUsers() - Free allow/deny users.
35 * LoadAllPrinters() - Load printers from the printers.conf file.
36 * SaveAllPrinters() - Save all printer definitions to the printers.conf
37 * SetPrinterAttrs() - Set printer attributes based upon the PPD file.
38 * SetPrinterReasons() - Set/update the reasons strings.
39 * SetPrinterState() - Update the current state of a printer.
40 * SortPrinters() - Sort the printer list when a printer name is
42 * StopPrinter() - Stop a printer from printing any jobs...
43 * ValidateDest() - Validate a printer/class destination.
44 * WritePrintcap() - Write a pseudo-printcap file for older
45 * applications that need it...
46 * cupsdSanitizeURI() - Sanitize a device URI...
47 * write_irix_config() - Update the config files used by the IRIX
49 * write_irix_state() - Update the status files used by IRIX printing
54 * Include necessary headers...
65 static void write_irix_config(printer_t
*p
);
66 static void write_irix_state(printer_t
*p
);
71 * 'AddPrinter()' - Add a printer to the system.
74 printer_t
* /* O - New printer */
75 AddPrinter(const char *name
) /* I - Name of printer */
77 printer_t
*p
, /* New printer */
78 *current
, /* Current printer in list */
79 *prev
; /* Previous printer in list */
83 * Range check input...
86 LogMessage(L_DEBUG2
, "AddPrinter(\"%s\")", name
? name
: "(null)");
92 * Create a new printer entity...
95 if ((p
= calloc(1, sizeof(printer_t
))) == NULL
)
97 LogMessage(L_CRIT
, "Unable to allocate memory for printer - %s",
102 SetString(&p
->name
, name
);
103 SetString(&p
->info
, name
);
104 SetString(&p
->hostname
, ServerName
);
106 SetStringf(&p
->uri
, "ipp://%s:%d/printers/%s", ServerName
, LocalPort
, name
);
107 SetStringf(&p
->device_uri
, "file:/dev/null");
109 p
->state
= IPP_PRINTER_STOPPED
;
112 p
->filetype
= mimeAddType(MimeDatabase
, "printer", name
);
114 SetString(&p
->job_sheets
[0], "none");
115 SetString(&p
->job_sheets
[1], "none");
117 SetString(&p
->error_policy
, "stop-printer");
118 SetString(&p
->op_policy
, DefaultPolicy
);
120 p
->op_policy_ptr
= DefaultPolicyPtr
;
122 if (MaxPrinterHistory
)
123 p
->history
= calloc(MaxPrinterHistory
, sizeof(ipp_t
*));
126 * Insert the printer in the printer list alphabetically...
129 for (prev
= NULL
, current
= Printers
;
131 prev
= current
, current
= current
->next
)
132 if (strcasecmp(p
->name
, current
->name
) < 0)
136 * Insert this printer before the current one...
147 * Write a new /etc/printcap or /var/spool/lp/pstatus file.
153 * Bump the printer count and return...
163 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
167 AddPrinterFilter(printer_t
*p
, /* I - Printer to add to */
168 const char *filter
) /* I - Filter to add */
170 int i
; /* Looping var */
171 char super
[MIME_MAX_SUPER
], /* Super-type for filter */
172 type
[MIME_MAX_TYPE
], /* Type for filter */
173 program
[1024]; /* Program/filter name */
174 int cost
; /* Cost of filter */
175 mime_type_t
**temptype
; /* MIME type looping var */
179 * Range check input...
182 if (p
== NULL
|| p
->filetype
== NULL
|| filter
== NULL
)
186 * Parse the filter string; it should be in the following format:
188 * super/type cost program
191 if (sscanf(filter
, "%15[^/]/%31s%d%1023s", super
, type
, &cost
, program
) != 4)
193 LogMessage(L_ERROR
, "AddPrinterFilter: Invalid filter string \"%s\"!",
199 * Add the filter to the MIME database, supporting wildcards as needed...
202 for (temptype
= MimeDatabase
->types
, i
= MimeDatabase
->num_types
;
205 if (((super
[0] == '*' && strcasecmp((*temptype
)->super
, "printer") != 0) ||
206 !strcasecmp((*temptype
)->super
, super
)) &&
207 (type
[0] == '*' || !strcasecmp((*temptype
)->type
, type
)))
209 LogMessage(L_DEBUG2
, "Adding filter %s/%s %s/%s %d %s",
210 (*temptype
)->super
, (*temptype
)->type
,
211 p
->filetype
->super
, p
->filetype
->type
,
213 mimeAddFilter(MimeDatabase
, *temptype
, p
->filetype
, cost
, program
);
219 * 'AddPrinterHistory()' - Add the current printer state to the history.
223 AddPrinterHistory(printer_t
*p
) /* I - Printer */
225 ipp_t
*history
; /* History collection */
229 * Stop early if we aren't keeping history data...
232 if (MaxPrinterHistory
<= 0)
236 * Retire old history data as needed...
239 p
->sequence_number
++;
241 if (p
->num_history
>= MaxPrinterHistory
)
244 ippDelete(p
->history
[0]);
245 memmove(p
->history
, p
->history
+ 1, p
->num_history
* sizeof(ipp_t
*));
249 * Create a collection containing the current printer-state, printer-up-time,
250 * printer-state-message, and printer-state-reasons attributes.
254 ippAddInteger(history
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
256 ippAddBoolean(history
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs",
258 ippAddString(history
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-state-message",
259 NULL
, p
->state_message
);
260 if (p
->num_reasons
== 0)
261 ippAddString(history
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
262 "printer-state-reasons", NULL
,
263 p
->state
== IPP_PRINTER_STOPPED
? "paused" : "none");
265 ippAddStrings(history
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
266 "printer-state-reasons", p
->num_reasons
, NULL
,
267 (const char * const *)p
->reasons
);
268 ippAddInteger(history
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
269 "printer-state-time", p
->state_time
);
270 ippAddInteger(history
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
271 "printer-state-sequence-number", p
->sequence_number
);
273 p
->history
[p
->num_history
] = history
;
279 * 'AddPrinterUser()' - Add a user to the ACL.
283 AddPrinterUser(printer_t
*p
, /* I - Printer */
284 const char *username
) /* I - User */
286 const char **temp
; /* Temporary array pointer */
292 if (p
->num_users
== 0)
293 temp
= malloc(sizeof(char **));
295 temp
= realloc(p
->users
, sizeof(char **) * (p
->num_users
+ 1));
301 temp
+= p
->num_users
;
303 if ((*temp
= strdup(username
)) != NULL
)
309 * 'CreateCommonData()' - Create the common printer data.
313 CreateCommonData(void)
315 int i
; /* Looping var */
316 ipp_attribute_t
*attr
; /* Attribute data */
317 printer_t
*p
; /* Current printer */
318 static const int nups
[] = /* number-up-supported values */
319 { 1, 2, 4, 6, 9, 16 };
320 static const ipp_orient_t orients
[4] =/* orientation-requested-supported values */
324 IPP_REVERSE_LANDSCAPE
,
327 static const char * const holds
[] = /* job-hold-until-supported values */
338 static const char * const versions
[] =/* ipp-versions-supported values */
343 static const ipp_op_t ops
[] = /* operations-supported values */
350 IPP_GET_JOB_ATTRIBUTES
,
352 IPP_GET_PRINTER_ATTRIBUTES
,
358 IPP_SET_JOB_ATTRIBUTES
,
359 IPP_CREATE_PRINTER_SUBSCRIPTION
,
360 IPP_CREATE_JOB_SUBSCRIPTION
,
361 IPP_GET_SUBSCRIPTION_ATTRIBUTES
,
362 IPP_GET_SUBSCRIPTIONS
,
363 IPP_RENEW_SUBSCRIPTION
,
364 IPP_CANCEL_SUBSCRIPTION
,
365 IPP_GET_NOTIFICATIONS
,
381 static const char * const charsets
[] =/* charset-supported values */
386 static const char * const compressions
[] =
387 { /* document-compression-supported values */
391 #endif /* HAVE_LIBZ */
393 static const char * const multiple_document_handling
[] =
394 { /* multiple-document-handling-supported values */
395 "separate-documents-uncollated-copies",
396 "separate-documents-collated-copies"
398 static const char * const errors
[] = /* printer-error-policy-supported values */
407 ippDelete(CommonData
);
409 CommonData
= ippNew();
411 ippAddString(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
412 "pdl-override-supported", NULL
, "not-attempted");
413 ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
414 "ipp-versions-supported", sizeof(versions
) / sizeof(versions
[0]),
416 ippAddIntegers(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
417 "operations-supported",
418 sizeof(ops
) / sizeof(ops
[0]) + JobFiles
- 1, (int *)ops
);
419 ippAddBoolean(CommonData
, IPP_TAG_PRINTER
,
420 "multiple-document-jobs-supported", 1);
421 ippAddInteger(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
422 "multiple-operation-time-out", 60);
423 ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
424 "multiple-document-handling-supported",
425 sizeof(multiple_document_handling
) /
426 sizeof(multiple_document_handling
[0]), NULL
,
427 multiple_document_handling
);
428 ippAddString(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_CHARSET
,
429 "charset-configured", NULL
, DefaultCharset
);
430 ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_CHARSET
,
431 "charset-supported", sizeof(charsets
) / sizeof(charsets
[0]),
433 ippAddString(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_LANGUAGE
,
434 "natural-language-configured", NULL
, DefaultLanguage
);
435 ippAddString(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_LANGUAGE
,
436 "generated-natural-language-supported", NULL
, DefaultLanguage
);
437 ippAddString(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_MIMETYPE
,
438 "document-format-default", NULL
, "application/octet-stream");
439 ippAddStrings(CommonData
, IPP_TAG_PRINTER
,
440 (ipp_tag_t
)(IPP_TAG_MIMETYPE
| IPP_TAG_COPY
),
441 "document-format-supported", NumMimeTypes
, NULL
, MimeTypes
);
442 ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
443 "compression-supported",
444 sizeof(compressions
) / sizeof(compressions
[0]),
446 ippAddInteger(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
447 "job-priority-supported", 100);
448 ippAddInteger(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
449 "job-priority-default", 50);
450 ippAddRange(CommonData
, IPP_TAG_PRINTER
, "copies-supported", 1, MaxCopies
);
451 ippAddInteger(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
452 "copies-default", 1);
453 ippAddBoolean(CommonData
, IPP_TAG_PRINTER
, "page-ranges-supported", 1);
454 ippAddIntegers(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
455 "number-up-supported", sizeof(nups
) / sizeof(nups
[0]), nups
);
456 ippAddInteger(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
457 "number-up-default", 1);
458 ippAddIntegers(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
459 "orientation-requested-supported", 4, (int *)orients
);
460 ippAddInteger(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
461 "orientation-requested-default", IPP_PORTRAIT
);
462 ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
463 "job-hold-until-supported", sizeof(holds
) / sizeof(holds
[0]),
465 ippAddString(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
466 "job-hold-until-default", NULL
, "no-hold");
467 attr
= ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
468 "printer-op-policy-supported", NumPolicies
, NULL
, NULL
);
469 for (i
= 0; i
< NumPolicies
; i
++)
470 attr
->values
[i
].string
.text
= strdup(Policies
[i
]->name
);
471 ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
472 "printer-error-policy-supported",
473 sizeof(errors
) / sizeof(errors
[0]), NULL
, errors
);
478 * Setup the job-sheets-supported and job-sheets-default attributes...
481 if (Classification
&& !ClassifyOverride
)
482 attr
= ippAddString(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
483 "job-sheets-supported", NULL
, Classification
);
485 attr
= ippAddStrings(CommonData
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
486 "job-sheets-supported", NumBanners
+ 1, NULL
, NULL
);
489 LogMessage(L_EMERG
, "SetPrinterAttrs: Unable to allocate memory for "
490 "job-sheets-supported attribute: %s!",
492 else if (!Classification
|| ClassifyOverride
)
494 attr
->values
[0].string
.text
= strdup("none");
496 for (i
= 0; i
< NumBanners
; i
++)
497 attr
->values
[i
+ 1].string
.text
= strdup(Banners
[i
].name
);
502 * Loop through the printers and update the op_policy_ptr values...
505 for (p
= Printers
; p
; p
= p
->next
)
506 if ((p
->op_policy_ptr
= cupsdFindPolicy(p
->op_policy
)) == NULL
)
507 p
->op_policy_ptr
= DefaultPolicyPtr
;
512 * 'DeleteAllPrinters()' - Delete all printers from the system.
516 DeleteAllPrinters(void)
518 printer_t
*p
, /* Pointer to current printer/class */
519 *next
; /* Pointer to next printer in list */
522 for (p
= Printers
; p
!= NULL
; p
= next
)
526 if (!(p
->type
& CUPS_PRINTER_CLASS
))
533 * 'DeletePrinter()' - Delete a printer from the system.
537 DeletePrinter(printer_t
*p
, /* I - Printer to delete */
538 int update
) /* I - Update printers.conf? */
540 int i
; /* Looping var */
541 printer_t
*current
, /* Current printer in list */
542 *prev
; /* Previous printer in list */
544 char filename
[1024]; /* Interface script filename */
548 DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p
, p
->name
));
551 * Range check input...
558 * Find the printer in the list...
561 for (prev
= NULL
, current
= Printers
;
563 prev
= current
, current
= current
->next
)
569 LogMessage(L_ERROR
, "Tried to delete a non-existent printer %s!\n",
575 * Remove the printer from the list...
581 prev
->next
= p
->next
;
586 * Stop printing on this printer...
589 StopPrinter(p
, update
);
592 * If this printer is the next for browsing, point to the next one...
596 BrowseNext
= p
->next
;
599 * Remove the dummy interface/icon/option files under IRIX...
603 snprintf(filename
, sizeof(filename
), "/var/spool/lp/interface/%s", p
->name
);
606 snprintf(filename
, sizeof(filename
), "/var/spool/lp/gui_interface/ELF/%s.gui",
610 snprintf(filename
, sizeof(filename
), "/var/spool/lp/activeicons/%s", p
->name
);
613 snprintf(filename
, sizeof(filename
), "/var/spool/lp/pod/%s.config", p
->name
);
616 snprintf(filename
, sizeof(filename
), "/var/spool/lp/pod/%s.status", p
->name
);
619 snprintf(filename
, sizeof(filename
), "/var/spool/lp/member/%s", p
->name
);
624 * If p is the default printer, assign the next one...
627 if (p
== DefaultPrinter
)
629 DefaultPrinter
= Printers
;
635 * Remove this printer from any classes and send a browse delete message...
638 if (!(p
->type
& CUPS_PRINTER_IMPLICIT
))
640 DeletePrinterFromClasses(p
);
645 * Free all memory used by the printer...
648 if (p
->printers
!= NULL
)
651 if (MaxPrinterHistory
)
653 for (i
= 0; i
< p
->num_history
; i
++)
654 ippDelete(p
->history
[i
]);
659 for (i
= 0; i
< p
->num_reasons
; i
++)
664 DeletePrinterFilters(p
);
669 ClearString(&p
->uri
);
670 ClearString(&p
->hostname
);
671 ClearString(&p
->name
);
672 ClearString(&p
->location
);
673 ClearString(&p
->make_model
);
674 ClearString(&p
->info
);
675 ClearString(&p
->job_sheets
[0]);
676 ClearString(&p
->job_sheets
[1]);
677 ClearString(&p
->device_uri
);
678 ClearString(&p
->port_monitor
);
679 ClearString(&p
->op_policy
);
680 ClearString(&p
->error_policy
);
685 * Write a new /etc/printcap file...
693 * 'DeletePrinterFilters()' - Delete all MIME filters for a printer.
697 DeletePrinterFilters(printer_t
*p
) /* I - Printer to remove from */
699 int i
; /* Looping var */
700 mime_filter_t
*filter
; /* MIME filter looping var */
704 * Range check input...
711 * Remove all filters from the MIME database that have a destination
715 for (filter
= MimeDatabase
->filters
, i
= MimeDatabase
->num_filters
;
718 if (filter
->dst
== p
->filetype
)
721 * Delete the current filter...
724 MimeDatabase
->num_filters
--;
727 memmove(filter
, filter
+ 1, sizeof(mime_filter_t
) * (i
- 1));
735 * 'FindDest()' - Find a destination in the list.
738 printer_t
* /* O - Destination in list */
739 FindDest(const char *name
) /* I - Name of printer or class to find */
741 printer_t
*p
; /* Current destination */
742 int diff
; /* Difference */
745 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
746 if ((diff
= strcasecmp(name
, p
->name
)) == 0)/* name == p->name */
748 else if (diff
< 0) /* name < p->name */
756 * 'FindPrinter()' - Find a printer in the list.
759 printer_t
* /* O - Printer in list */
760 FindPrinter(const char *name
) /* I - Name of printer to find */
762 printer_t
*p
; /* Current printer */
763 int diff
; /* Difference */
766 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
767 if ((diff
= strcasecmp(name
, p
->name
)) == 0 &&
768 !(p
->type
& CUPS_PRINTER_CLASS
)) /* name == p->name */
770 else if (diff
< 0) /* name < p->name */
778 * 'FreePrinterUsers()' - Free allow/deny users.
782 FreePrinterUsers(printer_t
*p
) /* I - Printer */
784 int i
; /* Looping var */
787 if (!p
|| !p
->num_users
)
790 for (i
= 0; i
< p
->num_users
; i
++)
791 free((void *)p
->users
[i
]);
801 * 'LoadAllPrinters()' - Load printers from the printers.conf file.
805 LoadAllPrinters(void)
807 cups_file_t
*fp
; /* printers.conf file */
808 int linenum
; /* Current line number */
809 char line
[1024], /* Line from file */
810 *value
, /* Pointer to value */
811 *valueptr
; /* Pointer into value */
812 printer_t
*p
; /* Current printer */
816 * Open the printers.conf file...
819 snprintf(line
, sizeof(line
), "%s/printers.conf", ServerRoot
);
820 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
822 LogMessage(L_ERROR
, "LoadAllPrinters: Unable to open %s - %s", line
,
828 * Read printer configurations until we hit EOF...
834 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
837 * Decode the directive...
840 if (!strcasecmp(line
, "<Printer") ||
841 !strcasecmp(line
, "<DefaultPrinter"))
844 * <Printer name> or <DefaultPrinter name>
847 if (p
== NULL
&& value
)
850 * Add the printer and a base file type...
853 LogMessage(L_DEBUG
, "LoadAllPrinters: Loading printer %s...", value
);
855 p
= AddPrinter(value
);
857 p
->state
= IPP_PRINTER_IDLE
;
860 * Set the default printer as needed...
863 if (!strcasecmp(line
, "<DefaultPrinter"))
868 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
873 else if (!strcasecmp(line
, "</Printer>"))
878 * Close out the current printer...
882 AddPrinterHistory(p
);
884 if (p
->device_uri
&& strncmp(p
->device_uri
, "file:", 5) &&
885 p
->state
!= IPP_PRINTER_STOPPED
)
888 * See if the backend exists...
891 snprintf(line
, sizeof(line
), "%s/backends/%s", ServerBin
,
894 if ((valueptr
= strchr(line
+ strlen(ServerBin
), ':')) != NULL
)
895 *valueptr
= '\0'; /* Chop everything but URI scheme */
900 * Backend does not exist, stop printer...
903 p
->state
= IPP_PRINTER_STOPPED
;
904 snprintf(p
->state_message
, sizeof(p
->state_message
),
905 "Backend %s does not exist!", line
);
913 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
920 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
924 else if (!strcasecmp(line
, "Info"))
927 SetString(&p
->info
, value
);
929 else if (!strcasecmp(line
, "Location"))
932 SetString(&p
->location
, value
);
934 else if (!strcasecmp(line
, "DeviceURI"))
937 SetString(&p
->device_uri
, value
);
940 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
945 else if (!strcasecmp(line
, "PortMonitor"))
947 if (value
&& strcmp(value
, "none"))
948 SetString(&p
->port_monitor
, value
);
950 ClearString(&p
->port_monitor
);
953 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
958 else if (!strcasecmp(line
, "State"))
961 * Set the initial queue state...
964 if (value
&& !strcasecmp(value
, "idle"))
965 p
->state
= IPP_PRINTER_IDLE
;
966 else if (value
&& !strcasecmp(value
, "stopped"))
967 p
->state
= IPP_PRINTER_STOPPED
;
970 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
975 else if (!strcasecmp(line
, "StateMessage"))
978 * Set the initial queue state message...
982 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
984 else if (!strcasecmp(line
, "Accepting"))
987 * Set the initial accepting state...
991 (!strcasecmp(value
, "yes") ||
992 !strcasecmp(value
, "on") ||
993 !strcasecmp(value
, "true")))
996 (!strcasecmp(value
, "no") ||
997 !strcasecmp(value
, "off") ||
998 !strcasecmp(value
, "false")))
1002 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1007 else if (!strcasecmp(line
, "Shared"))
1010 * Set the initial shared state...
1014 (!strcasecmp(value
, "yes") ||
1015 !strcasecmp(value
, "on") ||
1016 !strcasecmp(value
, "true")))
1019 (!strcasecmp(value
, "no") ||
1020 !strcasecmp(value
, "off") ||
1021 !strcasecmp(value
, "false")))
1025 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1030 else if (!strcasecmp(line
, "JobSheets"))
1033 * Set the initial job sheets...
1038 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
1043 SetString(&p
->job_sheets
[0], value
);
1045 while (isspace(*valueptr
& 255))
1050 for (value
= valueptr
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
1055 SetString(&p
->job_sheets
[1], value
);
1060 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1065 else if (!strcasecmp(line
, "AllowUser"))
1070 AddPrinterUser(p
, value
);
1074 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1079 else if (!strcasecmp(line
, "DenyUser"))
1084 AddPrinterUser(p
, value
);
1088 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1093 else if (!strcasecmp(line
, "QuotaPeriod"))
1096 p
->quota_period
= atoi(value
);
1099 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1104 else if (!strcasecmp(line
, "PageLimit"))
1107 p
->page_limit
= atoi(value
);
1110 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1115 else if (!strcasecmp(line
, "KLimit"))
1118 p
->k_limit
= atoi(value
);
1121 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1126 else if (!strcasecmp(line
, "OpPolicy"))
1129 SetString(&p
->op_policy
, value
);
1132 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1137 else if (!strcasecmp(line
, "ErrorPolicy"))
1140 SetString(&p
->error_policy
, value
);
1143 LogMessage(L_ERROR
, "Syntax error on line %d of printers.conf.",
1151 * Something else we don't understand...
1154 LogMessage(L_ERROR
, "Unknown configuration directive %s on line %d of printers.conf.",
1164 * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf
1169 SaveAllPrinters(void)
1171 int i
; /* Looping var */
1172 cups_file_t
*fp
; /* printers.conf file */
1173 char temp
[1024]; /* Temporary string */
1174 char backup
[1024]; /* printers.conf.O file */
1175 printer_t
*printer
; /* Current printer class */
1176 time_t curtime
; /* Current time */
1177 struct tm
*curdate
; /* Current date */
1181 * Create the printers.conf file...
1184 snprintf(temp
, sizeof(temp
), "%s/printers.conf", ServerRoot
);
1185 snprintf(backup
, sizeof(backup
), "%s/printers.conf.O", ServerRoot
);
1187 if (rename(temp
, backup
))
1188 LogMessage(L_ERROR
, "Unable to backup printers.conf - %s", strerror(errno
));
1190 if ((fp
= cupsFileOpen(temp
, "w")) == NULL
)
1192 LogMessage(L_ERROR
, "Unable to save printers.conf - %s", strerror(errno
));
1194 if (rename(backup
, temp
))
1195 LogMessage(L_ERROR
, "Unable to restore printers.conf - %s", strerror(errno
));
1199 LogMessage(L_INFO
, "Saving printers.conf...");
1202 * Restrict access to the file...
1205 fchown(cupsFileNumber(fp
), getuid(), Group
);
1206 fchmod(cupsFileNumber(fp
), ConfigFilePerm
);
1209 * Write a small header to the file...
1212 curtime
= time(NULL
);
1213 curdate
= localtime(&curtime
);
1214 strftime(temp
, sizeof(temp
) - 1, CUPS_STRFTIME_FORMAT
, curdate
);
1216 cupsFilePuts(fp
, "# Printer configuration file for " CUPS_SVERSION
"\n");
1217 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
1220 * Write each local printer known to the system...
1223 for (printer
= Printers
; printer
!= NULL
; printer
= printer
->next
)
1226 * Skip remote destinations and printer classes...
1229 if ((printer
->type
& CUPS_PRINTER_REMOTE
) ||
1230 (printer
->type
& CUPS_PRINTER_CLASS
) ||
1231 (printer
->type
& CUPS_PRINTER_IMPLICIT
))
1235 * Write printers as needed...
1238 if (printer
== DefaultPrinter
)
1239 cupsFilePrintf(fp
, "<DefaultPrinter %s>\n", printer
->name
);
1241 cupsFilePrintf(fp
, "<Printer %s>\n", printer
->name
);
1244 cupsFilePrintf(fp
, "Info %s\n", printer
->info
);
1246 if (printer
->location
)
1247 cupsFilePrintf(fp
, "Location %s\n", printer
->location
);
1249 if (printer
->device_uri
)
1250 cupsFilePrintf(fp
, "DeviceURI %s\n", printer
->device_uri
);
1252 if (printer
->port_monitor
)
1253 cupsFilePrintf(fp
, "PortMonitor %s\n", printer
->port_monitor
);
1255 if (printer
->state
== IPP_PRINTER_STOPPED
)
1257 cupsFilePuts(fp
, "State Stopped\n");
1258 cupsFilePrintf(fp
, "StateMessage %s\n", printer
->state_message
);
1261 cupsFilePuts(fp
, "State Idle\n");
1263 if (printer
->accepting
)
1264 cupsFilePuts(fp
, "Accepting Yes\n");
1266 cupsFilePuts(fp
, "Accepting No\n");
1268 if (printer
->shared
)
1269 cupsFilePuts(fp
, "Shared Yes\n");
1271 cupsFilePuts(fp
, "Shared No\n");
1273 cupsFilePrintf(fp
, "JobSheets %s %s\n", printer
->job_sheets
[0],
1274 printer
->job_sheets
[1]);
1276 cupsFilePrintf(fp
, "QuotaPeriod %d\n", printer
->quota_period
);
1277 cupsFilePrintf(fp
, "PageLimit %d\n", printer
->page_limit
);
1278 cupsFilePrintf(fp
, "KLimit %d\n", printer
->k_limit
);
1280 for (i
= 0; i
< printer
->num_users
; i
++)
1281 cupsFilePrintf(fp
, "%sUser %s\n", printer
->deny_users
? "Deny" : "Allow",
1284 if (printer
->op_policy
)
1285 cupsFilePrintf(fp
, "OpPolicy %s\n", printer
->op_policy
);
1286 if (printer
->error_policy
)
1287 cupsFilePrintf(fp
, "ErrorPolicy %s\n", printer
->error_policy
);
1289 cupsFilePuts(fp
, "</Printer>\n");
1293 * Make IRIX desktop & printer status happy
1296 write_irix_state(printer
);
1305 * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file.
1309 SetPrinterAttrs(printer_t
*p
) /* I - Printer to setup */
1311 char uri
[HTTP_MAX_URI
]; /* URI for printer */
1312 char resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1313 int i
; /* Looping var */
1314 char filename
[1024]; /* Name of PPD file */
1315 int num_media
; /* Number of media options */
1316 location_t
*auth
; /* Pointer to authentication element */
1317 const char *auth_supported
; /* Authentication supported */
1318 cups_ptype_t printer_type
; /* Printer type data */
1319 ppd_file_t
*ppd
; /* PPD file data */
1320 ppd_option_t
*input_slot
, /* InputSlot options */
1321 *media_type
, /* MediaType options */
1322 *page_size
, /* PageSize options */
1323 *output_bin
, /* OutputBin options */
1324 *media_quality
; /* EFMediaQualityMode options */
1325 ppd_attr_t
*ppdattr
; /* PPD attribute */
1326 ipp_attribute_t
*attr
; /* Attribute data */
1327 ipp_value_t
*val
; /* Attribute value */
1329 ipp_finish_t finishings
[5]; /* finishings-supported values */
1330 static const char * const sides
[3] = /* sides-supported values */
1338 DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p
->name
,
1342 * Make sure that we have the common attributes defined...
1349 * Clear out old filters, if any...
1352 DeletePrinterFilters(p
);
1355 * Figure out the authentication that is required for the printer.
1358 auth_supported
= "requesting-user-name";
1359 if (!(p
->type
& CUPS_PRINTER_REMOTE
))
1361 if (p
->type
& CUPS_PRINTER_CLASS
)
1362 snprintf(resource
, sizeof(resource
), "/classes/%s", p
->name
);
1364 snprintf(resource
, sizeof(resource
), "/printers/%s", p
->name
);
1366 if ((auth
= FindBest(resource
, HTTP_POST
)) != NULL
)
1368 if (auth
->type
== AUTH_BASIC
|| auth
->type
== AUTH_BASICDIGEST
)
1369 auth_supported
= "basic";
1370 else if (auth
->type
== AUTH_DIGEST
)
1371 auth_supported
= "digest";
1376 * Create the required IPP attributes for a printer...
1380 ippDelete(p
->attrs
);
1382 p
->attrs
= ippNew();
1384 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1385 "uri-authentication-supported", NULL
, auth_supported
);
1386 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1387 "uri-security-supported", NULL
, "none");
1388 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "printer-name", NULL
,
1390 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1391 NULL
, p
->location
? p
->location
: "");
1392 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1393 NULL
, p
->info
? p
->info
: "");
1394 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "printer-more-info",
1400 ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1401 "requesting-user-name-denied", p
->num_users
, NULL
,
1404 ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1405 "requesting-user-name-allowed", p
->num_users
, NULL
,
1409 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1410 "job-quota-period", p
->quota_period
);
1411 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1412 "job-k-limit", p
->k_limit
);
1413 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1414 "job-page-limit", p
->page_limit
);
1416 if (NumBanners
> 0 && !(p
->type
& CUPS_PRINTER_REMOTE
))
1419 * Setup the job-sheets-default attribute...
1422 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1423 "job-sheets-default", 2, NULL
, NULL
);
1427 attr
->values
[0].string
.text
= strdup(Classification
?
1428 Classification
: p
->job_sheets
[0]);
1429 attr
->values
[1].string
.text
= strdup(Classification
?
1430 Classification
: p
->job_sheets
[1]);
1434 printer_type
= p
->type
;
1438 if (p
->type
& CUPS_PRINTER_REMOTE
)
1441 * Tell the client this is a remote printer of some type...
1444 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
1445 "printer-uri-supported", NULL
, p
->uri
);
1447 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1448 "printer-make-and-model", NULL
, p
->make_model
);
1454 * Assign additional attributes depending on whether this is a printer
1458 p
->type
&= ~CUPS_PRINTER_OPTIONS
;
1460 if (p
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
))
1465 * Add class-specific attributes...
1468 if ((p
->type
& CUPS_PRINTER_IMPLICIT
) && p
->num_printers
> 0)
1469 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1470 "printer-make-and-model", NULL
, p
->printers
[0]->make_model
);
1472 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1473 "printer-make-and-model", NULL
, "Local Printer Class");
1475 if (p
->num_printers
> 0)
1478 * Add a list of member URIs and names...
1481 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
1482 "member-uris", p
->num_printers
, NULL
, NULL
);
1483 p
->type
|= CUPS_PRINTER_OPTIONS
;
1485 for (i
= 0; i
< p
->num_printers
; i
++)
1488 attr
->values
[i
].string
.text
= strdup(p
->printers
[i
]->uri
);
1490 p
->type
&= ~CUPS_PRINTER_OPTIONS
| p
->printers
[i
]->type
;
1493 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1494 "member-names", p
->num_printers
, NULL
, NULL
);
1498 for (i
= 0; i
< p
->num_printers
; i
++)
1499 attr
->values
[i
].string
.text
= strdup(p
->printers
[i
]->name
);
1506 * Add printer-specific attributes... Start by sanitizing the device
1507 * URI so it doesn't have a username or password in it...
1511 strcpy(uri
, "file:/dev/null");
1512 else if (strstr(p
->device_uri
, "://") != NULL
)
1515 * http://..., ipp://..., etc.
1518 cupsdSanitizeURI(p
->device_uri
, uri
, sizeof(uri
));
1523 * file:..., serial:..., etc.
1526 strlcpy(uri
, p
->device_uri
, sizeof(uri
));
1529 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri", NULL
,
1533 * Assign additional attributes from the PPD file (if any)...
1536 p
->type
|= CUPS_PRINTER_BW
;
1537 finishings
[0] = IPP_FINISHINGS_NONE
;
1540 snprintf(filename
, sizeof(filename
), "%s/ppd/%s.ppd", ServerRoot
,
1543 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1546 * Add make/model and other various attributes...
1549 if (ppd
->color_device
)
1550 p
->type
|= CUPS_PRINTER_COLOR
;
1551 if (ppd
->variable_sizes
)
1552 p
->type
|= CUPS_PRINTER_VARIABLE
;
1553 if (!ppd
->manual_copies
)
1554 p
->type
|= CUPS_PRINTER_COPIES
;
1555 if ((ppdattr
= ppdFindAttr(ppd
, "cupsFax", NULL
)) != NULL
)
1556 if (ppdattr
->value
&& !strcasecmp(ppdattr
->value
, "true"))
1557 p
->type
|= CUPS_PRINTER_FAX
;
1559 ippAddBoolean(p
->attrs
, IPP_TAG_PRINTER
, "color-supported",
1561 if (ppd
->throughput
)
1562 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_INTEGER
,
1563 "pages-per-minute", ppd
->throughput
);
1566 SetString(&p
->make_model
, ppd
->nickname
);
1567 else if (ppd
->modelname
)
1568 SetString(&p
->make_model
, ppd
->modelname
);
1570 SetString(&p
->make_model
, "Bad PPD File");
1572 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1573 "printer-make-and-model", NULL
, p
->make_model
);
1576 * Add media options from the PPD file...
1579 if ((input_slot
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
1580 num_media
= input_slot
->num_choices
;
1584 if ((media_type
= ppdFindOption(ppd
, "MediaType")) != NULL
)
1585 num_media
+= media_type
->num_choices
;
1587 if ((page_size
= ppdFindOption(ppd
, "PageSize")) != NULL
)
1588 num_media
+= page_size
->num_choices
;
1590 if ((media_quality
= ppdFindOption(ppd
, "EFMediaQualityMode")) != NULL
)
1591 num_media
+= media_quality
->num_choices
;
1595 LogMessage(L_CRIT
, "SetPrinterAttrs: The PPD file for printer %s "
1596 "contains no media options and is therefore "
1597 "invalid!", p
->name
);
1601 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1602 "media-supported", num_media
, NULL
, NULL
);
1607 if (input_slot
!= NULL
)
1608 for (i
= 0; i
< input_slot
->num_choices
; i
++, val
++)
1609 val
->string
.text
= strdup(input_slot
->choices
[i
].choice
);
1611 if (media_type
!= NULL
)
1612 for (i
= 0; i
< media_type
->num_choices
; i
++, val
++)
1613 val
->string
.text
= strdup(media_type
->choices
[i
].choice
);
1615 if (media_quality
!= NULL
)
1616 for (i
= 0; i
< media_quality
->num_choices
; i
++, val
++)
1617 val
->string
.text
= strdup(media_quality
->choices
[i
].choice
);
1619 if (page_size
!= NULL
)
1621 for (i
= 0; i
< page_size
->num_choices
; i
++, val
++)
1622 val
->string
.text
= strdup(page_size
->choices
[i
].choice
);
1624 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "media-default",
1625 NULL
, page_size
->defchoice
);
1627 else if (input_slot
!= NULL
)
1628 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "media-default",
1629 NULL
, input_slot
->defchoice
);
1630 else if (media_type
!= NULL
)
1631 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "media-default",
1632 NULL
, media_type
->defchoice
);
1633 else if (media_quality
!= NULL
)
1634 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "media-default",
1635 NULL
, media_quality
->defchoice
);
1637 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "media-default",
1646 if ((output_bin
= ppdFindOption(ppd
, "OutputBin")) != NULL
)
1648 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1649 "output-bin-supported", output_bin
->num_choices
,
1654 for (i
= 0, val
= attr
->values
;
1655 i
< output_bin
->num_choices
;
1657 val
->string
.text
= strdup(output_bin
->choices
[i
].choice
);
1665 if (ppdFindOption(ppd
, "Duplex") != NULL
)
1667 p
->type
|= CUPS_PRINTER_DUPLEX
;
1669 ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "sides-supported",
1671 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "sides-default",
1675 if (ppdFindOption(ppd
, "Collate") != NULL
)
1676 p
->type
|= CUPS_PRINTER_COLLATE
;
1678 if (ppdFindOption(ppd
, "StapleLocation") != NULL
)
1680 p
->type
|= CUPS_PRINTER_STAPLE
;
1681 finishings
[num_finishings
++] = IPP_FINISHINGS_STAPLE
;
1684 if (ppdFindOption(ppd
, "BindEdge") != NULL
)
1686 p
->type
|= CUPS_PRINTER_BIND
;
1687 finishings
[num_finishings
++] = IPP_FINISHINGS_BIND
;
1690 for (i
= 0; i
< ppd
->num_sizes
; i
++)
1691 if (ppd
->sizes
[i
].length
> 1728)
1692 p
->type
|= CUPS_PRINTER_LARGE
;
1693 else if (ppd
->sizes
[i
].length
> 1008)
1694 p
->type
|= CUPS_PRINTER_MEDIUM
;
1696 p
->type
|= CUPS_PRINTER_SMALL
;
1699 * Add a filter from application/vnd.cups-raw to printer/name to
1700 * handle "raw" printing by users.
1703 AddPrinterFilter(p
, "application/vnd.cups-raw 0 -");
1706 * Add any filters in the PPD file...
1709 DEBUG_printf(("ppd->num_filters = %d\n", ppd
->num_filters
));
1710 for (i
= 0; i
< ppd
->num_filters
; i
++)
1712 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i
, ppd
->filters
[i
]));
1713 AddPrinterFilter(p
, ppd
->filters
[i
]);
1716 if (ppd
->num_filters
== 0)
1719 * If there are no filters, add a PostScript printing filter.
1722 AddPrinterFilter(p
, "application/vnd.cups-postscript 0 -");
1726 * Show current and available port monitors for this printer...
1729 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
, "port-monitor",
1730 NULL
, p
->port_monitor
? p
->port_monitor
: "none");
1733 for (i
= 1, ppdattr
= ppdFindAttr(ppd
, "cupsPortMonitor", NULL
);
1735 i
++, ppdattr
= ppdFindNextAttr(ppd
, "cupsPortMonitor", NULL
));
1739 if (strstr(ppd
->protocols
, "TBCP"))
1741 else if (strstr(ppd
->protocols
, "BCP"))
1745 attr
= ippAddStrings(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_KEYWORD
,
1746 "port-monitor-supported", i
, NULL
, NULL
);
1748 attr
->values
[0].string
.text
= strdup("none");
1750 for (i
= 1, ppdattr
= ppdFindAttr(ppd
, "cupsPortMonitor", NULL
);
1752 i
++, ppdattr
= ppdFindNextAttr(ppd
, "cupsPortMonitor", NULL
))
1753 attr
->values
[i
].string
.text
= strdup(ppdattr
->value
);
1757 if (strstr(ppd
->protocols
, "TBCP"))
1758 attr
->values
[i
].string
.text
= strdup("tbcp");
1759 else if (strstr(ppd
->protocols
, "BCP"))
1760 attr
->values
[i
].string
.text
= strdup("bcp");
1764 * Close the PPD and set the type...
1769 printer_type
= p
->type
;
1771 else if (!access(filename
, 0))
1773 int pline
; /* PPD line number */
1774 ppd_status_t pstatus
; /* PPD load status */
1777 pstatus
= ppdLastError(&pline
);
1779 LogMessage(L_ERROR
, "PPD file for %s cannot be loaded!", p
->name
);
1781 if (pstatus
<= PPD_ALLOC_ERROR
)
1782 LogMessage(L_ERROR
, "%s", strerror(errno
));
1784 LogMessage(L_ERROR
, "%s on line %d.", ppdErrorString(pstatus
),
1787 LogMessage(L_INFO
, "Hint: Run \"cupstestppd %s\" and fix any errors.",
1791 * Add a filter from application/vnd.cups-raw to printer/name to
1792 * handle "raw" printing by users.
1795 AddPrinterFilter(p
, "application/vnd.cups-raw 0 -");
1798 * Add a PostScript filter, since this is still possibly PS printer.
1801 AddPrinterFilter(p
, "application/vnd.cups-postscript 0 -");
1806 * If we have an interface script, add a filter entry for it...
1809 snprintf(filename
, sizeof(filename
), "%s/interfaces/%s", ServerRoot
,
1811 if (access(filename
, X_OK
) == 0)
1814 * Yes, we have a System V style interface script; use it!
1817 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1818 "printer-make-and-model", NULL
, "Local System V Printer");
1820 snprintf(filename
, sizeof(filename
), "*/* 0 %s/interfaces/%s",
1821 ServerRoot
, p
->name
);
1822 AddPrinterFilter(p
, filename
);
1824 else if (p
->device_uri
&&
1825 !strncmp(p
->device_uri
, "ipp://", 6) &&
1826 (strstr(p
->device_uri
, "/printers/") != NULL
||
1827 strstr(p
->device_uri
, "/classes/") != NULL
))
1830 * Tell the client this is really a hard-wired remote printer.
1833 printer_type
|= CUPS_PRINTER_REMOTE
;
1836 * Point the printer-uri-supported attribute to the
1840 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
1841 "printer-uri-supported", NULL
, p
->device_uri
);
1844 * Then set the make-and-model accordingly...
1847 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1848 "printer-make-and-model", NULL
, "Remote Printer");
1851 * Print all files directly...
1859 * Otherwise we have neither - treat this as a "dumb" printer
1860 * with no PPD file...
1863 ippAddString(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
,
1864 "printer-make-and-model", NULL
, "Local Raw Printer");
1870 ippAddIntegers(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
1871 "finishings-supported", num_finishings
, (int *)finishings
);
1872 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
,
1873 "finishings-default", IPP_FINISHINGS_NONE
);
1878 * Add the CUPS-specific printer-type attribute...
1882 p
->type
|= CUPS_PRINTER_NOT_SHARED
;
1884 p
->type
&= ~CUPS_PRINTER_NOT_SHARED
;
1886 ippAddInteger(p
->attrs
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-type",
1889 DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p
->name
,
1894 * Write the IRIX printer config and status files...
1897 write_irix_config(p
);
1898 write_irix_state(p
);
1904 * 'SetPrinterReasons()' - Set/update the reasons strings.
1908 SetPrinterReasons(printer_t
*p
, /* I - Printer */
1909 const char *s
) /* I - Reasons strings */
1911 int i
; /* Looping var */
1912 const char *sptr
; /* Pointer into reasons */
1913 char reason
[255], /* Reason string */
1914 *rptr
; /* Pointer into reason */
1917 if (s
[0] == '-' || s
[0] == '+')
1920 * Add/remove reasons...
1928 * Replace reasons...
1933 for (i
= 0; i
< p
->num_reasons
; i
++)
1934 free(p
->reasons
[i
]);
1940 * Loop through all of the reasons...
1946 * Skip leading whitespace and commas...
1949 while (isspace(*sptr
& 255) || *sptr
== ',')
1952 for (rptr
= reason
; *sptr
&& !isspace(*sptr
& 255) && *sptr
!= ','; sptr
++)
1953 if (rptr
< (reason
+ sizeof(reason
) - 1))
1967 for (i
= 0; i
< p
->num_reasons
; i
++)
1968 if (!strcasecmp(reason
, p
->reasons
[i
]))
1971 * Found a match, so remove it...
1975 free(p
->reasons
[i
]);
1977 if (i
< p
->num_reasons
)
1978 memmove(p
->reasons
+ i
, p
->reasons
+ i
+ 1,
1979 (p
->num_reasons
- i
) * sizeof(char *));
1984 else if (p
->num_reasons
< (int)(sizeof(p
->reasons
) / sizeof(p
->reasons
[0])))
1990 for (i
= 0; i
< p
->num_reasons
; i
++)
1991 if (!strcasecmp(reason
, p
->reasons
[i
]))
1994 if (i
>= p
->num_reasons
)
1996 p
->reasons
[i
] = strdup(reason
);
2005 * 'SetPrinterState()' - Update the current state of a printer.
2009 SetPrinterState(printer_t
*p
, /* I - Printer to change */
2010 ipp_pstate_t s
, /* I - New state */
2011 int update
) /* I - Update printers.conf? */
2013 ipp_pstate_t old_state
; /* Old printer state */
2017 * Can't set status of remote printers...
2020 if (p
->type
& CUPS_PRINTER_REMOTE
)
2024 * Set the new state...
2027 old_state
= p
->state
;
2033 * Let the browse code know this needs to be updated...
2037 p
->state_time
= time(NULL
);
2041 write_irix_state(p
);
2045 AddPrinterHistory(p
);
2048 * Save the printer configuration if a printer goes from idle or processing
2049 * to stopped (or visa-versa)...
2052 if ((old_state
== IPP_PRINTER_STOPPED
) != (s
== IPP_PRINTER_STOPPED
) &&
2055 if (p
->type
& CUPS_PRINTER_CLASS
)
2064 * 'SortPrinters()' - Sort the printer list when a printer name is changed.
2070 printer_t
*current
, /* Current printer */
2071 *prev
, /* Previous printer */
2072 *next
; /* Next printer */
2073 int did_swap
; /* Non-zero if we did a swap */
2078 for (did_swap
= 0, current
= Printers
, prev
= NULL
; current
!= NULL
;)
2079 if (current
->next
== NULL
)
2081 else if (strcasecmp(current
->name
, current
->next
->name
) > 0)
2083 DEBUG_printf(("Swapping %s and %s...\n", current
->name
,
2084 current
->next
->name
));
2087 * Need to swap these two printers...
2093 Printers
= current
->next
;
2095 prev
->next
= current
->next
;
2098 * Yes, we can all get a headache from the next bunch of pointer
2102 next
= current
->next
;
2103 current
->next
= next
->next
;
2104 next
->next
= current
;
2110 current
= current
->next
;
2118 * 'StopPrinter()' - Stop a printer from printing any jobs...
2122 StopPrinter(printer_t
*p
, /* I - Printer to stop */
2123 int update
) /* I - Update printers.conf? */
2125 job_t
*job
; /* Active print job */
2129 * Set the printer state...
2132 SetPrinterState(p
, IPP_PRINTER_STOPPED
, update
);
2135 * See if we have a job printing on this printer...
2141 * Get pointer to job...
2144 job
= (job_t
*)p
->job
;
2150 StopJob(job
->id
, 0);
2153 * Reset the state to pending...
2156 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
2164 * 'ValidateDest()' - Validate a printer/class destination.
2167 const char * /* O - Printer or class name */
2168 ValidateDest(const char *hostname
, /* I - Host name */
2169 const char *resource
, /* I - Resource name */
2170 cups_ptype_t
*dtype
, /* O - Type (printer or class) */
2171 printer_t
**printer
) /* O - Printer pointer */
2173 printer_t
*p
; /* Current printer */
2174 char localname
[1024], /* Localized hostname */
2175 *lptr
, /* Pointer into localized hostname */
2176 *sptr
; /* Pointer into server name */
2179 DEBUG_printf(("ValidateDest(\"%s\", \"%s\", %p, %p)\n", hostname
, resource
,
2183 * Initialize return values...
2189 *dtype
= (cups_ptype_t
)0;
2192 * See if the resource is a class or printer...
2195 if (!strncmp(resource
, "/classes/", 9))
2203 else if (!strncmp(resource
, "/printers/", 10))
2214 * Bad resource name...
2221 * See if the printer or class name exists...
2224 if ((p
= FindPrinter(resource
)) == NULL
)
2225 p
= FindClass(resource
);
2227 if (p
== NULL
&& strchr(resource
, '@') == NULL
)
2234 *dtype
= p
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
|
2235 CUPS_PRINTER_REMOTE
);
2240 * Change localhost to the server name...
2243 if (!strcasecmp(hostname
, "localhost"))
2244 hostname
= ServerName
;
2246 strlcpy(localname
, hostname
, sizeof(localname
));
2248 if (!strcasecmp(hostname
, ServerName
))
2251 * Localize the hostname...
2254 lptr
= strchr(localname
, '.');
2255 sptr
= strchr(ServerName
, '.');
2257 if (sptr
!= NULL
&& lptr
!= NULL
)
2260 * Strip the common domain name components...
2263 while (lptr
!= NULL
)
2265 if (!strcasecmp(lptr
, sptr
))
2271 lptr
= strchr(lptr
+ 1, '.');
2276 DEBUG_printf(("localized hostname is \"%s\"...\n", localname
));
2279 * Find a matching printer or class...
2282 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
2283 if (!strcasecmp(p
->hostname
, localname
) &&
2284 !strcasecmp(p
->name
, resource
))
2289 *dtype
= p
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
|
2290 CUPS_PRINTER_REMOTE
);
2299 * 'WritePrintcap()' - Write a pseudo-printcap file for older applications
2306 cups_file_t
*fp
; /* printcap file */
2307 printer_t
*p
; /* Current printer */
2312 * Update the IRIX printer state for the default printer; if
2313 * no printers remain, then the default printer file will be
2317 write_irix_state(DefaultPrinter
);
2321 * See if we have a printcap file; if not, don't bother writing it.
2324 if (!Printcap
|| !*Printcap
)
2328 * Open the printcap file...
2331 if ((fp
= cupsFileOpen(Printcap
, "w")) == NULL
)
2335 * Put a comment header at the top so that users will know where the
2336 * data has come from...
2339 cupsFilePuts(fp
, "# This file was automatically generated by cupsd(8) from the\n");
2340 cupsFilePrintf(fp
, "# %s/printers.conf file. All changes to this file\n",
2342 cupsFilePuts(fp
, "# will be lost.\n");
2345 * Write a new printcap with the current list of printers.
2348 switch (PrintcapFormat
)
2352 * Each printer is put in the file as:
2362 cupsFilePrintf(fp
, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter
->name
,
2363 DefaultPrinter
->info
, ServerName
, DefaultPrinter
->name
);
2365 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
2366 if (p
!= DefaultPrinter
)
2367 cupsFilePrintf(fp
, "%s|%s:rm=%s:rp=%s:\n", p
->name
, p
->info
,
2368 ServerName
, p
->name
);
2371 case PRINTCAP_SOLARIS
:
2373 * Each printer is put in the file as:
2375 * _all:all=Printer1,Printer2,Printer3,...,PrinterN
2376 * _default:use=DefaultPrinter
2378 * :bsdaddr=ServerName,Printer1:\
2379 * :description=Description:
2381 * :bsdaddr=ServerName,Printer2:\
2382 * :description=Description:
2384 * :bsdaddr=ServerName,Printer3:\
2385 * :description=Description:
2388 * :bsdaddr=ServerName,PrinterN:\
2389 * :description=Description:
2392 cupsFilePuts(fp
, "_all:all=");
2393 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
2394 cupsFilePrintf(fp
, "%s%c", p
->name
, p
->next
? ',' : '\n');
2397 cupsFilePrintf(fp
, "_default:use=%s\n", DefaultPrinter
->name
);
2399 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
2400 cupsFilePrintf(fp
, "%s:\\\n"
2401 "\t:bsdaddr=%s,%s:\\\n"
2402 "\t:description=%s:\n",
2403 p
->name
, ServerName
, p
->name
, p
->info
? p
->info
: "");
2416 * 'cupsdSanitizeURI()' - Sanitize a device URI...
2419 char * /* O - New device URI */
2420 cupsdSanitizeURI(const char *uri
, /* I - Original device URI */
2421 char *buffer
, /* O - New device URI */
2422 int buflen
) /* I - Size of new device URI buffer */
2424 char *start
, /* Start of data after scheme */
2425 *slash
, /* First slash after scheme:// */
2426 *ptr
; /* Pointer into user@host:port part */
2430 * Range check input...
2433 if (!uri
|| !buffer
|| buflen
< 2)
2437 * Copy the device URI to the new buffer...
2440 strlcpy(buffer
, uri
, buflen
);
2443 * Find the end of the scheme:// part...
2446 if ((ptr
= strchr(buffer
, ':')) == NULL
)
2447 return (buffer
); /* No scheme: part... */
2449 for (start
= ptr
+ 1; *start
; start
++)
2454 * Find the next slash (/) in the URI...
2457 if ((slash
= strchr(start
, '/')) == NULL
)
2458 slash
= start
+ strlen(start
); /* No slash, point to the end */
2461 * Check for an @ sign before the slash...
2464 if ((ptr
= strchr(start
, '@')) != NULL
&& ptr
< slash
)
2467 * Found an @ sign and it is before the resource part, so we have
2468 * an authentication string. Copy the remaining URI over the
2469 * authentication string...
2472 cups_strcpy(start
, ptr
+ 1);
2476 * Return the new device URI...
2485 * 'write_irix_config()' - Update the config files used by the IRIX
2490 write_irix_config(printer_t
*p
) /* I - Printer to update */
2492 char filename
[1024]; /* Interface script filename */
2493 cups_file_t
*fp
; /* Interface script file */
2494 int tag
; /* Status tag value */
2499 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
2500 * tools. First the interface script that tells the tools what kind of
2501 * printer we have...
2504 snprintf(filename
, sizeof(filename
), "/var/spool/lp/interface/%s", p
->name
);
2506 if (p
->type
& CUPS_PRINTER_CLASS
)
2508 else if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
2510 cupsFilePuts(fp
, "#!/bin/sh\n");
2512 if ((attr
= ippFindAttribute(p
->attrs
, "printer-make-and-model",
2513 IPP_TAG_TEXT
)) != NULL
)
2514 cupsFilePrintf(fp
, "NAME=\"%s\"\n", attr
->values
[0].string
.text
);
2515 else if (p
->type
& CUPS_PRINTER_CLASS
)
2516 cupsFilePuts(fp
, "NAME=\"Printer Class\"\n");
2518 cupsFilePuts(fp
, "NAME=\"Remote Destination\"\n");
2520 if (p
->type
& CUPS_PRINTER_COLOR
)
2521 cupsFilePuts(fp
, "TYPE=ColorPostScript\n");
2523 cupsFilePuts(fp
, "TYPE=MonoPostScript\n");
2525 cupsFilePrintf(fp
, "HOSTNAME=%s\n", ServerName
);
2526 cupsFilePrintf(fp
, "HOSTPRINTER=%s\n", p
->name
);
2530 chmod(filename
, 0755);
2531 chown(filename
, User
, Group
);
2535 * Then the member file that tells which device file the queue is connected
2536 * to... Networked printers use "/dev/null" in this file, so that's what
2537 * we use (the actual device URI can confuse some apps...)
2540 snprintf(filename
, sizeof(filename
), "/var/spool/lp/member/%s", p
->name
);
2542 if (p
->type
& CUPS_PRINTER_CLASS
)
2544 else if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
2546 cupsFilePuts(fp
, "/dev/null\n");
2550 chmod(filename
, 0644);
2551 chown(filename
, User
, Group
);
2555 * The gui_interface file is a script or program that launches a GUI
2556 * option panel for the printer, using options specified on the
2557 * command-line in the third argument. The option panel must send
2558 * any printing options to stdout on a single line when the user
2559 * accepts them, or nothing if the user cancels the dialog.
2561 * The default options panel program is /usr/bin/glpoptions, from
2562 * the ESP Print Pro software. You can select another using the
2563 * PrintcapGUI option.
2566 snprintf(filename
, sizeof(filename
), "/var/spool/lp/gui_interface/ELF/%s.gui", p
->name
);
2568 if (p
->type
& CUPS_PRINTER_CLASS
)
2570 else if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
2572 cupsFilePuts(fp
, "#!/bin/sh\n");
2573 cupsFilePrintf(fp
, "%s -d %s -o \"$3\"\n", PrintcapGUI
, p
->name
);
2577 chmod(filename
, 0755);
2578 chown(filename
, User
, Group
);
2582 * The POD config file is needed by the printstatus command to show
2583 * the printer location and device.
2586 snprintf(filename
, sizeof(filename
), "/var/spool/lp/pod/%s.config", p
->name
);
2588 if (p
->type
& CUPS_PRINTER_CLASS
)
2590 else if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
2592 cupsFilePrintf(fp
, "Printer Class | %s\n",
2593 (p
->type
& CUPS_PRINTER_COLOR
) ? "ColorPostScript" : "MonoPostScript");
2594 cupsFilePrintf(fp
, "Printer Model | %s\n", p
->make_model
? p
->make_model
: "");
2595 cupsFilePrintf(fp
, "Location Code | %s\n", p
->location
? p
->location
: "");
2596 cupsFilePrintf(fp
, "Physical Location | %s\n", p
->info
? p
->info
: "");
2597 cupsFilePrintf(fp
, "Port Path | %s\n", p
->device_uri
? p
->device_uri
: "");
2598 cupsFilePrintf(fp
, "Config Path | /var/spool/lp/pod/%s.config\n", p
->name
);
2599 cupsFilePrintf(fp
, "Active Status Path | /var/spool/lp/pod/%s.status\n", p
->name
);
2600 cupsFilePuts(fp
, "Status Update Wait | 10 seconds\n");
2604 chmod(filename
, 0664);
2605 chown(filename
, User
, Group
);
2611 * 'write_irix_state()' - Update the status files used by IRIX printing
2616 write_irix_state(printer_t
*p
) /* I - Printer to update */
2618 char filename
[1024]; /* Interface script filename */
2619 cups_file_t
*fp
; /* Interface script file */
2620 int tag
; /* Status tag value */
2626 * The POD status file is needed for the printstatus window to
2627 * provide the current status of the printer.
2630 snprintf(filename
, sizeof(filename
), "/var/spool/lp/pod/%s.status", p
->name
);
2632 if (p
->type
& CUPS_PRINTER_CLASS
)
2634 else if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
2636 cupsFilePrintf(fp
, "Operational Status | %s\n",
2637 (p
->state
== IPP_PRINTER_IDLE
) ? "Idle" :
2638 (p
->state
== IPP_PRINTER_PROCESSING
) ? "Busy" :
2640 cupsFilePrintf(fp
, "Information | 01 00 00 | %s\n", CUPS_SVERSION
);
2641 cupsFilePrintf(fp
, "Information | 02 00 00 | Device URI: %s\n",
2642 p
->device_uri
? p
->device_uri
: "");
2643 cupsFilePrintf(fp
, "Information | 03 00 00 | %s jobs\n",
2644 p
->accepting
? "Accepting" : "Not accepting");
2645 cupsFilePrintf(fp
, "Information | 04 00 00 | %s\n", p
->state_message
);
2649 chmod(filename
, 0664);
2650 chown(filename
, User
, Group
);
2654 * The activeicons file is needed to provide desktop icons for printers:
2656 * [ quoted from /usr/lib/print/tagit ]
2658 * --- Type of printer tags (base values)
2660 * Dumb=66048 # 0x10200
2661 * DumbColor=66080 # 0x10220
2662 * Raster=66112 # 0x10240
2663 * ColorRaster=66144 # 0x10260
2664 * Plotter=66176 # 0x10280
2665 * PostScript=66208 # 0x102A0
2666 * ColorPostScript=66240 # 0x102C0
2667 * MonoPostScript=66272 # 0x102E0
2669 * --- Printer state modifiers for local printers
2674 * Unknown=3 # 0x3 (Faulted due to unknown reason)
2676 * --- Printer state modifiers for network printers
2680 * NetFaulted=10 # 0xA
2681 * NetUnknown=11 # 0xB (Faulted due to unknown reason)
2684 snprintf(filename
, sizeof(filename
), "/var/spool/lp/activeicons/%s", p
->name
);
2686 if (p
->type
& CUPS_PRINTER_CLASS
)
2688 else if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
2690 if (p
->type
& CUPS_PRINTER_COLOR
)
2695 if (p
->type
& CUPS_PRINTER_REMOTE
)
2698 if (p
->state
== IPP_PRINTER_PROCESSING
)
2701 else if (p
->state
== IPP_PRINTER_STOPPED
)
2704 cupsFilePuts(fp
, "#!/bin/sh\n");
2705 cupsFilePrintf(fp
, "#Tag %d\n", tag
);
2709 chmod(filename
, 0755);
2710 chown(filename
, User
, Group
);
2715 * The default file is needed by the printers window to show
2716 * the default printer.
2719 snprintf(filename
, sizeof(filename
), "/var/spool/lp/default");
2721 if (DefaultPrinter
!= NULL
)
2723 if ((fp
= cupsFileOpen(filename
, "w")) != NULL
)
2725 cupsFilePrintf(fp
, "%s\n", DefaultPrinter
->name
);
2729 chmod(filename
, 0644);
2730 chown(filename
, User
, Group
);