2 * Administration CGI for CUPS.
4 * Copyright © 2007-2019 by Apple Inc.
5 * Copyright © 1997-2007 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * Include necessary headers...
15 #include "cgi-private.h"
16 #include <cups/http-private.h>
17 #include <cups/ppd-private.h>
18 #include <cups/adminutil.h>
31 static int current_device
= 0; /* Current device shown */
38 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
);
39 static void do_am_class(http_t
*http
, int modify
);
40 static void do_am_printer(http_t
*http
, int modify
);
41 static void do_config_server(http_t
*http
);
42 static void do_delete_class(http_t
*http
);
43 static void do_delete_printer(http_t
*http
);
44 static void do_list_printers(http_t
*http
);
45 static void do_menu(http_t
*http
);
46 static void do_set_allowed_users(http_t
*http
);
47 static void do_set_default(http_t
*http
);
48 static void do_set_options(http_t
*http
, int is_class
);
49 static void do_set_sharing(http_t
*http
);
50 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
51 char *buffer
, size_t bufsize
);
52 static double get_points(double number
, const char *uval
);
53 static char *get_printer_ppd(const char *uri
, char *buffer
, size_t bufsize
);
57 * 'main()' - Main entry for CGI.
60 int /* O - Exit status */
63 http_t
*http
; /* Connection to the server */
64 const char *op
; /* Operation name */
68 * Connect to the HTTP server...
71 fputs("DEBUG: admin.cgi started...\n", stderr
);
73 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
77 perror("ERROR: Unable to connect to cupsd");
78 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
79 cupsServer() ? cupsServer() : "(null)");
80 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
81 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
85 fprintf(stderr
, "DEBUG: http=%p\n", http
);
88 * Set the web interface section...
91 cgiSetVariable("SECTION", "admin");
92 cgiSetVariable("REFRESH_PAGE", "");
95 * See if we have form data...
98 if (!cgiInitialize() || !cgiGetVariable("OP"))
101 * Nope, send the administration menu...
104 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
108 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
111 * Do the operation...
114 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
118 const char *printer
= getenv("PRINTER_NAME"),
119 /* Printer or class name */
120 *server_port
= getenv("SERVER_PORT");
121 /* Port number string */
122 int port
= atoi(server_port
? server_port
: "0");
124 char uri
[1024]; /* URL */
127 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
128 getenv("HTTPS") ? "https" : "http", NULL
,
129 getenv("SERVER_NAME"), port
, "/%s/%s",
130 cgiGetVariable("IS_CLASS") ? "classes" : "printers",
133 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
134 getenv("HTTPS") ? "https" : "http", NULL
,
135 getenv("SERVER_NAME"), port
, "/admin");
137 printf("Location: %s\n\n", uri
);
139 else if (!strcmp(op
, "set-allowed-users"))
140 do_set_allowed_users(http
);
141 else if (!strcmp(op
, "set-as-default"))
142 do_set_default(http
);
143 else if (!strcmp(op
, "set-sharing"))
144 do_set_sharing(http
);
145 else if (!strcmp(op
, "find-new-printers") ||
146 !strcmp(op
, "list-available-printers"))
147 do_list_printers(http
);
148 else if (!strcmp(op
, "add-class"))
149 do_am_class(http
, 0);
150 else if (!strcmp(op
, "add-printer"))
151 do_am_printer(http
, 0);
152 else if (!strcmp(op
, "modify-class"))
153 do_am_class(http
, 1);
154 else if (!strcmp(op
, "modify-printer"))
155 do_am_printer(http
, 1);
156 else if (!strcmp(op
, "delete-class"))
157 do_delete_class(http
);
158 else if (!strcmp(op
, "delete-printer"))
159 do_delete_printer(http
);
160 else if (!strcmp(op
, "set-class-options"))
161 do_set_options(http
, 1);
162 else if (!strcmp(op
, "set-printer-options"))
163 do_set_options(http
, 0);
164 else if (!strcmp(op
, "config-server"))
165 do_config_server(http
);
169 * Bad operation code - display an error...
172 cgiStartHTML(cgiText(_("Administration")));
173 cgiCopyTemplateLang("error-op.tmpl");
177 else if (op
&& !strcmp(op
, "redirect"))
179 const char *url
; /* Redirection URL... */
180 char prefix
[1024]; /* URL prefix */
184 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
185 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
187 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
188 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
190 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
192 if ((url
= cgiGetVariable("URL")) != NULL
)
194 char encoded
[1024], /* Encoded URL string */
195 *ptr
; /* Pointer into encoded string */
202 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
204 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
207 * Percent-encode this character; safe because we have at least 4
208 * bytes left in the array...
211 snprintf(ptr
, sizeof(encoded
) - (size_t)(ptr
- encoded
), "%%%02X", *url
& 255);
223 * URL was too long, just redirect to the admin page...
226 printf("Location: %s/admin\n\n", prefix
);
231 * URL is OK, redirect there...
234 printf("Location: %s%s\n\n", prefix
, encoded
);
238 printf("Location: %s/admin\n\n", prefix
);
243 * Form data but no operation code - display an error...
246 cgiStartHTML(cgiText(_("Administration")));
247 cgiCopyTemplateLang("error-op.tmpl");
252 * Close the HTTP server connection...
258 * Return with no errors...
266 * 'choose_device_cb()' - Add a device to the device selection page.
271 const char *device_class
, /* I - Class */
272 const char *device_id
, /* I - 1284 device ID */
273 const char *device_info
, /* I - Description */
274 const char *device_make_and_model
, /* I - Make and model */
275 const char *device_uri
, /* I - Device URI */
276 const char *device_location
, /* I - Location */
277 const char *title
) /* I - Page title */
280 * For modern browsers, start a multi-part page so we can show that something
281 * is happening. Non-modern browsers just get everything at the end...
284 if (current_device
== 0 && cgiSupportsMultipart())
288 cgiCopyTemplateLang("choose-device.tmpl");
295 * Add the device to the array...
298 cgiSetArray("device_class", current_device
, device_class
);
299 cgiSetArray("device_id", current_device
, device_id
);
300 cgiSetArray("device_info", current_device
, device_info
);
301 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
302 cgiSetArray("device_uri", current_device
, device_uri
);
303 cgiSetArray("device_location", current_device
, device_location
);
310 * 'do_am_class()' - Add or modify a class.
314 do_am_class(http_t
*http
, /* I - HTTP connection */
315 int modify
) /* I - Modify the printer? */
317 int i
, j
; /* Looping vars */
318 int element
; /* Element number */
319 int num_printers
; /* Number of printers */
320 ipp_t
*request
, /* IPP request */
321 *response
; /* IPP response */
322 ipp_attribute_t
*attr
; /* member-uris attribute */
323 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
324 const char *name
, /* Pointer to class name */
325 *op
, /* Operation name */
326 *ptr
; /* Pointer to CGI variable */
327 const char *title
; /* Title of page */
328 static const char * const pattrs
[] = /* Requested printer attributes */
336 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
337 op
= cgiGetVariable("OP");
338 name
= cgiGetVariable("PRINTER_NAME");
340 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
343 * Build a CUPS_GET_PRINTERS request, which requires the
344 * following attributes:
347 * attributes-natural-language
350 request
= ippNewRequest(CUPS_GET_PRINTERS
);
352 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
354 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
355 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
358 * Do the request and get back a response...
363 cgiSetVariable("OP", op
);
365 cgiSetVariable("PRINTER_NAME", name
);
367 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
370 * Create MEMBER_URIS and MEMBER_NAMES arrays...
373 for (element
= 0, attr
= response
->attrs
;
376 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
378 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
379 (!name
|| _cups_strcasecmp(name
, ptr
+ 1)))
382 * Don't show the current class...
385 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
390 for (element
= 0, attr
= response
->attrs
;
393 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
395 if (!name
|| _cups_strcasecmp(name
, attr
->values
[0].string
.text
))
398 * Don't show the current class...
401 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
406 num_printers
= cgiGetSize("MEMBER_URIS");
416 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
417 * following attributes:
420 * attributes-natural-language
424 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
426 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
427 "localhost", 0, "/classes/%s", name
);
428 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
431 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
432 "requested-attributes",
433 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
437 * Do the request and get back a response...
440 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
442 if ((attr
= ippFindAttribute(response
, "member-names",
443 IPP_TAG_NAME
)) != NULL
)
446 * Mark any current members in the class...
449 for (j
= 0; j
< num_printers
; j
++)
450 cgiSetArray("MEMBER_SELECTED", j
, "");
452 for (i
= 0; i
< attr
->num_values
; i
++)
454 for (j
= 0; j
< num_printers
; j
++)
456 if (!_cups_strcasecmp(attr
->values
[i
].string
.text
,
457 cgiGetArray("MEMBER_NAMES", j
)))
459 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
466 if ((attr
= ippFindAttribute(response
, "printer-info",
467 IPP_TAG_TEXT
)) != NULL
)
468 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
470 if ((attr
= ippFindAttribute(response
, "printer-location",
471 IPP_TAG_TEXT
)) != NULL
)
472 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
478 * Update the location and description of an existing printer...
482 cgiCopyTemplateLang("modify-class.tmpl");
487 * Get the name, location, and description for a new printer...
491 cgiCopyTemplateLang("add-class.tmpl");
502 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
503 cgiCopyTemplateLang("error.tmpl");
508 for (ptr
= name
; *ptr
; ptr
++)
509 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
512 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
514 cgiSetVariable("ERROR",
515 cgiText(_("The class name may only contain up to "
516 "127 printable characters and may not "
517 "contain spaces, slashes (/), or the "
518 "pound sign (#).")));
520 cgiCopyTemplateLang("error.tmpl");
526 * Build a CUPS_ADD_CLASS request, which requires the following
530 * attributes-natural-language
534 * printer-is-accepting-jobs
539 request
= ippNewRequest(CUPS_ADD_CLASS
);
541 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
542 "localhost", 0, "/classes/%s", name
);
543 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
546 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
547 NULL
, cgiGetVariable("PRINTER_LOCATION"));
549 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
550 NULL
, cgiGetVariable("PRINTER_INFO"));
552 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
554 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
557 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
559 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
560 num_printers
, NULL
, NULL
);
561 for (i
= 0; i
< num_printers
; i
++)
562 ippSetString(request
, &attr
, i
, cgiGetArray("MEMBER_URIS", i
));
566 * Do the request and get back a response...
569 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
571 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
573 puts("Status: 401\n");
576 else if (cupsLastError() > IPP_OK_CONFLICT
)
579 cgiShowIPPError(modify
? _("Unable to modify class") :
580 _("Unable to add class"));
585 * Redirect successful updates back to the class page...
588 char refresh
[1024]; /* Refresh URL */
590 cgiFormEncode(uri
, name
, sizeof(uri
));
591 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
593 cgiSetVariable("refresh_page", refresh
);
598 cgiCopyTemplateLang("class-modified.tmpl");
600 cgiCopyTemplateLang("class-added.tmpl");
608 * 'do_am_printer()' - Add or modify a printer.
612 do_am_printer(http_t
*http
, /* I - HTTP connection */
613 int modify
) /* I - Modify the printer? */
615 int i
; /* Looping var */
616 ipp_attribute_t
*attr
; /* Current attribute */
617 ipp_t
*request
, /* IPP request */
618 *response
, /* IPP response */
619 *oldinfo
; /* Old printer information */
620 const cgi_file_t
*file
; /* Uploaded file, if any */
621 const char *var
; /* CGI variable */
622 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
623 *uriptr
, /* Pointer into URI */
624 evefile
[1024] = ""; /* IPP Everywhere PPD file */
625 int maxrate
; /* Maximum baud rate */
626 char baudrate
[255]; /* Baud rate string */
627 const char *name
, /* Pointer to class name */
628 *ptr
; /* Pointer to CGI variable */
629 const char *title
; /* Title of page */
630 static int baudrates
[] = /* Baud rates */
645 ptr
= cgiGetVariable("DEVICE_URI");
646 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
647 ptr
? ptr
: "(null)");
649 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
654 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
655 * following attributes:
658 * attributes-natural-language
662 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
664 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
665 "localhost", 0, "/printers/%s",
666 cgiGetVariable("PRINTER_NAME"));
667 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
671 * Do the request and get back a response...
674 oldinfo
= cupsDoRequest(http
, request
, "/");
683 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
684 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
685 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
686 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
689 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
691 for (ptr
= name
; *ptr
; ptr
++)
692 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '\\' || *ptr
== '?' || *ptr
== '\'' || *ptr
== '\"' || *ptr
== '#')
695 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
697 cgiSetVariable("ERROR",
698 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 (#).")));
700 cgiCopyTemplateLang("error.tmpl");
706 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
708 if ((uriptr
= strrchr(var
, '|')) != NULL
)
711 * Extract make and make/model from device URI string...
714 char make
[1024], /* Make string */
715 *makeptr
; /* Pointer into make */
720 strlcpy(make
, uriptr
, sizeof(make
));
722 if ((makeptr
= strchr(make
, ' ')) != NULL
)
724 else if ((makeptr
= strchr(make
, '-')) != NULL
)
726 else if (!_cups_strncasecmp(make
, "laserjet", 8) ||
727 !_cups_strncasecmp(make
, "deskjet", 7) ||
728 !_cups_strncasecmp(make
, "designjet", 9))
729 strlcpy(make
, "HP", sizeof(make
));
730 else if (!_cups_strncasecmp(make
, "phaser", 6))
731 strlcpy(make
, "Xerox", sizeof(make
));
732 else if (!_cups_strncasecmp(make
, "stylus", 6))
733 strlcpy(make
, "Epson", sizeof(make
));
735 strlcpy(make
, "Generic", sizeof(make
));
737 if (!cgiGetVariable("CURRENT_MAKE"))
738 cgiSetVariable("CURRENT_MAKE", make
);
740 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
741 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
745 char template[128], /* Template name */
746 *tptr
; /* Pointer into template name */
748 cgiSetVariable("PRINTER_INFO", uriptr
);
750 for (tptr
= template;
751 tptr
< (template + sizeof(template) - 1) && *uriptr
;
753 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
756 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
759 else if (*uriptr
== '?' || *uriptr
== '(')
764 cgiSetVariable("TEMPLATE_NAME", template);
768 * Set DEVICE_URI to the actual device uri, without make and model from
772 cgiSetVariable("DEVICE_URI", var
);
779 * Look for devices so the user can pick something...
782 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
784 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
785 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
788 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
789 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
793 * Scan for devices for up to 30 seconds...
796 fputs("DEBUG: Getting list of devices...\n", stderr
);
799 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
800 (cups_device_cb_t
)choose_device_cb
,
801 (void *)title
) == IPP_OK
)
803 fputs("DEBUG: Got device list!\n", stderr
);
805 if (cgiSupportsMultipart())
808 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
810 cgiCopyTemplateLang("choose-device.tmpl");
813 if (cgiSupportsMultipart())
819 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
820 cupsLastError(), cupsLastErrorString());
821 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
823 puts("Status: 401\n");
829 cgiShowIPPError(modify
? _("Unable to modify printer") :
830 _("Unable to add printer"));
836 else if (!strchr(var
, '/') ||
837 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
839 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
842 * Set the current device URI for the form to the old one...
845 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
846 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
850 * User needs to set the full URI...
854 cgiCopyTemplateLang("choose-uri.tmpl");
857 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
860 * Need baud rate, parity, etc.
863 if ((var
= strchr(var
, '?')) != NULL
&&
864 strncmp(var
, "?baud=", 6) == 0)
865 maxrate
= atoi(var
+ 6);
869 for (i
= 0; i
< 10; i
++)
870 if (baudrates
[i
] > maxrate
)
874 snprintf(baudrate
, sizeof(baudrate
), "%d", baudrates
[i
]);
875 cgiSetArray("BAUDRATES", i
, baudrate
);
879 cgiCopyTemplateLang("choose-serial.tmpl");
882 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
889 * Update the location and description of an existing printer...
894 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
895 IPP_TAG_TEXT
)) != NULL
)
896 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
898 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
899 IPP_TAG_TEXT
)) != NULL
)
900 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
902 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
903 IPP_TAG_BOOLEAN
)) != NULL
)
904 cgiSetVariable("PRINTER_IS_SHARED",
905 attr
->values
[0].boolean
? "1" : "0");
908 cgiCopyTemplateLang("modify-printer.tmpl");
913 * Get the name, location, and description for a new printer...
917 if (!strncmp(var
, "usb:", 4))
918 cgiSetVariable("printer_is_shared", "1");
920 #endif /* __APPLE__ */
921 cgiSetVariable("printer_is_shared", "0");
923 cgiCopyTemplateLang("add-printer.tmpl");
934 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
936 int ipp_everywhere
= !strncmp(var
, "ipp://", 6) || !strncmp(var
, "ipps://", 7) || (!strncmp(var
, "dnssd://", 8) && (strstr(var
, "_ipp._tcp") || strstr(var
, "_ipps._tcp")));
938 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
941 * Get the PPD file...
944 int fd
; /* PPD file */
945 char filename
[1024]; /* PPD filename */
946 ppd_file_t
*ppd
; /* PPD information */
947 char buffer
[1024]; /* Buffer */
948 ssize_t bytes
; /* Number of bytes */
949 http_status_t get_status
; /* Status of GET */
952 /* TODO: Use cupsGetFile() API... */
953 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
955 if (httpGet(http
, uri
))
958 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
960 if (get_status
!= HTTP_OK
)
964 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
965 uri
, get_status
, httpStatus(get_status
));
967 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
969 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
970 write(fd
, buffer
, (size_t)bytes
);
974 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
976 if (ppd
->manufacturer
)
977 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
980 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
987 int linenum
; /* Line number */
989 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
990 filename
, ppdErrorString(ppdLastError(&linenum
)));
998 "ERROR: Unable to create temporary file for PPD file: %s\n",
1004 * Build a CUPS_GET_PPDS request, which requires the following
1007 * attributes-charset
1008 * attributes-natural-language
1012 request
= ippNewRequest(CUPS_GET_PPDS
);
1014 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1015 NULL
, "ipp://localhost/printers/");
1017 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1018 var
= cgiGetVariable("CURRENT_MAKE");
1019 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1021 const char *make_model
; /* Make and model */
1024 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1025 "ppd-make", NULL
, var
);
1027 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1028 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1029 "ppd-make-and-model", NULL
, make_model
);
1032 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1033 "requested-attributes", NULL
, "ppd-make");
1036 * Do the request and get back a response...
1039 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1042 * Got the list of PPDs, see if the user has selected a make...
1045 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1048 * No PPD files with this make, try again with all makes...
1051 ippDelete(response
);
1053 request
= ippNewRequest(CUPS_GET_PPDS
);
1055 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1056 NULL
, "ipp://localhost/printers/");
1058 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1059 "requested-attributes", NULL
, "ppd-make");
1061 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1062 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1064 cgiStartHTML(title
);
1065 cgiCopyTemplateLang("choose-make.tmpl");
1068 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1070 cgiStartHTML(title
);
1071 cgiCopyTemplateLang("choose-make.tmpl");
1077 * Let the user choose a model...
1080 cgiStartHTML(title
);
1081 if (!cgiGetVariable("PPD_MAKE"))
1082 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1084 cgiSetVariable("SHOW_IPP_EVERYWHERE", "1");
1085 cgiCopyTemplateLang("choose-model.tmpl");
1089 ippDelete(response
);
1093 cgiStartHTML(title
);
1094 cgiShowIPPError(_("Unable to get list of printer drivers"));
1095 cgiCopyTemplateLang("error.tmpl");
1102 * Build a CUPS_ADD_PRINTER request, which requires the following
1105 * attributes-charset
1106 * attributes-natural-language
1112 * printer-is-accepting-jobs
1117 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1119 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1120 "localhost", 0, "/printers/%s",
1121 cgiGetVariable("PRINTER_NAME"));
1122 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1127 var
= cgiGetVariable("PPD_NAME");
1128 if (!strcmp(var
, "everywhere"))
1129 get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile
, sizeof(evefile
));
1130 else if (strcmp(var
, "__no_change__"))
1131 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name",
1135 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1136 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1138 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1139 NULL
, cgiGetVariable("PRINTER_INFO"));
1141 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1144 * Strip make and model from URI...
1147 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1150 if (!strncmp(uri
, "serial:", 7))
1153 * Update serial port URI to include baud rate, etc.
1156 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1157 uriptr
= uri
+ strlen(uri
);
1159 snprintf(uriptr
, sizeof(uri
) - (size_t)(uriptr
- uri
),
1160 "?baud=%s+bits=%s+parity=%s+flow=%s",
1161 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1162 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1165 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1168 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1170 var
= cgiGetVariable("printer_is_shared");
1171 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1172 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1174 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1178 * Do the request and get back a response...
1182 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1183 else if (evefile
[0])
1185 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", evefile
));
1189 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1191 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1193 puts("Status: 401\n");
1196 else if (cupsLastError() > IPP_OK_CONFLICT
)
1198 cgiStartHTML(title
);
1199 cgiShowIPPError(modify
? _("Unable to modify printer") :
1200 _("Unable to add printer"));
1205 * Redirect successful updates back to the printer page...
1208 char refresh
[1024]; /* Refresh URL */
1211 cgiFormEncode(uri
, name
, sizeof(uri
));
1213 snprintf(refresh
, sizeof(refresh
),
1214 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1216 cgiSetVariable("refresh_page", refresh
);
1218 cgiStartHTML(title
);
1220 cgiCopyTemplateLang("printer-modified.tmpl");
1225 * Set the printer options...
1228 cgiSetVariable("OP", "set-printer-options");
1229 do_set_options(http
, 0);
1242 * 'do_config_server()' - Configure server settings.
1246 do_config_server(http_t
*http
) /* I - HTTP connection */
1248 if (cgiGetVariable("CHANGESETTINGS"))
1251 * Save basic setting changes...
1254 int num_settings
; /* Number of server settings */
1255 cups_option_t
*settings
; /* Server settings */
1256 int advanced
, /* Advanced settings shown? */
1257 changed
; /* Have settings changed? */
1258 const char *debug_logging
, /* DEBUG_LOGGING value */
1259 *preserve_jobs
= NULL
,
1260 /* PRESERVE_JOBS value */
1261 *remote_admin
, /* REMOTE_ADMIN value */
1262 *remote_any
, /* REMOTE_ANY value */
1263 *share_printers
,/* SHARE_PRINTERS value */
1265 /* USER_CANCEL_ANY value */
1266 *browse_web_if
= NULL
,
1267 /* BrowseWebIF value */
1268 *preserve_job_history
= NULL
,
1269 /* PreserveJobHistory value */
1270 *preserve_job_files
= NULL
,
1271 /* PreserveJobFiles value */
1272 *max_clients
= NULL
,
1273 /* MaxClients value */
1276 *max_log_size
= NULL
;
1277 /* MaxLogSize value */
1278 const char *current_browse_web_if
,
1279 /* BrowseWebIF value */
1280 *current_preserve_job_history
,
1281 /* PreserveJobHistory value */
1282 *current_preserve_job_files
,
1283 /* PreserveJobFiles value */
1284 *current_max_clients
,
1285 /* MaxClients value */
1288 *current_max_log_size
;
1289 /* MaxLogSize value */
1291 char default_auth_type
[255];
1292 /* DefaultAuthType value */
1293 const char *val
; /* Setting value */
1294 #endif /* HAVE_GSSAPI */
1298 * Get the checkbox values from the form...
1301 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1302 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1303 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1304 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1305 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1307 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1311 * Get advanced settings...
1314 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1315 max_clients
= cgiGetVariable("MAX_CLIENTS");
1316 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1317 preserve_jobs
= cgiGetVariable("PRESERVE_JOBS");
1321 max_jobs
= cgiGetVariable("MAX_JOBS");
1322 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY");
1323 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES");
1325 if (!max_jobs
|| atoi(max_jobs
) < 0)
1328 if (!preserve_job_history
)
1329 preserve_job_history
= "On";
1331 if (!preserve_job_files
)
1332 preserve_job_files
= "1d";
1337 preserve_job_history
= "No";
1338 preserve_job_files
= "No";
1341 if (!max_clients
|| atoi(max_clients
) <= 0)
1342 max_clients
= "100";
1344 if (!max_log_size
|| atoi(max_log_size
) <= 0.0)
1345 max_log_size
= "1m";
1349 * Get the current server settings...
1352 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1354 cgiStartHTML(cgiText(_("Change Settings")));
1355 cgiSetVariable("MESSAGE",
1356 cgiText(_("Unable to change server settings")));
1357 cgiSetVariable("ERROR", cupsLastErrorString());
1358 cgiCopyTemplateLang("error.tmpl");
1365 * Get authentication settings...
1368 if (cgiGetVariable("KERBEROS"))
1369 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1372 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1374 if (!val
|| !_cups_strcasecmp(val
, "Negotiate"))
1375 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1377 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1380 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1381 #endif /* HAVE_GSSAPI */
1383 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1385 current_browse_web_if
= "No";
1387 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1390 current_preserve_job_history
= "Yes";
1392 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1395 current_preserve_job_files
= "1d";
1397 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1399 current_max_clients
= "100";
1401 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1403 current_max_jobs
= "500";
1405 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1407 current_max_log_size
= "1m";
1410 * See if the settings have changed...
1413 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1414 num_settings
, settings
)) ||
1415 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1416 num_settings
, settings
)) ||
1417 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1418 num_settings
, settings
)) ||
1419 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1420 num_settings
, settings
)) ||
1422 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1423 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1424 num_settings
, settings
)) ||
1425 #endif /* HAVE_GSSAPI */
1426 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1427 num_settings
, settings
));
1429 if (advanced
&& !changed
)
1430 changed
= _cups_strcasecmp(browse_web_if
, current_browse_web_if
) ||
1431 _cups_strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1432 _cups_strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1433 _cups_strcasecmp(max_clients
, current_max_clients
) ||
1434 _cups_strcasecmp(max_jobs
, current_max_jobs
) ||
1435 _cups_strcasecmp(max_log_size
, current_max_log_size
);
1440 * Settings *have* changed, so save the changes...
1443 cupsFreeOptions(num_settings
, settings
);
1446 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1447 debug_logging
, num_settings
, &settings
);
1448 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1449 remote_admin
, num_settings
, &settings
);
1450 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1451 remote_any
, num_settings
, &settings
);
1452 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1453 share_printers
, num_settings
, &settings
);
1454 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1455 user_cancel_any
, num_settings
, &settings
);
1457 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1458 num_settings
, &settings
);
1459 #endif /* HAVE_GSSAPI */
1464 * Add advanced settings...
1467 if (_cups_strcasecmp(browse_web_if
, current_browse_web_if
))
1468 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1469 num_settings
, &settings
);
1470 if (_cups_strcasecmp(preserve_job_history
, current_preserve_job_history
))
1471 num_settings
= cupsAddOption("PreserveJobHistory",
1472 preserve_job_history
, num_settings
,
1474 if (_cups_strcasecmp(preserve_job_files
, current_preserve_job_files
))
1475 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1476 num_settings
, &settings
);
1477 if (_cups_strcasecmp(max_clients
, current_max_clients
))
1478 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1480 if (_cups_strcasecmp(max_jobs
, current_max_jobs
))
1481 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1483 if (_cups_strcasecmp(max_log_size
, current_max_log_size
))
1484 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1488 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1490 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1492 puts("Status: 401\n");
1496 cgiStartHTML(cgiText(_("Change Settings")));
1497 cgiSetVariable("MESSAGE",
1498 cgiText(_("Unable to change server settings")));
1499 cgiSetVariable("ERROR", cupsLastErrorString());
1500 cgiCopyTemplateLang("error.tmpl");
1505 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1506 "URL=/admin/?ADVANCEDSETTINGS=YES");
1508 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1509 cgiStartHTML(cgiText(_("Change Settings")));
1510 cgiCopyTemplateLang("restart.tmpl");
1519 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1520 cgiStartHTML(cgiText(_("Change Settings")));
1521 cgiCopyTemplateLang("norestart.tmpl");
1524 cupsFreeOptions(num_settings
, settings
);
1528 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1531 * Save hand-edited config file...
1534 http_status_t status
; /* PUT status */
1535 char tempfile
[1024]; /* Temporary new cupsd.conf */
1536 int tempfd
; /* Temporary file descriptor */
1537 cups_file_t
*temp
; /* Temporary file */
1538 const char *start
, /* Start of line */
1539 *end
; /* End of line */
1543 * Create a temporary file for the new cupsd.conf file...
1546 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1548 cgiStartHTML(cgiText(_("Edit Configuration File")));
1549 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1550 cgiSetVariable("ERROR", strerror(errno
));
1551 cgiCopyTemplateLang("error.tmpl");
1558 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1560 cgiStartHTML(cgiText(_("Edit Configuration File")));
1561 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1562 cgiSetVariable("ERROR", strerror(errno
));
1563 cgiCopyTemplateLang("error.tmpl");
1573 * Copy the cupsd.conf text from the form variable...
1576 start
= cgiGetVariable("CUPSDCONF");
1579 if ((end
= strstr(start
, "\r\n")) == NULL
)
1580 if ((end
= strstr(start
, "\n")) == NULL
)
1581 end
= start
+ strlen(start
);
1583 cupsFileWrite(temp
, start
, (size_t)(end
- start
));
1584 cupsFilePutChar(temp
, '\n');
1588 else if (*end
== '\n')
1594 cupsFileClose(temp
);
1597 * Upload the configuration file to the server...
1600 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1602 if (status
== HTTP_UNAUTHORIZED
)
1604 puts("Status: 401\n");
1608 else if (status
!= HTTP_CREATED
)
1610 cgiSetVariable("MESSAGE",
1611 cgiText(_("Unable to upload cupsd.conf file")));
1612 cgiSetVariable("ERROR", httpStatus(status
));
1614 cgiStartHTML(cgiText(_("Edit Configuration File")));
1615 cgiCopyTemplateLang("error.tmpl");
1619 cgiSetVariable("refresh_page", "5;URL=/admin/");
1621 cgiStartHTML(cgiText(_("Edit Configuration File")));
1622 cgiCopyTemplateLang("restart.tmpl");
1631 struct stat info
; /* cupsd.conf information */
1632 cups_file_t
*cupsd
; /* cupsd.conf file */
1633 char *buffer
, /* Buffer for entire file */
1634 *bufptr
, /* Pointer into buffer */
1635 *bufend
; /* End of buffer */
1636 int ch
; /* Character from file */
1637 char filename
[1024]; /* Filename */
1638 const char *server_root
; /* Location of config files */
1642 * Locate the cupsd.conf file...
1645 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1646 server_root
= CUPS_SERVERROOT
;
1648 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1651 * Figure out the size...
1654 if (stat(filename
, &info
))
1656 cgiStartHTML(cgiText(_("Edit Configuration File")));
1657 cgiSetVariable("MESSAGE",
1658 cgiText(_("Unable to access cupsd.conf file")));
1659 cgiSetVariable("ERROR", strerror(errno
));
1660 cgiCopyTemplateLang("error.tmpl");
1667 if (info
.st_size
> (1024 * 1024))
1669 cgiStartHTML(cgiText(_("Edit Configuration File")));
1670 cgiSetVariable("MESSAGE",
1671 cgiText(_("Unable to access cupsd.conf file")));
1672 cgiSetVariable("ERROR",
1673 cgiText(_("Unable to edit cupsd.conf files larger than "
1675 cgiCopyTemplateLang("error.tmpl");
1678 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1679 (long)info
.st_size
);
1684 * Open the cupsd.conf file...
1687 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1690 * Unable to open - log an error...
1693 cgiStartHTML(cgiText(_("Edit Configuration File")));
1694 cgiSetVariable("MESSAGE",
1695 cgiText(_("Unable to access cupsd.conf file")));
1696 cgiSetVariable("ERROR", strerror(errno
));
1697 cgiCopyTemplateLang("error.tmpl");
1705 * Allocate memory and load the file into a string buffer...
1708 if ((buffer
= calloc(1, (size_t)info
.st_size
+ 1)) != NULL
)
1710 cupsFileRead(cupsd
, buffer
, (size_t)info
.st_size
);
1711 cgiSetVariable("CUPSDCONF", buffer
);
1715 cupsFileClose(cupsd
);
1718 * Then get the default cupsd.conf file and put that into a string as
1722 strlcat(filename
, ".default", sizeof(filename
));
1724 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1725 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1727 if ((buffer
= calloc(1, 2 * (size_t)info
.st_size
+ 1)) != NULL
)
1729 bufend
= buffer
+ 2 * info
.st_size
- 1;
1731 for (bufptr
= buffer
;
1732 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1734 if (ch
== '\\' || ch
== '\"')
1737 *bufptr
++ = (char)ch
;
1739 else if (ch
== '\n')
1744 else if (ch
== '\t')
1750 *bufptr
++ = (char)ch
;
1755 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1759 cupsFileClose(cupsd
);
1763 * Show the current config file...
1766 cgiStartHTML(cgiText(_("Edit Configuration File")));
1768 cgiCopyTemplateLang("edit-config.tmpl");
1776 * 'do_delete_class()' - Delete a class.
1780 do_delete_class(http_t
*http
) /* I - HTTP connection */
1782 ipp_t
*request
; /* IPP request */
1783 char uri
[HTTP_MAX_URI
]; /* Job URI */
1784 const char *pclass
; /* Printer class name */
1788 * Get form variables...
1791 if (cgiGetVariable("CONFIRM") == NULL
)
1793 cgiStartHTML(cgiText(_("Delete Class")));
1794 cgiCopyTemplateLang("class-confirm.tmpl");
1799 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1800 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1801 "localhost", 0, "/classes/%s", pclass
);
1804 cgiStartHTML(cgiText(_("Delete Class")));
1805 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1806 cgiCopyTemplateLang("error.tmpl");
1812 * Build a CUPS_DELETE_CLASS request, which requires the following
1815 * attributes-charset
1816 * attributes-natural-language
1820 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1822 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1826 * Do the request and get back a response...
1829 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1832 * Show the results...
1835 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1837 puts("Status: 401\n");
1840 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1843 * Redirect successful updates back to the classes page...
1846 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1849 cgiStartHTML(cgiText(_("Delete Class")));
1851 if (cupsLastError() > IPP_OK_CONFLICT
)
1852 cgiShowIPPError(_("Unable to delete class"));
1854 cgiCopyTemplateLang("class-deleted.tmpl");
1861 * 'do_delete_printer()' - Delete a printer.
1865 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1867 ipp_t
*request
; /* IPP request */
1868 char uri
[HTTP_MAX_URI
]; /* Job URI */
1869 const char *printer
; /* Printer printer name */
1873 * Get form variables...
1876 if (cgiGetVariable("CONFIRM") == NULL
)
1878 cgiStartHTML(cgiText(_("Delete Printer")));
1879 cgiCopyTemplateLang("printer-confirm.tmpl");
1884 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1885 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1886 "localhost", 0, "/printers/%s", printer
);
1889 cgiStartHTML(cgiText(_("Delete Printer")));
1890 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1891 cgiCopyTemplateLang("error.tmpl");
1897 * Build a CUPS_DELETE_PRINTER request, which requires the following
1900 * attributes-charset
1901 * attributes-natural-language
1905 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1907 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1911 * Do the request and get back a response...
1914 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1917 * Show the results...
1920 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1922 puts("Status: 401\n");
1925 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1928 * Redirect successful updates back to the printers page...
1931 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1934 cgiStartHTML(cgiText(_("Delete Printer")));
1936 if (cupsLastError() > IPP_OK_CONFLICT
)
1937 cgiShowIPPError(_("Unable to delete printer"));
1939 cgiCopyTemplateLang("printer-deleted.tmpl");
1946 * 'do_list_printers()' - List available printers.
1950 do_list_printers(http_t
*http
) /* I - HTTP connection */
1952 ipp_t
*request
, /* IPP request */
1953 *response
; /* IPP response */
1954 ipp_attribute_t
*attr
; /* IPP attribute */
1957 cgiStartHTML(cgiText(_("List Available Printers")));
1961 * Get the list of printers and their devices...
1964 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1966 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1967 "requested-attributes", NULL
, "device-uri");
1969 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
1970 CUPS_PRINTER_LOCAL
);
1971 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
1972 CUPS_PRINTER_LOCAL
);
1974 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1977 * Got the printer list, now load the devices...
1980 int i
; /* Looping var */
1981 cups_array_t
*printer_devices
; /* Printer devices for local printers */
1982 char *printer_device
; /* Current printer device */
1986 * Allocate an array and copy the device strings...
1989 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
1991 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
1993 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
1995 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
1999 * Free the printer list and get the device list...
2002 ippDelete(response
);
2004 request
= ippNewRequest(CUPS_GET_DEVICES
);
2006 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2009 * Got the device list, let's parse it...
2012 const char *device_uri
, /* device-uri attribute value */
2013 *device_make_and_model
, /* device-make-and-model value */
2014 *device_info
; /* device-info value */
2017 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2020 * Skip leading attributes until we hit a device...
2023 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2030 * Pull the needed attributes from this device...
2034 device_make_and_model
= NULL
;
2037 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2039 if (!strcmp(attr
->name
, "device-info") &&
2040 attr
->value_tag
== IPP_TAG_TEXT
)
2041 device_info
= attr
->values
[0].string
.text
;
2043 if (!strcmp(attr
->name
, "device-make-and-model") &&
2044 attr
->value_tag
== IPP_TAG_TEXT
)
2045 device_make_and_model
= attr
->values
[0].string
.text
;
2047 if (!strcmp(attr
->name
, "device-uri") &&
2048 attr
->value_tag
== IPP_TAG_URI
)
2049 device_uri
= attr
->values
[0].string
.text
;
2055 * See if we have everything needed...
2058 if (device_info
&& device_make_and_model
&& device_uri
&&
2059 _cups_strcasecmp(device_make_and_model
, "unknown") &&
2060 strchr(device_uri
, ':'))
2063 * Yes, now see if there is already a printer for this
2067 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2070 * Not found, so it must be a new printer...
2073 char option
[1024], /* Form variables for this device */
2074 *option_ptr
; /* Pointer into string */
2075 const char *ptr
; /* Pointer into device string */
2079 * Format the printer name variable for this device...
2081 * We use the device-info string first, then device-uri,
2082 * and finally device-make-and-model to come up with a
2086 if (_cups_strncasecmp(device_info
, "unknown", 7))
2088 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2091 ptr
= device_make_and_model
;
2093 for (option_ptr
= option
;
2094 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2096 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2098 *option_ptr
++ = *ptr
;
2099 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2100 option_ptr
[-1] != '_')
2101 *option_ptr
++ = '_';
2102 else if (*ptr
== '?' || *ptr
== '(')
2107 cgiSetArray("TEMPLATE_NAME", i
, option
);
2110 * Finally, set the form variables for this printer...
2113 cgiSetArray("device_info", i
, device_info
);
2114 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2115 cgiSetArray("device_uri", i
, device_uri
);
2124 ippDelete(response
);
2127 * Free the device list...
2130 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2132 printer_device
= (char *)cupsArrayNext(printer_devices
))
2133 free(printer_device
);
2135 cupsArrayDelete(printer_devices
);
2140 * Finally, show the printer list...
2143 cgiCopyTemplateLang("list-available-printers.tmpl");
2150 * 'do_menu()' - Show the main menu.
2154 do_menu(http_t
*http
) /* I - HTTP connection */
2156 int num_settings
; /* Number of server settings */
2157 cups_option_t
*settings
; /* Server settings */
2158 const char *val
; /* Setting value */
2162 * Get the current server settings...
2165 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2167 cgiSetVariable("SETTINGS_MESSAGE",
2168 cgiText(_("Unable to open cupsd.conf file:")));
2169 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2172 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2173 settings
)) != NULL
&& atoi(val
))
2174 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2176 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2177 settings
)) != NULL
&& atoi(val
))
2178 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2180 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2181 settings
)) != NULL
&& atoi(val
))
2182 cgiSetVariable("REMOTE_ANY", "CHECKED");
2184 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2185 settings
)) != NULL
&& atoi(val
))
2186 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2188 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2189 settings
)) != NULL
&& atoi(val
))
2190 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2193 cgiSetVariable("HAVE_GSSAPI", "1");
2195 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2196 settings
)) != NULL
&& !_cups_strcasecmp(val
, "Negotiate"))
2197 cgiSetVariable("KERBEROS", "CHECKED");
2199 #endif /* HAVE_GSSAPI */
2200 cgiSetVariable("KERBEROS", "");
2202 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2206 if (!_cups_strcasecmp(val
, "yes") || !_cups_strcasecmp(val
, "on") ||
2207 !_cups_strcasecmp(val
, "true"))
2208 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2210 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2215 (!_cups_strcasecmp(val
, "0") || !_cups_strcasecmp(val
, "no") ||
2216 !_cups_strcasecmp(val
, "off") || !_cups_strcasecmp(val
, "false") ||
2217 !_cups_strcasecmp(val
, "disabled")))
2219 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2220 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2224 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2225 cgiSetVariable("PRESERVE_JOB_HISTORY", val
);
2227 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2231 cgiSetVariable("PRESERVE_JOB_FILES", val
);
2235 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2238 cgiSetVariable("MAX_CLIENTS", val
);
2240 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2243 cgiSetVariable("MAX_JOBS", val
);
2245 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2248 cgiSetVariable("MAX_LOG_SIZE", val
);
2250 cupsFreeOptions(num_settings
, settings
);
2253 * Finally, show the main menu template...
2256 cgiStartHTML(cgiText(_("Administration")));
2258 cgiCopyTemplateLang("admin.tmpl");
2265 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2269 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2271 int i
; /* Looping var */
2272 ipp_t
*request
, /* IPP request */
2273 *response
; /* IPP response */
2274 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2275 const char *printer
, /* Printer name (purge-jobs) */
2276 *is_class
, /* Is a class? */
2277 *users
, /* List of users or groups */
2278 *type
; /* Allow/deny type */
2279 int num_users
; /* Number of users */
2280 char *ptr
, /* Pointer into users string */
2281 *end
, /* Pointer to end of users string */
2282 quote
; /* Quote character */
2283 ipp_attribute_t
*attr
; /* Attribute */
2284 static const char * const attrs
[] = /* Requested attributes */
2286 "requesting-user-name-allowed",
2287 "requesting-user-name-denied"
2291 is_class
= cgiGetVariable("IS_CLASS");
2292 printer
= cgiGetVariable("PRINTER_NAME");
2296 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2297 cgiStartHTML(cgiText(_("Set Allowed Users")));
2298 cgiCopyTemplateLang("error.tmpl");
2303 users
= cgiGetVariable("users");
2304 type
= cgiGetVariable("type");
2306 if (!users
|| !type
||
2307 (strcmp(type
, "requesting-user-name-allowed") &&
2308 strcmp(type
, "requesting-user-name-denied")))
2311 * Build a Get-Printer-Attributes request, which requires the following
2314 * attributes-charset
2315 * attributes-natural-language
2317 * requested-attributes
2320 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2322 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2323 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2325 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2328 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2329 "requested-attributes",
2330 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2333 * Do the request and get back a response...
2336 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2338 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2340 ippDelete(response
);
2343 cgiStartHTML(cgiText(_("Set Allowed Users")));
2345 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2347 puts("Status: 401\n");
2350 else if (cupsLastError() > IPP_OK_CONFLICT
)
2351 cgiShowIPPError(_("Unable to get printer attributes"));
2353 cgiCopyTemplateLang("users.tmpl");
2360 * Save the changes...
2363 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2366 * Skip whitespace and commas...
2369 while (*ptr
== ',' || isspace(*ptr
& 255))
2375 if (*ptr
== '\'' || *ptr
== '\"')
2378 * Scan quoted name...
2383 for (end
= ptr
; *end
; end
++)
2390 * Scan space or comma-delimited name...
2393 for (end
= ptr
; *end
; end
++)
2394 if (isspace(*end
& 255) || *end
== ',')
2399 * Advance to the next name...
2406 * Build a CUPS-Add-Printer/Class request, which requires the following
2409 * attributes-charset
2410 * attributes-natural-language
2412 * requesting-user-name-{allowed,denied}
2415 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2417 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2418 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2420 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2424 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2425 "requesting-user-name-allowed", NULL
, "all");
2428 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2429 type
, num_users
, NULL
, NULL
);
2431 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2434 * Skip whitespace and commas...
2437 while (*ptr
== ',' || isspace(*ptr
& 255))
2443 if (*ptr
== '\'' || *ptr
== '\"')
2446 * Scan quoted name...
2451 for (end
= ptr
; *end
; end
++)
2458 * Scan space or comma-delimited name...
2461 for (end
= ptr
; *end
; end
++)
2462 if (isspace(*end
& 255) || *end
== ',')
2467 * Terminate the name...
2477 ippSetString(request
, &attr
, i
, ptr
);
2480 * Advance to the next name...
2488 * Do the request and get back a response...
2491 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2493 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2495 puts("Status: 401\n");
2498 else if (cupsLastError() > IPP_OK_CONFLICT
)
2500 cgiStartHTML(cgiText(_("Set Allowed Users")));
2501 cgiShowIPPError(_("Unable to change printer"));
2506 * Redirect successful updates back to the printer page...
2509 char url
[1024], /* Printer/class URL */
2510 refresh
[1024]; /* Refresh URL */
2513 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2514 cgiFormEncode(uri
, url
, sizeof(uri
));
2515 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2517 cgiSetVariable("refresh_page", refresh
);
2519 cgiStartHTML(cgiText(_("Set Allowed Users")));
2521 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2522 "printer-modified.tmpl");
2531 * 'do_set_default()' - Set the server default printer/class.
2535 do_set_default(http_t
*http
) /* I - HTTP connection */
2537 const char *title
; /* Page title */
2538 ipp_t
*request
; /* IPP request */
2539 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2540 const char *printer
, /* Printer name (purge-jobs) */
2541 *is_class
; /* Is a class? */
2544 is_class
= cgiGetVariable("IS_CLASS");
2545 printer
= cgiGetVariable("PRINTER_NAME");
2546 title
= cgiText(_("Set As Server Default"));
2550 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2551 cgiStartHTML(title
);
2552 cgiCopyTemplateLang("error.tmpl");
2558 * Build a printer request, which requires the following
2561 * attributes-charset
2562 * attributes-natural-language
2566 request
= ippNewRequest(CUPS_SET_DEFAULT
);
2568 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2569 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2571 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2575 * Do the request and get back a response...
2578 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2580 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2582 puts("Status: 401\n");
2585 else if (cupsLastError() > IPP_OK_CONFLICT
)
2587 cgiStartHTML(title
);
2588 cgiShowIPPError(_("Unable to set server default"));
2593 * Redirect successful updates back to the printer page...
2596 char url
[1024], /* Printer/class URL */
2597 refresh
[1024]; /* Refresh URL */
2600 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2601 cgiFormEncode(uri
, url
, sizeof(uri
));
2602 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2603 cgiSetVariable("refresh_page", refresh
);
2605 cgiStartHTML(title
);
2606 cgiCopyTemplateLang("printer-default.tmpl");
2614 * 'do_set_options()' - Configure the default options for a queue.
2618 do_set_options(http_t
*http
, /* I - HTTP connection */
2619 int is_class
) /* I - Set options for class? */
2621 int i
, j
, k
, m
; /* Looping vars */
2622 int have_options
; /* Have options? */
2623 ipp_t
*request
, /* IPP request */
2624 *response
; /* IPP response */
2625 ipp_attribute_t
*attr
; /* IPP attribute */
2626 char uri
[HTTP_MAX_URI
]; /* Job URI */
2627 const char *var
; /* Variable value */
2628 const char *printer
; /* Printer printer name */
2629 const char *filename
; /* PPD filename */
2630 char tempfile
[1024]; /* Temporary filename */
2631 cups_file_t
*in
, /* Input file */
2632 *out
; /* Output file */
2633 char line
[1024], /* Line from PPD file */
2634 value
[1024], /* Option value */
2635 keyword
[1024], /* Keyword from Default line */
2636 *keyptr
; /* Pointer into keyword... */
2637 ppd_file_t
*ppd
; /* PPD file */
2638 ppd_group_t
*group
; /* Option group */
2639 ppd_option_t
*option
; /* Option */
2640 ppd_coption_t
*coption
; /* Custom option */
2641 ppd_cparam_t
*cparam
; /* Custom parameter */
2642 ppd_attr_t
*ppdattr
; /* PPD attribute */
2643 const char *title
; /* Page title */
2646 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2648 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2652 * Get the printer name...
2655 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2656 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2657 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2661 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2662 cgiStartHTML(title
);
2663 cgiCopyTemplateLang("error.tmpl");
2668 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2671 * If the user clicks on the Auto-Configure button, send an AutoConfigure
2672 * command file to the printer...
2675 if (cgiGetVariable("AUTOCONFIGURE"))
2677 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
2682 * Get the PPD file...
2688 filename
= cupsGetPPD2(http
, printer
);
2692 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2694 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2696 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2697 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
2698 cgiStartHTML(title
);
2699 cgiCopyTemplateLang("error.tmpl");
2706 fputs("DEBUG: No PPD file\n", stderr
);
2710 if (cgiGetVariable("job_sheets_start") != NULL
||
2711 cgiGetVariable("job_sheets_end") != NULL
)
2718 ppdMarkDefaults(ppd
);
2720 for (option
= ppdFirstOption(ppd
);
2722 option
= ppdNextOption(ppd
))
2724 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2727 ppdMarkOption(ppd
, option
->keyword
, var
);
2728 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
2731 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
2735 if (!have_options
|| ppdConflicts(ppd
))
2738 * Show the options to the user...
2741 fputs("DEBUG: Showing options...\n", stderr
);
2744 * Show auto-configure button if supported...
2749 if (ppd
->num_filters
== 0 ||
2750 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
2751 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
2752 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2755 for (i
= 0; i
< ppd
->num_filters
; i
++)
2756 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
2758 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2765 * Get the printer attributes...
2768 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2770 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2771 "localhost", 0, "/printers/%s", printer
);
2772 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2775 response
= cupsDoRequest(http
, request
, "/");
2778 * List the groups used as "tabs"...
2785 for (group
= ppd
->groups
;
2786 i
< ppd
->num_groups
;
2789 cgiSetArray("GROUP_ID", i
, group
->name
);
2791 if (!strcmp(group
->name
, "InstallableOptions"))
2792 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
2794 cgiSetArray("GROUP", i
, group
->text
);
2798 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
2800 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
2801 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
2804 if (ippFindAttribute(response
, "printer-error-policy-supported",
2806 ippFindAttribute(response
, "printer-op-policy-supported",
2809 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
2810 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
2813 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
2814 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
2816 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
2817 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
2820 cgiStartHTML(cgiText(_("Set Printer Options")));
2821 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2827 if (ppdConflicts(ppd
))
2829 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
2832 for (j
= group
->num_options
, option
= group
->options
;
2835 if (option
->conflicted
)
2837 cgiSetArray("ckeyword", k
, option
->keyword
);
2838 cgiSetArray("ckeytext", k
, option
->text
);
2840 for (m
= 0; m
< option
->num_choices
; m
++)
2842 if (option
->choices
[m
].marked
)
2844 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
2852 cgiCopyTemplateLang("option-conflict.tmpl");
2855 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2859 for (j
= group
->num_options
, option
= group
->options
;
2863 if (!strcmp(option
->keyword
, "PageRegion"))
2866 if (option
->num_choices
> 1)
2873 cgiSetVariable("GROUP_ID", group
->name
);
2875 if (!strcmp(group
->name
, "InstallableOptions"))
2876 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2878 cgiSetVariable("GROUP", group
->text
);
2880 cgiCopyTemplateLang("option-header.tmpl");
2882 for (j
= group
->num_options
, option
= group
->options
;
2886 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
2889 cgiSetVariable("KEYWORD", option
->keyword
);
2890 cgiSetVariable("KEYTEXT", option
->text
);
2892 if (option
->conflicted
)
2893 cgiSetVariable("CONFLICTED", "1");
2895 cgiSetVariable("CONFLICTED", "0");
2897 cgiSetSize("CHOICES", 0);
2898 cgiSetSize("TEXT", 0);
2899 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
2901 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
2902 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
2906 if (option
->choices
[k
].marked
)
2907 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
2910 cgiSetSize("PARAMS", 0);
2911 cgiSetSize("PARAMTEXT", 0);
2912 cgiSetSize("PARAMVALUE", 0);
2913 cgiSetSize("INPUTTYPE", 0);
2915 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
2917 const char *units
= NULL
; /* Units value, if any */
2919 cgiSetVariable("ISCUSTOM", "1");
2921 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
2923 cparam
= ppdNextCustomParam(coption
), m
++)
2925 if (!_cups_strcasecmp(option
->keyword
, "PageSize") &&
2926 _cups_strcasecmp(cparam
->name
, "Width") &&
2927 _cups_strcasecmp(cparam
->name
, "Height"))
2933 cgiSetArray("PARAMS", m
, cparam
->name
);
2934 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
2935 cgiSetArray("INPUTTYPE", m
, "text");
2937 switch (cparam
->type
)
2939 case PPD_CUSTOM_UNKNOWN
:
2942 case PPD_CUSTOM_POINTS
:
2943 if (!_cups_strncasecmp(option
->defchoice
, "Custom.", 7))
2945 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
2947 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
2948 strcmp(units
, "in") && strcmp(units
, "ft"))
2950 if (units
[1] == 'm')
2959 if (!strcmp(units
, "mm"))
2960 snprintf(value
, sizeof(value
), "%g",
2961 cparam
->current
.custom_points
/ 72.0 * 25.4);
2962 else if (!strcmp(units
, "cm"))
2963 snprintf(value
, sizeof(value
), "%g",
2964 cparam
->current
.custom_points
/ 72.0 * 2.54);
2965 else if (!strcmp(units
, "in"))
2966 snprintf(value
, sizeof(value
), "%g",
2967 cparam
->current
.custom_points
/ 72.0);
2968 else if (!strcmp(units
, "ft"))
2969 snprintf(value
, sizeof(value
), "%g",
2970 cparam
->current
.custom_points
/ 72.0 / 12.0);
2971 else if (!strcmp(units
, "m"))
2972 snprintf(value
, sizeof(value
), "%g",
2973 cparam
->current
.custom_points
/ 72.0 * 0.0254);
2975 snprintf(value
, sizeof(value
), "%g",
2976 cparam
->current
.custom_points
);
2977 cgiSetArray("PARAMVALUE", m
, value
);
2980 case PPD_CUSTOM_CURVE
:
2981 case PPD_CUSTOM_INVCURVE
:
2982 case PPD_CUSTOM_REAL
:
2983 snprintf(value
, sizeof(value
), "%g",
2984 cparam
->current
.custom_real
);
2985 cgiSetArray("PARAMVALUE", m
, value
);
2988 case PPD_CUSTOM_INT
:
2989 snprintf(value
, sizeof(value
), "%d",
2990 cparam
->current
.custom_int
);
2991 cgiSetArray("PARAMVALUE", m
, value
);
2994 case PPD_CUSTOM_PASSCODE
:
2995 case PPD_CUSTOM_PASSWORD
:
2996 if (cparam
->current
.custom_password
)
2997 cgiSetArray("PARAMVALUE", m
,
2998 cparam
->current
.custom_password
);
3000 cgiSetArray("PARAMVALUE", m
, "");
3001 cgiSetArray("INPUTTYPE", m
, "password");
3004 case PPD_CUSTOM_STRING
:
3005 if (cparam
->current
.custom_string
)
3006 cgiSetArray("PARAMVALUE", m
,
3007 cparam
->current
.custom_string
);
3009 cgiSetArray("PARAMVALUE", m
, "");
3016 cgiSetArray("PARAMS", m
, "Units");
3017 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3018 cgiSetArray("PARAMVALUE", m
, units
);
3022 cgiSetVariable("ISCUSTOM", "0");
3026 case PPD_UI_BOOLEAN
:
3027 cgiCopyTemplateLang("option-boolean.tmpl");
3029 case PPD_UI_PICKONE
:
3030 cgiCopyTemplateLang("option-pickone.tmpl");
3032 case PPD_UI_PICKMANY
:
3033 cgiCopyTemplateLang("option-pickmany.tmpl");
3038 cgiCopyTemplateLang("option-trailer.tmpl");
3042 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3043 IPP_TAG_ZERO
)) != NULL
)
3046 * Add the job sheets options...
3049 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3050 cgiSetVariable("GROUP", cgiText(_("Banners")));
3051 cgiCopyTemplateLang("option-header.tmpl");
3053 cgiSetSize("CHOICES", attr
->num_values
);
3054 cgiSetSize("TEXT", attr
->num_values
);
3055 for (k
= 0; k
< attr
->num_values
; k
++)
3057 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3058 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3061 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3063 cgiSetVariable("KEYWORD", "job_sheets_start");
3064 cgiSetVariable("KEYTEXT",
3065 /* TRANSLATORS: Banner/cover sheet before the print job. */
3066 cgiText(_("Starting Banner")));
3067 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3068 attr
->values
[0].string
.text
: "");
3070 cgiCopyTemplateLang("option-pickone.tmpl");
3072 cgiSetVariable("KEYWORD", "job_sheets_end");
3073 cgiSetVariable("KEYTEXT",
3074 /* TRANSLATORS: Banner/cover sheet after the print job. */
3075 cgiText(_("Ending Banner")));
3076 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3077 attr
->values
[1].string
.text
: "");
3079 cgiCopyTemplateLang("option-pickone.tmpl");
3081 cgiCopyTemplateLang("option-trailer.tmpl");
3084 if (ippFindAttribute(response
, "printer-error-policy-supported",
3086 ippFindAttribute(response
, "printer-op-policy-supported",
3090 * Add the error and operation policy options...
3093 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3094 cgiSetVariable("GROUP", cgiText(_("Policies")));
3095 cgiCopyTemplateLang("option-header.tmpl");
3101 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3106 cgiSetSize("CHOICES", attr
->num_values
);
3107 cgiSetSize("TEXT", attr
->num_values
);
3108 for (k
= 0; k
< attr
->num_values
; k
++)
3110 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3111 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3114 attr
= ippFindAttribute(response
, "printer-error-policy",
3117 cgiSetVariable("KEYWORD", "printer_error_policy");
3118 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3119 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3120 "" : attr
->values
[0].string
.text
);
3123 cgiCopyTemplateLang("option-pickone.tmpl");
3126 * Operation policy...
3129 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3134 cgiSetSize("CHOICES", attr
->num_values
);
3135 cgiSetSize("TEXT", attr
->num_values
);
3136 for (k
= 0; k
< attr
->num_values
; k
++)
3138 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3139 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3142 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3144 cgiSetVariable("KEYWORD", "printer_op_policy");
3145 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3146 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3147 "" : attr
->values
[0].string
.text
);
3149 cgiCopyTemplateLang("option-pickone.tmpl");
3152 cgiCopyTemplateLang("option-trailer.tmpl");
3156 * Binary protocol support...
3159 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3160 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3162 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3163 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3165 cgiSetSize("CHOICES", attr
->num_values
);
3166 cgiSetSize("TEXT", attr
->num_values
);
3168 for (i
= 0; i
< attr
->num_values
; i
++)
3170 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3171 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3174 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3175 cgiSetVariable("KEYWORD", "port_monitor");
3176 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3177 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3179 cgiCopyTemplateLang("option-header.tmpl");
3180 cgiCopyTemplateLang("option-pickone.tmpl");
3181 cgiCopyTemplateLang("option-trailer.tmpl");
3184 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3187 ippDelete(response
);
3192 * Set default options...
3195 fputs("DEBUG: Setting options...\n", stderr
);
3199 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3200 in
= cupsFileOpen(filename
, "r");
3204 cgiSetVariable("ERROR", strerror(errno
));
3205 cgiStartHTML(cgiText(_("Set Printer Options")));
3206 cgiCopyTemplateLang("error.tmpl");
3222 while (cupsFileGets(in
, line
, sizeof(line
)))
3224 if (!strncmp(line
, "*cupsProtocol:", 14))
3226 else if (strncmp(line
, "*Default", 8))
3227 cupsFilePrintf(out
, "%s\n", line
);
3231 * Get default option name...
3234 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3236 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3237 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3242 if (!strcmp(keyword
, "PageRegion") ||
3243 !strcmp(keyword
, "PaperDimension") ||
3244 !strcmp(keyword
, "ImageableArea"))
3245 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3247 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3250 cupsFilePrintf(out
, "%s\n", line
);
3252 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3262 * Make sure temporary filename is cleared when there is no PPD...
3269 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3270 * following attributes:
3272 * attributes-charset
3273 * attributes-natural-language
3275 * job-sheets-default
3276 * printer-error-policy
3281 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3282 CUPS_ADD_MODIFY_PRINTER
);
3284 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3287 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3288 "job-sheets-default", 2, NULL
, NULL
);
3289 ippSetString(request
, &attr
, 0, cgiGetVariable("job_sheets_start"));
3290 ippSetString(request
, &attr
, 1, cgiGetVariable("job_sheets_end"));
3292 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3293 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3294 "printer-error-policy", NULL
, var
);
3296 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3297 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3298 "printer-op-policy", NULL
, var
);
3300 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3301 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3302 "port-monitor", NULL
, var
);
3305 * Do the request and get back a response...
3309 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3311 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3313 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3315 puts("Status: 401\n");
3318 else if (cupsLastError() > IPP_OK_CONFLICT
)
3320 cgiStartHTML(title
);
3321 cgiShowIPPError(_("Unable to set options"));
3326 * Redirect successful updates back to the printer page...
3329 char refresh
[1024]; /* Refresh URL */
3332 cgiFormEncode(uri
, printer
, sizeof(uri
));
3333 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3334 is_class
? "classes" : "printers", uri
);
3335 cgiSetVariable("refresh_page", refresh
);
3337 cgiStartHTML(title
);
3339 cgiCopyTemplateLang("printer-configured.tmpl");
3354 * 'do_set_sharing()' - Set printer-is-shared value.
3358 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3360 ipp_t
*request
, /* IPP request */
3361 *response
; /* IPP response */
3362 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3363 const char *printer
, /* Printer name */
3364 *is_class
, /* Is a class? */
3365 *shared
; /* Sharing value */
3368 is_class
= cgiGetVariable("IS_CLASS");
3369 printer
= cgiGetVariable("PRINTER_NAME");
3370 shared
= cgiGetVariable("SHARED");
3372 if (!printer
|| !shared
)
3374 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3375 cgiStartHTML(cgiText(_("Set Publishing")));
3376 cgiCopyTemplateLang("error.tmpl");
3382 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3383 * following attributes:
3385 * attributes-charset
3386 * attributes-natural-language
3391 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3393 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3394 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3396 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3399 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", (char)atoi(shared
));
3402 * Do the request and get back a response...
3405 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3407 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3409 ippDelete(response
);
3412 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3414 puts("Status: 401\n");
3417 else if (cupsLastError() > IPP_OK_CONFLICT
)
3419 cgiStartHTML(cgiText(_("Set Publishing")));
3420 cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
3425 * Redirect successful updates back to the printer page...
3428 char url
[1024], /* Printer/class URL */
3429 refresh
[1024]; /* Refresh URL */
3432 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3433 cgiFormEncode(uri
, url
, sizeof(uri
));
3434 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3435 cgiSetVariable("refresh_page", refresh
);
3437 cgiStartHTML(cgiText(_("Set Publishing")));
3438 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3439 "printer-modified.tmpl");
3447 * 'get_option_value()' - Return the value of an option.
3449 * This function also handles generation of custom option values.
3452 static char * /* O - Value string or NULL on error */
3454 ppd_file_t
*ppd
, /* I - PPD file */
3455 const char *name
, /* I - Option name */
3456 char *buffer
, /* I - String buffer */
3457 size_t bufsize
) /* I - Size of buffer */
3459 char *bufptr
, /* Pointer into buffer */
3460 *bufend
; /* End of buffer */
3461 ppd_coption_t
*coption
; /* Custom option */
3462 ppd_cparam_t
*cparam
; /* Current custom parameter */
3463 char keyword
[256]; /* Parameter name */
3464 const char *val
, /* Parameter value */
3465 *uval
; /* Units value */
3466 long integer
; /* Integer value */
3467 double number
, /* Number value */
3468 number_points
; /* Number in points */
3472 * See if we have a custom option choice...
3475 if ((val
= cgiGetVariable(name
)) == NULL
)
3483 else if (_cups_strcasecmp(val
, "Custom") ||
3484 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3487 * Not a custom choice...
3490 strlcpy(buffer
, val
, bufsize
);
3495 * OK, we have a custom option choice, format it...
3500 if (!strcmp(coption
->keyword
, "PageSize"))
3502 const char *lval
; /* Length string value */
3503 double width
, /* Width value */
3504 width_points
, /* Width in points */
3505 length
, /* Length value */
3506 length_points
; /* Length in points */
3509 val
= cgiGetVariable("PageSize.Width");
3510 lval
= cgiGetVariable("PageSize.Height");
3511 uval
= cgiGetVariable("PageSize.Units");
3513 if (!val
|| !lval
|| !uval
||
3514 (width
= strtod(val
, NULL
)) == 0.0 ||
3515 (length
= strtod(lval
, NULL
)) == 0.0 ||
3516 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3517 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3520 width_points
= get_points(width
, uval
);
3521 length_points
= get_points(length
, uval
);
3523 if (width_points
< ppd
->custom_min
[0] ||
3524 width_points
> ppd
->custom_max
[0] ||
3525 length_points
< ppd
->custom_min
[1] ||
3526 length_points
> ppd
->custom_max
[1])
3529 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
3531 else if (cupsArrayCount(coption
->params
) == 1)
3533 cparam
= ppdFirstCustomParam(coption
);
3534 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
3536 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3539 switch (cparam
->type
)
3541 case PPD_CUSTOM_UNKNOWN
:
3544 case PPD_CUSTOM_CURVE
:
3545 case PPD_CUSTOM_INVCURVE
:
3546 case PPD_CUSTOM_REAL
:
3547 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3548 number
< cparam
->minimum
.custom_real
||
3549 number
> cparam
->maximum
.custom_real
)
3552 snprintf(buffer
, bufsize
, "Custom.%g", number
);
3555 case PPD_CUSTOM_INT
:
3556 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3557 integer
== LONG_MAX
||
3558 integer
< cparam
->minimum
.custom_int
||
3559 integer
> cparam
->maximum
.custom_int
)
3562 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
3565 case PPD_CUSTOM_POINTS
:
3566 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3568 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3569 (uval
= cgiGetVariable(keyword
)) == NULL
||
3570 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3571 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3574 number_points
= get_points(number
, uval
);
3575 if (number_points
< cparam
->minimum
.custom_points
||
3576 number_points
> cparam
->maximum
.custom_points
)
3579 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
3582 case PPD_CUSTOM_PASSCODE
:
3583 for (uval
= val
; *uval
; uval
++)
3584 if (!isdigit(*uval
& 255))
3587 case PPD_CUSTOM_PASSWORD
:
3588 case PPD_CUSTOM_STRING
:
3589 integer
= (long)strlen(val
);
3590 if (integer
< cparam
->minimum
.custom_string
||
3591 integer
> cparam
->maximum
.custom_string
)
3594 snprintf(buffer
, bufsize
, "Custom.%s", val
);
3600 const char *prefix
= "{"; /* Prefix string */
3604 bufend
= buffer
+ bufsize
;
3606 for (cparam
= ppdFirstCustomParam(coption
);
3608 cparam
= ppdNextCustomParam(coption
))
3610 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
3613 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3616 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%s%s=", prefix
, cparam
->name
);
3617 bufptr
+= strlen(bufptr
);
3620 switch (cparam
->type
)
3622 case PPD_CUSTOM_UNKNOWN
:
3625 case PPD_CUSTOM_CURVE
:
3626 case PPD_CUSTOM_INVCURVE
:
3627 case PPD_CUSTOM_REAL
:
3628 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3629 number
< cparam
->minimum
.custom_real
||
3630 number
> cparam
->maximum
.custom_real
)
3633 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g", number
);
3636 case PPD_CUSTOM_INT
:
3637 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3638 integer
== LONG_MAX
||
3639 integer
< cparam
->minimum
.custom_int
||
3640 integer
> cparam
->maximum
.custom_int
)
3643 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%ld", integer
);
3646 case PPD_CUSTOM_POINTS
:
3647 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3649 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3650 (uval
= cgiGetVariable(keyword
)) == NULL
||
3651 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
3652 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
3653 strcmp(uval
, "mm") && strcmp(uval
, "m")))
3656 number_points
= get_points(number
, uval
);
3657 if (number_points
< cparam
->minimum
.custom_points
||
3658 number_points
> cparam
->maximum
.custom_points
)
3661 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g%s", number
, uval
);
3664 case PPD_CUSTOM_PASSCODE
:
3665 for (uval
= val
; *uval
; uval
++)
3666 if (!isdigit(*uval
& 255))
3669 case PPD_CUSTOM_PASSWORD
:
3670 case PPD_CUSTOM_STRING
:
3671 integer
= (long)strlen(val
);
3672 if (integer
< cparam
->minimum
.custom_string
||
3673 integer
> cparam
->maximum
.custom_string
)
3676 if ((bufptr
+ 2) > bufend
)
3682 while (*val
&& bufptr
< bufend
)
3684 if (*val
== '\\' || *val
== '\"')
3686 if ((bufptr
+ 1) >= bufend
)
3695 if (bufptr
>= bufend
)
3704 bufptr
+= strlen(bufptr
);
3707 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
3710 memcpy(bufptr
, "}", 2);
3718 * 'get_points()' - Get a value in points.
3721 static double /* O - Number in points */
3722 get_points(double number
, /* I - Original number */
3723 const char *uval
) /* I - Units */
3725 if (!strcmp(uval
, "mm")) /* Millimeters */
3726 return (number
* 72.0 / 25.4);
3727 else if (!strcmp(uval
, "cm")) /* Centimeters */
3728 return (number
* 72.0 / 2.54);
3729 else if (!strcmp(uval
, "in")) /* Inches */
3730 return (number
* 72.0);
3731 else if (!strcmp(uval
, "ft")) /* Feet */
3732 return (number
* 72.0 * 12.0);
3733 else if (!strcmp(uval
, "m")) /* Meters */
3734 return (number
* 72.0 / 0.0254);
3741 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
3744 static char * /* O - Filename or NULL */
3745 get_printer_ppd(const char *uri
, /* I - Printer URI */
3746 char *buffer
, /* I - Filename buffer */
3747 size_t bufsize
) /* I - Size of filename buffer */
3749 http_t
*http
; /* Connection to printer */
3750 ipp_t
*request
, /* Get-Printer-Attributes request */
3751 *response
; /* Get-Printer-Attributes response */
3752 char resolved
[1024], /* Resolved URI */
3753 scheme
[32], /* URI scheme */
3754 userpass
[256], /* Username:password */
3755 host
[256], /* Hostname */
3756 resource
[256]; /* Resource path */
3757 int port
; /* Port number */
3758 static const char * const pattrs
[] = /* Printer attributes we need */
3761 "media-col-database"
3766 * Connect to the printer...
3769 if (strstr(uri
, "._tcp"))
3775 if (!_httpResolveURI(uri
, resolved
, sizeof(resolved
), _HTTP_RESOLVE_DEFAULT
, NULL
, NULL
))
3777 fprintf(stderr
, "ERROR: Unable to resolve \"%s\".\n", uri
);
3784 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), host
, sizeof(host
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
3786 fprintf(stderr
, "ERROR: Bad printer URI \"%s\".\n", uri
);
3790 http
= httpConnect2(host
, port
, NULL
, AF_UNSPEC
, !strcmp(scheme
, "ipps") ? HTTP_ENCRYPTION_ALWAYS
: HTTP_ENCRYPTION_IF_REQUESTED
, 1, 30000, NULL
);
3793 fprintf(stderr
, "ERROR: Unable to connect to \"%s:%d\": %s\n", host
, port
, cupsLastErrorString());
3798 * Send a Get-Printer-Attributes request...
3801 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
3802 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
3803 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "requested-attributes", (int)(sizeof(pattrs
) / sizeof(pattrs
[0])), NULL
, pattrs
);
3804 response
= cupsDoRequest(http
, request
, resource
);
3806 if (!_ppdCreateFromIPP(buffer
, bufsize
, response
))
3807 fprintf(stderr
, "ERROR: Unable to create PPD file: %s\n", strerror(errno
));
3809 ippDelete(response
);