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_export(http_t
*http
);
45 static void do_list_printers(http_t
*http
);
46 static void do_menu(http_t
*http
);
47 static void do_set_allowed_users(http_t
*http
);
48 static void do_set_default(http_t
*http
);
49 static void do_set_options(http_t
*http
, int is_class
);
50 static void do_set_sharing(http_t
*http
);
51 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
52 char *buffer
, size_t bufsize
);
53 static double get_points(double number
, const char *uval
);
54 static char *get_printer_ppd(const char *uri
, char *buffer
, size_t bufsize
);
58 * 'main()' - Main entry for CGI.
61 int /* O - Exit status */
64 http_t
*http
; /* Connection to the server */
65 const char *op
; /* Operation name */
69 * Connect to the HTTP server...
72 fputs("DEBUG: admin.cgi started...\n", stderr
);
74 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
78 perror("ERROR: Unable to connect to cupsd");
79 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
80 cupsServer() ? cupsServer() : "(null)");
81 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
82 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
86 fprintf(stderr
, "DEBUG: http=%p\n", http
);
89 * Set the web interface section...
92 cgiSetVariable("SECTION", "admin");
93 cgiSetVariable("REFRESH_PAGE", "");
96 * See if we have form data...
99 if (!cgiInitialize() || !cgiGetVariable("OP"))
102 * Nope, send the administration menu...
105 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
109 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
112 * Do the operation...
115 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
119 const char *printer
= getenv("PRINTER_NAME"),
120 /* Printer or class name */
121 *server_port
= getenv("SERVER_PORT");
122 /* Port number string */
123 int port
= atoi(server_port
? server_port
: "0");
125 char uri
[1024]; /* URL */
128 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
129 getenv("HTTPS") ? "https" : "http", NULL
,
130 getenv("SERVER_NAME"), port
, "/%s/%s",
131 cgiGetVariable("IS_CLASS") ? "classes" : "printers",
134 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
135 getenv("HTTPS") ? "https" : "http", NULL
,
136 getenv("SERVER_NAME"), port
, "/admin");
138 printf("Location: %s\n\n", uri
);
140 else if (!strcmp(op
, "set-allowed-users"))
141 do_set_allowed_users(http
);
142 else if (!strcmp(op
, "set-as-default"))
143 do_set_default(http
);
144 else if (!strcmp(op
, "set-sharing"))
145 do_set_sharing(http
);
146 else if (!strcmp(op
, "find-new-printers") ||
147 !strcmp(op
, "list-available-printers"))
148 do_list_printers(http
);
149 else if (!strcmp(op
, "add-class"))
150 do_am_class(http
, 0);
151 else if (!strcmp(op
, "add-printer"))
152 do_am_printer(http
, 0);
153 else if (!strcmp(op
, "modify-class"))
154 do_am_class(http
, 1);
155 else if (!strcmp(op
, "modify-printer"))
156 do_am_printer(http
, 1);
157 else if (!strcmp(op
, "delete-class"))
158 do_delete_class(http
);
159 else if (!strcmp(op
, "delete-printer"))
160 do_delete_printer(http
);
161 else if (!strcmp(op
, "set-class-options"))
162 do_set_options(http
, 1);
163 else if (!strcmp(op
, "set-printer-options"))
164 do_set_options(http
, 0);
165 else if (!strcmp(op
, "config-server"))
166 do_config_server(http
);
167 else if (!strcmp(op
, "export-samba"))
172 * Bad operation code - display an error...
175 cgiStartHTML(cgiText(_("Administration")));
176 cgiCopyTemplateLang("error-op.tmpl");
180 else if (op
&& !strcmp(op
, "redirect"))
182 const char *url
; /* Redirection URL... */
183 char prefix
[1024]; /* URL prefix */
187 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
188 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
190 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
191 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
193 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
195 if ((url
= cgiGetVariable("URL")) != NULL
)
197 char encoded
[1024], /* Encoded URL string */
198 *ptr
; /* Pointer into encoded string */
205 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
207 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
210 * Percent-encode this character; safe because we have at least 4
211 * bytes left in the array...
214 sprintf(ptr
, "%%%02X", *url
& 255);
226 * URL was too long, just redirect to the admin page...
229 printf("Location: %s/admin\n\n", prefix
);
234 * URL is OK, redirect there...
237 printf("Location: %s%s\n\n", prefix
, encoded
);
241 printf("Location: %s/admin\n\n", prefix
);
246 * Form data but no operation code - display an error...
249 cgiStartHTML(cgiText(_("Administration")));
250 cgiCopyTemplateLang("error-op.tmpl");
255 * Close the HTTP server connection...
261 * Return with no errors...
269 * 'choose_device_cb()' - Add a device to the device selection page.
274 const char *device_class
, /* I - Class */
275 const char *device_id
, /* I - 1284 device ID */
276 const char *device_info
, /* I - Description */
277 const char *device_make_and_model
, /* I - Make and model */
278 const char *device_uri
, /* I - Device URI */
279 const char *device_location
, /* I - Location */
280 const char *title
) /* I - Page title */
283 * For modern browsers, start a multi-part page so we can show that something
284 * is happening. Non-modern browsers just get everything at the end...
287 if (current_device
== 0 && cgiSupportsMultipart())
291 cgiCopyTemplateLang("choose-device.tmpl");
298 * Add the device to the array...
301 cgiSetArray("device_class", current_device
, device_class
);
302 cgiSetArray("device_id", current_device
, device_id
);
303 cgiSetArray("device_info", current_device
, device_info
);
304 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
305 cgiSetArray("device_uri", current_device
, device_uri
);
306 cgiSetArray("device_location", current_device
, device_location
);
313 * 'do_am_class()' - Add or modify a class.
317 do_am_class(http_t
*http
, /* I - HTTP connection */
318 int modify
) /* I - Modify the printer? */
320 int i
, j
; /* Looping vars */
321 int element
; /* Element number */
322 int num_printers
; /* Number of printers */
323 ipp_t
*request
, /* IPP request */
324 *response
; /* IPP response */
325 ipp_attribute_t
*attr
; /* member-uris attribute */
326 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
327 const char *name
, /* Pointer to class name */
328 *op
, /* Operation name */
329 *ptr
; /* Pointer to CGI variable */
330 const char *title
; /* Title of page */
331 static const char * const pattrs
[] = /* Requested printer attributes */
339 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
340 op
= cgiGetVariable("OP");
341 name
= cgiGetVariable("PRINTER_NAME");
343 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
346 * Build a CUPS_GET_PRINTERS request, which requires the
347 * following attributes:
350 * attributes-natural-language
353 request
= ippNewRequest(CUPS_GET_PRINTERS
);
355 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
357 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
358 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
361 * Do the request and get back a response...
366 cgiSetVariable("OP", op
);
368 cgiSetVariable("PRINTER_NAME", name
);
370 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
373 * Create MEMBER_URIS and MEMBER_NAMES arrays...
376 for (element
= 0, attr
= response
->attrs
;
379 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
381 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
382 (!name
|| _cups_strcasecmp(name
, ptr
+ 1)))
385 * Don't show the current class...
388 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
393 for (element
= 0, attr
= response
->attrs
;
396 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
398 if (!name
|| _cups_strcasecmp(name
, attr
->values
[0].string
.text
))
401 * Don't show the current class...
404 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
409 num_printers
= cgiGetSize("MEMBER_URIS");
419 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
420 * following attributes:
423 * attributes-natural-language
427 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
429 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
430 "localhost", 0, "/classes/%s", name
);
431 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
434 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
435 "requested-attributes",
436 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
440 * Do the request and get back a response...
443 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
445 if ((attr
= ippFindAttribute(response
, "member-names",
446 IPP_TAG_NAME
)) != NULL
)
449 * Mark any current members in the class...
452 for (j
= 0; j
< num_printers
; j
++)
453 cgiSetArray("MEMBER_SELECTED", j
, "");
455 for (i
= 0; i
< attr
->num_values
; i
++)
457 for (j
= 0; j
< num_printers
; j
++)
459 if (!_cups_strcasecmp(attr
->values
[i
].string
.text
,
460 cgiGetArray("MEMBER_NAMES", j
)))
462 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
469 if ((attr
= ippFindAttribute(response
, "printer-info",
470 IPP_TAG_TEXT
)) != NULL
)
471 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
473 if ((attr
= ippFindAttribute(response
, "printer-location",
474 IPP_TAG_TEXT
)) != NULL
)
475 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
481 * Update the location and description of an existing printer...
485 cgiCopyTemplateLang("modify-class.tmpl");
490 * Get the name, location, and description for a new printer...
494 cgiCopyTemplateLang("add-class.tmpl");
505 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
506 cgiCopyTemplateLang("error.tmpl");
511 for (ptr
= name
; *ptr
; ptr
++)
512 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
515 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
517 cgiSetVariable("ERROR",
518 cgiText(_("The class name may only contain up to "
519 "127 printable characters and may not "
520 "contain spaces, slashes (/), or the "
521 "pound sign (#).")));
523 cgiCopyTemplateLang("error.tmpl");
529 * Build a CUPS_ADD_CLASS request, which requires the following
533 * attributes-natural-language
537 * printer-is-accepting-jobs
542 request
= ippNewRequest(CUPS_ADD_CLASS
);
544 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
545 "localhost", 0, "/classes/%s", name
);
546 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
549 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
550 NULL
, cgiGetVariable("PRINTER_LOCATION"));
552 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
553 NULL
, cgiGetVariable("PRINTER_INFO"));
555 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
557 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
560 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
562 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
563 num_printers
, NULL
, NULL
);
564 for (i
= 0; i
< num_printers
; i
++)
565 ippSetString(request
, &attr
, i
, cgiGetArray("MEMBER_URIS", i
));
569 * Do the request and get back a response...
572 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
574 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
576 puts("Status: 401\n");
579 else if (cupsLastError() > IPP_OK_CONFLICT
)
582 cgiShowIPPError(modify
? _("Unable to modify class") :
583 _("Unable to add class"));
588 * Redirect successful updates back to the class page...
591 char refresh
[1024]; /* Refresh URL */
593 cgiFormEncode(uri
, name
, sizeof(uri
));
594 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
596 cgiSetVariable("refresh_page", refresh
);
601 cgiCopyTemplateLang("class-modified.tmpl");
603 cgiCopyTemplateLang("class-added.tmpl");
611 * 'do_am_printer()' - Add or modify a printer.
615 do_am_printer(http_t
*http
, /* I - HTTP connection */
616 int modify
) /* I - Modify the printer? */
618 int i
; /* Looping var */
619 ipp_attribute_t
*attr
; /* Current attribute */
620 ipp_t
*request
, /* IPP request */
621 *response
, /* IPP response */
622 *oldinfo
; /* Old printer information */
623 const cgi_file_t
*file
; /* Uploaded file, if any */
624 const char *var
; /* CGI variable */
625 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
626 *uriptr
, /* Pointer into URI */
627 evefile
[1024] = ""; /* IPP Everywhere PPD file */
628 int maxrate
; /* Maximum baud rate */
629 char baudrate
[255]; /* Baud rate string */
630 const char *name
, /* Pointer to class name */
631 *ptr
; /* Pointer to CGI variable */
632 const char *title
; /* Title of page */
633 static int baudrates
[] = /* Baud rates */
648 ptr
= cgiGetVariable("DEVICE_URI");
649 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
650 ptr
? ptr
: "(null)");
652 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
657 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
658 * following attributes:
661 * attributes-natural-language
665 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
667 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
668 "localhost", 0, "/printers/%s",
669 cgiGetVariable("PRINTER_NAME"));
670 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
674 * Do the request and get back a response...
677 oldinfo
= cupsDoRequest(http
, request
, "/");
686 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
687 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
688 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
689 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
692 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
694 for (ptr
= name
; *ptr
; ptr
++)
695 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '\\' || *ptr
== '?' || *ptr
== '\'' || *ptr
== '\"' || *ptr
== '#')
698 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
700 cgiSetVariable("ERROR",
701 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 (#).")));
703 cgiCopyTemplateLang("error.tmpl");
709 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
711 if ((uriptr
= strrchr(var
, '|')) != NULL
)
714 * Extract make and make/model from device URI string...
717 char make
[1024], /* Make string */
718 *makeptr
; /* Pointer into make */
723 strlcpy(make
, uriptr
, sizeof(make
));
725 if ((makeptr
= strchr(make
, ' ')) != NULL
)
727 else if ((makeptr
= strchr(make
, '-')) != NULL
)
729 else if (!_cups_strncasecmp(make
, "laserjet", 8) ||
730 !_cups_strncasecmp(make
, "deskjet", 7) ||
731 !_cups_strncasecmp(make
, "designjet", 9))
732 strlcpy(make
, "HP", sizeof(make
));
733 else if (!_cups_strncasecmp(make
, "phaser", 6))
734 strlcpy(make
, "Xerox", sizeof(make
));
735 else if (!_cups_strncasecmp(make
, "stylus", 6))
736 strlcpy(make
, "Epson", sizeof(make
));
738 strlcpy(make
, "Generic", sizeof(make
));
740 if (!cgiGetVariable("CURRENT_MAKE"))
741 cgiSetVariable("CURRENT_MAKE", make
);
743 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
744 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
748 char template[128], /* Template name */
749 *tptr
; /* Pointer into template name */
751 cgiSetVariable("PRINTER_INFO", uriptr
);
753 for (tptr
= template;
754 tptr
< (template + sizeof(template) - 1) && *uriptr
;
756 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
759 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
762 else if (*uriptr
== '?' || *uriptr
== '(')
767 cgiSetVariable("TEMPLATE_NAME", template);
775 * Look for devices so the user can pick something...
778 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
780 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
781 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
784 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
785 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
789 * Scan for devices for up to 30 seconds...
792 fputs("DEBUG: Getting list of devices...\n", stderr
);
795 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
796 (cups_device_cb_t
)choose_device_cb
,
797 (void *)title
) == IPP_OK
)
799 fputs("DEBUG: Got device list!\n", stderr
);
801 if (cgiSupportsMultipart())
804 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
806 cgiCopyTemplateLang("choose-device.tmpl");
809 if (cgiSupportsMultipart())
815 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
816 cupsLastError(), cupsLastErrorString());
817 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
819 puts("Status: 401\n");
825 cgiShowIPPError(modify
? _("Unable to modify printer") :
826 _("Unable to add printer"));
832 else if (!strchr(var
, '/') ||
833 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
835 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
838 * Set the current device URI for the form to the old one...
841 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
842 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
846 * User needs to set the full URI...
850 cgiCopyTemplateLang("choose-uri.tmpl");
853 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
856 * Need baud rate, parity, etc.
859 if ((var
= strchr(var
, '?')) != NULL
&&
860 strncmp(var
, "?baud=", 6) == 0)
861 maxrate
= atoi(var
+ 6);
865 for (i
= 0; i
< 10; i
++)
866 if (baudrates
[i
] > maxrate
)
870 sprintf(baudrate
, "%d", baudrates
[i
]);
871 cgiSetArray("BAUDRATES", i
, baudrate
);
875 cgiCopyTemplateLang("choose-serial.tmpl");
878 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
885 * Update the location and description of an existing printer...
890 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
891 IPP_TAG_TEXT
)) != NULL
)
892 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
894 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
895 IPP_TAG_TEXT
)) != NULL
)
896 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
898 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
899 IPP_TAG_BOOLEAN
)) != NULL
)
900 cgiSetVariable("PRINTER_IS_SHARED",
901 attr
->values
[0].boolean
? "1" : "0");
904 cgiCopyTemplateLang("modify-printer.tmpl");
909 * Get the name, location, and description for a new printer...
913 if (!strncmp(var
, "usb:", 4))
914 cgiSetVariable("printer_is_shared", "1");
916 #endif /* __APPLE__ */
917 cgiSetVariable("printer_is_shared", "0");
919 cgiCopyTemplateLang("add-printer.tmpl");
930 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
932 int ipp_everywhere
= !strncmp(var
, "ipp://", 6) || !strncmp(var
, "ipps://", 7) || (!strncmp(var
, "dnssd://", 8) && (strstr(var
, "_ipp._tcp") || strstr(var
, "_ipps._tcp")));
934 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
937 * Get the PPD file...
940 int fd
; /* PPD file */
941 char filename
[1024]; /* PPD filename */
942 ppd_file_t
*ppd
; /* PPD information */
943 char buffer
[1024]; /* Buffer */
944 ssize_t bytes
; /* Number of bytes */
945 http_status_t get_status
; /* Status of GET */
948 /* TODO: Use cupsGetFile() API... */
949 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
951 if (httpGet(http
, uri
))
954 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
956 if (get_status
!= HTTP_OK
)
960 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
961 uri
, get_status
, httpStatus(get_status
));
963 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
965 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
966 write(fd
, buffer
, (size_t)bytes
);
970 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
972 if (ppd
->manufacturer
)
973 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
976 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
983 int linenum
; /* Line number */
985 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
986 filename
, ppdErrorString(ppdLastError(&linenum
)));
994 "ERROR: Unable to create temporary file for PPD file: %s\n",
1000 * Build a CUPS_GET_PPDS request, which requires the following
1003 * attributes-charset
1004 * attributes-natural-language
1008 request
= ippNewRequest(CUPS_GET_PPDS
);
1010 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1011 NULL
, "ipp://localhost/printers/");
1013 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1014 var
= cgiGetVariable("CURRENT_MAKE");
1015 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1017 const char *make_model
; /* Make and model */
1020 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1021 "ppd-make", NULL
, var
);
1023 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1024 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1025 "ppd-make-and-model", NULL
, make_model
);
1028 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1029 "requested-attributes", NULL
, "ppd-make");
1032 * Do the request and get back a response...
1035 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1038 * Got the list of PPDs, see if the user has selected a make...
1041 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1044 * No PPD files with this make, try again with all makes...
1047 ippDelete(response
);
1049 request
= ippNewRequest(CUPS_GET_PPDS
);
1051 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1052 NULL
, "ipp://localhost/printers/");
1054 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1055 "requested-attributes", NULL
, "ppd-make");
1057 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1058 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1060 cgiStartHTML(title
);
1061 cgiCopyTemplateLang("choose-make.tmpl");
1064 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1066 cgiStartHTML(title
);
1067 cgiCopyTemplateLang("choose-make.tmpl");
1073 * Let the user choose a model...
1076 cgiStartHTML(title
);
1077 if (!cgiGetVariable("PPD_MAKE"))
1078 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1080 cgiSetVariable("SHOW_IPP_EVERYWHERE", "1");
1081 cgiCopyTemplateLang("choose-model.tmpl");
1085 ippDelete(response
);
1089 cgiStartHTML(title
);
1090 cgiShowIPPError(_("Unable to get list of printer drivers"));
1091 cgiCopyTemplateLang("error.tmpl");
1098 * Build a CUPS_ADD_PRINTER request, which requires the following
1101 * attributes-charset
1102 * attributes-natural-language
1108 * printer-is-accepting-jobs
1113 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1115 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1116 "localhost", 0, "/printers/%s",
1117 cgiGetVariable("PRINTER_NAME"));
1118 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1123 var
= cgiGetVariable("PPD_NAME");
1124 if (!strcmp(var
, "everywhere"))
1125 get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile
, sizeof(evefile
));
1126 else if (strcmp(var
, "__no_change__"))
1127 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name",
1131 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1132 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1134 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1135 NULL
, cgiGetVariable("PRINTER_INFO"));
1137 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1140 * Strip make and model from URI...
1143 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1146 if (!strncmp(uri
, "serial:", 7))
1149 * Update serial port URI to include baud rate, etc.
1152 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1153 uriptr
= uri
+ strlen(uri
);
1155 snprintf(uriptr
, sizeof(uri
) - (size_t)(uriptr
- uri
),
1156 "?baud=%s+bits=%s+parity=%s+flow=%s",
1157 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1158 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1161 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1164 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1166 var
= cgiGetVariable("printer_is_shared");
1167 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1168 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1170 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1174 * Do the request and get back a response...
1178 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1179 else if (evefile
[0])
1181 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", evefile
));
1185 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1187 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1189 puts("Status: 401\n");
1192 else if (cupsLastError() > IPP_OK_CONFLICT
)
1194 cgiStartHTML(title
);
1195 cgiShowIPPError(modify
? _("Unable to modify printer") :
1196 _("Unable to add printer"));
1201 * Redirect successful updates back to the printer page...
1204 char refresh
[1024]; /* Refresh URL */
1207 cgiFormEncode(uri
, name
, sizeof(uri
));
1209 snprintf(refresh
, sizeof(refresh
),
1210 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1212 cgiSetVariable("refresh_page", refresh
);
1214 cgiStartHTML(title
);
1216 cgiCopyTemplateLang("printer-modified.tmpl");
1221 * Set the printer options...
1224 cgiSetVariable("OP", "set-printer-options");
1225 do_set_options(http
, 0);
1238 * 'do_config_server()' - Configure server settings.
1242 do_config_server(http_t
*http
) /* I - HTTP connection */
1244 if (cgiGetVariable("CHANGESETTINGS"))
1247 * Save basic setting changes...
1250 int num_settings
; /* Number of server settings */
1251 cups_option_t
*settings
; /* Server settings */
1252 int advanced
, /* Advanced settings shown? */
1253 changed
; /* Have settings changed? */
1254 const char *debug_logging
, /* DEBUG_LOGGING value */
1255 *preserve_jobs
= NULL
,
1256 /* PRESERVE_JOBS value */
1257 *remote_admin
, /* REMOTE_ADMIN value */
1258 *remote_any
, /* REMOTE_ANY value */
1259 *share_printers
,/* SHARE_PRINTERS value */
1261 /* USER_CANCEL_ANY value */
1262 *browse_web_if
= NULL
,
1263 /* BrowseWebIF value */
1264 *preserve_job_history
= NULL
,
1265 /* PreserveJobHistory value */
1266 *preserve_job_files
= NULL
,
1267 /* PreserveJobFiles value */
1268 *max_clients
= NULL
,
1269 /* MaxClients value */
1272 *max_log_size
= NULL
;
1273 /* MaxLogSize value */
1274 const char *current_browse_web_if
,
1275 /* BrowseWebIF value */
1276 *current_preserve_job_history
,
1277 /* PreserveJobHistory value */
1278 *current_preserve_job_files
,
1279 /* PreserveJobFiles value */
1280 *current_max_clients
,
1281 /* MaxClients value */
1284 *current_max_log_size
;
1285 /* MaxLogSize value */
1287 char default_auth_type
[255];
1288 /* DefaultAuthType value */
1289 const char *val
; /* Setting value */
1290 #endif /* HAVE_GSSAPI */
1294 * Get the checkbox values from the form...
1297 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1298 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1299 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1300 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1301 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1303 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1307 * Get advanced settings...
1310 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1311 max_clients
= cgiGetVariable("MAX_CLIENTS");
1312 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1313 preserve_jobs
= cgiGetVariable("PRESERVE_JOBS");
1317 max_jobs
= cgiGetVariable("MAX_JOBS");
1318 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY");
1319 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES");
1321 if (!max_jobs
|| atoi(max_jobs
) < 0)
1324 if (!preserve_job_history
)
1325 preserve_job_history
= "On";
1327 if (!preserve_job_files
)
1328 preserve_job_files
= "1d";
1333 preserve_job_history
= "No";
1334 preserve_job_files
= "No";
1337 if (!max_clients
|| atoi(max_clients
) <= 0)
1338 max_clients
= "100";
1340 if (!max_log_size
|| atoi(max_log_size
) <= 0.0)
1341 max_log_size
= "1m";
1345 * Get the current server settings...
1348 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1350 cgiStartHTML(cgiText(_("Change Settings")));
1351 cgiSetVariable("MESSAGE",
1352 cgiText(_("Unable to change server settings")));
1353 cgiSetVariable("ERROR", cupsLastErrorString());
1354 cgiCopyTemplateLang("error.tmpl");
1361 * Get authentication settings...
1364 if (cgiGetVariable("KERBEROS"))
1365 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1368 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1370 if (!val
|| !_cups_strcasecmp(val
, "Negotiate"))
1371 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1373 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1376 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1377 #endif /* HAVE_GSSAPI */
1379 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1381 current_browse_web_if
= "No";
1383 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1386 current_preserve_job_history
= "Yes";
1388 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1391 current_preserve_job_files
= "1d";
1393 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1395 current_max_clients
= "100";
1397 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1399 current_max_jobs
= "500";
1401 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1403 current_max_log_size
= "1m";
1406 * See if the settings have changed...
1409 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1410 num_settings
, settings
)) ||
1411 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1412 num_settings
, settings
)) ||
1413 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1414 num_settings
, settings
)) ||
1415 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1416 num_settings
, settings
)) ||
1418 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1419 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1420 num_settings
, settings
)) ||
1421 #endif /* HAVE_GSSAPI */
1422 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1423 num_settings
, settings
));
1425 if (advanced
&& !changed
)
1426 changed
= _cups_strcasecmp(browse_web_if
, current_browse_web_if
) ||
1427 _cups_strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1428 _cups_strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1429 _cups_strcasecmp(max_clients
, current_max_clients
) ||
1430 _cups_strcasecmp(max_jobs
, current_max_jobs
) ||
1431 _cups_strcasecmp(max_log_size
, current_max_log_size
);
1436 * Settings *have* changed, so save the changes...
1439 cupsFreeOptions(num_settings
, settings
);
1442 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1443 debug_logging
, num_settings
, &settings
);
1444 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1445 remote_admin
, num_settings
, &settings
);
1446 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1447 remote_any
, num_settings
, &settings
);
1448 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1449 share_printers
, num_settings
, &settings
);
1450 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1451 user_cancel_any
, num_settings
, &settings
);
1453 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1454 num_settings
, &settings
);
1455 #endif /* HAVE_GSSAPI */
1460 * Add advanced settings...
1463 if (_cups_strcasecmp(browse_web_if
, current_browse_web_if
))
1464 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1465 num_settings
, &settings
);
1466 if (_cups_strcasecmp(preserve_job_history
, current_preserve_job_history
))
1467 num_settings
= cupsAddOption("PreserveJobHistory",
1468 preserve_job_history
, num_settings
,
1470 if (_cups_strcasecmp(preserve_job_files
, current_preserve_job_files
))
1471 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1472 num_settings
, &settings
);
1473 if (_cups_strcasecmp(max_clients
, current_max_clients
))
1474 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1476 if (_cups_strcasecmp(max_jobs
, current_max_jobs
))
1477 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1479 if (_cups_strcasecmp(max_log_size
, current_max_log_size
))
1480 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1484 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1486 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1488 puts("Status: 401\n");
1492 cgiStartHTML(cgiText(_("Change Settings")));
1493 cgiSetVariable("MESSAGE",
1494 cgiText(_("Unable to change server settings")));
1495 cgiSetVariable("ERROR", cupsLastErrorString());
1496 cgiCopyTemplateLang("error.tmpl");
1501 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1502 "URL=/admin/?ADVANCEDSETTINGS=YES");
1504 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1505 cgiStartHTML(cgiText(_("Change Settings")));
1506 cgiCopyTemplateLang("restart.tmpl");
1515 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1516 cgiStartHTML(cgiText(_("Change Settings")));
1517 cgiCopyTemplateLang("norestart.tmpl");
1520 cupsFreeOptions(num_settings
, settings
);
1524 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1527 * Save hand-edited config file...
1530 http_status_t status
; /* PUT status */
1531 char tempfile
[1024]; /* Temporary new cupsd.conf */
1532 int tempfd
; /* Temporary file descriptor */
1533 cups_file_t
*temp
; /* Temporary file */
1534 const char *start
, /* Start of line */
1535 *end
; /* End of line */
1539 * Create a temporary file for the new cupsd.conf file...
1542 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1544 cgiStartHTML(cgiText(_("Edit Configuration File")));
1545 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1546 cgiSetVariable("ERROR", strerror(errno
));
1547 cgiCopyTemplateLang("error.tmpl");
1554 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1556 cgiStartHTML(cgiText(_("Edit Configuration File")));
1557 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1558 cgiSetVariable("ERROR", strerror(errno
));
1559 cgiCopyTemplateLang("error.tmpl");
1569 * Copy the cupsd.conf text from the form variable...
1572 start
= cgiGetVariable("CUPSDCONF");
1575 if ((end
= strstr(start
, "\r\n")) == NULL
)
1576 if ((end
= strstr(start
, "\n")) == NULL
)
1577 end
= start
+ strlen(start
);
1579 cupsFileWrite(temp
, start
, (size_t)(end
- start
));
1580 cupsFilePutChar(temp
, '\n');
1584 else if (*end
== '\n')
1590 cupsFileClose(temp
);
1593 * Upload the configuration file to the server...
1596 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1598 if (status
== HTTP_UNAUTHORIZED
)
1600 puts("Status: 401\n");
1604 else if (status
!= HTTP_CREATED
)
1606 cgiSetVariable("MESSAGE",
1607 cgiText(_("Unable to upload cupsd.conf file")));
1608 cgiSetVariable("ERROR", httpStatus(status
));
1610 cgiStartHTML(cgiText(_("Edit Configuration File")));
1611 cgiCopyTemplateLang("error.tmpl");
1615 cgiSetVariable("refresh_page", "5;URL=/admin/");
1617 cgiStartHTML(cgiText(_("Edit Configuration File")));
1618 cgiCopyTemplateLang("restart.tmpl");
1627 struct stat info
; /* cupsd.conf information */
1628 cups_file_t
*cupsd
; /* cupsd.conf file */
1629 char *buffer
, /* Buffer for entire file */
1630 *bufptr
, /* Pointer into buffer */
1631 *bufend
; /* End of buffer */
1632 int ch
; /* Character from file */
1633 char filename
[1024]; /* Filename */
1634 const char *server_root
; /* Location of config files */
1638 * Locate the cupsd.conf file...
1641 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1642 server_root
= CUPS_SERVERROOT
;
1644 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1647 * Figure out the size...
1650 if (stat(filename
, &info
))
1652 cgiStartHTML(cgiText(_("Edit Configuration File")));
1653 cgiSetVariable("MESSAGE",
1654 cgiText(_("Unable to access cupsd.conf file")));
1655 cgiSetVariable("ERROR", strerror(errno
));
1656 cgiCopyTemplateLang("error.tmpl");
1663 if (info
.st_size
> (1024 * 1024))
1665 cgiStartHTML(cgiText(_("Edit Configuration File")));
1666 cgiSetVariable("MESSAGE",
1667 cgiText(_("Unable to access cupsd.conf file")));
1668 cgiSetVariable("ERROR",
1669 cgiText(_("Unable to edit cupsd.conf files larger than "
1671 cgiCopyTemplateLang("error.tmpl");
1674 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1675 (long)info
.st_size
);
1680 * Open the cupsd.conf file...
1683 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1686 * Unable to open - log an error...
1689 cgiStartHTML(cgiText(_("Edit Configuration File")));
1690 cgiSetVariable("MESSAGE",
1691 cgiText(_("Unable to access cupsd.conf file")));
1692 cgiSetVariable("ERROR", strerror(errno
));
1693 cgiCopyTemplateLang("error.tmpl");
1701 * Allocate memory and load the file into a string buffer...
1704 if ((buffer
= calloc(1, (size_t)info
.st_size
+ 1)) != NULL
)
1706 cupsFileRead(cupsd
, buffer
, (size_t)info
.st_size
);
1707 cgiSetVariable("CUPSDCONF", buffer
);
1711 cupsFileClose(cupsd
);
1714 * Then get the default cupsd.conf file and put that into a string as
1718 strlcat(filename
, ".default", sizeof(filename
));
1720 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1721 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1723 if ((buffer
= calloc(1, 2 * (size_t)info
.st_size
+ 1)) != NULL
)
1725 bufend
= buffer
+ 2 * info
.st_size
- 1;
1727 for (bufptr
= buffer
;
1728 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1730 if (ch
== '\\' || ch
== '\"')
1733 *bufptr
++ = (char)ch
;
1735 else if (ch
== '\n')
1740 else if (ch
== '\t')
1746 *bufptr
++ = (char)ch
;
1751 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1755 cupsFileClose(cupsd
);
1759 * Show the current config file...
1762 cgiStartHTML(cgiText(_("Edit Configuration File")));
1764 cgiCopyTemplateLang("edit-config.tmpl");
1772 * 'do_delete_class()' - Delete a class.
1776 do_delete_class(http_t
*http
) /* I - HTTP connection */
1778 ipp_t
*request
; /* IPP request */
1779 char uri
[HTTP_MAX_URI
]; /* Job URI */
1780 const char *pclass
; /* Printer class name */
1784 * Get form variables...
1787 if (cgiGetVariable("CONFIRM") == NULL
)
1789 cgiStartHTML(cgiText(_("Delete Class")));
1790 cgiCopyTemplateLang("class-confirm.tmpl");
1795 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1796 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1797 "localhost", 0, "/classes/%s", pclass
);
1800 cgiStartHTML(cgiText(_("Delete Class")));
1801 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1802 cgiCopyTemplateLang("error.tmpl");
1808 * Build a CUPS_DELETE_CLASS request, which requires the following
1811 * attributes-charset
1812 * attributes-natural-language
1816 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1818 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1822 * Do the request and get back a response...
1825 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1828 * Show the results...
1831 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1833 puts("Status: 401\n");
1836 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1839 * Redirect successful updates back to the classes page...
1842 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1845 cgiStartHTML(cgiText(_("Delete Class")));
1847 if (cupsLastError() > IPP_OK_CONFLICT
)
1848 cgiShowIPPError(_("Unable to delete class"));
1850 cgiCopyTemplateLang("class-deleted.tmpl");
1857 * 'do_delete_printer()' - Delete a printer.
1861 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1863 ipp_t
*request
; /* IPP request */
1864 char uri
[HTTP_MAX_URI
]; /* Job URI */
1865 const char *printer
; /* Printer printer name */
1869 * Get form variables...
1872 if (cgiGetVariable("CONFIRM") == NULL
)
1874 cgiStartHTML(cgiText(_("Delete Printer")));
1875 cgiCopyTemplateLang("printer-confirm.tmpl");
1880 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1881 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1882 "localhost", 0, "/printers/%s", printer
);
1885 cgiStartHTML(cgiText(_("Delete Printer")));
1886 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1887 cgiCopyTemplateLang("error.tmpl");
1893 * Build a CUPS_DELETE_PRINTER request, which requires the following
1896 * attributes-charset
1897 * attributes-natural-language
1901 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1903 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1907 * Do the request and get back a response...
1910 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1913 * Show the results...
1916 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1918 puts("Status: 401\n");
1921 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1924 * Redirect successful updates back to the printers page...
1927 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1930 cgiStartHTML(cgiText(_("Delete Printer")));
1932 if (cupsLastError() > IPP_OK_CONFLICT
)
1933 cgiShowIPPError(_("Unable to delete printer"));
1935 cgiCopyTemplateLang("printer-deleted.tmpl");
1942 * 'do_export()' - Export printers to Samba.
1946 do_export(http_t
*http
) /* I - HTTP connection */
1948 int i
, j
; /* Looping vars */
1949 ipp_t
*request
, /* IPP request */
1950 *response
; /* IPP response */
1951 const char *username
, /* Samba username */
1952 *password
, /* Samba password */
1953 *export_all
; /* Export all printers? */
1954 int export_count
, /* Number of printers to export */
1955 printer_count
; /* Number of available printers */
1956 const char *name
, /* What name to pull */
1957 *dest
; /* Current destination */
1958 char ppd
[1024]; /* PPD file */
1965 username
= cgiGetVariable("USERNAME");
1966 password
= cgiGetVariable("PASSWORD");
1967 export_all
= cgiGetVariable("EXPORT_ALL");
1968 export_count
= cgiGetSize("EXPORT_NAME");
1971 * Get list of available printers...
1974 cgiSetSize("PRINTER_NAME", 0);
1975 cgiSetSize("PRINTER_EXPORT", 0);
1977 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1979 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1982 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1983 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
1985 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1986 "requested-attributes", NULL
, "printer-name");
1988 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1990 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1991 ippDelete(response
);
1995 printer_count
= cgiGetSize("PRINTER_NAME");
1997 for (i
= 0; i
< printer_count
; i
++)
1999 dest
= cgiGetArray("PRINTER_NAME", i
);
2001 for (j
= 0; j
< export_count
; j
++)
2002 if (!_cups_strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2005 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2011 * Export or get the printers to export...
2014 if (username
&& *username
&& password
&& *password
&&
2015 (export_all
|| export_count
> 0))
2021 fputs("DEBUG: Export printers...\n", stderr
);
2025 name
= "PRINTER_NAME";
2026 export_count
= cgiGetSize("PRINTER_NAME");
2029 name
= "EXPORT_NAME";
2031 for (i
= 0; i
< export_count
; i
++)
2033 dest
= cgiGetArray(name
, i
);
2035 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2038 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2047 if (i
< export_count
)
2048 cgiSetVariable("ERROR", cupsLastErrorString());
2051 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2052 cgiCopyTemplateLang("samba-exported.tmpl");
2057 else if (username
&& !*username
)
2058 cgiSetVariable("ERROR",
2059 cgiText(_("A Samba username is required to export "
2060 "printer drivers")));
2061 else if (username
&& (!password
|| !*password
))
2062 cgiSetVariable("ERROR",
2063 cgiText(_("A Samba password is required to export "
2064 "printer drivers")));
2070 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2071 cgiCopyTemplateLang("samba-export.tmpl");
2077 * 'do_list_printers()' - List available printers.
2081 do_list_printers(http_t
*http
) /* I - HTTP connection */
2083 ipp_t
*request
, /* IPP request */
2084 *response
; /* IPP response */
2085 ipp_attribute_t
*attr
; /* IPP attribute */
2088 cgiStartHTML(cgiText(_("List Available Printers")));
2092 * Get the list of printers and their devices...
2095 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2097 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2098 "requested-attributes", NULL
, "device-uri");
2100 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2101 CUPS_PRINTER_LOCAL
);
2102 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2103 CUPS_PRINTER_LOCAL
);
2105 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2108 * Got the printer list, now load the devices...
2111 int i
; /* Looping var */
2112 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2113 char *printer_device
; /* Current printer device */
2117 * Allocate an array and copy the device strings...
2120 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2122 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2124 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2126 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2130 * Free the printer list and get the device list...
2133 ippDelete(response
);
2135 request
= ippNewRequest(CUPS_GET_DEVICES
);
2137 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2140 * Got the device list, let's parse it...
2143 const char *device_uri
, /* device-uri attribute value */
2144 *device_make_and_model
, /* device-make-and-model value */
2145 *device_info
; /* device-info value */
2148 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2151 * Skip leading attributes until we hit a device...
2154 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2161 * Pull the needed attributes from this device...
2165 device_make_and_model
= NULL
;
2168 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2170 if (!strcmp(attr
->name
, "device-info") &&
2171 attr
->value_tag
== IPP_TAG_TEXT
)
2172 device_info
= attr
->values
[0].string
.text
;
2174 if (!strcmp(attr
->name
, "device-make-and-model") &&
2175 attr
->value_tag
== IPP_TAG_TEXT
)
2176 device_make_and_model
= attr
->values
[0].string
.text
;
2178 if (!strcmp(attr
->name
, "device-uri") &&
2179 attr
->value_tag
== IPP_TAG_URI
)
2180 device_uri
= attr
->values
[0].string
.text
;
2186 * See if we have everything needed...
2189 if (device_info
&& device_make_and_model
&& device_uri
&&
2190 _cups_strcasecmp(device_make_and_model
, "unknown") &&
2191 strchr(device_uri
, ':'))
2194 * Yes, now see if there is already a printer for this
2198 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2201 * Not found, so it must be a new printer...
2204 char option
[1024], /* Form variables for this device */
2205 *option_ptr
; /* Pointer into string */
2206 const char *ptr
; /* Pointer into device string */
2210 * Format the printer name variable for this device...
2212 * We use the device-info string first, then device-uri,
2213 * and finally device-make-and-model to come up with a
2217 if (_cups_strncasecmp(device_info
, "unknown", 7))
2219 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2222 ptr
= device_make_and_model
;
2224 for (option_ptr
= option
;
2225 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2227 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2229 *option_ptr
++ = *ptr
;
2230 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2231 option_ptr
[-1] != '_')
2232 *option_ptr
++ = '_';
2233 else if (*ptr
== '?' || *ptr
== '(')
2238 cgiSetArray("TEMPLATE_NAME", i
, option
);
2241 * Finally, set the form variables for this printer...
2244 cgiSetArray("device_info", i
, device_info
);
2245 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2246 cgiSetArray("device_uri", i
, device_uri
);
2255 ippDelete(response
);
2258 * Free the device list...
2261 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2263 printer_device
= (char *)cupsArrayNext(printer_devices
))
2264 free(printer_device
);
2266 cupsArrayDelete(printer_devices
);
2271 * Finally, show the printer list...
2274 cgiCopyTemplateLang("list-available-printers.tmpl");
2281 * 'do_menu()' - Show the main menu.
2285 do_menu(http_t
*http
) /* I - HTTP connection */
2287 int num_settings
; /* Number of server settings */
2288 cups_option_t
*settings
; /* Server settings */
2289 const char *val
; /* Setting value */
2290 char filename
[1024]; /* Temporary filename */
2291 const char *datadir
; /* Location of data files */
2292 ipp_t
*request
, /* IPP request */
2293 *response
; /* IPP response */
2297 * Get the current server settings...
2300 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2302 cgiSetVariable("SETTINGS_MESSAGE",
2303 cgiText(_("Unable to open cupsd.conf file:")));
2304 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2307 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2308 settings
)) != NULL
&& atoi(val
))
2309 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2311 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2312 settings
)) != NULL
&& atoi(val
))
2313 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2315 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2316 settings
)) != NULL
&& atoi(val
))
2317 cgiSetVariable("REMOTE_ANY", "CHECKED");
2319 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2320 settings
)) != NULL
&& atoi(val
))
2321 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2323 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2324 settings
)) != NULL
&& atoi(val
))
2325 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2328 cgiSetVariable("HAVE_GSSAPI", "1");
2330 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2331 settings
)) != NULL
&& !_cups_strcasecmp(val
, "Negotiate"))
2332 cgiSetVariable("KERBEROS", "CHECKED");
2334 #endif /* HAVE_GSSAPI */
2335 cgiSetVariable("KERBEROS", "");
2337 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2341 if (!_cups_strcasecmp(val
, "yes") || !_cups_strcasecmp(val
, "on") ||
2342 !_cups_strcasecmp(val
, "true"))
2343 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2345 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2350 (!_cups_strcasecmp(val
, "0") || !_cups_strcasecmp(val
, "no") ||
2351 !_cups_strcasecmp(val
, "off") || !_cups_strcasecmp(val
, "false") ||
2352 !_cups_strcasecmp(val
, "disabled")))
2354 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2355 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2359 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2360 cgiSetVariable("PRESERVE_JOB_HISTORY", val
);
2362 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2366 cgiSetVariable("PRESERVE_JOB_FILES", val
);
2370 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2373 cgiSetVariable("MAX_CLIENTS", val
);
2375 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2378 cgiSetVariable("MAX_JOBS", val
);
2380 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2383 cgiSetVariable("MAX_LOG_SIZE", val
);
2385 cupsFreeOptions(num_settings
, settings
);
2388 * See if Samba and the Windows drivers are installed...
2391 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2392 datadir
= CUPS_DATADIR
;
2394 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2395 if (!access(filename
, R_OK
))
2398 * Found Windows 2000 driver file, see if we have smbclient and
2402 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2403 sizeof(filename
)) &&
2404 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2406 cgiSetVariable("HAVE_SAMBA", "Y");
2409 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2411 fputs("ERROR: smbclient not found!\n", stderr
);
2413 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2415 fputs("ERROR: rpcclient not found!\n", stderr
);
2425 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2427 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2428 NULL
, "ipp://localhost/");
2430 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2432 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2433 ippDelete(response
);
2437 * Finally, show the main menu template...
2440 cgiStartHTML(cgiText(_("Administration")));
2442 cgiCopyTemplateLang("admin.tmpl");
2449 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2453 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2455 int i
; /* Looping var */
2456 ipp_t
*request
, /* IPP request */
2457 *response
; /* IPP response */
2458 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2459 const char *printer
, /* Printer name (purge-jobs) */
2460 *is_class
, /* Is a class? */
2461 *users
, /* List of users or groups */
2462 *type
; /* Allow/deny type */
2463 int num_users
; /* Number of users */
2464 char *ptr
, /* Pointer into users string */
2465 *end
, /* Pointer to end of users string */
2466 quote
; /* Quote character */
2467 ipp_attribute_t
*attr
; /* Attribute */
2468 static const char * const attrs
[] = /* Requested attributes */
2470 "requesting-user-name-allowed",
2471 "requesting-user-name-denied"
2475 is_class
= cgiGetVariable("IS_CLASS");
2476 printer
= cgiGetVariable("PRINTER_NAME");
2480 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2481 cgiStartHTML(cgiText(_("Set Allowed Users")));
2482 cgiCopyTemplateLang("error.tmpl");
2487 users
= cgiGetVariable("users");
2488 type
= cgiGetVariable("type");
2490 if (!users
|| !type
||
2491 (strcmp(type
, "requesting-user-name-allowed") &&
2492 strcmp(type
, "requesting-user-name-denied")))
2495 * Build a Get-Printer-Attributes request, which requires the following
2498 * attributes-charset
2499 * attributes-natural-language
2501 * requested-attributes
2504 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2506 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2507 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2509 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2512 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2513 "requested-attributes",
2514 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2517 * Do the request and get back a response...
2520 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2522 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2524 ippDelete(response
);
2527 cgiStartHTML(cgiText(_("Set Allowed Users")));
2529 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2531 puts("Status: 401\n");
2534 else if (cupsLastError() > IPP_OK_CONFLICT
)
2535 cgiShowIPPError(_("Unable to get printer attributes"));
2537 cgiCopyTemplateLang("users.tmpl");
2544 * Save the changes...
2547 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2550 * Skip whitespace and commas...
2553 while (*ptr
== ',' || isspace(*ptr
& 255))
2559 if (*ptr
== '\'' || *ptr
== '\"')
2562 * Scan quoted name...
2567 for (end
= ptr
; *end
; end
++)
2574 * Scan space or comma-delimited name...
2577 for (end
= ptr
; *end
; end
++)
2578 if (isspace(*end
& 255) || *end
== ',')
2583 * Advance to the next name...
2590 * Build a CUPS-Add-Printer/Class request, which requires the following
2593 * attributes-charset
2594 * attributes-natural-language
2596 * requesting-user-name-{allowed,denied}
2599 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2601 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2602 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2604 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2608 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2609 "requesting-user-name-allowed", NULL
, "all");
2612 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2613 type
, num_users
, NULL
, NULL
);
2615 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2618 * Skip whitespace and commas...
2621 while (*ptr
== ',' || isspace(*ptr
& 255))
2627 if (*ptr
== '\'' || *ptr
== '\"')
2630 * Scan quoted name...
2635 for (end
= ptr
; *end
; end
++)
2642 * Scan space or comma-delimited name...
2645 for (end
= ptr
; *end
; end
++)
2646 if (isspace(*end
& 255) || *end
== ',')
2651 * Terminate the name...
2661 ippSetString(request
, &attr
, i
, ptr
);
2664 * Advance to the next name...
2672 * Do the request and get back a response...
2675 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2677 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2679 puts("Status: 401\n");
2682 else if (cupsLastError() > IPP_OK_CONFLICT
)
2684 cgiStartHTML(cgiText(_("Set Allowed Users")));
2685 cgiShowIPPError(_("Unable to change printer"));
2690 * Redirect successful updates back to the printer page...
2693 char url
[1024], /* Printer/class URL */
2694 refresh
[1024]; /* Refresh URL */
2697 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2698 cgiFormEncode(uri
, url
, sizeof(uri
));
2699 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2701 cgiSetVariable("refresh_page", refresh
);
2703 cgiStartHTML(cgiText(_("Set Allowed Users")));
2705 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2706 "printer-modified.tmpl");
2715 * 'do_set_default()' - Set the server default printer/class.
2719 do_set_default(http_t
*http
) /* I - HTTP connection */
2721 const char *title
; /* Page title */
2722 ipp_t
*request
; /* IPP request */
2723 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2724 const char *printer
, /* Printer name (purge-jobs) */
2725 *is_class
; /* Is a class? */
2728 is_class
= cgiGetVariable("IS_CLASS");
2729 printer
= cgiGetVariable("PRINTER_NAME");
2730 title
= cgiText(_("Set As Server Default"));
2734 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2735 cgiStartHTML(title
);
2736 cgiCopyTemplateLang("error.tmpl");
2742 * Build a printer request, which requires the following
2745 * attributes-charset
2746 * attributes-natural-language
2750 request
= ippNewRequest(CUPS_SET_DEFAULT
);
2752 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2753 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2755 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2759 * Do the request and get back a response...
2762 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2764 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2766 puts("Status: 401\n");
2769 else if (cupsLastError() > IPP_OK_CONFLICT
)
2771 cgiStartHTML(title
);
2772 cgiShowIPPError(_("Unable to set server default"));
2777 * Redirect successful updates back to the printer page...
2780 char url
[1024], /* Printer/class URL */
2781 refresh
[1024]; /* Refresh URL */
2784 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2785 cgiFormEncode(uri
, url
, sizeof(uri
));
2786 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2787 cgiSetVariable("refresh_page", refresh
);
2789 cgiStartHTML(title
);
2790 cgiCopyTemplateLang("printer-default.tmpl");
2798 * 'do_set_options()' - Configure the default options for a queue.
2802 do_set_options(http_t
*http
, /* I - HTTP connection */
2803 int is_class
) /* I - Set options for class? */
2805 int i
, j
, k
, m
; /* Looping vars */
2806 int have_options
; /* Have options? */
2807 ipp_t
*request
, /* IPP request */
2808 *response
; /* IPP response */
2809 ipp_attribute_t
*attr
; /* IPP attribute */
2810 char uri
[HTTP_MAX_URI
]; /* Job URI */
2811 const char *var
; /* Variable value */
2812 const char *printer
; /* Printer printer name */
2813 const char *filename
; /* PPD filename */
2814 char tempfile
[1024]; /* Temporary filename */
2815 cups_file_t
*in
, /* Input file */
2816 *out
; /* Output file */
2817 char line
[1024], /* Line from PPD file */
2818 value
[1024], /* Option value */
2819 keyword
[1024], /* Keyword from Default line */
2820 *keyptr
; /* Pointer into keyword... */
2821 ppd_file_t
*ppd
; /* PPD file */
2822 ppd_group_t
*group
; /* Option group */
2823 ppd_option_t
*option
; /* Option */
2824 ppd_coption_t
*coption
; /* Custom option */
2825 ppd_cparam_t
*cparam
; /* Custom parameter */
2826 ppd_attr_t
*ppdattr
; /* PPD attribute */
2827 const char *title
; /* Page title */
2830 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2832 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2836 * Get the printer name...
2839 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2840 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2841 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2845 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2846 cgiStartHTML(title
);
2847 cgiCopyTemplateLang("error.tmpl");
2852 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2855 * If the user clicks on the Auto-Configure button, send an AutoConfigure
2856 * command file to the printer...
2859 if (cgiGetVariable("AUTOCONFIGURE"))
2861 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
2866 * Get the PPD file...
2872 filename
= cupsGetPPD2(http
, printer
);
2876 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2878 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2880 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2881 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
2882 cgiStartHTML(title
);
2883 cgiCopyTemplateLang("error.tmpl");
2890 fputs("DEBUG: No PPD file\n", stderr
);
2894 if (cgiGetVariable("job_sheets_start") != NULL
||
2895 cgiGetVariable("job_sheets_end") != NULL
)
2902 ppdMarkDefaults(ppd
);
2904 for (option
= ppdFirstOption(ppd
);
2906 option
= ppdNextOption(ppd
))
2908 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2911 ppdMarkOption(ppd
, option
->keyword
, var
);
2912 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
2915 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
2919 if (!have_options
|| ppdConflicts(ppd
))
2922 * Show the options to the user...
2925 fputs("DEBUG: Showing options...\n", stderr
);
2928 * Show auto-configure button if supported...
2933 if (ppd
->num_filters
== 0 ||
2934 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
2935 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
2936 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2939 for (i
= 0; i
< ppd
->num_filters
; i
++)
2940 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
2942 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2949 * Get the printer attributes...
2952 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2954 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2955 "localhost", 0, "/printers/%s", printer
);
2956 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2959 response
= cupsDoRequest(http
, request
, "/");
2962 * List the groups used as "tabs"...
2969 for (group
= ppd
->groups
;
2970 i
< ppd
->num_groups
;
2973 cgiSetArray("GROUP_ID", i
, group
->name
);
2975 if (!strcmp(group
->name
, "InstallableOptions"))
2976 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
2978 cgiSetArray("GROUP", i
, group
->text
);
2982 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
2984 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
2985 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
2988 if (ippFindAttribute(response
, "printer-error-policy-supported",
2990 ippFindAttribute(response
, "printer-op-policy-supported",
2993 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
2994 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
2997 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
2998 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3000 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3001 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3004 cgiStartHTML(cgiText(_("Set Printer Options")));
3005 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3011 if (ppdConflicts(ppd
))
3013 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3016 for (j
= group
->num_options
, option
= group
->options
;
3019 if (option
->conflicted
)
3021 cgiSetArray("ckeyword", k
, option
->keyword
);
3022 cgiSetArray("ckeytext", k
, option
->text
);
3024 for (m
= 0; m
< option
->num_choices
; m
++)
3026 if (option
->choices
[m
].marked
)
3028 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3036 cgiCopyTemplateLang("option-conflict.tmpl");
3039 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3043 for (j
= group
->num_options
, option
= group
->options
;
3047 if (!strcmp(option
->keyword
, "PageRegion"))
3050 if (option
->num_choices
> 1)
3057 cgiSetVariable("GROUP_ID", group
->name
);
3059 if (!strcmp(group
->name
, "InstallableOptions"))
3060 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3062 cgiSetVariable("GROUP", group
->text
);
3064 cgiCopyTemplateLang("option-header.tmpl");
3066 for (j
= group
->num_options
, option
= group
->options
;
3070 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
3073 cgiSetVariable("KEYWORD", option
->keyword
);
3074 cgiSetVariable("KEYTEXT", option
->text
);
3076 if (option
->conflicted
)
3077 cgiSetVariable("CONFLICTED", "1");
3079 cgiSetVariable("CONFLICTED", "0");
3081 cgiSetSize("CHOICES", 0);
3082 cgiSetSize("TEXT", 0);
3083 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3085 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3086 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3090 if (option
->choices
[k
].marked
)
3091 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3094 cgiSetSize("PARAMS", 0);
3095 cgiSetSize("PARAMTEXT", 0);
3096 cgiSetSize("PARAMVALUE", 0);
3097 cgiSetSize("INPUTTYPE", 0);
3099 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3101 const char *units
= NULL
; /* Units value, if any */
3103 cgiSetVariable("ISCUSTOM", "1");
3105 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3107 cparam
= ppdNextCustomParam(coption
), m
++)
3109 if (!_cups_strcasecmp(option
->keyword
, "PageSize") &&
3110 _cups_strcasecmp(cparam
->name
, "Width") &&
3111 _cups_strcasecmp(cparam
->name
, "Height"))
3117 cgiSetArray("PARAMS", m
, cparam
->name
);
3118 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3119 cgiSetArray("INPUTTYPE", m
, "text");
3121 switch (cparam
->type
)
3123 case PPD_CUSTOM_POINTS
:
3124 if (!_cups_strncasecmp(option
->defchoice
, "Custom.", 7))
3126 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3128 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3129 strcmp(units
, "in") && strcmp(units
, "ft"))
3131 if (units
[1] == 'm')
3140 if (!strcmp(units
, "mm"))
3141 snprintf(value
, sizeof(value
), "%g",
3142 cparam
->current
.custom_points
/ 72.0 * 25.4);
3143 else if (!strcmp(units
, "cm"))
3144 snprintf(value
, sizeof(value
), "%g",
3145 cparam
->current
.custom_points
/ 72.0 * 2.54);
3146 else if (!strcmp(units
, "in"))
3147 snprintf(value
, sizeof(value
), "%g",
3148 cparam
->current
.custom_points
/ 72.0);
3149 else if (!strcmp(units
, "ft"))
3150 snprintf(value
, sizeof(value
), "%g",
3151 cparam
->current
.custom_points
/ 72.0 / 12.0);
3152 else if (!strcmp(units
, "m"))
3153 snprintf(value
, sizeof(value
), "%g",
3154 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3156 snprintf(value
, sizeof(value
), "%g",
3157 cparam
->current
.custom_points
);
3158 cgiSetArray("PARAMVALUE", m
, value
);
3161 case PPD_CUSTOM_CURVE
:
3162 case PPD_CUSTOM_INVCURVE
:
3163 case PPD_CUSTOM_REAL
:
3164 snprintf(value
, sizeof(value
), "%g",
3165 cparam
->current
.custom_real
);
3166 cgiSetArray("PARAMVALUE", m
, value
);
3169 case PPD_CUSTOM_INT
:
3170 snprintf(value
, sizeof(value
), "%d",
3171 cparam
->current
.custom_int
);
3172 cgiSetArray("PARAMVALUE", m
, value
);
3175 case PPD_CUSTOM_PASSCODE
:
3176 case PPD_CUSTOM_PASSWORD
:
3177 if (cparam
->current
.custom_password
)
3178 cgiSetArray("PARAMVALUE", m
,
3179 cparam
->current
.custom_password
);
3181 cgiSetArray("PARAMVALUE", m
, "");
3182 cgiSetArray("INPUTTYPE", m
, "password");
3185 case PPD_CUSTOM_STRING
:
3186 if (cparam
->current
.custom_string
)
3187 cgiSetArray("PARAMVALUE", m
,
3188 cparam
->current
.custom_string
);
3190 cgiSetArray("PARAMVALUE", m
, "");
3197 cgiSetArray("PARAMS", m
, "Units");
3198 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3199 cgiSetArray("PARAMVALUE", m
, units
);
3203 cgiSetVariable("ISCUSTOM", "0");
3207 case PPD_UI_BOOLEAN
:
3208 cgiCopyTemplateLang("option-boolean.tmpl");
3210 case PPD_UI_PICKONE
:
3211 cgiCopyTemplateLang("option-pickone.tmpl");
3213 case PPD_UI_PICKMANY
:
3214 cgiCopyTemplateLang("option-pickmany.tmpl");
3219 cgiCopyTemplateLang("option-trailer.tmpl");
3223 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3224 IPP_TAG_ZERO
)) != NULL
)
3227 * Add the job sheets options...
3230 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3231 cgiSetVariable("GROUP", cgiText(_("Banners")));
3232 cgiCopyTemplateLang("option-header.tmpl");
3234 cgiSetSize("CHOICES", attr
->num_values
);
3235 cgiSetSize("TEXT", attr
->num_values
);
3236 for (k
= 0; k
< attr
->num_values
; k
++)
3238 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3239 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3242 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3244 cgiSetVariable("KEYWORD", "job_sheets_start");
3245 cgiSetVariable("KEYTEXT",
3246 /* TRANSLATORS: Banner/cover sheet before the print job. */
3247 cgiText(_("Starting Banner")));
3248 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3249 attr
->values
[0].string
.text
: "");
3251 cgiCopyTemplateLang("option-pickone.tmpl");
3253 cgiSetVariable("KEYWORD", "job_sheets_end");
3254 cgiSetVariable("KEYTEXT",
3255 /* TRANSLATORS: Banner/cover sheet after the print job. */
3256 cgiText(_("Ending Banner")));
3257 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3258 attr
->values
[1].string
.text
: "");
3260 cgiCopyTemplateLang("option-pickone.tmpl");
3262 cgiCopyTemplateLang("option-trailer.tmpl");
3265 if (ippFindAttribute(response
, "printer-error-policy-supported",
3267 ippFindAttribute(response
, "printer-op-policy-supported",
3271 * Add the error and operation policy options...
3274 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3275 cgiSetVariable("GROUP", cgiText(_("Policies")));
3276 cgiCopyTemplateLang("option-header.tmpl");
3282 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3287 cgiSetSize("CHOICES", attr
->num_values
);
3288 cgiSetSize("TEXT", attr
->num_values
);
3289 for (k
= 0; k
< attr
->num_values
; k
++)
3291 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3292 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3295 attr
= ippFindAttribute(response
, "printer-error-policy",
3298 cgiSetVariable("KEYWORD", "printer_error_policy");
3299 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3300 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3301 "" : attr
->values
[0].string
.text
);
3304 cgiCopyTemplateLang("option-pickone.tmpl");
3307 * Operation policy...
3310 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3315 cgiSetSize("CHOICES", attr
->num_values
);
3316 cgiSetSize("TEXT", attr
->num_values
);
3317 for (k
= 0; k
< attr
->num_values
; k
++)
3319 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3320 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3323 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3325 cgiSetVariable("KEYWORD", "printer_op_policy");
3326 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3327 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3328 "" : attr
->values
[0].string
.text
);
3330 cgiCopyTemplateLang("option-pickone.tmpl");
3333 cgiCopyTemplateLang("option-trailer.tmpl");
3337 * Binary protocol support...
3340 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3341 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3343 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3344 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3346 cgiSetSize("CHOICES", attr
->num_values
);
3347 cgiSetSize("TEXT", attr
->num_values
);
3349 for (i
= 0; i
< attr
->num_values
; i
++)
3351 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3352 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3355 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3356 cgiSetVariable("KEYWORD", "port_monitor");
3357 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3358 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3360 cgiCopyTemplateLang("option-header.tmpl");
3361 cgiCopyTemplateLang("option-pickone.tmpl");
3362 cgiCopyTemplateLang("option-trailer.tmpl");
3365 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3368 ippDelete(response
);
3373 * Set default options...
3376 fputs("DEBUG: Setting options...\n", stderr
);
3380 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3381 in
= cupsFileOpen(filename
, "r");
3385 cgiSetVariable("ERROR", strerror(errno
));
3386 cgiStartHTML(cgiText(_("Set Printer Options")));
3387 cgiCopyTemplateLang("error.tmpl");
3403 while (cupsFileGets(in
, line
, sizeof(line
)))
3405 if (!strncmp(line
, "*cupsProtocol:", 14))
3407 else if (strncmp(line
, "*Default", 8))
3408 cupsFilePrintf(out
, "%s\n", line
);
3412 * Get default option name...
3415 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3417 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3418 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3423 if (!strcmp(keyword
, "PageRegion") ||
3424 !strcmp(keyword
, "PaperDimension") ||
3425 !strcmp(keyword
, "ImageableArea"))
3426 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3428 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3431 cupsFilePrintf(out
, "%s\n", line
);
3433 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3443 * Make sure temporary filename is cleared when there is no PPD...
3450 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3451 * following attributes:
3453 * attributes-charset
3454 * attributes-natural-language
3456 * job-sheets-default
3457 * printer-error-policy
3462 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3463 CUPS_ADD_MODIFY_PRINTER
);
3465 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3468 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3469 "job-sheets-default", 2, NULL
, NULL
);
3470 ippSetString(request
, &attr
, 0, cgiGetVariable("job_sheets_start"));
3471 ippSetString(request
, &attr
, 1, cgiGetVariable("job_sheets_end"));
3473 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3474 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3475 "printer-error-policy", NULL
, var
);
3477 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3478 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3479 "printer-op-policy", NULL
, var
);
3481 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3482 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3483 "port-monitor", NULL
, var
);
3486 * Do the request and get back a response...
3490 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3492 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3494 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3496 puts("Status: 401\n");
3499 else if (cupsLastError() > IPP_OK_CONFLICT
)
3501 cgiStartHTML(title
);
3502 cgiShowIPPError(_("Unable to set options"));
3507 * Redirect successful updates back to the printer page...
3510 char refresh
[1024]; /* Refresh URL */
3513 cgiFormEncode(uri
, printer
, sizeof(uri
));
3514 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3515 is_class
? "classes" : "printers", uri
);
3516 cgiSetVariable("refresh_page", refresh
);
3518 cgiStartHTML(title
);
3520 cgiCopyTemplateLang("printer-configured.tmpl");
3535 * 'do_set_sharing()' - Set printer-is-shared value.
3539 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3541 ipp_t
*request
, /* IPP request */
3542 *response
; /* IPP response */
3543 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3544 const char *printer
, /* Printer name */
3545 *is_class
, /* Is a class? */
3546 *shared
; /* Sharing value */
3549 is_class
= cgiGetVariable("IS_CLASS");
3550 printer
= cgiGetVariable("PRINTER_NAME");
3551 shared
= cgiGetVariable("SHARED");
3553 if (!printer
|| !shared
)
3555 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3556 cgiStartHTML(cgiText(_("Set Publishing")));
3557 cgiCopyTemplateLang("error.tmpl");
3563 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3564 * following attributes:
3566 * attributes-charset
3567 * attributes-natural-language
3572 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3574 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3575 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3577 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3580 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", (char)atoi(shared
));
3583 * Do the request and get back a response...
3586 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3588 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3590 ippDelete(response
);
3593 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3595 puts("Status: 401\n");
3598 else if (cupsLastError() > IPP_OK_CONFLICT
)
3600 cgiStartHTML(cgiText(_("Set Publishing")));
3601 cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
3606 * Redirect successful updates back to the printer page...
3609 char url
[1024], /* Printer/class URL */
3610 refresh
[1024]; /* Refresh URL */
3613 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3614 cgiFormEncode(uri
, url
, sizeof(uri
));
3615 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3616 cgiSetVariable("refresh_page", refresh
);
3618 cgiStartHTML(cgiText(_("Set Publishing")));
3619 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3620 "printer-modified.tmpl");
3628 * 'get_option_value()' - Return the value of an option.
3630 * This function also handles generation of custom option values.
3633 static char * /* O - Value string or NULL on error */
3635 ppd_file_t
*ppd
, /* I - PPD file */
3636 const char *name
, /* I - Option name */
3637 char *buffer
, /* I - String buffer */
3638 size_t bufsize
) /* I - Size of buffer */
3640 char *bufptr
, /* Pointer into buffer */
3641 *bufend
; /* End of buffer */
3642 ppd_coption_t
*coption
; /* Custom option */
3643 ppd_cparam_t
*cparam
; /* Current custom parameter */
3644 char keyword
[256]; /* Parameter name */
3645 const char *val
, /* Parameter value */
3646 *uval
; /* Units value */
3647 long integer
; /* Integer value */
3648 double number
, /* Number value */
3649 number_points
; /* Number in points */
3653 * See if we have a custom option choice...
3656 if ((val
= cgiGetVariable(name
)) == NULL
)
3664 else if (_cups_strcasecmp(val
, "Custom") ||
3665 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3668 * Not a custom choice...
3671 strlcpy(buffer
, val
, bufsize
);
3676 * OK, we have a custom option choice, format it...
3681 if (!strcmp(coption
->keyword
, "PageSize"))
3683 const char *lval
; /* Length string value */
3684 double width
, /* Width value */
3685 width_points
, /* Width in points */
3686 length
, /* Length value */
3687 length_points
; /* Length in points */
3690 val
= cgiGetVariable("PageSize.Width");
3691 lval
= cgiGetVariable("PageSize.Height");
3692 uval
= cgiGetVariable("PageSize.Units");
3694 if (!val
|| !lval
|| !uval
||
3695 (width
= strtod(val
, NULL
)) == 0.0 ||
3696 (length
= strtod(lval
, NULL
)) == 0.0 ||
3697 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3698 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3701 width_points
= get_points(width
, uval
);
3702 length_points
= get_points(length
, uval
);
3704 if (width_points
< ppd
->custom_min
[0] ||
3705 width_points
> ppd
->custom_max
[0] ||
3706 length_points
< ppd
->custom_min
[1] ||
3707 length_points
> ppd
->custom_max
[1])
3710 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
3712 else if (cupsArrayCount(coption
->params
) == 1)
3714 cparam
= ppdFirstCustomParam(coption
);
3715 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
3717 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3720 switch (cparam
->type
)
3722 case PPD_CUSTOM_CURVE
:
3723 case PPD_CUSTOM_INVCURVE
:
3724 case PPD_CUSTOM_REAL
:
3725 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3726 number
< cparam
->minimum
.custom_real
||
3727 number
> cparam
->maximum
.custom_real
)
3730 snprintf(buffer
, bufsize
, "Custom.%g", number
);
3733 case PPD_CUSTOM_INT
:
3734 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3735 integer
== LONG_MAX
||
3736 integer
< cparam
->minimum
.custom_int
||
3737 integer
> cparam
->maximum
.custom_int
)
3740 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
3743 case PPD_CUSTOM_POINTS
:
3744 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3746 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3747 (uval
= cgiGetVariable(keyword
)) == NULL
||
3748 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3749 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3752 number_points
= get_points(number
, uval
);
3753 if (number_points
< cparam
->minimum
.custom_points
||
3754 number_points
> cparam
->maximum
.custom_points
)
3757 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
3760 case PPD_CUSTOM_PASSCODE
:
3761 for (uval
= val
; *uval
; uval
++)
3762 if (!isdigit(*uval
& 255))
3765 case PPD_CUSTOM_PASSWORD
:
3766 case PPD_CUSTOM_STRING
:
3767 integer
= (long)strlen(val
);
3768 if (integer
< cparam
->minimum
.custom_string
||
3769 integer
> cparam
->maximum
.custom_string
)
3772 snprintf(buffer
, bufsize
, "Custom.%s", val
);
3778 const char *prefix
= "{"; /* Prefix string */
3782 bufend
= buffer
+ bufsize
;
3784 for (cparam
= ppdFirstCustomParam(coption
);
3786 cparam
= ppdNextCustomParam(coption
))
3788 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
3791 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3794 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%s%s=", prefix
, cparam
->name
);
3795 bufptr
+= strlen(bufptr
);
3798 switch (cparam
->type
)
3800 case PPD_CUSTOM_CURVE
:
3801 case PPD_CUSTOM_INVCURVE
:
3802 case PPD_CUSTOM_REAL
:
3803 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3804 number
< cparam
->minimum
.custom_real
||
3805 number
> cparam
->maximum
.custom_real
)
3808 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g", number
);
3811 case PPD_CUSTOM_INT
:
3812 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3813 integer
== LONG_MAX
||
3814 integer
< cparam
->minimum
.custom_int
||
3815 integer
> cparam
->maximum
.custom_int
)
3818 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%ld", integer
);
3821 case PPD_CUSTOM_POINTS
:
3822 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3824 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3825 (uval
= cgiGetVariable(keyword
)) == NULL
||
3826 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
3827 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
3828 strcmp(uval
, "mm") && strcmp(uval
, "m")))
3831 number_points
= get_points(number
, uval
);
3832 if (number_points
< cparam
->minimum
.custom_points
||
3833 number_points
> cparam
->maximum
.custom_points
)
3836 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g%s", number
, uval
);
3839 case PPD_CUSTOM_PASSCODE
:
3840 for (uval
= val
; *uval
; uval
++)
3841 if (!isdigit(*uval
& 255))
3844 case PPD_CUSTOM_PASSWORD
:
3845 case PPD_CUSTOM_STRING
:
3846 integer
= (long)strlen(val
);
3847 if (integer
< cparam
->minimum
.custom_string
||
3848 integer
> cparam
->maximum
.custom_string
)
3851 if ((bufptr
+ 2) > bufend
)
3857 while (*val
&& bufptr
< bufend
)
3859 if (*val
== '\\' || *val
== '\"')
3861 if ((bufptr
+ 1) >= bufend
)
3870 if (bufptr
>= bufend
)
3879 bufptr
+= strlen(bufptr
);
3882 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
3885 memcpy(bufptr
, "}", 2);
3893 * 'get_points()' - Get a value in points.
3896 static double /* O - Number in points */
3897 get_points(double number
, /* I - Original number */
3898 const char *uval
) /* I - Units */
3900 if (!strcmp(uval
, "mm")) /* Millimeters */
3901 return (number
* 72.0 / 25.4);
3902 else if (!strcmp(uval
, "cm")) /* Centimeters */
3903 return (number
* 72.0 / 2.54);
3904 else if (!strcmp(uval
, "in")) /* Inches */
3905 return (number
* 72.0);
3906 else if (!strcmp(uval
, "ft")) /* Feet */
3907 return (number
* 72.0 * 12.0);
3908 else if (!strcmp(uval
, "m")) /* Meters */
3909 return (number
* 72.0 / 0.0254);
3916 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
3919 static char * /* O - Filename or NULL */
3920 get_printer_ppd(const char *uri
, /* I - Printer URI */
3921 char *buffer
, /* I - Filename buffer */
3922 size_t bufsize
) /* I - Size of filename buffer */
3924 http_t
*http
; /* Connection to printer */
3925 ipp_t
*request
, /* Get-Printer-Attributes request */
3926 *response
; /* Get-Printer-Attributes response */
3927 char resolved
[1024], /* Resolved URI */
3928 scheme
[32], /* URI scheme */
3929 userpass
[256], /* Username:password */
3930 host
[256], /* Hostname */
3931 resource
[256]; /* Resource path */
3932 int port
; /* Port number */
3933 static const char * const pattrs
[] = /* Printer attributes we need */
3936 "media-col-database"
3941 * Connect to the printer...
3944 if (strstr(uri
, "._tcp"))
3950 if (!_httpResolveURI(uri
, resolved
, sizeof(resolved
), _HTTP_RESOLVE_DEFAULT
, NULL
, NULL
))
3952 fprintf(stderr
, "ERROR: Unable to resolve \"%s\".\n", uri
);
3959 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), host
, sizeof(host
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
3961 fprintf(stderr
, "ERROR: Bad printer URI \"%s\".\n", uri
);
3965 http
= httpConnect2(host
, port
, NULL
, AF_UNSPEC
, !strcmp(scheme
, "ipps") ? HTTP_ENCRYPTION_ALWAYS
: HTTP_ENCRYPTION_IF_REQUESTED
, 1, 30000, NULL
);
3968 fprintf(stderr
, "ERROR: Unable to connect to \"%s:%d\": %s\n", host
, port
, cupsLastErrorString());
3973 * Send a Get-Printer-Attributes request...
3976 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
3977 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
3978 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "requested-attributes", (int)(sizeof(pattrs
) / sizeof(pattrs
[0])), NULL
, pattrs
);
3979 response
= cupsDoRequest(http
, request
, resource
);
3981 if (!_ppdCreateFromIPP(buffer
, bufsize
, response
))
3982 fprintf(stderr
, "ERROR: Unable to create PPD file: %s\n", strerror(errno
));
3984 ippDelete(response
);