2 * "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $"
4 * Administration CGI for CUPS.
6 * Copyright 2007-2011 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>
55 static int current_device
= 0; /* Current device shown */
62 static void choose_device_cb(const char *device_class
,
63 const char *device_id
, const char *device_info
,
64 const char *device_make_and_model
,
65 const char *device_uri
,
66 const char *device_location
,
68 static void do_add_rss_subscription(http_t
*http
);
69 static void do_am_class(http_t
*http
, int modify
);
70 static void do_am_printer(http_t
*http
, int modify
);
71 static void do_cancel_subscription(http_t
*http
);
72 static void do_config_server(http_t
*http
);
73 static void do_delete_class(http_t
*http
);
74 static void do_delete_printer(http_t
*http
);
75 static void do_export(http_t
*http
);
76 static void do_list_printers(http_t
*http
);
77 static void do_menu(http_t
*http
);
78 static void do_set_allowed_users(http_t
*http
);
79 static void do_set_default(http_t
*http
);
80 static void do_set_options(http_t
*http
, int is_class
);
81 static void do_set_sharing(http_t
*http
);
82 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
83 char *buffer
, size_t bufsize
);
84 static double get_points(double number
, const char *uval
);
88 * 'main()' - Main entry for CGI.
91 int /* O - Exit status */
92 main(int argc
, /* I - Number of command-line arguments */
93 char *argv
[]) /* I - Command-line arguments */
95 http_t
*http
; /* Connection to the server */
96 const char *op
; /* Operation name */
100 * Connect to the HTTP server...
103 fputs("DEBUG: admin.cgi started...\n", stderr
);
105 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
109 perror("ERROR: Unable to connect to cupsd");
110 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
111 cupsServer() ? cupsServer() : "(null)");
112 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
113 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
117 fprintf(stderr
, "DEBUG: http=%p\n", http
);
120 * Set the web interface section...
123 cgiSetVariable("SECTION", "admin");
124 cgiSetVariable("REFRESH_PAGE", "");
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
);
150 const char *printer
= getenv("PRINTER_NAME"),
151 /* Printer or class name */
152 *server_port
= getenv("SERVER_PORT");
153 /* Port number string */
154 int port
= atoi(server_port
? server_port
: "0");
156 char uri
[1024]; /* URL */
159 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
160 getenv("HTTPS") ? "https" : "http", NULL
,
161 getenv("SERVER_NAME"), port
, "/%s/%s",
162 cgiGetVariable("IS_CLASS") ? "classes" : "printers",
165 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
166 getenv("HTTPS") ? "https" : "http", NULL
,
167 getenv("SERVER_NAME"), port
, "/admin");
169 printf("Location: %s\n\n", uri
);
171 else if (!strcmp(op
, "set-allowed-users"))
172 do_set_allowed_users(http
);
173 else if (!strcmp(op
, "set-as-default"))
174 do_set_default(http
);
175 else if (!strcmp(op
, "set-sharing"))
176 do_set_sharing(http
);
177 else if (!strcmp(op
, "find-new-printers") ||
178 !strcmp(op
, "list-available-printers"))
179 do_list_printers(http
);
180 else if (!strcmp(op
, "add-class"))
181 do_am_class(http
, 0);
182 else if (!strcmp(op
, "add-printer"))
183 do_am_printer(http
, 0);
184 else if (!strcmp(op
, "modify-class"))
185 do_am_class(http
, 1);
186 else if (!strcmp(op
, "modify-printer"))
187 do_am_printer(http
, 1);
188 else if (!strcmp(op
, "delete-class"))
189 do_delete_class(http
);
190 else if (!strcmp(op
, "delete-printer"))
191 do_delete_printer(http
);
192 else if (!strcmp(op
, "set-class-options"))
193 do_set_options(http
, 1);
194 else if (!strcmp(op
, "set-printer-options"))
195 do_set_options(http
, 0);
196 else if (!strcmp(op
, "config-server"))
197 do_config_server(http
);
198 else if (!strcmp(op
, "export-samba"))
200 else if (!strcmp(op
, "add-rss-subscription"))
201 do_add_rss_subscription(http
);
202 else if (!strcmp(op
, "cancel-subscription"))
203 do_cancel_subscription(http
);
207 * Bad operation code - display an error...
210 cgiStartHTML(cgiText(_("Administration")));
211 cgiCopyTemplateLang("error-op.tmpl");
215 else if (op
&& !strcmp(op
, "redirect"))
217 const char *url
; /* Redirection URL... */
218 char prefix
[1024]; /* URL prefix */
222 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
223 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
225 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
226 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
228 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
230 if ((url
= cgiGetVariable("URL")) != NULL
)
232 char encoded
[1024], /* Encoded URL string */
233 *ptr
; /* Pointer into encoded string */
240 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
242 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
245 * Percent-encode this character; safe because we have at least 4
246 * bytes left in the array...
249 sprintf(ptr
, "%%%02X", *url
& 255);
261 * URL was too long, just redirect to the admin page...
264 printf("Location: %s/admin\n\n", prefix
);
269 * URL is OK, redirect there...
272 printf("Location: %s%s\n\n", prefix
, encoded
);
276 printf("Location: %s/admin\n\n", prefix
);
281 * Form data but no operation code - display an error...
284 cgiStartHTML(cgiText(_("Administration")));
285 cgiCopyTemplateLang("error-op.tmpl");
290 * Close the HTTP server connection...
296 * Return with no errors...
304 * 'choose_device_cb()' - Add a device to the device selection page.
309 const char *device_class
, /* I - Class */
310 const char *device_id
, /* I - 1284 device ID */
311 const char *device_info
, /* I - Description */
312 const char *device_make_and_model
, /* I - Make and model */
313 const char *device_uri
, /* I - Device URI */
314 const char *device_location
, /* I - Location */
315 const char *title
) /* I - Page title */
318 * For modern browsers, start a multi-part page so we can show that something
319 * is happening. Non-modern browsers just get everything at the end...
322 if (current_device
== 0 && cgiSupportsMultipart())
326 cgiCopyTemplateLang("choose-device.tmpl");
333 * Add the device to the array...
336 cgiSetArray("device_class", current_device
, device_class
);
337 cgiSetArray("device_id", current_device
, device_id
);
338 cgiSetArray("device_info", current_device
, device_info
);
339 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
340 cgiSetArray("device_uri", current_device
, device_uri
);
341 cgiSetArray("device_location", current_device
, device_location
);
348 * 'do_add_rss_subscription()' - Add a RSS subscription.
352 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
354 ipp_t
*request
, /* IPP request data */
355 *response
; /* IPP response data */
356 char rss_uri
[1024]; /* RSS notify-recipient URI */
357 int num_events
; /* Number of events */
358 const char *events
[12], /* Subscribed events */
359 *subscription_name
, /* Subscription name */
360 *printer_uri
, /* Printer URI */
361 *ptr
, /* Pointer into name */
362 *user
; /* Username */
363 int max_events
; /* Maximum number of events */
367 * See if we have all of the required information...
370 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
371 printer_uri
= cgiGetVariable("PRINTER_URI");
374 if (cgiGetVariable("EVENT_JOB_CREATED"))
375 events
[num_events
++] = "job-created";
376 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
377 events
[num_events
++] = "job-completed";
378 if (cgiGetVariable("EVENT_JOB_STOPPED"))
379 events
[num_events
++] = "job-stopped";
380 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
381 events
[num_events
++] = "job-config-changed";
382 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
383 events
[num_events
++] = "printer-stopped";
384 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
385 events
[num_events
++] = "printer-added";
386 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
387 events
[num_events
++] = "printer-modified";
388 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
389 events
[num_events
++] = "printer-deleted";
390 if (cgiGetVariable("EVENT_SERVER_STARTED"))
391 events
[num_events
++] = "server-started";
392 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
393 events
[num_events
++] = "server-stopped";
394 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
395 events
[num_events
++] = "server-restarted";
396 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
397 events
[num_events
++] = "server-audit";
399 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
400 max_events
= atoi(ptr
);
404 if (!subscription_name
|| !printer_uri
|| !num_events
||
405 max_events
<= 0 || max_events
> 9999)
408 * Don't have everything we need, so get the available printers
409 * and classes and (re)show the add page...
412 if (cgiGetVariable("EVENT_JOB_CREATED"))
413 cgiSetVariable("EVENT_JOB_CREATED", "CHECKED");
414 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
415 cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED");
416 if (cgiGetVariable("EVENT_JOB_STOPPED"))
417 cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED");
418 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
419 cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED");
420 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
421 cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED");
422 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
423 cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED");
424 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
425 cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED");
426 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
427 cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED");
428 if (cgiGetVariable("EVENT_SERVER_STARTED"))
429 cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED");
430 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
431 cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED");
432 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
433 cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED");
434 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
435 cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED");
437 request
= ippNewRequest(CUPS_GET_PRINTERS
);
438 response
= cupsDoRequest(http
, request
, "/");
440 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
444 cgiStartHTML(cgiText(_("Add RSS Subscription")));
446 cgiCopyTemplateLang("add-rss-subscription.tmpl");
453 * Make sure we have a username...
456 if ((user
= getenv("REMOTE_USER")) == NULL
)
458 puts("Status: 401\n");
463 * Validate the subscription name...
466 for (ptr
= subscription_name
; *ptr
; ptr
++)
467 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
468 *ptr
== '?' || *ptr
== '#')
473 cgiSetVariable("ERROR",
474 cgiText(_("The subscription name may not "
475 "contain spaces, slashes (/), question marks (?), "
476 "or the pound sign (#).")));
477 cgiStartHTML(_("Add RSS Subscription"));
478 cgiCopyTemplateLang("error.tmpl");
484 * Add the subscription...
487 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
488 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
489 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
490 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
493 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
494 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
497 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
499 if (!strcasecmp(printer_uri
, "#ALL#"))
500 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
501 NULL
, "ipp://localhost/");
503 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
506 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
509 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
510 "notify-recipient-uri", NULL
, rss_uri
);
511 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
512 num_events
, NULL
, events
);
513 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
514 "notify-lease-duration", 0);
516 ippDelete(cupsDoRequest(http
, request
, "/"));
518 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
520 puts("Status: 401\n");
523 else if (cupsLastError() > IPP_OK_CONFLICT
)
525 cgiStartHTML(_("Add RSS Subscription"));
526 cgiShowIPPError(_("Unable to add RSS subscription:"));
531 * Redirect successful updates back to the admin page...
534 cgiSetVariable("refresh_page", "5;URL=/admin");
535 cgiStartHTML(_("Add RSS Subscription"));
536 cgiCopyTemplateLang("subscription-added.tmpl");
544 * 'do_am_class()' - Add or modify a class.
548 do_am_class(http_t
*http
, /* I - HTTP connection */
549 int modify
) /* I - Modify the printer? */
551 int i
, j
; /* Looping vars */
552 int element
; /* Element number */
553 int num_printers
; /* Number of printers */
554 ipp_t
*request
, /* IPP request */
555 *response
; /* IPP response */
556 ipp_attribute_t
*attr
; /* member-uris attribute */
557 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
558 const char *name
, /* Pointer to class name */
559 *op
, /* Operation name */
560 *ptr
; /* Pointer to CGI variable */
561 const char *title
; /* Title of page */
562 static const char * const pattrs
[] = /* Requested printer attributes */
570 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
571 op
= cgiGetVariable("OP");
572 name
= cgiGetVariable("PRINTER_NAME");
574 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
577 * Build a CUPS_GET_PRINTERS request, which requires the
578 * following attributes:
581 * attributes-natural-language
584 request
= ippNewRequest(CUPS_GET_PRINTERS
);
586 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
588 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
589 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
590 CUPS_PRINTER_IMPLICIT
);
593 * Do the request and get back a response...
598 cgiSetVariable("OP", op
);
600 cgiSetVariable("PRINTER_NAME", name
);
602 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
605 * Create MEMBER_URIS and MEMBER_NAMES arrays...
608 for (element
= 0, attr
= response
->attrs
;
611 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
613 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
614 (!name
|| strcasecmp(name
, ptr
+ 1)))
617 * Don't show the current class...
620 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
625 for (element
= 0, attr
= response
->attrs
;
628 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
630 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
633 * Don't show the current class...
636 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
641 num_printers
= cgiGetSize("MEMBER_URIS");
651 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
652 * following attributes:
655 * attributes-natural-language
659 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
661 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
662 "localhost", 0, "/classes/%s", name
);
663 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
666 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
667 "requested-attributes",
668 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
672 * Do the request and get back a response...
675 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
677 if ((attr
= ippFindAttribute(response
, "member-names",
678 IPP_TAG_NAME
)) != NULL
)
681 * Mark any current members in the class...
684 for (j
= 0; j
< num_printers
; j
++)
685 cgiSetArray("MEMBER_SELECTED", j
, "");
687 for (i
= 0; i
< attr
->num_values
; i
++)
689 for (j
= 0; j
< num_printers
; j
++)
691 if (!strcasecmp(attr
->values
[i
].string
.text
,
692 cgiGetArray("MEMBER_NAMES", j
)))
694 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
701 if ((attr
= ippFindAttribute(response
, "printer-info",
702 IPP_TAG_TEXT
)) != NULL
)
703 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
705 if ((attr
= ippFindAttribute(response
, "printer-location",
706 IPP_TAG_TEXT
)) != NULL
)
707 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
713 * Update the location and description of an existing printer...
717 cgiCopyTemplateLang("modify-class.tmpl");
722 * Get the name, location, and description for a new printer...
726 cgiCopyTemplateLang("add-class.tmpl");
737 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
738 cgiCopyTemplateLang("error.tmpl");
743 for (ptr
= name
; *ptr
; ptr
++)
744 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
747 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
749 cgiSetVariable("ERROR",
750 cgiText(_("The class name may only contain up to "
751 "127 printable characters and may not "
752 "contain spaces, slashes (/), or the "
753 "pound sign (#).")));
755 cgiCopyTemplateLang("error.tmpl");
761 * Build a CUPS_ADD_CLASS request, which requires the following
765 * attributes-natural-language
769 * printer-is-accepting-jobs
774 request
= ippNewRequest(CUPS_ADD_CLASS
);
776 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
777 "localhost", 0, "/classes/%s", name
);
778 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
781 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
782 NULL
, cgiGetVariable("PRINTER_LOCATION"));
784 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
785 NULL
, cgiGetVariable("PRINTER_INFO"));
787 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
789 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
792 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
794 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
795 num_printers
, NULL
, NULL
);
796 for (i
= 0; i
< num_printers
; i
++)
797 attr
->values
[i
].string
.text
= _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i
));
801 * Do the request and get back a response...
804 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
806 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
808 puts("Status: 401\n");
811 else if (cupsLastError() > IPP_OK_CONFLICT
)
814 cgiShowIPPError(modify
? _("Unable to modify class:") :
815 _("Unable to add class:"));
820 * Redirect successful updates back to the class page...
823 char refresh
[1024]; /* Refresh URL */
825 cgiFormEncode(uri
, name
, sizeof(uri
));
826 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
828 cgiSetVariable("refresh_page", refresh
);
833 cgiCopyTemplateLang("class-modified.tmpl");
835 cgiCopyTemplateLang("class-added.tmpl");
843 * 'do_am_printer()' - Add or modify a printer.
847 do_am_printer(http_t
*http
, /* I - HTTP connection */
848 int modify
) /* I - Modify the printer? */
850 int i
; /* Looping var */
851 ipp_attribute_t
*attr
; /* Current attribute */
852 ipp_t
*request
, /* IPP request */
853 *response
, /* IPP response */
854 *oldinfo
; /* Old printer information */
855 const cgi_file_t
*file
; /* Uploaded file, if any */
856 const char *var
; /* CGI variable */
857 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
858 *uriptr
; /* Pointer into URI */
859 int maxrate
; /* Maximum baud rate */
860 char baudrate
[255]; /* Baud rate string */
861 const char *name
, /* Pointer to class name */
862 *ptr
; /* Pointer to CGI variable */
863 const char *title
; /* Title of page */
864 static int baudrates
[] = /* Baud rates */
879 ptr
= cgiGetVariable("DEVICE_URI");
880 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
881 ptr
? ptr
: "(null)");
883 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
888 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
889 * following attributes:
892 * attributes-natural-language
896 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
898 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
899 "localhost", 0, "/printers/%s",
900 cgiGetVariable("PRINTER_NAME"));
901 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
905 * Do the request and get back a response...
908 oldinfo
= cupsDoRequest(http
, request
, "/");
917 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
918 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
919 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
920 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
923 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
925 for (ptr
= name
; *ptr
; ptr
++)
926 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
929 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
931 cgiSetVariable("ERROR",
932 cgiText(_("The printer name may only contain up to "
933 "127 printable characters and may not "
934 "contain spaces, slashes (/), or the "
935 "pound sign (#).")));
937 cgiCopyTemplateLang("error.tmpl");
943 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
945 if ((uriptr
= strrchr(var
, '|')) != NULL
)
948 * Extract make and make/model from device URI string...
951 char make
[1024], /* Make string */
952 *makeptr
; /* Pointer into make */
957 strlcpy(make
, uriptr
, sizeof(make
));
959 if ((makeptr
= strchr(make
, ' ')) != NULL
)
961 else if ((makeptr
= strchr(make
, '-')) != NULL
)
963 else if (!strncasecmp(make
, "laserjet", 8) ||
964 !strncasecmp(make
, "deskjet", 7) ||
965 !strncasecmp(make
, "designjet", 9))
967 else if (!strncasecmp(make
, "phaser", 6))
968 strcpy(make
, "Xerox");
969 else if (!strncasecmp(make
, "stylus", 6))
970 strcpy(make
, "Epson");
972 strcpy(make
, "Generic");
974 if (!cgiGetVariable("CURRENT_MAKE"))
975 cgiSetVariable("CURRENT_MAKE", make
);
977 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
978 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
982 char template[128], /* Template name */
983 *tptr
; /* Pointer into template name */
985 cgiSetVariable("PRINTER_INFO", uriptr
);
987 for (tptr
= template;
988 tptr
< (template + sizeof(template) - 1) && *uriptr
;
990 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
993 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
996 else if (*uriptr
== '?' || *uriptr
== '(')
1001 cgiSetVariable("TEMPLATE_NAME", template);
1009 * Look for devices so the user can pick something...
1012 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
1014 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
1015 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
1018 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
1019 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
1023 * Scan for devices for up to 30 seconds...
1026 fputs("DEBUG: Getting list of devices...\n", stderr
);
1029 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
1030 (cups_device_cb_t
)choose_device_cb
,
1031 (void *)title
) == IPP_OK
)
1033 fputs("DEBUG: Got device list!\n", stderr
);
1035 if (cgiSupportsMultipart())
1036 cgiStartMultipart();
1038 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1039 cgiStartHTML(title
);
1040 cgiCopyTemplateLang("choose-device.tmpl");
1043 if (cgiSupportsMultipart())
1049 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1050 cupsLastError(), cupsLastErrorString());
1051 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1053 puts("Status: 401\n");
1058 cgiStartHTML(title
);
1059 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1060 _("Unable to add printer:"));
1066 else if (!strchr(var
, '/') ||
1067 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
1069 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
1072 * Set the current device URI for the form to the old one...
1075 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
1076 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
1080 * User needs to set the full URI...
1083 cgiStartHTML(title
);
1084 cgiCopyTemplateLang("choose-uri.tmpl");
1087 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1090 * Need baud rate, parity, etc.
1093 if ((var
= strchr(var
, '?')) != NULL
&&
1094 strncmp(var
, "?baud=", 6) == 0)
1095 maxrate
= atoi(var
+ 6);
1099 for (i
= 0; i
< 10; i
++)
1100 if (baudrates
[i
] > maxrate
)
1104 sprintf(baudrate
, "%d", baudrates
[i
]);
1105 cgiSetArray("BAUDRATES", i
, baudrate
);
1108 cgiStartHTML(title
);
1109 cgiCopyTemplateLang("choose-serial.tmpl");
1112 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
1114 cgiStartHTML(title
);
1119 * Update the location and description of an existing printer...
1124 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
1125 IPP_TAG_TEXT
)) != NULL
)
1126 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
1128 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
1129 IPP_TAG_TEXT
)) != NULL
)
1130 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
1132 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
1133 IPP_TAG_BOOLEAN
)) != NULL
)
1134 cgiSetVariable("PRINTER_IS_SHARED",
1135 attr
->values
[0].boolean
? "1" : "0");
1138 cgiCopyTemplateLang("modify-printer.tmpl");
1143 * Get the name, location, and description for a new printer...
1147 if (!strncmp(var
, "usb:", 4))
1148 cgiSetVariable("printer_is_shared", "1");
1150 #endif /* __APPLE__ */
1151 cgiSetVariable("printer_is_shared", "0");
1153 cgiCopyTemplateLang("add-printer.tmpl");
1164 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1166 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
1169 * Get the PPD file...
1172 int fd
; /* PPD file */
1173 char filename
[1024]; /* PPD filename */
1174 ppd_file_t
*ppd
; /* PPD information */
1175 char buffer
[1024]; /* Buffer */
1176 int bytes
; /* Number of bytes */
1177 http_status_t get_status
; /* Status of GET */
1180 /* TODO: Use cupsGetFile() API... */
1181 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1183 if (httpGet(http
, uri
))
1186 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1188 if (get_status
!= HTTP_OK
)
1192 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1193 uri
, get_status
, httpStatus(get_status
));
1195 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1197 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1198 write(fd
, buffer
, bytes
);
1202 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1204 if (ppd
->manufacturer
)
1205 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1208 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1215 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1216 filename
, ppdErrorString(ppdLastError(&bytes
)));
1224 "ERROR: Unable to create temporary file for PPD file: %s\n",
1230 * Build a CUPS_GET_PPDS request, which requires the following
1233 * attributes-charset
1234 * attributes-natural-language
1238 request
= ippNewRequest(CUPS_GET_PPDS
);
1240 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1241 NULL
, "ipp://localhost/printers/");
1243 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1244 var
= cgiGetVariable("CURRENT_MAKE");
1245 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1247 const char *make_model
; /* Make and model */
1250 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1251 "ppd-make", NULL
, var
);
1253 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1254 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1255 "ppd-make-and-model", NULL
, make_model
);
1258 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1259 "requested-attributes", NULL
, "ppd-make");
1262 * Do the request and get back a response...
1265 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1268 * Got the list of PPDs, see if the user has selected a make...
1271 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1274 * No PPD files with this make, try again with all makes...
1277 ippDelete(response
);
1279 request
= ippNewRequest(CUPS_GET_PPDS
);
1281 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1282 NULL
, "ipp://localhost/printers/");
1284 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1285 "requested-attributes", NULL
, "ppd-make");
1287 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1288 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1290 cgiStartHTML(title
);
1291 cgiCopyTemplateLang("choose-make.tmpl");
1294 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1296 cgiStartHTML(title
);
1297 cgiCopyTemplateLang("choose-make.tmpl");
1303 * Let the user choose a model...
1306 cgiStartHTML(title
);
1307 if (!cgiGetVariable("PPD_MAKE"))
1308 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1310 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1311 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1312 cgiCopyTemplateLang("choose-model.tmpl");
1316 ippDelete(response
);
1320 cgiStartHTML(title
);
1321 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1322 cgiCopyTemplateLang("error.tmpl");
1329 * Build a CUPS_ADD_PRINTER request, which requires the following
1332 * attributes-charset
1333 * attributes-natural-language
1339 * printer-is-accepting-jobs
1344 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1346 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1347 "localhost", 0, "/printers/%s",
1348 cgiGetVariable("PRINTER_NAME"));
1349 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1352 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1353 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1355 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1356 NULL
, cgiGetVariable("PRINTER_INFO"));
1360 var
= cgiGetVariable("PPD_NAME");
1361 if (strcmp(var
, "__no_change__"))
1362 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1366 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1369 * Strip make and model from URI...
1372 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1375 if (!strncmp(uri
, "serial:", 7))
1378 * Update serial port URI to include baud rate, etc.
1381 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1382 uriptr
= uri
+ strlen(uri
);
1384 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1385 "?baud=%s+bits=%s+parity=%s+flow=%s",
1386 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1387 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1390 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1393 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1395 var
= cgiGetVariable("printer_is_shared");
1396 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1397 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1399 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1403 * Do the request and get back a response...
1407 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1409 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1411 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1413 puts("Status: 401\n");
1416 else if (cupsLastError() > IPP_OK_CONFLICT
)
1418 cgiStartHTML(title
);
1419 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1420 _("Unable to add printer:"));
1425 * Redirect successful updates back to the printer page...
1428 char refresh
[1024]; /* Refresh URL */
1431 cgiFormEncode(uri
, name
, sizeof(uri
));
1433 snprintf(refresh
, sizeof(refresh
),
1434 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1436 cgiSetVariable("refresh_page", refresh
);
1438 cgiStartHTML(title
);
1440 cgiCopyTemplateLang("printer-modified.tmpl");
1445 * Set the printer options...
1448 cgiSetVariable("OP", "set-printer-options");
1449 do_set_options(http
, 0);
1462 * 'do_cancel_subscription()' - Cancel a subscription.
1466 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1468 ipp_t
*request
; /* IPP request data */
1469 const char *var
, /* Form variable */
1470 *user
; /* Username */
1471 int id
; /* Subscription ID */
1475 * See if we have all of the required information...
1478 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1485 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1486 cgiStartHTML(_("Cancel RSS Subscription"));
1487 cgiCopyTemplateLang("error.tmpl");
1493 * Require a username...
1496 if ((user
= getenv("REMOTE_USER")) == NULL
)
1498 puts("Status: 401\n");
1503 * Cancel the subscription...
1506 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1508 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1509 NULL
, "ipp://localhost/");
1510 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1511 "notify-subscription-id", id
);
1513 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1516 ippDelete(cupsDoRequest(http
, request
, "/"));
1518 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1520 puts("Status: 401\n");
1523 else if (cupsLastError() > IPP_OK_CONFLICT
)
1525 cgiStartHTML(_("Cancel RSS Subscription"));
1526 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1531 * Redirect successful updates back to the admin page...
1534 cgiSetVariable("refresh_page", "5;URL=/admin");
1535 cgiStartHTML(_("Cancel RSS Subscription"));
1536 cgiCopyTemplateLang("subscription-canceled.tmpl");
1544 * 'do_config_server()' - Configure server settings.
1548 do_config_server(http_t
*http
) /* I - HTTP connection */
1550 if (cgiGetVariable("CHANGESETTINGS"))
1553 * Save basic setting changes...
1556 int num_settings
; /* Number of server settings */
1557 cups_option_t
*settings
; /* Server settings */
1558 int advanced
, /* Advanced settings shown? */
1559 changed
; /* Have settings changed? */
1560 const char *debug_logging
, /* DEBUG_LOGGING value */
1561 *remote_admin
, /* REMOTE_ADMIN value */
1562 *remote_any
, /* REMOTE_ANY value */
1564 /* REMOTE_PRINTERS value */
1565 *share_printers
,/* SHARE_PRINTERS value */
1567 /* USER_CANCEL_ANY value */
1568 *browse_web_if
= NULL
,
1569 /* BrowseWebIF value */
1570 *preserve_job_history
= NULL
,
1571 /* PreserveJobHistory value */
1572 *preserve_job_files
= NULL
,
1573 /* PreserveJobFiles value */
1574 *max_clients
= NULL
,
1575 /* MaxClients value */
1578 *max_log_size
= NULL
;
1579 /* MaxLogSize value */
1580 char local_protocols
[255],
1581 /* BrowseLocalProtocols */
1582 remote_protocols
[255];
1583 /* BrowseRemoteProtocols */
1584 const char *current_browse_web_if
,
1585 /* BrowseWebIF value */
1586 *current_preserve_job_history
,
1587 /* PreserveJobHistory value */
1588 *current_preserve_job_files
,
1589 /* PreserveJobFiles value */
1590 *current_max_clients
,
1591 /* MaxClients value */
1594 *current_max_log_size
,
1595 /* MaxLogSize value */
1596 *current_local_protocols
,
1597 /* BrowseLocalProtocols */
1598 *current_remote_protocols
;
1599 /* BrowseRemoteProtocols */
1601 char default_auth_type
[255];
1602 /* DefaultAuthType value */
1603 const char *val
; /* Setting value */
1604 #endif /* HAVE_GSSAPI */
1608 * Get the checkbox values from the form...
1611 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1612 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1613 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1614 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1615 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1616 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1618 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1622 * Get advanced settings...
1625 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1626 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1627 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1628 max_clients
= cgiGetVariable("MAX_CLIENTS");
1629 max_jobs
= cgiGetVariable("MAX_JOBS");
1630 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1632 if (!max_clients
|| atoi(max_clients
) <= 0)
1633 max_clients
= "100";
1635 if (!max_jobs
|| atoi(max_jobs
) <= 0)
1638 if (!max_log_size
|| atof(max_log_size
) <= 0.0)
1639 max_log_size
= "1m";
1641 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1642 strcpy(local_protocols
, "cups");
1644 local_protocols
[0] = '\0';
1647 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1649 if (local_protocols
[0])
1650 strcat(local_protocols
, " dnssd");
1652 strcat(local_protocols
, "dnssd");
1654 #endif /* HAVE_DNSSD */
1657 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1659 if (local_protocols
[0])
1660 strcat(local_protocols
, " ldap");
1662 strcat(local_protocols
, "ldap");
1664 #endif /* HAVE_LDAP */
1667 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1669 if (local_protocols
[0])
1670 strcat(local_protocols
, " slp");
1672 strcat(local_protocols
, "slp");
1674 #endif /* HAVE_SLP */
1676 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1677 strcpy(remote_protocols
, "cups");
1679 remote_protocols
[0] = '\0';
1682 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1684 if (remote_protocols
[0])
1685 strcat(remote_protocols
, " ldap");
1687 strcat(remote_protocols
, "ldap");
1689 #endif /* HAVE_LDAP */
1692 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1694 if (remote_protocols
[0])
1695 strcat(remote_protocols
, " slp");
1697 strcat(remote_protocols
, "slp");
1699 #endif /* HAVE_SLP */
1703 * Get the current server settings...
1706 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1708 cgiStartHTML(cgiText(_("Change Settings")));
1709 cgiSetVariable("MESSAGE",
1710 cgiText(_("Unable to change server settings:")));
1711 cgiSetVariable("ERROR", cupsLastErrorString());
1712 cgiCopyTemplateLang("error.tmpl");
1719 * Get authentication settings...
1722 if (cgiGetVariable("KERBEROS"))
1723 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1726 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1728 if (!val
|| !strcasecmp(val
, "Negotiate"))
1729 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1731 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1734 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1735 #endif /* HAVE_GSSAPI */
1737 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1739 current_browse_web_if
= "No";
1741 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1744 current_preserve_job_history
= "Yes";
1746 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1749 current_preserve_job_files
= "No";
1751 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1753 current_max_clients
= "100";
1755 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1757 current_max_jobs
= "500";
1759 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1761 current_max_log_size
= "1m";
1763 if ((current_local_protocols
= cupsGetOption("BrowseLocalProtocols",
1766 current_local_protocols
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
1768 if ((current_remote_protocols
= cupsGetOption("BrowseRemoteProtocols",
1771 current_remote_protocols
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
1774 * See if the settings have changed...
1777 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1778 num_settings
, settings
)) ||
1779 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1780 num_settings
, settings
)) ||
1781 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1782 num_settings
, settings
)) ||
1783 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1784 num_settings
, settings
)) ||
1785 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1786 num_settings
, settings
)) ||
1788 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1789 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1790 num_settings
, settings
)) ||
1791 #endif /* HAVE_GSSAPI */
1792 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1793 num_settings
, settings
));
1795 if (advanced
&& !changed
)
1796 changed
= strcasecmp(local_protocols
, current_local_protocols
) ||
1797 strcasecmp(remote_protocols
, current_remote_protocols
) ||
1798 strcasecmp(browse_web_if
, current_browse_web_if
) ||
1799 strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1800 strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1801 strcasecmp(max_clients
, current_max_clients
) ||
1802 strcasecmp(max_jobs
, current_max_jobs
) ||
1803 strcasecmp(max_log_size
, current_max_log_size
);
1808 * Settings *have* changed, so save the changes...
1811 cupsFreeOptions(num_settings
, settings
);
1814 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1815 debug_logging
, num_settings
, &settings
);
1816 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1817 remote_admin
, num_settings
, &settings
);
1818 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1819 remote_any
, num_settings
, &settings
);
1820 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1821 remote_printers
, num_settings
, &settings
);
1822 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1823 share_printers
, num_settings
, &settings
);
1824 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1825 user_cancel_any
, num_settings
, &settings
);
1827 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1828 num_settings
, &settings
);
1829 #endif /* HAVE_GSSAPI */
1834 * Add advanced settings...
1837 if (strcasecmp(local_protocols
, current_local_protocols
))
1838 num_settings
= cupsAddOption("BrowseLocalProtocols", local_protocols
,
1839 num_settings
, &settings
);
1840 if (strcasecmp(remote_protocols
, current_remote_protocols
))
1841 num_settings
= cupsAddOption("BrowseRemoteProtocols", remote_protocols
,
1842 num_settings
, &settings
);
1843 if (strcasecmp(browse_web_if
, current_browse_web_if
))
1844 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1845 num_settings
, &settings
);
1846 if (strcasecmp(preserve_job_history
, current_preserve_job_history
))
1847 num_settings
= cupsAddOption("PreserveJobHistory",
1848 preserve_job_history
, num_settings
,
1850 if (strcasecmp(preserve_job_files
, current_preserve_job_files
))
1851 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1852 num_settings
, &settings
);
1853 if (strcasecmp(max_clients
, current_max_clients
))
1854 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1856 if (strcasecmp(max_jobs
, current_max_jobs
))
1857 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1859 if (strcasecmp(max_log_size
, current_max_log_size
))
1860 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1864 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1866 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1868 puts("Status: 401\n");
1872 cgiStartHTML(cgiText(_("Change Settings")));
1873 cgiSetVariable("MESSAGE",
1874 cgiText(_("Unable to change server settings:")));
1875 cgiSetVariable("ERROR", cupsLastErrorString());
1876 cgiCopyTemplateLang("error.tmpl");
1881 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1883 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1884 cgiStartHTML(cgiText(_("Change Settings")));
1885 cgiCopyTemplateLang("restart.tmpl");
1894 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1895 cgiStartHTML(cgiText(_("Change Settings")));
1896 cgiCopyTemplateLang("norestart.tmpl");
1899 cupsFreeOptions(num_settings
, settings
);
1903 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1906 * Save hand-edited config file...
1909 http_status_t status
; /* PUT status */
1910 char tempfile
[1024]; /* Temporary new cupsd.conf */
1911 int tempfd
; /* Temporary file descriptor */
1912 cups_file_t
*temp
; /* Temporary file */
1913 const char *start
, /* Start of line */
1914 *end
; /* End of line */
1918 * Create a temporary file for the new cupsd.conf file...
1921 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1923 cgiStartHTML(cgiText(_("Edit Configuration File")));
1924 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1925 cgiSetVariable("ERROR", strerror(errno
));
1926 cgiCopyTemplateLang("error.tmpl");
1933 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1935 cgiStartHTML(cgiText(_("Edit Configuration File")));
1936 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1937 cgiSetVariable("ERROR", strerror(errno
));
1938 cgiCopyTemplateLang("error.tmpl");
1948 * Copy the cupsd.conf text from the form variable...
1951 start
= cgiGetVariable("CUPSDCONF");
1954 if ((end
= strstr(start
, "\r\n")) == NULL
)
1955 if ((end
= strstr(start
, "\n")) == NULL
)
1956 end
= start
+ strlen(start
);
1958 cupsFileWrite(temp
, start
, end
- start
);
1959 cupsFilePutChar(temp
, '\n');
1963 else if (*end
== '\n')
1969 cupsFileClose(temp
);
1972 * Upload the configuration file to the server...
1975 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1977 if (status
== HTTP_UNAUTHORIZED
)
1979 puts("Status: 401\n");
1983 else if (status
!= HTTP_CREATED
)
1985 cgiSetVariable("MESSAGE",
1986 cgiText(_("Unable to upload cupsd.conf file:")));
1987 cgiSetVariable("ERROR", httpStatus(status
));
1989 cgiStartHTML(cgiText(_("Edit Configuration File")));
1990 cgiCopyTemplateLang("error.tmpl");
1994 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1996 cgiStartHTML(cgiText(_("Edit Configuration File")));
1997 cgiCopyTemplateLang("restart.tmpl");
2006 struct stat info
; /* cupsd.conf information */
2007 cups_file_t
*cupsd
; /* cupsd.conf file */
2008 char *buffer
, /* Buffer for entire file */
2009 *bufptr
, /* Pointer into buffer */
2010 *bufend
; /* End of buffer */
2011 int ch
; /* Character from file */
2012 char filename
[1024]; /* Filename */
2013 const char *server_root
; /* Location of config files */
2017 * Locate the cupsd.conf file...
2020 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
2021 server_root
= CUPS_SERVERROOT
;
2023 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
2026 * Figure out the size...
2029 if (stat(filename
, &info
))
2031 cgiStartHTML(cgiText(_("Edit Configuration File")));
2032 cgiSetVariable("MESSAGE",
2033 cgiText(_("Unable to access cupsd.conf file:")));
2034 cgiSetVariable("ERROR", strerror(errno
));
2035 cgiCopyTemplateLang("error.tmpl");
2042 if (info
.st_size
> (1024 * 1024))
2044 cgiStartHTML(cgiText(_("Edit Configuration File")));
2045 cgiSetVariable("MESSAGE",
2046 cgiText(_("Unable to access cupsd.conf file:")));
2047 cgiSetVariable("ERROR",
2048 cgiText(_("Unable to edit cupsd.conf files larger than "
2050 cgiCopyTemplateLang("error.tmpl");
2053 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
2054 (long)info
.st_size
);
2059 * Open the cupsd.conf file...
2062 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
2065 * Unable to open - log an error...
2068 cgiStartHTML(cgiText(_("Edit Configuration File")));
2069 cgiSetVariable("MESSAGE",
2070 cgiText(_("Unable to access cupsd.conf file:")));
2071 cgiSetVariable("ERROR", strerror(errno
));
2072 cgiCopyTemplateLang("error.tmpl");
2080 * Allocate memory and load the file into a string buffer...
2083 if ((buffer
= calloc(1, info
.st_size
+ 1)) != NULL
)
2085 cupsFileRead(cupsd
, buffer
, info
.st_size
);
2086 cgiSetVariable("CUPSDCONF", buffer
);
2090 cupsFileClose(cupsd
);
2093 * Then get the default cupsd.conf file and put that into a string as
2097 strlcat(filename
, ".default", sizeof(filename
));
2099 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
2100 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
2102 if ((buffer
= calloc(1, 2 * info
.st_size
+ 1)) != NULL
)
2104 bufend
= buffer
+ 2 * info
.st_size
- 1;
2106 for (bufptr
= buffer
;
2107 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
2109 if (ch
== '\\' || ch
== '\"')
2114 else if (ch
== '\n')
2119 else if (ch
== '\t')
2130 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
2134 cupsFileClose(cupsd
);
2138 * Show the current config file...
2141 cgiStartHTML(cgiText(_("Edit Configuration File")));
2143 cgiCopyTemplateLang("edit-config.tmpl");
2151 * 'do_delete_class()' - Delete a class.
2155 do_delete_class(http_t
*http
) /* I - HTTP connection */
2157 ipp_t
*request
; /* IPP request */
2158 char uri
[HTTP_MAX_URI
]; /* Job URI */
2159 const char *pclass
; /* Printer class name */
2163 * Get form variables...
2166 if (cgiGetVariable("CONFIRM") == NULL
)
2168 cgiStartHTML(cgiText(_("Delete Class")));
2169 cgiCopyTemplateLang("class-confirm.tmpl");
2174 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2175 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2176 "localhost", 0, "/classes/%s", pclass
);
2179 cgiStartHTML(cgiText(_("Delete Class")));
2180 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2181 cgiCopyTemplateLang("error.tmpl");
2187 * Build a CUPS_DELETE_CLASS request, which requires the following
2190 * attributes-charset
2191 * attributes-natural-language
2195 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2197 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2201 * Do the request and get back a response...
2204 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2207 * Show the results...
2210 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2212 puts("Status: 401\n");
2215 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2218 * Redirect successful updates back to the classes page...
2221 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2224 cgiStartHTML(cgiText(_("Delete Class")));
2226 if (cupsLastError() > IPP_OK_CONFLICT
)
2227 cgiShowIPPError(_("Unable to delete class:"));
2229 cgiCopyTemplateLang("class-deleted.tmpl");
2236 * 'do_delete_printer()' - Delete a printer.
2240 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2242 ipp_t
*request
; /* IPP request */
2243 char uri
[HTTP_MAX_URI
]; /* Job URI */
2244 const char *printer
; /* Printer printer name */
2248 * Get form variables...
2251 if (cgiGetVariable("CONFIRM") == NULL
)
2253 cgiStartHTML(cgiText(_("Delete Printer")));
2254 cgiCopyTemplateLang("printer-confirm.tmpl");
2259 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2260 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2261 "localhost", 0, "/printers/%s", printer
);
2264 cgiStartHTML(cgiText(_("Delete Printer")));
2265 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2266 cgiCopyTemplateLang("error.tmpl");
2272 * Build a CUPS_DELETE_PRINTER request, which requires the following
2275 * attributes-charset
2276 * attributes-natural-language
2280 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2282 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2286 * Do the request and get back a response...
2289 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2292 * Show the results...
2295 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2297 puts("Status: 401\n");
2300 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2303 * Redirect successful updates back to the printers page...
2306 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2309 cgiStartHTML(cgiText(_("Delete Printer")));
2311 if (cupsLastError() > IPP_OK_CONFLICT
)
2312 cgiShowIPPError(_("Unable to delete printer:"));
2314 cgiCopyTemplateLang("printer-deleted.tmpl");
2321 * 'do_export()' - Export printers to Samba.
2325 do_export(http_t
*http
) /* I - HTTP connection */
2327 int i
, j
; /* Looping vars */
2328 ipp_t
*request
, /* IPP request */
2329 *response
; /* IPP response */
2330 const char *username
, /* Samba username */
2331 *password
, /* Samba password */
2332 *export_all
; /* Export all printers? */
2333 int export_count
, /* Number of printers to export */
2334 printer_count
; /* Number of available printers */
2335 const char *name
, /* What name to pull */
2336 *dest
; /* Current destination */
2337 char ppd
[1024]; /* PPD file */
2344 username
= cgiGetVariable("USERNAME");
2345 password
= cgiGetVariable("PASSWORD");
2346 export_all
= cgiGetVariable("EXPORT_ALL");
2347 export_count
= cgiGetSize("EXPORT_NAME");
2350 * Get list of available printers...
2353 cgiSetSize("PRINTER_NAME", 0);
2354 cgiSetSize("PRINTER_EXPORT", 0);
2356 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2358 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2361 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2362 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2363 CUPS_PRINTER_IMPLICIT
);
2365 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2366 "requested-attributes", NULL
, "printer-name");
2368 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2370 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2371 ippDelete(response
);
2375 printer_count
= cgiGetSize("PRINTER_NAME");
2377 for (i
= 0; i
< printer_count
; i
++)
2379 dest
= cgiGetArray("PRINTER_NAME", i
);
2381 for (j
= 0; j
< export_count
; j
++)
2382 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2385 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2391 * Export or get the printers to export...
2394 if (username
&& *username
&& password
&& *password
&&
2395 (export_all
|| export_count
> 0))
2401 fputs("DEBUG: Export printers...\n", stderr
);
2405 name
= "PRINTER_NAME";
2406 export_count
= cgiGetSize("PRINTER_NAME");
2409 name
= "EXPORT_NAME";
2411 for (i
= 0; i
< export_count
; i
++)
2413 dest
= cgiGetArray(name
, i
);
2415 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2418 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2427 if (i
< export_count
)
2428 cgiSetVariable("ERROR", cupsLastErrorString());
2431 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2432 cgiCopyTemplateLang("samba-exported.tmpl");
2437 else if (username
&& !*username
)
2438 cgiSetVariable("ERROR",
2439 cgiText(_("A Samba username is required to export "
2440 "printer drivers")));
2441 else if (username
&& (!password
|| !*password
))
2442 cgiSetVariable("ERROR",
2443 cgiText(_("A Samba password is required to export "
2444 "printer drivers")));
2450 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2451 cgiCopyTemplateLang("samba-export.tmpl");
2457 * 'do_list_printers()' - List available printers.
2461 do_list_printers(http_t
*http
) /* I - HTTP connection */
2463 ipp_t
*request
, /* IPP request */
2464 *response
; /* IPP response */
2465 ipp_attribute_t
*attr
; /* IPP attribute */
2468 cgiStartHTML(cgiText(_("List Available Printers")));
2472 * Get the list of printers and their devices...
2475 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2477 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2478 "requested-attributes", NULL
, "device-uri");
2480 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2481 CUPS_PRINTER_LOCAL
);
2482 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2483 CUPS_PRINTER_LOCAL
);
2485 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2488 * Got the printer list, now load the devices...
2491 int i
; /* Looping var */
2492 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2493 char *printer_device
; /* Current printer device */
2497 * Allocate an array and copy the device strings...
2500 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2502 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2504 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2506 cupsArrayAdd(printer_devices
, _cupsStrAlloc(attr
->values
[0].string
.text
));
2510 * Free the printer list and get the device list...
2513 ippDelete(response
);
2515 request
= ippNewRequest(CUPS_GET_DEVICES
);
2517 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2520 * Got the device list, let's parse it...
2523 const char *device_uri
, /* device-uri attribute value */
2524 *device_make_and_model
, /* device-make-and-model value */
2525 *device_info
; /* device-info value */
2528 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2531 * Skip leading attributes until we hit a device...
2534 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2541 * Pull the needed attributes from this device...
2545 device_make_and_model
= NULL
;
2548 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2550 if (!strcmp(attr
->name
, "device-info") &&
2551 attr
->value_tag
== IPP_TAG_TEXT
)
2552 device_info
= attr
->values
[0].string
.text
;
2554 if (!strcmp(attr
->name
, "device-make-and-model") &&
2555 attr
->value_tag
== IPP_TAG_TEXT
)
2556 device_make_and_model
= attr
->values
[0].string
.text
;
2558 if (!strcmp(attr
->name
, "device-uri") &&
2559 attr
->value_tag
== IPP_TAG_URI
)
2560 device_uri
= attr
->values
[0].string
.text
;
2566 * See if we have everything needed...
2569 if (device_info
&& device_make_and_model
&& device_uri
&&
2570 strcasecmp(device_make_and_model
, "unknown") &&
2571 strchr(device_uri
, ':'))
2574 * Yes, now see if there is already a printer for this
2578 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2581 * Not found, so it must be a new printer...
2584 char option
[1024], /* Form variables for this device */
2585 *option_ptr
; /* Pointer into string */
2586 const char *ptr
; /* Pointer into device string */
2590 * Format the printer name variable for this device...
2592 * We use the device-info string first, then device-uri,
2593 * and finally device-make-and-model to come up with a
2597 if (strncasecmp(device_info
, "unknown", 7))
2599 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2602 ptr
= device_make_and_model
;
2604 for (option_ptr
= option
;
2605 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2607 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2609 *option_ptr
++ = *ptr
;
2610 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2611 option_ptr
[-1] != '_')
2612 *option_ptr
++ = '_';
2613 else if (*ptr
== '?' || *ptr
== '(')
2618 cgiSetArray("TEMPLATE_NAME", i
, option
);
2621 * Finally, set the form variables for this printer...
2624 cgiSetArray("device_info", i
, device_info
);
2625 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2626 cgiSetArray("device_uri", i
, device_uri
);
2635 ippDelete(response
);
2638 * Free the device list...
2641 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2643 printer_device
= (char *)cupsArrayNext(printer_devices
))
2644 _cupsStrFree(printer_device
);
2646 cupsArrayDelete(printer_devices
);
2651 * Finally, show the printer list...
2654 cgiCopyTemplateLang("list-available-printers.tmpl");
2661 * 'do_menu()' - Show the main menu.
2665 do_menu(http_t
*http
) /* I - HTTP connection */
2667 int num_settings
; /* Number of server settings */
2668 cups_option_t
*settings
; /* Server settings */
2669 const char *val
; /* Setting value */
2670 char filename
[1024]; /* Temporary filename */
2671 const char *datadir
; /* Location of data files */
2672 ipp_t
*request
, /* IPP request */
2673 *response
; /* IPP response */
2677 * Get the current server settings...
2680 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2682 cgiSetVariable("SETTINGS_MESSAGE",
2683 cgiText(_("Unable to open cupsd.conf file:")));
2684 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2687 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2688 settings
)) != NULL
&& atoi(val
))
2689 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2691 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2692 settings
)) != NULL
&& atoi(val
))
2693 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2695 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2696 settings
)) != NULL
&& atoi(val
))
2697 cgiSetVariable("REMOTE_ANY", "CHECKED");
2699 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2700 settings
)) != NULL
&& atoi(val
))
2701 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2703 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2704 settings
)) != NULL
&& atoi(val
))
2705 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2707 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2708 settings
)) != NULL
&& atoi(val
))
2709 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2712 cgiSetVariable("HAVE_GSSAPI", "1");
2714 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2715 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2716 cgiSetVariable("KERBEROS", "CHECKED");
2718 #endif /* HAVE_GSSAPI */
2719 cgiSetVariable("KERBEROS", "");
2722 cgiSetVariable("HAVE_DNSSD", "1");
2723 #endif /* HAVE_DNSSD */
2726 cgiSetVariable("HAVE_LDAP", "1");
2727 #endif /* HAVE_LDAP */
2730 cgiSetVariable("HAVE_LIBSLP", "1");
2731 #endif /* HAVE_LIBSLP */
2733 if ((val
= cupsGetOption("BrowseRemoteProtocols", num_settings
,
2735 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2737 val
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
2739 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2740 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2742 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2743 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2745 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2746 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2748 if ((val
= cupsGetOption("BrowseLocalProtocols", num_settings
,
2750 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2752 val
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
2754 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2755 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2757 if (strstr(val
, "dnssd") || strstr(val
, "DNSSD") ||
2758 strstr(val
, "dns-sd") || strstr(val
, "DNS-SD") ||
2759 strstr(val
, "bonjour") || strstr(val
, "BONJOUR"))
2760 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2762 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2763 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2765 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2766 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2768 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2772 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2773 !strcasecmp(val
, "true"))
2774 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2776 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2780 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2781 !strcasecmp(val
, "true"))
2783 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2785 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2789 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2790 !strcasecmp(val
, "true"))
2791 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2794 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2797 cgiSetVariable("MAX_CLIENTS", val
);
2799 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2802 cgiSetVariable("MAX_JOBS", val
);
2804 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2807 cgiSetVariable("MAX_LOG_SIZE", val
);
2809 cupsFreeOptions(num_settings
, settings
);
2812 * See if Samba and the Windows drivers are installed...
2815 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2816 datadir
= CUPS_DATADIR
;
2818 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2819 if (!access(filename
, R_OK
))
2822 * Found Windows 2000 driver file, see if we have smbclient and
2826 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2827 sizeof(filename
)) &&
2828 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2830 cgiSetVariable("HAVE_SAMBA", "Y");
2833 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2835 fputs("ERROR: smbclient not found!\n", stderr
);
2837 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2839 fputs("ERROR: rpcclient not found!\n", stderr
);
2849 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2851 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2852 NULL
, "ipp://localhost/");
2854 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2856 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2857 ippDelete(response
);
2861 * Finally, show the main menu template...
2864 cgiStartHTML(cgiText(_("Administration")));
2866 cgiCopyTemplateLang("admin.tmpl");
2873 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2877 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2879 int i
; /* Looping var */
2880 ipp_t
*request
, /* IPP request */
2881 *response
; /* IPP response */
2882 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2883 const char *printer
, /* Printer name (purge-jobs) */
2884 *is_class
, /* Is a class? */
2885 *users
, /* List of users or groups */
2886 *type
; /* Allow/deny type */
2887 int num_users
; /* Number of users */
2888 char *ptr
, /* Pointer into users string */
2889 *end
, /* Pointer to end of users string */
2890 quote
; /* Quote character */
2891 ipp_attribute_t
*attr
; /* Attribute */
2892 static const char * const attrs
[] = /* Requested attributes */
2894 "requesting-user-name-allowed",
2895 "requesting-user-name-denied"
2899 is_class
= cgiGetVariable("IS_CLASS");
2900 printer
= cgiGetVariable("PRINTER_NAME");
2904 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2905 cgiStartHTML(cgiText(_("Set Allowed Users")));
2906 cgiCopyTemplateLang("error.tmpl");
2911 users
= cgiGetVariable("users");
2912 type
= cgiGetVariable("type");
2914 if (!users
|| !type
||
2915 (strcmp(type
, "requesting-user-name-allowed") &&
2916 strcmp(type
, "requesting-user-name-denied")))
2919 * Build a Get-Printer-Attributes request, which requires the following
2922 * attributes-charset
2923 * attributes-natural-language
2925 * requested-attributes
2928 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
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",
2936 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2937 "requested-attributes",
2938 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2941 * Do the request and get back a response...
2944 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2946 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2948 ippDelete(response
);
2951 cgiStartHTML(cgiText(_("Set Allowed Users")));
2953 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2955 puts("Status: 401\n");
2958 else if (cupsLastError() > IPP_OK_CONFLICT
)
2959 cgiShowIPPError(_("Unable to get printer attributes:"));
2961 cgiCopyTemplateLang("users.tmpl");
2968 * Save the changes...
2971 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2974 * Skip whitespace and commas...
2977 while (*ptr
== ',' || isspace(*ptr
& 255))
2983 if (*ptr
== '\'' || *ptr
== '\"')
2986 * Scan quoted name...
2991 for (end
= ptr
; *end
; end
++)
2998 * Scan space or comma-delimited name...
3001 for (end
= ptr
; *end
; end
++)
3002 if (isspace(*end
& 255) || *end
== ',')
3007 * Advance to the next name...
3014 * Build a CUPS-Add-Printer/Class request, which requires the following
3017 * attributes-charset
3018 * attributes-natural-language
3020 * requesting-user-name-{allowed,denied}
3023 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3025 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3026 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3028 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3032 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3033 "requesting-user-name-allowed", NULL
, "all");
3036 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3037 type
, num_users
, NULL
, NULL
);
3039 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
3042 * Skip whitespace and commas...
3045 while (*ptr
== ',' || isspace(*ptr
& 255))
3051 if (*ptr
== '\'' || *ptr
== '\"')
3054 * Scan quoted name...
3059 for (end
= ptr
; *end
; end
++)
3066 * Scan space or comma-delimited name...
3069 for (end
= ptr
; *end
; end
++)
3070 if (isspace(*end
& 255) || *end
== ',')
3075 * Terminate the name...
3085 attr
->values
[i
].string
.text
= _cupsStrAlloc(ptr
);
3088 * Advance to the next name...
3096 * Do the request and get back a response...
3099 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3101 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3103 puts("Status: 401\n");
3106 else if (cupsLastError() > IPP_OK_CONFLICT
)
3108 cgiStartHTML(cgiText(_("Set Allowed Users")));
3109 cgiShowIPPError(_("Unable to change printer:"));
3114 * Redirect successful updates back to the printer page...
3117 char url
[1024], /* Printer/class URL */
3118 refresh
[1024]; /* Refresh URL */
3121 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3122 cgiFormEncode(uri
, url
, sizeof(uri
));
3123 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
3125 cgiSetVariable("refresh_page", refresh
);
3127 cgiStartHTML(cgiText(_("Set Allowed Users")));
3129 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3130 "printer-modified.tmpl");
3139 * 'do_set_default()' - Set the server default printer/class.
3143 do_set_default(http_t
*http
) /* I - HTTP connection */
3145 const char *title
; /* Page title */
3146 ipp_t
*request
; /* IPP request */
3147 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3148 const char *printer
, /* Printer name (purge-jobs) */
3149 *is_class
; /* Is a class? */
3152 is_class
= cgiGetVariable("IS_CLASS");
3153 printer
= cgiGetVariable("PRINTER_NAME");
3154 title
= cgiText(_("Set As Server Default"));
3158 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3159 cgiStartHTML(title
);
3160 cgiCopyTemplateLang("error.tmpl");
3166 * Build a printer request, which requires the following
3169 * attributes-charset
3170 * attributes-natural-language
3174 request
= ippNewRequest(CUPS_SET_DEFAULT
);
3176 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3177 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3179 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3183 * Do the request and get back a response...
3186 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3188 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3190 puts("Status: 401\n");
3193 else if (cupsLastError() > IPP_OK_CONFLICT
)
3195 cgiStartHTML(title
);
3196 cgiShowIPPError(_("Unable to set server default:"));
3201 * Redirect successful updates back to the printer page...
3204 char url
[1024], /* Printer/class URL */
3205 refresh
[1024]; /* Refresh URL */
3208 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3209 cgiFormEncode(uri
, url
, sizeof(uri
));
3210 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3211 cgiSetVariable("refresh_page", refresh
);
3213 cgiStartHTML(title
);
3214 cgiCopyTemplateLang("printer-default.tmpl");
3222 * 'do_set_options()' - Configure the default options for a queue.
3226 do_set_options(http_t
*http
, /* I - HTTP connection */
3227 int is_class
) /* I - Set options for class? */
3229 int i
, j
, k
, m
; /* Looping vars */
3230 int have_options
; /* Have options? */
3231 ipp_t
*request
, /* IPP request */
3232 *response
; /* IPP response */
3233 ipp_attribute_t
*attr
; /* IPP attribute */
3234 char uri
[HTTP_MAX_URI
]; /* Job URI */
3235 const char *var
; /* Variable value */
3236 const char *printer
; /* Printer printer name */
3237 const char *filename
; /* PPD filename */
3238 char tempfile
[1024]; /* Temporary filename */
3239 cups_file_t
*in
, /* Input file */
3240 *out
; /* Output file */
3241 char line
[1024], /* Line from PPD file */
3242 value
[1024], /* Option value */
3243 keyword
[1024], /* Keyword from Default line */
3244 *keyptr
; /* Pointer into keyword... */
3245 ppd_file_t
*ppd
; /* PPD file */
3246 ppd_group_t
*group
; /* Option group */
3247 ppd_option_t
*option
; /* Option */
3248 ppd_coption_t
*coption
; /* Custom option */
3249 ppd_cparam_t
*cparam
; /* Custom parameter */
3250 ppd_attr_t
*ppdattr
; /* PPD attribute */
3251 const char *title
; /* Page title */
3254 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
3256 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
3260 * Get the printer name...
3263 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
3264 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3265 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3269 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3270 cgiStartHTML(title
);
3271 cgiCopyTemplateLang("error.tmpl");
3276 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
3279 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3280 * command file to the printer...
3283 if (cgiGetVariable("AUTOCONFIGURE"))
3285 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
3290 * Get the PPD file...
3296 filename
= cupsGetPPD2(http
, printer
);
3300 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
3302 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
3304 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
3305 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3306 cgiStartHTML(title
);
3307 cgiCopyTemplateLang("error.tmpl");
3314 fputs("DEBUG: No PPD file\n", stderr
);
3318 if (cgiGetVariable("job_sheets_start") != NULL
||
3319 cgiGetVariable("job_sheets_end") != NULL
)
3326 ppdMarkDefaults(ppd
);
3328 for (option
= ppdFirstOption(ppd
);
3330 option
= ppdNextOption(ppd
))
3332 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
3335 ppdMarkOption(ppd
, option
->keyword
, var
);
3336 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
3339 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
3343 if (!have_options
|| ppdConflicts(ppd
))
3346 * Show the options to the user...
3349 fputs("DEBUG: Showing options...\n", stderr
);
3352 * Show auto-configure button if supported...
3357 if (ppd
->num_filters
== 0 ||
3358 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
3359 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
3360 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3363 for (i
= 0; i
< ppd
->num_filters
; i
++)
3364 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
3366 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3373 * Get the printer attributes...
3376 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3378 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3379 "localhost", 0, "/printers/%s", printer
);
3380 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3383 response
= cupsDoRequest(http
, request
, "/");
3386 * List the groups used as "tabs"...
3393 for (group
= ppd
->groups
;
3394 i
< ppd
->num_groups
;
3397 cgiSetArray("GROUP_ID", i
, group
->name
);
3399 if (!strcmp(group
->name
, "InstallableOptions"))
3400 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
3402 cgiSetArray("GROUP", i
, group
->text
);
3406 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
3408 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
3409 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
3412 if (ippFindAttribute(response
, "printer-error-policy-supported",
3414 ippFindAttribute(response
, "printer-op-policy-supported",
3417 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
3418 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3421 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3422 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3424 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3425 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3428 cgiStartHTML(cgiText(_("Set Printer Options")));
3429 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3435 if (ppdConflicts(ppd
))
3437 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3440 for (j
= group
->num_options
, option
= group
->options
;
3443 if (option
->conflicted
)
3445 cgiSetArray("ckeyword", k
, option
->keyword
);
3446 cgiSetArray("ckeytext", k
, option
->text
);
3448 for (m
= 0; m
< option
->num_choices
; m
++)
3450 if (option
->choices
[m
].marked
)
3452 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3460 cgiCopyTemplateLang("option-conflict.tmpl");
3463 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3467 for (j
= group
->num_options
, option
= group
->options
;
3471 if (!strcmp(option
->keyword
, "PageRegion"))
3474 if (option
->num_choices
> 1)
3481 cgiSetVariable("GROUP_ID", group
->name
);
3483 if (!strcmp(group
->name
, "InstallableOptions"))
3484 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3486 cgiSetVariable("GROUP", group
->text
);
3488 cgiCopyTemplateLang("option-header.tmpl");
3490 for (j
= group
->num_options
, option
= group
->options
;
3494 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
3497 cgiSetVariable("KEYWORD", option
->keyword
);
3498 cgiSetVariable("KEYTEXT", option
->text
);
3500 if (option
->conflicted
)
3501 cgiSetVariable("CONFLICTED", "1");
3503 cgiSetVariable("CONFLICTED", "0");
3505 cgiSetSize("CHOICES", 0);
3506 cgiSetSize("TEXT", 0);
3507 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3509 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3510 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3514 if (option
->choices
[k
].marked
)
3515 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3518 cgiSetSize("PARAMS", 0);
3519 cgiSetSize("PARAMTEXT", 0);
3520 cgiSetSize("PARAMVALUE", 0);
3521 cgiSetSize("INPUTTYPE", 0);
3523 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3525 const char *units
= NULL
; /* Units value, if any */
3527 cgiSetVariable("ISCUSTOM", "1");
3529 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3531 cparam
= ppdNextCustomParam(coption
), m
++)
3533 if (!strcasecmp(option
->keyword
, "PageSize") &&
3534 strcasecmp(cparam
->name
, "Width") &&
3535 strcasecmp(cparam
->name
, "Height"))
3541 cgiSetArray("PARAMS", m
, cparam
->name
);
3542 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3543 cgiSetArray("INPUTTYPE", m
, "text");
3545 switch (cparam
->type
)
3547 case PPD_CUSTOM_POINTS
:
3548 if (!strncasecmp(option
->defchoice
, "Custom.", 7))
3550 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3552 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3553 strcmp(units
, "in") && strcmp(units
, "ft"))
3555 if (units
[1] == 'm')
3564 if (!strcmp(units
, "mm"))
3565 snprintf(value
, sizeof(value
), "%g",
3566 cparam
->current
.custom_points
/ 72.0 * 25.4);
3567 else if (!strcmp(units
, "cm"))
3568 snprintf(value
, sizeof(value
), "%g",
3569 cparam
->current
.custom_points
/ 72.0 * 2.54);
3570 else if (!strcmp(units
, "in"))
3571 snprintf(value
, sizeof(value
), "%g",
3572 cparam
->current
.custom_points
/ 72.0);
3573 else if (!strcmp(units
, "ft"))
3574 snprintf(value
, sizeof(value
), "%g",
3575 cparam
->current
.custom_points
/ 72.0 / 12.0);
3576 else if (!strcmp(units
, "m"))
3577 snprintf(value
, sizeof(value
), "%g",
3578 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3580 snprintf(value
, sizeof(value
), "%g",
3581 cparam
->current
.custom_points
);
3582 cgiSetArray("PARAMVALUE", m
, value
);
3585 case PPD_CUSTOM_CURVE
:
3586 case PPD_CUSTOM_INVCURVE
:
3587 case PPD_CUSTOM_REAL
:
3588 snprintf(value
, sizeof(value
), "%g",
3589 cparam
->current
.custom_real
);
3590 cgiSetArray("PARAMVALUE", m
, value
);
3593 case PPD_CUSTOM_INT
:
3594 snprintf(value
, sizeof(value
), "%d",
3595 cparam
->current
.custom_int
);
3596 cgiSetArray("PARAMVALUE", m
, value
);
3599 case PPD_CUSTOM_PASSCODE
:
3600 case PPD_CUSTOM_PASSWORD
:
3601 if (cparam
->current
.custom_password
)
3602 cgiSetArray("PARAMVALUE", m
,
3603 cparam
->current
.custom_password
);
3605 cgiSetArray("PARAMVALUE", m
, "");
3606 cgiSetArray("INPUTTYPE", m
, "password");
3609 case PPD_CUSTOM_STRING
:
3610 if (cparam
->current
.custom_string
)
3611 cgiSetArray("PARAMVALUE", m
,
3612 cparam
->current
.custom_string
);
3614 cgiSetArray("PARAMVALUE", m
, "");
3621 cgiSetArray("PARAMS", m
, "Units");
3622 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3623 cgiSetArray("PARAMVALUE", m
, units
);
3627 cgiSetVariable("ISCUSTOM", "0");
3631 case PPD_UI_BOOLEAN
:
3632 cgiCopyTemplateLang("option-boolean.tmpl");
3634 case PPD_UI_PICKONE
:
3635 cgiCopyTemplateLang("option-pickone.tmpl");
3637 case PPD_UI_PICKMANY
:
3638 cgiCopyTemplateLang("option-pickmany.tmpl");
3643 cgiCopyTemplateLang("option-trailer.tmpl");
3647 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3648 IPP_TAG_ZERO
)) != NULL
)
3651 * Add the job sheets options...
3654 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3655 cgiSetVariable("GROUP", cgiText(_("Banners")));
3656 cgiCopyTemplateLang("option-header.tmpl");
3658 cgiSetSize("CHOICES", attr
->num_values
);
3659 cgiSetSize("TEXT", attr
->num_values
);
3660 for (k
= 0; k
< attr
->num_values
; k
++)
3662 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3663 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3666 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3668 cgiSetVariable("KEYWORD", "job_sheets_start");
3669 cgiSetVariable("KEYTEXT",
3670 /* TRANSLATORS: Banner/cover sheet before the print job. */
3671 cgiText(_("Starting Banner")));
3672 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3673 attr
->values
[0].string
.text
: "");
3675 cgiCopyTemplateLang("option-pickone.tmpl");
3677 cgiSetVariable("KEYWORD", "job_sheets_end");
3678 cgiSetVariable("KEYTEXT",
3679 /* TRANSLATORS: Banner/cover sheet after the print job. */
3680 cgiText(_("Ending Banner")));
3681 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3682 attr
->values
[1].string
.text
: "");
3684 cgiCopyTemplateLang("option-pickone.tmpl");
3686 cgiCopyTemplateLang("option-trailer.tmpl");
3689 if (ippFindAttribute(response
, "printer-error-policy-supported",
3691 ippFindAttribute(response
, "printer-op-policy-supported",
3695 * Add the error and operation policy options...
3698 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3699 cgiSetVariable("GROUP", cgiText(_("Policies")));
3700 cgiCopyTemplateLang("option-header.tmpl");
3706 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3711 cgiSetSize("CHOICES", attr
->num_values
);
3712 cgiSetSize("TEXT", attr
->num_values
);
3713 for (k
= 0; k
< attr
->num_values
; k
++)
3715 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3716 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3719 attr
= ippFindAttribute(response
, "printer-error-policy",
3722 cgiSetVariable("KEYWORD", "printer_error_policy");
3723 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3724 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3725 "" : attr
->values
[0].string
.text
);
3728 cgiCopyTemplateLang("option-pickone.tmpl");
3731 * Operation policy...
3734 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3739 cgiSetSize("CHOICES", attr
->num_values
);
3740 cgiSetSize("TEXT", attr
->num_values
);
3741 for (k
= 0; k
< attr
->num_values
; k
++)
3743 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3744 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3747 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3749 cgiSetVariable("KEYWORD", "printer_op_policy");
3750 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3751 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3752 "" : attr
->values
[0].string
.text
);
3754 cgiCopyTemplateLang("option-pickone.tmpl");
3757 cgiCopyTemplateLang("option-trailer.tmpl");
3761 * Binary protocol support...
3764 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3765 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3767 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3768 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3770 cgiSetSize("CHOICES", attr
->num_values
);
3771 cgiSetSize("TEXT", attr
->num_values
);
3773 for (i
= 0; i
< attr
->num_values
; i
++)
3775 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3776 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3779 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3780 cgiSetVariable("KEYWORD", "port_monitor");
3781 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3782 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3784 cgiCopyTemplateLang("option-header.tmpl");
3785 cgiCopyTemplateLang("option-pickone.tmpl");
3786 cgiCopyTemplateLang("option-trailer.tmpl");
3789 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3792 ippDelete(response
);
3797 * Set default options...
3800 fputs("DEBUG: Setting options...\n", stderr
);
3804 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3805 in
= cupsFileOpen(filename
, "r");
3809 cgiSetVariable("ERROR", strerror(errno
));
3810 cgiStartHTML(cgiText(_("Set Printer Options")));
3811 cgiCopyTemplateLang("error.tmpl");
3827 while (cupsFileGets(in
, line
, sizeof(line
)))
3829 if (!strncmp(line
, "*cupsProtocol:", 14))
3831 else if (strncmp(line
, "*Default", 8))
3832 cupsFilePrintf(out
, "%s\n", line
);
3836 * Get default option name...
3839 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3841 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3842 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3847 if (!strcmp(keyword
, "PageRegion") ||
3848 !strcmp(keyword
, "PaperDimension") ||
3849 !strcmp(keyword
, "ImageableArea"))
3850 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3852 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3855 cupsFilePrintf(out
, "%s\n", line
);
3857 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3867 * Make sure temporary filename is cleared when there is no PPD...
3874 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3875 * following attributes:
3877 * attributes-charset
3878 * attributes-natural-language
3880 * job-sheets-default
3881 * printer-error-policy
3886 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3887 CUPS_ADD_MODIFY_PRINTER
);
3889 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3892 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3893 "job-sheets-default", 2, NULL
, NULL
);
3894 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3895 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3897 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3898 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3899 "printer-error-policy", NULL
, var
);
3901 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3902 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3903 "printer-op-policy", NULL
, var
);
3905 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3906 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3907 "port-monitor", NULL
, var
);
3910 * Do the request and get back a response...
3914 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3916 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3918 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3920 puts("Status: 401\n");
3923 else if (cupsLastError() > IPP_OK_CONFLICT
)
3925 cgiStartHTML(title
);
3926 cgiShowIPPError(_("Unable to set options:"));
3931 * Redirect successful updates back to the printer page...
3934 char refresh
[1024]; /* Refresh URL */
3937 cgiFormEncode(uri
, printer
, sizeof(uri
));
3938 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3939 is_class
? "classes" : "printers", uri
);
3940 cgiSetVariable("refresh_page", refresh
);
3942 cgiStartHTML(title
);
3944 cgiCopyTemplateLang("printer-configured.tmpl");
3959 * 'do_set_sharing()' - Set printer-is-shared value.
3963 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3965 ipp_t
*request
, /* IPP request */
3966 *response
; /* IPP response */
3967 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3968 const char *printer
, /* Printer name */
3969 *is_class
, /* Is a class? */
3970 *shared
; /* Sharing value */
3973 is_class
= cgiGetVariable("IS_CLASS");
3974 printer
= cgiGetVariable("PRINTER_NAME");
3975 shared
= cgiGetVariable("SHARED");
3977 if (!printer
|| !shared
)
3979 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3980 cgiStartHTML(cgiText(_("Set Publishing")));
3981 cgiCopyTemplateLang("error.tmpl");
3987 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3988 * following attributes:
3990 * attributes-charset
3991 * attributes-natural-language
3996 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3998 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3999 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
4001 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
4004 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
4007 * Do the request and get back a response...
4010 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
4012 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
4014 ippDelete(response
);
4017 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
4019 puts("Status: 401\n");
4022 else if (cupsLastError() > IPP_OK_CONFLICT
)
4024 cgiStartHTML(cgiText(_("Set Publishing")));
4025 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
4030 * Redirect successful updates back to the printer page...
4033 char url
[1024], /* Printer/class URL */
4034 refresh
[1024]; /* Refresh URL */
4037 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
4038 cgiFormEncode(uri
, url
, sizeof(uri
));
4039 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
4040 cgiSetVariable("refresh_page", refresh
);
4042 cgiStartHTML(cgiText(_("Set Publishing")));
4043 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
4044 "printer-modified.tmpl");
4052 * 'get_option_value()' - Return the value of an option.
4054 * This function also handles generation of custom option values.
4057 static char * /* O - Value string or NULL on error */
4059 ppd_file_t
*ppd
, /* I - PPD file */
4060 const char *name
, /* I - Option name */
4061 char *buffer
, /* I - String buffer */
4062 size_t bufsize
) /* I - Size of buffer */
4064 char *bufptr
, /* Pointer into buffer */
4065 *bufend
; /* End of buffer */
4066 ppd_coption_t
*coption
; /* Custom option */
4067 ppd_cparam_t
*cparam
; /* Current custom parameter */
4068 char keyword
[256]; /* Parameter name */
4069 const char *val
, /* Parameter value */
4070 *uval
; /* Units value */
4071 long integer
; /* Integer value */
4072 double number
, /* Number value */
4073 number_points
; /* Number in points */
4077 * See if we have a custom option choice...
4080 if ((val
= cgiGetVariable(name
)) == NULL
)
4088 else if (strcasecmp(val
, "Custom") ||
4089 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
4092 * Not a custom choice...
4095 strlcpy(buffer
, val
, bufsize
);
4100 * OK, we have a custom option choice, format it...
4105 if (!strcmp(coption
->keyword
, "PageSize"))
4107 const char *lval
; /* Length string value */
4108 double width
, /* Width value */
4109 width_points
, /* Width in points */
4110 length
, /* Length value */
4111 length_points
; /* Length in points */
4114 val
= cgiGetVariable("PageSize.Width");
4115 lval
= cgiGetVariable("PageSize.Height");
4116 uval
= cgiGetVariable("PageSize.Units");
4118 if (!val
|| !lval
|| !uval
||
4119 (width
= strtod(val
, NULL
)) == 0.0 ||
4120 (length
= strtod(lval
, NULL
)) == 0.0 ||
4121 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4122 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4125 width_points
= get_points(width
, uval
);
4126 length_points
= get_points(length
, uval
);
4128 if (width_points
< ppd
->custom_min
[0] ||
4129 width_points
> ppd
->custom_max
[0] ||
4130 length_points
< ppd
->custom_min
[1] ||
4131 length_points
> ppd
->custom_max
[1])
4134 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
4136 else if (cupsArrayCount(coption
->params
) == 1)
4138 cparam
= ppdFirstCustomParam(coption
);
4139 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
4141 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4144 switch (cparam
->type
)
4146 case PPD_CUSTOM_CURVE
:
4147 case PPD_CUSTOM_INVCURVE
:
4148 case PPD_CUSTOM_REAL
:
4149 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4150 number
< cparam
->minimum
.custom_real
||
4151 number
> cparam
->maximum
.custom_real
)
4154 snprintf(buffer
, bufsize
, "Custom.%g", number
);
4157 case PPD_CUSTOM_INT
:
4158 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4159 integer
== LONG_MAX
||
4160 integer
< cparam
->minimum
.custom_int
||
4161 integer
> cparam
->maximum
.custom_int
)
4164 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
4167 case PPD_CUSTOM_POINTS
:
4168 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4170 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4171 (uval
= cgiGetVariable(keyword
)) == NULL
||
4172 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4173 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4176 number_points
= get_points(number
, uval
);
4177 if (number_points
< cparam
->minimum
.custom_points
||
4178 number_points
> cparam
->maximum
.custom_points
)
4181 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
4184 case PPD_CUSTOM_PASSCODE
:
4185 for (uval
= val
; *uval
; uval
++)
4186 if (!isdigit(*uval
& 255))
4189 case PPD_CUSTOM_PASSWORD
:
4190 case PPD_CUSTOM_STRING
:
4191 integer
= (long)strlen(val
);
4192 if (integer
< cparam
->minimum
.custom_string
||
4193 integer
> cparam
->maximum
.custom_string
)
4196 snprintf(buffer
, bufsize
, "Custom.%s", val
);
4202 const char *prefix
= "{"; /* Prefix string */
4206 bufend
= buffer
+ bufsize
;
4208 for (cparam
= ppdFirstCustomParam(coption
);
4210 cparam
= ppdNextCustomParam(coption
))
4212 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
4215 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4218 snprintf(bufptr
, bufend
- bufptr
, "%s%s=", prefix
, cparam
->name
);
4219 bufptr
+= strlen(bufptr
);
4222 switch (cparam
->type
)
4224 case PPD_CUSTOM_CURVE
:
4225 case PPD_CUSTOM_INVCURVE
:
4226 case PPD_CUSTOM_REAL
:
4227 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4228 number
< cparam
->minimum
.custom_real
||
4229 number
> cparam
->maximum
.custom_real
)
4232 snprintf(bufptr
, bufend
- bufptr
, "%g", number
);
4235 case PPD_CUSTOM_INT
:
4236 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4237 integer
== LONG_MAX
||
4238 integer
< cparam
->minimum
.custom_int
||
4239 integer
> cparam
->maximum
.custom_int
)
4242 snprintf(bufptr
, bufend
- bufptr
, "%ld", integer
);
4245 case PPD_CUSTOM_POINTS
:
4246 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4248 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4249 (uval
= cgiGetVariable(keyword
)) == NULL
||
4250 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
4251 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
4252 strcmp(uval
, "mm") && strcmp(uval
, "m")))
4255 number_points
= get_points(number
, uval
);
4256 if (number_points
< cparam
->minimum
.custom_points
||
4257 number_points
> cparam
->maximum
.custom_points
)
4260 snprintf(bufptr
, bufend
- bufptr
, "%g%s", number
, uval
);
4263 case PPD_CUSTOM_PASSCODE
:
4264 for (uval
= val
; *uval
; uval
++)
4265 if (!isdigit(*uval
& 255))
4268 case PPD_CUSTOM_PASSWORD
:
4269 case PPD_CUSTOM_STRING
:
4270 integer
= (long)strlen(val
);
4271 if (integer
< cparam
->minimum
.custom_string
||
4272 integer
> cparam
->maximum
.custom_string
)
4275 if ((bufptr
+ 2) > bufend
)
4281 while (*val
&& bufptr
< bufend
)
4283 if (*val
== '\\' || *val
== '\"')
4285 if ((bufptr
+ 1) >= bufend
)
4294 if (bufptr
>= bufend
)
4303 bufptr
+= strlen(bufptr
);
4306 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
4309 strcpy(bufptr
, "}");
4317 * 'get_points()' - Get a value in points.
4320 static double /* O - Number in points */
4321 get_points(double number
, /* I - Original number */
4322 const char *uval
) /* I - Units */
4324 if (!strcmp(uval
, "mm")) /* Millimeters */
4325 return (number
* 72.0 / 25.4);
4326 else if (!strcmp(uval
, "cm")) /* Centimeters */
4327 return (number
* 72.0 / 2.54);
4328 else if (!strcmp(uval
, "in")) /* Inches */
4329 return (number
* 72.0);
4330 else if (!strcmp(uval
, "ft")) /* Feet */
4331 return (number
* 72.0 * 12.0);
4332 else if (!strcmp(uval
, "m")) /* Meters */
4333 return (number
* 72.0 / 0.0254);
4340 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".