2 * "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2010 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
);
148 if (!strcmp(op
, "set-allowed-users"))
149 do_set_allowed_users(http
);
150 else if (!strcmp(op
, "set-as-default"))
151 do_set_default(http
);
152 else if (!strcmp(op
, "set-sharing"))
153 do_set_sharing(http
);
154 else if (!strcmp(op
, "find-new-printers") ||
155 !strcmp(op
, "list-available-printers"))
156 do_list_printers(http
);
157 else if (!strcmp(op
, "add-class"))
158 do_am_class(http
, 0);
159 else if (!strcmp(op
, "add-printer"))
160 do_am_printer(http
, 0);
161 else if (!strcmp(op
, "modify-class"))
162 do_am_class(http
, 1);
163 else if (!strcmp(op
, "modify-printer"))
164 do_am_printer(http
, 1);
165 else if (!strcmp(op
, "delete-class"))
166 do_delete_class(http
);
167 else if (!strcmp(op
, "delete-printer"))
168 do_delete_printer(http
);
169 else if (!strcmp(op
, "set-class-options"))
170 do_set_options(http
, 1);
171 else if (!strcmp(op
, "set-printer-options"))
172 do_set_options(http
, 0);
173 else if (!strcmp(op
, "config-server"))
174 do_config_server(http
);
175 else if (!strcmp(op
, "export-samba"))
177 else if (!strcmp(op
, "add-rss-subscription"))
178 do_add_rss_subscription(http
);
179 else if (!strcmp(op
, "cancel-subscription"))
180 do_cancel_subscription(http
);
184 * Bad operation code - display an error...
187 cgiStartHTML(cgiText(_("Administration")));
188 cgiCopyTemplateLang("error-op.tmpl");
192 else if (op
&& !strcmp(op
, "redirect"))
194 const char *url
; /* Redirection URL... */
195 char prefix
[1024]; /* URL prefix */
199 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
200 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
202 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
203 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
205 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
207 if ((url
= cgiGetVariable("URL")) != NULL
)
209 char encoded
[1024], /* Encoded URL string */
210 *ptr
; /* Pointer into encoded string */
217 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
219 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
222 * Percent-encode this character; safe because we have at least 4
223 * bytes left in the array...
226 sprintf(ptr
, "%%%02X", *url
& 255);
238 * URL was too long, just redirect to the admin page...
241 printf("Location: %s/admin\n\n", prefix
);
246 * URL is OK, redirect there...
249 printf("Location: %s%s\n\n", prefix
, encoded
);
253 printf("Location: %s/admin\n\n", prefix
);
258 * Form data but no operation code - display an error...
261 cgiStartHTML(cgiText(_("Administration")));
262 cgiCopyTemplateLang("error-op.tmpl");
267 * Close the HTTP server connection...
273 * Return with no errors...
281 * 'choose_device_cb()' - Add a device to the device selection page.
286 const char *device_class
, /* I - Class */
287 const char *device_id
, /* I - 1284 device ID */
288 const char *device_info
, /* I - Description */
289 const char *device_make_and_model
, /* I - Make and model */
290 const char *device_uri
, /* I - Device URI */
291 const char *device_location
, /* I - Location */
292 const char *title
) /* I - Page title */
295 * For modern browsers, start a multi-part page so we can show that something
296 * is happening. Non-modern browsers just get everything at the end...
299 if (current_device
== 0 && cgiSupportsMultipart())
303 cgiCopyTemplateLang("choose-device.tmpl");
310 * Add the device to the array...
313 cgiSetArray("device_class", current_device
, device_class
);
314 cgiSetArray("device_id", current_device
, device_id
);
315 cgiSetArray("device_info", current_device
, device_info
);
316 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
317 cgiSetArray("device_uri", current_device
, device_uri
);
318 cgiSetArray("device_location", current_device
, device_location
);
325 * 'do_add_rss_subscription()' - Add a RSS subscription.
329 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
331 ipp_t
*request
, /* IPP request data */
332 *response
; /* IPP response data */
333 char rss_uri
[1024]; /* RSS notify-recipient URI */
334 int num_events
; /* Number of events */
335 const char *events
[12], /* Subscribed events */
336 *subscription_name
, /* Subscription name */
337 *printer_uri
, /* Printer URI */
338 *ptr
, /* Pointer into name */
339 *user
; /* Username */
340 int max_events
; /* Maximum number of events */
344 * See if we have all of the required information...
347 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
348 printer_uri
= cgiGetVariable("PRINTER_URI");
351 if (cgiGetVariable("EVENT_JOB_CREATED"))
352 events
[num_events
++] = "job-created";
353 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
354 events
[num_events
++] = "job-completed";
355 if (cgiGetVariable("EVENT_JOB_STOPPED"))
356 events
[num_events
++] = "job-stopped";
357 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
358 events
[num_events
++] = "job-config-changed";
359 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
360 events
[num_events
++] = "printer-stopped";
361 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
362 events
[num_events
++] = "printer-added";
363 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
364 events
[num_events
++] = "printer-modified";
365 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
366 events
[num_events
++] = "printer-deleted";
367 if (cgiGetVariable("EVENT_SERVER_STARTED"))
368 events
[num_events
++] = "server-started";
369 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
370 events
[num_events
++] = "server-stopped";
371 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
372 events
[num_events
++] = "server-restarted";
373 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
374 events
[num_events
++] = "server-audit";
376 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
377 max_events
= atoi(ptr
);
381 if (!subscription_name
|| !printer_uri
|| !num_events
||
382 max_events
<= 0 || max_events
> 9999)
385 * Don't have everything we need, so get the available printers
386 * and classes and (re)show the add page...
389 if (cgiGetVariable("EVENT_JOB_CREATED"))
390 cgiSetVariable("EVENT_JOB_CREATED", "CHECKED");
391 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
392 cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED");
393 if (cgiGetVariable("EVENT_JOB_STOPPED"))
394 cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED");
395 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
396 cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED");
397 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
398 cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED");
399 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
400 cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED");
401 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
402 cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED");
403 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
404 cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED");
405 if (cgiGetVariable("EVENT_SERVER_STARTED"))
406 cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED");
407 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
408 cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED");
409 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
410 cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED");
411 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
412 cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED");
414 request
= ippNewRequest(CUPS_GET_PRINTERS
);
415 response
= cupsDoRequest(http
, request
, "/");
417 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
421 cgiStartHTML(cgiText(_("Add RSS Subscription")));
423 cgiCopyTemplateLang("add-rss-subscription.tmpl");
430 * Make sure we have a username...
433 if ((user
= getenv("REMOTE_USER")) == NULL
)
435 puts("Status: 401\n");
440 * Validate the subscription name...
443 for (ptr
= subscription_name
; *ptr
; ptr
++)
444 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
445 *ptr
== '?' || *ptr
== '#')
450 cgiSetVariable("ERROR",
451 cgiText(_("The subscription name may not "
452 "contain spaces, slashes (/), question marks (?), "
453 "or the pound sign (#).")));
454 cgiStartHTML(_("Add RSS Subscription"));
455 cgiCopyTemplateLang("error.tmpl");
461 * Add the subscription...
464 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
465 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
466 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
467 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
470 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
471 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
474 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
476 if (!strcasecmp(printer_uri
, "#ALL#"))
477 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
478 NULL
, "ipp://localhost/");
480 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
483 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
486 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
487 "notify-recipient-uri", NULL
, rss_uri
);
488 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
489 num_events
, NULL
, events
);
490 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
491 "notify-lease-duration", 0);
493 ippDelete(cupsDoRequest(http
, request
, "/"));
495 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
497 puts("Status: 401\n");
500 else if (cupsLastError() > IPP_OK_CONFLICT
)
502 cgiStartHTML(_("Add RSS Subscription"));
503 cgiShowIPPError(_("Unable to add RSS subscription:"));
508 * Redirect successful updates back to the admin page...
511 cgiSetVariable("refresh_page", "5;URL=/admin");
512 cgiStartHTML(_("Add RSS Subscription"));
513 cgiCopyTemplateLang("subscription-added.tmpl");
521 * 'do_am_class()' - Add or modify a class.
525 do_am_class(http_t
*http
, /* I - HTTP connection */
526 int modify
) /* I - Modify the printer? */
528 int i
, j
; /* Looping vars */
529 int element
; /* Element number */
530 int num_printers
; /* Number of printers */
531 ipp_t
*request
, /* IPP request */
532 *response
; /* IPP response */
533 ipp_attribute_t
*attr
; /* member-uris attribute */
534 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
535 const char *name
, /* Pointer to class name */
536 *op
, /* Operation name */
537 *ptr
; /* Pointer to CGI variable */
538 const char *title
; /* Title of page */
539 static const char * const pattrs
[] = /* Requested printer attributes */
547 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
548 op
= cgiGetVariable("OP");
549 name
= cgiGetVariable("PRINTER_NAME");
551 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
554 * Build a CUPS_GET_PRINTERS request, which requires the
555 * following attributes:
558 * attributes-natural-language
561 request
= ippNewRequest(CUPS_GET_PRINTERS
);
563 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
565 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
566 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
567 CUPS_PRINTER_IMPLICIT
);
570 * Do the request and get back a response...
575 cgiSetVariable("OP", op
);
577 cgiSetVariable("PRINTER_NAME", name
);
579 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
582 * Create MEMBER_URIS and MEMBER_NAMES arrays...
585 for (element
= 0, attr
= response
->attrs
;
588 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
590 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
591 (!name
|| strcasecmp(name
, ptr
+ 1)))
594 * Don't show the current class...
597 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
602 for (element
= 0, attr
= response
->attrs
;
605 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
607 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
610 * Don't show the current class...
613 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
618 num_printers
= cgiGetSize("MEMBER_URIS");
628 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
629 * following attributes:
632 * attributes-natural-language
636 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
638 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
639 "localhost", 0, "/classes/%s", name
);
640 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
643 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
644 "requested-attributes",
645 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
649 * Do the request and get back a response...
652 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
654 if ((attr
= ippFindAttribute(response
, "member-names",
655 IPP_TAG_NAME
)) != NULL
)
658 * Mark any current members in the class...
661 for (j
= 0; j
< num_printers
; j
++)
662 cgiSetArray("MEMBER_SELECTED", j
, "");
664 for (i
= 0; i
< attr
->num_values
; i
++)
666 for (j
= 0; j
< num_printers
; j
++)
668 if (!strcasecmp(attr
->values
[i
].string
.text
,
669 cgiGetArray("MEMBER_NAMES", j
)))
671 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
678 if ((attr
= ippFindAttribute(response
, "printer-info",
679 IPP_TAG_TEXT
)) != NULL
)
680 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
682 if ((attr
= ippFindAttribute(response
, "printer-location",
683 IPP_TAG_TEXT
)) != NULL
)
684 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
690 * Update the location and description of an existing printer...
694 cgiCopyTemplateLang("modify-class.tmpl");
699 * Get the name, location, and description for a new printer...
703 cgiCopyTemplateLang("add-class.tmpl");
714 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
715 cgiCopyTemplateLang("error.tmpl");
720 for (ptr
= name
; *ptr
; ptr
++)
721 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
724 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
726 cgiSetVariable("ERROR",
727 cgiText(_("The class name may only contain up to "
728 "127 printable characters and may not "
729 "contain spaces, slashes (/), or the "
730 "pound sign (#).")));
732 cgiCopyTemplateLang("error.tmpl");
738 * Build a CUPS_ADD_CLASS request, which requires the following
742 * attributes-natural-language
746 * printer-is-accepting-jobs
751 request
= ippNewRequest(CUPS_ADD_CLASS
);
753 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
754 "localhost", 0, "/classes/%s", name
);
755 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
758 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
759 NULL
, cgiGetVariable("PRINTER_LOCATION"));
761 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
762 NULL
, cgiGetVariable("PRINTER_INFO"));
764 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
766 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
769 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
771 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
772 num_printers
, NULL
, NULL
);
773 for (i
= 0; i
< num_printers
; i
++)
774 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
778 * Do the request and get back a response...
781 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
783 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
785 puts("Status: 401\n");
788 else if (cupsLastError() > IPP_OK_CONFLICT
)
791 cgiShowIPPError(modify
? _("Unable to modify class:") :
792 _("Unable to add class:"));
797 * Redirect successful updates back to the class page...
800 char refresh
[1024]; /* Refresh URL */
802 cgiFormEncode(uri
, name
, sizeof(uri
));
803 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
805 cgiSetVariable("refresh_page", refresh
);
810 cgiCopyTemplateLang("class-modified.tmpl");
812 cgiCopyTemplateLang("class-added.tmpl");
820 * 'do_am_printer()' - Add or modify a printer.
824 do_am_printer(http_t
*http
, /* I - HTTP connection */
825 int modify
) /* I - Modify the printer? */
827 int i
; /* Looping var */
828 ipp_attribute_t
*attr
; /* Current attribute */
829 ipp_t
*request
, /* IPP request */
830 *response
, /* IPP response */
831 *oldinfo
; /* Old printer information */
832 const cgi_file_t
*file
; /* Uploaded file, if any */
833 const char *var
; /* CGI variable */
834 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
835 *uriptr
; /* Pointer into URI */
836 int maxrate
; /* Maximum baud rate */
837 char baudrate
[255]; /* Baud rate string */
838 const char *name
, /* Pointer to class name */
839 *ptr
; /* Pointer to CGI variable */
840 const char *title
; /* Title of page */
841 static int baudrates
[] = /* Baud rates */
856 ptr
= cgiGetVariable("DEVICE_URI");
857 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
858 ptr
? ptr
: "(null)");
860 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
865 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
866 * following attributes:
869 * attributes-natural-language
873 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
875 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
876 "localhost", 0, "/printers/%s",
877 cgiGetVariable("PRINTER_NAME"));
878 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
882 * Do the request and get back a response...
885 oldinfo
= cupsDoRequest(http
, request
, "/");
894 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
895 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
896 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
897 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
900 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
902 for (ptr
= name
; *ptr
; ptr
++)
903 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
906 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
908 cgiSetVariable("ERROR",
909 cgiText(_("The printer name may only contain up to "
910 "127 printable characters and may not "
911 "contain spaces, slashes (/), or the "
912 "pound sign (#).")));
914 cgiCopyTemplateLang("error.tmpl");
920 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
922 if ((uriptr
= strrchr(var
, '|')) != NULL
)
925 * Extract make and make/model from device URI string...
928 char make
[1024], /* Make string */
929 *makeptr
; /* Pointer into make */
934 strlcpy(make
, uriptr
, sizeof(make
));
936 if ((makeptr
= strchr(make
, ' ')) != NULL
)
938 else if ((makeptr
= strchr(make
, '-')) != NULL
)
940 else if (!strncasecmp(make
, "laserjet", 8) ||
941 !strncasecmp(make
, "deskjet", 7) ||
942 !strncasecmp(make
, "designjet", 9))
944 else if (!strncasecmp(make
, "phaser", 6))
945 strcpy(make
, "Xerox");
946 else if (!strncasecmp(make
, "stylus", 6))
947 strcpy(make
, "Epson");
949 strcpy(make
, "Generic");
951 if (!cgiGetVariable("CURRENT_MAKE"))
952 cgiSetVariable("CURRENT_MAKE", make
);
954 cgiSetVariable("PPD_MAKE", make
);
956 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
957 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
961 char template[128], /* Template name */
962 *tptr
; /* Pointer into template name */
964 cgiSetVariable("PRINTER_INFO", uriptr
);
966 for (tptr
= template;
967 tptr
< (template + sizeof(template) - 1) && *uriptr
;
969 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
972 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
975 else if (*uriptr
== '?' || *uriptr
== '(')
980 cgiSetVariable("TEMPLATE_NAME", template);
988 * Look for devices so the user can pick something...
991 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
993 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
994 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
997 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
998 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
1002 * Scan for devices for up to 30 seconds...
1005 fputs("DEBUG: Getting list of devices...\n", stderr
);
1008 if (cupsGetDevices(http
, 30, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
1009 (cups_device_cb_t
)choose_device_cb
,
1010 (void *)title
) == IPP_OK
)
1012 fputs("DEBUG: Got device list!\n", stderr
);
1014 if (cgiSupportsMultipart())
1015 cgiStartMultipart();
1017 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1018 cgiStartHTML(title
);
1019 cgiCopyTemplateLang("choose-device.tmpl");
1022 if (cgiSupportsMultipart())
1028 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1029 cupsLastError(), cupsLastErrorString());
1030 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1032 puts("Status: 401\n");
1037 cgiStartHTML(title
);
1038 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1039 _("Unable to add printer:"));
1045 else if (strchr(var
, '/') == NULL
)
1047 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
1050 * Set the current device URI for the form to the old one...
1053 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
1054 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
1058 * User needs to set the full URI...
1061 cgiStartHTML(title
);
1062 cgiCopyTemplateLang("choose-uri.tmpl");
1065 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1068 * Need baud rate, parity, etc.
1071 if ((var
= strchr(var
, '?')) != NULL
&&
1072 strncmp(var
, "?baud=", 6) == 0)
1073 maxrate
= atoi(var
+ 6);
1077 for (i
= 0; i
< 10; i
++)
1078 if (baudrates
[i
] > maxrate
)
1082 sprintf(baudrate
, "%d", baudrates
[i
]);
1083 cgiSetArray("BAUDRATES", i
, baudrate
);
1086 cgiStartHTML(title
);
1087 cgiCopyTemplateLang("choose-serial.tmpl");
1090 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
1092 cgiStartHTML(title
);
1097 * Update the location and description of an existing printer...
1102 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
1103 IPP_TAG_TEXT
)) != NULL
)
1104 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
1106 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
1107 IPP_TAG_TEXT
)) != NULL
)
1108 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
1110 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
1111 IPP_TAG_BOOLEAN
)) != NULL
)
1112 cgiSetVariable("PRINTER_IS_SHARED",
1113 attr
->values
[0].boolean
? "1" : "0");
1116 cgiCopyTemplateLang("modify-printer.tmpl");
1121 * Get the name, location, and description for a new printer...
1125 if (!strncmp(var
, "usb:", 4))
1126 cgiSetVariable("printer_is_shared", "1");
1128 #endif /* __APPLE__ */
1129 cgiSetVariable("printer_is_shared", "0");
1131 cgiCopyTemplateLang("add-printer.tmpl");
1142 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1144 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
1147 * Get the PPD file...
1150 int fd
; /* PPD file */
1151 char filename
[1024]; /* PPD filename */
1152 ppd_file_t
*ppd
; /* PPD information */
1153 char buffer
[1024]; /* Buffer */
1154 int bytes
; /* Number of bytes */
1155 http_status_t get_status
; /* Status of GET */
1158 /* TODO: Use cupsGetFile() API... */
1159 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1161 if (httpGet(http
, uri
))
1164 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1166 if (get_status
!= HTTP_OK
)
1170 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1171 uri
, get_status
, httpStatus(get_status
));
1173 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1175 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1176 write(fd
, buffer
, bytes
);
1180 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1182 if (ppd
->manufacturer
)
1183 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1186 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1193 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1194 filename
, ppdErrorString(ppdLastError(&bytes
)));
1202 "ERROR: Unable to create temporary file for PPD file: %s\n",
1208 * Build a CUPS_GET_PPDS request, which requires the following
1211 * attributes-charset
1212 * attributes-natural-language
1216 request
= ippNewRequest(CUPS_GET_PPDS
);
1218 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1219 NULL
, "ipp://localhost/printers/");
1221 if ((var
= cgiGetVariable("CURRENT_MAKE")) == NULL
)
1222 var
= cgiGetVariable("PPD_MAKE");
1223 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1225 const char *make_model
; /* Make and model */
1228 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1229 "ppd-make", NULL
, var
);
1231 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1232 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1233 "ppd-make-and-model", NULL
, make_model
);
1236 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1237 "requested-attributes", NULL
, "ppd-make");
1240 * Do the request and get back a response...
1243 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1246 * Got the list of PPDs, see if the user has selected a make...
1249 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1252 * No PPD files with this make, try again with all makes...
1255 ippDelete(response
);
1257 request
= ippNewRequest(CUPS_GET_PPDS
);
1259 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1260 NULL
, "ipp://localhost/printers/");
1262 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1263 "requested-attributes", NULL
, "ppd-make");
1265 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1266 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1268 cgiStartHTML(title
);
1269 cgiCopyTemplateLang("choose-make.tmpl");
1272 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1274 cgiStartHTML(title
);
1275 cgiCopyTemplateLang("choose-make.tmpl");
1281 * Let the user choose a model...
1284 cgiStartHTML(title
);
1285 if (!cgiGetVariable("PPD_MAKE"))
1286 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1288 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1289 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1290 cgiCopyTemplateLang("choose-model.tmpl");
1294 ippDelete(response
);
1298 cgiStartHTML(title
);
1299 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1300 cgiCopyTemplateLang("error.tmpl");
1307 * Build a CUPS_ADD_PRINTER request, which requires the following
1310 * attributes-charset
1311 * attributes-natural-language
1317 * printer-is-accepting-jobs
1322 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1324 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1325 "localhost", 0, "/printers/%s",
1326 cgiGetVariable("PRINTER_NAME"));
1327 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1330 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1331 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1333 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1334 NULL
, cgiGetVariable("PRINTER_INFO"));
1338 var
= cgiGetVariable("PPD_NAME");
1339 if (strcmp(var
, "__no_change__"))
1340 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1344 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1347 * Strip make and model from URI...
1350 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1353 if (!strncmp(uri
, "serial:", 7))
1356 * Update serial port URI to include baud rate, etc.
1359 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1360 uriptr
= uri
+ strlen(uri
);
1362 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1363 "?baud=%s+bits=%s+parity=%s+flow=%s",
1364 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1365 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1368 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1371 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1373 var
= cgiGetVariable("printer_is_shared");
1374 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1375 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1377 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1381 * Do the request and get back a response...
1385 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1387 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1389 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1391 puts("Status: 401\n");
1394 else if (cupsLastError() > IPP_OK_CONFLICT
)
1396 cgiStartHTML(title
);
1397 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1398 _("Unable to add printer:"));
1403 * Redirect successful updates back to the printer page...
1406 char refresh
[1024]; /* Refresh URL */
1409 cgiFormEncode(uri
, name
, sizeof(uri
));
1411 snprintf(refresh
, sizeof(refresh
),
1412 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1414 cgiSetVariable("refresh_page", refresh
);
1416 cgiStartHTML(title
);
1418 cgiCopyTemplateLang("printer-modified.tmpl");
1423 * Set the printer options...
1426 cgiSetVariable("OP", "set-printer-options");
1427 do_set_options(http
, 0);
1440 * 'do_cancel_subscription()' - Cancel a subscription.
1444 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1446 ipp_t
*request
; /* IPP request data */
1447 const char *var
, /* Form variable */
1448 *user
; /* Username */
1449 int id
; /* Subscription ID */
1453 * See if we have all of the required information...
1456 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1463 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1464 cgiStartHTML(_("Cancel RSS Subscription"));
1465 cgiCopyTemplateLang("error.tmpl");
1471 * Require a username...
1474 if ((user
= getenv("REMOTE_USER")) == NULL
)
1476 puts("Status: 401\n");
1481 * Cancel the subscription...
1484 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1486 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1487 NULL
, "ipp://localhost/");
1488 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1489 "notify-subscription-id", id
);
1491 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1494 ippDelete(cupsDoRequest(http
, request
, "/"));
1496 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1498 puts("Status: 401\n");
1501 else if (cupsLastError() > IPP_OK_CONFLICT
)
1503 cgiStartHTML(_("Cancel RSS Subscription"));
1504 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1509 * Redirect successful updates back to the admin page...
1512 cgiSetVariable("refresh_page", "5;URL=/admin");
1513 cgiStartHTML(_("Cancel RSS Subscription"));
1514 cgiCopyTemplateLang("subscription-canceled.tmpl");
1522 * 'do_config_server()' - Configure server settings.
1526 do_config_server(http_t
*http
) /* I - HTTP connection */
1528 if (cgiGetVariable("CHANGESETTINGS"))
1531 * Save basic setting changes...
1534 int num_settings
; /* Number of server settings */
1535 cups_option_t
*settings
; /* Server settings */
1536 int advanced
, /* Advanced settings shown? */
1537 changed
; /* Have settings changed? */
1538 const char *debug_logging
, /* DEBUG_LOGGING value */
1539 *remote_admin
, /* REMOTE_ADMIN value */
1540 *remote_any
, /* REMOTE_ANY value */
1542 /* REMOTE_PRINTERS value */
1543 *share_printers
,/* SHARE_PRINTERS value */
1545 /* USER_CANCEL_ANY value */
1546 *browse_web_if
= NULL
,
1547 /* BrowseWebIF value */
1548 *preserve_job_history
= NULL
,
1549 /* PreserveJobHistory value */
1550 *preserve_job_files
= NULL
,
1551 /* PreserveJobFiles value */
1552 *max_clients
= NULL
,
1553 /* MaxClients value */
1556 *max_log_size
= NULL
;
1557 /* MaxLogSize value */
1558 char local_protocols
[255],
1559 /* BrowseLocalProtocols */
1560 remote_protocols
[255];
1561 /* BrowseRemoteProtocols */
1562 const char *current_browse_web_if
,
1563 /* BrowseWebIF value */
1564 *current_preserve_job_history
,
1565 /* PreserveJobHistory value */
1566 *current_preserve_job_files
,
1567 /* PreserveJobFiles value */
1568 *current_max_clients
,
1569 /* MaxClients value */
1572 *current_max_log_size
,
1573 /* MaxLogSize value */
1574 *current_local_protocols
,
1575 /* BrowseLocalProtocols */
1576 *current_remote_protocols
;
1577 /* BrowseRemoteProtocols */
1579 char default_auth_type
[255];
1580 /* DefaultAuthType value */
1581 const char *val
; /* Setting value */
1582 #endif /* HAVE_GSSAPI */
1586 * Get the checkbox values from the form...
1589 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1590 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1591 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1592 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1593 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1594 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1596 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1600 * Get advanced settings...
1603 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1604 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1605 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1606 max_clients
= cgiGetVariable("MAX_CLIENTS");
1607 max_jobs
= cgiGetVariable("MAX_JOBS");
1608 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1610 if (!max_clients
|| atoi(max_clients
) <= 0)
1611 max_clients
= "100";
1613 if (!max_jobs
|| atoi(max_jobs
) <= 0)
1616 if (!max_log_size
|| atof(max_log_size
) <= 0.0)
1617 max_log_size
= "1m";
1619 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1620 strcpy(local_protocols
, "cups");
1622 local_protocols
[0] = '\0';
1625 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1627 if (local_protocols
[0])
1628 strcat(local_protocols
, " dnssd");
1630 strcat(local_protocols
, "dnssd");
1632 #endif /* HAVE_DNSSD */
1635 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1637 if (local_protocols
[0])
1638 strcat(local_protocols
, " ldap");
1640 strcat(local_protocols
, "ldap");
1642 #endif /* HAVE_LDAP */
1645 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1647 if (local_protocols
[0])
1648 strcat(local_protocols
, " slp");
1650 strcat(local_protocols
, "slp");
1652 #endif /* HAVE_SLP */
1654 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1655 strcpy(remote_protocols
, "cups");
1657 remote_protocols
[0] = '\0';
1660 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1662 if (remote_protocols
[0])
1663 strcat(remote_protocols
, " ldap");
1665 strcat(remote_protocols
, "ldap");
1667 #endif /* HAVE_LDAP */
1670 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1672 if (remote_protocols
[0])
1673 strcat(remote_protocols
, " slp");
1675 strcat(remote_protocols
, "slp");
1677 #endif /* HAVE_SLP */
1681 * Get the current server settings...
1684 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1686 cgiStartHTML(cgiText(_("Change Settings")));
1687 cgiSetVariable("MESSAGE",
1688 cgiText(_("Unable to change server settings:")));
1689 cgiSetVariable("ERROR", cupsLastErrorString());
1690 cgiCopyTemplateLang("error.tmpl");
1697 * Get authentication settings...
1700 if (cgiGetVariable("KERBEROS"))
1701 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1704 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1706 if (!val
|| !strcasecmp(val
, "Negotiate"))
1707 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1709 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1712 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1713 #endif /* HAVE_GSSAPI */
1715 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1717 current_browse_web_if
= "No";
1719 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1722 current_preserve_job_history
= "Yes";
1724 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1727 current_preserve_job_files
= "No";
1729 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1731 current_max_clients
= "100";
1733 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1735 current_max_jobs
= "500";
1737 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1739 current_max_log_size
= "1m";
1741 if ((current_local_protocols
= cupsGetOption("BrowseLocalProtocols",
1744 current_local_protocols
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
1746 if ((current_remote_protocols
= cupsGetOption("BrowseRemoteProtocols",
1749 current_remote_protocols
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
1752 * See if the settings have changed...
1755 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1756 num_settings
, settings
)) ||
1757 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1758 num_settings
, settings
)) ||
1759 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1760 num_settings
, settings
)) ||
1761 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1762 num_settings
, settings
)) ||
1763 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1764 num_settings
, settings
)) ||
1766 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1767 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1768 num_settings
, settings
)) ||
1769 #endif /* HAVE_GSSAPI */
1770 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1771 num_settings
, settings
));
1773 if (advanced
&& !changed
)
1774 changed
= strcasecmp(local_protocols
, current_local_protocols
) ||
1775 strcasecmp(remote_protocols
, current_remote_protocols
) ||
1776 strcasecmp(browse_web_if
, current_browse_web_if
) ||
1777 strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1778 strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1779 strcasecmp(max_clients
, current_max_clients
) ||
1780 strcasecmp(max_jobs
, current_max_jobs
) ||
1781 strcasecmp(max_log_size
, current_max_log_size
);
1786 * Settings *have* changed, so save the changes...
1789 cupsFreeOptions(num_settings
, settings
);
1792 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1793 debug_logging
, num_settings
, &settings
);
1794 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1795 remote_admin
, num_settings
, &settings
);
1796 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1797 remote_any
, num_settings
, &settings
);
1798 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1799 remote_printers
, num_settings
, &settings
);
1800 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1801 share_printers
, num_settings
, &settings
);
1802 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1803 user_cancel_any
, num_settings
, &settings
);
1805 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1806 num_settings
, &settings
);
1807 #endif /* HAVE_GSSAPI */
1812 * Add advanced settings...
1815 if (strcasecmp(local_protocols
, current_local_protocols
))
1816 num_settings
= cupsAddOption("BrowseLocalProtocols", local_protocols
,
1817 num_settings
, &settings
);
1818 if (strcasecmp(remote_protocols
, current_remote_protocols
))
1819 num_settings
= cupsAddOption("BrowseRemoteProtocols", remote_protocols
,
1820 num_settings
, &settings
);
1821 if (strcasecmp(browse_web_if
, current_browse_web_if
))
1822 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1823 num_settings
, &settings
);
1824 if (strcasecmp(preserve_job_history
, current_preserve_job_history
))
1825 num_settings
= cupsAddOption("PreserveJobHistory",
1826 preserve_job_history
, num_settings
,
1828 if (strcasecmp(preserve_job_files
, current_preserve_job_files
))
1829 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1830 num_settings
, &settings
);
1831 if (strcasecmp(max_clients
, current_max_clients
))
1832 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1834 if (strcasecmp(max_jobs
, current_max_jobs
))
1835 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1837 if (strcasecmp(max_log_size
, current_max_log_size
))
1838 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1842 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1844 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1846 puts("Status: 401\n");
1850 cgiStartHTML(cgiText(_("Change Settings")));
1851 cgiSetVariable("MESSAGE",
1852 cgiText(_("Unable to change server settings:")));
1853 cgiSetVariable("ERROR", cupsLastErrorString());
1854 cgiCopyTemplateLang("error.tmpl");
1859 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1861 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1862 cgiStartHTML(cgiText(_("Change Settings")));
1863 cgiCopyTemplateLang("restart.tmpl");
1872 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1873 cgiStartHTML(cgiText(_("Change Settings")));
1874 cgiCopyTemplateLang("norestart.tmpl");
1877 cupsFreeOptions(num_settings
, settings
);
1881 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1884 * Save hand-edited config file...
1887 http_status_t status
; /* PUT status */
1888 char tempfile
[1024]; /* Temporary new cupsd.conf */
1889 int tempfd
; /* Temporary file descriptor */
1890 cups_file_t
*temp
; /* Temporary file */
1891 const char *start
, /* Start of line */
1892 *end
; /* End of line */
1896 * Create a temporary file for the new cupsd.conf file...
1899 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1901 cgiStartHTML(cgiText(_("Edit Configuration File")));
1902 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1903 cgiSetVariable("ERROR", strerror(errno
));
1904 cgiCopyTemplateLang("error.tmpl");
1911 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1913 cgiStartHTML(cgiText(_("Edit Configuration File")));
1914 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1915 cgiSetVariable("ERROR", strerror(errno
));
1916 cgiCopyTemplateLang("error.tmpl");
1926 * Copy the cupsd.conf text from the form variable...
1929 start
= cgiGetVariable("CUPSDCONF");
1932 if ((end
= strstr(start
, "\r\n")) == NULL
)
1933 if ((end
= strstr(start
, "\n")) == NULL
)
1934 end
= start
+ strlen(start
);
1936 cupsFileWrite(temp
, start
, end
- start
);
1937 cupsFilePutChar(temp
, '\n');
1941 else if (*end
== '\n')
1947 cupsFileClose(temp
);
1950 * Upload the configuration file to the server...
1953 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1955 if (status
== HTTP_UNAUTHORIZED
)
1957 puts("Status: 401\n");
1961 else if (status
!= HTTP_CREATED
)
1963 cgiSetVariable("MESSAGE",
1964 cgiText(_("Unable to upload cupsd.conf file:")));
1965 cgiSetVariable("ERROR", httpStatus(status
));
1967 cgiStartHTML(cgiText(_("Edit Configuration File")));
1968 cgiCopyTemplateLang("error.tmpl");
1972 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1974 cgiStartHTML(cgiText(_("Edit Configuration File")));
1975 cgiCopyTemplateLang("restart.tmpl");
1984 struct stat info
; /* cupsd.conf information */
1985 cups_file_t
*cupsd
; /* cupsd.conf file */
1986 char *buffer
, /* Buffer for entire file */
1987 *bufptr
, /* Pointer into buffer */
1988 *bufend
; /* End of buffer */
1989 int ch
; /* Character from file */
1990 char filename
[1024]; /* Filename */
1991 const char *server_root
; /* Location of config files */
1995 * Locate the cupsd.conf file...
1998 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1999 server_root
= CUPS_SERVERROOT
;
2001 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
2004 * Figure out the size...
2007 if (stat(filename
, &info
))
2009 cgiStartHTML(cgiText(_("Edit Configuration File")));
2010 cgiSetVariable("MESSAGE",
2011 cgiText(_("Unable to access cupsd.conf file:")));
2012 cgiSetVariable("ERROR", strerror(errno
));
2013 cgiCopyTemplateLang("error.tmpl");
2020 if (info
.st_size
> (1024 * 1024))
2022 cgiStartHTML(cgiText(_("Edit Configuration File")));
2023 cgiSetVariable("MESSAGE",
2024 cgiText(_("Unable to access cupsd.conf file:")));
2025 cgiSetVariable("ERROR",
2026 cgiText(_("Unable to edit cupsd.conf files larger than "
2028 cgiCopyTemplateLang("error.tmpl");
2031 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
2032 (long)info
.st_size
);
2037 * Open the cupsd.conf file...
2040 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
2043 * Unable to open - log an error...
2046 cgiStartHTML(cgiText(_("Edit Configuration File")));
2047 cgiSetVariable("MESSAGE",
2048 cgiText(_("Unable to access cupsd.conf file:")));
2049 cgiSetVariable("ERROR", strerror(errno
));
2050 cgiCopyTemplateLang("error.tmpl");
2058 * Allocate memory and load the file into a string buffer...
2061 if ((buffer
= calloc(1, info
.st_size
+ 1)) != NULL
)
2063 cupsFileRead(cupsd
, buffer
, info
.st_size
);
2064 cgiSetVariable("CUPSDCONF", buffer
);
2068 cupsFileClose(cupsd
);
2071 * Then get the default cupsd.conf file and put that into a string as
2075 strlcat(filename
, ".default", sizeof(filename
));
2077 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
2078 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
2080 if ((buffer
= calloc(1, 2 * info
.st_size
+ 1)) != NULL
)
2082 bufend
= buffer
+ 2 * info
.st_size
- 1;
2084 for (bufptr
= buffer
;
2085 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
2087 if (ch
== '\\' || ch
== '\"')
2092 else if (ch
== '\n')
2097 else if (ch
== '\t')
2108 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
2112 cupsFileClose(cupsd
);
2116 * Show the current config file...
2119 cgiStartHTML(cgiText(_("Edit Configuration File")));
2121 cgiCopyTemplateLang("edit-config.tmpl");
2129 * 'do_delete_class()' - Delete a class.
2133 do_delete_class(http_t
*http
) /* I - HTTP connection */
2135 ipp_t
*request
; /* IPP request */
2136 char uri
[HTTP_MAX_URI
]; /* Job URI */
2137 const char *pclass
; /* Printer class name */
2141 * Get form variables...
2144 if (cgiGetVariable("CONFIRM") == NULL
)
2146 cgiStartHTML(cgiText(_("Delete Class")));
2147 cgiCopyTemplateLang("class-confirm.tmpl");
2152 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2153 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2154 "localhost", 0, "/classes/%s", pclass
);
2157 cgiStartHTML(cgiText(_("Delete Class")));
2158 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2159 cgiCopyTemplateLang("error.tmpl");
2165 * Build a CUPS_DELETE_CLASS request, which requires the following
2168 * attributes-charset
2169 * attributes-natural-language
2173 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2175 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2179 * Do the request and get back a response...
2182 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2185 * Show the results...
2188 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2190 puts("Status: 401\n");
2193 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2196 * Redirect successful updates back to the classes page...
2199 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2202 cgiStartHTML(cgiText(_("Delete Class")));
2204 if (cupsLastError() > IPP_OK_CONFLICT
)
2205 cgiShowIPPError(_("Unable to delete class:"));
2207 cgiCopyTemplateLang("class-deleted.tmpl");
2214 * 'do_delete_printer()' - Delete a printer.
2218 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2220 ipp_t
*request
; /* IPP request */
2221 char uri
[HTTP_MAX_URI
]; /* Job URI */
2222 const char *printer
; /* Printer printer name */
2226 * Get form variables...
2229 if (cgiGetVariable("CONFIRM") == NULL
)
2231 cgiStartHTML(cgiText(_("Delete Printer")));
2232 cgiCopyTemplateLang("printer-confirm.tmpl");
2237 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2238 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2239 "localhost", 0, "/printers/%s", printer
);
2242 cgiStartHTML(cgiText(_("Delete Printer")));
2243 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2244 cgiCopyTemplateLang("error.tmpl");
2250 * Build a CUPS_DELETE_PRINTER request, which requires the following
2253 * attributes-charset
2254 * attributes-natural-language
2258 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2260 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2264 * Do the request and get back a response...
2267 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2270 * Show the results...
2273 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2275 puts("Status: 401\n");
2278 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2281 * Redirect successful updates back to the printers page...
2284 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2287 cgiStartHTML(cgiText(_("Delete Printer")));
2289 if (cupsLastError() > IPP_OK_CONFLICT
)
2290 cgiShowIPPError(_("Unable to delete printer:"));
2292 cgiCopyTemplateLang("printer-deleted.tmpl");
2299 * 'do_export()' - Export printers to Samba.
2303 do_export(http_t
*http
) /* I - HTTP connection */
2305 int i
, j
; /* Looping vars */
2306 ipp_t
*request
, /* IPP request */
2307 *response
; /* IPP response */
2308 const char *username
, /* Samba username */
2309 *password
, /* Samba password */
2310 *export_all
; /* Export all printers? */
2311 int export_count
, /* Number of printers to export */
2312 printer_count
; /* Number of available printers */
2313 const char *name
, /* What name to pull */
2314 *dest
; /* Current destination */
2315 char ppd
[1024]; /* PPD file */
2322 username
= cgiGetVariable("USERNAME");
2323 password
= cgiGetVariable("PASSWORD");
2324 export_all
= cgiGetVariable("EXPORT_ALL");
2325 export_count
= cgiGetSize("EXPORT_NAME");
2328 * Get list of available printers...
2331 cgiSetSize("PRINTER_NAME", 0);
2332 cgiSetSize("PRINTER_EXPORT", 0);
2334 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2336 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2339 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2340 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2341 CUPS_PRINTER_IMPLICIT
);
2343 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2344 "requested-attributes", NULL
, "printer-name");
2346 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2348 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2349 ippDelete(response
);
2353 printer_count
= cgiGetSize("PRINTER_NAME");
2355 for (i
= 0; i
< printer_count
; i
++)
2357 dest
= cgiGetArray("PRINTER_NAME", i
);
2359 for (j
= 0; j
< export_count
; j
++)
2360 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2363 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2369 * Export or get the printers to export...
2372 if (username
&& *username
&& password
&& *password
&&
2373 (export_all
|| export_count
> 0))
2379 fputs("DEBUG: Export printers...\n", stderr
);
2383 name
= "PRINTER_NAME";
2384 export_count
= cgiGetSize("PRINTER_NAME");
2387 name
= "EXPORT_NAME";
2389 for (i
= 0; i
< export_count
; i
++)
2391 dest
= cgiGetArray(name
, i
);
2393 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2396 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2405 if (i
< export_count
)
2406 cgiSetVariable("ERROR", cupsLastErrorString());
2409 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2410 cgiCopyTemplateLang("samba-exported.tmpl");
2415 else if (username
&& !*username
)
2416 cgiSetVariable("ERROR",
2417 cgiText(_("A Samba username is required to export "
2418 "printer drivers")));
2419 else if (username
&& (!password
|| !*password
))
2420 cgiSetVariable("ERROR",
2421 cgiText(_("A Samba password is required to export "
2422 "printer drivers")));
2428 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2429 cgiCopyTemplateLang("samba-export.tmpl");
2435 * 'do_list_printers()' - List available printers.
2439 do_list_printers(http_t
*http
) /* I - HTTP connection */
2441 ipp_t
*request
, /* IPP request */
2442 *response
; /* IPP response */
2443 ipp_attribute_t
*attr
; /* IPP attribute */
2446 cgiStartHTML(cgiText(_("List Available Printers")));
2450 * Get the list of printers and their devices...
2453 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2455 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2456 "requested-attributes", NULL
, "device-uri");
2458 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2459 CUPS_PRINTER_LOCAL
);
2460 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2461 CUPS_PRINTER_LOCAL
);
2463 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2466 * Got the printer list, now load the devices...
2469 int i
; /* Looping var */
2470 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2471 char *printer_device
; /* Current printer device */
2475 * Allocate an array and copy the device strings...
2478 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2480 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2482 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2484 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2488 * Free the printer list and get the device list...
2491 ippDelete(response
);
2493 request
= ippNewRequest(CUPS_GET_DEVICES
);
2495 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2498 * Got the device list, let's parse it...
2501 const char *device_uri
, /* device-uri attribute value */
2502 *device_make_and_model
, /* device-make-and-model value */
2503 *device_info
; /* device-info value */
2506 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2509 * Skip leading attributes until we hit a device...
2512 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2519 * Pull the needed attributes from this device...
2523 device_make_and_model
= NULL
;
2526 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2528 if (!strcmp(attr
->name
, "device-info") &&
2529 attr
->value_tag
== IPP_TAG_TEXT
)
2530 device_info
= attr
->values
[0].string
.text
;
2532 if (!strcmp(attr
->name
, "device-make-and-model") &&
2533 attr
->value_tag
== IPP_TAG_TEXT
)
2534 device_make_and_model
= attr
->values
[0].string
.text
;
2536 if (!strcmp(attr
->name
, "device-uri") &&
2537 attr
->value_tag
== IPP_TAG_URI
)
2538 device_uri
= attr
->values
[0].string
.text
;
2544 * See if we have everything needed...
2547 if (device_info
&& device_make_and_model
&& device_uri
&&
2548 strcasecmp(device_make_and_model
, "unknown") &&
2549 strchr(device_uri
, ':'))
2552 * Yes, now see if there is already a printer for this
2556 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2559 * Not found, so it must be a new printer...
2562 char option
[1024], /* Form variables for this device */
2563 *option_ptr
; /* Pointer into string */
2564 const char *ptr
; /* Pointer into device string */
2568 * Format the printer name variable for this device...
2570 * We use the device-info string first, then device-uri,
2571 * and finally device-make-and-model to come up with a
2575 if (strncasecmp(device_info
, "unknown", 7))
2577 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2580 ptr
= device_make_and_model
;
2582 for (option_ptr
= option
;
2583 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2585 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2587 *option_ptr
++ = *ptr
;
2588 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
[-1] != '_')
2589 *option_ptr
++ = '_';
2590 else if (*ptr
== '?' || *ptr
== '(')
2595 cgiSetArray("TEMPLATE_NAME", i
, option
);
2598 * Finally, set the form variables for this printer...
2601 cgiSetArray("device_info", i
, device_info
);
2602 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2603 cgiSetArray("device_uri", i
, device_uri
);
2612 ippDelete(response
);
2615 * Free the device list...
2618 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2620 printer_device
= (char *)cupsArrayNext(printer_devices
))
2621 free(printer_device
);
2623 cupsArrayDelete(printer_devices
);
2628 * Finally, show the printer list...
2631 cgiCopyTemplateLang("list-available-printers.tmpl");
2638 * 'do_menu()' - Show the main menu.
2642 do_menu(http_t
*http
) /* I - HTTP connection */
2644 int num_settings
; /* Number of server settings */
2645 cups_option_t
*settings
; /* Server settings */
2646 const char *val
; /* Setting value */
2647 char filename
[1024]; /* Temporary filename */
2648 const char *datadir
; /* Location of data files */
2649 ipp_t
*request
, /* IPP request */
2650 *response
; /* IPP response */
2654 * Get the current server settings...
2657 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2659 cgiSetVariable("SETTINGS_MESSAGE",
2660 cgiText(_("Unable to open cupsd.conf file:")));
2661 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2664 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2665 settings
)) != NULL
&& atoi(val
))
2666 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2668 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2669 settings
)) != NULL
&& atoi(val
))
2670 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2672 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2673 settings
)) != NULL
&& atoi(val
))
2674 cgiSetVariable("REMOTE_ANY", "CHECKED");
2676 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2677 settings
)) != NULL
&& atoi(val
))
2678 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2680 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2681 settings
)) != NULL
&& atoi(val
))
2682 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2684 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2685 settings
)) != NULL
&& atoi(val
))
2686 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2689 cgiSetVariable("HAVE_GSSAPI", "1");
2691 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2692 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2693 cgiSetVariable("KERBEROS", "CHECKED");
2695 #endif /* HAVE_GSSAPI */
2696 cgiSetVariable("KERBEROS", "");
2699 cgiSetVariable("HAVE_DNSSD", "1");
2700 #endif /* HAVE_DNSSD */
2703 cgiSetVariable("HAVE_LDAP", "1");
2704 #endif /* HAVE_LDAP */
2707 cgiSetVariable("HAVE_LIBSLP", "1");
2708 #endif /* HAVE_LIBSLP */
2710 if ((val
= cupsGetOption("BrowseRemoteProtocols", num_settings
,
2712 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2714 val
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
2716 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2717 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2719 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2720 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2722 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2723 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2725 if ((val
= cupsGetOption("BrowseLocalProtocols", num_settings
,
2727 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2729 val
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
2731 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2732 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2734 if (strstr(val
, "dnssd") || strstr(val
, "DNSSD") ||
2735 strstr(val
, "dns-sd") || strstr(val
, "DNS-SD") ||
2736 strstr(val
, "bonjour") || strstr(val
, "BONJOUR"))
2737 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2739 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2740 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2742 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2743 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2745 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2749 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2750 !strcasecmp(val
, "true"))
2751 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2753 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2757 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2758 !strcasecmp(val
, "true"))
2760 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2762 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2766 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2767 !strcasecmp(val
, "true"))
2768 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2771 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2774 cgiSetVariable("MAX_CLIENTS", val
);
2776 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2779 cgiSetVariable("MAX_JOBS", val
);
2781 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2784 cgiSetVariable("MAX_LOG_SIZE", val
);
2786 cupsFreeOptions(num_settings
, settings
);
2789 * See if Samba and the Windows drivers are installed...
2792 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2793 datadir
= CUPS_DATADIR
;
2795 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2796 if (!access(filename
, R_OK
))
2799 * Found Windows 2000 driver file, see if we have smbclient and
2803 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2804 sizeof(filename
)) &&
2805 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2807 cgiSetVariable("HAVE_SAMBA", "Y");
2810 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2812 fputs("ERROR: smbclient not found!\n", stderr
);
2814 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2816 fputs("ERROR: rpcclient not found!\n", stderr
);
2826 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2828 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2829 NULL
, "ipp://localhost/");
2831 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2833 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2834 ippDelete(response
);
2838 * Finally, show the main menu template...
2841 cgiStartHTML(cgiText(_("Administration")));
2843 cgiCopyTemplateLang("admin.tmpl");
2850 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2854 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2856 int i
; /* Looping var */
2857 ipp_t
*request
, /* IPP request */
2858 *response
; /* IPP response */
2859 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2860 const char *printer
, /* Printer name (purge-jobs) */
2861 *is_class
, /* Is a class? */
2862 *users
, /* List of users or groups */
2863 *type
; /* Allow/deny type */
2864 int num_users
; /* Number of users */
2865 char *ptr
, /* Pointer into users string */
2866 *end
, /* Pointer to end of users string */
2867 quote
; /* Quote character */
2868 ipp_attribute_t
*attr
; /* Attribute */
2869 static const char * const attrs
[] = /* Requested attributes */
2871 "requesting-user-name-allowed",
2872 "requesting-user-name-denied"
2876 is_class
= cgiGetVariable("IS_CLASS");
2877 printer
= cgiGetVariable("PRINTER_NAME");
2881 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2882 cgiStartHTML(cgiText(_("Set Allowed Users")));
2883 cgiCopyTemplateLang("error.tmpl");
2888 users
= cgiGetVariable("users");
2889 type
= cgiGetVariable("type");
2891 if (!users
|| !type
||
2892 (strcmp(type
, "requesting-user-name-allowed") &&
2893 strcmp(type
, "requesting-user-name-denied")))
2896 * Build a Get-Printer-Attributes request, which requires the following
2899 * attributes-charset
2900 * attributes-natural-language
2902 * requested-attributes
2905 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2907 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2908 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2910 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2913 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2914 "requested-attributes",
2915 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2918 * Do the request and get back a response...
2921 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2923 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2925 ippDelete(response
);
2928 cgiStartHTML(cgiText(_("Set Allowed Users")));
2930 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2932 puts("Status: 401\n");
2935 else if (cupsLastError() > IPP_OK_CONFLICT
)
2936 cgiShowIPPError(_("Unable to get printer attributes:"));
2938 cgiCopyTemplateLang("users.tmpl");
2945 * Save the changes...
2948 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2951 * Skip whitespace and commas...
2954 while (*ptr
== ',' || isspace(*ptr
& 255))
2960 if (*ptr
== '\'' || *ptr
== '\"')
2963 * Scan quoted name...
2968 for (end
= ptr
; *end
; end
++)
2975 * Scan space or comma-delimited name...
2978 for (end
= ptr
; *end
; end
++)
2979 if (isspace(*end
& 255) || *end
== ',')
2984 * Advance to the next name...
2991 * Build a CUPS-Add-Printer/Class request, which requires the following
2994 * attributes-charset
2995 * attributes-natural-language
2997 * requesting-user-name-{allowed,denied}
3000 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3002 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3003 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3005 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3009 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3010 "requesting-user-name-allowed", NULL
, "all");
3013 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3014 type
, num_users
, NULL
, NULL
);
3016 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
3019 * Skip whitespace and commas...
3022 while (*ptr
== ',' || isspace(*ptr
& 255))
3028 if (*ptr
== '\'' || *ptr
== '\"')
3031 * Scan quoted name...
3036 for (end
= ptr
; *end
; end
++)
3043 * Scan space or comma-delimited name...
3046 for (end
= ptr
; *end
; end
++)
3047 if (isspace(*end
& 255) || *end
== ',')
3052 * Terminate the name...
3062 attr
->values
[i
].string
.text
= strdup(ptr
);
3065 * Advance to the next name...
3073 * Do the request and get back a response...
3076 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3078 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3080 puts("Status: 401\n");
3083 else if (cupsLastError() > IPP_OK_CONFLICT
)
3085 cgiStartHTML(cgiText(_("Set Allowed Users")));
3086 cgiShowIPPError(_("Unable to change printer:"));
3091 * Redirect successful updates back to the printer page...
3094 char url
[1024], /* Printer/class URL */
3095 refresh
[1024]; /* Refresh URL */
3098 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3099 cgiFormEncode(uri
, url
, sizeof(uri
));
3100 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
3102 cgiSetVariable("refresh_page", refresh
);
3104 cgiStartHTML(cgiText(_("Set Allowed Users")));
3106 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3107 "printer-modified.tmpl");
3116 * 'do_set_default()' - Set the server default printer/class.
3120 do_set_default(http_t
*http
) /* I - HTTP connection */
3122 const char *title
; /* Page title */
3123 ipp_t
*request
; /* IPP request */
3124 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3125 const char *printer
, /* Printer name (purge-jobs) */
3126 *is_class
; /* Is a class? */
3129 is_class
= cgiGetVariable("IS_CLASS");
3130 printer
= cgiGetVariable("PRINTER_NAME");
3131 title
= cgiText(_("Set As Server Default"));
3135 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3136 cgiStartHTML(title
);
3137 cgiCopyTemplateLang("error.tmpl");
3143 * Build a printer request, which requires the following
3146 * attributes-charset
3147 * attributes-natural-language
3151 request
= ippNewRequest(CUPS_SET_DEFAULT
);
3153 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3154 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3156 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3160 * Do the request and get back a response...
3163 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3165 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3167 puts("Status: 401\n");
3170 else if (cupsLastError() > IPP_OK_CONFLICT
)
3172 cgiStartHTML(title
);
3173 cgiShowIPPError(_("Unable to set server default:"));
3178 * Redirect successful updates back to the printer page...
3181 char url
[1024], /* Printer/class URL */
3182 refresh
[1024]; /* Refresh URL */
3185 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3186 cgiFormEncode(uri
, url
, sizeof(uri
));
3187 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3188 cgiSetVariable("refresh_page", refresh
);
3190 cgiStartHTML(title
);
3191 cgiCopyTemplateLang("printer-default.tmpl");
3199 * 'do_set_options()' - Configure the default options for a queue.
3203 do_set_options(http_t
*http
, /* I - HTTP connection */
3204 int is_class
) /* I - Set options for class? */
3206 int i
, j
, k
, m
; /* Looping vars */
3207 int have_options
; /* Have options? */
3208 ipp_t
*request
, /* IPP request */
3209 *response
; /* IPP response */
3210 ipp_attribute_t
*attr
; /* IPP attribute */
3211 char uri
[HTTP_MAX_URI
]; /* Job URI */
3212 const char *var
; /* Variable value */
3213 const char *printer
; /* Printer printer name */
3214 const char *filename
; /* PPD filename */
3215 char tempfile
[1024]; /* Temporary filename */
3216 cups_file_t
*in
, /* Input file */
3217 *out
; /* Output file */
3218 char line
[1024], /* Line from PPD file */
3219 value
[1024], /* Option value */
3220 keyword
[1024], /* Keyword from Default line */
3221 *keyptr
; /* Pointer into keyword... */
3222 ppd_file_t
*ppd
; /* PPD file */
3223 ppd_group_t
*group
; /* Option group */
3224 ppd_option_t
*option
; /* Option */
3225 ppd_coption_t
*coption
; /* Custom option */
3226 ppd_cparam_t
*cparam
; /* Custom parameter */
3227 ppd_attr_t
*ppdattr
; /* PPD attribute */
3228 const char *title
; /* Page title */
3231 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
3233 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
3237 * Get the printer name...
3240 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
3241 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3242 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3246 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3247 cgiStartHTML(title
);
3248 cgiCopyTemplateLang("error.tmpl");
3253 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
3256 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3257 * command file to the printer...
3260 if (cgiGetVariable("AUTOCONFIGURE"))
3262 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
3267 * Get the PPD file...
3273 filename
= cupsGetPPD2(http
, printer
);
3277 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
3279 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
3281 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
3282 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3283 cgiStartHTML(title
);
3284 cgiCopyTemplateLang("error.tmpl");
3291 fputs("DEBUG: No PPD file\n", stderr
);
3295 if (cgiGetVariable("job_sheets_start") != NULL
||
3296 cgiGetVariable("job_sheets_end") != NULL
)
3303 ppdMarkDefaults(ppd
);
3305 for (option
= ppdFirstOption(ppd
);
3307 option
= ppdNextOption(ppd
))
3309 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
3312 ppdMarkOption(ppd
, option
->keyword
, var
);
3313 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
3316 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
3320 if (!have_options
|| ppdConflicts(ppd
))
3323 * Show the options to the user...
3326 fputs("DEBUG: Showing options...\n", stderr
);
3329 * Show auto-configure button if supported...
3334 if (ppd
->num_filters
== 0 ||
3335 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
3336 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
3337 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3340 for (i
= 0; i
< ppd
->num_filters
; i
++)
3341 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
3343 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3350 * Get the printer attributes...
3353 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3355 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3356 "localhost", 0, "/printers/%s", printer
);
3357 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3360 response
= cupsDoRequest(http
, request
, "/");
3363 * List the groups used as "tabs"...
3370 for (group
= ppd
->groups
;
3371 i
< ppd
->num_groups
;
3374 cgiSetArray("GROUP_ID", i
, group
->name
);
3376 if (!strcmp(group
->name
, "InstallableOptions"))
3377 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
3379 cgiSetArray("GROUP", i
, group
->text
);
3383 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
3385 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
3386 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
3389 if (ippFindAttribute(response
, "printer-error-policy-supported",
3391 ippFindAttribute(response
, "printer-op-policy-supported",
3394 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
3395 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3398 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3399 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3401 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3402 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3405 cgiStartHTML(cgiText(_("Set Printer Options")));
3406 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3412 if (ppdConflicts(ppd
))
3414 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3417 for (j
= group
->num_options
, option
= group
->options
;
3420 if (option
->conflicted
)
3422 cgiSetArray("ckeyword", k
, option
->keyword
);
3423 cgiSetArray("ckeytext", k
, option
->text
);
3425 for (m
= 0; m
< option
->num_choices
; m
++)
3427 if (option
->choices
[m
].marked
)
3429 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3437 cgiCopyTemplateLang("option-conflict.tmpl");
3440 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3444 cgiSetVariable("GROUP_ID", group
->name
);
3446 if (!strcmp(group
->name
, "InstallableOptions"))
3447 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3449 cgiSetVariable("GROUP", group
->text
);
3451 cgiCopyTemplateLang("option-header.tmpl");
3453 for (j
= group
->num_options
, option
= group
->options
;
3457 if (!strcmp(option
->keyword
, "PageRegion"))
3460 cgiSetVariable("KEYWORD", option
->keyword
);
3461 cgiSetVariable("KEYTEXT", option
->text
);
3463 if (option
->conflicted
)
3464 cgiSetVariable("CONFLICTED", "1");
3466 cgiSetVariable("CONFLICTED", "0");
3468 cgiSetSize("CHOICES", 0);
3469 cgiSetSize("TEXT", 0);
3470 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3472 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3473 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3477 if (option
->choices
[k
].marked
)
3478 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3481 cgiSetSize("PARAMS", 0);
3482 cgiSetSize("PARAMTEXT", 0);
3483 cgiSetSize("PARAMVALUE", 0);
3484 cgiSetSize("INPUTTYPE", 0);
3486 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3488 const char *units
= NULL
; /* Units value, if any */
3491 cgiSetVariable("ISCUSTOM", "1");
3493 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3495 cparam
= ppdNextCustomParam(coption
), m
++)
3497 if (!strcasecmp(option
->keyword
, "PageSize") &&
3498 strcasecmp(cparam
->name
, "Width") &&
3499 strcasecmp(cparam
->name
, "Height"))
3505 cgiSetArray("PARAMS", m
, cparam
->name
);
3506 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3507 cgiSetArray("INPUTTYPE", m
, "text");
3509 switch (cparam
->type
)
3511 case PPD_CUSTOM_POINTS
:
3512 if (!strncasecmp(option
->defchoice
, "Custom.", 7))
3514 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3516 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3517 strcmp(units
, "in") && strcmp(units
, "ft"))
3519 if (units
[1] == 'm')
3528 if (!strcmp(units
, "mm"))
3529 snprintf(value
, sizeof(value
), "%g",
3530 cparam
->current
.custom_points
/ 72.0 * 25.4);
3531 else if (!strcmp(units
, "cm"))
3532 snprintf(value
, sizeof(value
), "%g",
3533 cparam
->current
.custom_points
/ 72.0 * 2.54);
3534 else if (!strcmp(units
, "in"))
3535 snprintf(value
, sizeof(value
), "%g",
3536 cparam
->current
.custom_points
/ 72.0);
3537 else if (!strcmp(units
, "ft"))
3538 snprintf(value
, sizeof(value
), "%g",
3539 cparam
->current
.custom_points
/ 72.0 / 12.0);
3540 else if (!strcmp(units
, "m"))
3541 snprintf(value
, sizeof(value
), "%g",
3542 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3544 snprintf(value
, sizeof(value
), "%g",
3545 cparam
->current
.custom_points
);
3546 cgiSetArray("PARAMVALUE", m
, value
);
3549 case PPD_CUSTOM_CURVE
:
3550 case PPD_CUSTOM_INVCURVE
:
3551 case PPD_CUSTOM_REAL
:
3552 snprintf(value
, sizeof(value
), "%g",
3553 cparam
->current
.custom_real
);
3554 cgiSetArray("PARAMVALUE", m
, value
);
3557 case PPD_CUSTOM_INT
:
3558 snprintf(value
, sizeof(value
), "%d",
3559 cparam
->current
.custom_int
);
3560 cgiSetArray("PARAMVALUE", m
, value
);
3563 case PPD_CUSTOM_PASSCODE
:
3564 case PPD_CUSTOM_PASSWORD
:
3565 if (cparam
->current
.custom_password
)
3566 cgiSetArray("PARAMVALUE", m
,
3567 cparam
->current
.custom_password
);
3569 cgiSetArray("PARAMVALUE", m
, "");
3570 cgiSetArray("INPUTTYPE", m
, "password");
3573 case PPD_CUSTOM_STRING
:
3574 if (cparam
->current
.custom_string
)
3575 cgiSetArray("PARAMVALUE", m
,
3576 cparam
->current
.custom_string
);
3578 cgiSetArray("PARAMVALUE", m
, "");
3585 cgiSetArray("PARAMS", m
, "Units");
3586 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3587 cgiSetArray("PARAMVALUE", m
, units
);
3591 cgiSetVariable("ISCUSTOM", "0");
3595 case PPD_UI_BOOLEAN
:
3596 cgiCopyTemplateLang("option-boolean.tmpl");
3598 case PPD_UI_PICKONE
:
3599 cgiCopyTemplateLang("option-pickone.tmpl");
3601 case PPD_UI_PICKMANY
:
3602 cgiCopyTemplateLang("option-pickmany.tmpl");
3607 cgiCopyTemplateLang("option-trailer.tmpl");
3611 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3612 IPP_TAG_ZERO
)) != NULL
)
3615 * Add the job sheets options...
3618 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3619 cgiSetVariable("GROUP", cgiText(_("Banners")));
3620 cgiCopyTemplateLang("option-header.tmpl");
3622 cgiSetSize("CHOICES", attr
->num_values
);
3623 cgiSetSize("TEXT", attr
->num_values
);
3624 for (k
= 0; k
< attr
->num_values
; k
++)
3626 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3627 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3630 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3632 cgiSetVariable("KEYWORD", "job_sheets_start");
3633 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3634 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3635 attr
->values
[0].string
.text
: "");
3637 cgiCopyTemplateLang("option-pickone.tmpl");
3639 cgiSetVariable("KEYWORD", "job_sheets_end");
3640 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3641 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3642 attr
->values
[1].string
.text
: "");
3644 cgiCopyTemplateLang("option-pickone.tmpl");
3646 cgiCopyTemplateLang("option-trailer.tmpl");
3649 if (ippFindAttribute(response
, "printer-error-policy-supported",
3651 ippFindAttribute(response
, "printer-op-policy-supported",
3655 * Add the error and operation policy options...
3658 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3659 cgiSetVariable("GROUP", cgiText(_("Policies")));
3660 cgiCopyTemplateLang("option-header.tmpl");
3666 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3671 cgiSetSize("CHOICES", attr
->num_values
);
3672 cgiSetSize("TEXT", attr
->num_values
);
3673 for (k
= 0; k
< attr
->num_values
; k
++)
3675 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3676 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3679 attr
= ippFindAttribute(response
, "printer-error-policy",
3682 cgiSetVariable("KEYWORD", "printer_error_policy");
3683 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3684 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3685 "" : attr
->values
[0].string
.text
);
3688 cgiCopyTemplateLang("option-pickone.tmpl");
3691 * Operation policy...
3694 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3699 cgiSetSize("CHOICES", attr
->num_values
);
3700 cgiSetSize("TEXT", attr
->num_values
);
3701 for (k
= 0; k
< attr
->num_values
; k
++)
3703 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3704 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3707 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3709 cgiSetVariable("KEYWORD", "printer_op_policy");
3710 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3711 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3712 "" : attr
->values
[0].string
.text
);
3714 cgiCopyTemplateLang("option-pickone.tmpl");
3717 cgiCopyTemplateLang("option-trailer.tmpl");
3721 * Binary protocol support...
3724 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3725 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3727 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3728 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3730 cgiSetSize("CHOICES", attr
->num_values
);
3731 cgiSetSize("TEXT", attr
->num_values
);
3733 for (i
= 0; i
< attr
->num_values
; i
++)
3735 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3736 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3739 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3740 cgiSetVariable("KEYWORD", "port_monitor");
3741 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3742 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3744 cgiCopyTemplateLang("option-header.tmpl");
3745 cgiCopyTemplateLang("option-pickone.tmpl");
3746 cgiCopyTemplateLang("option-trailer.tmpl");
3749 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3752 ippDelete(response
);
3757 * Set default options...
3760 fputs("DEBUG: Setting options...\n", stderr
);
3764 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3765 in
= cupsFileOpen(filename
, "r");
3769 cgiSetVariable("ERROR", strerror(errno
));
3770 cgiStartHTML(cgiText(_("Set Printer Options")));
3771 cgiCopyTemplateLang("error.tmpl");
3787 while (cupsFileGets(in
, line
, sizeof(line
)))
3789 if (!strncmp(line
, "*cupsProtocol:", 14))
3791 else if (strncmp(line
, "*Default", 8))
3792 cupsFilePrintf(out
, "%s\n", line
);
3796 * Get default option name...
3799 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3801 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3802 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3807 if (!strcmp(keyword
, "PageRegion") ||
3808 !strcmp(keyword
, "PaperDimension") ||
3809 !strcmp(keyword
, "ImageableArea"))
3810 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3812 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3815 cupsFilePrintf(out
, "%s\n", line
);
3817 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3827 * Make sure temporary filename is cleared when there is no PPD...
3834 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3835 * following attributes:
3837 * attributes-charset
3838 * attributes-natural-language
3840 * job-sheets-default
3841 * printer-error-policy
3846 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3847 CUPS_ADD_MODIFY_PRINTER
);
3849 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3852 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3853 "job-sheets-default", 2, NULL
, NULL
);
3854 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3855 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3857 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3858 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3859 "printer-error-policy", NULL
, var
);
3861 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3862 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3863 "printer-op-policy", NULL
, var
);
3865 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3866 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3867 "port-monitor", NULL
, var
);
3870 * Do the request and get back a response...
3874 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3876 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3878 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3880 puts("Status: 401\n");
3883 else if (cupsLastError() > IPP_OK_CONFLICT
)
3885 cgiStartHTML(title
);
3886 cgiShowIPPError(_("Unable to set options:"));
3891 * Redirect successful updates back to the printer page...
3894 char refresh
[1024]; /* Refresh URL */
3897 cgiFormEncode(uri
, printer
, sizeof(uri
));
3898 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3899 is_class
? "classes" : "printers", uri
);
3900 cgiSetVariable("refresh_page", refresh
);
3902 cgiStartHTML(title
);
3904 cgiCopyTemplateLang("printer-configured.tmpl");
3919 * 'do_set_sharing()' - Set printer-is-shared value.
3923 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3925 ipp_t
*request
, /* IPP request */
3926 *response
; /* IPP response */
3927 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3928 const char *printer
, /* Printer name */
3929 *is_class
, /* Is a class? */
3930 *shared
; /* Sharing value */
3933 is_class
= cgiGetVariable("IS_CLASS");
3934 printer
= cgiGetVariable("PRINTER_NAME");
3935 shared
= cgiGetVariable("SHARED");
3937 if (!printer
|| !shared
)
3939 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3940 cgiStartHTML(cgiText(_("Set Publishing")));
3941 cgiCopyTemplateLang("error.tmpl");
3947 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3948 * following attributes:
3950 * attributes-charset
3951 * attributes-natural-language
3956 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3958 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3959 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3961 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3964 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3967 * Do the request and get back a response...
3970 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3972 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3974 ippDelete(response
);
3977 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3979 puts("Status: 401\n");
3982 else if (cupsLastError() > IPP_OK_CONFLICT
)
3984 cgiStartHTML(cgiText(_("Set Publishing")));
3985 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3990 * Redirect successful updates back to the printer page...
3993 char url
[1024], /* Printer/class URL */
3994 refresh
[1024]; /* Refresh URL */
3997 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3998 cgiFormEncode(uri
, url
, sizeof(uri
));
3999 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
4000 cgiSetVariable("refresh_page", refresh
);
4002 cgiStartHTML(cgiText(_("Set Publishing")));
4003 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
4004 "printer-modified.tmpl");
4012 * 'get_option_value()' - Return the value of an option.
4014 * This function also handles generation of custom option values.
4017 static char * /* O - Value string or NULL on error */
4019 ppd_file_t
*ppd
, /* I - PPD file */
4020 const char *name
, /* I - Option name */
4021 char *buffer
, /* I - String buffer */
4022 size_t bufsize
) /* I - Size of buffer */
4024 char *bufptr
, /* Pointer into buffer */
4025 *bufend
; /* End of buffer */
4026 ppd_coption_t
*coption
; /* Custom option */
4027 ppd_cparam_t
*cparam
; /* Current custom parameter */
4028 char keyword
[256]; /* Parameter name */
4029 const char *val
, /* Parameter value */
4030 *uval
; /* Units value */
4031 long integer
; /* Integer value */
4032 double number
, /* Number value */
4033 number_points
; /* Number in points */
4037 * See if we have a custom option choice...
4040 if ((val
= cgiGetVariable(name
)) == NULL
)
4048 else if (strcasecmp(val
, "Custom") ||
4049 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
4052 * Not a custom choice...
4055 strlcpy(buffer
, val
, bufsize
);
4060 * OK, we have a custom option choice, format it...
4065 if (!strcmp(coption
->keyword
, "PageSize"))
4067 const char *lval
; /* Length string value */
4068 double width
, /* Width value */
4069 width_points
, /* Width in points */
4070 length
, /* Length value */
4071 length_points
; /* Length in points */
4074 val
= cgiGetVariable("PageSize.Width");
4075 lval
= cgiGetVariable("PageSize.Height");
4076 uval
= cgiGetVariable("PageSize.Units");
4078 if (!val
|| !lval
|| !uval
||
4079 (width
= strtod(val
, NULL
)) == 0.0 ||
4080 (length
= strtod(lval
, NULL
)) == 0.0 ||
4081 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4082 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4085 width_points
= get_points(width
, uval
);
4086 length_points
= get_points(length
, uval
);
4088 if (width_points
< ppd
->custom_min
[0] ||
4089 width_points
> ppd
->custom_max
[0] ||
4090 length_points
< ppd
->custom_min
[1] ||
4091 length_points
> ppd
->custom_max
[1])
4094 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
4096 else if (cupsArrayCount(coption
->params
) == 1)
4098 cparam
= ppdFirstCustomParam(coption
);
4099 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
4101 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4104 switch (cparam
->type
)
4106 case PPD_CUSTOM_CURVE
:
4107 case PPD_CUSTOM_INVCURVE
:
4108 case PPD_CUSTOM_REAL
:
4109 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4110 number
< cparam
->minimum
.custom_real
||
4111 number
> cparam
->maximum
.custom_real
)
4114 snprintf(buffer
, bufsize
, "Custom.%g", number
);
4117 case PPD_CUSTOM_INT
:
4118 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4119 integer
== LONG_MAX
||
4120 integer
< cparam
->minimum
.custom_int
||
4121 integer
> cparam
->maximum
.custom_int
)
4124 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
4127 case PPD_CUSTOM_POINTS
:
4128 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4130 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4131 (uval
= cgiGetVariable(keyword
)) == NULL
||
4132 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4133 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4136 number_points
= get_points(number
, uval
);
4137 if (number_points
< cparam
->minimum
.custom_points
||
4138 number_points
> cparam
->maximum
.custom_points
)
4141 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
4144 case PPD_CUSTOM_PASSCODE
:
4145 for (uval
= val
; *uval
; uval
++)
4146 if (!isdigit(*uval
& 255))
4149 case PPD_CUSTOM_PASSWORD
:
4150 case PPD_CUSTOM_STRING
:
4151 integer
= (long)strlen(val
);
4152 if (integer
< cparam
->minimum
.custom_string
||
4153 integer
> cparam
->maximum
.custom_string
)
4156 snprintf(buffer
, bufsize
, "Custom.%s", val
);
4162 const char *prefix
= "{"; /* Prefix string */
4166 bufend
= buffer
+ bufsize
;
4168 for (cparam
= ppdFirstCustomParam(coption
);
4170 cparam
= ppdNextCustomParam(coption
))
4172 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
4175 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4178 snprintf(bufptr
, bufend
- bufptr
, "%s%s=", prefix
, cparam
->name
);
4179 bufptr
+= strlen(bufptr
);
4182 switch (cparam
->type
)
4184 case PPD_CUSTOM_CURVE
:
4185 case PPD_CUSTOM_INVCURVE
:
4186 case PPD_CUSTOM_REAL
:
4187 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4188 number
< cparam
->minimum
.custom_real
||
4189 number
> cparam
->maximum
.custom_real
)
4192 snprintf(bufptr
, bufend
- bufptr
, "%g", number
);
4195 case PPD_CUSTOM_INT
:
4196 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4197 integer
== LONG_MAX
||
4198 integer
< cparam
->minimum
.custom_int
||
4199 integer
> cparam
->maximum
.custom_int
)
4202 snprintf(bufptr
, bufend
- bufptr
, "%ld", integer
);
4205 case PPD_CUSTOM_POINTS
:
4206 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4208 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4209 (uval
= cgiGetVariable(keyword
)) == NULL
||
4210 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
4211 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
4212 strcmp(uval
, "mm") && strcmp(uval
, "m")))
4215 number_points
= get_points(number
, uval
);
4216 if (number_points
< cparam
->minimum
.custom_points
||
4217 number_points
> cparam
->maximum
.custom_points
)
4220 snprintf(bufptr
, bufend
- bufptr
, "%g%s", number
, uval
);
4223 case PPD_CUSTOM_PASSCODE
:
4224 for (uval
= val
; *uval
; uval
++)
4225 if (!isdigit(*uval
& 255))
4228 case PPD_CUSTOM_PASSWORD
:
4229 case PPD_CUSTOM_STRING
:
4230 integer
= (long)strlen(val
);
4231 if (integer
< cparam
->minimum
.custom_string
||
4232 integer
> cparam
->maximum
.custom_string
)
4235 if ((bufptr
+ 2) > bufend
)
4241 while (*val
&& bufptr
< bufend
)
4243 if (*val
== '\\' || *val
== '\"')
4245 if ((bufptr
+ 1) >= bufend
)
4254 if (bufptr
>= bufend
)
4263 bufptr
+= strlen(bufptr
);
4266 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
4269 strcpy(bufptr
, "}");
4277 * 'get_points()' - Get a value in points.
4280 static double /* O - Number in points */
4281 get_points(double number
, /* I - Original number */
4282 const char *uval
) /* I - Units */
4284 if (!strcmp(uval
, "mm")) /* Millimeters */
4285 return (number
* 72.0 / 25.4);
4286 else if (!strcmp(uval
, "cm")) /* Centimeters */
4287 return (number
* 72.0 / 2.54);
4288 else if (!strcmp(uval
, "in")) /* Inches */
4289 return (number
* 72.0);
4290 else if (!strcmp(uval
, "ft")) /* Feet */
4291 return (number
* 72.0 * 12.0);
4292 else if (!strcmp(uval
, "m")) /* Meters */
4293 return (number
* 72.0 / 0.0254);
4300 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".