2 * Administration CGI for CUPS.
4 * Copyright © 2021-2025 by OpenPrinting
5 * Copyright © 2007-2021 by Apple Inc.
6 * Copyright © 1997-2007 by Easy Software Products.
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 #include "cgi-private.h"
13 #include <cups/http-private.h>
14 #include <cups/ppd-private.h>
15 #include <cups/adminutil.h>
28 static int current_device
= 0; /* Current device shown */
35 static void choose_device_cb(const char *device_class
, const char *device_id
, const char *device_info
, const char *device_make_and_model
, const char *device_uri
, const char *device_location
, const char *title
);
36 static void do_am_class(http_t
*http
, int modify
);
37 static void do_am_printer(http_t
*http
, int modify
);
38 static void do_config_server(http_t
*http
);
39 static void do_delete_class(http_t
*http
);
40 static void do_delete_printer(http_t
*http
);
41 static void do_list_printers(http_t
*http
);
42 static void do_menu(http_t
*http
);
43 static void do_set_allowed_users(http_t
*http
);
44 static void do_set_default(http_t
*http
);
45 static void do_set_options(http_t
*http
, int is_class
);
46 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
47 char *buffer
, size_t bufsize
);
48 static double get_points(double number
, const char *uval
);
52 * 'main()' - Main entry for CGI.
55 int /* O - Exit status */
58 http_t
*http
; /* Connection to the server */
59 const char *op
; /* Operation name */
63 * Connect to the HTTP server...
66 fputs("DEBUG: admin.cgi started...\n", stderr
);
68 if ((http
= httpConnect2(cupsGetServer(), ippGetPort(), /*addrlist*/NULL
, AF_UNSPEC
, cupsGetEncryption(), /*blocking*/1, /*msec*/30000, /*cancel*/NULL
)) == NULL
)
70 fprintf(stderr
, "ERROR: Unable to connect to cupsd: %s\n", cupsGetErrorString());
71 fprintf(stderr
, "DEBUG: cupsGetServer()=\"%s\"\n", cupsGetServer() ? cupsGetServer() : "(null)");
72 fprintf(stderr
, "DEBUG: ippGetPort()=%d\n", ippGetPort());
73 fprintf(stderr
, "DEBUG: cupsGetEncryption()=%d\n", cupsGetEncryption());
78 const char *authorization
; /* HTTP_AUTHORIZATION value */
80 if ((authorization
= getenv("HTTP_AUTHORIZATION")) != NULL
&& !strncmp(authorization
, "Bearer ", 7))
81 httpSetAuthString(http
, "Bearer", authorization
+ 7);
84 fprintf(stderr
, "DEBUG: http=%p\n", (void *)http
);
87 * Set the web interface section...
90 cgiSetVariable("SECTION", "admin");
91 cgiSetVariable("REFRESH_PAGE", "");
94 * See if we have form data...
97 if (!cgiInitialize() || !cgiGetVariable("OP"))
100 * Nope, send the administration menu...
103 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
107 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
110 * Do the operation...
113 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
117 const char *printer
= getenv("PRINTER_NAME"),
118 /* Printer or class name */
119 *server_port
= getenv("SERVER_PORT");
120 /* Port number string */
121 int port
= server_port
? atoi(server_port
) : 0;
123 char uri
[1024]; /* URL */
126 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
127 getenv("HTTPS") ? "https" : "http", NULL
,
128 getenv("SERVER_NAME"), port
, "/%s/%s",
129 cgiGetVariable("IS_CLASS") ? "classes" : "printers",
132 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
133 getenv("HTTPS") ? "https" : "http", NULL
,
134 getenv("SERVER_NAME"), port
, "/admin");
136 printf("Location: %s\n\n", uri
);
138 else if (!strcmp(op
, "set-allowed-users"))
139 do_set_allowed_users(http
);
140 else if (!strcmp(op
, "set-as-default"))
141 do_set_default(http
);
142 else if (!strcmp(op
, "find-new-printers") ||
143 !strcmp(op
, "list-available-printers"))
144 do_list_printers(http
);
145 else if (!strcmp(op
, "add-class"))
146 do_am_class(http
, 0);
147 else if (!strcmp(op
, "add-printer"))
148 do_am_printer(http
, 0);
149 else if (!strcmp(op
, "modify-class"))
150 do_am_class(http
, 1);
151 else if (!strcmp(op
, "modify-printer"))
152 do_am_printer(http
, 1);
153 else if (!strcmp(op
, "delete-class"))
154 do_delete_class(http
);
155 else if (!strcmp(op
, "delete-printer"))
156 do_delete_printer(http
);
157 else if (!strcmp(op
, "set-class-options"))
158 do_set_options(http
, 1);
159 else if (!strcmp(op
, "set-printer-options"))
160 do_set_options(http
, 0);
161 else if (!strcmp(op
, "config-server"))
162 do_config_server(http
);
166 * Bad operation code - display an error...
169 cgiStartHTML(cgiText(_("Administration")));
170 cgiCopyTemplateLang("error-op.tmpl");
174 else if (op
&& !strcmp(op
, "redirect"))
176 const char *url
; /* Redirection URL... */
177 char prefix
[1024]; /* URL prefix */
181 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
182 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
184 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
185 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
187 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
189 if ((url
= cgiGetVariable("URL")) != NULL
)
191 char encoded
[1024], /* Encoded URL string */
192 *ptr
; /* Pointer into encoded string */
199 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
201 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
204 * Percent-encode this character; safe because we have at least 4
205 * bytes left in the array...
208 snprintf(ptr
, sizeof(encoded
) - (size_t)(ptr
- encoded
), "%%%02X", *url
& 255);
220 * URL was too long, just redirect to the admin page...
223 printf("Location: %s/admin\n\n", prefix
);
228 * URL is OK, redirect there...
231 printf("Location: %s%s\n\n", prefix
, encoded
);
235 printf("Location: %s/admin\n\n", prefix
);
240 * Form data but no operation code - display an error...
243 cgiStartHTML(cgiText(_("Administration")));
244 cgiCopyTemplateLang("error-op.tmpl");
249 * Close the HTTP server connection...
255 * Return with no errors...
263 * 'choose_device_cb()' - Add a device to the device selection page.
268 const char *device_class
, /* I - Class */
269 const char *device_id
, /* I - 1284 device ID */
270 const char *device_info
, /* I - Description */
271 const char *device_make_and_model
, /* I - Make and model */
272 const char *device_uri
, /* I - Device URI */
273 const char *device_location
, /* I - Location */
274 const char *title
) /* I - Page title */
277 * For modern browsers, start a multi-part page so we can show that something
278 * is happening. Non-modern browsers just get everything at the end...
281 if (current_device
== 0 && cgiSupportsMultipart())
285 cgiCopyTemplateLang("choose-device.tmpl");
292 * Add the device to the array...
295 cgiSetArray("device_class", current_device
, device_class
);
296 cgiSetArray("device_id", current_device
, device_id
);
297 cgiSetArray("device_info", current_device
, device_info
);
298 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
299 cgiSetArray("device_uri", current_device
, device_uri
);
300 cgiSetArray("device_location", current_device
, device_location
);
307 * 'do_am_class()' - Add or modify a class.
311 do_am_class(http_t
*http
, /* I - HTTP connection */
312 int modify
) /* I - Modify the printer? */
314 int i
, j
; /* Looping vars */
315 int element
; /* Element number */
316 int num_printers
; /* Number of printers */
317 ipp_t
*request
, /* IPP request */
318 *response
; /* IPP response */
319 ipp_attribute_t
*attr
; /* member-uris attribute */
320 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
321 const char *name
, /* Pointer to class name */
322 *op
, /* Operation name */
323 *ptr
; /* Pointer to CGI variable */
324 const char *title
; /* Title of page */
325 static const char * const pattrs
[] = /* Requested printer attributes */
333 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
334 op
= cgiGetVariable("OP");
335 name
= cgiGetTextfield("PRINTER_NAME");
337 if (cgiGetTextfield("PRINTER_LOCATION") == NULL
)
340 * Build a CUPS_GET_PRINTERS request, which requires the
341 * following attributes:
344 * attributes-natural-language
347 request
= ippNewRequest(IPP_OP_CUPS_GET_PRINTERS
);
349 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
351 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
352 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
355 * Do the request and get back a response...
360 cgiSetVariable("OP", op
);
362 cgiSetVariable("PRINTER_NAME", name
);
364 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
367 * Create MEMBER_URIS and MEMBER_NAMES arrays...
370 for (element
= 0, attr
= response
->attrs
;
373 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
375 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
376 (!name
|| _cups_strcasecmp(name
, ptr
+ 1)))
379 * Don't show the current class...
382 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
387 for (element
= 0, attr
= response
->attrs
;
390 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
392 if (!name
|| _cups_strcasecmp(name
, attr
->values
[0].string
.text
))
395 * Don't show the current class...
398 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
403 num_printers
= cgiGetSize("MEMBER_URIS");
413 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
414 * following attributes:
417 * attributes-natural-language
421 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
423 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
424 "localhost", 0, "/classes/%s", name
);
425 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
428 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
429 "requested-attributes",
430 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
434 * Do the request and get back a response...
437 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
439 if ((attr
= ippFindAttribute(response
, "member-names",
440 IPP_TAG_NAME
)) != NULL
)
443 * Mark any current members in the class...
446 for (j
= 0; j
< num_printers
; j
++)
447 cgiSetArray("MEMBER_SELECTED", j
, "");
449 for (i
= 0; i
< attr
->num_values
; i
++)
451 for (j
= 0; j
< num_printers
; j
++)
453 if (!_cups_strcasecmp(attr
->values
[i
].string
.text
,
454 cgiGetArray("MEMBER_NAMES", j
)))
456 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
463 if ((attr
= ippFindAttribute(response
, "printer-info",
464 IPP_TAG_TEXT
)) != NULL
)
465 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
467 if ((attr
= ippFindAttribute(response
, "printer-location",
468 IPP_TAG_TEXT
)) != NULL
)
469 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
475 * Update the location and description of an existing printer...
479 cgiCopyTemplateLang("modify-class.tmpl");
484 * Get the name, location, and description for a new printer...
488 cgiCopyTemplateLang("add-class.tmpl");
499 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
500 cgiCopyTemplateLang("error.tmpl");
505 for (ptr
= name
; *ptr
; ptr
++)
506 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
509 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
511 cgiSetVariable("ERROR",
512 cgiText(_("The class name may only contain up to "
513 "127 printable characters and may not "
514 "contain spaces, slashes (/), or the "
515 "pound sign (#).")));
517 cgiCopyTemplateLang("error.tmpl");
523 * Build a CUPS_ADD_CLASS request, which requires the following
527 * attributes-natural-language
531 * printer-is-accepting-jobs
536 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS
);
538 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
539 "localhost", 0, "/classes/%s", name
);
540 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
543 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
544 NULL
, cgiGetTextfield("PRINTER_LOCATION"));
546 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
547 NULL
, cgiGetTextfield("PRINTER_INFO"));
549 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
551 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
554 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
556 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
557 num_printers
, NULL
, NULL
);
558 for (i
= 0; i
< num_printers
; i
++)
559 ippSetString(request
, &attr
, i
, cgiGetArray("MEMBER_URIS", i
));
563 * Do the request and get back a response...
566 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
568 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
570 puts("Status: 401\n");
573 else if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
576 cgiShowIPPError(modify
? _("Unable to modify class") :
577 _("Unable to add class"));
582 * Redirect successful updates back to the class page...
585 char refresh
[1024]; /* Refresh URL */
587 cgiFormEncode(uri
, name
, sizeof(uri
));
588 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
590 cgiSetVariable("refresh_page", refresh
);
595 cgiCopyTemplateLang("class-modified.tmpl");
597 cgiCopyTemplateLang("class-added.tmpl");
605 * 'do_am_printer()' - Add or modify a printer.
609 do_am_printer(http_t
*http
, /* I - HTTP connection */
610 int modify
) /* I - Modify the printer? */
612 int i
; /* Looping var */
613 ipp_attribute_t
*attr
; /* Current attribute */
614 ipp_t
*request
, /* IPP request */
615 *response
, /* IPP response */
616 *oldinfo
; /* Old printer information */
617 const cgi_file_t
*file
; /* Uploaded file, if any */
618 const char *var
; /* CGI variable */
619 char *ppd_name
= NULL
; /* Pointer to PPD name */
620 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
621 *uriptr
, /* Pointer into URI */
622 evefile
[1024] = ""; /* IPP Everywhere PPD file */
623 int maxrate
; /* Maximum baud rate */
624 char baudrate
[255]; /* Baud rate string */
625 const char *name
, /* Pointer to class name */
626 *ptr
; /* Pointer to CGI variable */
627 const char *title
; /* Title of page */
628 static int baudrates
[] = /* Baud rates */
643 ptr
= cgiGetVariable("DEVICE_URI");
644 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
645 ptr
? ptr
: "(null)");
647 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
652 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
653 * following attributes:
656 * attributes-natural-language
660 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
662 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
663 "localhost", 0, "/printers/%s",
664 cgiGetTextfield("PRINTER_NAME"));
665 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
669 * Do the request and get back a response...
672 oldinfo
= cupsDoRequest(http
, request
, "/");
681 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
682 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
683 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
684 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
687 if ((name
= cgiGetTextfield("PRINTER_NAME")) != NULL
)
689 for (ptr
= name
; *ptr
; ptr
++)
690 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '\\' || *ptr
== '?' || *ptr
== '\'' || *ptr
== '\"' || *ptr
== '#')
693 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
695 cgiSetVariable("ERROR",
696 cgiText(_("The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/ \\), quotes (' \"), question mark (?), or the pound sign (#).")));
698 cgiCopyTemplateLang("error.tmpl");
704 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
706 if ((uriptr
= strrchr(var
, '|')) != NULL
)
709 * Extract make and make/model from device URI string...
712 char make
[1024], /* Make string */
713 *makeptr
; /* Pointer into make */
718 cupsCopyString(make
, uriptr
, sizeof(make
));
720 if ((makeptr
= strchr(make
, ' ')) != NULL
)
722 else if ((makeptr
= strchr(make
, '-')) != NULL
)
724 else if (!_cups_strncasecmp(make
, "laserjet", 8) ||
725 !_cups_strncasecmp(make
, "deskjet", 7) ||
726 !_cups_strncasecmp(make
, "designjet", 9))
727 cupsCopyString(make
, "HP", sizeof(make
));
728 else if (!_cups_strncasecmp(make
, "phaser", 6))
729 cupsCopyString(make
, "Xerox", sizeof(make
));
730 else if (!_cups_strncasecmp(make
, "stylus", 6))
731 cupsCopyString(make
, "Epson", sizeof(make
));
733 cupsCopyString(make
, "Generic", sizeof(make
));
735 if (!cgiGetVariable("CURRENT_MAKE"))
736 cgiSetVariable("CURRENT_MAKE", make
);
738 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
739 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
743 char template[128], /* Template name */
744 *tptr
; /* Pointer into template name */
746 cgiSetVariable("PRINTER_INFO", uriptr
);
748 for (tptr
= template;
749 tptr
< (template + sizeof(template) - 1) && *uriptr
;
751 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
754 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
757 else if (*uriptr
== '?' || *uriptr
== '(')
762 cgiSetVariable("TEMPLATE_NAME", template);
766 * Set DEVICE_URI to the actual device uri, without make and model from
770 cgiSetVariable("DEVICE_URI", var
);
777 * Look for devices so the user can pick something...
780 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
782 cupsCopyString(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
783 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
786 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
787 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
791 * Scan for devices for up to 30 seconds...
794 fputs("DEBUG: Getting list of devices...\n", stderr
);
797 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
798 (cups_device_cb_t
)choose_device_cb
,
799 (void *)title
) == IPP_STATUS_OK
)
801 fputs("DEBUG: Got device list!\n", stderr
);
803 if (cgiSupportsMultipart())
806 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
808 cgiCopyTemplateLang("choose-device.tmpl");
811 if (cgiSupportsMultipart())
817 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
818 cupsGetError(), cupsGetErrorString());
819 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
821 puts("Status: 401\n");
827 cgiShowIPPError(modify
? _("Unable to modify printer") :
828 _("Unable to add printer"));
834 else if (!strchr(var
, '/') ||
835 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
837 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
840 * Set the current device URI for the form to the old one...
843 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
844 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
848 * User needs to set the full URI...
852 cgiCopyTemplateLang("choose-uri.tmpl");
855 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
858 * Need baud rate, parity, etc.
861 if ((var
= strchr(var
, '?')) != NULL
&&
862 strncmp(var
, "?baud=", 6) == 0)
863 maxrate
= atoi(var
+ 6);
867 for (i
= 0; i
< (int)(sizeof(baudrates
)/sizeof(baudrates
[0])); i
++)
868 if (baudrates
[i
] > maxrate
)
872 snprintf(baudrate
, sizeof(baudrate
), "%d", baudrates
[i
]);
873 cgiSetArray("BAUDRATES", i
, baudrate
);
877 cgiCopyTemplateLang("choose-serial.tmpl");
880 else if (!name
|| !cgiGetTextfield("PRINTER_LOCATION"))
887 * Update the location and description of an existing printer...
892 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
893 IPP_TAG_TEXT
)) != NULL
)
894 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
896 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
897 IPP_TAG_TEXT
)) != NULL
)
898 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
900 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
901 IPP_TAG_BOOLEAN
)) != NULL
)
902 cgiSetVariable("PRINTER_IS_SHARED",
903 attr
->values
[0].boolean
? "1" : "0");
906 cgiCopyTemplateLang("modify-printer.tmpl");
911 * Get the name, location, and description for a new printer...
915 if (!strncmp(var
, "usb:", 4))
916 cgiSetVariable("PRINTER_IS_SHARED", "1");
918 #endif /* __APPLE__ */
919 cgiSetVariable("PRINTER_IS_SHARED", "0");
921 cgiCopyTemplateLang("add-printer.tmpl");
932 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
934 int ipp_everywhere
= !strncmp(var
, "ipp://", 6) || !strncmp(var
, "ipps://", 7) || (!strncmp(var
, "dnssd://", 8) && (strstr(var
, "_ipp._tcp") || strstr(var
, "_ipps._tcp")));
936 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
939 * Get the PPD file...
942 int fd
; /* PPD file */
943 char filename
[1024]; /* PPD filename */
944 ppd_file_t
*ppd
; /* PPD information */
946 if ((fd
= cupsCreateTempFd(NULL
, NULL
, filename
, sizeof(filename
))) < 0)
948 fprintf(stderr
, "ERROR: Unable to create temporary file: %s\n",
953 close(fd
); // Close the temp fd since cupsGetFile will reopen it
955 if (cupsGetFile(http
, uri
, filename
) != HTTP_STATUS_OK
)
957 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %s\n",
958 uri
, cupsGetErrorString());
960 else if ((ppd
= ppdOpenFile(filename
)) != NULL
)
962 if (ppd
->manufacturer
)
963 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
966 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
973 int linenum
; /* Line number */
975 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
976 filename
, ppdErrorString(ppdLastError(&linenum
)));
982 * Build a CUPS_GET_PPDS request, which requires the following
986 * attributes-natural-language
990 request
= ippNewRequest(IPP_OP_CUPS_GET_PPDS
);
992 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
993 NULL
, "ipp://localhost/printers/");
995 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
996 var
= cgiGetVariable("CURRENT_MAKE");
997 if (var
&& !cgiGetVariable("SELECT_MAKE"))
999 const char *make_model
; /* Make and model */
1002 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1003 "ppd-make", NULL
, var
);
1005 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1006 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1007 "ppd-make-and-model", NULL
, make_model
);
1010 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1011 "requested-attributes", NULL
, "ppd-make");
1014 * Do the request and get back a response...
1017 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1020 * Got the list of PPDs, see if the user has selected a make...
1023 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1026 * No PPD files with this make, try again with all makes...
1029 ippDelete(response
);
1031 request
= ippNewRequest(IPP_OP_CUPS_GET_PPDS
);
1033 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1034 NULL
, "ipp://localhost/printers/");
1036 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1037 "requested-attributes", NULL
, "ppd-make");
1039 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1040 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1042 cgiStartHTML(title
);
1043 cgiCopyTemplateLang("choose-make.tmpl");
1046 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1048 cgiStartHTML(title
);
1049 cgiCopyTemplateLang("choose-make.tmpl");
1055 * Let the user choose a model...
1058 cgiStartHTML(title
);
1059 if (!cgiGetVariable("PPD_MAKE"))
1060 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1062 cgiSetVariable("SHOW_IPP_EVERYWHERE", "1");
1063 cgiCopyTemplateLang("choose-model.tmpl");
1067 ippDelete(response
);
1071 cgiStartHTML(title
);
1072 cgiShowIPPError(_("Unable to get list of printer drivers"));
1073 cgiCopyTemplateLang("error.tmpl");
1080 * Build a CUPS_ADD_PRINTER request, which requires the following
1083 * attributes-charset
1084 * attributes-natural-language
1090 * printer-is-accepting-jobs
1095 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER
);
1097 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1098 "localhost", 0, "/printers/%s",
1099 cgiGetTextfield("PRINTER_NAME"));
1100 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1105 ppd_name
= cgiGetVariable("PPD_NAME");
1106 if (strcmp(ppd_name
, "__no_change__"))
1107 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name",
1111 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1112 NULL
, cgiGetTextfield("PRINTER_LOCATION"));
1114 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1115 NULL
, cgiGetTextfield("PRINTER_INFO"));
1117 cupsCopyString(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1120 * Strip make and model from URI...
1123 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1126 if (!strncmp(uri
, "serial:", 7))
1129 * Update serial port URI to include baud rate, etc.
1132 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1133 uriptr
= uri
+ strlen(uri
);
1135 snprintf(uriptr
, sizeof(uri
) - (size_t)(uriptr
- uri
),
1136 "?baud=%s+bits=%s+parity=%s+flow=%s",
1137 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1138 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1141 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1144 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1146 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared", (char)cgiGetCheckbox("PRINTER_IS_SHARED"));
1148 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1152 * Do the request and get back a response...
1156 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1157 else if (evefile
[0])
1159 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", evefile
));
1163 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1165 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
1167 puts("Status: 401\n");
1170 else if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
1172 cgiStartHTML(title
);
1173 cgiShowIPPError(modify
? _("Unable to modify printer") :
1174 _("Unable to add printer"));
1179 * Redirect successful updates back to the printer page...
1182 char refresh
[1024]; /* Refresh URL */
1185 cgiFormEncode(uri
, name
, sizeof(uri
));
1187 snprintf(refresh
, sizeof(refresh
),
1188 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1190 cgiSetVariable("refresh_page", refresh
);
1192 cgiStartHTML(title
);
1194 cgiCopyTemplateLang("printer-modified.tmpl");
1196 else if (ppd_name
&& (strcmp(ppd_name
, "everywhere") == 0 || strstr(ppd_name
, "driverless")))
1199 * Set the printer options...
1202 cgiSetVariable("OP", "set-printer-options");
1203 do_set_options(http
, 0);
1209 * If we don't have an everywhere model, show printer-added
1210 * template with warning about drivers going away...
1213 cgiStartHTML(title
);
1214 cgiCopyTemplateLang("printer-added.tmpl");
1226 * 'do_config_server()' - Configure server settings.
1230 do_config_server(http_t
*http
) /* I - HTTP connection */
1232 if (cgiGetVariable("CHANGESETTINGS"))
1235 * Save basic setting changes...
1238 int num_settings
; /* Number of server settings */
1239 cups_option_t
*settings
; /* Server settings */
1240 int advanced
, /* Advanced settings shown? */
1241 changed
; /* Have settings changed? */
1242 const char *debug_logging
, /* DEBUG_LOGGING value */
1243 *preserve_jobs
= NULL
,
1244 /* PRESERVE_JOBS value */
1245 *remote_admin
, /* REMOTE_ADMIN value */
1246 *remote_any
, /* REMOTE_ANY value */
1247 *share_printers
,/* SHARE_PRINTERS value */
1249 /* USER_CANCEL_ANY value */
1250 *browse_web_if
= NULL
,
1251 /* BrowseWebIF value */
1252 *preserve_job_history
= NULL
,
1253 /* PreserveJobHistory value */
1254 *preserve_job_files
= NULL
,
1255 /* PreserveJobFiles value */
1256 *max_clients
= NULL
,
1257 /* MaxClients value */
1260 *max_log_size
= NULL
;
1261 /* MaxLogSize value */
1262 const char *current_browse_web_if
,
1263 /* BrowseWebIF value */
1264 *current_preserve_job_history
,
1265 /* PreserveJobHistory value */
1266 *current_preserve_job_files
,
1267 /* PreserveJobFiles value */
1268 *current_max_clients
,
1269 /* MaxClients value */
1272 *current_max_log_size
;
1273 /* MaxLogSize value */
1275 char default_auth_type
[255];
1276 /* DefaultAuthType value */
1277 const char *val
; /* Setting value */
1278 #endif /* HAVE_GSSAPI */
1282 * Get the checkbox values from the form...
1285 debug_logging
= cgiGetCheckbox("DEBUG_LOGGING") ? "1" : "0";
1286 remote_admin
= cgiGetCheckbox("REMOTE_ADMIN") ? "1" : "0";
1287 remote_any
= cgiGetCheckbox("REMOTE_ANY") ? "1" : "0";
1288 share_printers
= cgiGetCheckbox("SHARE_PRINTERS") ? "1" : "0";
1289 user_cancel_any
= cgiGetCheckbox("USER_CANCEL_ANY") ? "1" : "0";
1291 advanced
= cgiGetCheckbox("ADVANCEDSETTINGS");
1295 * Get advanced settings...
1298 browse_web_if
= cgiGetCheckbox("BROWSE_WEB_IF") ? "Yes" : "No";
1299 max_clients
= cgiGetTextfield("MAX_CLIENTS");
1300 max_log_size
= cgiGetTextfield("MAX_LOG_SIZE");
1301 preserve_jobs
= cgiGetCheckbox("PRESERVE_JOBS") ? "1" : "0";
1303 if (atoi(preserve_jobs
))
1305 max_jobs
= cgiGetTextfield("MAX_JOBS");
1306 preserve_job_history
= cgiGetTextfield("PRESERVE_JOB_HISTORY");
1307 preserve_job_files
= cgiGetTextfield("PRESERVE_JOB_FILES");
1309 if (!max_jobs
|| atoi(max_jobs
) < 0)
1312 if (!preserve_job_history
|| !preserve_job_history
[0] ||
1313 (strcasecmp(preserve_job_history
, "yes") && strcasecmp(preserve_job_history
, "no") && !atoi(preserve_job_history
)))
1314 preserve_job_history
= "Yes";
1316 if (!preserve_job_files
|| !preserve_job_files
[0] ||
1317 (strcasecmp(preserve_job_files
, "yes") && strcasecmp(preserve_job_files
, "no") && !atoi(preserve_job_files
)))
1318 preserve_job_files
= "1d";
1323 preserve_job_history
= "No";
1324 preserve_job_files
= "No";
1327 if (!max_clients
|| atoi(max_clients
) <= 0)
1328 max_clients
= "100";
1330 if (!max_log_size
|| atoi(max_log_size
) <= 0.0)
1331 max_log_size
= "1m";
1335 * Get the current server settings...
1338 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1340 cgiStartHTML(cgiText(_("Change Settings")));
1341 cgiSetVariable("MESSAGE",
1342 cgiText(_("Unable to change server settings")));
1343 cgiSetVariable("ERROR", cupsGetErrorString());
1344 cgiCopyTemplateLang("error.tmpl");
1351 * Get authentication settings...
1354 if (cgiGetCheckbox("KERBEROS"))
1356 cupsCopyString(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1360 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1362 if (!val
|| !_cups_strcasecmp(val
, "Negotiate"))
1363 cupsCopyString(default_auth_type
, "Basic", sizeof(default_auth_type
));
1365 cupsCopyString(default_auth_type
, val
, sizeof(default_auth_type
));
1368 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1369 #endif /* HAVE_GSSAPI */
1371 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1373 current_browse_web_if
= "No";
1375 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1378 current_preserve_job_history
= "Yes";
1380 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1383 current_preserve_job_files
= "1d";
1385 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1387 current_max_clients
= "100";
1389 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1391 current_max_jobs
= "500";
1393 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1395 current_max_log_size
= "1m";
1398 * See if the settings have changed...
1401 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1402 num_settings
, settings
)) ||
1403 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1404 num_settings
, settings
)) ||
1405 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1406 num_settings
, settings
)) ||
1407 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1408 num_settings
, settings
)) ||
1410 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1411 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1412 num_settings
, settings
)) ||
1413 #endif /* HAVE_GSSAPI */
1414 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1415 num_settings
, settings
));
1417 if (advanced
&& !changed
)
1418 changed
= _cups_strcasecmp(browse_web_if
, current_browse_web_if
) ||
1419 _cups_strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1420 _cups_strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1421 _cups_strcasecmp(max_clients
, current_max_clients
) ||
1422 _cups_strcasecmp(max_jobs
, current_max_jobs
) ||
1423 _cups_strcasecmp(max_log_size
, current_max_log_size
);
1428 * Settings *have* changed, so save the changes...
1431 int num_newsettings
;/* New number of server settings */
1432 cups_option_t
*newsettings
; /* New server settings */
1434 num_newsettings
= 0;
1435 num_newsettings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
, debug_logging
, num_newsettings
, &newsettings
);
1436 num_newsettings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
, remote_admin
, num_newsettings
, &newsettings
);
1437 num_newsettings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
, remote_any
, num_newsettings
, &newsettings
);
1438 num_newsettings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
, share_printers
, num_newsettings
, &newsettings
);
1439 num_newsettings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
, user_cancel_any
, num_newsettings
, &newsettings
);
1441 num_newsettings
= cupsAddOption("DefaultAuthType", default_auth_type
, num_newsettings
, &newsettings
);
1442 #endif /* HAVE_GSSAPI */
1447 * Add advanced newsettings...
1450 if (_cups_strcasecmp(browse_web_if
, current_browse_web_if
))
1451 num_newsettings
= cupsAddOption("BrowseWebIF", browse_web_if
, num_newsettings
, &newsettings
);
1452 if (_cups_strcasecmp(preserve_job_history
, current_preserve_job_history
))
1453 num_newsettings
= cupsAddOption("PreserveJobHistory", preserve_job_history
, num_newsettings
, &newsettings
);
1454 if (_cups_strcasecmp(preserve_job_files
, current_preserve_job_files
))
1455 num_newsettings
= cupsAddOption("PreserveJobFiles", preserve_job_files
, num_newsettings
, &newsettings
);
1456 if (_cups_strcasecmp(max_clients
, current_max_clients
))
1457 num_newsettings
= cupsAddOption("MaxClients", max_clients
, num_newsettings
, &newsettings
);
1458 if (_cups_strcasecmp(max_jobs
, current_max_jobs
))
1459 num_newsettings
= cupsAddOption("MaxJobs", max_jobs
, num_newsettings
, &newsettings
);
1460 if (_cups_strcasecmp(max_log_size
, current_max_log_size
))
1461 num_newsettings
= cupsAddOption("MaxLogSize", max_log_size
, num_newsettings
, &newsettings
);
1464 if (!cupsAdminSetServerSettings(http
, num_newsettings
, newsettings
))
1466 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
1468 puts("Status: 401\n");
1472 cgiStartHTML(cgiText(_("Change Settings")));
1473 cgiSetVariable("MESSAGE",
1474 cgiText(_("Unable to change server settings")));
1475 cgiSetVariable("ERROR", cupsGetErrorString());
1476 cgiCopyTemplateLang("error.tmpl");
1481 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1482 "URL=/admin/?ADVANCEDSETTINGS=YES");
1484 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1485 cgiStartHTML(cgiText(_("Change Settings")));
1486 cgiCopyTemplateLang("restart.tmpl");
1489 cupsFreeOptions(num_newsettings
, newsettings
);
1497 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1498 cgiStartHTML(cgiText(_("Change Settings")));
1499 cgiCopyTemplateLang("norestart.tmpl");
1502 cupsFreeOptions(num_settings
, settings
);
1506 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1509 * Save hand-edited config file...
1512 http_status_t status
; /* PUT status */
1513 char tempfile
[1024]; /* Temporary new cupsd.conf */
1514 int tempfd
; /* Temporary file descriptor */
1515 cups_file_t
*temp
; /* Temporary file */
1516 const char *start
, /* Start of line */
1517 *end
; /* End of line */
1521 * Create a temporary file for the new cupsd.conf file...
1524 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1526 cgiStartHTML(cgiText(_("Edit Configuration File")));
1527 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1528 cgiSetVariable("ERROR", strerror(errno
));
1529 cgiCopyTemplateLang("error.tmpl");
1536 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1538 cgiStartHTML(cgiText(_("Edit Configuration File")));
1539 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1540 cgiSetVariable("ERROR", strerror(errno
));
1541 cgiCopyTemplateLang("error.tmpl");
1551 * Copy the cupsd.conf text from the form variable...
1554 start
= cgiGetVariable("CUPSDCONF");
1557 if ((end
= strstr(start
, "\r\n")) == NULL
)
1558 if ((end
= strstr(start
, "\n")) == NULL
)
1559 end
= start
+ strlen(start
);
1561 cupsFileWrite(temp
, start
, (size_t)(end
- start
));
1562 cupsFilePutChar(temp
, '\n');
1566 else if (*end
== '\n')
1572 cupsFileClose(temp
);
1575 * Upload the configuration file to the server...
1578 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1580 if (status
== HTTP_STATUS_UNAUTHORIZED
)
1582 puts("Status: 401\n");
1586 else if (status
!= HTTP_STATUS_CREATED
)
1588 cgiSetVariable("MESSAGE",
1589 cgiText(_("Unable to upload cupsd.conf file")));
1590 cgiSetVariable("ERROR", httpStatus(status
));
1592 cgiStartHTML(cgiText(_("Edit Configuration File")));
1593 cgiCopyTemplateLang("error.tmpl");
1597 cgiSetVariable("refresh_page", "5;URL=/admin/");
1599 cgiStartHTML(cgiText(_("Edit Configuration File")));
1600 cgiCopyTemplateLang("restart.tmpl");
1609 struct stat info
; /* cupsd.conf information */
1610 cups_file_t
*cupsd
; /* cupsd.conf file */
1611 char *buffer
, /* Buffer for entire file */
1612 *bufptr
, /* Pointer into buffer */
1613 *bufend
; /* End of buffer */
1614 int ch
; /* Character from file */
1615 char filename
[1024]; /* Filename */
1616 const char *server_root
; /* Location of config files */
1620 * Locate the cupsd.conf file...
1623 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1624 server_root
= CUPS_SERVERROOT
;
1626 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1629 * Figure out the size...
1632 if (stat(filename
, &info
))
1634 cgiStartHTML(cgiText(_("Edit Configuration File")));
1635 cgiSetVariable("MESSAGE",
1636 cgiText(_("Unable to access cupsd.conf file")));
1637 cgiSetVariable("ERROR", strerror(errno
));
1638 cgiCopyTemplateLang("error.tmpl");
1645 if (info
.st_size
> (1024 * 1024))
1647 cgiStartHTML(cgiText(_("Edit Configuration File")));
1648 cgiSetVariable("MESSAGE",
1649 cgiText(_("Unable to access cupsd.conf file")));
1650 cgiSetVariable("ERROR",
1651 cgiText(_("Unable to edit cupsd.conf files larger than "
1653 cgiCopyTemplateLang("error.tmpl");
1656 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1657 (long)info
.st_size
);
1662 * Open the cupsd.conf file...
1665 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1668 * Unable to open - log an error...
1671 cgiStartHTML(cgiText(_("Edit Configuration File")));
1672 cgiSetVariable("MESSAGE",
1673 cgiText(_("Unable to access cupsd.conf file")));
1674 cgiSetVariable("ERROR", strerror(errno
));
1675 cgiCopyTemplateLang("error.tmpl");
1683 * Allocate memory and load the file into a string buffer...
1686 if ((buffer
= calloc(1, (size_t)info
.st_size
+ 1)) != NULL
)
1688 cupsFileRead(cupsd
, buffer
, (size_t)info
.st_size
);
1689 cgiSetVariable("CUPSDCONF", buffer
);
1693 cupsFileClose(cupsd
);
1696 * Then get the default cupsd.conf file and put that into a string as
1700 cupsConcatString(filename
, ".default", sizeof(filename
));
1702 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1703 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1705 if ((buffer
= calloc(1, 2 * (size_t)info
.st_size
+ 1)) != NULL
)
1707 bufend
= buffer
+ 2 * info
.st_size
- 1;
1709 for (bufptr
= buffer
;
1710 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1712 if (ch
== '\\' || ch
== '\"')
1715 *bufptr
++ = (char)ch
;
1717 else if (ch
== '\n')
1722 else if (ch
== '\t')
1728 *bufptr
++ = (char)ch
;
1733 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1737 cupsFileClose(cupsd
);
1741 * Show the current config file...
1744 cgiStartHTML(cgiText(_("Edit Configuration File")));
1746 cgiCopyTemplateLang("edit-config.tmpl");
1754 * 'do_delete_class()' - Delete a class.
1758 do_delete_class(http_t
*http
) /* I - HTTP connection */
1760 ipp_t
*request
; /* IPP request */
1761 char uri
[HTTP_MAX_URI
]; /* Job URI */
1762 const char *pclass
; /* Printer class name */
1766 * Get form variables...
1769 if (cgiGetVariable("CONFIRM") == NULL
)
1771 cgiStartHTML(cgiText(_("Delete Class")));
1772 cgiCopyTemplateLang("class-confirm.tmpl");
1777 if ((pclass
= cgiGetTextfield("PRINTER_NAME")) != NULL
)
1778 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1779 "localhost", 0, "/classes/%s", pclass
);
1782 cgiStartHTML(cgiText(_("Delete Class")));
1783 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1784 cgiCopyTemplateLang("error.tmpl");
1790 * Build a CUPS_DELETE_CLASS request, which requires the following
1793 * attributes-charset
1794 * attributes-natural-language
1798 request
= ippNewRequest(IPP_OP_CUPS_DELETE_CLASS
);
1800 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1804 * Do the request and get back a response...
1807 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1810 * Show the results...
1813 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
1815 puts("Status: 401\n");
1818 else if (cupsGetError() <= IPP_STATUS_OK_CONFLICTING
)
1821 * Redirect successful updates back to the classes page...
1824 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1827 cgiStartHTML(cgiText(_("Delete Class")));
1829 if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
1830 cgiShowIPPError(_("Unable to delete class"));
1832 cgiCopyTemplateLang("class-deleted.tmpl");
1839 * 'do_delete_printer()' - Delete a printer.
1843 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1845 ipp_t
*request
; /* IPP request */
1846 char uri
[HTTP_MAX_URI
]; /* Job URI */
1847 const char *printer
; /* Printer printer name */
1851 * Get form variables...
1854 if (cgiGetVariable("CONFIRM") == NULL
)
1856 cgiStartHTML(cgiText(_("Delete Printer")));
1857 cgiCopyTemplateLang("printer-confirm.tmpl");
1862 if ((printer
= cgiGetTextfield("PRINTER_NAME")) != NULL
)
1863 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1864 "localhost", 0, "/printers/%s", printer
);
1867 cgiStartHTML(cgiText(_("Delete Printer")));
1868 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1869 cgiCopyTemplateLang("error.tmpl");
1875 * Build a CUPS_DELETE_PRINTER request, which requires the following
1878 * attributes-charset
1879 * attributes-natural-language
1883 request
= ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER
);
1885 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1889 * Do the request and get back a response...
1892 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1895 * Show the results...
1898 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
1900 puts("Status: 401\n");
1903 else if (cupsGetError() <= IPP_STATUS_OK_CONFLICTING
)
1906 * Redirect successful updates back to the printers page...
1909 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1912 cgiStartHTML(cgiText(_("Delete Printer")));
1914 if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
1915 cgiShowIPPError(_("Unable to delete printer"));
1917 cgiCopyTemplateLang("printer-deleted.tmpl");
1924 * 'do_list_printers()' - List available printers.
1928 do_list_printers(http_t
*http
) /* I - HTTP connection */
1930 ipp_t
*request
, /* IPP request */
1931 *response
; /* IPP response */
1932 ipp_attribute_t
*attr
; /* IPP attribute */
1935 cgiStartHTML(cgiText(_("List Available Printers")));
1939 * Get the list of printers and their devices...
1942 request
= ippNewRequest(IPP_OP_CUPS_GET_PRINTERS
);
1944 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1945 "requested-attributes", NULL
, "device-uri");
1947 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
1948 CUPS_PRINTER_LOCAL
);
1949 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
1950 CUPS_PRINTER_LOCAL
);
1952 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1955 * Got the printer list, now load the devices...
1958 int i
; /* Looping var */
1959 cups_array_t
*printer_devices
; /* Printer devices for local printers */
1960 char *printer_device
; /* Current printer device */
1964 * Allocate an array and copy the device strings...
1967 printer_devices
= cupsArrayNew((cups_array_func_t
)_cupsArrayStrcmp
, NULL
);
1969 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
1971 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
1973 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
1977 * Free the printer list and get the device list...
1980 ippDelete(response
);
1982 request
= ippNewRequest(IPP_OP_CUPS_GET_DEVICES
);
1984 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1987 * Got the device list, let's parse it...
1990 const char *device_uri
, /* device-uri attribute value */
1991 *device_make_and_model
, /* device-make-and-model value */
1992 *device_info
; /* device-info value */
1995 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
1998 * Skip leading attributes until we hit a device...
2001 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2008 * Pull the needed attributes from this device...
2012 device_make_and_model
= NULL
;
2015 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2017 if (!strcmp(attr
->name
, "device-info") &&
2018 attr
->value_tag
== IPP_TAG_TEXT
)
2019 device_info
= attr
->values
[0].string
.text
;
2021 if (!strcmp(attr
->name
, "device-make-and-model") &&
2022 attr
->value_tag
== IPP_TAG_TEXT
)
2023 device_make_and_model
= attr
->values
[0].string
.text
;
2025 if (!strcmp(attr
->name
, "device-uri") &&
2026 attr
->value_tag
== IPP_TAG_URI
)
2027 device_uri
= attr
->values
[0].string
.text
;
2033 * See if we have everything needed...
2036 if (device_info
&& device_make_and_model
&& device_uri
&&
2037 _cups_strcasecmp(device_make_and_model
, "unknown") &&
2038 strchr(device_uri
, ':'))
2041 * Yes, now see if there is already a printer for this
2045 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2048 * Not found, so it must be a new printer...
2051 char option
[1024], /* Form variables for this device */
2052 *option_ptr
; /* Pointer into string */
2053 const char *ptr
; /* Pointer into device string */
2057 * Format the printer name variable for this device...
2059 * We use the device-info string first, then device-uri,
2060 * and finally device-make-and-model to come up with a
2064 if (_cups_strncasecmp(device_info
, "unknown", 7))
2066 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2069 ptr
= device_make_and_model
;
2071 for (option_ptr
= option
;
2072 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2074 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2076 *option_ptr
++ = *ptr
;
2077 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2078 option_ptr
[-1] != '_')
2079 *option_ptr
++ = '_';
2080 else if (*ptr
== '?' || *ptr
== '(')
2085 cgiSetArray("TEMPLATE_NAME", i
, option
);
2088 * Finally, set the form variables for this printer...
2091 cgiSetArray("device_info", i
, device_info
);
2092 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2093 cgiSetArray("device_uri", i
, device_uri
);
2102 ippDelete(response
);
2105 * Free the device list...
2108 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2110 printer_device
= (char *)cupsArrayNext(printer_devices
))
2111 free(printer_device
);
2113 cupsArrayDelete(printer_devices
);
2118 * Finally, show the printer list...
2121 cgiCopyTemplateLang("list-available-printers.tmpl");
2128 * 'do_menu()' - Show the main menu.
2132 do_menu(http_t
*http
) /* I - HTTP connection */
2134 int num_settings
; /* Number of server settings */
2135 cups_option_t
*settings
; /* Server settings */
2136 const char *val
; /* Setting value */
2140 * Get the current server settings...
2143 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2145 cgiSetVariable("SETTINGS_MESSAGE",
2146 cgiText(_("Unable to open cupsd.conf file:")));
2147 cgiSetVariable("SETTINGS_ERROR", cupsGetErrorString());
2150 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2151 settings
)) != NULL
&& atoi(val
))
2152 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2154 cgiSetVariable("DEBUG_LOGGING", "");
2156 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2157 settings
)) != NULL
&& atoi(val
))
2158 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2160 cgiSetVariable("REMOTE_ADMIN", "");
2162 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2163 settings
)) != NULL
&& atoi(val
))
2164 cgiSetVariable("REMOTE_ANY", "CHECKED");
2166 cgiSetVariable("REMOTE_ANY", "");
2168 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2169 settings
)) != NULL
&& atoi(val
))
2170 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2172 cgiSetVariable("SHARE_PRINTERS", "");
2174 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2175 settings
)) != NULL
&& atoi(val
))
2176 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2178 cgiSetVariable("USER_CANCEL_ANY", "");
2181 cgiSetVariable("HAVE_GSSAPI", "1");
2183 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2184 settings
)) != NULL
&& !_cups_strcasecmp(val
, "Negotiate"))
2185 cgiSetVariable("KERBEROS", "CHECKED");
2187 #endif /* HAVE_GSSAPI */
2188 cgiSetVariable("KERBEROS", "");
2190 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2194 if (!_cups_strcasecmp(val
, "yes") || !_cups_strcasecmp(val
, "on") ||
2195 !_cups_strcasecmp(val
, "true"))
2196 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2198 cgiSetVariable("BROWSE_WEB_IF", "");
2200 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2205 (!_cups_strcasecmp(val
, "0") || !_cups_strcasecmp(val
, "no") ||
2206 !_cups_strcasecmp(val
, "off") || !_cups_strcasecmp(val
, "false") ||
2207 !_cups_strcasecmp(val
, "disabled")))
2209 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2210 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2214 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2215 cgiSetVariable("PRESERVE_JOB_HISTORY", val
);
2217 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2221 cgiSetVariable("PRESERVE_JOB_FILES", val
);
2225 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2228 cgiSetVariable("MAX_CLIENTS", val
);
2230 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2233 cgiSetVariable("MAX_JOBS", val
);
2235 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2238 cgiSetVariable("MAX_LOG_SIZE", val
);
2240 cupsFreeOptions(num_settings
, settings
);
2243 * Finally, show the main menu template...
2246 cgiStartHTML(cgiText(_("Administration")));
2248 cgiCopyTemplateLang("admin.tmpl");
2255 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2259 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2261 int i
; /* Looping var */
2262 ipp_t
*request
, /* IPP request */
2263 *response
; /* IPP response */
2264 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2265 const char *printer
, /* Printer name */
2266 *is_class
, /* Is a class? */
2267 *users
, /* List of users or groups */
2268 *type
; /* Allow/deny type */
2269 int num_users
; /* Number of users */
2270 char *ptr
, /* Pointer into users string */
2271 *end
, /* Pointer to end of users string */
2272 quote
; /* Quote character */
2273 ipp_attribute_t
*attr
; /* Attribute */
2274 static const char * const attrs
[] = /* Requested attributes */
2276 "requesting-user-name-allowed",
2277 "requesting-user-name-denied"
2281 is_class
= cgiGetVariable("IS_CLASS");
2282 printer
= cgiGetTextfield("PRINTER_NAME");
2286 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2287 cgiStartHTML(cgiText(_("Set Allowed Users")));
2288 cgiCopyTemplateLang("error.tmpl");
2293 users
= cgiGetTextfield("users");
2294 type
= cgiGetVariable("type");
2296 if (!users
|| !type
||
2297 (strcmp(type
, "requesting-user-name-allowed") &&
2298 strcmp(type
, "requesting-user-name-denied")))
2301 * Build a Get-Printer-Attributes request, which requires the following
2304 * attributes-charset
2305 * attributes-natural-language
2307 * requested-attributes
2310 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
2312 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2313 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2315 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2318 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2319 "requested-attributes",
2320 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2323 * Do the request and get back a response...
2326 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2328 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2330 ippDelete(response
);
2333 cgiStartHTML(cgiText(_("Set Allowed Users")));
2335 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
2337 puts("Status: 401\n");
2340 else if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
2341 cgiShowIPPError(_("Unable to get printer attributes"));
2343 cgiCopyTemplateLang("users.tmpl");
2350 * Save the changes...
2353 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2356 * Skip whitespace and commas...
2359 while (*ptr
== ',' || isspace(*ptr
& 255))
2365 if (*ptr
== '\'' || *ptr
== '\"')
2368 * Scan quoted name...
2373 for (end
= ptr
; *end
; end
++)
2380 * Scan space or comma-delimited name...
2383 for (end
= ptr
; *end
; end
++)
2384 if (isspace(*end
& 255) || *end
== ',')
2389 * Advance to the next name...
2396 * Build a CUPS-Add-Printer/Class request, which requires the following
2399 * attributes-charset
2400 * attributes-natural-language
2402 * requesting-user-name-{allowed,denied}
2405 request
= ippNewRequest(is_class
? IPP_OP_CUPS_ADD_MODIFY_CLASS
: IPP_OP_CUPS_ADD_MODIFY_PRINTER
);
2407 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2408 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2410 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2414 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2415 "requesting-user-name-allowed", NULL
, "all");
2418 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2419 type
, num_users
, NULL
, NULL
);
2421 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2424 * Skip whitespace and commas...
2427 while (*ptr
== ',' || isspace(*ptr
& 255))
2433 if (*ptr
== '\'' || *ptr
== '\"')
2436 * Scan quoted name...
2441 for (end
= ptr
; *end
; end
++)
2448 * Scan space or comma-delimited name...
2451 for (end
= ptr
; *end
; end
++)
2452 if (isspace(*end
& 255) || *end
== ',')
2457 * Terminate the name...
2467 ippSetString(request
, &attr
, i
, ptr
);
2470 * Advance to the next name...
2478 * Do the request and get back a response...
2481 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2483 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
2485 puts("Status: 401\n");
2488 else if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
2490 cgiStartHTML(cgiText(_("Set Allowed Users")));
2491 cgiShowIPPError(_("Unable to change printer"));
2496 * Redirect successful updates back to the printer page...
2499 char url
[1024], /* Printer/class URL */
2500 refresh
[1024]; /* Refresh URL */
2503 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2504 cgiFormEncode(uri
, url
, sizeof(uri
));
2505 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2507 cgiSetVariable("refresh_page", refresh
);
2509 cgiStartHTML(cgiText(_("Set Allowed Users")));
2511 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2512 "printer-modified.tmpl");
2521 * 'do_set_default()' - Set the server default printer/class.
2525 do_set_default(http_t
*http
) /* I - HTTP connection */
2527 const char *title
; /* Page title */
2528 ipp_t
*request
; /* IPP request */
2529 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2530 const char *printer
, /* Printer name */
2531 *is_class
; /* Is a class? */
2534 is_class
= cgiGetVariable("IS_CLASS");
2535 printer
= cgiGetTextfield("PRINTER_NAME");
2536 title
= cgiText(_("Set As Server Default"));
2540 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2541 cgiStartHTML(title
);
2542 cgiCopyTemplateLang("error.tmpl");
2548 * Build a printer request, which requires the following
2551 * attributes-charset
2552 * attributes-natural-language
2556 request
= ippNewRequest(IPP_OP_CUPS_SET_DEFAULT
);
2558 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2559 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2561 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2565 * Do the request and get back a response...
2568 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2570 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
2572 puts("Status: 401\n");
2575 else if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
2577 cgiStartHTML(title
);
2578 cgiShowIPPError(_("Unable to set server default"));
2583 * Redirect successful updates back to the printer page...
2586 char url
[1024], /* Printer/class URL */
2587 refresh
[1024]; /* Refresh URL */
2590 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2591 cgiFormEncode(uri
, url
, sizeof(uri
));
2592 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2593 cgiSetVariable("refresh_page", refresh
);
2595 cgiStartHTML(title
);
2596 cgiCopyTemplateLang("printer-default.tmpl");
2604 * 'do_set_options()' - Configure the default options for a queue.
2608 do_set_options(http_t
*http
, /* I - HTTP connection */
2609 int is_class
) /* I - Set options for class? */
2611 int i
, j
, k
, m
; /* Looping vars */
2612 int have_options
; /* Have options? */
2613 ipp_t
*request
, /* IPP request */
2614 *response
; /* IPP response */
2615 ipp_attribute_t
*attr
; /* IPP attribute */
2616 char uri
[HTTP_MAX_URI
]; /* Job URI */
2617 const char *var
; /* Variable value */
2618 const char *printer
; /* Printer printer name */
2619 const char *filename
; /* PPD filename */
2620 char tempfile
[1024]; /* Temporary filename */
2621 cups_file_t
*in
, /* Input file */
2622 *out
; /* Output file */
2623 char line
[1024], /* Line from PPD file */
2624 value
[1024], /* Option value */
2625 keyword
[1024], /* Keyword from Default line */
2626 *keyptr
; /* Pointer into keyword... */
2627 ppd_file_t
*ppd
; /* PPD file */
2628 ppd_group_t
*group
; /* Option group */
2629 ppd_option_t
*option
; /* Option */
2630 ppd_coption_t
*coption
; /* Custom option */
2631 ppd_cparam_t
*cparam
; /* Custom parameter */
2632 ppd_attr_t
*ppdattr
; /* PPD attribute */
2633 const char *title
; /* Page title */
2636 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2638 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", (void *)http
,
2642 * Get the printer name...
2645 if ((printer
= cgiGetTextfield("PRINTER_NAME")) != NULL
)
2646 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2647 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2651 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2652 cgiStartHTML(title
);
2653 cgiCopyTemplateLang("error.tmpl");
2658 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2661 * If the user clicks on the Auto-Configure button, send an AutoConfigure
2662 * command file to the printer...
2665 if (cgiGetVariable("AUTOCONFIGURE"))
2667 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
2672 * Get the PPD file...
2678 filename
= cupsGetPPD2(http
, printer
);
2682 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2684 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2686 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2687 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
2688 cgiStartHTML(title
);
2689 cgiCopyTemplateLang("error.tmpl");
2696 fputs("DEBUG: No PPD file\n", stderr
);
2700 if (cgiGetVariable("job_sheets_start") != NULL
||
2701 cgiGetVariable("job_sheets_end") != NULL
)
2708 ppdMarkDefaults(ppd
);
2710 for (option
= ppdFirstOption(ppd
);
2712 option
= ppdNextOption(ppd
))
2714 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2717 ppdMarkOption(ppd
, option
->keyword
, var
);
2718 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
2721 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
2725 if (!have_options
|| ppdConflicts(ppd
))
2728 * Show the options to the user...
2731 fputs("DEBUG: Showing options...\n", stderr
);
2734 * Show auto-configure button if supported...
2739 if (ppd
->num_filters
== 0 ||
2740 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
2741 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
2742 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2745 for (i
= 0; i
< ppd
->num_filters
; i
++)
2746 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
2748 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2755 * Get the printer attributes...
2758 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
2760 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2761 "localhost", 0, "/printers/%s", printer
);
2762 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2765 response
= cupsDoRequest(http
, request
, "/");
2768 * List the groups used as "tabs"...
2775 for (group
= ppd
->groups
;
2776 i
< ppd
->num_groups
;
2779 cgiSetArray("GROUP_ID", i
, group
->name
);
2781 if (!strcmp(group
->name
, "InstallableOptions"))
2782 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
2784 cgiSetArray("GROUP", i
, group
->text
);
2788 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
2790 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
2791 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
2794 if (ippFindAttribute(response
, "printer-error-policy-supported",
2796 ippFindAttribute(response
, "printer-op-policy-supported",
2799 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
2800 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
2803 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
2804 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
2806 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
2807 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
2810 cgiStartHTML(cgiText(_("Set Printer Options")));
2811 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2817 if (ppdConflicts(ppd
))
2819 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
2822 for (j
= group
->num_options
, option
= group
->options
;
2825 if (option
->conflicted
)
2827 cgiSetArray("ckeyword", k
, option
->keyword
);
2828 cgiSetArray("ckeytext", k
, option
->text
);
2830 for (m
= 0; m
< option
->num_choices
; m
++)
2832 if (option
->choices
[m
].marked
)
2834 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
2842 cgiCopyTemplateLang("option-conflict.tmpl");
2845 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2849 for (j
= group
->num_options
, option
= group
->options
;
2853 if (!strcmp(option
->keyword
, "PageRegion"))
2856 if (option
->num_choices
> 1)
2863 cgiSetVariable("GROUP_ID", group
->name
);
2865 if (!strcmp(group
->name
, "InstallableOptions"))
2866 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2868 cgiSetVariable("GROUP", group
->text
);
2870 cgiCopyTemplateLang("option-header.tmpl");
2872 for (j
= group
->num_options
, option
= group
->options
;
2876 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
2879 cgiSetVariable("KEYWORD", option
->keyword
);
2880 cgiSetVariable("KEYTEXT", option
->text
);
2882 if (option
->conflicted
)
2883 cgiSetVariable("CONFLICTED", "1");
2885 cgiSetVariable("CONFLICTED", "0");
2887 cgiSetSize("CHOICES", 0);
2888 cgiSetSize("TEXT", 0);
2889 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
2891 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
2892 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
2896 if (option
->choices
[k
].marked
)
2897 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
2900 cgiSetSize("PARAMS", 0);
2901 cgiSetSize("PARAMTEXT", 0);
2902 cgiSetSize("PARAMVALUE", 0);
2903 cgiSetSize("INPUTTYPE", 0);
2905 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
2907 const char *units
= NULL
; /* Units value, if any */
2909 cgiSetVariable("ISCUSTOM", "1");
2911 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
2913 cparam
= ppdNextCustomParam(coption
), m
++)
2915 if (!_cups_strcasecmp(option
->keyword
, "PageSize") &&
2916 _cups_strcasecmp(cparam
->name
, "Width") &&
2917 _cups_strcasecmp(cparam
->name
, "Height"))
2923 cgiSetArray("PARAMS", m
, cparam
->name
);
2924 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
2925 cgiSetArray("INPUTTYPE", m
, "text");
2927 switch (cparam
->type
)
2929 case PPD_CUSTOM_UNKNOWN
:
2932 case PPD_CUSTOM_POINTS
:
2933 if (!_cups_strncasecmp(option
->defchoice
, "Custom.", 7))
2935 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
2937 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
2938 strcmp(units
, "in") && strcmp(units
, "ft"))
2940 if (units
[1] == 'm')
2949 if (!strcmp(units
, "mm"))
2950 snprintf(value
, sizeof(value
), "%g",
2951 cparam
->current
.custom_points
/ 72.0 * 25.4);
2952 else if (!strcmp(units
, "cm"))
2953 snprintf(value
, sizeof(value
), "%g",
2954 cparam
->current
.custom_points
/ 72.0 * 2.54);
2955 else if (!strcmp(units
, "in"))
2956 snprintf(value
, sizeof(value
), "%g",
2957 cparam
->current
.custom_points
/ 72.0);
2958 else if (!strcmp(units
, "ft"))
2959 snprintf(value
, sizeof(value
), "%g",
2960 cparam
->current
.custom_points
/ 72.0 / 12.0);
2961 else if (!strcmp(units
, "m"))
2962 snprintf(value
, sizeof(value
), "%g",
2963 cparam
->current
.custom_points
/ 72.0 * 0.0254);
2965 snprintf(value
, sizeof(value
), "%g",
2966 cparam
->current
.custom_points
);
2967 cgiSetArray("PARAMVALUE", m
, value
);
2970 case PPD_CUSTOM_CURVE
:
2971 case PPD_CUSTOM_INVCURVE
:
2972 case PPD_CUSTOM_REAL
:
2973 snprintf(value
, sizeof(value
), "%g",
2974 cparam
->current
.custom_real
);
2975 cgiSetArray("PARAMVALUE", m
, value
);
2978 case PPD_CUSTOM_INT
:
2979 snprintf(value
, sizeof(value
), "%d",
2980 cparam
->current
.custom_int
);
2981 cgiSetArray("PARAMVALUE", m
, value
);
2984 case PPD_CUSTOM_PASSCODE
:
2985 case PPD_CUSTOM_PASSWORD
:
2986 if (cparam
->current
.custom_password
)
2987 cgiSetArray("PARAMVALUE", m
,
2988 cparam
->current
.custom_password
);
2990 cgiSetArray("PARAMVALUE", m
, "");
2991 cgiSetArray("INPUTTYPE", m
, "password");
2994 case PPD_CUSTOM_STRING
:
2995 if (cparam
->current
.custom_string
)
2996 cgiSetArray("PARAMVALUE", m
,
2997 cparam
->current
.custom_string
);
2999 cgiSetArray("PARAMVALUE", m
, "");
3006 cgiSetArray("PARAMS", m
, "Units");
3007 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3008 cgiSetArray("PARAMVALUE", m
, units
);
3012 cgiSetVariable("ISCUSTOM", "0");
3016 case PPD_UI_BOOLEAN
:
3017 cgiCopyTemplateLang("option-boolean.tmpl");
3019 case PPD_UI_PICKONE
:
3020 cgiCopyTemplateLang("option-pickone.tmpl");
3022 case PPD_UI_PICKMANY
:
3023 cgiCopyTemplateLang("option-pickmany.tmpl");
3028 cgiCopyTemplateLang("option-trailer.tmpl");
3032 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3033 IPP_TAG_ZERO
)) != NULL
)
3036 * Add the job sheets options...
3039 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3040 cgiSetVariable("GROUP", cgiText(_("Banners")));
3041 cgiCopyTemplateLang("option-header.tmpl");
3043 cgiSetSize("CHOICES", attr
->num_values
);
3044 cgiSetSize("TEXT", attr
->num_values
);
3045 for (k
= 0; k
< attr
->num_values
; k
++)
3047 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3048 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3051 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3053 cgiSetVariable("KEYWORD", "job_sheets_start");
3054 cgiSetVariable("KEYTEXT",
3055 /* TRANSLATORS: Banner/cover sheet before the print job. */
3056 cgiText(_("Starting Banner")));
3057 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3058 attr
->values
[0].string
.text
: "");
3060 cgiCopyTemplateLang("option-pickone.tmpl");
3062 cgiSetVariable("KEYWORD", "job_sheets_end");
3063 cgiSetVariable("KEYTEXT",
3064 /* TRANSLATORS: Banner/cover sheet after the print job. */
3065 cgiText(_("Ending Banner")));
3066 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3067 attr
->values
[1].string
.text
: "");
3069 cgiCopyTemplateLang("option-pickone.tmpl");
3071 cgiCopyTemplateLang("option-trailer.tmpl");
3074 if (ippFindAttribute(response
, "printer-error-policy-supported",
3076 ippFindAttribute(response
, "printer-op-policy-supported",
3080 * Add the error and operation policy options...
3083 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3084 cgiSetVariable("GROUP", cgiText(_("Policies")));
3085 cgiCopyTemplateLang("option-header.tmpl");
3091 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3096 cgiSetSize("CHOICES", attr
->num_values
);
3097 cgiSetSize("TEXT", attr
->num_values
);
3098 for (k
= 0; k
< attr
->num_values
; k
++)
3100 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3101 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3104 attr
= ippFindAttribute(response
, "printer-error-policy",
3107 cgiSetVariable("KEYWORD", "printer_error_policy");
3108 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3109 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3110 "" : attr
->values
[0].string
.text
);
3113 cgiCopyTemplateLang("option-pickone.tmpl");
3116 * Operation policy...
3119 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3124 cgiSetSize("CHOICES", attr
->num_values
);
3125 cgiSetSize("TEXT", attr
->num_values
);
3126 for (k
= 0; k
< attr
->num_values
; k
++)
3128 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3129 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3132 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3134 cgiSetVariable("KEYWORD", "printer_op_policy");
3135 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3136 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3137 "" : attr
->values
[0].string
.text
);
3139 cgiCopyTemplateLang("option-pickone.tmpl");
3142 cgiCopyTemplateLang("option-trailer.tmpl");
3146 * Binary protocol support...
3149 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3150 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3152 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3153 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3155 cgiSetSize("CHOICES", attr
->num_values
);
3156 cgiSetSize("TEXT", attr
->num_values
);
3158 for (i
= 0; i
< attr
->num_values
; i
++)
3160 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3161 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3164 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3165 cgiSetVariable("KEYWORD", "port_monitor");
3166 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3167 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3169 cgiCopyTemplateLang("option-header.tmpl");
3170 cgiCopyTemplateLang("option-pickone.tmpl");
3171 cgiCopyTemplateLang("option-trailer.tmpl");
3174 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3177 ippDelete(response
);
3182 * Set default options...
3185 fputs("DEBUG: Setting options...\n", stderr
);
3189 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3190 in
= cupsFileOpen(filename
, "r");
3194 cgiSetVariable("ERROR", strerror(errno
));
3195 cgiStartHTML(cgiText(_("Set Printer Options")));
3196 cgiCopyTemplateLang("error.tmpl");
3212 while (cupsFileGets(in
, line
, sizeof(line
)))
3214 if (!strncmp(line
, "*cupsProtocol:", 14))
3216 else if (strncmp(line
, "*Default", 8))
3217 cupsFilePrintf(out
, "%s\n", line
);
3221 * Get default option name...
3224 cupsCopyString(keyword
, line
+ 8, sizeof(keyword
));
3226 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3227 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3232 if (!strcmp(keyword
, "PageRegion") ||
3233 !strcmp(keyword
, "PaperDimension") ||
3234 !strcmp(keyword
, "ImageableArea"))
3235 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3237 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3240 cupsFilePrintf(out
, "%s\n", line
);
3242 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3252 * Make sure temporary filename is cleared when there is no PPD...
3259 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3260 * following attributes:
3262 * attributes-charset
3263 * attributes-natural-language
3265 * job-sheets-default
3266 * printer-error-policy
3271 request
= ippNewRequest(is_class
? IPP_OP_CUPS_ADD_MODIFY_CLASS
:
3272 IPP_OP_CUPS_ADD_MODIFY_PRINTER
);
3274 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3277 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3278 "job-sheets-default", 2, NULL
, NULL
);
3279 ippSetString(request
, &attr
, 0, cgiGetVariable("job_sheets_start"));
3280 ippSetString(request
, &attr
, 1, cgiGetVariable("job_sheets_end"));
3282 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3283 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3284 "printer-error-policy", NULL
, var
);
3286 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3287 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3288 "printer-op-policy", NULL
, var
);
3290 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3291 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3292 "port-monitor", NULL
, var
);
3295 * Do the request and get back a response...
3299 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3301 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3303 if (cupsGetError() == IPP_STATUS_ERROR_NOT_AUTHORIZED
)
3305 puts("Status: 401\n");
3308 else if (cupsGetError() > IPP_STATUS_OK_CONFLICTING
)
3310 cgiStartHTML(title
);
3311 cgiShowIPPError(_("Unable to set options"));
3316 * Redirect successful updates back to the printer page...
3319 char refresh
[1024]; /* Refresh URL */
3322 cgiFormEncode(uri
, printer
, sizeof(uri
));
3323 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3324 is_class
? "classes" : "printers", uri
);
3325 cgiSetVariable("refresh_page", refresh
);
3327 cgiStartHTML(title
);
3329 cgiCopyTemplateLang("printer-configured.tmpl");
3344 * 'get_option_value()' - Return the value of an option.
3346 * This function also handles generation of custom option values.
3349 static char * /* O - Value string or NULL on error */
3351 ppd_file_t
*ppd
, /* I - PPD file */
3352 const char *name
, /* I - Option name */
3353 char *buffer
, /* I - String buffer */
3354 size_t bufsize
) /* I - Size of buffer */
3356 char *bufptr
, /* Pointer into buffer */
3357 *bufend
; /* End of buffer */
3358 ppd_coption_t
*coption
; /* Custom option */
3359 ppd_cparam_t
*cparam
; /* Current custom parameter */
3360 char keyword
[256]; /* Parameter name */
3361 const char *val
, /* Parameter value */
3362 *uval
; /* Units value */
3363 long integer
; /* Integer value */
3364 double number
, /* Number value */
3365 number_points
; /* Number in points */
3369 * See if we have a custom option choice...
3372 if ((val
= cgiGetVariable(name
)) == NULL
)
3380 else if (_cups_strcasecmp(val
, "Custom") ||
3381 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3384 * Not a custom choice...
3387 cupsCopyString(buffer
, val
, bufsize
);
3392 * OK, we have a custom option choice, format it...
3397 if (!strcmp(coption
->keyword
, "PageSize"))
3399 const char *lval
; /* Length string value */
3400 double width
, /* Width value */
3401 width_points
, /* Width in points */
3402 length
, /* Length value */
3403 length_points
; /* Length in points */
3406 val
= cgiGetVariable("PageSize.Width");
3407 lval
= cgiGetVariable("PageSize.Height");
3408 uval
= cgiGetVariable("PageSize.Units");
3410 if (!val
|| !lval
|| !uval
||
3411 (width
= atof(val
)) == 0.0 ||
3412 (length
= atof(lval
)) == 0.0 ||
3413 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3414 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3417 width_points
= get_points(width
, uval
);
3418 length_points
= get_points(length
, uval
);
3420 if (width_points
< ppd
->custom_min
[0] ||
3421 width_points
> ppd
->custom_max
[0] ||
3422 length_points
< ppd
->custom_min
[1] ||
3423 length_points
> ppd
->custom_max
[1])
3426 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
3428 else if (cupsArrayCount(coption
->params
) == 1)
3430 cparam
= ppdFirstCustomParam(coption
);
3431 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
3433 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3436 switch (cparam
->type
)
3438 case PPD_CUSTOM_UNKNOWN
:
3441 case PPD_CUSTOM_CURVE
:
3442 case PPD_CUSTOM_INVCURVE
:
3443 case PPD_CUSTOM_REAL
:
3444 if ((number
= atof(val
)) == 0.0 ||
3445 number
< cparam
->minimum
.custom_real
||
3446 number
> cparam
->maximum
.custom_real
)
3449 snprintf(buffer
, bufsize
, "Custom.%g", number
);
3452 case PPD_CUSTOM_INT
:
3453 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3454 integer
== LONG_MAX
||
3455 integer
< cparam
->minimum
.custom_int
||
3456 integer
> cparam
->maximum
.custom_int
)
3459 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
3462 case PPD_CUSTOM_POINTS
:
3463 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3465 if ((number
= atof(val
)) == 0.0 ||
3466 (uval
= cgiGetVariable(keyword
)) == NULL
||
3467 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3468 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3471 number_points
= get_points(number
, uval
);
3472 if (number_points
< cparam
->minimum
.custom_points
||
3473 number_points
> cparam
->maximum
.custom_points
)
3476 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
3479 case PPD_CUSTOM_PASSCODE
:
3480 for (uval
= val
; *uval
; uval
++)
3481 if (!isdigit(*uval
& 255))
3484 case PPD_CUSTOM_PASSWORD
:
3485 case PPD_CUSTOM_STRING
:
3486 integer
= (long)strlen(val
);
3487 if (integer
< cparam
->minimum
.custom_string
||
3488 integer
> cparam
->maximum
.custom_string
)
3491 snprintf(buffer
, bufsize
, "Custom.%s", val
);
3497 const char *prefix
= "{"; /* Prefix string */
3501 bufend
= buffer
+ bufsize
;
3503 for (cparam
= ppdFirstCustomParam(coption
);
3505 cparam
= ppdNextCustomParam(coption
))
3507 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
3510 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3513 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%s%s=", prefix
, cparam
->name
);
3514 bufptr
+= strlen(bufptr
);
3517 switch (cparam
->type
)
3519 case PPD_CUSTOM_UNKNOWN
:
3522 case PPD_CUSTOM_CURVE
:
3523 case PPD_CUSTOM_INVCURVE
:
3524 case PPD_CUSTOM_REAL
:
3525 if ((number
= atof(val
)) == 0.0 ||
3526 number
< cparam
->minimum
.custom_real
||
3527 number
> cparam
->maximum
.custom_real
)
3530 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g", number
);
3533 case PPD_CUSTOM_INT
:
3534 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3535 integer
== LONG_MAX
||
3536 integer
< cparam
->minimum
.custom_int
||
3537 integer
> cparam
->maximum
.custom_int
)
3540 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%ld", integer
);
3543 case PPD_CUSTOM_POINTS
:
3544 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3546 if ((number
= atof(val
)) == 0.0 ||
3547 (uval
= cgiGetVariable(keyword
)) == NULL
||
3548 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
3549 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
3550 strcmp(uval
, "mm") && strcmp(uval
, "m")))
3553 number_points
= get_points(number
, uval
);
3554 if (number_points
< cparam
->minimum
.custom_points
||
3555 number_points
> cparam
->maximum
.custom_points
)
3558 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g%s", number
, uval
);
3561 case PPD_CUSTOM_PASSCODE
:
3562 for (uval
= val
; *uval
; uval
++)
3563 if (!isdigit(*uval
& 255))
3566 case PPD_CUSTOM_PASSWORD
:
3567 case PPD_CUSTOM_STRING
:
3568 integer
= (long)strlen(val
);
3569 if (integer
< cparam
->minimum
.custom_string
||
3570 integer
> cparam
->maximum
.custom_string
)
3573 if ((bufptr
+ 2) > bufend
)
3579 while (*val
&& bufptr
< bufend
)
3581 if (*val
== '\\' || *val
== '\"')
3583 if ((bufptr
+ 1) >= bufend
)
3592 if (bufptr
>= bufend
)
3601 bufptr
+= strlen(bufptr
);
3604 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
3616 * 'get_points()' - Get a value in points.
3619 static double /* O - Number in points */
3620 get_points(double number
, /* I - Original number */
3621 const char *uval
) /* I - Units */
3623 if (!strcmp(uval
, "mm")) /* Millimeters */
3624 return (number
* 72.0 / 25.4);
3625 else if (!strcmp(uval
, "cm")) /* Centimeters */
3626 return (number
* 72.0 / 2.54);
3627 else if (!strcmp(uval
, "in")) /* Inches */
3628 return (number
* 72.0);
3629 else if (!strcmp(uval
, "ft")) /* Feet */
3630 return (number
* 72.0 * 12.0);
3631 else if (!strcmp(uval
, "m")) /* Meters */
3632 return (number
* 72.0 / 0.0254);