2 * "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 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 * main() - Main entry for CGI.
18 * choose_device_cb() - Add a device to the device selection page.
19 * do_add_rss_subscription() - Add a RSS subscription.
20 * do_am_class() - Add or modify a class.
21 * do_am_printer() - Add or modify a printer.
22 * do_cancel_subscription() - Cancel a subscription.
23 * do_config_server() - Configure server settings.
24 * do_delete_class() - Delete a class.
25 * do_delete_printer() - Delete a printer.
26 * do_export() - Export printers to Samba.
27 * do_list_printers() - List available printers.
28 * do_menu() - Show the main menu.
29 * do_set_allowed_users() - Set the allowed/denied users for a queue.
30 * do_set_default() - Set the server default printer/class.
31 * do_set_options() - Configure the default options for a queue.
32 * do_set_sharing() - Set printer-is-shared value.
33 * get_option_value() - Return the value of an option.
34 * get_points() - Get a value in points.
38 * Include necessary headers...
41 #include "cgi-private.h"
42 #include <cups/adminutil.h>
43 #include <cups/file.h>
55 static int current_device
; /* Current device for add/modify */
56 static time_t last_device_time
; /* Last update time for device list */
63 static void choose_device_cb(const char *device_class
,
64 const char *device_id
, const char *device_info
,
65 const char *device_make_and_model
,
66 const char *device_uri
,
67 const char *device_location
,
69 static void do_add_rss_subscription(http_t
*http
);
70 static void do_am_class(http_t
*http
, int modify
);
71 static void do_am_printer(http_t
*http
, int modify
);
72 static void do_cancel_subscription(http_t
*http
);
73 static void do_config_server(http_t
*http
);
74 static void do_delete_class(http_t
*http
);
75 static void do_delete_printer(http_t
*http
);
76 static void do_export(http_t
*http
);
77 static void do_list_printers(http_t
*http
);
78 static void do_menu(http_t
*http
);
79 static void do_set_allowed_users(http_t
*http
);
80 static void do_set_default(http_t
*http
);
81 static void do_set_options(http_t
*http
, int is_class
);
82 static void do_set_sharing(http_t
*http
);
83 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
84 char *buffer
, size_t bufsize
);
85 static double get_points(double number
, const char *uval
);
89 * 'main()' - Main entry for CGI.
92 int /* O - Exit status */
93 main(int argc
, /* I - Number of command-line arguments */
94 char *argv
[]) /* I - Command-line arguments */
96 http_t
*http
; /* Connection to the server */
97 const char *op
; /* Operation name */
101 * Connect to the HTTP server...
104 fputs("DEBUG: admin.cgi started...\n", stderr
);
106 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
110 perror("ERROR: Unable to connect to cupsd");
111 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
112 cupsServer() ? cupsServer() : "(null)");
113 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
114 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
118 fprintf(stderr
, "DEBUG: http=%p\n", http
);
121 * Set the web interface section...
124 cgiSetVariable("SECTION", "admin");
127 * See if we have form data...
130 if (!cgiInitialize() || !cgiGetVariable("OP"))
133 * Nope, send the administration menu...
136 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
140 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
143 * Do the operation...
146 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
148 if (!strcmp(op
, "set-allowed-users"))
149 do_set_allowed_users(http
);
150 else if (!strcmp(op
, "set-as-default"))
151 do_set_default(http
);
152 else if (!strcmp(op
, "set-sharing"))
153 do_set_sharing(http
);
154 else if (!strcmp(op
, "find-new-printers") ||
155 !strcmp(op
, "list-available-printers"))
156 do_list_printers(http
);
157 else if (!strcmp(op
, "add-class"))
158 do_am_class(http
, 0);
159 else if (!strcmp(op
, "add-printer"))
160 do_am_printer(http
, 0);
161 else if (!strcmp(op
, "modify-class"))
162 do_am_class(http
, 1);
163 else if (!strcmp(op
, "modify-printer"))
164 do_am_printer(http
, 1);
165 else if (!strcmp(op
, "delete-class"))
166 do_delete_class(http
);
167 else if (!strcmp(op
, "delete-printer"))
168 do_delete_printer(http
);
169 else if (!strcmp(op
, "set-class-options"))
170 do_set_options(http
, 1);
171 else if (!strcmp(op
, "set-printer-options"))
172 do_set_options(http
, 0);
173 else if (!strcmp(op
, "config-server"))
174 do_config_server(http
);
175 else if (!strcmp(op
, "export-samba"))
177 else if (!strcmp(op
, "add-rss-subscription"))
178 do_add_rss_subscription(http
);
179 else if (!strcmp(op
, "cancel-subscription"))
180 do_cancel_subscription(http
);
184 * Bad operation code - display an error...
187 cgiStartHTML(cgiText(_("Administration")));
188 cgiCopyTemplateLang("error-op.tmpl");
192 else if (op
&& !strcmp(op
, "redirect"))
194 const char *url
; /* Redirection URL... */
195 char prefix
[1024]; /* URL prefix */
199 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
200 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
202 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
203 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
205 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
207 if ((url
= cgiGetVariable("URL")) != NULL
)
208 printf("Location: %s%s\n\n", prefix
, url
);
210 printf("Location: %s/admin\n\n", prefix
);
215 * Form data but no operation code - display an error...
218 cgiStartHTML(cgiText(_("Administration")));
219 cgiCopyTemplateLang("error-op.tmpl");
224 * Close the HTTP server connection...
230 * Return with no errors...
238 * 'choose_device_cb()' - Add a device to the device selection page.
243 const char *device_class
, /* I - Class */
244 const char *device_id
, /* I - 1284 device ID */
245 const char *device_info
, /* I - Description */
246 const char *device_make_and_model
, /* I - Make and model */
247 const char *device_uri
, /* I - Device URI */
248 const char *device_location
, /* I - Location */
249 const char *title
) /* I - Page title */
252 * Add the device to the array...
255 cgiSetArray("device_class", current_device
, device_class
);
256 cgiSetArray("device_id", current_device
, device_id
);
257 cgiSetArray("device_info", current_device
, device_info
);
258 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
259 cgiSetArray("device_uri", current_device
, device_uri
);
260 cgiSetArray("device_location", current_device
, device_location
);
264 if (time(NULL
) > last_device_time
&& cgiSupportsMultipart())
270 if (!last_device_time
)
274 cgiCopyTemplateLang("choose-device.tmpl");
278 time(&last_device_time
);
284 * 'do_add_rss_subscription()' - Add a RSS subscription.
288 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
290 ipp_t
*request
, /* IPP request data */
291 *response
; /* IPP response data */
292 char rss_uri
[1024]; /* RSS notify-recipient URI */
293 int num_events
; /* Number of events */
294 const char *events
[12], /* Subscribed events */
295 *subscription_name
, /* Subscription name */
296 *printer_uri
, /* Printer URI */
297 *ptr
, /* Pointer into name */
298 *user
; /* Username */
299 int max_events
; /* Maximum number of events */
303 * See if we have all of the required information...
306 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
307 printer_uri
= cgiGetVariable("PRINTER_URI");
310 if (cgiGetVariable("EVENT_JOB_CREATED"))
311 events
[num_events
++] = "job-created";
312 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
313 events
[num_events
++] = "job-completed";
314 if (cgiGetVariable("EVENT_JOB_STOPPED"))
315 events
[num_events
++] = "job-stopped";
316 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
317 events
[num_events
++] = "job-config-changed";
318 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
319 events
[num_events
++] = "printer-stopped";
320 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
321 events
[num_events
++] = "printer-added";
322 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
323 events
[num_events
++] = "printer-modified";
324 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
325 events
[num_events
++] = "printer-deleted";
326 if (cgiGetVariable("EVENT_SERVER_STARTED"))
327 events
[num_events
++] = "server-started";
328 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
329 events
[num_events
++] = "server-stopped";
330 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
331 events
[num_events
++] = "server-restarted";
332 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
333 events
[num_events
++] = "server-audit";
335 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
336 max_events
= atoi(ptr
);
340 if (!subscription_name
|| !printer_uri
|| !num_events
||
341 max_events
<= 0 || max_events
> 9999)
344 * Don't have everything we need, so get the available printers
345 * and classes and (re)show the add page...
348 request
= ippNewRequest(CUPS_GET_PRINTERS
);
349 response
= cupsDoRequest(http
, request
, "/");
351 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
355 cgiStartHTML(cgiText(_("Add RSS Subscription")));
357 cgiCopyTemplateLang("add-rss-subscription.tmpl");
364 * Make sure we have a username...
367 if ((user
= getenv("REMOTE_USER")) == NULL
)
369 puts("Status: 401\n");
374 * Validate the subscription name...
377 for (ptr
= subscription_name
; *ptr
; ptr
++)
378 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
379 *ptr
== '?' || *ptr
== '#')
384 cgiSetVariable("ERROR",
385 cgiText(_("The subscription name may not "
386 "contain spaces, slashes (/), question marks (?), "
387 "or the pound sign (#).")));
388 cgiStartHTML(_("Add RSS Subscription"));
389 cgiCopyTemplateLang("error.tmpl");
395 * Add the subscription...
398 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
399 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
400 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
401 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
404 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
405 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
408 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
410 if (!strcasecmp(printer_uri
, "#ALL#"))
411 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
412 NULL
, "ipp://localhost/");
414 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
417 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
420 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
421 "notify-recipient-uri", NULL
, rss_uri
);
422 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
423 num_events
, NULL
, events
);
424 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
425 "notify-lease-duration", 0);
427 ippDelete(cupsDoRequest(http
, request
, "/"));
429 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
431 puts("Status: 401\n");
434 else if (cupsLastError() > IPP_OK_CONFLICT
)
436 cgiStartHTML(_("Add RSS Subscription"));
437 cgiShowIPPError(_("Unable to add RSS subscription:"));
442 * Redirect successful updates back to the admin page...
445 cgiSetVariable("refresh_page", "5;URL=/admin");
446 cgiStartHTML(_("Add RSS Subscription"));
447 cgiCopyTemplateLang("subscription-added.tmpl");
455 * 'do_am_class()' - Add or modify a class.
459 do_am_class(http_t
*http
, /* I - HTTP connection */
460 int modify
) /* I - Modify the printer? */
462 int i
, j
; /* Looping vars */
463 int element
; /* Element number */
464 int num_printers
; /* Number of printers */
465 ipp_t
*request
, /* IPP request */
466 *response
; /* IPP response */
467 ipp_attribute_t
*attr
; /* member-uris attribute */
468 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
469 const char *name
, /* Pointer to class name */
470 *ptr
; /* Pointer to CGI variable */
471 const char *title
; /* Title of page */
472 static const char * const pattrs
[] = /* Requested printer attributes */
480 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
481 name
= cgiGetVariable("PRINTER_NAME");
483 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
486 * Build a CUPS_GET_PRINTERS request, which requires the
487 * following attributes:
490 * attributes-natural-language
493 request
= ippNewRequest(CUPS_GET_PRINTERS
);
495 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
497 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
498 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
499 CUPS_PRINTER_IMPLICIT
);
502 * Do the request and get back a response...
505 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
508 * Create MEMBER_URIS and MEMBER_NAMES arrays...
511 for (element
= 0, attr
= response
->attrs
;
514 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
516 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
517 (!name
|| strcasecmp(name
, ptr
+ 1)))
520 * Don't show the current class...
523 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
528 for (element
= 0, attr
= response
->attrs
;
531 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
533 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
536 * Don't show the current class...
539 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
544 num_printers
= cgiGetSize("MEMBER_URIS");
554 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
555 * following attributes:
558 * attributes-natural-language
562 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
564 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
565 "localhost", 0, "/classes/%s", name
);
566 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
569 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
570 "requested-attributes",
571 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
575 * Do the request and get back a response...
578 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
580 if ((attr
= ippFindAttribute(response
, "member-names",
581 IPP_TAG_NAME
)) != NULL
)
584 * Mark any current members in the class...
587 for (j
= 0; j
< num_printers
; j
++)
588 cgiSetArray("MEMBER_SELECTED", j
, "");
590 for (i
= 0; i
< attr
->num_values
; i
++)
592 for (j
= 0; j
< num_printers
; j
++)
594 if (!strcasecmp(attr
->values
[i
].string
.text
,
595 cgiGetArray("MEMBER_NAMES", j
)))
597 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
604 if ((attr
= ippFindAttribute(response
, "printer-info",
605 IPP_TAG_TEXT
)) != NULL
)
606 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
608 if ((attr
= ippFindAttribute(response
, "printer-location",
609 IPP_TAG_TEXT
)) != NULL
)
610 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
616 * Update the location and description of an existing printer...
620 cgiCopyTemplateLang("modify-class.tmpl");
625 * Get the name, location, and description for a new printer...
629 cgiCopyTemplateLang("add-class.tmpl");
640 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
641 cgiCopyTemplateLang("error.tmpl");
646 for (ptr
= name
; *ptr
; ptr
++)
647 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
650 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
652 cgiSetVariable("ERROR",
653 cgiText(_("The class name may only contain up to "
654 "127 printable characters and may not "
655 "contain spaces, slashes (/), or the "
656 "pound sign (#).")));
658 cgiCopyTemplateLang("error.tmpl");
664 * Build a CUPS_ADD_CLASS request, which requires the following
668 * attributes-natural-language
672 * printer-is-accepting-jobs
677 request
= ippNewRequest(CUPS_ADD_CLASS
);
679 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
680 "localhost", 0, "/classes/%s", name
);
681 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
684 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
685 NULL
, cgiGetVariable("PRINTER_LOCATION"));
687 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
688 NULL
, cgiGetVariable("PRINTER_INFO"));
690 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
692 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
695 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
697 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
698 num_printers
, NULL
, NULL
);
699 for (i
= 0; i
< num_printers
; i
++)
700 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
704 * Do the request and get back a response...
707 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
709 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
711 puts("Status: 401\n");
714 else if (cupsLastError() > IPP_OK_CONFLICT
)
717 cgiShowIPPError(modify
? _("Unable to modify class:") :
718 _("Unable to add class:"));
723 * Redirect successful updates back to the class page...
726 char refresh
[1024]; /* Refresh URL */
728 cgiFormEncode(uri
, name
, sizeof(uri
));
729 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
731 cgiSetVariable("refresh_page", refresh
);
736 cgiCopyTemplateLang("class-modified.tmpl");
738 cgiCopyTemplateLang("class-added.tmpl");
746 * 'do_am_printer()' - Add or modify a printer.
750 do_am_printer(http_t
*http
, /* I - HTTP connection */
751 int modify
) /* I - Modify the printer? */
753 int i
; /* Looping var */
754 ipp_attribute_t
*attr
; /* Current attribute */
755 ipp_t
*request
, /* IPP request */
756 *response
, /* IPP response */
757 *oldinfo
; /* Old printer information */
758 const cgi_file_t
*file
; /* Uploaded file, if any */
759 const char *var
; /* CGI variable */
760 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
761 *uriptr
; /* Pointer into URI */
762 int maxrate
; /* Maximum baud rate */
763 char baudrate
[255]; /* Baud rate string */
764 const char *name
, /* Pointer to class name */
765 *ptr
; /* Pointer to CGI variable */
766 const char *title
; /* Title of page */
767 static int baudrates
[] = /* Baud rates */
782 ptr
= cgiGetVariable("DEVICE_URI");
783 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
784 ptr
? ptr
: "(null)");
786 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
791 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
792 * following attributes:
795 * attributes-natural-language
799 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
801 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
802 "localhost", 0, "/printers/%s",
803 cgiGetVariable("PRINTER_NAME"));
804 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
808 * Do the request and get back a response...
811 oldinfo
= cupsDoRequest(http
, request
, "/");
820 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
821 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
822 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
823 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
826 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
828 for (ptr
= name
; *ptr
; ptr
++)
829 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
832 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
834 cgiSetVariable("ERROR",
835 cgiText(_("The printer name may only contain up to "
836 "127 printable characters and may not "
837 "contain spaces, slashes (/), or the "
838 "pound sign (#).")));
840 cgiCopyTemplateLang("error.tmpl");
846 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
848 if ((uriptr
= strrchr(var
, '|')) != NULL
)
851 * Extract make and make/model from device URI string...
854 char make
[1024], /* Make string */
855 *makeptr
; /* Pointer into make */
860 strlcpy(make
, uriptr
, sizeof(make
));
862 if ((makeptr
= strchr(make
, ' ')) != NULL
)
864 else if ((makeptr
= strchr(make
, '-')) != NULL
)
866 else if (!strncasecmp(make
, "laserjet", 8) ||
867 !strncasecmp(make
, "deskjet", 7) ||
868 !strncasecmp(make
, "designjet", 9))
870 else if (!strncasecmp(make
, "phaser", 6))
871 strcpy(make
, "Xerox");
872 else if (!strncasecmp(make
, "stylus", 6))
873 strcpy(make
, "Epson");
875 strcpy(make
, "Generic");
877 if (!cgiGetVariable("CURRENT_MAKE"))
878 cgiSetVariable("CURRENT_MAKE", make
);
880 cgiSetVariable("PPD_MAKE", make
);
882 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
883 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
887 char template[128], /* Template name */
888 *tptr
; /* Pointer into template name */
890 cgiSetVariable("PRINTER_INFO", uriptr
);
892 for (tptr
= template;
893 tptr
< (template + sizeof(template) - 1) && *uriptr
;
895 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
898 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
[-1] != '_')
900 else if (*uriptr
== '?' || *uriptr
== '(')
905 cgiSetVariable("TEMPLATE_NAME", template);
913 * Look for devices so the user can pick something...
916 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
918 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
919 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
922 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
923 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
927 * Scan for devices for up to 30 seconds, updating the page as we find
931 fputs("DEBUG: Getting list of devices...\n", stderr
);
933 last_device_time
= 0;
935 if (cupsGetDevices(http
, 30, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
936 (cups_device_cb_t
)choose_device_cb
,
937 (void *)title
) == IPP_OK
)
939 fputs("DEBUG: Got device list!\n", stderr
);
941 if (!cgiSupportsMultipart())
944 * Non-modern browsers that don't support multi-part documents get
945 * everything at the end...
949 cgiCopyTemplateLang("choose-device.tmpl");
956 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
957 cupsLastError(), cupsLastErrorString());
958 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
960 puts("Status: 401\n");
966 cgiShowIPPError(modify
? _("Unable to modify printer:") :
967 _("Unable to add printer:"));
974 * Show the final selection page...
977 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
979 cgiCopyTemplateLang("choose-device.tmpl");
983 else if (strchr(var
, '/') == NULL
)
985 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
988 * Set the current device URI for the form to the old one...
991 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
992 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
996 * User needs to set the full URI...
1000 cgiCopyTemplateLang("choose-uri.tmpl");
1003 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1006 * Need baud rate, parity, etc.
1009 if ((var
= strchr(var
, '?')) != NULL
&&
1010 strncmp(var
, "?baud=", 6) == 0)
1011 maxrate
= atoi(var
+ 6);
1015 for (i
= 0; i
< 10; i
++)
1016 if (baudrates
[i
] > maxrate
)
1020 sprintf(baudrate
, "%d", baudrates
[i
]);
1021 cgiSetArray("BAUDRATES", i
, baudrate
);
1024 cgiStartHTML(title
);
1025 cgiCopyTemplateLang("choose-serial.tmpl");
1028 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
1030 cgiStartHTML(title
);
1035 * Update the location and description of an existing printer...
1040 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
1041 IPP_TAG_TEXT
)) != NULL
)
1042 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
1044 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
1045 IPP_TAG_TEXT
)) != NULL
)
1046 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
1049 cgiCopyTemplateLang("modify-printer.tmpl");
1054 * Get the name, location, and description for a new printer...
1058 if (!strncmp(var
, "usb:", 4))
1059 cgiSetVariable("printer_is_shared", "1");
1061 #endif /* __APPLE__ */
1062 cgiSetVariable("printer_is_shared", "0");
1064 cgiCopyTemplateLang("add-printer.tmpl");
1075 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1077 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
1080 * Get the PPD file...
1083 int fd
; /* PPD file */
1084 char filename
[1024]; /* PPD filename */
1085 ppd_file_t
*ppd
; /* PPD information */
1086 char buffer
[1024]; /* Buffer */
1087 int bytes
; /* Number of bytes */
1088 http_status_t get_status
; /* Status of GET */
1091 /* TODO: Use cupsGetFile() API... */
1092 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1094 if (httpGet(http
, uri
))
1097 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1099 if (get_status
!= HTTP_OK
)
1103 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1104 uri
, get_status
, httpStatus(get_status
));
1106 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1108 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1109 write(fd
, buffer
, bytes
);
1113 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1115 if (ppd
->manufacturer
)
1116 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1119 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1126 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1127 filename
, ppdErrorString(ppdLastError(&bytes
)));
1135 "ERROR: Unable to create temporary file for PPD file: %s\n",
1141 * Build a CUPS_GET_PPDS request, which requires the following
1144 * attributes-charset
1145 * attributes-natural-language
1149 request
= ippNewRequest(CUPS_GET_PPDS
);
1151 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1152 NULL
, "ipp://localhost/printers/");
1154 if ((var
= cgiGetVariable("CURRENT_MAKE")) == NULL
)
1155 var
= cgiGetVariable("PPD_MAKE");
1156 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1158 const char *make_model
; /* Make and model */
1161 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1162 "ppd-make", NULL
, var
);
1164 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1165 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1166 "ppd-make-and-model", NULL
, make_model
);
1169 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1170 "requested-attributes", NULL
, "ppd-make");
1173 * Do the request and get back a response...
1176 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1179 * Got the list of PPDs, see if the user has selected a make...
1182 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
1185 * No PPD files with this make, try again with all makes...
1188 ippDelete(response
);
1190 request
= ippNewRequest(CUPS_GET_PPDS
);
1192 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1193 NULL
, "ipp://localhost/printers/");
1195 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1196 "requested-attributes", NULL
, "ppd-make");
1198 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1199 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1201 cgiStartHTML(title
);
1202 cgiCopyTemplateLang("choose-make.tmpl");
1205 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1207 cgiStartHTML(title
);
1208 cgiCopyTemplateLang("choose-make.tmpl");
1214 * Let the user choose a model...
1217 cgiStartHTML(title
);
1218 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1219 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1220 cgiCopyTemplateLang("choose-model.tmpl");
1224 ippDelete(response
);
1228 cgiStartHTML(title
);
1229 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1230 cgiCopyTemplateLang("error.tmpl");
1237 * Build a CUPS_ADD_PRINTER request, which requires the following
1240 * attributes-charset
1241 * attributes-natural-language
1247 * printer-is-accepting-jobs
1252 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1254 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1255 "localhost", 0, "/printers/%s",
1256 cgiGetVariable("PRINTER_NAME"));
1257 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1260 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1261 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1263 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1264 NULL
, cgiGetVariable("PRINTER_INFO"));
1268 var
= cgiGetVariable("PPD_NAME");
1269 if (strcmp(var
, "__no_change__"))
1270 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1274 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1277 * Strip make and model from URI...
1280 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1283 if (!strncmp(uri
, "serial:", 7))
1286 * Update serial port URI to include baud rate, etc.
1289 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1290 uriptr
= uri
+ strlen(uri
);
1292 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1293 "?baud=%s+bits=%s+parity=%s+flow=%s",
1294 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1295 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1298 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1301 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1303 var
= cgiGetVariable("printer_is_shared");
1304 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1305 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1307 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1311 * Do the request and get back a response...
1315 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1317 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1319 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1321 puts("Status: 401\n");
1324 else if (cupsLastError() > IPP_OK_CONFLICT
)
1326 cgiStartHTML(title
);
1327 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1328 _("Unable to add printer:"));
1333 * Redirect successful updates back to the printer page...
1336 char refresh
[1024]; /* Refresh URL */
1339 cgiFormEncode(uri
, name
, sizeof(uri
));
1341 snprintf(refresh
, sizeof(refresh
),
1342 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1344 cgiSetVariable("refresh_page", refresh
);
1346 cgiStartHTML(title
);
1348 cgiCopyTemplateLang("printer-modified.tmpl");
1353 * Set the printer options...
1356 cgiSetVariable("OP", "set-printer-options");
1357 do_set_options(http
, 0);
1370 * 'do_cancel_subscription()' - Cancel a subscription.
1374 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1376 ipp_t
*request
; /* IPP request data */
1377 const char *var
, /* Form variable */
1378 *user
; /* Username */
1379 int id
; /* Subscription ID */
1383 * See if we have all of the required information...
1386 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1393 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1394 cgiStartHTML(_("Cancel RSS Subscription"));
1395 cgiCopyTemplateLang("error.tmpl");
1401 * Require a username...
1404 if ((user
= getenv("REMOTE_USER")) == NULL
)
1406 puts("Status: 401\n");
1411 * Cancel the subscription...
1414 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1416 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1417 NULL
, "ipp://localhost/");
1418 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1419 "notify-subscription-id", id
);
1421 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1424 ippDelete(cupsDoRequest(http
, request
, "/"));
1426 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1428 puts("Status: 401\n");
1431 else if (cupsLastError() > IPP_OK_CONFLICT
)
1433 cgiStartHTML(_("Cancel RSS Subscription"));
1434 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1439 * Redirect successful updates back to the admin page...
1442 cgiSetVariable("refresh_page", "5;URL=/admin");
1443 cgiStartHTML(_("Cancel RSS Subscription"));
1444 cgiCopyTemplateLang("subscription-canceled.tmpl");
1452 * 'do_config_server()' - Configure server settings.
1456 do_config_server(http_t
*http
) /* I - HTTP connection */
1458 if (cgiGetVariable("CHANGESETTINGS"))
1461 * Save basic setting changes...
1464 int num_settings
; /* Number of server settings */
1465 cups_option_t
*settings
; /* Server settings */
1466 int advanced
, /* Advanced settings shown? */
1467 changed
; /* Have settings changed? */
1468 const char *debug_logging
, /* DEBUG_LOGGING value */
1469 *remote_admin
, /* REMOTE_ADMIN value */
1470 *remote_any
, /* REMOTE_ANY value */
1472 /* REMOTE_PRINTERS value */
1473 *share_printers
,/* SHARE_PRINTERS value */
1475 /* USER_CANCEL_ANY value */
1476 *browse_web_if
= NULL
,
1477 /* BrowseWebIF value */
1478 *preserve_job_history
= NULL
,
1479 /* PreserveJobHistory value */
1480 *preserve_job_files
= NULL
,
1481 /* PreserveJobFiles value */
1482 *max_clients
= NULL
,
1483 /* MaxClients value */
1486 *max_log_size
= NULL
;
1487 /* MaxLogSize value */
1488 char local_protocols
[255],
1489 /* BrowseLocalProtocols */
1490 remote_protocols
[255];
1491 /* BrowseRemoteProtocols */
1492 const char *current_browse_web_if
,
1493 /* BrowseWebIF value */
1494 *current_preserve_job_history
,
1495 /* PreserveJobHistory value */
1496 *current_preserve_job_files
,
1497 /* PreserveJobFiles value */
1498 *current_max_clients
,
1499 /* MaxClients value */
1502 *current_max_log_size
,
1503 /* MaxLogSize value */
1504 *current_local_protocols
,
1505 /* BrowseLocalProtocols */
1506 *current_remote_protocols
;
1507 /* BrowseRemoteProtocols */
1509 char default_auth_type
[255];
1510 /* DefaultAuthType value */
1511 const char *val
; /* Setting value */
1512 #endif /* HAVE_GSSAPI */
1516 * Get the checkbox values from the form...
1519 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1520 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1521 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1522 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1523 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1524 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1526 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1530 * Get advanced settings...
1533 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1534 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1535 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1536 max_clients
= cgiGetVariable("MAX_CLIENTS");
1537 max_jobs
= cgiGetVariable("MAX_JOBS");
1538 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1540 if (!max_clients
|| atoi(max_clients
) <= 0)
1541 max_clients
= "100";
1543 if (!max_jobs
|| atoi(max_jobs
) <= 0)
1546 if (!max_log_size
|| atof(max_log_size
) <= 0.0)
1547 max_log_size
= "1m";
1549 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1550 strcpy(local_protocols
, "cups");
1552 local_protocols
[0] = '\0';
1555 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1557 if (local_protocols
[0])
1558 strcat(local_protocols
, " dnssd");
1560 strcat(local_protocols
, "dnssd");
1562 #endif /* HAVE_DNSSD */
1565 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1567 if (local_protocols
[0])
1568 strcat(local_protocols
, " ldap");
1570 strcat(local_protocols
, "ldap");
1572 #endif /* HAVE_LDAP */
1575 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1577 if (local_protocols
[0])
1578 strcat(local_protocols
, " slp");
1580 strcat(local_protocols
, "slp");
1582 #endif /* HAVE_SLP */
1584 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1585 strcpy(remote_protocols
, "cups");
1587 remote_protocols
[0] = '\0';
1590 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1592 if (remote_protocols
[0])
1593 strcat(remote_protocols
, " ldap");
1595 strcat(remote_protocols
, "ldap");
1597 #endif /* HAVE_LDAP */
1600 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1602 if (remote_protocols
[0])
1603 strcat(remote_protocols
, " slp");
1605 strcat(remote_protocols
, "slp");
1607 #endif /* HAVE_SLP */
1611 * Get the current server settings...
1614 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1616 cgiStartHTML(cgiText(_("Change Settings")));
1617 cgiSetVariable("MESSAGE",
1618 cgiText(_("Unable to change server settings:")));
1619 cgiSetVariable("ERROR", cupsLastErrorString());
1620 cgiCopyTemplateLang("error.tmpl");
1627 * Get authentication settings...
1630 if (cgiGetVariable("KERBEROS"))
1631 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1634 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1636 if (!val
|| !strcasecmp(val
, "Negotiate"))
1637 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1639 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1642 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1643 #endif /* HAVE_GSSAPI */
1645 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1647 current_browse_web_if
= "No";
1649 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1652 current_preserve_job_history
= "Yes";
1654 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1657 current_preserve_job_files
= "No";
1659 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1661 current_max_clients
= "100";
1663 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1665 current_max_jobs
= "500";
1667 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1669 current_max_log_size
= "1m";
1671 if ((current_local_protocols
= cupsGetOption("BrowseLocalProtocols",
1674 current_local_protocols
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
1676 if ((current_remote_protocols
= cupsGetOption("BrowseRemoteProtocols",
1679 current_remote_protocols
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
1682 * See if the settings have changed...
1685 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1686 num_settings
, settings
)) ||
1687 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1688 num_settings
, settings
)) ||
1689 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1690 num_settings
, settings
)) ||
1691 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1692 num_settings
, settings
)) ||
1693 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1694 num_settings
, settings
)) ||
1696 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1697 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1698 num_settings
, settings
)) ||
1699 #endif /* HAVE_GSSAPI */
1700 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1701 num_settings
, settings
));
1703 if (advanced
&& !changed
)
1704 changed
= strcasecmp(local_protocols
, current_local_protocols
) ||
1705 strcasecmp(remote_protocols
, current_remote_protocols
) ||
1706 strcasecmp(browse_web_if
, current_browse_web_if
) ||
1707 strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1708 strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1709 strcasecmp(max_clients
, current_max_clients
) ||
1710 strcasecmp(max_jobs
, current_max_jobs
) ||
1711 strcasecmp(max_log_size
, current_max_log_size
);
1716 * Settings *have* changed, so save the changes...
1719 cupsFreeOptions(num_settings
, settings
);
1722 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1723 debug_logging
, num_settings
, &settings
);
1724 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1725 remote_admin
, num_settings
, &settings
);
1726 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1727 remote_any
, num_settings
, &settings
);
1728 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1729 remote_printers
, num_settings
, &settings
);
1730 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1731 share_printers
, num_settings
, &settings
);
1732 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1733 user_cancel_any
, num_settings
, &settings
);
1735 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1736 num_settings
, &settings
);
1737 #endif /* HAVE_GSSAPI */
1742 * Add advanced settings...
1745 if (strcasecmp(local_protocols
, current_local_protocols
))
1746 num_settings
= cupsAddOption("BrowseLocalProtocols", local_protocols
,
1747 num_settings
, &settings
);
1748 if (strcasecmp(remote_protocols
, current_remote_protocols
))
1749 num_settings
= cupsAddOption("BrowseRemoteProtocols", remote_protocols
,
1750 num_settings
, &settings
);
1751 if (strcasecmp(browse_web_if
, current_browse_web_if
))
1752 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1753 num_settings
, &settings
);
1754 if (strcasecmp(preserve_job_history
, current_preserve_job_history
))
1755 num_settings
= cupsAddOption("PreserveJobHistory",
1756 preserve_job_history
, num_settings
,
1758 if (strcasecmp(preserve_job_files
, current_preserve_job_files
))
1759 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1760 num_settings
, &settings
);
1761 if (strcasecmp(max_clients
, current_max_clients
))
1762 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1764 if (strcasecmp(max_jobs
, current_max_jobs
))
1765 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1767 if (strcasecmp(max_log_size
, current_max_log_size
))
1768 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1772 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1774 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1776 puts("Status: 401\n");
1780 cgiStartHTML(cgiText(_("Change Settings")));
1781 cgiSetVariable("MESSAGE",
1782 cgiText(_("Unable to change server settings:")));
1783 cgiSetVariable("ERROR", cupsLastErrorString());
1784 cgiCopyTemplateLang("error.tmpl");
1789 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1791 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1792 cgiStartHTML(cgiText(_("Change Settings")));
1793 cgiCopyTemplateLang("restart.tmpl");
1802 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1803 cgiStartHTML(cgiText(_("Change Settings")));
1804 cgiCopyTemplateLang("norestart.tmpl");
1807 cupsFreeOptions(num_settings
, settings
);
1811 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1814 * Save hand-edited config file...
1817 http_status_t status
; /* PUT status */
1818 char tempfile
[1024]; /* Temporary new cupsd.conf */
1819 int tempfd
; /* Temporary file descriptor */
1820 cups_file_t
*temp
; /* Temporary file */
1821 const char *start
, /* Start of line */
1822 *end
; /* End of line */
1826 * Create a temporary file for the new cupsd.conf file...
1829 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1831 cgiStartHTML(cgiText(_("Edit Configuration File")));
1832 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1833 cgiSetVariable("ERROR", strerror(errno
));
1834 cgiCopyTemplateLang("error.tmpl");
1841 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1843 cgiStartHTML(cgiText(_("Edit Configuration File")));
1844 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1845 cgiSetVariable("ERROR", strerror(errno
));
1846 cgiCopyTemplateLang("error.tmpl");
1856 * Copy the cupsd.conf text from the form variable...
1859 start
= cgiGetVariable("CUPSDCONF");
1862 if ((end
= strstr(start
, "\r\n")) == NULL
)
1863 if ((end
= strstr(start
, "\n")) == NULL
)
1864 end
= start
+ strlen(start
);
1866 cupsFileWrite(temp
, start
, end
- start
);
1867 cupsFilePutChar(temp
, '\n');
1871 else if (*end
== '\n')
1877 cupsFileClose(temp
);
1880 * Upload the configuration file to the server...
1883 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1885 if (status
== HTTP_UNAUTHORIZED
)
1887 puts("Status: 401\n");
1891 else if (status
!= HTTP_CREATED
)
1893 cgiSetVariable("MESSAGE",
1894 cgiText(_("Unable to upload cupsd.conf file:")));
1895 cgiSetVariable("ERROR", httpStatus(status
));
1897 cgiStartHTML(cgiText(_("Edit Configuration File")));
1898 cgiCopyTemplateLang("error.tmpl");
1902 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1904 cgiStartHTML(cgiText(_("Edit Configuration File")));
1905 cgiCopyTemplateLang("restart.tmpl");
1914 struct stat info
; /* cupsd.conf information */
1915 cups_file_t
*cupsd
; /* cupsd.conf file */
1916 char *buffer
, /* Buffer for entire file */
1917 *bufptr
, /* Pointer into buffer */
1918 *bufend
; /* End of buffer */
1919 int ch
; /* Character from file */
1920 char filename
[1024]; /* Filename */
1921 const char *server_root
; /* Location of config files */
1925 * Locate the cupsd.conf file...
1928 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1929 server_root
= CUPS_SERVERROOT
;
1931 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1934 * Figure out the size...
1937 if (stat(filename
, &info
))
1939 cgiStartHTML(cgiText(_("Edit Configuration File")));
1940 cgiSetVariable("MESSAGE",
1941 cgiText(_("Unable to access cupsd.conf file:")));
1942 cgiSetVariable("ERROR", strerror(errno
));
1943 cgiCopyTemplateLang("error.tmpl");
1950 if (info
.st_size
> (1024 * 1024))
1952 cgiStartHTML(cgiText(_("Edit Configuration File")));
1953 cgiSetVariable("MESSAGE",
1954 cgiText(_("Unable to access cupsd.conf file:")));
1955 cgiSetVariable("ERROR",
1956 cgiText(_("Unable to edit cupsd.conf files larger than "
1958 cgiCopyTemplateLang("error.tmpl");
1961 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1962 (long)info
.st_size
);
1967 * Open the cupsd.conf file...
1970 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1973 * Unable to open - log an error...
1976 cgiStartHTML(cgiText(_("Edit Configuration File")));
1977 cgiSetVariable("MESSAGE",
1978 cgiText(_("Unable to access cupsd.conf file:")));
1979 cgiSetVariable("ERROR", strerror(errno
));
1980 cgiCopyTemplateLang("error.tmpl");
1988 * Allocate memory and load the file into a string buffer...
1991 if ((buffer
= calloc(1, info
.st_size
+ 1)) != NULL
)
1993 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1994 cgiSetVariable("CUPSDCONF", buffer
);
1998 cupsFileClose(cupsd
);
2001 * Then get the default cupsd.conf file and put that into a string as
2005 strlcat(filename
, ".default", sizeof(filename
));
2007 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
2008 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
2010 if ((buffer
= calloc(1, 2 * info
.st_size
+ 1)) != NULL
)
2012 bufend
= buffer
+ 2 * info
.st_size
- 1;
2014 for (bufptr
= buffer
;
2015 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
2017 if (ch
== '\\' || ch
== '\"')
2022 else if (ch
== '\n')
2027 else if (ch
== '\t')
2038 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
2042 cupsFileClose(cupsd
);
2046 * Show the current config file...
2049 cgiStartHTML(cgiText(_("Edit Configuration File")));
2051 cgiCopyTemplateLang("edit-config.tmpl");
2059 * 'do_delete_class()' - Delete a class.
2063 do_delete_class(http_t
*http
) /* I - HTTP connection */
2065 ipp_t
*request
; /* IPP request */
2066 char uri
[HTTP_MAX_URI
]; /* Job URI */
2067 const char *pclass
; /* Printer class name */
2071 * Get form variables...
2074 if (cgiGetVariable("CONFIRM") == NULL
)
2076 cgiStartHTML(cgiText(_("Delete Class")));
2077 cgiCopyTemplateLang("class-confirm.tmpl");
2082 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2083 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2084 "localhost", 0, "/classes/%s", pclass
);
2087 cgiStartHTML(cgiText(_("Delete Class")));
2088 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2089 cgiCopyTemplateLang("error.tmpl");
2095 * Build a CUPS_DELETE_CLASS request, which requires the following
2098 * attributes-charset
2099 * attributes-natural-language
2103 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2105 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2109 * Do the request and get back a response...
2112 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2115 * Show the results...
2118 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2120 puts("Status: 401\n");
2123 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2126 * Redirect successful updates back to the classes page...
2129 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2132 cgiStartHTML(cgiText(_("Delete Class")));
2134 if (cupsLastError() > IPP_OK_CONFLICT
)
2135 cgiShowIPPError(_("Unable to delete class:"));
2137 cgiCopyTemplateLang("class-deleted.tmpl");
2144 * 'do_delete_printer()' - Delete a printer.
2148 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2150 ipp_t
*request
; /* IPP request */
2151 char uri
[HTTP_MAX_URI
]; /* Job URI */
2152 const char *printer
; /* Printer printer name */
2156 * Get form variables...
2159 if (cgiGetVariable("CONFIRM") == NULL
)
2161 cgiStartHTML(cgiText(_("Delete Printer")));
2162 cgiCopyTemplateLang("printer-confirm.tmpl");
2167 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2168 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2169 "localhost", 0, "/printers/%s", printer
);
2172 cgiStartHTML(cgiText(_("Delete Printer")));
2173 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2174 cgiCopyTemplateLang("error.tmpl");
2180 * Build a CUPS_DELETE_PRINTER request, which requires the following
2183 * attributes-charset
2184 * attributes-natural-language
2188 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2190 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2194 * Do the request and get back a response...
2197 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2200 * Show the results...
2203 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2205 puts("Status: 401\n");
2208 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2211 * Redirect successful updates back to the printers page...
2214 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2217 cgiStartHTML(cgiText(_("Delete Printer")));
2219 if (cupsLastError() > IPP_OK_CONFLICT
)
2220 cgiShowIPPError(_("Unable to delete printer:"));
2222 cgiCopyTemplateLang("printer-deleted.tmpl");
2229 * 'do_export()' - Export printers to Samba.
2233 do_export(http_t
*http
) /* I - HTTP connection */
2235 int i
, j
; /* Looping vars */
2236 ipp_t
*request
, /* IPP request */
2237 *response
; /* IPP response */
2238 const char *username
, /* Samba username */
2239 *password
, /* Samba password */
2240 *export_all
; /* Export all printers? */
2241 int export_count
, /* Number of printers to export */
2242 printer_count
; /* Number of available printers */
2243 const char *name
, /* What name to pull */
2244 *dest
; /* Current destination */
2245 char ppd
[1024]; /* PPD file */
2252 username
= cgiGetVariable("USERNAME");
2253 password
= cgiGetVariable("PASSWORD");
2254 export_all
= cgiGetVariable("EXPORT_ALL");
2255 export_count
= cgiGetSize("EXPORT_NAME");
2258 * Get list of available printers...
2261 cgiSetSize("PRINTER_NAME", 0);
2262 cgiSetSize("PRINTER_EXPORT", 0);
2264 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2266 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2269 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2270 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2271 CUPS_PRINTER_IMPLICIT
);
2273 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2274 "requested-attributes", NULL
, "printer-name");
2276 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2278 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2279 ippDelete(response
);
2283 printer_count
= cgiGetSize("PRINTER_NAME");
2285 for (i
= 0; i
< printer_count
; i
++)
2287 dest
= cgiGetArray("PRINTER_NAME", i
);
2289 for (j
= 0; j
< export_count
; j
++)
2290 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2293 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2299 * Export or get the printers to export...
2302 if (username
&& *username
&& password
&& *password
&&
2303 (export_all
|| export_count
> 0))
2309 fputs("DEBUG: Export printers...\n", stderr
);
2313 name
= "PRINTER_NAME";
2314 export_count
= cgiGetSize("PRINTER_NAME");
2317 name
= "EXPORT_NAME";
2319 for (i
= 0; i
< export_count
; i
++)
2321 dest
= cgiGetArray(name
, i
);
2323 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2326 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2335 if (i
< export_count
)
2336 cgiSetVariable("ERROR", cupsLastErrorString());
2339 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2340 cgiCopyTemplateLang("samba-exported.tmpl");
2345 else if (username
&& !*username
)
2346 cgiSetVariable("ERROR",
2347 cgiText(_("A Samba username is required to export "
2348 "printer drivers")));
2349 else if (username
&& (!password
|| !*password
))
2350 cgiSetVariable("ERROR",
2351 cgiText(_("A Samba password is required to export "
2352 "printer drivers")));
2358 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2359 cgiCopyTemplateLang("samba-export.tmpl");
2365 * 'do_list_printers()' - List available printers.
2369 do_list_printers(http_t
*http
) /* I - HTTP connection */
2371 ipp_t
*request
, /* IPP request */
2372 *response
; /* IPP response */
2373 ipp_attribute_t
*attr
; /* IPP attribute */
2376 cgiStartHTML(cgiText(_("List Available Printers")));
2380 * Get the list of printers and their devices...
2383 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2385 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2386 "requested-attributes", NULL
, "device-uri");
2388 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2389 CUPS_PRINTER_LOCAL
);
2390 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2391 CUPS_PRINTER_LOCAL
);
2393 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2396 * Got the printer list, now load the devices...
2399 int i
; /* Looping var */
2400 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2401 char *printer_device
; /* Current printer device */
2405 * Allocate an array and copy the device strings...
2408 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2410 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2412 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2414 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2418 * Free the printer list and get the device list...
2421 ippDelete(response
);
2423 request
= ippNewRequest(CUPS_GET_DEVICES
);
2425 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2428 * Got the device list, let's parse it...
2431 const char *device_uri
, /* device-uri attribute value */
2432 *device_make_and_model
, /* device-make-and-model value */
2433 *device_info
; /* device-info value */
2436 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2439 * Skip leading attributes until we hit a device...
2442 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2449 * Pull the needed attributes from this device...
2453 device_make_and_model
= NULL
;
2456 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2458 if (!strcmp(attr
->name
, "device-info") &&
2459 attr
->value_tag
== IPP_TAG_TEXT
)
2460 device_info
= attr
->values
[0].string
.text
;
2462 if (!strcmp(attr
->name
, "device-make-and-model") &&
2463 attr
->value_tag
== IPP_TAG_TEXT
)
2464 device_make_and_model
= attr
->values
[0].string
.text
;
2466 if (!strcmp(attr
->name
, "device-uri") &&
2467 attr
->value_tag
== IPP_TAG_URI
)
2468 device_uri
= attr
->values
[0].string
.text
;
2474 * See if we have everything needed...
2477 if (device_info
&& device_make_and_model
&& device_uri
&&
2478 strcasecmp(device_make_and_model
, "unknown") &&
2479 strchr(device_uri
, ':'))
2482 * Yes, now see if there is already a printer for this
2486 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2489 * Not found, so it must be a new printer...
2492 char option
[1024], /* Form variables for this device */
2493 *option_ptr
; /* Pointer into string */
2494 const char *ptr
; /* Pointer into device string */
2498 * Format the printer name variable for this device...
2500 * We use the device-info string first, then device-uri,
2501 * and finally device-make-and-model to come up with a
2505 if (strncasecmp(device_info
, "unknown", 7))
2507 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2510 ptr
= device_make_and_model
;
2512 for (option_ptr
= option
;
2513 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2515 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2517 *option_ptr
++ = *ptr
;
2518 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
[-1] != '_')
2519 *option_ptr
++ = '_';
2520 else if (*ptr
== '?' || *ptr
== '(')
2525 cgiSetArray("TEMPLATE_NAME", i
, option
);
2528 * Finally, set the form variables for this printer...
2531 cgiSetArray("device_info", i
, device_info
);
2532 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2533 cgiSetArray("device_uri", i
, device_uri
);
2542 ippDelete(response
);
2545 * Free the device list...
2548 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2550 printer_device
= (char *)cupsArrayNext(printer_devices
))
2551 free(printer_device
);
2553 cupsArrayDelete(printer_devices
);
2558 * Finally, show the printer list...
2561 cgiCopyTemplateLang("list-available-printers.tmpl");
2568 * 'do_menu()' - Show the main menu.
2572 do_menu(http_t
*http
) /* I - HTTP connection */
2574 int num_settings
; /* Number of server settings */
2575 cups_option_t
*settings
; /* Server settings */
2576 const char *val
; /* Setting value */
2577 char filename
[1024]; /* Temporary filename */
2578 const char *datadir
; /* Location of data files */
2579 ipp_t
*request
, /* IPP request */
2580 *response
; /* IPP response */
2584 * Get the current server settings...
2587 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2589 cgiSetVariable("SETTINGS_MESSAGE",
2590 cgiText(_("Unable to open cupsd.conf file:")));
2591 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2594 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2595 settings
)) != NULL
&& atoi(val
))
2596 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2598 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2599 settings
)) != NULL
&& atoi(val
))
2600 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2602 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2603 settings
)) != NULL
&& atoi(val
))
2604 cgiSetVariable("REMOTE_ANY", "CHECKED");
2606 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2607 settings
)) != NULL
&& atoi(val
))
2608 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2610 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2611 settings
)) != NULL
&& atoi(val
))
2612 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2614 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2615 settings
)) != NULL
&& atoi(val
))
2616 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2619 cgiSetVariable("HAVE_GSSAPI", "1");
2621 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2622 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2623 cgiSetVariable("KERBEROS", "CHECKED");
2624 #endif /* HAVE_GSSAPI */
2627 cgiSetVariable("HAVE_DNSSD", "1");
2628 #endif /* HAVE_DNSSD */
2631 cgiSetVariable("HAVE_LDAP", "1");
2632 #endif /* HAVE_LDAP */
2635 cgiSetVariable("HAVE_LIBSLP", "1");
2636 #endif /* HAVE_LIBSLP */
2638 if ((val
= cupsGetOption("BrowseRemoteProtocols", num_settings
,
2640 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2642 val
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
2644 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2645 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2647 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2648 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2650 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2651 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2653 if ((val
= cupsGetOption("BrowseLocalProtocols", num_settings
,
2655 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2657 val
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
2659 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2660 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2662 if (strstr(val
, "dnssd") || strstr(val
, "DNSSD") ||
2663 strstr(val
, "dns-sd") || strstr(val
, "DNS-SD") ||
2664 strstr(val
, "bonjour") || strstr(val
, "BONJOUR"))
2665 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2667 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2668 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2670 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2671 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2673 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2677 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2678 !strcasecmp(val
, "true"))
2679 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2681 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2685 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2686 !strcasecmp(val
, "true"))
2688 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2690 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2694 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2695 !strcasecmp(val
, "true"))
2696 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2699 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2702 cgiSetVariable("MAX_CLIENTS", val
);
2704 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2707 cgiSetVariable("MAX_JOBS", val
);
2709 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2712 cgiSetVariable("MAX_LOG_SIZE", val
);
2714 cupsFreeOptions(num_settings
, settings
);
2717 * See if Samba and the Windows drivers are installed...
2720 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2721 datadir
= CUPS_DATADIR
;
2723 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2724 if (!access(filename
, R_OK
))
2727 * Found Windows 2000 driver file, see if we have smbclient and
2731 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2732 sizeof(filename
)) &&
2733 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2735 cgiSetVariable("HAVE_SAMBA", "Y");
2738 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2740 fputs("ERROR: smbclient not found!\n", stderr
);
2742 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2744 fputs("ERROR: rpcclient not found!\n", stderr
);
2754 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2756 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2757 NULL
, "ipp://localhost/");
2759 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2761 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2762 ippDelete(response
);
2766 * Finally, show the main menu template...
2769 cgiStartHTML(cgiText(_("Administration")));
2771 cgiCopyTemplateLang("admin.tmpl");
2778 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2782 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2784 int i
; /* Looping var */
2785 ipp_t
*request
, /* IPP request */
2786 *response
; /* IPP response */
2787 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2788 const char *printer
, /* Printer name (purge-jobs) */
2789 *is_class
, /* Is a class? */
2790 *users
, /* List of users or groups */
2791 *type
; /* Allow/deny type */
2792 int num_users
; /* Number of users */
2793 char *ptr
, /* Pointer into users string */
2794 *end
, /* Pointer to end of users string */
2795 quote
; /* Quote character */
2796 ipp_attribute_t
*attr
; /* Attribute */
2797 static const char * const attrs
[] = /* Requested attributes */
2799 "requesting-user-name-allowed",
2800 "requesting-user-name-denied"
2804 is_class
= cgiGetVariable("IS_CLASS");
2805 printer
= cgiGetVariable("PRINTER_NAME");
2809 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2810 cgiStartHTML(cgiText(_("Set Allowed Users")));
2811 cgiCopyTemplateLang("error.tmpl");
2816 users
= cgiGetVariable("users");
2817 type
= cgiGetVariable("type");
2819 if (!users
|| !type
||
2820 (strcmp(type
, "requesting-user-name-allowed") &&
2821 strcmp(type
, "requesting-user-name-denied")))
2824 * Build a Get-Printer-Attributes request, which requires the following
2827 * attributes-charset
2828 * attributes-natural-language
2830 * requested-attributes
2833 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2835 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2836 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2838 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2841 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2842 "requested-attributes",
2843 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2846 * Do the request and get back a response...
2849 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2851 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2853 ippDelete(response
);
2856 cgiStartHTML(cgiText(_("Set Allowed Users")));
2858 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2860 puts("Status: 401\n");
2863 else if (cupsLastError() > IPP_OK_CONFLICT
)
2864 cgiShowIPPError(_("Unable to get printer attributes:"));
2866 cgiCopyTemplateLang("users.tmpl");
2873 * Save the changes...
2876 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2879 * Skip whitespace and commas...
2882 while (*ptr
== ',' || isspace(*ptr
& 255))
2888 if (*ptr
== '\'' || *ptr
== '\"')
2891 * Scan quoted name...
2896 for (end
= ptr
; *end
; end
++)
2903 * Scan space or comma-delimited name...
2906 for (end
= ptr
; *end
; end
++)
2907 if (isspace(*end
& 255) || *end
== ',')
2912 * Advance to the next name...
2919 * Build a CUPS-Add-Printer/Class request, which requires the following
2922 * attributes-charset
2923 * attributes-natural-language
2925 * requesting-user-name-{allowed,denied}
2928 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2930 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2931 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2933 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2937 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2938 "requesting-user-name-allowed", NULL
, "all");
2941 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2942 type
, num_users
, NULL
, NULL
);
2944 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2947 * Skip whitespace and commas...
2950 while (*ptr
== ',' || isspace(*ptr
& 255))
2956 if (*ptr
== '\'' || *ptr
== '\"')
2959 * Scan quoted name...
2964 for (end
= ptr
; *end
; end
++)
2971 * Scan space or comma-delimited name...
2974 for (end
= ptr
; *end
; end
++)
2975 if (isspace(*end
& 255) || *end
== ',')
2980 * Terminate the name...
2990 attr
->values
[i
].string
.text
= strdup(ptr
);
2993 * Advance to the next name...
3001 * Do the request and get back a response...
3004 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3006 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3008 puts("Status: 401\n");
3011 else if (cupsLastError() > IPP_OK_CONFLICT
)
3013 cgiStartHTML(cgiText(_("Set Allowed Users")));
3014 cgiShowIPPError(_("Unable to change printer:"));
3019 * Redirect successful updates back to the printer page...
3022 char url
[1024], /* Printer/class URL */
3023 refresh
[1024]; /* Refresh URL */
3026 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3027 cgiFormEncode(uri
, url
, sizeof(uri
));
3028 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
3030 cgiSetVariable("refresh_page", refresh
);
3032 cgiStartHTML(cgiText(_("Set Allowed Users")));
3034 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3035 "printer-modified.tmpl");
3044 * 'do_set_default()' - Set the server default printer/class.
3048 do_set_default(http_t
*http
) /* I - HTTP connection */
3050 const char *title
; /* Page title */
3051 ipp_t
*request
; /* IPP request */
3052 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3053 const char *printer
, /* Printer name (purge-jobs) */
3054 *is_class
; /* Is a class? */
3057 is_class
= cgiGetVariable("IS_CLASS");
3058 printer
= cgiGetVariable("PRINTER_NAME");
3059 title
= cgiText(_("Set As Server Default"));
3063 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3064 cgiStartHTML(title
);
3065 cgiCopyTemplateLang("error.tmpl");
3071 * Build a printer request, which requires the following
3074 * attributes-charset
3075 * attributes-natural-language
3079 request
= ippNewRequest(CUPS_SET_DEFAULT
);
3081 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3082 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3084 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3088 * Do the request and get back a response...
3091 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3093 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3095 puts("Status: 401\n");
3098 else if (cupsLastError() > IPP_OK_CONFLICT
)
3100 cgiStartHTML(title
);
3101 cgiShowIPPError(_("Unable to set server default:"));
3106 * Redirect successful updates back to the printer page...
3109 char url
[1024], /* Printer/class URL */
3110 refresh
[1024]; /* Refresh URL */
3113 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3114 cgiFormEncode(uri
, url
, sizeof(uri
));
3115 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3116 cgiSetVariable("refresh_page", refresh
);
3118 cgiStartHTML(title
);
3119 cgiCopyTemplateLang("printer-default.tmpl");
3127 * 'do_set_options()' - Configure the default options for a queue.
3131 do_set_options(http_t
*http
, /* I - HTTP connection */
3132 int is_class
) /* I - Set options for class? */
3134 int i
, j
, k
, m
; /* Looping vars */
3135 int have_options
; /* Have options? */
3136 ipp_t
*request
, /* IPP request */
3137 *response
; /* IPP response */
3138 ipp_attribute_t
*attr
; /* IPP attribute */
3139 char uri
[HTTP_MAX_URI
]; /* Job URI */
3140 const char *var
; /* Variable value */
3141 const char *printer
; /* Printer printer name */
3142 const char *filename
; /* PPD filename */
3143 char tempfile
[1024]; /* Temporary filename */
3144 cups_file_t
*in
, /* Input file */
3145 *out
; /* Output file */
3146 char line
[1024], /* Line from PPD file */
3147 value
[1024], /* Option value */
3148 keyword
[1024], /* Keyword from Default line */
3149 *keyptr
; /* Pointer into keyword... */
3150 ppd_file_t
*ppd
; /* PPD file */
3151 ppd_group_t
*group
; /* Option group */
3152 ppd_option_t
*option
; /* Option */
3153 ppd_coption_t
*coption
; /* Custom option */
3154 ppd_cparam_t
*cparam
; /* Custom parameter */
3155 ppd_attr_t
*ppdattr
; /* PPD attribute */
3156 const char *title
; /* Page title */
3159 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
3161 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
3165 * Get the printer name...
3168 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
3169 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3170 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3174 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3175 cgiStartHTML(title
);
3176 cgiCopyTemplateLang("error.tmpl");
3181 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
3184 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3185 * command file to the printer...
3188 if (cgiGetVariable("AUTOCONFIGURE"))
3190 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
3195 * Get the PPD file...
3201 filename
= cupsGetPPD2(http
, printer
);
3205 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
3207 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
3209 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
3210 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3211 cgiStartHTML(title
);
3212 cgiCopyTemplateLang("error.tmpl");
3219 fputs("DEBUG: No PPD file\n", stderr
);
3223 if (cgiGetVariable("job_sheets_start") != NULL
||
3224 cgiGetVariable("job_sheets_end") != NULL
)
3231 ppdMarkDefaults(ppd
);
3233 for (option
= ppdFirstOption(ppd
);
3235 option
= ppdNextOption(ppd
))
3236 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
3239 ppdMarkOption(ppd
, option
->keyword
, var
);
3243 if (!have_options
|| ppdConflicts(ppd
))
3246 * Show the options to the user...
3249 fputs("DEBUG: Showing options...\n", stderr
);
3252 * Show auto-configure button if supported...
3257 if (ppd
->num_filters
== 0 ||
3258 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
3259 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
3260 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3263 for (i
= 0; i
< ppd
->num_filters
; i
++)
3264 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
3266 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3273 * Get the printer attributes...
3276 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3278 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3279 "localhost", 0, "/printers/%s", printer
);
3280 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3283 response
= cupsDoRequest(http
, request
, "/");
3286 * List the groups used as "tabs"...
3293 for (group
= ppd
->groups
;
3294 i
< ppd
->num_groups
;
3297 cgiSetArray("GROUP_ID", i
, group
->name
);
3299 if (!strcmp(group
->name
, "InstallableOptions"))
3300 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
3302 cgiSetArray("GROUP", i
, group
->text
);
3306 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
3308 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
3309 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
3312 if (ippFindAttribute(response
, "printer-error-policy-supported",
3314 ippFindAttribute(response
, "printer-op-policy-supported",
3317 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
3318 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3321 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3322 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3324 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3325 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3328 cgiStartHTML(cgiText(_("Set Printer Options")));
3329 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3335 if (ppdConflicts(ppd
))
3337 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3340 for (j
= group
->num_options
, option
= group
->options
;
3343 if (option
->conflicted
)
3345 cgiSetArray("ckeyword", k
, option
->keyword
);
3346 cgiSetArray("ckeytext", k
, option
->text
);
3350 cgiCopyTemplateLang("option-conflict.tmpl");
3353 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3357 cgiSetVariable("GROUP_ID", group
->name
);
3359 if (!strcmp(group
->name
, "InstallableOptions"))
3360 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3362 cgiSetVariable("GROUP", group
->text
);
3364 cgiCopyTemplateLang("option-header.tmpl");
3366 for (j
= group
->num_options
, option
= group
->options
;
3370 if (!strcmp(option
->keyword
, "PageRegion"))
3373 cgiSetVariable("KEYWORD", option
->keyword
);
3374 cgiSetVariable("KEYTEXT", option
->text
);
3376 if (option
->conflicted
)
3377 cgiSetVariable("CONFLICTED", "1");
3379 cgiSetVariable("CONFLICTED", "0");
3381 cgiSetSize("CHOICES", 0);
3382 cgiSetSize("TEXT", 0);
3383 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3385 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3386 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3390 if (option
->choices
[k
].marked
)
3391 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3394 cgiSetSize("PARAMS", 0);
3395 cgiSetSize("PARAMTEXT", 0);
3396 cgiSetSize("PARAMVALUE", 0);
3397 cgiSetSize("INPUTTYPE", 0);
3399 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3401 const char *units
= NULL
; /* Units value, if any */
3404 cgiSetVariable("ISCUSTOM", "1");
3406 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3408 cparam
= ppdNextCustomParam(coption
), m
++)
3410 if (!strcasecmp(option
->keyword
, "PageSize") &&
3411 strcasecmp(cparam
->name
, "Width") &&
3412 strcasecmp(cparam
->name
, "Height"))
3418 cgiSetArray("PARAMS", m
, cparam
->name
);
3419 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3420 cgiSetArray("INPUTTYPE", m
, "text");
3422 switch (cparam
->type
)
3424 case PPD_CUSTOM_POINTS
:
3425 if (!strncasecmp(option
->defchoice
, "Custom.", 7))
3427 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3429 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3430 strcmp(units
, "in") && strcmp(units
, "ft"))
3432 if (units
[1] == 'm')
3441 if (!strcmp(units
, "mm"))
3442 snprintf(value
, sizeof(value
), "%g",
3443 cparam
->current
.custom_points
/ 72.0 * 25.4);
3444 else if (!strcmp(units
, "cm"))
3445 snprintf(value
, sizeof(value
), "%g",
3446 cparam
->current
.custom_points
/ 72.0 * 2.54);
3447 else if (!strcmp(units
, "in"))
3448 snprintf(value
, sizeof(value
), "%g",
3449 cparam
->current
.custom_points
/ 72.0);
3450 else if (!strcmp(units
, "ft"))
3451 snprintf(value
, sizeof(value
), "%g",
3452 cparam
->current
.custom_points
/ 72.0 / 12.0);
3453 else if (!strcmp(units
, "m"))
3454 snprintf(value
, sizeof(value
), "%g",
3455 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3457 snprintf(value
, sizeof(value
), "%g",
3458 cparam
->current
.custom_points
);
3459 cgiSetArray("PARAMVALUE", m
, value
);
3462 case PPD_CUSTOM_CURVE
:
3463 case PPD_CUSTOM_INVCURVE
:
3464 case PPD_CUSTOM_REAL
:
3465 snprintf(value
, sizeof(value
), "%g",
3466 cparam
->current
.custom_real
);
3467 cgiSetArray("PARAMVALUE", m
, value
);
3470 case PPD_CUSTOM_INT
:
3471 snprintf(value
, sizeof(value
), "%d",
3472 cparam
->current
.custom_int
);
3473 cgiSetArray("PARAMVALUE", m
, value
);
3476 case PPD_CUSTOM_PASSCODE
:
3477 case PPD_CUSTOM_PASSWORD
:
3478 if (cparam
->current
.custom_password
)
3479 cgiSetArray("PARAMVALUE", m
,
3480 cparam
->current
.custom_password
);
3482 cgiSetArray("PARAMVALUE", m
, "");
3483 cgiSetArray("INPUTTYPE", m
, "password");
3486 case PPD_CUSTOM_STRING
:
3487 if (cparam
->current
.custom_string
)
3488 cgiSetArray("PARAMVALUE", m
,
3489 cparam
->current
.custom_string
);
3491 cgiSetArray("PARAMVALUE", m
, "");
3498 cgiSetArray("PARAMS", m
, "Units");
3499 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3500 cgiSetArray("PARAMVALUE", m
, units
);
3504 cgiSetVariable("ISCUSTOM", "0");
3508 case PPD_UI_BOOLEAN
:
3509 cgiCopyTemplateLang("option-boolean.tmpl");
3511 case PPD_UI_PICKONE
:
3512 cgiCopyTemplateLang("option-pickone.tmpl");
3514 case PPD_UI_PICKMANY
:
3515 cgiCopyTemplateLang("option-pickmany.tmpl");
3520 cgiCopyTemplateLang("option-trailer.tmpl");
3524 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3525 IPP_TAG_ZERO
)) != NULL
)
3528 * Add the job sheets options...
3531 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3532 cgiSetVariable("GROUP", cgiText(_("Banners")));
3533 cgiCopyTemplateLang("option-header.tmpl");
3535 cgiSetSize("CHOICES", attr
->num_values
);
3536 cgiSetSize("TEXT", attr
->num_values
);
3537 for (k
= 0; k
< attr
->num_values
; k
++)
3539 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3540 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3543 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3545 cgiSetVariable("KEYWORD", "job_sheets_start");
3546 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3547 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3548 attr
->values
[0].string
.text
: "");
3550 cgiCopyTemplateLang("option-pickone.tmpl");
3552 cgiSetVariable("KEYWORD", "job_sheets_end");
3553 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3554 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3555 attr
->values
[1].string
.text
: "");
3557 cgiCopyTemplateLang("option-pickone.tmpl");
3559 cgiCopyTemplateLang("option-trailer.tmpl");
3562 if (ippFindAttribute(response
, "printer-error-policy-supported",
3564 ippFindAttribute(response
, "printer-op-policy-supported",
3568 * Add the error and operation policy options...
3571 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3572 cgiSetVariable("GROUP", cgiText(_("Policies")));
3573 cgiCopyTemplateLang("option-header.tmpl");
3579 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3584 cgiSetSize("CHOICES", attr
->num_values
);
3585 cgiSetSize("TEXT", attr
->num_values
);
3586 for (k
= 0; k
< attr
->num_values
; k
++)
3588 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3589 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3592 attr
= ippFindAttribute(response
, "printer-error-policy",
3595 cgiSetVariable("KEYWORD", "printer_error_policy");
3596 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3597 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3598 "" : attr
->values
[0].string
.text
);
3601 cgiCopyTemplateLang("option-pickone.tmpl");
3604 * Operation policy...
3607 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3612 cgiSetSize("CHOICES", attr
->num_values
);
3613 cgiSetSize("TEXT", attr
->num_values
);
3614 for (k
= 0; k
< attr
->num_values
; k
++)
3616 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3617 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3620 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3622 cgiSetVariable("KEYWORD", "printer_op_policy");
3623 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3624 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3625 "" : attr
->values
[0].string
.text
);
3627 cgiCopyTemplateLang("option-pickone.tmpl");
3630 cgiCopyTemplateLang("option-trailer.tmpl");
3634 * Binary protocol support...
3637 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3638 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3640 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3641 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3643 cgiSetSize("CHOICES", attr
->num_values
);
3644 cgiSetSize("TEXT", attr
->num_values
);
3646 for (i
= 0; i
< attr
->num_values
; i
++)
3648 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3649 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3652 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3653 cgiSetVariable("KEYWORD", "port_monitor");
3654 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3655 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3657 cgiCopyTemplateLang("option-header.tmpl");
3658 cgiCopyTemplateLang("option-pickone.tmpl");
3659 cgiCopyTemplateLang("option-trailer.tmpl");
3662 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3665 ippDelete(response
);
3670 * Set default options...
3673 fputs("DEBUG: Setting options...\n", stderr
);
3677 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3678 in
= cupsFileOpen(filename
, "r");
3682 cgiSetVariable("ERROR", strerror(errno
));
3683 cgiStartHTML(cgiText(_("Set Printer Options")));
3684 cgiCopyTemplateLang("error.tmpl");
3700 while (cupsFileGets(in
, line
, sizeof(line
)))
3702 if (!strncmp(line
, "*cupsProtocol:", 14))
3704 else if (strncmp(line
, "*Default", 8))
3705 cupsFilePrintf(out
, "%s\n", line
);
3709 * Get default option name...
3712 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3714 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3715 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3720 if (!strcmp(keyword
, "PageRegion") ||
3721 !strcmp(keyword
, "PaperDimension") ||
3722 !strcmp(keyword
, "ImageableArea"))
3723 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3725 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3728 cupsFilePrintf(out
, "%s\n", line
);
3730 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3740 * Make sure temporary filename is cleared when there is no PPD...
3747 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3748 * following attributes:
3750 * attributes-charset
3751 * attributes-natural-language
3753 * job-sheets-default
3754 * printer-error-policy
3759 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3760 CUPS_ADD_MODIFY_PRINTER
);
3762 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3765 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3766 "job-sheets-default", 2, NULL
, NULL
);
3767 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3768 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3770 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3771 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3772 "printer-error-policy", NULL
, var
);
3774 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3775 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3776 "printer-op-policy", NULL
, var
);
3778 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3779 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3780 "port-monitor", NULL
, var
);
3783 * Do the request and get back a response...
3787 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3789 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3791 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3793 puts("Status: 401\n");
3796 else if (cupsLastError() > IPP_OK_CONFLICT
)
3798 cgiStartHTML(title
);
3799 cgiShowIPPError(_("Unable to set options:"));
3804 * Redirect successful updates back to the printer page...
3807 char refresh
[1024]; /* Refresh URL */
3810 cgiFormEncode(uri
, printer
, sizeof(uri
));
3811 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3812 is_class
? "classes" : "printers", uri
);
3813 cgiSetVariable("refresh_page", refresh
);
3815 cgiStartHTML(title
);
3817 cgiCopyTemplateLang("printer-configured.tmpl");
3832 * 'do_set_sharing()' - Set printer-is-shared value.
3836 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3838 ipp_t
*request
, /* IPP request */
3839 *response
; /* IPP response */
3840 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3841 const char *printer
, /* Printer name */
3842 *is_class
, /* Is a class? */
3843 *shared
; /* Sharing value */
3846 is_class
= cgiGetVariable("IS_CLASS");
3847 printer
= cgiGetVariable("PRINTER_NAME");
3848 shared
= cgiGetVariable("SHARED");
3850 if (!printer
|| !shared
)
3852 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3853 cgiStartHTML(cgiText(_("Set Publishing")));
3854 cgiCopyTemplateLang("error.tmpl");
3860 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3861 * following attributes:
3863 * attributes-charset
3864 * attributes-natural-language
3869 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3871 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3872 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3874 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3877 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3880 * Do the request and get back a response...
3883 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3885 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3887 ippDelete(response
);
3890 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3892 puts("Status: 401\n");
3895 else if (cupsLastError() > IPP_OK_CONFLICT
)
3897 cgiStartHTML(cgiText(_("Set Publishing")));
3898 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3903 * Redirect successful updates back to the printer page...
3906 char url
[1024], /* Printer/class URL */
3907 refresh
[1024]; /* Refresh URL */
3910 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3911 cgiFormEncode(uri
, url
, sizeof(uri
));
3912 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3913 cgiSetVariable("refresh_page", refresh
);
3915 cgiStartHTML(cgiText(_("Set Publishing")));
3916 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3917 "printer-modified.tmpl");
3925 * 'get_option_value()' - Return the value of an option.
3927 * This function also handles generation of custom option values.
3930 static char * /* O - Value string or NULL on error */
3932 ppd_file_t
*ppd
, /* I - PPD file */
3933 const char *name
, /* I - Option name */
3934 char *buffer
, /* I - String buffer */
3935 size_t bufsize
) /* I - Size of buffer */
3937 char *bufptr
, /* Pointer into buffer */
3938 *bufend
; /* End of buffer */
3939 ppd_coption_t
*coption
; /* Custom option */
3940 ppd_cparam_t
*cparam
; /* Current custom parameter */
3941 char keyword
[256]; /* Parameter name */
3942 const char *val
, /* Parameter value */
3943 *uval
; /* Units value */
3944 long integer
; /* Integer value */
3945 double number
, /* Number value */
3946 number_points
; /* Number in points */
3950 * See if we have a custom option choice...
3953 if ((val
= cgiGetVariable(name
)) == NULL
)
3961 else if (strcasecmp(val
, "Custom") ||
3962 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3965 * Not a custom choice...
3968 strlcpy(buffer
, val
, bufsize
);
3973 * OK, we have a custom option choice, format it...
3978 if (!strcmp(coption
->keyword
, "PageSize"))
3980 const char *lval
; /* Length string value */
3981 double width
, /* Width value */
3982 width_points
, /* Width in points */
3983 length
, /* Length value */
3984 length_points
; /* Length in points */
3987 val
= cgiGetVariable("PageSize.Width");
3988 lval
= cgiGetVariable("PageSize.Height");
3989 uval
= cgiGetVariable("PageSize.Units");
3991 if (!val
|| !lval
|| !uval
||
3992 (width
= strtod(val
, NULL
)) == 0.0 ||
3993 (length
= strtod(lval
, NULL
)) == 0.0 ||
3994 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3995 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3998 width_points
= get_points(width
, uval
);
3999 length_points
= get_points(length
, uval
);
4001 if (width_points
< ppd
->custom_min
[0] ||
4002 width_points
> ppd
->custom_max
[0] ||
4003 length_points
< ppd
->custom_min
[1] ||
4004 length_points
> ppd
->custom_max
[1])
4007 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
4009 else if (cupsArrayCount(coption
->params
) == 1)
4011 cparam
= ppdFirstCustomParam(coption
);
4012 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
4014 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4017 switch (cparam
->type
)
4019 case PPD_CUSTOM_CURVE
:
4020 case PPD_CUSTOM_INVCURVE
:
4021 case PPD_CUSTOM_REAL
:
4022 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4023 number
< cparam
->minimum
.custom_real
||
4024 number
> cparam
->maximum
.custom_real
)
4027 snprintf(buffer
, bufsize
, "Custom.%g", number
);
4030 case PPD_CUSTOM_INT
:
4031 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4032 integer
== LONG_MAX
||
4033 integer
< cparam
->minimum
.custom_int
||
4034 integer
> cparam
->maximum
.custom_int
)
4037 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
4040 case PPD_CUSTOM_POINTS
:
4041 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4043 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4044 (uval
= cgiGetVariable(keyword
)) == NULL
||
4045 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4046 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4049 number_points
= get_points(number
, uval
);
4050 if (number_points
< cparam
->minimum
.custom_points
||
4051 number_points
> cparam
->maximum
.custom_points
)
4054 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
4057 case PPD_CUSTOM_PASSCODE
:
4058 for (uval
= val
; *uval
; uval
++)
4059 if (!isdigit(*uval
& 255))
4062 case PPD_CUSTOM_PASSWORD
:
4063 case PPD_CUSTOM_STRING
:
4064 integer
= (long)strlen(val
);
4065 if (integer
< cparam
->minimum
.custom_string
||
4066 integer
> cparam
->maximum
.custom_string
)
4069 snprintf(buffer
, bufsize
, "Custom.%s", val
);
4075 const char *prefix
= "{"; /* Prefix string */
4079 bufend
= buffer
+ bufsize
;
4081 for (cparam
= ppdFirstCustomParam(coption
);
4083 cparam
= ppdNextCustomParam(coption
))
4085 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
4088 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4091 snprintf(bufptr
, bufend
- bufptr
, "%s%s=", prefix
, cparam
->name
);
4092 bufptr
+= strlen(bufptr
);
4095 switch (cparam
->type
)
4097 case PPD_CUSTOM_CURVE
:
4098 case PPD_CUSTOM_INVCURVE
:
4099 case PPD_CUSTOM_REAL
:
4100 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4101 number
< cparam
->minimum
.custom_real
||
4102 number
> cparam
->maximum
.custom_real
)
4105 snprintf(bufptr
, bufend
- bufptr
, "%g", number
);
4108 case PPD_CUSTOM_INT
:
4109 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4110 integer
== LONG_MAX
||
4111 integer
< cparam
->minimum
.custom_int
||
4112 integer
> cparam
->maximum
.custom_int
)
4115 snprintf(bufptr
, bufend
- bufptr
, "%ld", integer
);
4118 case PPD_CUSTOM_POINTS
:
4119 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4121 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4122 (uval
= cgiGetVariable(keyword
)) == NULL
||
4123 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
4124 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
4125 strcmp(uval
, "mm") && strcmp(uval
, "m")))
4128 number_points
= get_points(number
, uval
);
4129 if (number_points
< cparam
->minimum
.custom_points
||
4130 number_points
> cparam
->maximum
.custom_points
)
4133 snprintf(bufptr
, bufend
- bufptr
, "%g%s", number
, uval
);
4136 case PPD_CUSTOM_PASSCODE
:
4137 for (uval
= val
; *uval
; uval
++)
4138 if (!isdigit(*uval
& 255))
4141 case PPD_CUSTOM_PASSWORD
:
4142 case PPD_CUSTOM_STRING
:
4143 integer
= (long)strlen(val
);
4144 if (integer
< cparam
->minimum
.custom_string
||
4145 integer
> cparam
->maximum
.custom_string
)
4148 if ((bufptr
+ 2) > bufend
)
4154 while (*val
&& bufptr
< bufend
)
4156 if (*val
== '\\' || *val
== '\"')
4158 if ((bufptr
+ 1) >= bufend
)
4167 if (bufptr
>= bufend
)
4176 bufptr
+= strlen(bufptr
);
4179 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
4182 strcpy(bufptr
, "}");
4190 * 'get_points()' - Get a value in points.
4193 static double /* O - Number in points */
4194 get_points(double number
, /* I - Original number */
4195 const char *uval
) /* I - Units */
4197 if (!strcmp(uval
, "mm")) /* Millimeters */
4198 return (number
* 72.0 / 25.4);
4199 else if (!strcmp(uval
, "cm")) /* Centimeters */
4200 return (number
* 72.0 / 2.54);
4201 else if (!strcmp(uval
, "in")) /* Inches */
4202 return (number
* 72.0);
4203 else if (!strcmp(uval
, "ft")) /* Feet */
4204 return (number
* 72.0 * 12.0);
4205 else if (!strcmp(uval
, "m")) /* Meters */
4206 return (number
* 72.0 / 0.0254);
4213 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".