2 * "$Id: admin.c 11594 2014-02-14 20:09:01Z msweet $"
4 * Administration CGI for CUPS.
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * Include necessary headers...
20 #include "cgi-private.h"
21 #include <cups/adminutil.h>
34 static int current_device
= 0; /* Current device shown */
41 static void choose_device_cb(const char *device_class
,
42 const char *device_id
, const char *device_info
,
43 const char *device_make_and_model
,
44 const char *device_uri
,
45 const char *device_location
,
47 static void do_add_rss_subscription(http_t
*http
);
48 static void do_am_class(http_t
*http
, int modify
);
49 static void do_am_printer(http_t
*http
, int modify
);
50 static void do_cancel_subscription(http_t
*http
);
51 static void do_config_server(http_t
*http
);
52 static void do_delete_class(http_t
*http
);
53 static void do_delete_printer(http_t
*http
);
54 static void do_export(http_t
*http
);
55 static void do_list_printers(http_t
*http
);
56 static void do_menu(http_t
*http
);
57 static void do_set_allowed_users(http_t
*http
);
58 static void do_set_default(http_t
*http
);
59 static void do_set_options(http_t
*http
, int is_class
);
60 static void do_set_sharing(http_t
*http
);
61 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
62 char *buffer
, size_t bufsize
);
63 static double get_points(double number
, const char *uval
);
67 * 'main()' - Main entry for CGI.
70 int /* O - Exit status */
73 http_t
*http
; /* Connection to the server */
74 const char *op
; /* Operation name */
78 * Connect to the HTTP server...
81 fputs("DEBUG: admin.cgi started...\n", stderr
);
83 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
87 perror("ERROR: Unable to connect to cupsd");
88 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
89 cupsServer() ? cupsServer() : "(null)");
90 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
91 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
95 fprintf(stderr
, "DEBUG: http=%p\n", http
);
98 * Set the web interface section...
101 cgiSetVariable("SECTION", "admin");
102 cgiSetVariable("REFRESH_PAGE", "");
105 * See if we have form data...
108 if (!cgiInitialize() || !cgiGetVariable("OP"))
111 * Nope, send the administration menu...
114 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
118 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
121 * Do the operation...
124 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
128 const char *printer
= getenv("PRINTER_NAME"),
129 /* Printer or class name */
130 *server_port
= getenv("SERVER_PORT");
131 /* Port number string */
132 int port
= atoi(server_port
? server_port
: "0");
134 char uri
[1024]; /* URL */
137 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
138 getenv("HTTPS") ? "https" : "http", NULL
,
139 getenv("SERVER_NAME"), port
, "/%s/%s",
140 cgiGetVariable("IS_CLASS") ? "classes" : "printers",
143 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
144 getenv("HTTPS") ? "https" : "http", NULL
,
145 getenv("SERVER_NAME"), port
, "/admin");
147 printf("Location: %s\n\n", uri
);
149 else if (!strcmp(op
, "set-allowed-users"))
150 do_set_allowed_users(http
);
151 else if (!strcmp(op
, "set-as-default"))
152 do_set_default(http
);
153 else if (!strcmp(op
, "set-sharing"))
154 do_set_sharing(http
);
155 else if (!strcmp(op
, "find-new-printers") ||
156 !strcmp(op
, "list-available-printers"))
157 do_list_printers(http
);
158 else if (!strcmp(op
, "add-class"))
159 do_am_class(http
, 0);
160 else if (!strcmp(op
, "add-printer"))
161 do_am_printer(http
, 0);
162 else if (!strcmp(op
, "modify-class"))
163 do_am_class(http
, 1);
164 else if (!strcmp(op
, "modify-printer"))
165 do_am_printer(http
, 1);
166 else if (!strcmp(op
, "delete-class"))
167 do_delete_class(http
);
168 else if (!strcmp(op
, "delete-printer"))
169 do_delete_printer(http
);
170 else if (!strcmp(op
, "set-class-options"))
171 do_set_options(http
, 1);
172 else if (!strcmp(op
, "set-printer-options"))
173 do_set_options(http
, 0);
174 else if (!strcmp(op
, "config-server"))
175 do_config_server(http
);
176 else if (!strcmp(op
, "export-samba"))
178 else if (!strcmp(op
, "add-rss-subscription"))
179 do_add_rss_subscription(http
);
180 else if (!strcmp(op
, "cancel-subscription"))
181 do_cancel_subscription(http
);
185 * Bad operation code - display an error...
188 cgiStartHTML(cgiText(_("Administration")));
189 cgiCopyTemplateLang("error-op.tmpl");
193 else if (op
&& !strcmp(op
, "redirect"))
195 const char *url
; /* Redirection URL... */
196 char prefix
[1024]; /* URL prefix */
200 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
201 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
203 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
204 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
206 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
208 if ((url
= cgiGetVariable("URL")) != NULL
)
210 char encoded
[1024], /* Encoded URL string */
211 *ptr
; /* Pointer into encoded string */
218 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
220 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
223 * Percent-encode this character; safe because we have at least 4
224 * bytes left in the array...
227 sprintf(ptr
, "%%%02X", *url
& 255);
239 * URL was too long, just redirect to the admin page...
242 printf("Location: %s/admin\n\n", prefix
);
247 * URL is OK, redirect there...
250 printf("Location: %s%s\n\n", prefix
, encoded
);
254 printf("Location: %s/admin\n\n", prefix
);
259 * Form data but no operation code - display an error...
262 cgiStartHTML(cgiText(_("Administration")));
263 cgiCopyTemplateLang("error-op.tmpl");
268 * Close the HTTP server connection...
274 * Return with no errors...
282 * 'choose_device_cb()' - Add a device to the device selection page.
287 const char *device_class
, /* I - Class */
288 const char *device_id
, /* I - 1284 device ID */
289 const char *device_info
, /* I - Description */
290 const char *device_make_and_model
, /* I - Make and model */
291 const char *device_uri
, /* I - Device URI */
292 const char *device_location
, /* I - Location */
293 const char *title
) /* I - Page title */
296 * For modern browsers, start a multi-part page so we can show that something
297 * is happening. Non-modern browsers just get everything at the end...
300 if (current_device
== 0 && cgiSupportsMultipart())
304 cgiCopyTemplateLang("choose-device.tmpl");
311 * Add the device to the array...
314 cgiSetArray("device_class", current_device
, device_class
);
315 cgiSetArray("device_id", current_device
, device_id
);
316 cgiSetArray("device_info", current_device
, device_info
);
317 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
318 cgiSetArray("device_uri", current_device
, device_uri
);
319 cgiSetArray("device_location", current_device
, device_location
);
326 * 'do_add_rss_subscription()' - Add a RSS subscription.
330 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
332 ipp_t
*request
, /* IPP request data */
333 *response
; /* IPP response data */
334 char rss_uri
[1024]; /* RSS notify-recipient URI */
335 int num_events
; /* Number of events */
336 const char *events
[12], /* Subscribed events */
337 *subscription_name
, /* Subscription name */
338 *printer_uri
, /* Printer URI */
339 *ptr
, /* Pointer into name */
340 *user
; /* Username */
341 int max_events
; /* Maximum number of events */
345 * See if we have all of the required information...
348 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
349 printer_uri
= cgiGetVariable("PRINTER_URI");
352 if (cgiGetVariable("EVENT_JOB_CREATED"))
353 events
[num_events
++] = "job-created";
354 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
355 events
[num_events
++] = "job-completed";
356 if (cgiGetVariable("EVENT_JOB_STOPPED"))
357 events
[num_events
++] = "job-stopped";
358 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
359 events
[num_events
++] = "job-config-changed";
360 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
361 events
[num_events
++] = "printer-stopped";
362 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
363 events
[num_events
++] = "printer-added";
364 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
365 events
[num_events
++] = "printer-modified";
366 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
367 events
[num_events
++] = "printer-deleted";
368 if (cgiGetVariable("EVENT_SERVER_STARTED"))
369 events
[num_events
++] = "server-started";
370 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
371 events
[num_events
++] = "server-stopped";
372 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
373 events
[num_events
++] = "server-restarted";
374 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
375 events
[num_events
++] = "server-audit";
377 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
378 max_events
= atoi(ptr
);
382 if (!subscription_name
|| !printer_uri
|| !num_events
||
383 max_events
<= 0 || max_events
> 9999)
386 * Don't have everything we need, so get the available printers
387 * and classes and (re)show the add page...
390 if (cgiGetVariable("EVENT_JOB_CREATED"))
391 cgiSetVariable("EVENT_JOB_CREATED", "CHECKED");
392 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
393 cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED");
394 if (cgiGetVariable("EVENT_JOB_STOPPED"))
395 cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED");
396 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
397 cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED");
398 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
399 cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED");
400 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
401 cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED");
402 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
403 cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED");
404 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
405 cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED");
406 if (cgiGetVariable("EVENT_SERVER_STARTED"))
407 cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED");
408 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
409 cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED");
410 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
411 cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED");
412 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
413 cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED");
415 request
= ippNewRequest(CUPS_GET_PRINTERS
);
416 response
= cupsDoRequest(http
, request
, "/");
418 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
422 cgiStartHTML(cgiText(_("Add RSS Subscription")));
424 cgiCopyTemplateLang("add-rss-subscription.tmpl");
431 * Make sure we have a username...
434 if ((user
= getenv("REMOTE_USER")) == NULL
)
436 puts("Status: 401\n");
441 * Validate the subscription name...
444 for (ptr
= subscription_name
; *ptr
; ptr
++)
445 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
446 *ptr
== '?' || *ptr
== '#')
451 cgiSetVariable("ERROR",
452 cgiText(_("The subscription name may not "
453 "contain spaces, slashes (/), question marks (?), "
454 "or the pound sign (#).")));
455 cgiStartHTML(_("Add RSS Subscription"));
456 cgiCopyTemplateLang("error.tmpl");
462 * Add the subscription...
465 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
466 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
467 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
468 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
471 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
472 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
475 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
477 if (!_cups_strcasecmp(printer_uri
, "#ALL#"))
478 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
479 NULL
, "ipp://localhost/");
481 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
484 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
487 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
488 "notify-recipient-uri", NULL
, rss_uri
);
489 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
490 num_events
, NULL
, events
);
491 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
492 "notify-lease-duration", 0);
494 ippDelete(cupsDoRequest(http
, request
, "/"));
496 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
498 puts("Status: 401\n");
501 else if (cupsLastError() > IPP_OK_CONFLICT
)
503 cgiStartHTML(_("Add RSS Subscription"));
504 cgiShowIPPError(_("Unable to add RSS subscription"));
509 * Redirect successful updates back to the admin page...
512 cgiSetVariable("refresh_page", "5;URL=/admin");
513 cgiStartHTML(_("Add RSS Subscription"));
514 cgiCopyTemplateLang("subscription-added.tmpl");
522 * 'do_am_class()' - Add or modify a class.
526 do_am_class(http_t
*http
, /* I - HTTP connection */
527 int modify
) /* I - Modify the printer? */
529 int i
, j
; /* Looping vars */
530 int element
; /* Element number */
531 int num_printers
; /* Number of printers */
532 ipp_t
*request
, /* IPP request */
533 *response
; /* IPP response */
534 ipp_attribute_t
*attr
; /* member-uris attribute */
535 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
536 const char *name
, /* Pointer to class name */
537 *op
, /* Operation name */
538 *ptr
; /* Pointer to CGI variable */
539 const char *title
; /* Title of page */
540 static const char * const pattrs
[] = /* Requested printer attributes */
548 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
549 op
= cgiGetVariable("OP");
550 name
= cgiGetVariable("PRINTER_NAME");
552 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
555 * Build a CUPS_GET_PRINTERS request, which requires the
556 * following attributes:
559 * attributes-natural-language
562 request
= ippNewRequest(CUPS_GET_PRINTERS
);
564 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
566 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
567 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
570 * Do the request and get back a response...
575 cgiSetVariable("OP", op
);
577 cgiSetVariable("PRINTER_NAME", name
);
579 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
582 * Create MEMBER_URIS and MEMBER_NAMES arrays...
585 for (element
= 0, attr
= response
->attrs
;
588 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
590 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
591 (!name
|| _cups_strcasecmp(name
, ptr
+ 1)))
594 * Don't show the current class...
597 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
602 for (element
= 0, attr
= response
->attrs
;
605 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
607 if (!name
|| _cups_strcasecmp(name
, attr
->values
[0].string
.text
))
610 * Don't show the current class...
613 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
618 num_printers
= cgiGetSize("MEMBER_URIS");
628 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
629 * following attributes:
632 * attributes-natural-language
636 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
638 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
639 "localhost", 0, "/classes/%s", name
);
640 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
643 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
644 "requested-attributes",
645 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
649 * Do the request and get back a response...
652 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
654 if ((attr
= ippFindAttribute(response
, "member-names",
655 IPP_TAG_NAME
)) != NULL
)
658 * Mark any current members in the class...
661 for (j
= 0; j
< num_printers
; j
++)
662 cgiSetArray("MEMBER_SELECTED", j
, "");
664 for (i
= 0; i
< attr
->num_values
; i
++)
666 for (j
= 0; j
< num_printers
; j
++)
668 if (!_cups_strcasecmp(attr
->values
[i
].string
.text
,
669 cgiGetArray("MEMBER_NAMES", j
)))
671 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
678 if ((attr
= ippFindAttribute(response
, "printer-info",
679 IPP_TAG_TEXT
)) != NULL
)
680 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
682 if ((attr
= ippFindAttribute(response
, "printer-location",
683 IPP_TAG_TEXT
)) != NULL
)
684 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
690 * Update the location and description of an existing printer...
694 cgiCopyTemplateLang("modify-class.tmpl");
699 * Get the name, location, and description for a new printer...
703 cgiCopyTemplateLang("add-class.tmpl");
714 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
715 cgiCopyTemplateLang("error.tmpl");
720 for (ptr
= name
; *ptr
; ptr
++)
721 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
724 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
726 cgiSetVariable("ERROR",
727 cgiText(_("The class name may only contain up to "
728 "127 printable characters and may not "
729 "contain spaces, slashes (/), or the "
730 "pound sign (#).")));
732 cgiCopyTemplateLang("error.tmpl");
738 * Build a CUPS_ADD_CLASS request, which requires the following
742 * attributes-natural-language
746 * printer-is-accepting-jobs
751 request
= ippNewRequest(CUPS_ADD_CLASS
);
753 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
754 "localhost", 0, "/classes/%s", name
);
755 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
758 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
759 NULL
, cgiGetVariable("PRINTER_LOCATION"));
761 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
762 NULL
, cgiGetVariable("PRINTER_INFO"));
764 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
766 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
769 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
771 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
772 num_printers
, NULL
, NULL
);
773 for (i
= 0; i
< num_printers
; i
++)
774 attr
->values
[i
].string
.text
= _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i
));
778 * Do the request and get back a response...
781 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
783 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
785 puts("Status: 401\n");
788 else if (cupsLastError() > IPP_OK_CONFLICT
)
791 cgiShowIPPError(modify
? _("Unable to modify class") :
792 _("Unable to add class"));
797 * Redirect successful updates back to the class page...
800 char refresh
[1024]; /* Refresh URL */
802 cgiFormEncode(uri
, name
, sizeof(uri
));
803 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
805 cgiSetVariable("refresh_page", refresh
);
810 cgiCopyTemplateLang("class-modified.tmpl");
812 cgiCopyTemplateLang("class-added.tmpl");
820 * 'do_am_printer()' - Add or modify a printer.
824 do_am_printer(http_t
*http
, /* I - HTTP connection */
825 int modify
) /* I - Modify the printer? */
827 int i
; /* Looping var */
828 ipp_attribute_t
*attr
; /* Current attribute */
829 ipp_t
*request
, /* IPP request */
830 *response
, /* IPP response */
831 *oldinfo
; /* Old printer information */
832 const cgi_file_t
*file
; /* Uploaded file, if any */
833 const char *var
; /* CGI variable */
834 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
835 *uriptr
; /* Pointer into URI */
836 int maxrate
; /* Maximum baud rate */
837 char baudrate
[255]; /* Baud rate string */
838 const char *name
, /* Pointer to class name */
839 *ptr
; /* Pointer to CGI variable */
840 const char *title
; /* Title of page */
841 static int baudrates
[] = /* Baud rates */
856 ptr
= cgiGetVariable("DEVICE_URI");
857 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
858 ptr
? ptr
: "(null)");
860 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
865 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
866 * following attributes:
869 * attributes-natural-language
873 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
875 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
876 "localhost", 0, "/printers/%s",
877 cgiGetVariable("PRINTER_NAME"));
878 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
882 * Do the request and get back a response...
885 oldinfo
= cupsDoRequest(http
, request
, "/");
894 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
895 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
896 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
897 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
900 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
902 for (ptr
= name
; *ptr
; ptr
++)
903 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
906 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
908 cgiSetVariable("ERROR",
909 cgiText(_("The printer name may only contain up to "
910 "127 printable characters and may not "
911 "contain spaces, slashes (/), or the "
912 "pound sign (#).")));
914 cgiCopyTemplateLang("error.tmpl");
920 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
922 if ((uriptr
= strrchr(var
, '|')) != NULL
)
925 * Extract make and make/model from device URI string...
928 char make
[1024], /* Make string */
929 *makeptr
; /* Pointer into make */
934 strlcpy(make
, uriptr
, sizeof(make
));
936 if ((makeptr
= strchr(make
, ' ')) != NULL
)
938 else if ((makeptr
= strchr(make
, '-')) != NULL
)
940 else if (!_cups_strncasecmp(make
, "laserjet", 8) ||
941 !_cups_strncasecmp(make
, "deskjet", 7) ||
942 !_cups_strncasecmp(make
, "designjet", 9))
943 strlcpy(make
, "HP", sizeof(make
));
944 else if (!_cups_strncasecmp(make
, "phaser", 6))
945 strlcpy(make
, "Xerox", sizeof(make
));
946 else if (!_cups_strncasecmp(make
, "stylus", 6))
947 strlcpy(make
, "Epson", sizeof(make
));
949 strlcpy(make
, "Generic", sizeof(make
));
951 if (!cgiGetVariable("CURRENT_MAKE"))
952 cgiSetVariable("CURRENT_MAKE", make
);
954 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
955 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
959 char template[128], /* Template name */
960 *tptr
; /* Pointer into template name */
962 cgiSetVariable("PRINTER_INFO", uriptr
);
964 for (tptr
= template;
965 tptr
< (template + sizeof(template) - 1) && *uriptr
;
967 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
970 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
973 else if (*uriptr
== '?' || *uriptr
== '(')
978 cgiSetVariable("TEMPLATE_NAME", template);
986 * Look for devices so the user can pick something...
989 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
991 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
992 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
995 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
996 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
1000 * Scan for devices for up to 30 seconds...
1003 fputs("DEBUG: Getting list of devices...\n", stderr
);
1006 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
1007 (cups_device_cb_t
)choose_device_cb
,
1008 (void *)title
) == IPP_OK
)
1010 fputs("DEBUG: Got device list!\n", stderr
);
1012 if (cgiSupportsMultipart())
1013 cgiStartMultipart();
1015 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1016 cgiStartHTML(title
);
1017 cgiCopyTemplateLang("choose-device.tmpl");
1020 if (cgiSupportsMultipart())
1026 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1027 cupsLastError(), cupsLastErrorString());
1028 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1030 puts("Status: 401\n");
1035 cgiStartHTML(title
);
1036 cgiShowIPPError(modify
? _("Unable to modify printer") :
1037 _("Unable to add printer"));
1043 else if (!strchr(var
, '/') ||
1044 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
1046 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
1049 * Set the current device URI for the form to the old one...
1052 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
1053 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
1057 * User needs to set the full URI...
1060 cgiStartHTML(title
);
1061 cgiCopyTemplateLang("choose-uri.tmpl");
1064 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1067 * Need baud rate, parity, etc.
1070 if ((var
= strchr(var
, '?')) != NULL
&&
1071 strncmp(var
, "?baud=", 6) == 0)
1072 maxrate
= atoi(var
+ 6);
1076 for (i
= 0; i
< 10; i
++)
1077 if (baudrates
[i
] > maxrate
)
1081 sprintf(baudrate
, "%d", baudrates
[i
]);
1082 cgiSetArray("BAUDRATES", i
, baudrate
);
1085 cgiStartHTML(title
);
1086 cgiCopyTemplateLang("choose-serial.tmpl");
1089 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
1091 cgiStartHTML(title
);
1096 * Update the location and description of an existing printer...
1101 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
1102 IPP_TAG_TEXT
)) != NULL
)
1103 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
1105 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
1106 IPP_TAG_TEXT
)) != NULL
)
1107 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
1109 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
1110 IPP_TAG_BOOLEAN
)) != NULL
)
1111 cgiSetVariable("PRINTER_IS_SHARED",
1112 attr
->values
[0].boolean
? "1" : "0");
1115 cgiCopyTemplateLang("modify-printer.tmpl");
1120 * Get the name, location, and description for a new printer...
1124 if (!strncmp(var
, "usb:", 4))
1125 cgiSetVariable("printer_is_shared", "1");
1127 #endif /* __APPLE__ */
1128 cgiSetVariable("printer_is_shared", "0");
1130 cgiCopyTemplateLang("add-printer.tmpl");
1141 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1143 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
1146 * Get the PPD file...
1149 int fd
; /* PPD file */
1150 char filename
[1024]; /* PPD filename */
1151 ppd_file_t
*ppd
; /* PPD information */
1152 char buffer
[1024]; /* Buffer */
1153 ssize_t bytes
; /* Number of bytes */
1154 http_status_t get_status
; /* Status of GET */
1157 /* TODO: Use cupsGetFile() API... */
1158 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1160 if (httpGet(http
, uri
))
1163 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1165 if (get_status
!= HTTP_OK
)
1169 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1170 uri
, get_status
, httpStatus(get_status
));
1172 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1174 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1175 write(fd
, buffer
, (size_t)bytes
);
1179 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1181 if (ppd
->manufacturer
)
1182 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1185 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1192 int linenum
; /* Line number */
1194 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1195 filename
, ppdErrorString(ppdLastError(&linenum
)));
1203 "ERROR: Unable to create temporary file for PPD file: %s\n",
1209 * Build a CUPS_GET_PPDS request, which requires the following
1212 * attributes-charset
1213 * attributes-natural-language
1217 request
= ippNewRequest(CUPS_GET_PPDS
);
1219 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1220 NULL
, "ipp://localhost/printers/");
1222 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1223 var
= cgiGetVariable("CURRENT_MAKE");
1224 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1226 const char *make_model
; /* Make and model */
1229 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1230 "ppd-make", NULL
, var
);
1232 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1233 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1234 "ppd-make-and-model", NULL
, make_model
);
1237 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1238 "requested-attributes", NULL
, "ppd-make");
1241 * Do the request and get back a response...
1244 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1247 * Got the list of PPDs, see if the user has selected a make...
1250 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1253 * No PPD files with this make, try again with all makes...
1256 ippDelete(response
);
1258 request
= ippNewRequest(CUPS_GET_PPDS
);
1260 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1261 NULL
, "ipp://localhost/printers/");
1263 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1264 "requested-attributes", NULL
, "ppd-make");
1266 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1267 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1269 cgiStartHTML(title
);
1270 cgiCopyTemplateLang("choose-make.tmpl");
1273 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1275 cgiStartHTML(title
);
1276 cgiCopyTemplateLang("choose-make.tmpl");
1282 * Let the user choose a model...
1285 cgiStartHTML(title
);
1286 if (!cgiGetVariable("PPD_MAKE"))
1287 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1289 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1290 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1291 cgiCopyTemplateLang("choose-model.tmpl");
1295 ippDelete(response
);
1299 cgiStartHTML(title
);
1300 cgiShowIPPError(_("Unable to get list of printer drivers"));
1301 cgiCopyTemplateLang("error.tmpl");
1308 * Build a CUPS_ADD_PRINTER request, which requires the following
1311 * attributes-charset
1312 * attributes-natural-language
1318 * printer-is-accepting-jobs
1323 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1325 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1326 "localhost", 0, "/printers/%s",
1327 cgiGetVariable("PRINTER_NAME"));
1328 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1333 var
= cgiGetVariable("PPD_NAME");
1334 if (strcmp(var
, "__no_change__"))
1335 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name",
1339 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1340 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1342 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1343 NULL
, cgiGetVariable("PRINTER_INFO"));
1345 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1348 * Strip make and model from URI...
1351 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1354 if (!strncmp(uri
, "serial:", 7))
1357 * Update serial port URI to include baud rate, etc.
1360 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1361 uriptr
= uri
+ strlen(uri
);
1363 snprintf(uriptr
, sizeof(uri
) - (size_t)(uriptr
- uri
),
1364 "?baud=%s+bits=%s+parity=%s+flow=%s",
1365 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1366 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1369 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1372 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1374 var
= cgiGetVariable("printer_is_shared");
1375 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1376 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1378 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1382 * Do the request and get back a response...
1386 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1388 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1390 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1392 puts("Status: 401\n");
1395 else if (cupsLastError() > IPP_OK_CONFLICT
)
1397 cgiStartHTML(title
);
1398 cgiShowIPPError(modify
? _("Unable to modify printer") :
1399 _("Unable to add printer"));
1404 * Redirect successful updates back to the printer page...
1407 char refresh
[1024]; /* Refresh URL */
1410 cgiFormEncode(uri
, name
, sizeof(uri
));
1412 snprintf(refresh
, sizeof(refresh
),
1413 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1415 cgiSetVariable("refresh_page", refresh
);
1417 cgiStartHTML(title
);
1419 cgiCopyTemplateLang("printer-modified.tmpl");
1424 * Set the printer options...
1427 cgiSetVariable("OP", "set-printer-options");
1428 do_set_options(http
, 0);
1441 * 'do_cancel_subscription()' - Cancel a subscription.
1445 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1447 ipp_t
*request
; /* IPP request data */
1448 const char *var
, /* Form variable */
1449 *user
; /* Username */
1450 int id
; /* Subscription ID */
1454 * See if we have all of the required information...
1457 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1464 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1465 cgiStartHTML(_("Cancel RSS Subscription"));
1466 cgiCopyTemplateLang("error.tmpl");
1472 * Require a username...
1475 if ((user
= getenv("REMOTE_USER")) == NULL
)
1477 puts("Status: 401\n");
1482 * Cancel the subscription...
1485 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1487 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1488 NULL
, "ipp://localhost/");
1489 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1490 "notify-subscription-id", id
);
1492 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1495 ippDelete(cupsDoRequest(http
, request
, "/"));
1497 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1499 puts("Status: 401\n");
1502 else if (cupsLastError() > IPP_OK_CONFLICT
)
1504 cgiStartHTML(_("Cancel RSS Subscription"));
1505 cgiShowIPPError(_("Unable to cancel RSS subscription"));
1510 * Redirect successful updates back to the admin page...
1513 cgiSetVariable("refresh_page", "5;URL=/admin");
1514 cgiStartHTML(_("Cancel RSS Subscription"));
1515 cgiCopyTemplateLang("subscription-canceled.tmpl");
1523 * 'do_config_server()' - Configure server settings.
1527 do_config_server(http_t
*http
) /* I - HTTP connection */
1529 if (cgiGetVariable("CHANGESETTINGS"))
1532 * Save basic setting changes...
1535 int num_settings
; /* Number of server settings */
1536 cups_option_t
*settings
; /* Server settings */
1537 int advanced
, /* Advanced settings shown? */
1538 changed
; /* Have settings changed? */
1539 const char *debug_logging
, /* DEBUG_LOGGING value */
1540 *preserve_jobs
= NULL
,
1541 /* PRESERVE_JOBS value */
1542 *remote_admin
, /* REMOTE_ADMIN value */
1543 *remote_any
, /* REMOTE_ANY value */
1544 *share_printers
,/* SHARE_PRINTERS value */
1546 /* USER_CANCEL_ANY value */
1547 *browse_web_if
= NULL
,
1548 /* BrowseWebIF value */
1549 *preserve_job_history
= NULL
,
1550 /* PreserveJobHistory value */
1551 *preserve_job_files
= NULL
,
1552 /* PreserveJobFiles value */
1553 *max_clients
= NULL
,
1554 /* MaxClients value */
1557 *max_log_size
= NULL
;
1558 /* MaxLogSize value */
1559 const char *current_browse_web_if
,
1560 /* BrowseWebIF value */
1561 *current_preserve_job_history
,
1562 /* PreserveJobHistory value */
1563 *current_preserve_job_files
,
1564 /* PreserveJobFiles value */
1565 *current_max_clients
,
1566 /* MaxClients value */
1569 *current_max_log_size
;
1570 /* MaxLogSize value */
1572 char default_auth_type
[255];
1573 /* DefaultAuthType value */
1574 const char *val
; /* Setting value */
1575 #endif /* HAVE_GSSAPI */
1579 * Get the checkbox values from the form...
1582 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1583 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1584 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1585 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1586 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1588 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1592 * Get advanced settings...
1595 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1596 max_clients
= cgiGetVariable("MAX_CLIENTS");
1597 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1598 preserve_jobs
= cgiGetVariable("PRESERVE_JOBS");
1602 max_jobs
= cgiGetVariable("MAX_JOBS");
1603 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY");
1604 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES");
1606 if (!max_jobs
|| atoi(max_jobs
) < 0)
1609 if (!preserve_job_history
)
1610 preserve_job_history
= "On";
1612 if (!preserve_job_files
)
1613 preserve_job_files
= "1d";
1618 preserve_job_history
= "No";
1619 preserve_job_files
= "No";
1622 if (!max_clients
|| atoi(max_clients
) <= 0)
1623 max_clients
= "100";
1625 if (!max_log_size
|| atoi(max_log_size
) <= 0.0)
1626 max_log_size
= "1m";
1630 * Get the current server settings...
1633 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1635 cgiStartHTML(cgiText(_("Change Settings")));
1636 cgiSetVariable("MESSAGE",
1637 cgiText(_("Unable to change server settings")));
1638 cgiSetVariable("ERROR", cupsLastErrorString());
1639 cgiCopyTemplateLang("error.tmpl");
1646 * Get authentication settings...
1649 if (cgiGetVariable("KERBEROS"))
1650 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1653 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1655 if (!val
|| !_cups_strcasecmp(val
, "Negotiate"))
1656 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1658 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1661 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1662 #endif /* HAVE_GSSAPI */
1664 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1666 current_browse_web_if
= "No";
1668 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1671 current_preserve_job_history
= "Yes";
1673 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1676 current_preserve_job_files
= "1d";
1678 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1680 current_max_clients
= "100";
1682 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1684 current_max_jobs
= "500";
1686 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1688 current_max_log_size
= "1m";
1691 * See if the settings have changed...
1694 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1695 num_settings
, settings
)) ||
1696 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1697 num_settings
, settings
)) ||
1698 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1699 num_settings
, settings
)) ||
1700 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1701 num_settings
, settings
)) ||
1703 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1704 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1705 num_settings
, settings
)) ||
1706 #endif /* HAVE_GSSAPI */
1707 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1708 num_settings
, settings
));
1710 if (advanced
&& !changed
)
1711 changed
= _cups_strcasecmp(browse_web_if
, current_browse_web_if
) ||
1712 _cups_strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1713 _cups_strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1714 _cups_strcasecmp(max_clients
, current_max_clients
) ||
1715 _cups_strcasecmp(max_jobs
, current_max_jobs
) ||
1716 _cups_strcasecmp(max_log_size
, current_max_log_size
);
1721 * Settings *have* changed, so save the changes...
1724 cupsFreeOptions(num_settings
, settings
);
1727 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1728 debug_logging
, num_settings
, &settings
);
1729 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1730 remote_admin
, num_settings
, &settings
);
1731 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1732 remote_any
, num_settings
, &settings
);
1733 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1734 share_printers
, num_settings
, &settings
);
1735 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1736 user_cancel_any
, num_settings
, &settings
);
1738 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1739 num_settings
, &settings
);
1740 #endif /* HAVE_GSSAPI */
1745 * Add advanced settings...
1748 if (_cups_strcasecmp(browse_web_if
, current_browse_web_if
))
1749 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1750 num_settings
, &settings
);
1751 if (_cups_strcasecmp(preserve_job_history
, current_preserve_job_history
))
1752 num_settings
= cupsAddOption("PreserveJobHistory",
1753 preserve_job_history
, num_settings
,
1755 if (_cups_strcasecmp(preserve_job_files
, current_preserve_job_files
))
1756 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1757 num_settings
, &settings
);
1758 if (_cups_strcasecmp(max_clients
, current_max_clients
))
1759 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1761 if (_cups_strcasecmp(max_jobs
, current_max_jobs
))
1762 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1764 if (_cups_strcasecmp(max_log_size
, current_max_log_size
))
1765 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1769 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1771 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1773 puts("Status: 401\n");
1777 cgiStartHTML(cgiText(_("Change Settings")));
1778 cgiSetVariable("MESSAGE",
1779 cgiText(_("Unable to change server settings")));
1780 cgiSetVariable("ERROR", cupsLastErrorString());
1781 cgiCopyTemplateLang("error.tmpl");
1786 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1787 "URL=/admin/?ADVANCEDSETTINGS=YES");
1789 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1790 cgiStartHTML(cgiText(_("Change Settings")));
1791 cgiCopyTemplateLang("restart.tmpl");
1800 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1801 cgiStartHTML(cgiText(_("Change Settings")));
1802 cgiCopyTemplateLang("norestart.tmpl");
1805 cupsFreeOptions(num_settings
, settings
);
1809 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1812 * Save hand-edited config file...
1815 http_status_t status
; /* PUT status */
1816 char tempfile
[1024]; /* Temporary new cupsd.conf */
1817 int tempfd
; /* Temporary file descriptor */
1818 cups_file_t
*temp
; /* Temporary file */
1819 const char *start
, /* Start of line */
1820 *end
; /* End of line */
1824 * Create a temporary file for the new cupsd.conf file...
1827 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1829 cgiStartHTML(cgiText(_("Edit Configuration File")));
1830 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1831 cgiSetVariable("ERROR", strerror(errno
));
1832 cgiCopyTemplateLang("error.tmpl");
1839 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1841 cgiStartHTML(cgiText(_("Edit Configuration File")));
1842 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1843 cgiSetVariable("ERROR", strerror(errno
));
1844 cgiCopyTemplateLang("error.tmpl");
1854 * Copy the cupsd.conf text from the form variable...
1857 start
= cgiGetVariable("CUPSDCONF");
1860 if ((end
= strstr(start
, "\r\n")) == NULL
)
1861 if ((end
= strstr(start
, "\n")) == NULL
)
1862 end
= start
+ strlen(start
);
1864 cupsFileWrite(temp
, start
, (size_t)(end
- start
));
1865 cupsFilePutChar(temp
, '\n');
1869 else if (*end
== '\n')
1875 cupsFileClose(temp
);
1878 * Upload the configuration file to the server...
1881 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1883 if (status
== HTTP_UNAUTHORIZED
)
1885 puts("Status: 401\n");
1889 else if (status
!= HTTP_CREATED
)
1891 cgiSetVariable("MESSAGE",
1892 cgiText(_("Unable to upload cupsd.conf file")));
1893 cgiSetVariable("ERROR", httpStatus(status
));
1895 cgiStartHTML(cgiText(_("Edit Configuration File")));
1896 cgiCopyTemplateLang("error.tmpl");
1900 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1902 cgiStartHTML(cgiText(_("Edit Configuration File")));
1903 cgiCopyTemplateLang("restart.tmpl");
1912 struct stat info
; /* cupsd.conf information */
1913 cups_file_t
*cupsd
; /* cupsd.conf file */
1914 char *buffer
, /* Buffer for entire file */
1915 *bufptr
, /* Pointer into buffer */
1916 *bufend
; /* End of buffer */
1917 int ch
; /* Character from file */
1918 char filename
[1024]; /* Filename */
1919 const char *server_root
; /* Location of config files */
1923 * Locate the cupsd.conf file...
1926 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1927 server_root
= CUPS_SERVERROOT
;
1929 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1932 * Figure out the size...
1935 if (stat(filename
, &info
))
1937 cgiStartHTML(cgiText(_("Edit Configuration File")));
1938 cgiSetVariable("MESSAGE",
1939 cgiText(_("Unable to access cupsd.conf file")));
1940 cgiSetVariable("ERROR", strerror(errno
));
1941 cgiCopyTemplateLang("error.tmpl");
1948 if (info
.st_size
> (1024 * 1024))
1950 cgiStartHTML(cgiText(_("Edit Configuration File")));
1951 cgiSetVariable("MESSAGE",
1952 cgiText(_("Unable to access cupsd.conf file")));
1953 cgiSetVariable("ERROR",
1954 cgiText(_("Unable to edit cupsd.conf files larger than "
1956 cgiCopyTemplateLang("error.tmpl");
1959 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1960 (long)info
.st_size
);
1965 * Open the cupsd.conf file...
1968 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1971 * Unable to open - log an error...
1974 cgiStartHTML(cgiText(_("Edit Configuration File")));
1975 cgiSetVariable("MESSAGE",
1976 cgiText(_("Unable to access cupsd.conf file")));
1977 cgiSetVariable("ERROR", strerror(errno
));
1978 cgiCopyTemplateLang("error.tmpl");
1986 * Allocate memory and load the file into a string buffer...
1989 if ((buffer
= calloc(1, (size_t)info
.st_size
+ 1)) != NULL
)
1991 cupsFileRead(cupsd
, buffer
, (size_t)info
.st_size
);
1992 cgiSetVariable("CUPSDCONF", buffer
);
1996 cupsFileClose(cupsd
);
1999 * Then get the default cupsd.conf file and put that into a string as
2003 strlcat(filename
, ".default", sizeof(filename
));
2005 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
2006 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
2008 if ((buffer
= calloc(1, 2 * (size_t)info
.st_size
+ 1)) != NULL
)
2010 bufend
= buffer
+ 2 * info
.st_size
- 1;
2012 for (bufptr
= buffer
;
2013 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
2015 if (ch
== '\\' || ch
== '\"')
2018 *bufptr
++ = (char)ch
;
2020 else if (ch
== '\n')
2025 else if (ch
== '\t')
2031 *bufptr
++ = (char)ch
;
2036 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
2040 cupsFileClose(cupsd
);
2044 * Show the current config file...
2047 cgiStartHTML(cgiText(_("Edit Configuration File")));
2049 cgiCopyTemplateLang("edit-config.tmpl");
2057 * 'do_delete_class()' - Delete a class.
2061 do_delete_class(http_t
*http
) /* I - HTTP connection */
2063 ipp_t
*request
; /* IPP request */
2064 char uri
[HTTP_MAX_URI
]; /* Job URI */
2065 const char *pclass
; /* Printer class name */
2069 * Get form variables...
2072 if (cgiGetVariable("CONFIRM") == NULL
)
2074 cgiStartHTML(cgiText(_("Delete Class")));
2075 cgiCopyTemplateLang("class-confirm.tmpl");
2080 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2081 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2082 "localhost", 0, "/classes/%s", pclass
);
2085 cgiStartHTML(cgiText(_("Delete Class")));
2086 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2087 cgiCopyTemplateLang("error.tmpl");
2093 * Build a CUPS_DELETE_CLASS request, which requires the following
2096 * attributes-charset
2097 * attributes-natural-language
2101 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2103 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2107 * Do the request and get back a response...
2110 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2113 * Show the results...
2116 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2118 puts("Status: 401\n");
2121 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2124 * Redirect successful updates back to the classes page...
2127 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2130 cgiStartHTML(cgiText(_("Delete Class")));
2132 if (cupsLastError() > IPP_OK_CONFLICT
)
2133 cgiShowIPPError(_("Unable to delete class"));
2135 cgiCopyTemplateLang("class-deleted.tmpl");
2142 * 'do_delete_printer()' - Delete a printer.
2146 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2148 ipp_t
*request
; /* IPP request */
2149 char uri
[HTTP_MAX_URI
]; /* Job URI */
2150 const char *printer
; /* Printer printer name */
2154 * Get form variables...
2157 if (cgiGetVariable("CONFIRM") == NULL
)
2159 cgiStartHTML(cgiText(_("Delete Printer")));
2160 cgiCopyTemplateLang("printer-confirm.tmpl");
2165 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2166 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2167 "localhost", 0, "/printers/%s", printer
);
2170 cgiStartHTML(cgiText(_("Delete Printer")));
2171 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2172 cgiCopyTemplateLang("error.tmpl");
2178 * Build a CUPS_DELETE_PRINTER request, which requires the following
2181 * attributes-charset
2182 * attributes-natural-language
2186 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2188 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2192 * Do the request and get back a response...
2195 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2198 * Show the results...
2201 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2203 puts("Status: 401\n");
2206 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2209 * Redirect successful updates back to the printers page...
2212 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2215 cgiStartHTML(cgiText(_("Delete Printer")));
2217 if (cupsLastError() > IPP_OK_CONFLICT
)
2218 cgiShowIPPError(_("Unable to delete printer"));
2220 cgiCopyTemplateLang("printer-deleted.tmpl");
2227 * 'do_export()' - Export printers to Samba.
2231 do_export(http_t
*http
) /* I - HTTP connection */
2233 int i
, j
; /* Looping vars */
2234 ipp_t
*request
, /* IPP request */
2235 *response
; /* IPP response */
2236 const char *username
, /* Samba username */
2237 *password
, /* Samba password */
2238 *export_all
; /* Export all printers? */
2239 int export_count
, /* Number of printers to export */
2240 printer_count
; /* Number of available printers */
2241 const char *name
, /* What name to pull */
2242 *dest
; /* Current destination */
2243 char ppd
[1024]; /* PPD file */
2250 username
= cgiGetVariable("USERNAME");
2251 password
= cgiGetVariable("PASSWORD");
2252 export_all
= cgiGetVariable("EXPORT_ALL");
2253 export_count
= cgiGetSize("EXPORT_NAME");
2256 * Get list of available printers...
2259 cgiSetSize("PRINTER_NAME", 0);
2260 cgiSetSize("PRINTER_EXPORT", 0);
2262 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2264 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2267 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2268 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
2270 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2271 "requested-attributes", NULL
, "printer-name");
2273 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2275 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2276 ippDelete(response
);
2280 printer_count
= cgiGetSize("PRINTER_NAME");
2282 for (i
= 0; i
< printer_count
; i
++)
2284 dest
= cgiGetArray("PRINTER_NAME", i
);
2286 for (j
= 0; j
< export_count
; j
++)
2287 if (!_cups_strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2290 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2296 * Export or get the printers to export...
2299 if (username
&& *username
&& password
&& *password
&&
2300 (export_all
|| export_count
> 0))
2306 fputs("DEBUG: Export printers...\n", stderr
);
2310 name
= "PRINTER_NAME";
2311 export_count
= cgiGetSize("PRINTER_NAME");
2314 name
= "EXPORT_NAME";
2316 for (i
= 0; i
< export_count
; i
++)
2318 dest
= cgiGetArray(name
, i
);
2320 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2323 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2332 if (i
< export_count
)
2333 cgiSetVariable("ERROR", cupsLastErrorString());
2336 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2337 cgiCopyTemplateLang("samba-exported.tmpl");
2342 else if (username
&& !*username
)
2343 cgiSetVariable("ERROR",
2344 cgiText(_("A Samba username is required to export "
2345 "printer drivers")));
2346 else if (username
&& (!password
|| !*password
))
2347 cgiSetVariable("ERROR",
2348 cgiText(_("A Samba password is required to export "
2349 "printer drivers")));
2355 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2356 cgiCopyTemplateLang("samba-export.tmpl");
2362 * 'do_list_printers()' - List available printers.
2366 do_list_printers(http_t
*http
) /* I - HTTP connection */
2368 ipp_t
*request
, /* IPP request */
2369 *response
; /* IPP response */
2370 ipp_attribute_t
*attr
; /* IPP attribute */
2373 cgiStartHTML(cgiText(_("List Available Printers")));
2377 * Get the list of printers and their devices...
2380 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2382 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2383 "requested-attributes", NULL
, "device-uri");
2385 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2386 CUPS_PRINTER_LOCAL
);
2387 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2388 CUPS_PRINTER_LOCAL
);
2390 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2393 * Got the printer list, now load the devices...
2396 int i
; /* Looping var */
2397 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2398 char *printer_device
; /* Current printer device */
2402 * Allocate an array and copy the device strings...
2405 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2407 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2409 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2411 cupsArrayAdd(printer_devices
, _cupsStrAlloc(attr
->values
[0].string
.text
));
2415 * Free the printer list and get the device list...
2418 ippDelete(response
);
2420 request
= ippNewRequest(CUPS_GET_DEVICES
);
2422 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2425 * Got the device list, let's parse it...
2428 const char *device_uri
, /* device-uri attribute value */
2429 *device_make_and_model
, /* device-make-and-model value */
2430 *device_info
; /* device-info value */
2433 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2436 * Skip leading attributes until we hit a device...
2439 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2446 * Pull the needed attributes from this device...
2450 device_make_and_model
= NULL
;
2453 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2455 if (!strcmp(attr
->name
, "device-info") &&
2456 attr
->value_tag
== IPP_TAG_TEXT
)
2457 device_info
= attr
->values
[0].string
.text
;
2459 if (!strcmp(attr
->name
, "device-make-and-model") &&
2460 attr
->value_tag
== IPP_TAG_TEXT
)
2461 device_make_and_model
= attr
->values
[0].string
.text
;
2463 if (!strcmp(attr
->name
, "device-uri") &&
2464 attr
->value_tag
== IPP_TAG_URI
)
2465 device_uri
= attr
->values
[0].string
.text
;
2471 * See if we have everything needed...
2474 if (device_info
&& device_make_and_model
&& device_uri
&&
2475 _cups_strcasecmp(device_make_and_model
, "unknown") &&
2476 strchr(device_uri
, ':'))
2479 * Yes, now see if there is already a printer for this
2483 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2486 * Not found, so it must be a new printer...
2489 char option
[1024], /* Form variables for this device */
2490 *option_ptr
; /* Pointer into string */
2491 const char *ptr
; /* Pointer into device string */
2495 * Format the printer name variable for this device...
2497 * We use the device-info string first, then device-uri,
2498 * and finally device-make-and-model to come up with a
2502 if (_cups_strncasecmp(device_info
, "unknown", 7))
2504 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2507 ptr
= device_make_and_model
;
2509 for (option_ptr
= option
;
2510 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2512 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2514 *option_ptr
++ = *ptr
;
2515 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2516 option_ptr
[-1] != '_')
2517 *option_ptr
++ = '_';
2518 else if (*ptr
== '?' || *ptr
== '(')
2523 cgiSetArray("TEMPLATE_NAME", i
, option
);
2526 * Finally, set the form variables for this printer...
2529 cgiSetArray("device_info", i
, device_info
);
2530 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2531 cgiSetArray("device_uri", i
, device_uri
);
2540 ippDelete(response
);
2543 * Free the device list...
2546 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2548 printer_device
= (char *)cupsArrayNext(printer_devices
))
2549 _cupsStrFree(printer_device
);
2551 cupsArrayDelete(printer_devices
);
2556 * Finally, show the printer list...
2559 cgiCopyTemplateLang("list-available-printers.tmpl");
2566 * 'do_menu()' - Show the main menu.
2570 do_menu(http_t
*http
) /* I - HTTP connection */
2572 int num_settings
; /* Number of server settings */
2573 cups_option_t
*settings
; /* Server settings */
2574 const char *val
; /* Setting value */
2575 char filename
[1024]; /* Temporary filename */
2576 const char *datadir
; /* Location of data files */
2577 ipp_t
*request
, /* IPP request */
2578 *response
; /* IPP response */
2582 * Get the current server settings...
2585 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2587 cgiSetVariable("SETTINGS_MESSAGE",
2588 cgiText(_("Unable to open cupsd.conf file:")));
2589 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2592 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2593 settings
)) != NULL
&& atoi(val
))
2594 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2596 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2597 settings
)) != NULL
&& atoi(val
))
2598 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2600 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2601 settings
)) != NULL
&& atoi(val
))
2602 cgiSetVariable("REMOTE_ANY", "CHECKED");
2604 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2605 settings
)) != NULL
&& atoi(val
))
2606 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2608 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2609 settings
)) != NULL
&& atoi(val
))
2610 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2613 cgiSetVariable("HAVE_GSSAPI", "1");
2615 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2616 settings
)) != NULL
&& !_cups_strcasecmp(val
, "Negotiate"))
2617 cgiSetVariable("KERBEROS", "CHECKED");
2619 #endif /* HAVE_GSSAPI */
2620 cgiSetVariable("KERBEROS", "");
2622 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2626 if (!_cups_strcasecmp(val
, "yes") || !_cups_strcasecmp(val
, "on") ||
2627 !_cups_strcasecmp(val
, "true"))
2628 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2630 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2635 (!_cups_strcasecmp(val
, "0") || !_cups_strcasecmp(val
, "no") ||
2636 !_cups_strcasecmp(val
, "off") || !_cups_strcasecmp(val
, "false") ||
2637 !_cups_strcasecmp(val
, "disabled")))
2639 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2640 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2644 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2645 cgiSetVariable("PRESERVE_JOB_HISTORY", val
);
2647 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2651 cgiSetVariable("PRESERVE_JOB_FILES", val
);
2655 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2658 cgiSetVariable("MAX_CLIENTS", val
);
2660 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2663 cgiSetVariable("MAX_JOBS", val
);
2665 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2668 cgiSetVariable("MAX_LOG_SIZE", val
);
2670 cupsFreeOptions(num_settings
, settings
);
2673 * See if Samba and the Windows drivers are installed...
2676 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2677 datadir
= CUPS_DATADIR
;
2679 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2680 if (!access(filename
, R_OK
))
2683 * Found Windows 2000 driver file, see if we have smbclient and
2687 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2688 sizeof(filename
)) &&
2689 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2691 cgiSetVariable("HAVE_SAMBA", "Y");
2694 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2696 fputs("ERROR: smbclient not found!\n", stderr
);
2698 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2700 fputs("ERROR: rpcclient not found!\n", stderr
);
2710 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2712 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2713 NULL
, "ipp://localhost/");
2715 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2717 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2718 ippDelete(response
);
2722 * Finally, show the main menu template...
2725 cgiStartHTML(cgiText(_("Administration")));
2727 cgiCopyTemplateLang("admin.tmpl");
2734 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2738 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2740 int i
; /* Looping var */
2741 ipp_t
*request
, /* IPP request */
2742 *response
; /* IPP response */
2743 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2744 const char *printer
, /* Printer name (purge-jobs) */
2745 *is_class
, /* Is a class? */
2746 *users
, /* List of users or groups */
2747 *type
; /* Allow/deny type */
2748 int num_users
; /* Number of users */
2749 char *ptr
, /* Pointer into users string */
2750 *end
, /* Pointer to end of users string */
2751 quote
; /* Quote character */
2752 ipp_attribute_t
*attr
; /* Attribute */
2753 static const char * const attrs
[] = /* Requested attributes */
2755 "requesting-user-name-allowed",
2756 "requesting-user-name-denied"
2760 is_class
= cgiGetVariable("IS_CLASS");
2761 printer
= cgiGetVariable("PRINTER_NAME");
2765 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2766 cgiStartHTML(cgiText(_("Set Allowed Users")));
2767 cgiCopyTemplateLang("error.tmpl");
2772 users
= cgiGetVariable("users");
2773 type
= cgiGetVariable("type");
2775 if (!users
|| !type
||
2776 (strcmp(type
, "requesting-user-name-allowed") &&
2777 strcmp(type
, "requesting-user-name-denied")))
2780 * Build a Get-Printer-Attributes request, which requires the following
2783 * attributes-charset
2784 * attributes-natural-language
2786 * requested-attributes
2789 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2791 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2792 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2794 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2797 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2798 "requested-attributes",
2799 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2802 * Do the request and get back a response...
2805 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2807 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2809 ippDelete(response
);
2812 cgiStartHTML(cgiText(_("Set Allowed Users")));
2814 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2816 puts("Status: 401\n");
2819 else if (cupsLastError() > IPP_OK_CONFLICT
)
2820 cgiShowIPPError(_("Unable to get printer attributes"));
2822 cgiCopyTemplateLang("users.tmpl");
2829 * Save the changes...
2832 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2835 * Skip whitespace and commas...
2838 while (*ptr
== ',' || isspace(*ptr
& 255))
2844 if (*ptr
== '\'' || *ptr
== '\"')
2847 * Scan quoted name...
2852 for (end
= ptr
; *end
; end
++)
2859 * Scan space or comma-delimited name...
2862 for (end
= ptr
; *end
; end
++)
2863 if (isspace(*end
& 255) || *end
== ',')
2868 * Advance to the next name...
2875 * Build a CUPS-Add-Printer/Class request, which requires the following
2878 * attributes-charset
2879 * attributes-natural-language
2881 * requesting-user-name-{allowed,denied}
2884 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2886 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2887 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2889 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2893 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2894 "requesting-user-name-allowed", NULL
, "all");
2897 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2898 type
, num_users
, NULL
, NULL
);
2900 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2903 * Skip whitespace and commas...
2906 while (*ptr
== ',' || isspace(*ptr
& 255))
2912 if (*ptr
== '\'' || *ptr
== '\"')
2915 * Scan quoted name...
2920 for (end
= ptr
; *end
; end
++)
2927 * Scan space or comma-delimited name...
2930 for (end
= ptr
; *end
; end
++)
2931 if (isspace(*end
& 255) || *end
== ',')
2936 * Terminate the name...
2946 attr
->values
[i
].string
.text
= _cupsStrAlloc(ptr
);
2949 * Advance to the next name...
2957 * Do the request and get back a response...
2960 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2962 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2964 puts("Status: 401\n");
2967 else if (cupsLastError() > IPP_OK_CONFLICT
)
2969 cgiStartHTML(cgiText(_("Set Allowed Users")));
2970 cgiShowIPPError(_("Unable to change printer"));
2975 * Redirect successful updates back to the printer page...
2978 char url
[1024], /* Printer/class URL */
2979 refresh
[1024]; /* Refresh URL */
2982 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2983 cgiFormEncode(uri
, url
, sizeof(uri
));
2984 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2986 cgiSetVariable("refresh_page", refresh
);
2988 cgiStartHTML(cgiText(_("Set Allowed Users")));
2990 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2991 "printer-modified.tmpl");
3000 * 'do_set_default()' - Set the server default printer/class.
3004 do_set_default(http_t
*http
) /* I - HTTP connection */
3006 const char *title
; /* Page title */
3007 ipp_t
*request
; /* IPP request */
3008 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3009 const char *printer
, /* Printer name (purge-jobs) */
3010 *is_class
; /* Is a class? */
3013 is_class
= cgiGetVariable("IS_CLASS");
3014 printer
= cgiGetVariable("PRINTER_NAME");
3015 title
= cgiText(_("Set As Server Default"));
3019 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3020 cgiStartHTML(title
);
3021 cgiCopyTemplateLang("error.tmpl");
3027 * Build a printer request, which requires the following
3030 * attributes-charset
3031 * attributes-natural-language
3035 request
= ippNewRequest(CUPS_SET_DEFAULT
);
3037 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3038 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3040 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3044 * Do the request and get back a response...
3047 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3049 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3051 puts("Status: 401\n");
3054 else if (cupsLastError() > IPP_OK_CONFLICT
)
3056 cgiStartHTML(title
);
3057 cgiShowIPPError(_("Unable to set server default"));
3062 * Redirect successful updates back to the printer page...
3065 char url
[1024], /* Printer/class URL */
3066 refresh
[1024]; /* Refresh URL */
3069 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3070 cgiFormEncode(uri
, url
, sizeof(uri
));
3071 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3072 cgiSetVariable("refresh_page", refresh
);
3074 cgiStartHTML(title
);
3075 cgiCopyTemplateLang("printer-default.tmpl");
3083 * 'do_set_options()' - Configure the default options for a queue.
3087 do_set_options(http_t
*http
, /* I - HTTP connection */
3088 int is_class
) /* I - Set options for class? */
3090 int i
, j
, k
, m
; /* Looping vars */
3091 int have_options
; /* Have options? */
3092 ipp_t
*request
, /* IPP request */
3093 *response
; /* IPP response */
3094 ipp_attribute_t
*attr
; /* IPP attribute */
3095 char uri
[HTTP_MAX_URI
]; /* Job URI */
3096 const char *var
; /* Variable value */
3097 const char *printer
; /* Printer printer name */
3098 const char *filename
; /* PPD filename */
3099 char tempfile
[1024]; /* Temporary filename */
3100 cups_file_t
*in
, /* Input file */
3101 *out
; /* Output file */
3102 char line
[1024], /* Line from PPD file */
3103 value
[1024], /* Option value */
3104 keyword
[1024], /* Keyword from Default line */
3105 *keyptr
; /* Pointer into keyword... */
3106 ppd_file_t
*ppd
; /* PPD file */
3107 ppd_group_t
*group
; /* Option group */
3108 ppd_option_t
*option
; /* Option */
3109 ppd_coption_t
*coption
; /* Custom option */
3110 ppd_cparam_t
*cparam
; /* Custom parameter */
3111 ppd_attr_t
*ppdattr
; /* PPD attribute */
3112 const char *title
; /* Page title */
3115 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
3117 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
3121 * Get the printer name...
3124 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
3125 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3126 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3130 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3131 cgiStartHTML(title
);
3132 cgiCopyTemplateLang("error.tmpl");
3137 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
3140 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3141 * command file to the printer...
3144 if (cgiGetVariable("AUTOCONFIGURE"))
3146 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
3151 * Get the PPD file...
3157 filename
= cupsGetPPD2(http
, printer
);
3161 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
3163 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
3165 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
3166 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
3167 cgiStartHTML(title
);
3168 cgiCopyTemplateLang("error.tmpl");
3175 fputs("DEBUG: No PPD file\n", stderr
);
3179 if (cgiGetVariable("job_sheets_start") != NULL
||
3180 cgiGetVariable("job_sheets_end") != NULL
)
3187 ppdMarkDefaults(ppd
);
3189 for (option
= ppdFirstOption(ppd
);
3191 option
= ppdNextOption(ppd
))
3193 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
3196 ppdMarkOption(ppd
, option
->keyword
, var
);
3197 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
3200 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
3204 if (!have_options
|| ppdConflicts(ppd
))
3207 * Show the options to the user...
3210 fputs("DEBUG: Showing options...\n", stderr
);
3213 * Show auto-configure button if supported...
3218 if (ppd
->num_filters
== 0 ||
3219 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
3220 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
3221 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3224 for (i
= 0; i
< ppd
->num_filters
; i
++)
3225 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
3227 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3234 * Get the printer attributes...
3237 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3239 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3240 "localhost", 0, "/printers/%s", printer
);
3241 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3244 response
= cupsDoRequest(http
, request
, "/");
3247 * List the groups used as "tabs"...
3254 for (group
= ppd
->groups
;
3255 i
< ppd
->num_groups
;
3258 cgiSetArray("GROUP_ID", i
, group
->name
);
3260 if (!strcmp(group
->name
, "InstallableOptions"))
3261 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
3263 cgiSetArray("GROUP", i
, group
->text
);
3267 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
3269 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
3270 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
3273 if (ippFindAttribute(response
, "printer-error-policy-supported",
3275 ippFindAttribute(response
, "printer-op-policy-supported",
3278 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
3279 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3282 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3283 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3285 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3286 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3289 cgiStartHTML(cgiText(_("Set Printer Options")));
3290 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3296 if (ppdConflicts(ppd
))
3298 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3301 for (j
= group
->num_options
, option
= group
->options
;
3304 if (option
->conflicted
)
3306 cgiSetArray("ckeyword", k
, option
->keyword
);
3307 cgiSetArray("ckeytext", k
, option
->text
);
3309 for (m
= 0; m
< option
->num_choices
; m
++)
3311 if (option
->choices
[m
].marked
)
3313 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3321 cgiCopyTemplateLang("option-conflict.tmpl");
3324 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3328 for (j
= group
->num_options
, option
= group
->options
;
3332 if (!strcmp(option
->keyword
, "PageRegion"))
3335 if (option
->num_choices
> 1)
3342 cgiSetVariable("GROUP_ID", group
->name
);
3344 if (!strcmp(group
->name
, "InstallableOptions"))
3345 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3347 cgiSetVariable("GROUP", group
->text
);
3349 cgiCopyTemplateLang("option-header.tmpl");
3351 for (j
= group
->num_options
, option
= group
->options
;
3355 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
3358 cgiSetVariable("KEYWORD", option
->keyword
);
3359 cgiSetVariable("KEYTEXT", option
->text
);
3361 if (option
->conflicted
)
3362 cgiSetVariable("CONFLICTED", "1");
3364 cgiSetVariable("CONFLICTED", "0");
3366 cgiSetSize("CHOICES", 0);
3367 cgiSetSize("TEXT", 0);
3368 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3370 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3371 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3375 if (option
->choices
[k
].marked
)
3376 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3379 cgiSetSize("PARAMS", 0);
3380 cgiSetSize("PARAMTEXT", 0);
3381 cgiSetSize("PARAMVALUE", 0);
3382 cgiSetSize("INPUTTYPE", 0);
3384 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3386 const char *units
= NULL
; /* Units value, if any */
3388 cgiSetVariable("ISCUSTOM", "1");
3390 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3392 cparam
= ppdNextCustomParam(coption
), m
++)
3394 if (!_cups_strcasecmp(option
->keyword
, "PageSize") &&
3395 _cups_strcasecmp(cparam
->name
, "Width") &&
3396 _cups_strcasecmp(cparam
->name
, "Height"))
3402 cgiSetArray("PARAMS", m
, cparam
->name
);
3403 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3404 cgiSetArray("INPUTTYPE", m
, "text");
3406 switch (cparam
->type
)
3408 case PPD_CUSTOM_POINTS
:
3409 if (!_cups_strncasecmp(option
->defchoice
, "Custom.", 7))
3411 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3413 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3414 strcmp(units
, "in") && strcmp(units
, "ft"))
3416 if (units
[1] == 'm')
3425 if (!strcmp(units
, "mm"))
3426 snprintf(value
, sizeof(value
), "%g",
3427 cparam
->current
.custom_points
/ 72.0 * 25.4);
3428 else if (!strcmp(units
, "cm"))
3429 snprintf(value
, sizeof(value
), "%g",
3430 cparam
->current
.custom_points
/ 72.0 * 2.54);
3431 else if (!strcmp(units
, "in"))
3432 snprintf(value
, sizeof(value
), "%g",
3433 cparam
->current
.custom_points
/ 72.0);
3434 else if (!strcmp(units
, "ft"))
3435 snprintf(value
, sizeof(value
), "%g",
3436 cparam
->current
.custom_points
/ 72.0 / 12.0);
3437 else if (!strcmp(units
, "m"))
3438 snprintf(value
, sizeof(value
), "%g",
3439 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3441 snprintf(value
, sizeof(value
), "%g",
3442 cparam
->current
.custom_points
);
3443 cgiSetArray("PARAMVALUE", m
, value
);
3446 case PPD_CUSTOM_CURVE
:
3447 case PPD_CUSTOM_INVCURVE
:
3448 case PPD_CUSTOM_REAL
:
3449 snprintf(value
, sizeof(value
), "%g",
3450 cparam
->current
.custom_real
);
3451 cgiSetArray("PARAMVALUE", m
, value
);
3454 case PPD_CUSTOM_INT
:
3455 snprintf(value
, sizeof(value
), "%d",
3456 cparam
->current
.custom_int
);
3457 cgiSetArray("PARAMVALUE", m
, value
);
3460 case PPD_CUSTOM_PASSCODE
:
3461 case PPD_CUSTOM_PASSWORD
:
3462 if (cparam
->current
.custom_password
)
3463 cgiSetArray("PARAMVALUE", m
,
3464 cparam
->current
.custom_password
);
3466 cgiSetArray("PARAMVALUE", m
, "");
3467 cgiSetArray("INPUTTYPE", m
, "password");
3470 case PPD_CUSTOM_STRING
:
3471 if (cparam
->current
.custom_string
)
3472 cgiSetArray("PARAMVALUE", m
,
3473 cparam
->current
.custom_string
);
3475 cgiSetArray("PARAMVALUE", m
, "");
3482 cgiSetArray("PARAMS", m
, "Units");
3483 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3484 cgiSetArray("PARAMVALUE", m
, units
);
3488 cgiSetVariable("ISCUSTOM", "0");
3492 case PPD_UI_BOOLEAN
:
3493 cgiCopyTemplateLang("option-boolean.tmpl");
3495 case PPD_UI_PICKONE
:
3496 cgiCopyTemplateLang("option-pickone.tmpl");
3498 case PPD_UI_PICKMANY
:
3499 cgiCopyTemplateLang("option-pickmany.tmpl");
3504 cgiCopyTemplateLang("option-trailer.tmpl");
3508 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3509 IPP_TAG_ZERO
)) != NULL
)
3512 * Add the job sheets options...
3515 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3516 cgiSetVariable("GROUP", cgiText(_("Banners")));
3517 cgiCopyTemplateLang("option-header.tmpl");
3519 cgiSetSize("CHOICES", attr
->num_values
);
3520 cgiSetSize("TEXT", attr
->num_values
);
3521 for (k
= 0; k
< attr
->num_values
; k
++)
3523 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3524 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3527 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3529 cgiSetVariable("KEYWORD", "job_sheets_start");
3530 cgiSetVariable("KEYTEXT",
3531 /* TRANSLATORS: Banner/cover sheet before the print job. */
3532 cgiText(_("Starting Banner")));
3533 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3534 attr
->values
[0].string
.text
: "");
3536 cgiCopyTemplateLang("option-pickone.tmpl");
3538 cgiSetVariable("KEYWORD", "job_sheets_end");
3539 cgiSetVariable("KEYTEXT",
3540 /* TRANSLATORS: Banner/cover sheet after the print job. */
3541 cgiText(_("Ending Banner")));
3542 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3543 attr
->values
[1].string
.text
: "");
3545 cgiCopyTemplateLang("option-pickone.tmpl");
3547 cgiCopyTemplateLang("option-trailer.tmpl");
3550 if (ippFindAttribute(response
, "printer-error-policy-supported",
3552 ippFindAttribute(response
, "printer-op-policy-supported",
3556 * Add the error and operation policy options...
3559 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3560 cgiSetVariable("GROUP", cgiText(_("Policies")));
3561 cgiCopyTemplateLang("option-header.tmpl");
3567 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3572 cgiSetSize("CHOICES", attr
->num_values
);
3573 cgiSetSize("TEXT", attr
->num_values
);
3574 for (k
= 0; k
< attr
->num_values
; k
++)
3576 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3577 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3580 attr
= ippFindAttribute(response
, "printer-error-policy",
3583 cgiSetVariable("KEYWORD", "printer_error_policy");
3584 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3585 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3586 "" : attr
->values
[0].string
.text
);
3589 cgiCopyTemplateLang("option-pickone.tmpl");
3592 * Operation policy...
3595 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3600 cgiSetSize("CHOICES", attr
->num_values
);
3601 cgiSetSize("TEXT", attr
->num_values
);
3602 for (k
= 0; k
< attr
->num_values
; k
++)
3604 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3605 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3608 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3610 cgiSetVariable("KEYWORD", "printer_op_policy");
3611 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3612 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3613 "" : attr
->values
[0].string
.text
);
3615 cgiCopyTemplateLang("option-pickone.tmpl");
3618 cgiCopyTemplateLang("option-trailer.tmpl");
3622 * Binary protocol support...
3625 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3626 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3628 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3629 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3631 cgiSetSize("CHOICES", attr
->num_values
);
3632 cgiSetSize("TEXT", attr
->num_values
);
3634 for (i
= 0; i
< attr
->num_values
; i
++)
3636 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3637 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3640 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3641 cgiSetVariable("KEYWORD", "port_monitor");
3642 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3643 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3645 cgiCopyTemplateLang("option-header.tmpl");
3646 cgiCopyTemplateLang("option-pickone.tmpl");
3647 cgiCopyTemplateLang("option-trailer.tmpl");
3650 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3653 ippDelete(response
);
3658 * Set default options...
3661 fputs("DEBUG: Setting options...\n", stderr
);
3665 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3666 in
= cupsFileOpen(filename
, "r");
3670 cgiSetVariable("ERROR", strerror(errno
));
3671 cgiStartHTML(cgiText(_("Set Printer Options")));
3672 cgiCopyTemplateLang("error.tmpl");
3688 while (cupsFileGets(in
, line
, sizeof(line
)))
3690 if (!strncmp(line
, "*cupsProtocol:", 14))
3692 else if (strncmp(line
, "*Default", 8))
3693 cupsFilePrintf(out
, "%s\n", line
);
3697 * Get default option name...
3700 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3702 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3703 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3708 if (!strcmp(keyword
, "PageRegion") ||
3709 !strcmp(keyword
, "PaperDimension") ||
3710 !strcmp(keyword
, "ImageableArea"))
3711 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3713 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3716 cupsFilePrintf(out
, "%s\n", line
);
3718 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3728 * Make sure temporary filename is cleared when there is no PPD...
3735 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3736 * following attributes:
3738 * attributes-charset
3739 * attributes-natural-language
3741 * job-sheets-default
3742 * printer-error-policy
3747 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3748 CUPS_ADD_MODIFY_PRINTER
);
3750 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3753 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3754 "job-sheets-default", 2, NULL
, NULL
);
3755 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3756 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3758 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3759 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3760 "printer-error-policy", NULL
, var
);
3762 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3763 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3764 "printer-op-policy", NULL
, var
);
3766 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3767 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3768 "port-monitor", NULL
, var
);
3771 * Do the request and get back a response...
3775 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3777 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3779 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3781 puts("Status: 401\n");
3784 else if (cupsLastError() > IPP_OK_CONFLICT
)
3786 cgiStartHTML(title
);
3787 cgiShowIPPError(_("Unable to set options"));
3792 * Redirect successful updates back to the printer page...
3795 char refresh
[1024]; /* Refresh URL */
3798 cgiFormEncode(uri
, printer
, sizeof(uri
));
3799 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3800 is_class
? "classes" : "printers", uri
);
3801 cgiSetVariable("refresh_page", refresh
);
3803 cgiStartHTML(title
);
3805 cgiCopyTemplateLang("printer-configured.tmpl");
3820 * 'do_set_sharing()' - Set printer-is-shared value.
3824 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3826 ipp_t
*request
, /* IPP request */
3827 *response
; /* IPP response */
3828 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3829 const char *printer
, /* Printer name */
3830 *is_class
, /* Is a class? */
3831 *shared
; /* Sharing value */
3834 is_class
= cgiGetVariable("IS_CLASS");
3835 printer
= cgiGetVariable("PRINTER_NAME");
3836 shared
= cgiGetVariable("SHARED");
3838 if (!printer
|| !shared
)
3840 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3841 cgiStartHTML(cgiText(_("Set Publishing")));
3842 cgiCopyTemplateLang("error.tmpl");
3848 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3849 * following attributes:
3851 * attributes-charset
3852 * attributes-natural-language
3857 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3859 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3860 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3862 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3865 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", (char)atoi(shared
));
3868 * Do the request and get back a response...
3871 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3873 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3875 ippDelete(response
);
3878 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3880 puts("Status: 401\n");
3883 else if (cupsLastError() > IPP_OK_CONFLICT
)
3885 cgiStartHTML(cgiText(_("Set Publishing")));
3886 cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
3891 * Redirect successful updates back to the printer page...
3894 char url
[1024], /* Printer/class URL */
3895 refresh
[1024]; /* Refresh URL */
3898 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3899 cgiFormEncode(uri
, url
, sizeof(uri
));
3900 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3901 cgiSetVariable("refresh_page", refresh
);
3903 cgiStartHTML(cgiText(_("Set Publishing")));
3904 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3905 "printer-modified.tmpl");
3913 * 'get_option_value()' - Return the value of an option.
3915 * This function also handles generation of custom option values.
3918 static char * /* O - Value string or NULL on error */
3920 ppd_file_t
*ppd
, /* I - PPD file */
3921 const char *name
, /* I - Option name */
3922 char *buffer
, /* I - String buffer */
3923 size_t bufsize
) /* I - Size of buffer */
3925 char *bufptr
, /* Pointer into buffer */
3926 *bufend
; /* End of buffer */
3927 ppd_coption_t
*coption
; /* Custom option */
3928 ppd_cparam_t
*cparam
; /* Current custom parameter */
3929 char keyword
[256]; /* Parameter name */
3930 const char *val
, /* Parameter value */
3931 *uval
; /* Units value */
3932 long integer
; /* Integer value */
3933 double number
, /* Number value */
3934 number_points
; /* Number in points */
3938 * See if we have a custom option choice...
3941 if ((val
= cgiGetVariable(name
)) == NULL
)
3949 else if (_cups_strcasecmp(val
, "Custom") ||
3950 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3953 * Not a custom choice...
3956 strlcpy(buffer
, val
, bufsize
);
3961 * OK, we have a custom option choice, format it...
3966 if (!strcmp(coption
->keyword
, "PageSize"))
3968 const char *lval
; /* Length string value */
3969 double width
, /* Width value */
3970 width_points
, /* Width in points */
3971 length
, /* Length value */
3972 length_points
; /* Length in points */
3975 val
= cgiGetVariable("PageSize.Width");
3976 lval
= cgiGetVariable("PageSize.Height");
3977 uval
= cgiGetVariable("PageSize.Units");
3979 if (!val
|| !lval
|| !uval
||
3980 (width
= strtod(val
, NULL
)) == 0.0 ||
3981 (length
= strtod(lval
, NULL
)) == 0.0 ||
3982 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3983 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3986 width_points
= get_points(width
, uval
);
3987 length_points
= get_points(length
, uval
);
3989 if (width_points
< ppd
->custom_min
[0] ||
3990 width_points
> ppd
->custom_max
[0] ||
3991 length_points
< ppd
->custom_min
[1] ||
3992 length_points
> ppd
->custom_max
[1])
3995 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
3997 else if (cupsArrayCount(coption
->params
) == 1)
3999 cparam
= ppdFirstCustomParam(coption
);
4000 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
4002 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4005 switch (cparam
->type
)
4007 case PPD_CUSTOM_CURVE
:
4008 case PPD_CUSTOM_INVCURVE
:
4009 case PPD_CUSTOM_REAL
:
4010 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4011 number
< cparam
->minimum
.custom_real
||
4012 number
> cparam
->maximum
.custom_real
)
4015 snprintf(buffer
, bufsize
, "Custom.%g", number
);
4018 case PPD_CUSTOM_INT
:
4019 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4020 integer
== LONG_MAX
||
4021 integer
< cparam
->minimum
.custom_int
||
4022 integer
> cparam
->maximum
.custom_int
)
4025 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
4028 case PPD_CUSTOM_POINTS
:
4029 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4031 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4032 (uval
= cgiGetVariable(keyword
)) == NULL
||
4033 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4034 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4037 number_points
= get_points(number
, uval
);
4038 if (number_points
< cparam
->minimum
.custom_points
||
4039 number_points
> cparam
->maximum
.custom_points
)
4042 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
4045 case PPD_CUSTOM_PASSCODE
:
4046 for (uval
= val
; *uval
; uval
++)
4047 if (!isdigit(*uval
& 255))
4050 case PPD_CUSTOM_PASSWORD
:
4051 case PPD_CUSTOM_STRING
:
4052 integer
= (long)strlen(val
);
4053 if (integer
< cparam
->minimum
.custom_string
||
4054 integer
> cparam
->maximum
.custom_string
)
4057 snprintf(buffer
, bufsize
, "Custom.%s", val
);
4063 const char *prefix
= "{"; /* Prefix string */
4067 bufend
= buffer
+ bufsize
;
4069 for (cparam
= ppdFirstCustomParam(coption
);
4071 cparam
= ppdNextCustomParam(coption
))
4073 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
4076 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4079 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%s%s=", prefix
, cparam
->name
);
4080 bufptr
+= strlen(bufptr
);
4083 switch (cparam
->type
)
4085 case PPD_CUSTOM_CURVE
:
4086 case PPD_CUSTOM_INVCURVE
:
4087 case PPD_CUSTOM_REAL
:
4088 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4089 number
< cparam
->minimum
.custom_real
||
4090 number
> cparam
->maximum
.custom_real
)
4093 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g", number
);
4096 case PPD_CUSTOM_INT
:
4097 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4098 integer
== LONG_MAX
||
4099 integer
< cparam
->minimum
.custom_int
||
4100 integer
> cparam
->maximum
.custom_int
)
4103 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%ld", integer
);
4106 case PPD_CUSTOM_POINTS
:
4107 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4109 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4110 (uval
= cgiGetVariable(keyword
)) == NULL
||
4111 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
4112 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
4113 strcmp(uval
, "mm") && strcmp(uval
, "m")))
4116 number_points
= get_points(number
, uval
);
4117 if (number_points
< cparam
->minimum
.custom_points
||
4118 number_points
> cparam
->maximum
.custom_points
)
4121 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g%s", number
, uval
);
4124 case PPD_CUSTOM_PASSCODE
:
4125 for (uval
= val
; *uval
; uval
++)
4126 if (!isdigit(*uval
& 255))
4129 case PPD_CUSTOM_PASSWORD
:
4130 case PPD_CUSTOM_STRING
:
4131 integer
= (long)strlen(val
);
4132 if (integer
< cparam
->minimum
.custom_string
||
4133 integer
> cparam
->maximum
.custom_string
)
4136 if ((bufptr
+ 2) > bufend
)
4142 while (*val
&& bufptr
< bufend
)
4144 if (*val
== '\\' || *val
== '\"')
4146 if ((bufptr
+ 1) >= bufend
)
4155 if (bufptr
>= bufend
)
4164 bufptr
+= strlen(bufptr
);
4167 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
4170 memcpy(bufptr
, "}", 2);
4178 * 'get_points()' - Get a value in points.
4181 static double /* O - Number in points */
4182 get_points(double number
, /* I - Original number */
4183 const char *uval
) /* I - Units */
4185 if (!strcmp(uval
, "mm")) /* Millimeters */
4186 return (number
* 72.0 / 25.4);
4187 else if (!strcmp(uval
, "cm")) /* Centimeters */
4188 return (number
* 72.0 / 2.54);
4189 else if (!strcmp(uval
, "in")) /* Inches */
4190 return (number
* 72.0);
4191 else if (!strcmp(uval
, "ft")) /* Feet */
4192 return (number
* 72.0 * 12.0);
4193 else if (!strcmp(uval
, "m")) /* Meters */
4194 return (number
* 72.0 / 0.0254);
4201 * End of "$Id: admin.c 11594 2014-02-14 20:09:01Z msweet $".