2 * Administration CGI for CUPS.
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
14 #include "cgi-private.h"
15 #include <cups/http-private.h>
16 #include <cups/ppd-private.h>
17 #include <cups/adminutil.h>
30 static int current_device
= 0; /* Current device shown */
37 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
);
38 static void do_am_class(http_t
*http
, int modify
);
39 static void do_am_printer(http_t
*http
, int modify
);
40 static void do_config_server(http_t
*http
);
41 static void do_delete_class(http_t
*http
);
42 static void do_delete_printer(http_t
*http
);
43 static void do_export(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
);
166 else if (!strcmp(op
, "export-samba"))
171 * Bad operation code - display an error...
174 cgiStartHTML(cgiText(_("Administration")));
175 cgiCopyTemplateLang("error-op.tmpl");
179 else if (op
&& !strcmp(op
, "redirect"))
181 const char *url
; /* Redirection URL... */
182 char prefix
[1024]; /* URL prefix */
186 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
187 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
189 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
190 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
192 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
194 if ((url
= cgiGetVariable("URL")) != NULL
)
196 char encoded
[1024], /* Encoded URL string */
197 *ptr
; /* Pointer into encoded string */
204 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
206 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
209 * Percent-encode this character; safe because we have at least 4
210 * bytes left in the array...
213 sprintf(ptr
, "%%%02X", *url
& 255);
225 * URL was too long, just redirect to the admin page...
228 printf("Location: %s/admin\n\n", prefix
);
233 * URL is OK, redirect there...
236 printf("Location: %s%s\n\n", prefix
, encoded
);
240 printf("Location: %s/admin\n\n", prefix
);
245 * Form data but no operation code - display an error...
248 cgiStartHTML(cgiText(_("Administration")));
249 cgiCopyTemplateLang("error-op.tmpl");
254 * Close the HTTP server connection...
260 * Return with no errors...
268 * 'choose_device_cb()' - Add a device to the device selection page.
273 const char *device_class
, /* I - Class */
274 const char *device_id
, /* I - 1284 device ID */
275 const char *device_info
, /* I - Description */
276 const char *device_make_and_model
, /* I - Make and model */
277 const char *device_uri
, /* I - Device URI */
278 const char *device_location
, /* I - Location */
279 const char *title
) /* I - Page title */
282 * For modern browsers, start a multi-part page so we can show that something
283 * is happening. Non-modern browsers just get everything at the end...
286 if (current_device
== 0 && cgiSupportsMultipart())
290 cgiCopyTemplateLang("choose-device.tmpl");
297 * Add the device to the array...
300 cgiSetArray("device_class", current_device
, device_class
);
301 cgiSetArray("device_id", current_device
, device_id
);
302 cgiSetArray("device_info", current_device
, device_info
);
303 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
304 cgiSetArray("device_uri", current_device
, device_uri
);
305 cgiSetArray("device_location", current_device
, device_location
);
312 * 'do_am_class()' - Add or modify a class.
316 do_am_class(http_t
*http
, /* I - HTTP connection */
317 int modify
) /* I - Modify the printer? */
319 int i
, j
; /* Looping vars */
320 int element
; /* Element number */
321 int num_printers
; /* Number of printers */
322 ipp_t
*request
, /* IPP request */
323 *response
; /* IPP response */
324 ipp_attribute_t
*attr
; /* member-uris attribute */
325 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
326 const char *name
, /* Pointer to class name */
327 *op
, /* Operation name */
328 *ptr
; /* Pointer to CGI variable */
329 const char *title
; /* Title of page */
330 static const char * const pattrs
[] = /* Requested printer attributes */
338 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
339 op
= cgiGetVariable("OP");
340 name
= cgiGetVariable("PRINTER_NAME");
342 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
345 * Build a CUPS_GET_PRINTERS request, which requires the
346 * following attributes:
349 * attributes-natural-language
352 request
= ippNewRequest(CUPS_GET_PRINTERS
);
354 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
356 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
357 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
360 * Do the request and get back a response...
365 cgiSetVariable("OP", op
);
367 cgiSetVariable("PRINTER_NAME", name
);
369 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
372 * Create MEMBER_URIS and MEMBER_NAMES arrays...
375 for (element
= 0, attr
= response
->attrs
;
378 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
380 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
381 (!name
|| _cups_strcasecmp(name
, ptr
+ 1)))
384 * Don't show the current class...
387 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
392 for (element
= 0, attr
= response
->attrs
;
395 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
397 if (!name
|| _cups_strcasecmp(name
, attr
->values
[0].string
.text
))
400 * Don't show the current class...
403 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
408 num_printers
= cgiGetSize("MEMBER_URIS");
418 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
419 * following attributes:
422 * attributes-natural-language
426 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
428 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
429 "localhost", 0, "/classes/%s", name
);
430 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
433 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
434 "requested-attributes",
435 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
439 * Do the request and get back a response...
442 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
444 if ((attr
= ippFindAttribute(response
, "member-names",
445 IPP_TAG_NAME
)) != NULL
)
448 * Mark any current members in the class...
451 for (j
= 0; j
< num_printers
; j
++)
452 cgiSetArray("MEMBER_SELECTED", j
, "");
454 for (i
= 0; i
< attr
->num_values
; i
++)
456 for (j
= 0; j
< num_printers
; j
++)
458 if (!_cups_strcasecmp(attr
->values
[i
].string
.text
,
459 cgiGetArray("MEMBER_NAMES", j
)))
461 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
468 if ((attr
= ippFindAttribute(response
, "printer-info",
469 IPP_TAG_TEXT
)) != NULL
)
470 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
472 if ((attr
= ippFindAttribute(response
, "printer-location",
473 IPP_TAG_TEXT
)) != NULL
)
474 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
480 * Update the location and description of an existing printer...
484 cgiCopyTemplateLang("modify-class.tmpl");
489 * Get the name, location, and description for a new printer...
493 cgiCopyTemplateLang("add-class.tmpl");
504 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
505 cgiCopyTemplateLang("error.tmpl");
510 for (ptr
= name
; *ptr
; ptr
++)
511 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
514 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
516 cgiSetVariable("ERROR",
517 cgiText(_("The class name may only contain up to "
518 "127 printable characters and may not "
519 "contain spaces, slashes (/), or the "
520 "pound sign (#).")));
522 cgiCopyTemplateLang("error.tmpl");
528 * Build a CUPS_ADD_CLASS request, which requires the following
532 * attributes-natural-language
536 * printer-is-accepting-jobs
541 request
= ippNewRequest(CUPS_ADD_CLASS
);
543 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
544 "localhost", 0, "/classes/%s", name
);
545 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
548 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
549 NULL
, cgiGetVariable("PRINTER_LOCATION"));
551 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
552 NULL
, cgiGetVariable("PRINTER_INFO"));
554 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
556 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
559 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
561 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
562 num_printers
, NULL
, NULL
);
563 for (i
= 0; i
< num_printers
; i
++)
564 attr
->values
[i
].string
.text
= _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i
));
568 * Do the request and get back a response...
571 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
573 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
575 puts("Status: 401\n");
578 else if (cupsLastError() > IPP_OK_CONFLICT
)
581 cgiShowIPPError(modify
? _("Unable to modify class") :
582 _("Unable to add class"));
587 * Redirect successful updates back to the class page...
590 char refresh
[1024]; /* Refresh URL */
592 cgiFormEncode(uri
, name
, sizeof(uri
));
593 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
595 cgiSetVariable("refresh_page", refresh
);
600 cgiCopyTemplateLang("class-modified.tmpl");
602 cgiCopyTemplateLang("class-added.tmpl");
610 * 'do_am_printer()' - Add or modify a printer.
614 do_am_printer(http_t
*http
, /* I - HTTP connection */
615 int modify
) /* I - Modify the printer? */
617 int i
; /* Looping var */
618 ipp_attribute_t
*attr
; /* Current attribute */
619 ipp_t
*request
, /* IPP request */
620 *response
, /* IPP response */
621 *oldinfo
; /* Old printer information */
622 const cgi_file_t
*file
; /* Uploaded file, if any */
623 const char *var
; /* CGI variable */
624 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
625 *uriptr
, /* Pointer into URI */
626 evefile
[1024] = ""; /* IPP Everywhere PPD file */
627 int maxrate
; /* Maximum baud rate */
628 char baudrate
[255]; /* Baud rate string */
629 const char *name
, /* Pointer to class name */
630 *ptr
; /* Pointer to CGI variable */
631 const char *title
; /* Title of page */
632 static int baudrates
[] = /* Baud rates */
647 ptr
= cgiGetVariable("DEVICE_URI");
648 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
649 ptr
? ptr
: "(null)");
651 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
656 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
657 * following attributes:
660 * attributes-natural-language
664 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
666 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
667 "localhost", 0, "/printers/%s",
668 cgiGetVariable("PRINTER_NAME"));
669 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
673 * Do the request and get back a response...
676 oldinfo
= cupsDoRequest(http
, request
, "/");
685 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
686 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
687 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
688 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
691 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
693 for (ptr
= name
; *ptr
; ptr
++)
694 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '\\' || *ptr
== '?' || *ptr
== '\'' || *ptr
== '\"' || *ptr
== '#')
697 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
699 cgiSetVariable("ERROR",
700 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 (#).")));
702 cgiCopyTemplateLang("error.tmpl");
708 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
710 if ((uriptr
= strrchr(var
, '|')) != NULL
)
713 * Extract make and make/model from device URI string...
716 char make
[1024], /* Make string */
717 *makeptr
; /* Pointer into make */
722 strlcpy(make
, uriptr
, sizeof(make
));
724 if ((makeptr
= strchr(make
, ' ')) != NULL
)
726 else if ((makeptr
= strchr(make
, '-')) != NULL
)
728 else if (!_cups_strncasecmp(make
, "laserjet", 8) ||
729 !_cups_strncasecmp(make
, "deskjet", 7) ||
730 !_cups_strncasecmp(make
, "designjet", 9))
731 strlcpy(make
, "HP", sizeof(make
));
732 else if (!_cups_strncasecmp(make
, "phaser", 6))
733 strlcpy(make
, "Xerox", sizeof(make
));
734 else if (!_cups_strncasecmp(make
, "stylus", 6))
735 strlcpy(make
, "Epson", sizeof(make
));
737 strlcpy(make
, "Generic", sizeof(make
));
739 if (!cgiGetVariable("CURRENT_MAKE"))
740 cgiSetVariable("CURRENT_MAKE", make
);
742 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
743 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
747 char template[128], /* Template name */
748 *tptr
; /* Pointer into template name */
750 cgiSetVariable("PRINTER_INFO", uriptr
);
752 for (tptr
= template;
753 tptr
< (template + sizeof(template) - 1) && *uriptr
;
755 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
758 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
761 else if (*uriptr
== '?' || *uriptr
== '(')
766 cgiSetVariable("TEMPLATE_NAME", template);
774 * Look for devices so the user can pick something...
777 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
779 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
780 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
783 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
784 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
788 * Scan for devices for up to 30 seconds...
791 fputs("DEBUG: Getting list of devices...\n", stderr
);
794 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
795 (cups_device_cb_t
)choose_device_cb
,
796 (void *)title
) == IPP_OK
)
798 fputs("DEBUG: Got device list!\n", stderr
);
800 if (cgiSupportsMultipart())
803 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
805 cgiCopyTemplateLang("choose-device.tmpl");
808 if (cgiSupportsMultipart())
814 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
815 cupsLastError(), cupsLastErrorString());
816 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
818 puts("Status: 401\n");
824 cgiShowIPPError(modify
? _("Unable to modify printer") :
825 _("Unable to add printer"));
831 else if (!strchr(var
, '/') ||
832 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
834 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
837 * Set the current device URI for the form to the old one...
840 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
841 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
845 * User needs to set the full URI...
849 cgiCopyTemplateLang("choose-uri.tmpl");
852 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
855 * Need baud rate, parity, etc.
858 if ((var
= strchr(var
, '?')) != NULL
&&
859 strncmp(var
, "?baud=", 6) == 0)
860 maxrate
= atoi(var
+ 6);
864 for (i
= 0; i
< 10; i
++)
865 if (baudrates
[i
] > maxrate
)
869 sprintf(baudrate
, "%d", baudrates
[i
]);
870 cgiSetArray("BAUDRATES", i
, baudrate
);
874 cgiCopyTemplateLang("choose-serial.tmpl");
877 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
884 * Update the location and description of an existing printer...
889 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
890 IPP_TAG_TEXT
)) != NULL
)
891 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
893 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
894 IPP_TAG_TEXT
)) != NULL
)
895 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
897 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
898 IPP_TAG_BOOLEAN
)) != NULL
)
899 cgiSetVariable("PRINTER_IS_SHARED",
900 attr
->values
[0].boolean
? "1" : "0");
903 cgiCopyTemplateLang("modify-printer.tmpl");
908 * Get the name, location, and description for a new printer...
912 if (!strncmp(var
, "usb:", 4))
913 cgiSetVariable("printer_is_shared", "1");
915 #endif /* __APPLE__ */
916 cgiSetVariable("printer_is_shared", "0");
918 cgiCopyTemplateLang("add-printer.tmpl");
929 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
931 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
934 * Get the PPD file...
937 int fd
; /* PPD file */
938 char filename
[1024]; /* PPD filename */
939 ppd_file_t
*ppd
; /* PPD information */
940 char buffer
[1024]; /* Buffer */
941 ssize_t bytes
; /* Number of bytes */
942 http_status_t get_status
; /* Status of GET */
945 /* TODO: Use cupsGetFile() API... */
946 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
948 if (httpGet(http
, uri
))
951 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
953 if (get_status
!= HTTP_OK
)
957 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
958 uri
, get_status
, httpStatus(get_status
));
960 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
962 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
963 write(fd
, buffer
, (size_t)bytes
);
967 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
969 if (ppd
->manufacturer
)
970 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
973 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
980 int linenum
; /* Line number */
982 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
983 filename
, ppdErrorString(ppdLastError(&linenum
)));
991 "ERROR: Unable to create temporary file for PPD file: %s\n",
997 * Build a CUPS_GET_PPDS request, which requires the following
1000 * attributes-charset
1001 * attributes-natural-language
1005 request
= ippNewRequest(CUPS_GET_PPDS
);
1007 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1008 NULL
, "ipp://localhost/printers/");
1010 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1011 var
= cgiGetVariable("CURRENT_MAKE");
1012 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1014 const char *make_model
; /* Make and model */
1017 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1018 "ppd-make", NULL
, var
);
1020 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1021 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1022 "ppd-make-and-model", NULL
, make_model
);
1025 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1026 "requested-attributes", NULL
, "ppd-make");
1029 * Do the request and get back a response...
1032 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1035 * Got the list of PPDs, see if the user has selected a make...
1038 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1041 * No PPD files with this make, try again with all makes...
1044 ippDelete(response
);
1046 request
= ippNewRequest(CUPS_GET_PPDS
);
1048 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1049 NULL
, "ipp://localhost/printers/");
1051 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1052 "requested-attributes", NULL
, "ppd-make");
1054 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1055 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1057 cgiStartHTML(title
);
1058 cgiCopyTemplateLang("choose-make.tmpl");
1061 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1063 cgiStartHTML(title
);
1064 cgiCopyTemplateLang("choose-make.tmpl");
1070 * Let the user choose a model...
1073 cgiStartHTML(title
);
1074 if (!cgiGetVariable("PPD_MAKE"))
1075 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1077 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1078 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1079 cgiCopyTemplateLang("choose-model.tmpl");
1083 ippDelete(response
);
1087 cgiStartHTML(title
);
1088 cgiShowIPPError(_("Unable to get list of printer drivers"));
1089 cgiCopyTemplateLang("error.tmpl");
1096 * Build a CUPS_ADD_PRINTER request, which requires the following
1099 * attributes-charset
1100 * attributes-natural-language
1106 * printer-is-accepting-jobs
1111 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1113 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1114 "localhost", 0, "/printers/%s",
1115 cgiGetVariable("PRINTER_NAME"));
1116 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1121 var
= cgiGetVariable("PPD_NAME");
1122 if (!strcmp(var
, "everywhere"))
1123 get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile
, sizeof(evefile
));
1124 else if (strcmp(var
, "__no_change__"))
1125 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name",
1129 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1130 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1132 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1133 NULL
, cgiGetVariable("PRINTER_INFO"));
1135 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1138 * Strip make and model from URI...
1141 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1144 if (!strncmp(uri
, "serial:", 7))
1147 * Update serial port URI to include baud rate, etc.
1150 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1151 uriptr
= uri
+ strlen(uri
);
1153 snprintf(uriptr
, sizeof(uri
) - (size_t)(uriptr
- uri
),
1154 "?baud=%s+bits=%s+parity=%s+flow=%s",
1155 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1156 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1159 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1162 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1164 var
= cgiGetVariable("printer_is_shared");
1165 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1166 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1168 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1172 * Do the request and get back a response...
1176 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1177 else if (evefile
[0])
1179 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", evefile
));
1183 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1185 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1187 puts("Status: 401\n");
1190 else if (cupsLastError() > IPP_OK_CONFLICT
)
1192 cgiStartHTML(title
);
1193 cgiShowIPPError(modify
? _("Unable to modify printer") :
1194 _("Unable to add printer"));
1199 * Redirect successful updates back to the printer page...
1202 char refresh
[1024]; /* Refresh URL */
1205 cgiFormEncode(uri
, name
, sizeof(uri
));
1207 snprintf(refresh
, sizeof(refresh
),
1208 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1210 cgiSetVariable("refresh_page", refresh
);
1212 cgiStartHTML(title
);
1214 cgiCopyTemplateLang("printer-modified.tmpl");
1219 * Set the printer options...
1222 cgiSetVariable("OP", "set-printer-options");
1223 do_set_options(http
, 0);
1236 * 'do_config_server()' - Configure server settings.
1240 do_config_server(http_t
*http
) /* I - HTTP connection */
1242 if (cgiGetVariable("CHANGESETTINGS"))
1245 * Save basic setting changes...
1248 int num_settings
; /* Number of server settings */
1249 cups_option_t
*settings
; /* Server settings */
1250 int advanced
, /* Advanced settings shown? */
1251 changed
; /* Have settings changed? */
1252 const char *debug_logging
, /* DEBUG_LOGGING value */
1253 *preserve_jobs
= NULL
,
1254 /* PRESERVE_JOBS value */
1255 *remote_admin
, /* REMOTE_ADMIN value */
1256 *remote_any
, /* REMOTE_ANY value */
1257 *share_printers
,/* SHARE_PRINTERS value */
1259 /* USER_CANCEL_ANY value */
1260 *browse_web_if
= NULL
,
1261 /* BrowseWebIF value */
1262 *preserve_job_history
= NULL
,
1263 /* PreserveJobHistory value */
1264 *preserve_job_files
= NULL
,
1265 /* PreserveJobFiles value */
1266 *max_clients
= NULL
,
1267 /* MaxClients value */
1270 *max_log_size
= NULL
;
1271 /* MaxLogSize value */
1272 const char *current_browse_web_if
,
1273 /* BrowseWebIF value */
1274 *current_preserve_job_history
,
1275 /* PreserveJobHistory value */
1276 *current_preserve_job_files
,
1277 /* PreserveJobFiles value */
1278 *current_max_clients
,
1279 /* MaxClients value */
1282 *current_max_log_size
;
1283 /* MaxLogSize value */
1285 char default_auth_type
[255];
1286 /* DefaultAuthType value */
1287 const char *val
; /* Setting value */
1288 #endif /* HAVE_GSSAPI */
1292 * Get the checkbox values from the form...
1295 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1296 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1297 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1298 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1299 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1301 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1305 * Get advanced settings...
1308 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1309 max_clients
= cgiGetVariable("MAX_CLIENTS");
1310 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1311 preserve_jobs
= cgiGetVariable("PRESERVE_JOBS");
1315 max_jobs
= cgiGetVariable("MAX_JOBS");
1316 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY");
1317 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES");
1319 if (!max_jobs
|| atoi(max_jobs
) < 0)
1322 if (!preserve_job_history
)
1323 preserve_job_history
= "On";
1325 if (!preserve_job_files
)
1326 preserve_job_files
= "1d";
1331 preserve_job_history
= "No";
1332 preserve_job_files
= "No";
1335 if (!max_clients
|| atoi(max_clients
) <= 0)
1336 max_clients
= "100";
1338 if (!max_log_size
|| atoi(max_log_size
) <= 0.0)
1339 max_log_size
= "1m";
1343 * Get the current server settings...
1346 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1348 cgiStartHTML(cgiText(_("Change Settings")));
1349 cgiSetVariable("MESSAGE",
1350 cgiText(_("Unable to change server settings")));
1351 cgiSetVariable("ERROR", cupsLastErrorString());
1352 cgiCopyTemplateLang("error.tmpl");
1359 * Get authentication settings...
1362 if (cgiGetVariable("KERBEROS"))
1363 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1366 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1368 if (!val
|| !_cups_strcasecmp(val
, "Negotiate"))
1369 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1371 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1374 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1375 #endif /* HAVE_GSSAPI */
1377 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1379 current_browse_web_if
= "No";
1381 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1384 current_preserve_job_history
= "Yes";
1386 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1389 current_preserve_job_files
= "1d";
1391 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1393 current_max_clients
= "100";
1395 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1397 current_max_jobs
= "500";
1399 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1401 current_max_log_size
= "1m";
1404 * See if the settings have changed...
1407 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1408 num_settings
, settings
)) ||
1409 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1410 num_settings
, settings
)) ||
1411 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1412 num_settings
, settings
)) ||
1413 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1414 num_settings
, settings
)) ||
1416 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1417 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1418 num_settings
, settings
)) ||
1419 #endif /* HAVE_GSSAPI */
1420 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1421 num_settings
, settings
));
1423 if (advanced
&& !changed
)
1424 changed
= _cups_strcasecmp(browse_web_if
, current_browse_web_if
) ||
1425 _cups_strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1426 _cups_strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1427 _cups_strcasecmp(max_clients
, current_max_clients
) ||
1428 _cups_strcasecmp(max_jobs
, current_max_jobs
) ||
1429 _cups_strcasecmp(max_log_size
, current_max_log_size
);
1434 * Settings *have* changed, so save the changes...
1437 cupsFreeOptions(num_settings
, settings
);
1440 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1441 debug_logging
, num_settings
, &settings
);
1442 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1443 remote_admin
, num_settings
, &settings
);
1444 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1445 remote_any
, num_settings
, &settings
);
1446 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1447 share_printers
, num_settings
, &settings
);
1448 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1449 user_cancel_any
, num_settings
, &settings
);
1451 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1452 num_settings
, &settings
);
1453 #endif /* HAVE_GSSAPI */
1458 * Add advanced settings...
1461 if (_cups_strcasecmp(browse_web_if
, current_browse_web_if
))
1462 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1463 num_settings
, &settings
);
1464 if (_cups_strcasecmp(preserve_job_history
, current_preserve_job_history
))
1465 num_settings
= cupsAddOption("PreserveJobHistory",
1466 preserve_job_history
, num_settings
,
1468 if (_cups_strcasecmp(preserve_job_files
, current_preserve_job_files
))
1469 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1470 num_settings
, &settings
);
1471 if (_cups_strcasecmp(max_clients
, current_max_clients
))
1472 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1474 if (_cups_strcasecmp(max_jobs
, current_max_jobs
))
1475 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1477 if (_cups_strcasecmp(max_log_size
, current_max_log_size
))
1478 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1482 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1484 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1486 puts("Status: 401\n");
1490 cgiStartHTML(cgiText(_("Change Settings")));
1491 cgiSetVariable("MESSAGE",
1492 cgiText(_("Unable to change server settings")));
1493 cgiSetVariable("ERROR", cupsLastErrorString());
1494 cgiCopyTemplateLang("error.tmpl");
1499 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1500 "URL=/admin/?ADVANCEDSETTINGS=YES");
1502 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1503 cgiStartHTML(cgiText(_("Change Settings")));
1504 cgiCopyTemplateLang("restart.tmpl");
1513 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1514 cgiStartHTML(cgiText(_("Change Settings")));
1515 cgiCopyTemplateLang("norestart.tmpl");
1518 cupsFreeOptions(num_settings
, settings
);
1522 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1525 * Save hand-edited config file...
1528 http_status_t status
; /* PUT status */
1529 char tempfile
[1024]; /* Temporary new cupsd.conf */
1530 int tempfd
; /* Temporary file descriptor */
1531 cups_file_t
*temp
; /* Temporary file */
1532 const char *start
, /* Start of line */
1533 *end
; /* End of line */
1537 * Create a temporary file for the new cupsd.conf file...
1540 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1542 cgiStartHTML(cgiText(_("Edit Configuration File")));
1543 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1544 cgiSetVariable("ERROR", strerror(errno
));
1545 cgiCopyTemplateLang("error.tmpl");
1552 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1554 cgiStartHTML(cgiText(_("Edit Configuration File")));
1555 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1556 cgiSetVariable("ERROR", strerror(errno
));
1557 cgiCopyTemplateLang("error.tmpl");
1567 * Copy the cupsd.conf text from the form variable...
1570 start
= cgiGetVariable("CUPSDCONF");
1573 if ((end
= strstr(start
, "\r\n")) == NULL
)
1574 if ((end
= strstr(start
, "\n")) == NULL
)
1575 end
= start
+ strlen(start
);
1577 cupsFileWrite(temp
, start
, (size_t)(end
- start
));
1578 cupsFilePutChar(temp
, '\n');
1582 else if (*end
== '\n')
1588 cupsFileClose(temp
);
1591 * Upload the configuration file to the server...
1594 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1596 if (status
== HTTP_UNAUTHORIZED
)
1598 puts("Status: 401\n");
1602 else if (status
!= HTTP_CREATED
)
1604 cgiSetVariable("MESSAGE",
1605 cgiText(_("Unable to upload cupsd.conf file")));
1606 cgiSetVariable("ERROR", httpStatus(status
));
1608 cgiStartHTML(cgiText(_("Edit Configuration File")));
1609 cgiCopyTemplateLang("error.tmpl");
1613 cgiSetVariable("refresh_page", "5;URL=/admin/");
1615 cgiStartHTML(cgiText(_("Edit Configuration File")));
1616 cgiCopyTemplateLang("restart.tmpl");
1625 struct stat info
; /* cupsd.conf information */
1626 cups_file_t
*cupsd
; /* cupsd.conf file */
1627 char *buffer
, /* Buffer for entire file */
1628 *bufptr
, /* Pointer into buffer */
1629 *bufend
; /* End of buffer */
1630 int ch
; /* Character from file */
1631 char filename
[1024]; /* Filename */
1632 const char *server_root
; /* Location of config files */
1636 * Locate the cupsd.conf file...
1639 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1640 server_root
= CUPS_SERVERROOT
;
1642 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1645 * Figure out the size...
1648 if (stat(filename
, &info
))
1650 cgiStartHTML(cgiText(_("Edit Configuration File")));
1651 cgiSetVariable("MESSAGE",
1652 cgiText(_("Unable to access cupsd.conf file")));
1653 cgiSetVariable("ERROR", strerror(errno
));
1654 cgiCopyTemplateLang("error.tmpl");
1661 if (info
.st_size
> (1024 * 1024))
1663 cgiStartHTML(cgiText(_("Edit Configuration File")));
1664 cgiSetVariable("MESSAGE",
1665 cgiText(_("Unable to access cupsd.conf file")));
1666 cgiSetVariable("ERROR",
1667 cgiText(_("Unable to edit cupsd.conf files larger than "
1669 cgiCopyTemplateLang("error.tmpl");
1672 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1673 (long)info
.st_size
);
1678 * Open the cupsd.conf file...
1681 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1684 * Unable to open - log an error...
1687 cgiStartHTML(cgiText(_("Edit Configuration File")));
1688 cgiSetVariable("MESSAGE",
1689 cgiText(_("Unable to access cupsd.conf file")));
1690 cgiSetVariable("ERROR", strerror(errno
));
1691 cgiCopyTemplateLang("error.tmpl");
1699 * Allocate memory and load the file into a string buffer...
1702 if ((buffer
= calloc(1, (size_t)info
.st_size
+ 1)) != NULL
)
1704 cupsFileRead(cupsd
, buffer
, (size_t)info
.st_size
);
1705 cgiSetVariable("CUPSDCONF", buffer
);
1709 cupsFileClose(cupsd
);
1712 * Then get the default cupsd.conf file and put that into a string as
1716 strlcat(filename
, ".default", sizeof(filename
));
1718 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1719 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1721 if ((buffer
= calloc(1, 2 * (size_t)info
.st_size
+ 1)) != NULL
)
1723 bufend
= buffer
+ 2 * info
.st_size
- 1;
1725 for (bufptr
= buffer
;
1726 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1728 if (ch
== '\\' || ch
== '\"')
1731 *bufptr
++ = (char)ch
;
1733 else if (ch
== '\n')
1738 else if (ch
== '\t')
1744 *bufptr
++ = (char)ch
;
1749 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1753 cupsFileClose(cupsd
);
1757 * Show the current config file...
1760 cgiStartHTML(cgiText(_("Edit Configuration File")));
1762 cgiCopyTemplateLang("edit-config.tmpl");
1770 * 'do_delete_class()' - Delete a class.
1774 do_delete_class(http_t
*http
) /* I - HTTP connection */
1776 ipp_t
*request
; /* IPP request */
1777 char uri
[HTTP_MAX_URI
]; /* Job URI */
1778 const char *pclass
; /* Printer class name */
1782 * Get form variables...
1785 if (cgiGetVariable("CONFIRM") == NULL
)
1787 cgiStartHTML(cgiText(_("Delete Class")));
1788 cgiCopyTemplateLang("class-confirm.tmpl");
1793 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1794 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1795 "localhost", 0, "/classes/%s", pclass
);
1798 cgiStartHTML(cgiText(_("Delete Class")));
1799 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1800 cgiCopyTemplateLang("error.tmpl");
1806 * Build a CUPS_DELETE_CLASS request, which requires the following
1809 * attributes-charset
1810 * attributes-natural-language
1814 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1816 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1820 * Do the request and get back a response...
1823 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1826 * Show the results...
1829 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1831 puts("Status: 401\n");
1834 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1837 * Redirect successful updates back to the classes page...
1840 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1843 cgiStartHTML(cgiText(_("Delete Class")));
1845 if (cupsLastError() > IPP_OK_CONFLICT
)
1846 cgiShowIPPError(_("Unable to delete class"));
1848 cgiCopyTemplateLang("class-deleted.tmpl");
1855 * 'do_delete_printer()' - Delete a printer.
1859 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1861 ipp_t
*request
; /* IPP request */
1862 char uri
[HTTP_MAX_URI
]; /* Job URI */
1863 const char *printer
; /* Printer printer name */
1867 * Get form variables...
1870 if (cgiGetVariable("CONFIRM") == NULL
)
1872 cgiStartHTML(cgiText(_("Delete Printer")));
1873 cgiCopyTemplateLang("printer-confirm.tmpl");
1878 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1879 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1880 "localhost", 0, "/printers/%s", printer
);
1883 cgiStartHTML(cgiText(_("Delete Printer")));
1884 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1885 cgiCopyTemplateLang("error.tmpl");
1891 * Build a CUPS_DELETE_PRINTER request, which requires the following
1894 * attributes-charset
1895 * attributes-natural-language
1899 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1901 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1905 * Do the request and get back a response...
1908 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1911 * Show the results...
1914 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1916 puts("Status: 401\n");
1919 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1922 * Redirect successful updates back to the printers page...
1925 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1928 cgiStartHTML(cgiText(_("Delete Printer")));
1930 if (cupsLastError() > IPP_OK_CONFLICT
)
1931 cgiShowIPPError(_("Unable to delete printer"));
1933 cgiCopyTemplateLang("printer-deleted.tmpl");
1940 * 'do_export()' - Export printers to Samba.
1944 do_export(http_t
*http
) /* I - HTTP connection */
1946 int i
, j
; /* Looping vars */
1947 ipp_t
*request
, /* IPP request */
1948 *response
; /* IPP response */
1949 const char *username
, /* Samba username */
1950 *password
, /* Samba password */
1951 *export_all
; /* Export all printers? */
1952 int export_count
, /* Number of printers to export */
1953 printer_count
; /* Number of available printers */
1954 const char *name
, /* What name to pull */
1955 *dest
; /* Current destination */
1956 char ppd
[1024]; /* PPD file */
1963 username
= cgiGetVariable("USERNAME");
1964 password
= cgiGetVariable("PASSWORD");
1965 export_all
= cgiGetVariable("EXPORT_ALL");
1966 export_count
= cgiGetSize("EXPORT_NAME");
1969 * Get list of available printers...
1972 cgiSetSize("PRINTER_NAME", 0);
1973 cgiSetSize("PRINTER_EXPORT", 0);
1975 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1977 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1980 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1981 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
1983 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1984 "requested-attributes", NULL
, "printer-name");
1986 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1988 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1989 ippDelete(response
);
1993 printer_count
= cgiGetSize("PRINTER_NAME");
1995 for (i
= 0; i
< printer_count
; i
++)
1997 dest
= cgiGetArray("PRINTER_NAME", i
);
1999 for (j
= 0; j
< export_count
; j
++)
2000 if (!_cups_strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2003 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2009 * Export or get the printers to export...
2012 if (username
&& *username
&& password
&& *password
&&
2013 (export_all
|| export_count
> 0))
2019 fputs("DEBUG: Export printers...\n", stderr
);
2023 name
= "PRINTER_NAME";
2024 export_count
= cgiGetSize("PRINTER_NAME");
2027 name
= "EXPORT_NAME";
2029 for (i
= 0; i
< export_count
; i
++)
2031 dest
= cgiGetArray(name
, i
);
2033 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2036 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2045 if (i
< export_count
)
2046 cgiSetVariable("ERROR", cupsLastErrorString());
2049 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2050 cgiCopyTemplateLang("samba-exported.tmpl");
2055 else if (username
&& !*username
)
2056 cgiSetVariable("ERROR",
2057 cgiText(_("A Samba username is required to export "
2058 "printer drivers")));
2059 else if (username
&& (!password
|| !*password
))
2060 cgiSetVariable("ERROR",
2061 cgiText(_("A Samba password is required to export "
2062 "printer drivers")));
2068 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2069 cgiCopyTemplateLang("samba-export.tmpl");
2075 * 'do_list_printers()' - List available printers.
2079 do_list_printers(http_t
*http
) /* I - HTTP connection */
2081 ipp_t
*request
, /* IPP request */
2082 *response
; /* IPP response */
2083 ipp_attribute_t
*attr
; /* IPP attribute */
2086 cgiStartHTML(cgiText(_("List Available Printers")));
2090 * Get the list of printers and their devices...
2093 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2095 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2096 "requested-attributes", NULL
, "device-uri");
2098 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2099 CUPS_PRINTER_LOCAL
);
2100 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2101 CUPS_PRINTER_LOCAL
);
2103 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2106 * Got the printer list, now load the devices...
2109 int i
; /* Looping var */
2110 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2111 char *printer_device
; /* Current printer device */
2115 * Allocate an array and copy the device strings...
2118 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2120 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2122 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2124 cupsArrayAdd(printer_devices
, _cupsStrAlloc(attr
->values
[0].string
.text
));
2128 * Free the printer list and get the device list...
2131 ippDelete(response
);
2133 request
= ippNewRequest(CUPS_GET_DEVICES
);
2135 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2138 * Got the device list, let's parse it...
2141 const char *device_uri
, /* device-uri attribute value */
2142 *device_make_and_model
, /* device-make-and-model value */
2143 *device_info
; /* device-info value */
2146 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2149 * Skip leading attributes until we hit a device...
2152 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2159 * Pull the needed attributes from this device...
2163 device_make_and_model
= NULL
;
2166 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2168 if (!strcmp(attr
->name
, "device-info") &&
2169 attr
->value_tag
== IPP_TAG_TEXT
)
2170 device_info
= attr
->values
[0].string
.text
;
2172 if (!strcmp(attr
->name
, "device-make-and-model") &&
2173 attr
->value_tag
== IPP_TAG_TEXT
)
2174 device_make_and_model
= attr
->values
[0].string
.text
;
2176 if (!strcmp(attr
->name
, "device-uri") &&
2177 attr
->value_tag
== IPP_TAG_URI
)
2178 device_uri
= attr
->values
[0].string
.text
;
2184 * See if we have everything needed...
2187 if (device_info
&& device_make_and_model
&& device_uri
&&
2188 _cups_strcasecmp(device_make_and_model
, "unknown") &&
2189 strchr(device_uri
, ':'))
2192 * Yes, now see if there is already a printer for this
2196 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2199 * Not found, so it must be a new printer...
2202 char option
[1024], /* Form variables for this device */
2203 *option_ptr
; /* Pointer into string */
2204 const char *ptr
; /* Pointer into device string */
2208 * Format the printer name variable for this device...
2210 * We use the device-info string first, then device-uri,
2211 * and finally device-make-and-model to come up with a
2215 if (_cups_strncasecmp(device_info
, "unknown", 7))
2217 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2220 ptr
= device_make_and_model
;
2222 for (option_ptr
= option
;
2223 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2225 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2227 *option_ptr
++ = *ptr
;
2228 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2229 option_ptr
[-1] != '_')
2230 *option_ptr
++ = '_';
2231 else if (*ptr
== '?' || *ptr
== '(')
2236 cgiSetArray("TEMPLATE_NAME", i
, option
);
2239 * Finally, set the form variables for this printer...
2242 cgiSetArray("device_info", i
, device_info
);
2243 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2244 cgiSetArray("device_uri", i
, device_uri
);
2253 ippDelete(response
);
2256 * Free the device list...
2259 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2261 printer_device
= (char *)cupsArrayNext(printer_devices
))
2262 _cupsStrFree(printer_device
);
2264 cupsArrayDelete(printer_devices
);
2269 * Finally, show the printer list...
2272 cgiCopyTemplateLang("list-available-printers.tmpl");
2279 * 'do_menu()' - Show the main menu.
2283 do_menu(http_t
*http
) /* I - HTTP connection */
2285 int num_settings
; /* Number of server settings */
2286 cups_option_t
*settings
; /* Server settings */
2287 const char *val
; /* Setting value */
2288 char filename
[1024]; /* Temporary filename */
2289 const char *datadir
; /* Location of data files */
2290 ipp_t
*request
, /* IPP request */
2291 *response
; /* IPP response */
2295 * Get the current server settings...
2298 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2300 cgiSetVariable("SETTINGS_MESSAGE",
2301 cgiText(_("Unable to open cupsd.conf file:")));
2302 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2305 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2306 settings
)) != NULL
&& atoi(val
))
2307 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2309 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2310 settings
)) != NULL
&& atoi(val
))
2311 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2313 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2314 settings
)) != NULL
&& atoi(val
))
2315 cgiSetVariable("REMOTE_ANY", "CHECKED");
2317 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2318 settings
)) != NULL
&& atoi(val
))
2319 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2321 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2322 settings
)) != NULL
&& atoi(val
))
2323 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2326 cgiSetVariable("HAVE_GSSAPI", "1");
2328 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2329 settings
)) != NULL
&& !_cups_strcasecmp(val
, "Negotiate"))
2330 cgiSetVariable("KERBEROS", "CHECKED");
2332 #endif /* HAVE_GSSAPI */
2333 cgiSetVariable("KERBEROS", "");
2335 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2339 if (!_cups_strcasecmp(val
, "yes") || !_cups_strcasecmp(val
, "on") ||
2340 !_cups_strcasecmp(val
, "true"))
2341 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2343 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2348 (!_cups_strcasecmp(val
, "0") || !_cups_strcasecmp(val
, "no") ||
2349 !_cups_strcasecmp(val
, "off") || !_cups_strcasecmp(val
, "false") ||
2350 !_cups_strcasecmp(val
, "disabled")))
2352 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2353 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2357 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2358 cgiSetVariable("PRESERVE_JOB_HISTORY", val
);
2360 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2364 cgiSetVariable("PRESERVE_JOB_FILES", val
);
2368 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2371 cgiSetVariable("MAX_CLIENTS", val
);
2373 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2376 cgiSetVariable("MAX_JOBS", val
);
2378 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2381 cgiSetVariable("MAX_LOG_SIZE", val
);
2383 cupsFreeOptions(num_settings
, settings
);
2386 * See if Samba and the Windows drivers are installed...
2389 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2390 datadir
= CUPS_DATADIR
;
2392 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2393 if (!access(filename
, R_OK
))
2396 * Found Windows 2000 driver file, see if we have smbclient and
2400 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2401 sizeof(filename
)) &&
2402 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2404 cgiSetVariable("HAVE_SAMBA", "Y");
2407 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2409 fputs("ERROR: smbclient not found!\n", stderr
);
2411 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2413 fputs("ERROR: rpcclient not found!\n", stderr
);
2423 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2425 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2426 NULL
, "ipp://localhost/");
2428 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2430 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2431 ippDelete(response
);
2435 * Finally, show the main menu template...
2438 cgiStartHTML(cgiText(_("Administration")));
2440 cgiCopyTemplateLang("admin.tmpl");
2447 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2451 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2453 int i
; /* Looping var */
2454 ipp_t
*request
, /* IPP request */
2455 *response
; /* IPP response */
2456 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2457 const char *printer
, /* Printer name (purge-jobs) */
2458 *is_class
, /* Is a class? */
2459 *users
, /* List of users or groups */
2460 *type
; /* Allow/deny type */
2461 int num_users
; /* Number of users */
2462 char *ptr
, /* Pointer into users string */
2463 *end
, /* Pointer to end of users string */
2464 quote
; /* Quote character */
2465 ipp_attribute_t
*attr
; /* Attribute */
2466 static const char * const attrs
[] = /* Requested attributes */
2468 "requesting-user-name-allowed",
2469 "requesting-user-name-denied"
2473 is_class
= cgiGetVariable("IS_CLASS");
2474 printer
= cgiGetVariable("PRINTER_NAME");
2478 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2479 cgiStartHTML(cgiText(_("Set Allowed Users")));
2480 cgiCopyTemplateLang("error.tmpl");
2485 users
= cgiGetVariable("users");
2486 type
= cgiGetVariable("type");
2488 if (!users
|| !type
||
2489 (strcmp(type
, "requesting-user-name-allowed") &&
2490 strcmp(type
, "requesting-user-name-denied")))
2493 * Build a Get-Printer-Attributes request, which requires the following
2496 * attributes-charset
2497 * attributes-natural-language
2499 * requested-attributes
2502 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2504 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2505 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2507 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2510 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2511 "requested-attributes",
2512 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2515 * Do the request and get back a response...
2518 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2520 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2522 ippDelete(response
);
2525 cgiStartHTML(cgiText(_("Set Allowed Users")));
2527 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2529 puts("Status: 401\n");
2532 else if (cupsLastError() > IPP_OK_CONFLICT
)
2533 cgiShowIPPError(_("Unable to get printer attributes"));
2535 cgiCopyTemplateLang("users.tmpl");
2542 * Save the changes...
2545 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2548 * Skip whitespace and commas...
2551 while (*ptr
== ',' || isspace(*ptr
& 255))
2557 if (*ptr
== '\'' || *ptr
== '\"')
2560 * Scan quoted name...
2565 for (end
= ptr
; *end
; end
++)
2572 * Scan space or comma-delimited name...
2575 for (end
= ptr
; *end
; end
++)
2576 if (isspace(*end
& 255) || *end
== ',')
2581 * Advance to the next name...
2588 * Build a CUPS-Add-Printer/Class request, which requires the following
2591 * attributes-charset
2592 * attributes-natural-language
2594 * requesting-user-name-{allowed,denied}
2597 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2599 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2600 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2602 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2606 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2607 "requesting-user-name-allowed", NULL
, "all");
2610 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2611 type
, num_users
, NULL
, NULL
);
2613 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2616 * Skip whitespace and commas...
2619 while (*ptr
== ',' || isspace(*ptr
& 255))
2625 if (*ptr
== '\'' || *ptr
== '\"')
2628 * Scan quoted name...
2633 for (end
= ptr
; *end
; end
++)
2640 * Scan space or comma-delimited name...
2643 for (end
= ptr
; *end
; end
++)
2644 if (isspace(*end
& 255) || *end
== ',')
2649 * Terminate the name...
2659 attr
->values
[i
].string
.text
= _cupsStrAlloc(ptr
);
2662 * Advance to the next name...
2670 * Do the request and get back a response...
2673 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2675 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2677 puts("Status: 401\n");
2680 else if (cupsLastError() > IPP_OK_CONFLICT
)
2682 cgiStartHTML(cgiText(_("Set Allowed Users")));
2683 cgiShowIPPError(_("Unable to change printer"));
2688 * Redirect successful updates back to the printer page...
2691 char url
[1024], /* Printer/class URL */
2692 refresh
[1024]; /* Refresh URL */
2695 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2696 cgiFormEncode(uri
, url
, sizeof(uri
));
2697 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2699 cgiSetVariable("refresh_page", refresh
);
2701 cgiStartHTML(cgiText(_("Set Allowed Users")));
2703 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2704 "printer-modified.tmpl");
2713 * 'do_set_default()' - Set the server default printer/class.
2717 do_set_default(http_t
*http
) /* I - HTTP connection */
2719 const char *title
; /* Page title */
2720 ipp_t
*request
; /* IPP request */
2721 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2722 const char *printer
, /* Printer name (purge-jobs) */
2723 *is_class
; /* Is a class? */
2726 is_class
= cgiGetVariable("IS_CLASS");
2727 printer
= cgiGetVariable("PRINTER_NAME");
2728 title
= cgiText(_("Set As Server Default"));
2732 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2733 cgiStartHTML(title
);
2734 cgiCopyTemplateLang("error.tmpl");
2740 * Build a printer request, which requires the following
2743 * attributes-charset
2744 * attributes-natural-language
2748 request
= ippNewRequest(CUPS_SET_DEFAULT
);
2750 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2751 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2753 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2757 * Do the request and get back a response...
2760 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2762 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2764 puts("Status: 401\n");
2767 else if (cupsLastError() > IPP_OK_CONFLICT
)
2769 cgiStartHTML(title
);
2770 cgiShowIPPError(_("Unable to set server default"));
2775 * Redirect successful updates back to the printer page...
2778 char url
[1024], /* Printer/class URL */
2779 refresh
[1024]; /* Refresh URL */
2782 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2783 cgiFormEncode(uri
, url
, sizeof(uri
));
2784 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2785 cgiSetVariable("refresh_page", refresh
);
2787 cgiStartHTML(title
);
2788 cgiCopyTemplateLang("printer-default.tmpl");
2796 * 'do_set_options()' - Configure the default options for a queue.
2800 do_set_options(http_t
*http
, /* I - HTTP connection */
2801 int is_class
) /* I - Set options for class? */
2803 int i
, j
, k
, m
; /* Looping vars */
2804 int have_options
; /* Have options? */
2805 ipp_t
*request
, /* IPP request */
2806 *response
; /* IPP response */
2807 ipp_attribute_t
*attr
; /* IPP attribute */
2808 char uri
[HTTP_MAX_URI
]; /* Job URI */
2809 const char *var
; /* Variable value */
2810 const char *printer
; /* Printer printer name */
2811 const char *filename
; /* PPD filename */
2812 char tempfile
[1024]; /* Temporary filename */
2813 cups_file_t
*in
, /* Input file */
2814 *out
; /* Output file */
2815 char line
[1024], /* Line from PPD file */
2816 value
[1024], /* Option value */
2817 keyword
[1024], /* Keyword from Default line */
2818 *keyptr
; /* Pointer into keyword... */
2819 ppd_file_t
*ppd
; /* PPD file */
2820 ppd_group_t
*group
; /* Option group */
2821 ppd_option_t
*option
; /* Option */
2822 ppd_coption_t
*coption
; /* Custom option */
2823 ppd_cparam_t
*cparam
; /* Custom parameter */
2824 ppd_attr_t
*ppdattr
; /* PPD attribute */
2825 const char *title
; /* Page title */
2828 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2830 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2834 * Get the printer name...
2837 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2838 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2839 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2843 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2844 cgiStartHTML(title
);
2845 cgiCopyTemplateLang("error.tmpl");
2850 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2853 * If the user clicks on the Auto-Configure button, send an AutoConfigure
2854 * command file to the printer...
2857 if (cgiGetVariable("AUTOCONFIGURE"))
2859 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
2864 * Get the PPD file...
2870 filename
= cupsGetPPD2(http
, printer
);
2874 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2876 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2878 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2879 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
2880 cgiStartHTML(title
);
2881 cgiCopyTemplateLang("error.tmpl");
2888 fputs("DEBUG: No PPD file\n", stderr
);
2892 if (cgiGetVariable("job_sheets_start") != NULL
||
2893 cgiGetVariable("job_sheets_end") != NULL
)
2900 ppdMarkDefaults(ppd
);
2902 for (option
= ppdFirstOption(ppd
);
2904 option
= ppdNextOption(ppd
))
2906 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2909 ppdMarkOption(ppd
, option
->keyword
, var
);
2910 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
2913 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
2917 if (!have_options
|| ppdConflicts(ppd
))
2920 * Show the options to the user...
2923 fputs("DEBUG: Showing options...\n", stderr
);
2926 * Show auto-configure button if supported...
2931 if (ppd
->num_filters
== 0 ||
2932 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
2933 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
2934 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2937 for (i
= 0; i
< ppd
->num_filters
; i
++)
2938 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
2940 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2947 * Get the printer attributes...
2950 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2952 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2953 "localhost", 0, "/printers/%s", printer
);
2954 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2957 response
= cupsDoRequest(http
, request
, "/");
2960 * List the groups used as "tabs"...
2967 for (group
= ppd
->groups
;
2968 i
< ppd
->num_groups
;
2971 cgiSetArray("GROUP_ID", i
, group
->name
);
2973 if (!strcmp(group
->name
, "InstallableOptions"))
2974 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
2976 cgiSetArray("GROUP", i
, group
->text
);
2980 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
2982 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
2983 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
2986 if (ippFindAttribute(response
, "printer-error-policy-supported",
2988 ippFindAttribute(response
, "printer-op-policy-supported",
2991 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
2992 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
2995 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
2996 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
2998 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
2999 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3002 cgiStartHTML(cgiText(_("Set Printer Options")));
3003 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3009 if (ppdConflicts(ppd
))
3011 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3014 for (j
= group
->num_options
, option
= group
->options
;
3017 if (option
->conflicted
)
3019 cgiSetArray("ckeyword", k
, option
->keyword
);
3020 cgiSetArray("ckeytext", k
, option
->text
);
3022 for (m
= 0; m
< option
->num_choices
; m
++)
3024 if (option
->choices
[m
].marked
)
3026 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3034 cgiCopyTemplateLang("option-conflict.tmpl");
3037 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3041 for (j
= group
->num_options
, option
= group
->options
;
3045 if (!strcmp(option
->keyword
, "PageRegion"))
3048 if (option
->num_choices
> 1)
3055 cgiSetVariable("GROUP_ID", group
->name
);
3057 if (!strcmp(group
->name
, "InstallableOptions"))
3058 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3060 cgiSetVariable("GROUP", group
->text
);
3062 cgiCopyTemplateLang("option-header.tmpl");
3064 for (j
= group
->num_options
, option
= group
->options
;
3068 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
3071 cgiSetVariable("KEYWORD", option
->keyword
);
3072 cgiSetVariable("KEYTEXT", option
->text
);
3074 if (option
->conflicted
)
3075 cgiSetVariable("CONFLICTED", "1");
3077 cgiSetVariable("CONFLICTED", "0");
3079 cgiSetSize("CHOICES", 0);
3080 cgiSetSize("TEXT", 0);
3081 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3083 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3084 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3088 if (option
->choices
[k
].marked
)
3089 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3092 cgiSetSize("PARAMS", 0);
3093 cgiSetSize("PARAMTEXT", 0);
3094 cgiSetSize("PARAMVALUE", 0);
3095 cgiSetSize("INPUTTYPE", 0);
3097 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3099 const char *units
= NULL
; /* Units value, if any */
3101 cgiSetVariable("ISCUSTOM", "1");
3103 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3105 cparam
= ppdNextCustomParam(coption
), m
++)
3107 if (!_cups_strcasecmp(option
->keyword
, "PageSize") &&
3108 _cups_strcasecmp(cparam
->name
, "Width") &&
3109 _cups_strcasecmp(cparam
->name
, "Height"))
3115 cgiSetArray("PARAMS", m
, cparam
->name
);
3116 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3117 cgiSetArray("INPUTTYPE", m
, "text");
3119 switch (cparam
->type
)
3121 case PPD_CUSTOM_POINTS
:
3122 if (!_cups_strncasecmp(option
->defchoice
, "Custom.", 7))
3124 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3126 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3127 strcmp(units
, "in") && strcmp(units
, "ft"))
3129 if (units
[1] == 'm')
3138 if (!strcmp(units
, "mm"))
3139 snprintf(value
, sizeof(value
), "%g",
3140 cparam
->current
.custom_points
/ 72.0 * 25.4);
3141 else if (!strcmp(units
, "cm"))
3142 snprintf(value
, sizeof(value
), "%g",
3143 cparam
->current
.custom_points
/ 72.0 * 2.54);
3144 else if (!strcmp(units
, "in"))
3145 snprintf(value
, sizeof(value
), "%g",
3146 cparam
->current
.custom_points
/ 72.0);
3147 else if (!strcmp(units
, "ft"))
3148 snprintf(value
, sizeof(value
), "%g",
3149 cparam
->current
.custom_points
/ 72.0 / 12.0);
3150 else if (!strcmp(units
, "m"))
3151 snprintf(value
, sizeof(value
), "%g",
3152 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3154 snprintf(value
, sizeof(value
), "%g",
3155 cparam
->current
.custom_points
);
3156 cgiSetArray("PARAMVALUE", m
, value
);
3159 case PPD_CUSTOM_CURVE
:
3160 case PPD_CUSTOM_INVCURVE
:
3161 case PPD_CUSTOM_REAL
:
3162 snprintf(value
, sizeof(value
), "%g",
3163 cparam
->current
.custom_real
);
3164 cgiSetArray("PARAMVALUE", m
, value
);
3167 case PPD_CUSTOM_INT
:
3168 snprintf(value
, sizeof(value
), "%d",
3169 cparam
->current
.custom_int
);
3170 cgiSetArray("PARAMVALUE", m
, value
);
3173 case PPD_CUSTOM_PASSCODE
:
3174 case PPD_CUSTOM_PASSWORD
:
3175 if (cparam
->current
.custom_password
)
3176 cgiSetArray("PARAMVALUE", m
,
3177 cparam
->current
.custom_password
);
3179 cgiSetArray("PARAMVALUE", m
, "");
3180 cgiSetArray("INPUTTYPE", m
, "password");
3183 case PPD_CUSTOM_STRING
:
3184 if (cparam
->current
.custom_string
)
3185 cgiSetArray("PARAMVALUE", m
,
3186 cparam
->current
.custom_string
);
3188 cgiSetArray("PARAMVALUE", m
, "");
3195 cgiSetArray("PARAMS", m
, "Units");
3196 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3197 cgiSetArray("PARAMVALUE", m
, units
);
3201 cgiSetVariable("ISCUSTOM", "0");
3205 case PPD_UI_BOOLEAN
:
3206 cgiCopyTemplateLang("option-boolean.tmpl");
3208 case PPD_UI_PICKONE
:
3209 cgiCopyTemplateLang("option-pickone.tmpl");
3211 case PPD_UI_PICKMANY
:
3212 cgiCopyTemplateLang("option-pickmany.tmpl");
3217 cgiCopyTemplateLang("option-trailer.tmpl");
3221 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3222 IPP_TAG_ZERO
)) != NULL
)
3225 * Add the job sheets options...
3228 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3229 cgiSetVariable("GROUP", cgiText(_("Banners")));
3230 cgiCopyTemplateLang("option-header.tmpl");
3232 cgiSetSize("CHOICES", attr
->num_values
);
3233 cgiSetSize("TEXT", attr
->num_values
);
3234 for (k
= 0; k
< attr
->num_values
; k
++)
3236 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3237 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3240 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3242 cgiSetVariable("KEYWORD", "job_sheets_start");
3243 cgiSetVariable("KEYTEXT",
3244 /* TRANSLATORS: Banner/cover sheet before the print job. */
3245 cgiText(_("Starting Banner")));
3246 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3247 attr
->values
[0].string
.text
: "");
3249 cgiCopyTemplateLang("option-pickone.tmpl");
3251 cgiSetVariable("KEYWORD", "job_sheets_end");
3252 cgiSetVariable("KEYTEXT",
3253 /* TRANSLATORS: Banner/cover sheet after the print job. */
3254 cgiText(_("Ending Banner")));
3255 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3256 attr
->values
[1].string
.text
: "");
3258 cgiCopyTemplateLang("option-pickone.tmpl");
3260 cgiCopyTemplateLang("option-trailer.tmpl");
3263 if (ippFindAttribute(response
, "printer-error-policy-supported",
3265 ippFindAttribute(response
, "printer-op-policy-supported",
3269 * Add the error and operation policy options...
3272 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3273 cgiSetVariable("GROUP", cgiText(_("Policies")));
3274 cgiCopyTemplateLang("option-header.tmpl");
3280 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3285 cgiSetSize("CHOICES", attr
->num_values
);
3286 cgiSetSize("TEXT", attr
->num_values
);
3287 for (k
= 0; k
< attr
->num_values
; k
++)
3289 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3290 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3293 attr
= ippFindAttribute(response
, "printer-error-policy",
3296 cgiSetVariable("KEYWORD", "printer_error_policy");
3297 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3298 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3299 "" : attr
->values
[0].string
.text
);
3302 cgiCopyTemplateLang("option-pickone.tmpl");
3305 * Operation policy...
3308 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3313 cgiSetSize("CHOICES", attr
->num_values
);
3314 cgiSetSize("TEXT", attr
->num_values
);
3315 for (k
= 0; k
< attr
->num_values
; k
++)
3317 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3318 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3321 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3323 cgiSetVariable("KEYWORD", "printer_op_policy");
3324 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3325 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3326 "" : attr
->values
[0].string
.text
);
3328 cgiCopyTemplateLang("option-pickone.tmpl");
3331 cgiCopyTemplateLang("option-trailer.tmpl");
3335 * Binary protocol support...
3338 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3339 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3341 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3342 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3344 cgiSetSize("CHOICES", attr
->num_values
);
3345 cgiSetSize("TEXT", attr
->num_values
);
3347 for (i
= 0; i
< attr
->num_values
; i
++)
3349 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3350 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3353 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3354 cgiSetVariable("KEYWORD", "port_monitor");
3355 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3356 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3358 cgiCopyTemplateLang("option-header.tmpl");
3359 cgiCopyTemplateLang("option-pickone.tmpl");
3360 cgiCopyTemplateLang("option-trailer.tmpl");
3363 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3366 ippDelete(response
);
3371 * Set default options...
3374 fputs("DEBUG: Setting options...\n", stderr
);
3378 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3379 in
= cupsFileOpen(filename
, "r");
3383 cgiSetVariable("ERROR", strerror(errno
));
3384 cgiStartHTML(cgiText(_("Set Printer Options")));
3385 cgiCopyTemplateLang("error.tmpl");
3401 while (cupsFileGets(in
, line
, sizeof(line
)))
3403 if (!strncmp(line
, "*cupsProtocol:", 14))
3405 else if (strncmp(line
, "*Default", 8))
3406 cupsFilePrintf(out
, "%s\n", line
);
3410 * Get default option name...
3413 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3415 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3416 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3421 if (!strcmp(keyword
, "PageRegion") ||
3422 !strcmp(keyword
, "PaperDimension") ||
3423 !strcmp(keyword
, "ImageableArea"))
3424 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3426 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3429 cupsFilePrintf(out
, "%s\n", line
);
3431 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3441 * Make sure temporary filename is cleared when there is no PPD...
3448 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3449 * following attributes:
3451 * attributes-charset
3452 * attributes-natural-language
3454 * job-sheets-default
3455 * printer-error-policy
3460 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3461 CUPS_ADD_MODIFY_PRINTER
);
3463 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3466 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3467 "job-sheets-default", 2, NULL
, NULL
);
3468 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3469 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3471 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3472 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3473 "printer-error-policy", NULL
, var
);
3475 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3476 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3477 "printer-op-policy", NULL
, var
);
3479 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3480 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3481 "port-monitor", NULL
, var
);
3484 * Do the request and get back a response...
3488 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3490 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3492 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3494 puts("Status: 401\n");
3497 else if (cupsLastError() > IPP_OK_CONFLICT
)
3499 cgiStartHTML(title
);
3500 cgiShowIPPError(_("Unable to set options"));
3505 * Redirect successful updates back to the printer page...
3508 char refresh
[1024]; /* Refresh URL */
3511 cgiFormEncode(uri
, printer
, sizeof(uri
));
3512 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3513 is_class
? "classes" : "printers", uri
);
3514 cgiSetVariable("refresh_page", refresh
);
3516 cgiStartHTML(title
);
3518 cgiCopyTemplateLang("printer-configured.tmpl");
3533 * 'do_set_sharing()' - Set printer-is-shared value.
3537 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3539 ipp_t
*request
, /* IPP request */
3540 *response
; /* IPP response */
3541 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3542 const char *printer
, /* Printer name */
3543 *is_class
, /* Is a class? */
3544 *shared
; /* Sharing value */
3547 is_class
= cgiGetVariable("IS_CLASS");
3548 printer
= cgiGetVariable("PRINTER_NAME");
3549 shared
= cgiGetVariable("SHARED");
3551 if (!printer
|| !shared
)
3553 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3554 cgiStartHTML(cgiText(_("Set Publishing")));
3555 cgiCopyTemplateLang("error.tmpl");
3561 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3562 * following attributes:
3564 * attributes-charset
3565 * attributes-natural-language
3570 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3572 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3573 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3575 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3578 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", (char)atoi(shared
));
3581 * Do the request and get back a response...
3584 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3586 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3588 ippDelete(response
);
3591 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3593 puts("Status: 401\n");
3596 else if (cupsLastError() > IPP_OK_CONFLICT
)
3598 cgiStartHTML(cgiText(_("Set Publishing")));
3599 cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
3604 * Redirect successful updates back to the printer page...
3607 char url
[1024], /* Printer/class URL */
3608 refresh
[1024]; /* Refresh URL */
3611 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3612 cgiFormEncode(uri
, url
, sizeof(uri
));
3613 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3614 cgiSetVariable("refresh_page", refresh
);
3616 cgiStartHTML(cgiText(_("Set Publishing")));
3617 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3618 "printer-modified.tmpl");
3626 * 'get_option_value()' - Return the value of an option.
3628 * This function also handles generation of custom option values.
3631 static char * /* O - Value string or NULL on error */
3633 ppd_file_t
*ppd
, /* I - PPD file */
3634 const char *name
, /* I - Option name */
3635 char *buffer
, /* I - String buffer */
3636 size_t bufsize
) /* I - Size of buffer */
3638 char *bufptr
, /* Pointer into buffer */
3639 *bufend
; /* End of buffer */
3640 ppd_coption_t
*coption
; /* Custom option */
3641 ppd_cparam_t
*cparam
; /* Current custom parameter */
3642 char keyword
[256]; /* Parameter name */
3643 const char *val
, /* Parameter value */
3644 *uval
; /* Units value */
3645 long integer
; /* Integer value */
3646 double number
, /* Number value */
3647 number_points
; /* Number in points */
3651 * See if we have a custom option choice...
3654 if ((val
= cgiGetVariable(name
)) == NULL
)
3662 else if (_cups_strcasecmp(val
, "Custom") ||
3663 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3666 * Not a custom choice...
3669 strlcpy(buffer
, val
, bufsize
);
3674 * OK, we have a custom option choice, format it...
3679 if (!strcmp(coption
->keyword
, "PageSize"))
3681 const char *lval
; /* Length string value */
3682 double width
, /* Width value */
3683 width_points
, /* Width in points */
3684 length
, /* Length value */
3685 length_points
; /* Length in points */
3688 val
= cgiGetVariable("PageSize.Width");
3689 lval
= cgiGetVariable("PageSize.Height");
3690 uval
= cgiGetVariable("PageSize.Units");
3692 if (!val
|| !lval
|| !uval
||
3693 (width
= strtod(val
, NULL
)) == 0.0 ||
3694 (length
= strtod(lval
, NULL
)) == 0.0 ||
3695 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3696 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3699 width_points
= get_points(width
, uval
);
3700 length_points
= get_points(length
, uval
);
3702 if (width_points
< ppd
->custom_min
[0] ||
3703 width_points
> ppd
->custom_max
[0] ||
3704 length_points
< ppd
->custom_min
[1] ||
3705 length_points
> ppd
->custom_max
[1])
3708 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
3710 else if (cupsArrayCount(coption
->params
) == 1)
3712 cparam
= ppdFirstCustomParam(coption
);
3713 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
3715 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3718 switch (cparam
->type
)
3720 case PPD_CUSTOM_CURVE
:
3721 case PPD_CUSTOM_INVCURVE
:
3722 case PPD_CUSTOM_REAL
:
3723 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3724 number
< cparam
->minimum
.custom_real
||
3725 number
> cparam
->maximum
.custom_real
)
3728 snprintf(buffer
, bufsize
, "Custom.%g", number
);
3731 case PPD_CUSTOM_INT
:
3732 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3733 integer
== LONG_MAX
||
3734 integer
< cparam
->minimum
.custom_int
||
3735 integer
> cparam
->maximum
.custom_int
)
3738 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
3741 case PPD_CUSTOM_POINTS
:
3742 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3744 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3745 (uval
= cgiGetVariable(keyword
)) == NULL
||
3746 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3747 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3750 number_points
= get_points(number
, uval
);
3751 if (number_points
< cparam
->minimum
.custom_points
||
3752 number_points
> cparam
->maximum
.custom_points
)
3755 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
3758 case PPD_CUSTOM_PASSCODE
:
3759 for (uval
= val
; *uval
; uval
++)
3760 if (!isdigit(*uval
& 255))
3763 case PPD_CUSTOM_PASSWORD
:
3764 case PPD_CUSTOM_STRING
:
3765 integer
= (long)strlen(val
);
3766 if (integer
< cparam
->minimum
.custom_string
||
3767 integer
> cparam
->maximum
.custom_string
)
3770 snprintf(buffer
, bufsize
, "Custom.%s", val
);
3776 const char *prefix
= "{"; /* Prefix string */
3780 bufend
= buffer
+ bufsize
;
3782 for (cparam
= ppdFirstCustomParam(coption
);
3784 cparam
= ppdNextCustomParam(coption
))
3786 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
3789 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3792 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%s%s=", prefix
, cparam
->name
);
3793 bufptr
+= strlen(bufptr
);
3796 switch (cparam
->type
)
3798 case PPD_CUSTOM_CURVE
:
3799 case PPD_CUSTOM_INVCURVE
:
3800 case PPD_CUSTOM_REAL
:
3801 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3802 number
< cparam
->minimum
.custom_real
||
3803 number
> cparam
->maximum
.custom_real
)
3806 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g", number
);
3809 case PPD_CUSTOM_INT
:
3810 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3811 integer
== LONG_MAX
||
3812 integer
< cparam
->minimum
.custom_int
||
3813 integer
> cparam
->maximum
.custom_int
)
3816 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%ld", integer
);
3819 case PPD_CUSTOM_POINTS
:
3820 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3822 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3823 (uval
= cgiGetVariable(keyword
)) == NULL
||
3824 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
3825 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
3826 strcmp(uval
, "mm") && strcmp(uval
, "m")))
3829 number_points
= get_points(number
, uval
);
3830 if (number_points
< cparam
->minimum
.custom_points
||
3831 number_points
> cparam
->maximum
.custom_points
)
3834 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g%s", number
, uval
);
3837 case PPD_CUSTOM_PASSCODE
:
3838 for (uval
= val
; *uval
; uval
++)
3839 if (!isdigit(*uval
& 255))
3842 case PPD_CUSTOM_PASSWORD
:
3843 case PPD_CUSTOM_STRING
:
3844 integer
= (long)strlen(val
);
3845 if (integer
< cparam
->minimum
.custom_string
||
3846 integer
> cparam
->maximum
.custom_string
)
3849 if ((bufptr
+ 2) > bufend
)
3855 while (*val
&& bufptr
< bufend
)
3857 if (*val
== '\\' || *val
== '\"')
3859 if ((bufptr
+ 1) >= bufend
)
3868 if (bufptr
>= bufend
)
3877 bufptr
+= strlen(bufptr
);
3880 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
3883 memcpy(bufptr
, "}", 2);
3891 * 'get_points()' - Get a value in points.
3894 static double /* O - Number in points */
3895 get_points(double number
, /* I - Original number */
3896 const char *uval
) /* I - Units */
3898 if (!strcmp(uval
, "mm")) /* Millimeters */
3899 return (number
* 72.0 / 25.4);
3900 else if (!strcmp(uval
, "cm")) /* Centimeters */
3901 return (number
* 72.0 / 2.54);
3902 else if (!strcmp(uval
, "in")) /* Inches */
3903 return (number
* 72.0);
3904 else if (!strcmp(uval
, "ft")) /* Feet */
3905 return (number
* 72.0 * 12.0);
3906 else if (!strcmp(uval
, "m")) /* Meters */
3907 return (number
* 72.0 / 0.0254);
3914 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
3917 static char * /* O - Filename or NULL */
3918 get_printer_ppd(const char *uri
, /* I - Printer URI */
3919 char *buffer
, /* I - Filename buffer */
3920 size_t bufsize
) /* I - Size of filename buffer */
3922 http_t
*http
; /* Connection to printer */
3923 ipp_t
*request
, /* Get-Printer-Attributes request */
3924 *response
; /* Get-Printer-Attributes response */
3925 char resolved
[1024], /* Resolved URI */
3926 scheme
[32], /* URI scheme */
3927 userpass
[256], /* Username:password */
3928 host
[256], /* Hostname */
3929 resource
[256]; /* Resource path */
3930 int port
; /* Port number */
3934 * Connect to the printer...
3937 if (strstr(uri
, "._tcp"))
3943 if (!_httpResolveURI(uri
, resolved
, sizeof(resolved
), _HTTP_RESOLVE_DEFAULT
, NULL
, NULL
))
3945 fprintf(stderr
, "ERROR: Unable to resolve \"%s\".\n", uri
);
3952 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), host
, sizeof(host
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
3954 fprintf(stderr
, "ERROR: Bad printer URI \"%s\".\n", uri
);
3958 http
= httpConnect2(host
, port
, NULL
, AF_UNSPEC
, !strcmp(scheme
, "ipps") ? HTTP_ENCRYPTION_ALWAYS
: HTTP_ENCRYPTION_IF_REQUESTED
, 1, 30000, NULL
);
3961 fprintf(stderr
, "ERROR: Unable to connect to \"%s:%d\": %s\n", host
, port
, cupsLastErrorString());
3966 * Send a Get-Printer-Attributes request...
3969 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
3970 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
3971 response
= cupsDoRequest(http
, request
, resource
);
3973 if (!_ppdCreateFromIPP(buffer
, bufsize
, response
))
3974 fprintf(stderr
, "ERROR: Unable to create PPD file: %s\n", strerror(errno
));
3976 ippDelete(response
);