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
= _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i
));
778 * Do the request and get back a response...
781 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
783 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
785 puts("Status: 401\n");
788 else if (cupsLastError() > IPP_OK_CONFLICT
)
791 cgiShowIPPError(modify
? _("Unable to modify class:") :
792 _("Unable to add class:"));
797 * Redirect successful updates back to the class page...
800 char refresh
[1024]; /* Refresh URL */
802 cgiFormEncode(uri
, name
, sizeof(uri
));
803 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
805 cgiSetVariable("refresh_page", refresh
);
810 cgiCopyTemplateLang("class-modified.tmpl");
812 cgiCopyTemplateLang("class-added.tmpl");
820 * 'do_am_printer()' - Add or modify a printer.
824 do_am_printer(http_t
*http
, /* I - HTTP connection */
825 int modify
) /* I - Modify the printer? */
827 int i
; /* Looping var */
828 ipp_attribute_t
*attr
; /* Current attribute */
829 ipp_t
*request
, /* IPP request */
830 *response
, /* IPP response */
831 *oldinfo
; /* Old printer information */
832 const cgi_file_t
*file
; /* Uploaded file, if any */
833 const char *var
; /* CGI variable */
834 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
835 *uriptr
; /* Pointer into URI */
836 int maxrate
; /* Maximum baud rate */
837 char baudrate
[255]; /* Baud rate string */
838 const char *name
, /* Pointer to class name */
839 *ptr
; /* Pointer to CGI variable */
840 const char *title
; /* Title of page */
841 static int baudrates
[] = /* Baud rates */
856 ptr
= cgiGetVariable("DEVICE_URI");
857 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
858 ptr
? ptr
: "(null)");
860 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
865 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
866 * following attributes:
869 * attributes-natural-language
873 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
875 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
876 "localhost", 0, "/printers/%s",
877 cgiGetVariable("PRINTER_NAME"));
878 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
882 * Do the request and get back a response...
885 oldinfo
= cupsDoRequest(http
, request
, "/");
894 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
895 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
896 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
897 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
900 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
902 for (ptr
= name
; *ptr
; ptr
++)
903 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
906 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
908 cgiSetVariable("ERROR",
909 cgiText(_("The printer name may only contain up to "
910 "127 printable characters and may not "
911 "contain spaces, slashes (/), or the "
912 "pound sign (#).")));
914 cgiCopyTemplateLang("error.tmpl");
920 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
922 if ((uriptr
= strrchr(var
, '|')) != NULL
)
925 * Extract make and make/model from device URI string...
928 char make
[1024], /* Make string */
929 *makeptr
; /* Pointer into make */
934 strlcpy(make
, uriptr
, sizeof(make
));
936 if ((makeptr
= strchr(make
, ' ')) != NULL
)
938 else if ((makeptr
= strchr(make
, '-')) != NULL
)
940 else if (!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 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
955 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
959 char template[128], /* Template name */
960 *tptr
; /* Pointer into template name */
962 cgiSetVariable("PRINTER_INFO", uriptr
);
964 for (tptr
= template;
965 tptr
< (template + sizeof(template) - 1) && *uriptr
;
967 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
970 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
973 else if (*uriptr
== '?' || *uriptr
== '(')
978 cgiSetVariable("TEMPLATE_NAME", template);
986 * Look for devices so the user can pick something...
989 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
991 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
992 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
995 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
996 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
1000 * Scan for devices for up to 30 seconds...
1003 fputs("DEBUG: Getting list of devices...\n", stderr
);
1006 if (cupsGetDevices(http
, 30, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
1007 (cups_device_cb_t
)choose_device_cb
,
1008 (void *)title
) == IPP_OK
)
1010 fputs("DEBUG: Got device list!\n", stderr
);
1012 if (cgiSupportsMultipart())
1013 cgiStartMultipart();
1015 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1016 cgiStartHTML(title
);
1017 cgiCopyTemplateLang("choose-device.tmpl");
1020 if (cgiSupportsMultipart())
1026 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1027 cupsLastError(), cupsLastErrorString());
1028 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1030 puts("Status: 401\n");
1035 cgiStartHTML(title
);
1036 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1037 _("Unable to add printer:"));
1043 else if (strchr(var
, '/') == NULL
)
1045 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
1048 * Set the current device URI for the form to the old one...
1051 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
1052 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
1056 * User needs to set the full URI...
1059 cgiStartHTML(title
);
1060 cgiCopyTemplateLang("choose-uri.tmpl");
1063 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1066 * Need baud rate, parity, etc.
1069 if ((var
= strchr(var
, '?')) != NULL
&&
1070 strncmp(var
, "?baud=", 6) == 0)
1071 maxrate
= atoi(var
+ 6);
1075 for (i
= 0; i
< 10; i
++)
1076 if (baudrates
[i
] > maxrate
)
1080 sprintf(baudrate
, "%d", baudrates
[i
]);
1081 cgiSetArray("BAUDRATES", i
, baudrate
);
1084 cgiStartHTML(title
);
1085 cgiCopyTemplateLang("choose-serial.tmpl");
1088 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
1090 cgiStartHTML(title
);
1095 * Update the location and description of an existing printer...
1100 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
1101 IPP_TAG_TEXT
)) != NULL
)
1102 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
1104 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
1105 IPP_TAG_TEXT
)) != NULL
)
1106 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
1108 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
1109 IPP_TAG_BOOLEAN
)) != NULL
)
1110 cgiSetVariable("PRINTER_IS_SHARED",
1111 attr
->values
[0].boolean
? "1" : "0");
1114 cgiCopyTemplateLang("modify-printer.tmpl");
1119 * Get the name, location, and description for a new printer...
1123 if (!strncmp(var
, "usb:", 4))
1124 cgiSetVariable("printer_is_shared", "1");
1126 #endif /* __APPLE__ */
1127 cgiSetVariable("printer_is_shared", "0");
1129 cgiCopyTemplateLang("add-printer.tmpl");
1140 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1142 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
1145 * Get the PPD file...
1148 int fd
; /* PPD file */
1149 char filename
[1024]; /* PPD filename */
1150 ppd_file_t
*ppd
; /* PPD information */
1151 char buffer
[1024]; /* Buffer */
1152 int bytes
; /* Number of bytes */
1153 http_status_t get_status
; /* Status of GET */
1156 /* TODO: Use cupsGetFile() API... */
1157 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1159 if (httpGet(http
, uri
))
1162 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1164 if (get_status
!= HTTP_OK
)
1168 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1169 uri
, get_status
, httpStatus(get_status
));
1171 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1173 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1174 write(fd
, buffer
, bytes
);
1178 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1180 if (ppd
->manufacturer
)
1181 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1184 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1191 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1192 filename
, ppdErrorString(ppdLastError(&bytes
)));
1200 "ERROR: Unable to create temporary file for PPD file: %s\n",
1206 * Build a CUPS_GET_PPDS request, which requires the following
1209 * attributes-charset
1210 * attributes-natural-language
1214 request
= ippNewRequest(CUPS_GET_PPDS
);
1216 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1217 NULL
, "ipp://localhost/printers/");
1219 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1220 var
= cgiGetVariable("CURRENT_MAKE");
1221 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1223 const char *make_model
; /* Make and model */
1226 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1227 "ppd-make", NULL
, var
);
1229 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1230 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1231 "ppd-make-and-model", NULL
, make_model
);
1234 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1235 "requested-attributes", NULL
, "ppd-make");
1238 * Do the request and get back a response...
1241 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1244 * Got the list of PPDs, see if the user has selected a make...
1247 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1250 * No PPD files with this make, try again with all makes...
1253 ippDelete(response
);
1255 request
= ippNewRequest(CUPS_GET_PPDS
);
1257 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1258 NULL
, "ipp://localhost/printers/");
1260 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1261 "requested-attributes", NULL
, "ppd-make");
1263 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1264 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1266 cgiStartHTML(title
);
1267 cgiCopyTemplateLang("choose-make.tmpl");
1270 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1272 cgiStartHTML(title
);
1273 cgiCopyTemplateLang("choose-make.tmpl");
1279 * Let the user choose a model...
1282 cgiStartHTML(title
);
1283 if (!cgiGetVariable("PPD_MAKE"))
1284 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1286 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1287 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1288 cgiCopyTemplateLang("choose-model.tmpl");
1292 ippDelete(response
);
1296 cgiStartHTML(title
);
1297 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1298 cgiCopyTemplateLang("error.tmpl");
1305 * Build a CUPS_ADD_PRINTER request, which requires the following
1308 * attributes-charset
1309 * attributes-natural-language
1315 * printer-is-accepting-jobs
1320 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1322 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1323 "localhost", 0, "/printers/%s",
1324 cgiGetVariable("PRINTER_NAME"));
1325 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1328 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1329 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1331 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1332 NULL
, cgiGetVariable("PRINTER_INFO"));
1336 var
= cgiGetVariable("PPD_NAME");
1337 if (strcmp(var
, "__no_change__"))
1338 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1342 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1345 * Strip make and model from URI...
1348 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1351 if (!strncmp(uri
, "serial:", 7))
1354 * Update serial port URI to include baud rate, etc.
1357 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1358 uriptr
= uri
+ strlen(uri
);
1360 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1361 "?baud=%s+bits=%s+parity=%s+flow=%s",
1362 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1363 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1366 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1369 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1371 var
= cgiGetVariable("printer_is_shared");
1372 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1373 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1375 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1379 * Do the request and get back a response...
1383 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1385 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1387 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1389 puts("Status: 401\n");
1392 else if (cupsLastError() > IPP_OK_CONFLICT
)
1394 cgiStartHTML(title
);
1395 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1396 _("Unable to add printer:"));
1401 * Redirect successful updates back to the printer page...
1404 char refresh
[1024]; /* Refresh URL */
1407 cgiFormEncode(uri
, name
, sizeof(uri
));
1409 snprintf(refresh
, sizeof(refresh
),
1410 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1412 cgiSetVariable("refresh_page", refresh
);
1414 cgiStartHTML(title
);
1416 cgiCopyTemplateLang("printer-modified.tmpl");
1421 * Set the printer options...
1424 cgiSetVariable("OP", "set-printer-options");
1425 do_set_options(http
, 0);
1438 * 'do_cancel_subscription()' - Cancel a subscription.
1442 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1444 ipp_t
*request
; /* IPP request data */
1445 const char *var
, /* Form variable */
1446 *user
; /* Username */
1447 int id
; /* Subscription ID */
1451 * See if we have all of the required information...
1454 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1461 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1462 cgiStartHTML(_("Cancel RSS Subscription"));
1463 cgiCopyTemplateLang("error.tmpl");
1469 * Require a username...
1472 if ((user
= getenv("REMOTE_USER")) == NULL
)
1474 puts("Status: 401\n");
1479 * Cancel the subscription...
1482 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1484 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1485 NULL
, "ipp://localhost/");
1486 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1487 "notify-subscription-id", id
);
1489 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1492 ippDelete(cupsDoRequest(http
, request
, "/"));
1494 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1496 puts("Status: 401\n");
1499 else if (cupsLastError() > IPP_OK_CONFLICT
)
1501 cgiStartHTML(_("Cancel RSS Subscription"));
1502 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1507 * Redirect successful updates back to the admin page...
1510 cgiSetVariable("refresh_page", "5;URL=/admin");
1511 cgiStartHTML(_("Cancel RSS Subscription"));
1512 cgiCopyTemplateLang("subscription-canceled.tmpl");
1520 * 'do_config_server()' - Configure server settings.
1524 do_config_server(http_t
*http
) /* I - HTTP connection */
1526 if (cgiGetVariable("CHANGESETTINGS"))
1529 * Save basic setting changes...
1532 int num_settings
; /* Number of server settings */
1533 cups_option_t
*settings
; /* Server settings */
1534 int advanced
, /* Advanced settings shown? */
1535 changed
; /* Have settings changed? */
1536 const char *debug_logging
, /* DEBUG_LOGGING value */
1537 *remote_admin
, /* REMOTE_ADMIN value */
1538 *remote_any
, /* REMOTE_ANY value */
1540 /* REMOTE_PRINTERS value */
1541 *share_printers
,/* SHARE_PRINTERS value */
1543 /* USER_CANCEL_ANY value */
1544 *browse_web_if
= NULL
,
1545 /* BrowseWebIF value */
1546 *preserve_job_history
= NULL
,
1547 /* PreserveJobHistory value */
1548 *preserve_job_files
= NULL
,
1549 /* PreserveJobFiles value */
1550 *max_clients
= NULL
,
1551 /* MaxClients value */
1554 *max_log_size
= NULL
;
1555 /* MaxLogSize value */
1556 char local_protocols
[255],
1557 /* BrowseLocalProtocols */
1558 remote_protocols
[255];
1559 /* BrowseRemoteProtocols */
1560 const char *current_browse_web_if
,
1561 /* BrowseWebIF value */
1562 *current_preserve_job_history
,
1563 /* PreserveJobHistory value */
1564 *current_preserve_job_files
,
1565 /* PreserveJobFiles value */
1566 *current_max_clients
,
1567 /* MaxClients value */
1570 *current_max_log_size
,
1571 /* MaxLogSize value */
1572 *current_local_protocols
,
1573 /* BrowseLocalProtocols */
1574 *current_remote_protocols
;
1575 /* BrowseRemoteProtocols */
1577 char default_auth_type
[255];
1578 /* DefaultAuthType value */
1579 const char *val
; /* Setting value */
1580 #endif /* HAVE_GSSAPI */
1584 * Get the checkbox values from the form...
1587 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1588 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1589 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1590 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1591 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1592 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1594 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1598 * Get advanced settings...
1601 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1602 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1603 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1604 max_clients
= cgiGetVariable("MAX_CLIENTS");
1605 max_jobs
= cgiGetVariable("MAX_JOBS");
1606 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1608 if (!max_clients
|| atoi(max_clients
) <= 0)
1609 max_clients
= "100";
1611 if (!max_jobs
|| atoi(max_jobs
) <= 0)
1614 if (!max_log_size
|| atof(max_log_size
) <= 0.0)
1615 max_log_size
= "1m";
1617 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1618 strcpy(local_protocols
, "cups");
1620 local_protocols
[0] = '\0';
1623 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1625 if (local_protocols
[0])
1626 strcat(local_protocols
, " dnssd");
1628 strcat(local_protocols
, "dnssd");
1630 #endif /* HAVE_DNSSD */
1633 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1635 if (local_protocols
[0])
1636 strcat(local_protocols
, " ldap");
1638 strcat(local_protocols
, "ldap");
1640 #endif /* HAVE_LDAP */
1643 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1645 if (local_protocols
[0])
1646 strcat(local_protocols
, " slp");
1648 strcat(local_protocols
, "slp");
1650 #endif /* HAVE_SLP */
1652 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1653 strcpy(remote_protocols
, "cups");
1655 remote_protocols
[0] = '\0';
1658 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1660 if (remote_protocols
[0])
1661 strcat(remote_protocols
, " ldap");
1663 strcat(remote_protocols
, "ldap");
1665 #endif /* HAVE_LDAP */
1668 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1670 if (remote_protocols
[0])
1671 strcat(remote_protocols
, " slp");
1673 strcat(remote_protocols
, "slp");
1675 #endif /* HAVE_SLP */
1679 * Get the current server settings...
1682 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1684 cgiStartHTML(cgiText(_("Change Settings")));
1685 cgiSetVariable("MESSAGE",
1686 cgiText(_("Unable to change server settings:")));
1687 cgiSetVariable("ERROR", cupsLastErrorString());
1688 cgiCopyTemplateLang("error.tmpl");
1695 * Get authentication settings...
1698 if (cgiGetVariable("KERBEROS"))
1699 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1702 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1704 if (!val
|| !strcasecmp(val
, "Negotiate"))
1705 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1707 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1710 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1711 #endif /* HAVE_GSSAPI */
1713 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1715 current_browse_web_if
= "No";
1717 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1720 current_preserve_job_history
= "Yes";
1722 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1725 current_preserve_job_files
= "No";
1727 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1729 current_max_clients
= "100";
1731 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1733 current_max_jobs
= "500";
1735 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1737 current_max_log_size
= "1m";
1739 if ((current_local_protocols
= cupsGetOption("BrowseLocalProtocols",
1742 current_local_protocols
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
1744 if ((current_remote_protocols
= cupsGetOption("BrowseRemoteProtocols",
1747 current_remote_protocols
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
1750 * See if the settings have changed...
1753 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1754 num_settings
, settings
)) ||
1755 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1756 num_settings
, settings
)) ||
1757 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1758 num_settings
, settings
)) ||
1759 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1760 num_settings
, settings
)) ||
1761 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1762 num_settings
, settings
)) ||
1764 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1765 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1766 num_settings
, settings
)) ||
1767 #endif /* HAVE_GSSAPI */
1768 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1769 num_settings
, settings
));
1771 if (advanced
&& !changed
)
1772 changed
= strcasecmp(local_protocols
, current_local_protocols
) ||
1773 strcasecmp(remote_protocols
, current_remote_protocols
) ||
1774 strcasecmp(browse_web_if
, current_browse_web_if
) ||
1775 strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1776 strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1777 strcasecmp(max_clients
, current_max_clients
) ||
1778 strcasecmp(max_jobs
, current_max_jobs
) ||
1779 strcasecmp(max_log_size
, current_max_log_size
);
1784 * Settings *have* changed, so save the changes...
1787 cupsFreeOptions(num_settings
, settings
);
1790 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1791 debug_logging
, num_settings
, &settings
);
1792 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1793 remote_admin
, num_settings
, &settings
);
1794 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1795 remote_any
, num_settings
, &settings
);
1796 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1797 remote_printers
, num_settings
, &settings
);
1798 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1799 share_printers
, num_settings
, &settings
);
1800 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1801 user_cancel_any
, num_settings
, &settings
);
1803 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1804 num_settings
, &settings
);
1805 #endif /* HAVE_GSSAPI */
1810 * Add advanced settings...
1813 if (strcasecmp(local_protocols
, current_local_protocols
))
1814 num_settings
= cupsAddOption("BrowseLocalProtocols", local_protocols
,
1815 num_settings
, &settings
);
1816 if (strcasecmp(remote_protocols
, current_remote_protocols
))
1817 num_settings
= cupsAddOption("BrowseRemoteProtocols", remote_protocols
,
1818 num_settings
, &settings
);
1819 if (strcasecmp(browse_web_if
, current_browse_web_if
))
1820 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1821 num_settings
, &settings
);
1822 if (strcasecmp(preserve_job_history
, current_preserve_job_history
))
1823 num_settings
= cupsAddOption("PreserveJobHistory",
1824 preserve_job_history
, num_settings
,
1826 if (strcasecmp(preserve_job_files
, current_preserve_job_files
))
1827 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1828 num_settings
, &settings
);
1829 if (strcasecmp(max_clients
, current_max_clients
))
1830 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1832 if (strcasecmp(max_jobs
, current_max_jobs
))
1833 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1835 if (strcasecmp(max_log_size
, current_max_log_size
))
1836 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1840 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1842 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1844 puts("Status: 401\n");
1848 cgiStartHTML(cgiText(_("Change Settings")));
1849 cgiSetVariable("MESSAGE",
1850 cgiText(_("Unable to change server settings:")));
1851 cgiSetVariable("ERROR", cupsLastErrorString());
1852 cgiCopyTemplateLang("error.tmpl");
1857 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1859 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1860 cgiStartHTML(cgiText(_("Change Settings")));
1861 cgiCopyTemplateLang("restart.tmpl");
1870 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1871 cgiStartHTML(cgiText(_("Change Settings")));
1872 cgiCopyTemplateLang("norestart.tmpl");
1875 cupsFreeOptions(num_settings
, settings
);
1879 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1882 * Save hand-edited config file...
1885 http_status_t status
; /* PUT status */
1886 char tempfile
[1024]; /* Temporary new cupsd.conf */
1887 int tempfd
; /* Temporary file descriptor */
1888 cups_file_t
*temp
; /* Temporary file */
1889 const char *start
, /* Start of line */
1890 *end
; /* End of line */
1894 * Create a temporary file for the new cupsd.conf file...
1897 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1899 cgiStartHTML(cgiText(_("Edit Configuration File")));
1900 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1901 cgiSetVariable("ERROR", strerror(errno
));
1902 cgiCopyTemplateLang("error.tmpl");
1909 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1911 cgiStartHTML(cgiText(_("Edit Configuration File")));
1912 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1913 cgiSetVariable("ERROR", strerror(errno
));
1914 cgiCopyTemplateLang("error.tmpl");
1924 * Copy the cupsd.conf text from the form variable...
1927 start
= cgiGetVariable("CUPSDCONF");
1930 if ((end
= strstr(start
, "\r\n")) == NULL
)
1931 if ((end
= strstr(start
, "\n")) == NULL
)
1932 end
= start
+ strlen(start
);
1934 cupsFileWrite(temp
, start
, end
- start
);
1935 cupsFilePutChar(temp
, '\n');
1939 else if (*end
== '\n')
1945 cupsFileClose(temp
);
1948 * Upload the configuration file to the server...
1951 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1953 if (status
== HTTP_UNAUTHORIZED
)
1955 puts("Status: 401\n");
1959 else if (status
!= HTTP_CREATED
)
1961 cgiSetVariable("MESSAGE",
1962 cgiText(_("Unable to upload cupsd.conf file:")));
1963 cgiSetVariable("ERROR", httpStatus(status
));
1965 cgiStartHTML(cgiText(_("Edit Configuration File")));
1966 cgiCopyTemplateLang("error.tmpl");
1970 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1972 cgiStartHTML(cgiText(_("Edit Configuration File")));
1973 cgiCopyTemplateLang("restart.tmpl");
1982 struct stat info
; /* cupsd.conf information */
1983 cups_file_t
*cupsd
; /* cupsd.conf file */
1984 char *buffer
, /* Buffer for entire file */
1985 *bufptr
, /* Pointer into buffer */
1986 *bufend
; /* End of buffer */
1987 int ch
; /* Character from file */
1988 char filename
[1024]; /* Filename */
1989 const char *server_root
; /* Location of config files */
1993 * Locate the cupsd.conf file...
1996 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1997 server_root
= CUPS_SERVERROOT
;
1999 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
2002 * Figure out the size...
2005 if (stat(filename
, &info
))
2007 cgiStartHTML(cgiText(_("Edit Configuration File")));
2008 cgiSetVariable("MESSAGE",
2009 cgiText(_("Unable to access cupsd.conf file:")));
2010 cgiSetVariable("ERROR", strerror(errno
));
2011 cgiCopyTemplateLang("error.tmpl");
2018 if (info
.st_size
> (1024 * 1024))
2020 cgiStartHTML(cgiText(_("Edit Configuration File")));
2021 cgiSetVariable("MESSAGE",
2022 cgiText(_("Unable to access cupsd.conf file:")));
2023 cgiSetVariable("ERROR",
2024 cgiText(_("Unable to edit cupsd.conf files larger than "
2026 cgiCopyTemplateLang("error.tmpl");
2029 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
2030 (long)info
.st_size
);
2035 * Open the cupsd.conf file...
2038 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
2041 * Unable to open - log an error...
2044 cgiStartHTML(cgiText(_("Edit Configuration File")));
2045 cgiSetVariable("MESSAGE",
2046 cgiText(_("Unable to access cupsd.conf file:")));
2047 cgiSetVariable("ERROR", strerror(errno
));
2048 cgiCopyTemplateLang("error.tmpl");
2056 * Allocate memory and load the file into a string buffer...
2059 if ((buffer
= calloc(1, info
.st_size
+ 1)) != NULL
)
2061 cupsFileRead(cupsd
, buffer
, info
.st_size
);
2062 cgiSetVariable("CUPSDCONF", buffer
);
2066 cupsFileClose(cupsd
);
2069 * Then get the default cupsd.conf file and put that into a string as
2073 strlcat(filename
, ".default", sizeof(filename
));
2075 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
2076 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
2078 if ((buffer
= calloc(1, 2 * info
.st_size
+ 1)) != NULL
)
2080 bufend
= buffer
+ 2 * info
.st_size
- 1;
2082 for (bufptr
= buffer
;
2083 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
2085 if (ch
== '\\' || ch
== '\"')
2090 else if (ch
== '\n')
2095 else if (ch
== '\t')
2106 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
2110 cupsFileClose(cupsd
);
2114 * Show the current config file...
2117 cgiStartHTML(cgiText(_("Edit Configuration File")));
2119 cgiCopyTemplateLang("edit-config.tmpl");
2127 * 'do_delete_class()' - Delete a class.
2131 do_delete_class(http_t
*http
) /* I - HTTP connection */
2133 ipp_t
*request
; /* IPP request */
2134 char uri
[HTTP_MAX_URI
]; /* Job URI */
2135 const char *pclass
; /* Printer class name */
2139 * Get form variables...
2142 if (cgiGetVariable("CONFIRM") == NULL
)
2144 cgiStartHTML(cgiText(_("Delete Class")));
2145 cgiCopyTemplateLang("class-confirm.tmpl");
2150 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2151 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2152 "localhost", 0, "/classes/%s", pclass
);
2155 cgiStartHTML(cgiText(_("Delete Class")));
2156 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2157 cgiCopyTemplateLang("error.tmpl");
2163 * Build a CUPS_DELETE_CLASS request, which requires the following
2166 * attributes-charset
2167 * attributes-natural-language
2171 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2173 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2177 * Do the request and get back a response...
2180 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2183 * Show the results...
2186 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2188 puts("Status: 401\n");
2191 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2194 * Redirect successful updates back to the classes page...
2197 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2200 cgiStartHTML(cgiText(_("Delete Class")));
2202 if (cupsLastError() > IPP_OK_CONFLICT
)
2203 cgiShowIPPError(_("Unable to delete class:"));
2205 cgiCopyTemplateLang("class-deleted.tmpl");
2212 * 'do_delete_printer()' - Delete a printer.
2216 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2218 ipp_t
*request
; /* IPP request */
2219 char uri
[HTTP_MAX_URI
]; /* Job URI */
2220 const char *printer
; /* Printer printer name */
2224 * Get form variables...
2227 if (cgiGetVariable("CONFIRM") == NULL
)
2229 cgiStartHTML(cgiText(_("Delete Printer")));
2230 cgiCopyTemplateLang("printer-confirm.tmpl");
2235 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2236 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2237 "localhost", 0, "/printers/%s", printer
);
2240 cgiStartHTML(cgiText(_("Delete Printer")));
2241 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2242 cgiCopyTemplateLang("error.tmpl");
2248 * Build a CUPS_DELETE_PRINTER request, which requires the following
2251 * attributes-charset
2252 * attributes-natural-language
2256 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2258 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2262 * Do the request and get back a response...
2265 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2268 * Show the results...
2271 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2273 puts("Status: 401\n");
2276 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2279 * Redirect successful updates back to the printers page...
2282 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2285 cgiStartHTML(cgiText(_("Delete Printer")));
2287 if (cupsLastError() > IPP_OK_CONFLICT
)
2288 cgiShowIPPError(_("Unable to delete printer:"));
2290 cgiCopyTemplateLang("printer-deleted.tmpl");
2297 * 'do_export()' - Export printers to Samba.
2301 do_export(http_t
*http
) /* I - HTTP connection */
2303 int i
, j
; /* Looping vars */
2304 ipp_t
*request
, /* IPP request */
2305 *response
; /* IPP response */
2306 const char *username
, /* Samba username */
2307 *password
, /* Samba password */
2308 *export_all
; /* Export all printers? */
2309 int export_count
, /* Number of printers to export */
2310 printer_count
; /* Number of available printers */
2311 const char *name
, /* What name to pull */
2312 *dest
; /* Current destination */
2313 char ppd
[1024]; /* PPD file */
2320 username
= cgiGetVariable("USERNAME");
2321 password
= cgiGetVariable("PASSWORD");
2322 export_all
= cgiGetVariable("EXPORT_ALL");
2323 export_count
= cgiGetSize("EXPORT_NAME");
2326 * Get list of available printers...
2329 cgiSetSize("PRINTER_NAME", 0);
2330 cgiSetSize("PRINTER_EXPORT", 0);
2332 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2334 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2337 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2338 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2339 CUPS_PRINTER_IMPLICIT
);
2341 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2342 "requested-attributes", NULL
, "printer-name");
2344 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2346 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2347 ippDelete(response
);
2351 printer_count
= cgiGetSize("PRINTER_NAME");
2353 for (i
= 0; i
< printer_count
; i
++)
2355 dest
= cgiGetArray("PRINTER_NAME", i
);
2357 for (j
= 0; j
< export_count
; j
++)
2358 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2361 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2367 * Export or get the printers to export...
2370 if (username
&& *username
&& password
&& *password
&&
2371 (export_all
|| export_count
> 0))
2377 fputs("DEBUG: Export printers...\n", stderr
);
2381 name
= "PRINTER_NAME";
2382 export_count
= cgiGetSize("PRINTER_NAME");
2385 name
= "EXPORT_NAME";
2387 for (i
= 0; i
< export_count
; i
++)
2389 dest
= cgiGetArray(name
, i
);
2391 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2394 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2403 if (i
< export_count
)
2404 cgiSetVariable("ERROR", cupsLastErrorString());
2407 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2408 cgiCopyTemplateLang("samba-exported.tmpl");
2413 else if (username
&& !*username
)
2414 cgiSetVariable("ERROR",
2415 cgiText(_("A Samba username is required to export "
2416 "printer drivers")));
2417 else if (username
&& (!password
|| !*password
))
2418 cgiSetVariable("ERROR",
2419 cgiText(_("A Samba password is required to export "
2420 "printer drivers")));
2426 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2427 cgiCopyTemplateLang("samba-export.tmpl");
2433 * 'do_list_printers()' - List available printers.
2437 do_list_printers(http_t
*http
) /* I - HTTP connection */
2439 ipp_t
*request
, /* IPP request */
2440 *response
; /* IPP response */
2441 ipp_attribute_t
*attr
; /* IPP attribute */
2444 cgiStartHTML(cgiText(_("List Available Printers")));
2448 * Get the list of printers and their devices...
2451 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2453 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2454 "requested-attributes", NULL
, "device-uri");
2456 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2457 CUPS_PRINTER_LOCAL
);
2458 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2459 CUPS_PRINTER_LOCAL
);
2461 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2464 * Got the printer list, now load the devices...
2467 int i
; /* Looping var */
2468 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2469 char *printer_device
; /* Current printer device */
2473 * Allocate an array and copy the device strings...
2476 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2478 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2480 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2482 cupsArrayAdd(printer_devices
, _cupsStrAlloc(attr
->values
[0].string
.text
));
2486 * Free the printer list and get the device list...
2489 ippDelete(response
);
2491 request
= ippNewRequest(CUPS_GET_DEVICES
);
2493 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2496 * Got the device list, let's parse it...
2499 const char *device_uri
, /* device-uri attribute value */
2500 *device_make_and_model
, /* device-make-and-model value */
2501 *device_info
; /* device-info value */
2504 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2507 * Skip leading attributes until we hit a device...
2510 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2517 * Pull the needed attributes from this device...
2521 device_make_and_model
= NULL
;
2524 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2526 if (!strcmp(attr
->name
, "device-info") &&
2527 attr
->value_tag
== IPP_TAG_TEXT
)
2528 device_info
= attr
->values
[0].string
.text
;
2530 if (!strcmp(attr
->name
, "device-make-and-model") &&
2531 attr
->value_tag
== IPP_TAG_TEXT
)
2532 device_make_and_model
= attr
->values
[0].string
.text
;
2534 if (!strcmp(attr
->name
, "device-uri") &&
2535 attr
->value_tag
== IPP_TAG_URI
)
2536 device_uri
= attr
->values
[0].string
.text
;
2542 * See if we have everything needed...
2545 if (device_info
&& device_make_and_model
&& device_uri
&&
2546 strcasecmp(device_make_and_model
, "unknown") &&
2547 strchr(device_uri
, ':'))
2550 * Yes, now see if there is already a printer for this
2554 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2557 * Not found, so it must be a new printer...
2560 char option
[1024], /* Form variables for this device */
2561 *option_ptr
; /* Pointer into string */
2562 const char *ptr
; /* Pointer into device string */
2566 * Format the printer name variable for this device...
2568 * We use the device-info string first, then device-uri,
2569 * and finally device-make-and-model to come up with a
2573 if (strncasecmp(device_info
, "unknown", 7))
2575 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2578 ptr
= device_make_and_model
;
2580 for (option_ptr
= option
;
2581 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2583 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2585 *option_ptr
++ = *ptr
;
2586 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
[-1] != '_')
2587 *option_ptr
++ = '_';
2588 else if (*ptr
== '?' || *ptr
== '(')
2593 cgiSetArray("TEMPLATE_NAME", i
, option
);
2596 * Finally, set the form variables for this printer...
2599 cgiSetArray("device_info", i
, device_info
);
2600 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2601 cgiSetArray("device_uri", i
, device_uri
);
2610 ippDelete(response
);
2613 * Free the device list...
2616 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2618 printer_device
= (char *)cupsArrayNext(printer_devices
))
2619 _cupsStrFree(printer_device
);
2621 cupsArrayDelete(printer_devices
);
2626 * Finally, show the printer list...
2629 cgiCopyTemplateLang("list-available-printers.tmpl");
2636 * 'do_menu()' - Show the main menu.
2640 do_menu(http_t
*http
) /* I - HTTP connection */
2642 int num_settings
; /* Number of server settings */
2643 cups_option_t
*settings
; /* Server settings */
2644 const char *val
; /* Setting value */
2645 char filename
[1024]; /* Temporary filename */
2646 const char *datadir
; /* Location of data files */
2647 ipp_t
*request
, /* IPP request */
2648 *response
; /* IPP response */
2652 * Get the current server settings...
2655 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2657 cgiSetVariable("SETTINGS_MESSAGE",
2658 cgiText(_("Unable to open cupsd.conf file:")));
2659 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2662 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2663 settings
)) != NULL
&& atoi(val
))
2664 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2666 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2667 settings
)) != NULL
&& atoi(val
))
2668 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2670 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2671 settings
)) != NULL
&& atoi(val
))
2672 cgiSetVariable("REMOTE_ANY", "CHECKED");
2674 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2675 settings
)) != NULL
&& atoi(val
))
2676 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2678 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2679 settings
)) != NULL
&& atoi(val
))
2680 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2682 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2683 settings
)) != NULL
&& atoi(val
))
2684 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2687 cgiSetVariable("HAVE_GSSAPI", "1");
2689 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2690 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2691 cgiSetVariable("KERBEROS", "CHECKED");
2693 #endif /* HAVE_GSSAPI */
2694 cgiSetVariable("KERBEROS", "");
2697 cgiSetVariable("HAVE_DNSSD", "1");
2698 #endif /* HAVE_DNSSD */
2701 cgiSetVariable("HAVE_LDAP", "1");
2702 #endif /* HAVE_LDAP */
2705 cgiSetVariable("HAVE_LIBSLP", "1");
2706 #endif /* HAVE_LIBSLP */
2708 if ((val
= cupsGetOption("BrowseRemoteProtocols", num_settings
,
2710 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2712 val
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
2714 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2715 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2717 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2718 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2720 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2721 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2723 if ((val
= cupsGetOption("BrowseLocalProtocols", num_settings
,
2725 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2727 val
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
2729 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2730 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2732 if (strstr(val
, "dnssd") || strstr(val
, "DNSSD") ||
2733 strstr(val
, "dns-sd") || strstr(val
, "DNS-SD") ||
2734 strstr(val
, "bonjour") || strstr(val
, "BONJOUR"))
2735 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2737 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2738 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2740 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2741 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2743 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2747 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2748 !strcasecmp(val
, "true"))
2749 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2751 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2755 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2756 !strcasecmp(val
, "true"))
2758 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2760 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2764 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2765 !strcasecmp(val
, "true"))
2766 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2769 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2772 cgiSetVariable("MAX_CLIENTS", val
);
2774 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2777 cgiSetVariable("MAX_JOBS", val
);
2779 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2782 cgiSetVariable("MAX_LOG_SIZE", val
);
2784 cupsFreeOptions(num_settings
, settings
);
2787 * See if Samba and the Windows drivers are installed...
2790 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2791 datadir
= CUPS_DATADIR
;
2793 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2794 if (!access(filename
, R_OK
))
2797 * Found Windows 2000 driver file, see if we have smbclient and
2801 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2802 sizeof(filename
)) &&
2803 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2805 cgiSetVariable("HAVE_SAMBA", "Y");
2808 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2810 fputs("ERROR: smbclient not found!\n", stderr
);
2812 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2814 fputs("ERROR: rpcclient not found!\n", stderr
);
2824 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2826 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2827 NULL
, "ipp://localhost/");
2829 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2831 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2832 ippDelete(response
);
2836 * Finally, show the main menu template...
2839 cgiStartHTML(cgiText(_("Administration")));
2841 cgiCopyTemplateLang("admin.tmpl");
2848 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2852 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2854 int i
; /* Looping var */
2855 ipp_t
*request
, /* IPP request */
2856 *response
; /* IPP response */
2857 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2858 const char *printer
, /* Printer name (purge-jobs) */
2859 *is_class
, /* Is a class? */
2860 *users
, /* List of users or groups */
2861 *type
; /* Allow/deny type */
2862 int num_users
; /* Number of users */
2863 char *ptr
, /* Pointer into users string */
2864 *end
, /* Pointer to end of users string */
2865 quote
; /* Quote character */
2866 ipp_attribute_t
*attr
; /* Attribute */
2867 static const char * const attrs
[] = /* Requested attributes */
2869 "requesting-user-name-allowed",
2870 "requesting-user-name-denied"
2874 is_class
= cgiGetVariable("IS_CLASS");
2875 printer
= cgiGetVariable("PRINTER_NAME");
2879 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2880 cgiStartHTML(cgiText(_("Set Allowed Users")));
2881 cgiCopyTemplateLang("error.tmpl");
2886 users
= cgiGetVariable("users");
2887 type
= cgiGetVariable("type");
2889 if (!users
|| !type
||
2890 (strcmp(type
, "requesting-user-name-allowed") &&
2891 strcmp(type
, "requesting-user-name-denied")))
2894 * Build a Get-Printer-Attributes request, which requires the following
2897 * attributes-charset
2898 * attributes-natural-language
2900 * requested-attributes
2903 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2905 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2906 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2908 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2911 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2912 "requested-attributes",
2913 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2916 * Do the request and get back a response...
2919 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2921 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2923 ippDelete(response
);
2926 cgiStartHTML(cgiText(_("Set Allowed Users")));
2928 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2930 puts("Status: 401\n");
2933 else if (cupsLastError() > IPP_OK_CONFLICT
)
2934 cgiShowIPPError(_("Unable to get printer attributes:"));
2936 cgiCopyTemplateLang("users.tmpl");
2943 * Save the changes...
2946 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2949 * Skip whitespace and commas...
2952 while (*ptr
== ',' || isspace(*ptr
& 255))
2958 if (*ptr
== '\'' || *ptr
== '\"')
2961 * Scan quoted name...
2966 for (end
= ptr
; *end
; end
++)
2973 * Scan space or comma-delimited name...
2976 for (end
= ptr
; *end
; end
++)
2977 if (isspace(*end
& 255) || *end
== ',')
2982 * Advance to the next name...
2989 * Build a CUPS-Add-Printer/Class request, which requires the following
2992 * attributes-charset
2993 * attributes-natural-language
2995 * requesting-user-name-{allowed,denied}
2998 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3000 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3001 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3003 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3007 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3008 "requesting-user-name-allowed", NULL
, "all");
3011 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3012 type
, num_users
, NULL
, NULL
);
3014 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
3017 * Skip whitespace and commas...
3020 while (*ptr
== ',' || isspace(*ptr
& 255))
3026 if (*ptr
== '\'' || *ptr
== '\"')
3029 * Scan quoted name...
3034 for (end
= ptr
; *end
; end
++)
3041 * Scan space or comma-delimited name...
3044 for (end
= ptr
; *end
; end
++)
3045 if (isspace(*end
& 255) || *end
== ',')
3050 * Terminate the name...
3060 attr
->values
[i
].string
.text
= _cupsStrAlloc(ptr
);
3063 * Advance to the next name...
3071 * Do the request and get back a response...
3074 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3076 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3078 puts("Status: 401\n");
3081 else if (cupsLastError() > IPP_OK_CONFLICT
)
3083 cgiStartHTML(cgiText(_("Set Allowed Users")));
3084 cgiShowIPPError(_("Unable to change printer:"));
3089 * Redirect successful updates back to the printer page...
3092 char url
[1024], /* Printer/class URL */
3093 refresh
[1024]; /* Refresh URL */
3096 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3097 cgiFormEncode(uri
, url
, sizeof(uri
));
3098 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
3100 cgiSetVariable("refresh_page", refresh
);
3102 cgiStartHTML(cgiText(_("Set Allowed Users")));
3104 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3105 "printer-modified.tmpl");
3114 * 'do_set_default()' - Set the server default printer/class.
3118 do_set_default(http_t
*http
) /* I - HTTP connection */
3120 const char *title
; /* Page title */
3121 ipp_t
*request
; /* IPP request */
3122 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3123 const char *printer
, /* Printer name (purge-jobs) */
3124 *is_class
; /* Is a class? */
3127 is_class
= cgiGetVariable("IS_CLASS");
3128 printer
= cgiGetVariable("PRINTER_NAME");
3129 title
= cgiText(_("Set As Server Default"));
3133 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3134 cgiStartHTML(title
);
3135 cgiCopyTemplateLang("error.tmpl");
3141 * Build a printer request, which requires the following
3144 * attributes-charset
3145 * attributes-natural-language
3149 request
= ippNewRequest(CUPS_SET_DEFAULT
);
3151 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3152 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3154 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3158 * Do the request and get back a response...
3161 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3163 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3165 puts("Status: 401\n");
3168 else if (cupsLastError() > IPP_OK_CONFLICT
)
3170 cgiStartHTML(title
);
3171 cgiShowIPPError(_("Unable to set server default:"));
3176 * Redirect successful updates back to the printer page...
3179 char url
[1024], /* Printer/class URL */
3180 refresh
[1024]; /* Refresh URL */
3183 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3184 cgiFormEncode(uri
, url
, sizeof(uri
));
3185 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3186 cgiSetVariable("refresh_page", refresh
);
3188 cgiStartHTML(title
);
3189 cgiCopyTemplateLang("printer-default.tmpl");
3197 * 'do_set_options()' - Configure the default options for a queue.
3201 do_set_options(http_t
*http
, /* I - HTTP connection */
3202 int is_class
) /* I - Set options for class? */
3204 int i
, j
, k
, m
; /* Looping vars */
3205 int have_options
; /* Have options? */
3206 ipp_t
*request
, /* IPP request */
3207 *response
; /* IPP response */
3208 ipp_attribute_t
*attr
; /* IPP attribute */
3209 char uri
[HTTP_MAX_URI
]; /* Job URI */
3210 const char *var
; /* Variable value */
3211 const char *printer
; /* Printer printer name */
3212 const char *filename
; /* PPD filename */
3213 char tempfile
[1024]; /* Temporary filename */
3214 cups_file_t
*in
, /* Input file */
3215 *out
; /* Output file */
3216 char line
[1024], /* Line from PPD file */
3217 value
[1024], /* Option value */
3218 keyword
[1024], /* Keyword from Default line */
3219 *keyptr
; /* Pointer into keyword... */
3220 ppd_file_t
*ppd
; /* PPD file */
3221 ppd_group_t
*group
; /* Option group */
3222 ppd_option_t
*option
; /* Option */
3223 ppd_coption_t
*coption
; /* Custom option */
3224 ppd_cparam_t
*cparam
; /* Custom parameter */
3225 ppd_attr_t
*ppdattr
; /* PPD attribute */
3226 const char *title
; /* Page title */
3229 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
3231 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
3235 * Get the printer name...
3238 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
3239 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3240 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3244 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3245 cgiStartHTML(title
);
3246 cgiCopyTemplateLang("error.tmpl");
3251 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
3254 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3255 * command file to the printer...
3258 if (cgiGetVariable("AUTOCONFIGURE"))
3260 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
3265 * Get the PPD file...
3271 filename
= cupsGetPPD2(http
, printer
);
3275 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
3277 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
3279 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
3280 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3281 cgiStartHTML(title
);
3282 cgiCopyTemplateLang("error.tmpl");
3289 fputs("DEBUG: No PPD file\n", stderr
);
3293 if (cgiGetVariable("job_sheets_start") != NULL
||
3294 cgiGetVariable("job_sheets_end") != NULL
)
3301 ppdMarkDefaults(ppd
);
3303 for (option
= ppdFirstOption(ppd
);
3305 option
= ppdNextOption(ppd
))
3307 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
3310 ppdMarkOption(ppd
, option
->keyword
, var
);
3311 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
3314 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
3318 if (!have_options
|| ppdConflicts(ppd
))
3321 * Show the options to the user...
3324 fputs("DEBUG: Showing options...\n", stderr
);
3327 * Show auto-configure button if supported...
3332 if (ppd
->num_filters
== 0 ||
3333 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
3334 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
3335 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3338 for (i
= 0; i
< ppd
->num_filters
; i
++)
3339 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
3341 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3348 * Get the printer attributes...
3351 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3353 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3354 "localhost", 0, "/printers/%s", printer
);
3355 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3358 response
= cupsDoRequest(http
, request
, "/");
3361 * List the groups used as "tabs"...
3368 for (group
= ppd
->groups
;
3369 i
< ppd
->num_groups
;
3372 cgiSetArray("GROUP_ID", i
, group
->name
);
3374 if (!strcmp(group
->name
, "InstallableOptions"))
3375 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
3377 cgiSetArray("GROUP", i
, group
->text
);
3381 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
3383 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
3384 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
3387 if (ippFindAttribute(response
, "printer-error-policy-supported",
3389 ippFindAttribute(response
, "printer-op-policy-supported",
3392 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
3393 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3396 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3397 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3399 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3400 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3403 cgiStartHTML(cgiText(_("Set Printer Options")));
3404 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3410 if (ppdConflicts(ppd
))
3412 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3415 for (j
= group
->num_options
, option
= group
->options
;
3418 if (option
->conflicted
)
3420 cgiSetArray("ckeyword", k
, option
->keyword
);
3421 cgiSetArray("ckeytext", k
, option
->text
);
3423 for (m
= 0; m
< option
->num_choices
; m
++)
3425 if (option
->choices
[m
].marked
)
3427 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3435 cgiCopyTemplateLang("option-conflict.tmpl");
3438 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3442 cgiSetVariable("GROUP_ID", group
->name
);
3444 if (!strcmp(group
->name
, "InstallableOptions"))
3445 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3447 cgiSetVariable("GROUP", group
->text
);
3449 cgiCopyTemplateLang("option-header.tmpl");
3451 for (j
= group
->num_options
, option
= group
->options
;
3455 if (!strcmp(option
->keyword
, "PageRegion"))
3458 cgiSetVariable("KEYWORD", option
->keyword
);
3459 cgiSetVariable("KEYTEXT", option
->text
);
3461 if (option
->conflicted
)
3462 cgiSetVariable("CONFLICTED", "1");
3464 cgiSetVariable("CONFLICTED", "0");
3466 cgiSetSize("CHOICES", 0);
3467 cgiSetSize("TEXT", 0);
3468 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3470 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3471 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3475 if (option
->choices
[k
].marked
)
3476 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3479 cgiSetSize("PARAMS", 0);
3480 cgiSetSize("PARAMTEXT", 0);
3481 cgiSetSize("PARAMVALUE", 0);
3482 cgiSetSize("INPUTTYPE", 0);
3484 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3486 const char *units
= NULL
; /* Units value, if any */
3489 cgiSetVariable("ISCUSTOM", "1");
3491 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3493 cparam
= ppdNextCustomParam(coption
), m
++)
3495 if (!strcasecmp(option
->keyword
, "PageSize") &&
3496 strcasecmp(cparam
->name
, "Width") &&
3497 strcasecmp(cparam
->name
, "Height"))
3503 cgiSetArray("PARAMS", m
, cparam
->name
);
3504 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3505 cgiSetArray("INPUTTYPE", m
, "text");
3507 switch (cparam
->type
)
3509 case PPD_CUSTOM_POINTS
:
3510 if (!strncasecmp(option
->defchoice
, "Custom.", 7))
3512 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3514 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3515 strcmp(units
, "in") && strcmp(units
, "ft"))
3517 if (units
[1] == 'm')
3526 if (!strcmp(units
, "mm"))
3527 snprintf(value
, sizeof(value
), "%g",
3528 cparam
->current
.custom_points
/ 72.0 * 25.4);
3529 else if (!strcmp(units
, "cm"))
3530 snprintf(value
, sizeof(value
), "%g",
3531 cparam
->current
.custom_points
/ 72.0 * 2.54);
3532 else if (!strcmp(units
, "in"))
3533 snprintf(value
, sizeof(value
), "%g",
3534 cparam
->current
.custom_points
/ 72.0);
3535 else if (!strcmp(units
, "ft"))
3536 snprintf(value
, sizeof(value
), "%g",
3537 cparam
->current
.custom_points
/ 72.0 / 12.0);
3538 else if (!strcmp(units
, "m"))
3539 snprintf(value
, sizeof(value
), "%g",
3540 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3542 snprintf(value
, sizeof(value
), "%g",
3543 cparam
->current
.custom_points
);
3544 cgiSetArray("PARAMVALUE", m
, value
);
3547 case PPD_CUSTOM_CURVE
:
3548 case PPD_CUSTOM_INVCURVE
:
3549 case PPD_CUSTOM_REAL
:
3550 snprintf(value
, sizeof(value
), "%g",
3551 cparam
->current
.custom_real
);
3552 cgiSetArray("PARAMVALUE", m
, value
);
3555 case PPD_CUSTOM_INT
:
3556 snprintf(value
, sizeof(value
), "%d",
3557 cparam
->current
.custom_int
);
3558 cgiSetArray("PARAMVALUE", m
, value
);
3561 case PPD_CUSTOM_PASSCODE
:
3562 case PPD_CUSTOM_PASSWORD
:
3563 if (cparam
->current
.custom_password
)
3564 cgiSetArray("PARAMVALUE", m
,
3565 cparam
->current
.custom_password
);
3567 cgiSetArray("PARAMVALUE", m
, "");
3568 cgiSetArray("INPUTTYPE", m
, "password");
3571 case PPD_CUSTOM_STRING
:
3572 if (cparam
->current
.custom_string
)
3573 cgiSetArray("PARAMVALUE", m
,
3574 cparam
->current
.custom_string
);
3576 cgiSetArray("PARAMVALUE", m
, "");
3583 cgiSetArray("PARAMS", m
, "Units");
3584 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3585 cgiSetArray("PARAMVALUE", m
, units
);
3589 cgiSetVariable("ISCUSTOM", "0");
3593 case PPD_UI_BOOLEAN
:
3594 cgiCopyTemplateLang("option-boolean.tmpl");
3596 case PPD_UI_PICKONE
:
3597 cgiCopyTemplateLang("option-pickone.tmpl");
3599 case PPD_UI_PICKMANY
:
3600 cgiCopyTemplateLang("option-pickmany.tmpl");
3605 cgiCopyTemplateLang("option-trailer.tmpl");
3609 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3610 IPP_TAG_ZERO
)) != NULL
)
3613 * Add the job sheets options...
3616 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3617 cgiSetVariable("GROUP", cgiText(_("Banners")));
3618 cgiCopyTemplateLang("option-header.tmpl");
3620 cgiSetSize("CHOICES", attr
->num_values
);
3621 cgiSetSize("TEXT", attr
->num_values
);
3622 for (k
= 0; k
< attr
->num_values
; k
++)
3624 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3625 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3628 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3630 cgiSetVariable("KEYWORD", "job_sheets_start");
3631 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3632 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3633 attr
->values
[0].string
.text
: "");
3635 cgiCopyTemplateLang("option-pickone.tmpl");
3637 cgiSetVariable("KEYWORD", "job_sheets_end");
3638 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3639 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3640 attr
->values
[1].string
.text
: "");
3642 cgiCopyTemplateLang("option-pickone.tmpl");
3644 cgiCopyTemplateLang("option-trailer.tmpl");
3647 if (ippFindAttribute(response
, "printer-error-policy-supported",
3649 ippFindAttribute(response
, "printer-op-policy-supported",
3653 * Add the error and operation policy options...
3656 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3657 cgiSetVariable("GROUP", cgiText(_("Policies")));
3658 cgiCopyTemplateLang("option-header.tmpl");
3664 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3669 cgiSetSize("CHOICES", attr
->num_values
);
3670 cgiSetSize("TEXT", attr
->num_values
);
3671 for (k
= 0; k
< attr
->num_values
; k
++)
3673 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3674 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3677 attr
= ippFindAttribute(response
, "printer-error-policy",
3680 cgiSetVariable("KEYWORD", "printer_error_policy");
3681 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3682 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3683 "" : attr
->values
[0].string
.text
);
3686 cgiCopyTemplateLang("option-pickone.tmpl");
3689 * Operation policy...
3692 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3697 cgiSetSize("CHOICES", attr
->num_values
);
3698 cgiSetSize("TEXT", attr
->num_values
);
3699 for (k
= 0; k
< attr
->num_values
; k
++)
3701 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3702 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3705 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3707 cgiSetVariable("KEYWORD", "printer_op_policy");
3708 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3709 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3710 "" : attr
->values
[0].string
.text
);
3712 cgiCopyTemplateLang("option-pickone.tmpl");
3715 cgiCopyTemplateLang("option-trailer.tmpl");
3719 * Binary protocol support...
3722 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3723 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3725 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3726 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3728 cgiSetSize("CHOICES", attr
->num_values
);
3729 cgiSetSize("TEXT", attr
->num_values
);
3731 for (i
= 0; i
< attr
->num_values
; i
++)
3733 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3734 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3737 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3738 cgiSetVariable("KEYWORD", "port_monitor");
3739 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3740 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3742 cgiCopyTemplateLang("option-header.tmpl");
3743 cgiCopyTemplateLang("option-pickone.tmpl");
3744 cgiCopyTemplateLang("option-trailer.tmpl");
3747 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3750 ippDelete(response
);
3755 * Set default options...
3758 fputs("DEBUG: Setting options...\n", stderr
);
3762 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3763 in
= cupsFileOpen(filename
, "r");
3767 cgiSetVariable("ERROR", strerror(errno
));
3768 cgiStartHTML(cgiText(_("Set Printer Options")));
3769 cgiCopyTemplateLang("error.tmpl");
3785 while (cupsFileGets(in
, line
, sizeof(line
)))
3787 if (!strncmp(line
, "*cupsProtocol:", 14))
3789 else if (strncmp(line
, "*Default", 8))
3790 cupsFilePrintf(out
, "%s\n", line
);
3794 * Get default option name...
3797 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3799 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3800 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3805 if (!strcmp(keyword
, "PageRegion") ||
3806 !strcmp(keyword
, "PaperDimension") ||
3807 !strcmp(keyword
, "ImageableArea"))
3808 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3810 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3813 cupsFilePrintf(out
, "%s\n", line
);
3815 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3825 * Make sure temporary filename is cleared when there is no PPD...
3832 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3833 * following attributes:
3835 * attributes-charset
3836 * attributes-natural-language
3838 * job-sheets-default
3839 * printer-error-policy
3844 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3845 CUPS_ADD_MODIFY_PRINTER
);
3847 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3850 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3851 "job-sheets-default", 2, NULL
, NULL
);
3852 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3853 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3855 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3856 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3857 "printer-error-policy", NULL
, var
);
3859 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3860 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3861 "printer-op-policy", NULL
, var
);
3863 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3864 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3865 "port-monitor", NULL
, var
);
3868 * Do the request and get back a response...
3872 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3874 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3876 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3878 puts("Status: 401\n");
3881 else if (cupsLastError() > IPP_OK_CONFLICT
)
3883 cgiStartHTML(title
);
3884 cgiShowIPPError(_("Unable to set options:"));
3889 * Redirect successful updates back to the printer page...
3892 char refresh
[1024]; /* Refresh URL */
3895 cgiFormEncode(uri
, printer
, sizeof(uri
));
3896 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3897 is_class
? "classes" : "printers", uri
);
3898 cgiSetVariable("refresh_page", refresh
);
3900 cgiStartHTML(title
);
3902 cgiCopyTemplateLang("printer-configured.tmpl");
3917 * 'do_set_sharing()' - Set printer-is-shared value.
3921 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3923 ipp_t
*request
, /* IPP request */
3924 *response
; /* IPP response */
3925 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3926 const char *printer
, /* Printer name */
3927 *is_class
, /* Is a class? */
3928 *shared
; /* Sharing value */
3931 is_class
= cgiGetVariable("IS_CLASS");
3932 printer
= cgiGetVariable("PRINTER_NAME");
3933 shared
= cgiGetVariable("SHARED");
3935 if (!printer
|| !shared
)
3937 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3938 cgiStartHTML(cgiText(_("Set Publishing")));
3939 cgiCopyTemplateLang("error.tmpl");
3945 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3946 * following attributes:
3948 * attributes-charset
3949 * attributes-natural-language
3954 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3956 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3957 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3959 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3962 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3965 * Do the request and get back a response...
3968 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3970 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3972 ippDelete(response
);
3975 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3977 puts("Status: 401\n");
3980 else if (cupsLastError() > IPP_OK_CONFLICT
)
3982 cgiStartHTML(cgiText(_("Set Publishing")));
3983 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3988 * Redirect successful updates back to the printer page...
3991 char url
[1024], /* Printer/class URL */
3992 refresh
[1024]; /* Refresh URL */
3995 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3996 cgiFormEncode(uri
, url
, sizeof(uri
));
3997 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3998 cgiSetVariable("refresh_page", refresh
);
4000 cgiStartHTML(cgiText(_("Set Publishing")));
4001 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
4002 "printer-modified.tmpl");
4010 * 'get_option_value()' - Return the value of an option.
4012 * This function also handles generation of custom option values.
4015 static char * /* O - Value string or NULL on error */
4017 ppd_file_t
*ppd
, /* I - PPD file */
4018 const char *name
, /* I - Option name */
4019 char *buffer
, /* I - String buffer */
4020 size_t bufsize
) /* I - Size of buffer */
4022 char *bufptr
, /* Pointer into buffer */
4023 *bufend
; /* End of buffer */
4024 ppd_coption_t
*coption
; /* Custom option */
4025 ppd_cparam_t
*cparam
; /* Current custom parameter */
4026 char keyword
[256]; /* Parameter name */
4027 const char *val
, /* Parameter value */
4028 *uval
; /* Units value */
4029 long integer
; /* Integer value */
4030 double number
, /* Number value */
4031 number_points
; /* Number in points */
4035 * See if we have a custom option choice...
4038 if ((val
= cgiGetVariable(name
)) == NULL
)
4046 else if (strcasecmp(val
, "Custom") ||
4047 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
4050 * Not a custom choice...
4053 strlcpy(buffer
, val
, bufsize
);
4058 * OK, we have a custom option choice, format it...
4063 if (!strcmp(coption
->keyword
, "PageSize"))
4065 const char *lval
; /* Length string value */
4066 double width
, /* Width value */
4067 width_points
, /* Width in points */
4068 length
, /* Length value */
4069 length_points
; /* Length in points */
4072 val
= cgiGetVariable("PageSize.Width");
4073 lval
= cgiGetVariable("PageSize.Height");
4074 uval
= cgiGetVariable("PageSize.Units");
4076 if (!val
|| !lval
|| !uval
||
4077 (width
= strtod(val
, NULL
)) == 0.0 ||
4078 (length
= strtod(lval
, NULL
)) == 0.0 ||
4079 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4080 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4083 width_points
= get_points(width
, uval
);
4084 length_points
= get_points(length
, uval
);
4086 if (width_points
< ppd
->custom_min
[0] ||
4087 width_points
> ppd
->custom_max
[0] ||
4088 length_points
< ppd
->custom_min
[1] ||
4089 length_points
> ppd
->custom_max
[1])
4092 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
4094 else if (cupsArrayCount(coption
->params
) == 1)
4096 cparam
= ppdFirstCustomParam(coption
);
4097 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
4099 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4102 switch (cparam
->type
)
4104 case PPD_CUSTOM_CURVE
:
4105 case PPD_CUSTOM_INVCURVE
:
4106 case PPD_CUSTOM_REAL
:
4107 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4108 number
< cparam
->minimum
.custom_real
||
4109 number
> cparam
->maximum
.custom_real
)
4112 snprintf(buffer
, bufsize
, "Custom.%g", number
);
4115 case PPD_CUSTOM_INT
:
4116 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4117 integer
== LONG_MAX
||
4118 integer
< cparam
->minimum
.custom_int
||
4119 integer
> cparam
->maximum
.custom_int
)
4122 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
4125 case PPD_CUSTOM_POINTS
:
4126 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4128 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4129 (uval
= cgiGetVariable(keyword
)) == NULL
||
4130 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4131 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4134 number_points
= get_points(number
, uval
);
4135 if (number_points
< cparam
->minimum
.custom_points
||
4136 number_points
> cparam
->maximum
.custom_points
)
4139 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
4142 case PPD_CUSTOM_PASSCODE
:
4143 for (uval
= val
; *uval
; uval
++)
4144 if (!isdigit(*uval
& 255))
4147 case PPD_CUSTOM_PASSWORD
:
4148 case PPD_CUSTOM_STRING
:
4149 integer
= (long)strlen(val
);
4150 if (integer
< cparam
->minimum
.custom_string
||
4151 integer
> cparam
->maximum
.custom_string
)
4154 snprintf(buffer
, bufsize
, "Custom.%s", val
);
4160 const char *prefix
= "{"; /* Prefix string */
4164 bufend
= buffer
+ bufsize
;
4166 for (cparam
= ppdFirstCustomParam(coption
);
4168 cparam
= ppdNextCustomParam(coption
))
4170 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
4173 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4176 snprintf(bufptr
, bufend
- bufptr
, "%s%s=", prefix
, cparam
->name
);
4177 bufptr
+= strlen(bufptr
);
4180 switch (cparam
->type
)
4182 case PPD_CUSTOM_CURVE
:
4183 case PPD_CUSTOM_INVCURVE
:
4184 case PPD_CUSTOM_REAL
:
4185 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4186 number
< cparam
->minimum
.custom_real
||
4187 number
> cparam
->maximum
.custom_real
)
4190 snprintf(bufptr
, bufend
- bufptr
, "%g", number
);
4193 case PPD_CUSTOM_INT
:
4194 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4195 integer
== LONG_MAX
||
4196 integer
< cparam
->minimum
.custom_int
||
4197 integer
> cparam
->maximum
.custom_int
)
4200 snprintf(bufptr
, bufend
- bufptr
, "%ld", integer
);
4203 case PPD_CUSTOM_POINTS
:
4204 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4206 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4207 (uval
= cgiGetVariable(keyword
)) == NULL
||
4208 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
4209 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
4210 strcmp(uval
, "mm") && strcmp(uval
, "m")))
4213 number_points
= get_points(number
, uval
);
4214 if (number_points
< cparam
->minimum
.custom_points
||
4215 number_points
> cparam
->maximum
.custom_points
)
4218 snprintf(bufptr
, bufend
- bufptr
, "%g%s", number
, uval
);
4221 case PPD_CUSTOM_PASSCODE
:
4222 for (uval
= val
; *uval
; uval
++)
4223 if (!isdigit(*uval
& 255))
4226 case PPD_CUSTOM_PASSWORD
:
4227 case PPD_CUSTOM_STRING
:
4228 integer
= (long)strlen(val
);
4229 if (integer
< cparam
->minimum
.custom_string
||
4230 integer
> cparam
->maximum
.custom_string
)
4233 if ((bufptr
+ 2) > bufend
)
4239 while (*val
&& bufptr
< bufend
)
4241 if (*val
== '\\' || *val
== '\"')
4243 if ((bufptr
+ 1) >= bufend
)
4252 if (bufptr
>= bufend
)
4261 bufptr
+= strlen(bufptr
);
4264 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
4267 strcpy(bufptr
, "}");
4275 * 'get_points()' - Get a value in points.
4278 static double /* O - Number in points */
4279 get_points(double number
, /* I - Original number */
4280 const char *uval
) /* I - Units */
4282 if (!strcmp(uval
, "mm")) /* Millimeters */
4283 return (number
* 72.0 / 25.4);
4284 else if (!strcmp(uval
, "cm")) /* Centimeters */
4285 return (number
* 72.0 / 2.54);
4286 else if (!strcmp(uval
, "in")) /* Inches */
4287 return (number
* 72.0);
4288 else if (!strcmp(uval
, "ft")) /* Feet */
4289 return (number
* 72.0 * 12.0);
4290 else if (!strcmp(uval
, "m")) /* Meters */
4291 return (number
* 72.0 / 0.0254);
4298 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".