2 * "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * main() - Main entry for CGI.
18 * choose_device_cb() - Add a device to the device selection page.
19 * do_add_rss_subscription() - Add a RSS subscription.
20 * do_am_class() - Add or modify a class.
21 * do_am_printer() - Add or modify a printer.
22 * do_cancel_subscription() - Cancel a subscription.
23 * do_config_server() - Configure server settings.
24 * do_delete_class() - Delete a class.
25 * do_delete_printer() - Delete a printer.
26 * do_export() - Export printers to Samba.
27 * do_list_printers() - List available printers.
28 * do_menu() - Show the main menu.
29 * do_set_allowed_users() - Set the allowed/denied users for a queue.
30 * do_set_default() - Set the server default printer/class.
31 * do_set_options() - Configure the default options for a queue.
32 * do_set_sharing() - Set printer-is-shared value.
33 * get_option_value() - Return the value of an option.
34 * get_points() - Get a value in points.
38 * Include necessary headers...
41 #include "cgi-private.h"
42 #include <cups/adminutil.h>
43 #include <cups/file.h>
55 static void choose_device_cb(const char *device_class
,
56 const char *device_id
, const char *device_info
,
57 const char *device_make_and_model
,
58 const char *device_uri
,
59 const char *device_location
,
61 static void do_add_rss_subscription(http_t
*http
);
62 static void do_am_class(http_t
*http
, int modify
);
63 static void do_am_printer(http_t
*http
, int modify
);
64 static void do_cancel_subscription(http_t
*http
);
65 static void do_config_server(http_t
*http
);
66 static void do_delete_class(http_t
*http
);
67 static void do_delete_printer(http_t
*http
);
68 static void do_export(http_t
*http
);
69 static void do_list_printers(http_t
*http
);
70 static void do_menu(http_t
*http
);
71 static void do_set_allowed_users(http_t
*http
);
72 static void do_set_default(http_t
*http
);
73 static void do_set_options(http_t
*http
, int is_class
);
74 static void do_set_sharing(http_t
*http
);
75 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
76 char *buffer
, size_t bufsize
);
77 static double get_points(double number
, const char *uval
);
81 * 'main()' - Main entry for CGI.
84 int /* O - Exit status */
85 main(int argc
, /* I - Number of command-line arguments */
86 char *argv
[]) /* I - Command-line arguments */
88 http_t
*http
; /* Connection to the server */
89 const char *op
; /* Operation name */
93 * Connect to the HTTP server...
96 fputs("DEBUG: admin.cgi started...\n", stderr
);
98 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
102 perror("ERROR: Unable to connect to cupsd");
103 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
104 cupsServer() ? cupsServer() : "(null)");
105 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
106 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
110 fprintf(stderr
, "DEBUG: http=%p\n", http
);
113 * Set the web interface section...
116 cgiSetVariable("SECTION", "admin");
117 cgiSetVariable("REFRESH_PAGE", "");
120 * See if we have form data...
123 if (!cgiInitialize() || !cgiGetVariable("OP"))
126 * Nope, send the administration menu...
129 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
133 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
136 * Do the operation...
139 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
141 if (!strcmp(op
, "set-allowed-users"))
142 do_set_allowed_users(http
);
143 else if (!strcmp(op
, "set-as-default"))
144 do_set_default(http
);
145 else if (!strcmp(op
, "set-sharing"))
146 do_set_sharing(http
);
147 else if (!strcmp(op
, "find-new-printers") ||
148 !strcmp(op
, "list-available-printers"))
149 do_list_printers(http
);
150 else if (!strcmp(op
, "add-class"))
151 do_am_class(http
, 0);
152 else if (!strcmp(op
, "add-printer"))
153 do_am_printer(http
, 0);
154 else if (!strcmp(op
, "modify-class"))
155 do_am_class(http
, 1);
156 else if (!strcmp(op
, "modify-printer"))
157 do_am_printer(http
, 1);
158 else if (!strcmp(op
, "delete-class"))
159 do_delete_class(http
);
160 else if (!strcmp(op
, "delete-printer"))
161 do_delete_printer(http
);
162 else if (!strcmp(op
, "set-class-options"))
163 do_set_options(http
, 1);
164 else if (!strcmp(op
, "set-printer-options"))
165 do_set_options(http
, 0);
166 else if (!strcmp(op
, "config-server"))
167 do_config_server(http
);
168 else if (!strcmp(op
, "export-samba"))
170 else if (!strcmp(op
, "add-rss-subscription"))
171 do_add_rss_subscription(http
);
172 else if (!strcmp(op
, "cancel-subscription"))
173 do_cancel_subscription(http
);
177 * Bad operation code - display an error...
180 cgiStartHTML(cgiText(_("Administration")));
181 cgiCopyTemplateLang("error-op.tmpl");
185 else if (op
&& !strcmp(op
, "redirect"))
187 const char *url
; /* Redirection URL... */
188 char prefix
[1024]; /* URL prefix */
192 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
193 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
195 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
196 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
198 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
200 if ((url
= cgiGetVariable("URL")) != NULL
)
202 char encoded
[1024], /* Encoded URL string */
203 *ptr
; /* Pointer into encoded string */
210 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
212 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
215 * Percent-encode this character; safe because we have at least 4
216 * bytes left in the array...
219 sprintf(ptr
, "%%%02X", *url
& 255);
231 * URL was too long, just redirect to the admin page...
234 printf("Location: %s/admin\n\n", prefix
);
239 * URL is OK, redirect there...
242 printf("Location: %s%s\n\n", prefix
, encoded
);
246 printf("Location: %s/admin\n\n", prefix
);
251 * Form data but no operation code - display an error...
254 cgiStartHTML(cgiText(_("Administration")));
255 cgiCopyTemplateLang("error-op.tmpl");
260 * Close the HTTP server connection...
266 * Return with no errors...
274 * 'choose_device_cb()' - Add a device to the device selection page.
279 const char *device_class
, /* I - Class */
280 const char *device_id
, /* I - 1284 device ID */
281 const char *device_info
, /* I - Description */
282 const char *device_make_and_model
, /* I - Make and model */
283 const char *device_uri
, /* I - Device URI */
284 const char *device_location
, /* I - Location */
285 int *current_device
) /* I - Current device index */
288 * Add the device to the array...
291 cgiSetArray("device_class", *current_device
, device_class
);
292 cgiSetArray("device_id", *current_device
, device_id
);
293 cgiSetArray("device_info", *current_device
, device_info
);
294 cgiSetArray("device_make_and_model", *current_device
, device_make_and_model
);
295 cgiSetArray("device_uri", *current_device
, device_uri
);
296 cgiSetArray("device_location", *current_device
, device_location
);
298 (*current_device
) ++;
303 * 'do_add_rss_subscription()' - Add a RSS subscription.
307 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
309 ipp_t
*request
, /* IPP request data */
310 *response
; /* IPP response data */
311 char rss_uri
[1024]; /* RSS notify-recipient URI */
312 int num_events
; /* Number of events */
313 const char *events
[12], /* Subscribed events */
314 *subscription_name
, /* Subscription name */
315 *printer_uri
, /* Printer URI */
316 *ptr
, /* Pointer into name */
317 *user
; /* Username */
318 int max_events
; /* Maximum number of events */
322 * See if we have all of the required information...
325 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
326 printer_uri
= cgiGetVariable("PRINTER_URI");
329 if (cgiGetVariable("EVENT_JOB_CREATED"))
330 events
[num_events
++] = "job-created";
331 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
332 events
[num_events
++] = "job-completed";
333 if (cgiGetVariable("EVENT_JOB_STOPPED"))
334 events
[num_events
++] = "job-stopped";
335 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
336 events
[num_events
++] = "job-config-changed";
337 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
338 events
[num_events
++] = "printer-stopped";
339 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
340 events
[num_events
++] = "printer-added";
341 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
342 events
[num_events
++] = "printer-modified";
343 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
344 events
[num_events
++] = "printer-deleted";
345 if (cgiGetVariable("EVENT_SERVER_STARTED"))
346 events
[num_events
++] = "server-started";
347 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
348 events
[num_events
++] = "server-stopped";
349 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
350 events
[num_events
++] = "server-restarted";
351 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
352 events
[num_events
++] = "server-audit";
354 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
355 max_events
= atoi(ptr
);
359 if (!subscription_name
|| !printer_uri
|| !num_events
||
360 max_events
<= 0 || max_events
> 9999)
363 * Don't have everything we need, so get the available printers
364 * and classes and (re)show the add page...
367 if (cgiGetVariable("EVENT_JOB_CREATED"))
368 cgiSetVariable("EVENT_JOB_CREATED", "CHECKED");
369 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
370 cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED");
371 if (cgiGetVariable("EVENT_JOB_STOPPED"))
372 cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED");
373 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
374 cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED");
375 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
376 cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED");
377 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
378 cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED");
379 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
380 cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED");
381 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
382 cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED");
383 if (cgiGetVariable("EVENT_SERVER_STARTED"))
384 cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED");
385 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
386 cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED");
387 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
388 cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED");
389 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
390 cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED");
392 request
= ippNewRequest(CUPS_GET_PRINTERS
);
393 response
= cupsDoRequest(http
, request
, "/");
395 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
399 cgiStartHTML(cgiText(_("Add RSS Subscription")));
401 cgiCopyTemplateLang("add-rss-subscription.tmpl");
408 * Make sure we have a username...
411 if ((user
= getenv("REMOTE_USER")) == NULL
)
413 puts("Status: 401\n");
418 * Validate the subscription name...
421 for (ptr
= subscription_name
; *ptr
; ptr
++)
422 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
423 *ptr
== '?' || *ptr
== '#')
428 cgiSetVariable("ERROR",
429 cgiText(_("The subscription name may not "
430 "contain spaces, slashes (/), question marks (?), "
431 "or the pound sign (#).")));
432 cgiStartHTML(_("Add RSS Subscription"));
433 cgiCopyTemplateLang("error.tmpl");
439 * Add the subscription...
442 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
443 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
444 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
445 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
448 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
449 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
452 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
454 if (!strcasecmp(printer_uri
, "#ALL#"))
455 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
456 NULL
, "ipp://localhost/");
458 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
461 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
464 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
465 "notify-recipient-uri", NULL
, rss_uri
);
466 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
467 num_events
, NULL
, events
);
468 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
469 "notify-lease-duration", 0);
471 ippDelete(cupsDoRequest(http
, request
, "/"));
473 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
475 puts("Status: 401\n");
478 else if (cupsLastError() > IPP_OK_CONFLICT
)
480 cgiStartHTML(_("Add RSS Subscription"));
481 cgiShowIPPError(_("Unable to add RSS subscription:"));
486 * Redirect successful updates back to the admin page...
489 cgiSetVariable("refresh_page", "5;URL=/admin");
490 cgiStartHTML(_("Add RSS Subscription"));
491 cgiCopyTemplateLang("subscription-added.tmpl");
499 * 'do_am_class()' - Add or modify a class.
503 do_am_class(http_t
*http
, /* I - HTTP connection */
504 int modify
) /* I - Modify the printer? */
506 int i
, j
; /* Looping vars */
507 int element
; /* Element number */
508 int num_printers
; /* Number of printers */
509 ipp_t
*request
, /* IPP request */
510 *response
; /* IPP response */
511 ipp_attribute_t
*attr
; /* member-uris attribute */
512 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
513 const char *name
, /* Pointer to class name */
514 *op
, /* Operation name */
515 *ptr
; /* Pointer to CGI variable */
516 const char *title
; /* Title of page */
517 static const char * const pattrs
[] = /* Requested printer attributes */
525 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
526 op
= cgiGetVariable("OP");
527 name
= cgiGetVariable("PRINTER_NAME");
529 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
532 * Build a CUPS_GET_PRINTERS request, which requires the
533 * following attributes:
536 * attributes-natural-language
539 request
= ippNewRequest(CUPS_GET_PRINTERS
);
541 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
543 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
544 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
545 CUPS_PRINTER_IMPLICIT
);
548 * Do the request and get back a response...
553 cgiSetVariable("OP", op
);
555 cgiSetVariable("PRINTER_NAME", name
);
557 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
560 * Create MEMBER_URIS and MEMBER_NAMES arrays...
563 for (element
= 0, attr
= response
->attrs
;
566 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
568 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
569 (!name
|| strcasecmp(name
, ptr
+ 1)))
572 * Don't show the current class...
575 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
580 for (element
= 0, attr
= response
->attrs
;
583 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
585 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
588 * Don't show the current class...
591 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
596 num_printers
= cgiGetSize("MEMBER_URIS");
606 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
607 * following attributes:
610 * attributes-natural-language
614 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
616 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
617 "localhost", 0, "/classes/%s", name
);
618 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
621 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
622 "requested-attributes",
623 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
627 * Do the request and get back a response...
630 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
632 if ((attr
= ippFindAttribute(response
, "member-names",
633 IPP_TAG_NAME
)) != NULL
)
636 * Mark any current members in the class...
639 for (j
= 0; j
< num_printers
; j
++)
640 cgiSetArray("MEMBER_SELECTED", j
, "");
642 for (i
= 0; i
< attr
->num_values
; i
++)
644 for (j
= 0; j
< num_printers
; j
++)
646 if (!strcasecmp(attr
->values
[i
].string
.text
,
647 cgiGetArray("MEMBER_NAMES", j
)))
649 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
656 if ((attr
= ippFindAttribute(response
, "printer-info",
657 IPP_TAG_TEXT
)) != NULL
)
658 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
660 if ((attr
= ippFindAttribute(response
, "printer-location",
661 IPP_TAG_TEXT
)) != NULL
)
662 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
668 * Update the location and description of an existing printer...
672 cgiCopyTemplateLang("modify-class.tmpl");
677 * Get the name, location, and description for a new printer...
681 cgiCopyTemplateLang("add-class.tmpl");
692 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
693 cgiCopyTemplateLang("error.tmpl");
698 for (ptr
= name
; *ptr
; ptr
++)
699 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
702 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
704 cgiSetVariable("ERROR",
705 cgiText(_("The class name may only contain up to "
706 "127 printable characters and may not "
707 "contain spaces, slashes (/), or the "
708 "pound sign (#).")));
710 cgiCopyTemplateLang("error.tmpl");
716 * Build a CUPS_ADD_CLASS request, which requires the following
720 * attributes-natural-language
724 * printer-is-accepting-jobs
729 request
= ippNewRequest(CUPS_ADD_CLASS
);
731 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
732 "localhost", 0, "/classes/%s", name
);
733 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
736 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
737 NULL
, cgiGetVariable("PRINTER_LOCATION"));
739 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
740 NULL
, cgiGetVariable("PRINTER_INFO"));
742 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
744 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
747 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
749 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
750 num_printers
, NULL
, NULL
);
751 for (i
= 0; i
< num_printers
; i
++)
752 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
756 * Do the request and get back a response...
759 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
761 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
763 puts("Status: 401\n");
766 else if (cupsLastError() > IPP_OK_CONFLICT
)
769 cgiShowIPPError(modify
? _("Unable to modify class:") :
770 _("Unable to add class:"));
775 * Redirect successful updates back to the class page...
778 char refresh
[1024]; /* Refresh URL */
780 cgiFormEncode(uri
, name
, sizeof(uri
));
781 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
783 cgiSetVariable("refresh_page", refresh
);
788 cgiCopyTemplateLang("class-modified.tmpl");
790 cgiCopyTemplateLang("class-added.tmpl");
798 * 'do_am_printer()' - Add or modify a printer.
802 do_am_printer(http_t
*http
, /* I - HTTP connection */
803 int modify
) /* I - Modify the printer? */
805 int i
; /* Looping var */
806 ipp_attribute_t
*attr
; /* Current attribute */
807 ipp_t
*request
, /* IPP request */
808 *response
, /* IPP response */
809 *oldinfo
; /* Old printer information */
810 const cgi_file_t
*file
; /* Uploaded file, if any */
811 const char *var
; /* CGI variable */
812 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
813 *uriptr
; /* Pointer into URI */
814 int maxrate
; /* Maximum baud rate */
815 char baudrate
[255]; /* Baud rate string */
816 const char *name
, /* Pointer to class name */
817 *ptr
; /* Pointer to CGI variable */
818 const char *title
; /* Title of page */
819 int current_device
; /* Index of current device */
820 static int baudrates
[] = /* Baud rates */
835 ptr
= cgiGetVariable("DEVICE_URI");
836 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
837 ptr
? ptr
: "(null)");
839 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
844 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
845 * following attributes:
848 * attributes-natural-language
852 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
854 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
855 "localhost", 0, "/printers/%s",
856 cgiGetVariable("PRINTER_NAME"));
857 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
861 * Do the request and get back a response...
864 oldinfo
= cupsDoRequest(http
, request
, "/");
873 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
874 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
875 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
876 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
879 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
881 for (ptr
= name
; *ptr
; ptr
++)
882 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
885 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
887 cgiSetVariable("ERROR",
888 cgiText(_("The printer name may only contain up to "
889 "127 printable characters and may not "
890 "contain spaces, slashes (/), or the "
891 "pound sign (#).")));
893 cgiCopyTemplateLang("error.tmpl");
899 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
901 if ((uriptr
= strrchr(var
, '|')) != NULL
)
904 * Extract make and make/model from device URI string...
907 char make
[1024], /* Make string */
908 *makeptr
; /* Pointer into make */
913 strlcpy(make
, uriptr
, sizeof(make
));
915 if ((makeptr
= strchr(make
, ' ')) != NULL
)
917 else if ((makeptr
= strchr(make
, '-')) != NULL
)
919 else if (!strncasecmp(make
, "laserjet", 8) ||
920 !strncasecmp(make
, "deskjet", 7) ||
921 !strncasecmp(make
, "designjet", 9))
923 else if (!strncasecmp(make
, "phaser", 6))
924 strcpy(make
, "Xerox");
925 else if (!strncasecmp(make
, "stylus", 6))
926 strcpy(make
, "Epson");
928 strcpy(make
, "Generic");
930 if (!cgiGetVariable("CURRENT_MAKE"))
931 cgiSetVariable("CURRENT_MAKE", make
);
933 cgiSetVariable("PPD_MAKE", make
);
935 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
936 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
940 char template[128], /* Template name */
941 *tptr
; /* Pointer into template name */
943 cgiSetVariable("PRINTER_INFO", uriptr
);
945 for (tptr
= template;
946 tptr
< (template + sizeof(template) - 1) && *uriptr
;
948 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
951 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
954 else if (*uriptr
== '?' || *uriptr
== '(')
959 cgiSetVariable("TEMPLATE_NAME", template);
967 * Look for devices so the user can pick something...
970 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
972 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
973 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
976 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
977 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
981 * For modern browsers, start a multi-part page so we can show that something
982 * is happening. Non-modern browsers just get everything at the end...
985 if (cgiSupportsMultipart())
989 cgiCopyTemplateLang("choose-device.tmpl");
995 * Scan for devices for up to 30 seconds...
998 fputs("DEBUG: Getting list of devices...\n", stderr
);
1001 if (cupsGetDevices(http
, 30, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
1002 (cups_device_cb_t
)choose_device_cb
,
1003 ¤t_device
) == IPP_OK
)
1005 fputs("DEBUG: Got device list!\n", stderr
);
1007 if (cgiSupportsMultipart())
1008 cgiStartMultipart();
1010 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1011 cgiStartHTML(title
);
1012 cgiCopyTemplateLang("choose-device.tmpl");
1015 if (cgiSupportsMultipart())
1021 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1022 cupsLastError(), cupsLastErrorString());
1023 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1025 puts("Status: 401\n");
1030 cgiStartHTML(title
);
1031 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1032 _("Unable to add printer:"));
1038 else if (strchr(var
, '/') == NULL
)
1040 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
1043 * Set the current device URI for the form to the old one...
1046 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
1047 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
1051 * User needs to set the full URI...
1054 cgiStartHTML(title
);
1055 cgiCopyTemplateLang("choose-uri.tmpl");
1058 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1061 * Need baud rate, parity, etc.
1064 if ((var
= strchr(var
, '?')) != NULL
&&
1065 strncmp(var
, "?baud=", 6) == 0)
1066 maxrate
= atoi(var
+ 6);
1070 for (i
= 0; i
< 10; i
++)
1071 if (baudrates
[i
] > maxrate
)
1075 sprintf(baudrate
, "%d", baudrates
[i
]);
1076 cgiSetArray("BAUDRATES", i
, baudrate
);
1079 cgiStartHTML(title
);
1080 cgiCopyTemplateLang("choose-serial.tmpl");
1083 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
1085 cgiStartHTML(title
);
1090 * Update the location and description of an existing printer...
1095 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
1096 IPP_TAG_TEXT
)) != NULL
)
1097 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
1099 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
1100 IPP_TAG_TEXT
)) != NULL
)
1101 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
1103 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
1104 IPP_TAG_BOOLEAN
)) != NULL
)
1105 cgiSetVariable("PRINTER_IS_SHARED",
1106 attr
->values
[0].boolean
? "1" : "0");
1109 cgiCopyTemplateLang("modify-printer.tmpl");
1114 * Get the name, location, and description for a new printer...
1118 if (!strncmp(var
, "usb:", 4))
1119 cgiSetVariable("printer_is_shared", "1");
1121 #endif /* __APPLE__ */
1122 cgiSetVariable("printer_is_shared", "0");
1124 cgiCopyTemplateLang("add-printer.tmpl");
1135 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1137 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
1140 * Get the PPD file...
1143 int fd
; /* PPD file */
1144 char filename
[1024]; /* PPD filename */
1145 ppd_file_t
*ppd
; /* PPD information */
1146 char buffer
[1024]; /* Buffer */
1147 int bytes
; /* Number of bytes */
1148 http_status_t get_status
; /* Status of GET */
1151 /* TODO: Use cupsGetFile() API... */
1152 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1154 if (httpGet(http
, uri
))
1157 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1159 if (get_status
!= HTTP_OK
)
1163 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1164 uri
, get_status
, httpStatus(get_status
));
1166 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1168 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1169 write(fd
, buffer
, bytes
);
1173 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1175 if (ppd
->manufacturer
)
1176 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1179 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1186 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1187 filename
, ppdErrorString(ppdLastError(&bytes
)));
1195 "ERROR: Unable to create temporary file for PPD file: %s\n",
1201 * Build a CUPS_GET_PPDS request, which requires the following
1204 * attributes-charset
1205 * attributes-natural-language
1209 request
= ippNewRequest(CUPS_GET_PPDS
);
1211 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1212 NULL
, "ipp://localhost/printers/");
1214 if ((var
= cgiGetVariable("CURRENT_MAKE")) == NULL
)
1215 var
= cgiGetVariable("PPD_MAKE");
1216 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1218 const char *make_model
; /* Make and model */
1221 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1222 "ppd-make", NULL
, var
);
1224 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1225 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1226 "ppd-make-and-model", NULL
, make_model
);
1229 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1230 "requested-attributes", NULL
, "ppd-make");
1233 * Do the request and get back a response...
1236 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1239 * Got the list of PPDs, see if the user has selected a make...
1242 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1245 * No PPD files with this make, try again with all makes...
1248 ippDelete(response
);
1250 request
= ippNewRequest(CUPS_GET_PPDS
);
1252 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1253 NULL
, "ipp://localhost/printers/");
1255 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1256 "requested-attributes", NULL
, "ppd-make");
1258 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1259 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1261 cgiStartHTML(title
);
1262 cgiCopyTemplateLang("choose-make.tmpl");
1265 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1267 cgiStartHTML(title
);
1268 cgiCopyTemplateLang("choose-make.tmpl");
1274 * Let the user choose a model...
1277 cgiStartHTML(title
);
1278 if (!cgiGetVariable("PPD_MAKE"))
1279 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1281 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1282 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1283 cgiCopyTemplateLang("choose-model.tmpl");
1287 ippDelete(response
);
1291 cgiStartHTML(title
);
1292 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1293 cgiCopyTemplateLang("error.tmpl");
1300 * Build a CUPS_ADD_PRINTER request, which requires the following
1303 * attributes-charset
1304 * attributes-natural-language
1310 * printer-is-accepting-jobs
1315 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1317 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1318 "localhost", 0, "/printers/%s",
1319 cgiGetVariable("PRINTER_NAME"));
1320 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1323 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1324 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1326 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1327 NULL
, cgiGetVariable("PRINTER_INFO"));
1331 var
= cgiGetVariable("PPD_NAME");
1332 if (strcmp(var
, "__no_change__"))
1333 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1337 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1340 * Strip make and model from URI...
1343 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1346 if (!strncmp(uri
, "serial:", 7))
1349 * Update serial port URI to include baud rate, etc.
1352 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1353 uriptr
= uri
+ strlen(uri
);
1355 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1356 "?baud=%s+bits=%s+parity=%s+flow=%s",
1357 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1358 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1361 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1364 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1366 var
= cgiGetVariable("printer_is_shared");
1367 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1368 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1370 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1374 * Do the request and get back a response...
1378 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1380 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1382 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1384 puts("Status: 401\n");
1387 else if (cupsLastError() > IPP_OK_CONFLICT
)
1389 cgiStartHTML(title
);
1390 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1391 _("Unable to add printer:"));
1396 * Redirect successful updates back to the printer page...
1399 char refresh
[1024]; /* Refresh URL */
1402 cgiFormEncode(uri
, name
, sizeof(uri
));
1404 snprintf(refresh
, sizeof(refresh
),
1405 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1407 cgiSetVariable("refresh_page", refresh
);
1409 cgiStartHTML(title
);
1411 cgiCopyTemplateLang("printer-modified.tmpl");
1416 * Set the printer options...
1419 cgiSetVariable("OP", "set-printer-options");
1420 do_set_options(http
, 0);
1433 * 'do_cancel_subscription()' - Cancel a subscription.
1437 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1439 ipp_t
*request
; /* IPP request data */
1440 const char *var
, /* Form variable */
1441 *user
; /* Username */
1442 int id
; /* Subscription ID */
1446 * See if we have all of the required information...
1449 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1456 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1457 cgiStartHTML(_("Cancel RSS Subscription"));
1458 cgiCopyTemplateLang("error.tmpl");
1464 * Require a username...
1467 if ((user
= getenv("REMOTE_USER")) == NULL
)
1469 puts("Status: 401\n");
1474 * Cancel the subscription...
1477 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1479 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1480 NULL
, "ipp://localhost/");
1481 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1482 "notify-subscription-id", id
);
1484 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1487 ippDelete(cupsDoRequest(http
, request
, "/"));
1489 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1491 puts("Status: 401\n");
1494 else if (cupsLastError() > IPP_OK_CONFLICT
)
1496 cgiStartHTML(_("Cancel RSS Subscription"));
1497 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1502 * Redirect successful updates back to the admin page...
1505 cgiSetVariable("refresh_page", "5;URL=/admin");
1506 cgiStartHTML(_("Cancel RSS Subscription"));
1507 cgiCopyTemplateLang("subscription-canceled.tmpl");
1515 * 'do_config_server()' - Configure server settings.
1519 do_config_server(http_t
*http
) /* I - HTTP connection */
1521 if (cgiGetVariable("CHANGESETTINGS"))
1524 * Save basic setting changes...
1527 int num_settings
; /* Number of server settings */
1528 cups_option_t
*settings
; /* Server settings */
1529 int advanced
, /* Advanced settings shown? */
1530 changed
; /* Have settings changed? */
1531 const char *debug_logging
, /* DEBUG_LOGGING value */
1532 *remote_admin
, /* REMOTE_ADMIN value */
1533 *remote_any
, /* REMOTE_ANY value */
1535 /* REMOTE_PRINTERS value */
1536 *share_printers
,/* SHARE_PRINTERS value */
1538 /* USER_CANCEL_ANY value */
1539 *browse_web_if
= NULL
,
1540 /* BrowseWebIF value */
1541 *preserve_job_history
= NULL
,
1542 /* PreserveJobHistory value */
1543 *preserve_job_files
= NULL
,
1544 /* PreserveJobFiles value */
1545 *max_clients
= NULL
,
1546 /* MaxClients value */
1549 *max_log_size
= NULL
;
1550 /* MaxLogSize value */
1551 char local_protocols
[255],
1552 /* BrowseLocalProtocols */
1553 remote_protocols
[255];
1554 /* BrowseRemoteProtocols */
1555 const char *current_browse_web_if
,
1556 /* BrowseWebIF value */
1557 *current_preserve_job_history
,
1558 /* PreserveJobHistory value */
1559 *current_preserve_job_files
,
1560 /* PreserveJobFiles value */
1561 *current_max_clients
,
1562 /* MaxClients value */
1565 *current_max_log_size
,
1566 /* MaxLogSize value */
1567 *current_local_protocols
,
1568 /* BrowseLocalProtocols */
1569 *current_remote_protocols
;
1570 /* BrowseRemoteProtocols */
1572 char default_auth_type
[255];
1573 /* DefaultAuthType value */
1574 const char *val
; /* Setting value */
1575 #endif /* HAVE_GSSAPI */
1579 * Get the checkbox values from the form...
1582 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1583 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1584 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1585 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1586 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1587 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1589 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1593 * Get advanced settings...
1596 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1597 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1598 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1599 max_clients
= cgiGetVariable("MAX_CLIENTS");
1600 max_jobs
= cgiGetVariable("MAX_JOBS");
1601 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1603 if (!max_clients
|| atoi(max_clients
) <= 0)
1604 max_clients
= "100";
1606 if (!max_jobs
|| atoi(max_jobs
) <= 0)
1609 if (!max_log_size
|| atof(max_log_size
) <= 0.0)
1610 max_log_size
= "1m";
1612 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1613 strcpy(local_protocols
, "cups");
1615 local_protocols
[0] = '\0';
1618 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1620 if (local_protocols
[0])
1621 strcat(local_protocols
, " dnssd");
1623 strcat(local_protocols
, "dnssd");
1625 #endif /* HAVE_DNSSD */
1628 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1630 if (local_protocols
[0])
1631 strcat(local_protocols
, " ldap");
1633 strcat(local_protocols
, "ldap");
1635 #endif /* HAVE_LDAP */
1638 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1640 if (local_protocols
[0])
1641 strcat(local_protocols
, " slp");
1643 strcat(local_protocols
, "slp");
1645 #endif /* HAVE_SLP */
1647 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1648 strcpy(remote_protocols
, "cups");
1650 remote_protocols
[0] = '\0';
1653 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1655 if (remote_protocols
[0])
1656 strcat(remote_protocols
, " ldap");
1658 strcat(remote_protocols
, "ldap");
1660 #endif /* HAVE_LDAP */
1663 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1665 if (remote_protocols
[0])
1666 strcat(remote_protocols
, " slp");
1668 strcat(remote_protocols
, "slp");
1670 #endif /* HAVE_SLP */
1674 * Get the current server settings...
1677 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1679 cgiStartHTML(cgiText(_("Change Settings")));
1680 cgiSetVariable("MESSAGE",
1681 cgiText(_("Unable to change server settings:")));
1682 cgiSetVariable("ERROR", cupsLastErrorString());
1683 cgiCopyTemplateLang("error.tmpl");
1690 * Get authentication settings...
1693 if (cgiGetVariable("KERBEROS"))
1694 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1697 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1699 if (!val
|| !strcasecmp(val
, "Negotiate"))
1700 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1702 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1705 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1706 #endif /* HAVE_GSSAPI */
1708 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1710 current_browse_web_if
= "No";
1712 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1715 current_preserve_job_history
= "Yes";
1717 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1720 current_preserve_job_files
= "No";
1722 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1724 current_max_clients
= "100";
1726 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1728 current_max_jobs
= "500";
1730 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1732 current_max_log_size
= "1m";
1734 if ((current_local_protocols
= cupsGetOption("BrowseLocalProtocols",
1737 current_local_protocols
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
1739 if ((current_remote_protocols
= cupsGetOption("BrowseRemoteProtocols",
1742 current_remote_protocols
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
1745 * See if the settings have changed...
1748 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1749 num_settings
, settings
)) ||
1750 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1751 num_settings
, settings
)) ||
1752 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1753 num_settings
, settings
)) ||
1754 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1755 num_settings
, settings
)) ||
1756 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1757 num_settings
, settings
)) ||
1759 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1760 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1761 num_settings
, settings
)) ||
1762 #endif /* HAVE_GSSAPI */
1763 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1764 num_settings
, settings
));
1766 if (advanced
&& !changed
)
1767 changed
= strcasecmp(local_protocols
, current_local_protocols
) ||
1768 strcasecmp(remote_protocols
, current_remote_protocols
) ||
1769 strcasecmp(browse_web_if
, current_browse_web_if
) ||
1770 strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1771 strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1772 strcasecmp(max_clients
, current_max_clients
) ||
1773 strcasecmp(max_jobs
, current_max_jobs
) ||
1774 strcasecmp(max_log_size
, current_max_log_size
);
1779 * Settings *have* changed, so save the changes...
1782 cupsFreeOptions(num_settings
, settings
);
1785 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1786 debug_logging
, num_settings
, &settings
);
1787 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1788 remote_admin
, num_settings
, &settings
);
1789 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1790 remote_any
, num_settings
, &settings
);
1791 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1792 remote_printers
, num_settings
, &settings
);
1793 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1794 share_printers
, num_settings
, &settings
);
1795 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1796 user_cancel_any
, num_settings
, &settings
);
1798 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1799 num_settings
, &settings
);
1800 #endif /* HAVE_GSSAPI */
1805 * Add advanced settings...
1808 if (strcasecmp(local_protocols
, current_local_protocols
))
1809 num_settings
= cupsAddOption("BrowseLocalProtocols", local_protocols
,
1810 num_settings
, &settings
);
1811 if (strcasecmp(remote_protocols
, current_remote_protocols
))
1812 num_settings
= cupsAddOption("BrowseRemoteProtocols", remote_protocols
,
1813 num_settings
, &settings
);
1814 if (strcasecmp(browse_web_if
, current_browse_web_if
))
1815 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1816 num_settings
, &settings
);
1817 if (strcasecmp(preserve_job_history
, current_preserve_job_history
))
1818 num_settings
= cupsAddOption("PreserveJobHistory",
1819 preserve_job_history
, num_settings
,
1821 if (strcasecmp(preserve_job_files
, current_preserve_job_files
))
1822 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1823 num_settings
, &settings
);
1824 if (strcasecmp(max_clients
, current_max_clients
))
1825 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1827 if (strcasecmp(max_jobs
, current_max_jobs
))
1828 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1830 if (strcasecmp(max_log_size
, current_max_log_size
))
1831 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1835 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1837 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1839 puts("Status: 401\n");
1843 cgiStartHTML(cgiText(_("Change Settings")));
1844 cgiSetVariable("MESSAGE",
1845 cgiText(_("Unable to change server settings:")));
1846 cgiSetVariable("ERROR", cupsLastErrorString());
1847 cgiCopyTemplateLang("error.tmpl");
1852 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1854 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1855 cgiStartHTML(cgiText(_("Change Settings")));
1856 cgiCopyTemplateLang("restart.tmpl");
1865 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1866 cgiStartHTML(cgiText(_("Change Settings")));
1867 cgiCopyTemplateLang("norestart.tmpl");
1870 cupsFreeOptions(num_settings
, settings
);
1874 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1877 * Save hand-edited config file...
1880 http_status_t status
; /* PUT status */
1881 char tempfile
[1024]; /* Temporary new cupsd.conf */
1882 int tempfd
; /* Temporary file descriptor */
1883 cups_file_t
*temp
; /* Temporary file */
1884 const char *start
, /* Start of line */
1885 *end
; /* End of line */
1889 * Create a temporary file for the new cupsd.conf file...
1892 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1894 cgiStartHTML(cgiText(_("Edit Configuration File")));
1895 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1896 cgiSetVariable("ERROR", strerror(errno
));
1897 cgiCopyTemplateLang("error.tmpl");
1904 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1906 cgiStartHTML(cgiText(_("Edit Configuration File")));
1907 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1908 cgiSetVariable("ERROR", strerror(errno
));
1909 cgiCopyTemplateLang("error.tmpl");
1919 * Copy the cupsd.conf text from the form variable...
1922 start
= cgiGetVariable("CUPSDCONF");
1925 if ((end
= strstr(start
, "\r\n")) == NULL
)
1926 if ((end
= strstr(start
, "\n")) == NULL
)
1927 end
= start
+ strlen(start
);
1929 cupsFileWrite(temp
, start
, end
- start
);
1930 cupsFilePutChar(temp
, '\n');
1934 else if (*end
== '\n')
1940 cupsFileClose(temp
);
1943 * Upload the configuration file to the server...
1946 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1948 if (status
== HTTP_UNAUTHORIZED
)
1950 puts("Status: 401\n");
1954 else if (status
!= HTTP_CREATED
)
1956 cgiSetVariable("MESSAGE",
1957 cgiText(_("Unable to upload cupsd.conf file:")));
1958 cgiSetVariable("ERROR", httpStatus(status
));
1960 cgiStartHTML(cgiText(_("Edit Configuration File")));
1961 cgiCopyTemplateLang("error.tmpl");
1965 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1967 cgiStartHTML(cgiText(_("Edit Configuration File")));
1968 cgiCopyTemplateLang("restart.tmpl");
1977 struct stat info
; /* cupsd.conf information */
1978 cups_file_t
*cupsd
; /* cupsd.conf file */
1979 char *buffer
, /* Buffer for entire file */
1980 *bufptr
, /* Pointer into buffer */
1981 *bufend
; /* End of buffer */
1982 int ch
; /* Character from file */
1983 char filename
[1024]; /* Filename */
1984 const char *server_root
; /* Location of config files */
1988 * Locate the cupsd.conf file...
1991 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1992 server_root
= CUPS_SERVERROOT
;
1994 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1997 * Figure out the size...
2000 if (stat(filename
, &info
))
2002 cgiStartHTML(cgiText(_("Edit Configuration File")));
2003 cgiSetVariable("MESSAGE",
2004 cgiText(_("Unable to access cupsd.conf file:")));
2005 cgiSetVariable("ERROR", strerror(errno
));
2006 cgiCopyTemplateLang("error.tmpl");
2013 if (info
.st_size
> (1024 * 1024))
2015 cgiStartHTML(cgiText(_("Edit Configuration File")));
2016 cgiSetVariable("MESSAGE",
2017 cgiText(_("Unable to access cupsd.conf file:")));
2018 cgiSetVariable("ERROR",
2019 cgiText(_("Unable to edit cupsd.conf files larger than "
2021 cgiCopyTemplateLang("error.tmpl");
2024 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
2025 (long)info
.st_size
);
2030 * Open the cupsd.conf file...
2033 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
2036 * Unable to open - log an error...
2039 cgiStartHTML(cgiText(_("Edit Configuration File")));
2040 cgiSetVariable("MESSAGE",
2041 cgiText(_("Unable to access cupsd.conf file:")));
2042 cgiSetVariable("ERROR", strerror(errno
));
2043 cgiCopyTemplateLang("error.tmpl");
2051 * Allocate memory and load the file into a string buffer...
2054 if ((buffer
= calloc(1, info
.st_size
+ 1)) != NULL
)
2056 cupsFileRead(cupsd
, buffer
, info
.st_size
);
2057 cgiSetVariable("CUPSDCONF", buffer
);
2061 cupsFileClose(cupsd
);
2064 * Then get the default cupsd.conf file and put that into a string as
2068 strlcat(filename
, ".default", sizeof(filename
));
2070 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
2071 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
2073 if ((buffer
= calloc(1, 2 * info
.st_size
+ 1)) != NULL
)
2075 bufend
= buffer
+ 2 * info
.st_size
- 1;
2077 for (bufptr
= buffer
;
2078 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
2080 if (ch
== '\\' || ch
== '\"')
2085 else if (ch
== '\n')
2090 else if (ch
== '\t')
2101 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
2105 cupsFileClose(cupsd
);
2109 * Show the current config file...
2112 cgiStartHTML(cgiText(_("Edit Configuration File")));
2114 cgiCopyTemplateLang("edit-config.tmpl");
2122 * 'do_delete_class()' - Delete a class.
2126 do_delete_class(http_t
*http
) /* I - HTTP connection */
2128 ipp_t
*request
; /* IPP request */
2129 char uri
[HTTP_MAX_URI
]; /* Job URI */
2130 const char *pclass
; /* Printer class name */
2134 * Get form variables...
2137 if (cgiGetVariable("CONFIRM") == NULL
)
2139 cgiStartHTML(cgiText(_("Delete Class")));
2140 cgiCopyTemplateLang("class-confirm.tmpl");
2145 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2146 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2147 "localhost", 0, "/classes/%s", pclass
);
2150 cgiStartHTML(cgiText(_("Delete Class")));
2151 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2152 cgiCopyTemplateLang("error.tmpl");
2158 * Build a CUPS_DELETE_CLASS request, which requires the following
2161 * attributes-charset
2162 * attributes-natural-language
2166 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2168 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2172 * Do the request and get back a response...
2175 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2178 * Show the results...
2181 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2183 puts("Status: 401\n");
2186 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2189 * Redirect successful updates back to the classes page...
2192 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2195 cgiStartHTML(cgiText(_("Delete Class")));
2197 if (cupsLastError() > IPP_OK_CONFLICT
)
2198 cgiShowIPPError(_("Unable to delete class:"));
2200 cgiCopyTemplateLang("class-deleted.tmpl");
2207 * 'do_delete_printer()' - Delete a printer.
2211 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2213 ipp_t
*request
; /* IPP request */
2214 char uri
[HTTP_MAX_URI
]; /* Job URI */
2215 const char *printer
; /* Printer printer name */
2219 * Get form variables...
2222 if (cgiGetVariable("CONFIRM") == NULL
)
2224 cgiStartHTML(cgiText(_("Delete Printer")));
2225 cgiCopyTemplateLang("printer-confirm.tmpl");
2230 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2231 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2232 "localhost", 0, "/printers/%s", printer
);
2235 cgiStartHTML(cgiText(_("Delete Printer")));
2236 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2237 cgiCopyTemplateLang("error.tmpl");
2243 * Build a CUPS_DELETE_PRINTER request, which requires the following
2246 * attributes-charset
2247 * attributes-natural-language
2251 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2253 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2257 * Do the request and get back a response...
2260 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2263 * Show the results...
2266 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2268 puts("Status: 401\n");
2271 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2274 * Redirect successful updates back to the printers page...
2277 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2280 cgiStartHTML(cgiText(_("Delete Printer")));
2282 if (cupsLastError() > IPP_OK_CONFLICT
)
2283 cgiShowIPPError(_("Unable to delete printer:"));
2285 cgiCopyTemplateLang("printer-deleted.tmpl");
2292 * 'do_export()' - Export printers to Samba.
2296 do_export(http_t
*http
) /* I - HTTP connection */
2298 int i
, j
; /* Looping vars */
2299 ipp_t
*request
, /* IPP request */
2300 *response
; /* IPP response */
2301 const char *username
, /* Samba username */
2302 *password
, /* Samba password */
2303 *export_all
; /* Export all printers? */
2304 int export_count
, /* Number of printers to export */
2305 printer_count
; /* Number of available printers */
2306 const char *name
, /* What name to pull */
2307 *dest
; /* Current destination */
2308 char ppd
[1024]; /* PPD file */
2315 username
= cgiGetVariable("USERNAME");
2316 password
= cgiGetVariable("PASSWORD");
2317 export_all
= cgiGetVariable("EXPORT_ALL");
2318 export_count
= cgiGetSize("EXPORT_NAME");
2321 * Get list of available printers...
2324 cgiSetSize("PRINTER_NAME", 0);
2325 cgiSetSize("PRINTER_EXPORT", 0);
2327 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2329 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2332 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2333 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2334 CUPS_PRINTER_IMPLICIT
);
2336 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2337 "requested-attributes", NULL
, "printer-name");
2339 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2341 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2342 ippDelete(response
);
2346 printer_count
= cgiGetSize("PRINTER_NAME");
2348 for (i
= 0; i
< printer_count
; i
++)
2350 dest
= cgiGetArray("PRINTER_NAME", i
);
2352 for (j
= 0; j
< export_count
; j
++)
2353 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2356 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2362 * Export or get the printers to export...
2365 if (username
&& *username
&& password
&& *password
&&
2366 (export_all
|| export_count
> 0))
2372 fputs("DEBUG: Export printers...\n", stderr
);
2376 name
= "PRINTER_NAME";
2377 export_count
= cgiGetSize("PRINTER_NAME");
2380 name
= "EXPORT_NAME";
2382 for (i
= 0; i
< export_count
; i
++)
2384 dest
= cgiGetArray(name
, i
);
2386 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2389 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2398 if (i
< export_count
)
2399 cgiSetVariable("ERROR", cupsLastErrorString());
2402 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2403 cgiCopyTemplateLang("samba-exported.tmpl");
2408 else if (username
&& !*username
)
2409 cgiSetVariable("ERROR",
2410 cgiText(_("A Samba username is required to export "
2411 "printer drivers")));
2412 else if (username
&& (!password
|| !*password
))
2413 cgiSetVariable("ERROR",
2414 cgiText(_("A Samba password is required to export "
2415 "printer drivers")));
2421 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2422 cgiCopyTemplateLang("samba-export.tmpl");
2428 * 'do_list_printers()' - List available printers.
2432 do_list_printers(http_t
*http
) /* I - HTTP connection */
2434 ipp_t
*request
, /* IPP request */
2435 *response
; /* IPP response */
2436 ipp_attribute_t
*attr
; /* IPP attribute */
2439 cgiStartHTML(cgiText(_("List Available Printers")));
2443 * Get the list of printers and their devices...
2446 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2448 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2449 "requested-attributes", NULL
, "device-uri");
2451 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2452 CUPS_PRINTER_LOCAL
);
2453 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2454 CUPS_PRINTER_LOCAL
);
2456 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2459 * Got the printer list, now load the devices...
2462 int i
; /* Looping var */
2463 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2464 char *printer_device
; /* Current printer device */
2468 * Allocate an array and copy the device strings...
2471 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2473 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2475 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2477 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2481 * Free the printer list and get the device list...
2484 ippDelete(response
);
2486 request
= ippNewRequest(CUPS_GET_DEVICES
);
2488 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2491 * Got the device list, let's parse it...
2494 const char *device_uri
, /* device-uri attribute value */
2495 *device_make_and_model
, /* device-make-and-model value */
2496 *device_info
; /* device-info value */
2499 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2502 * Skip leading attributes until we hit a device...
2505 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2512 * Pull the needed attributes from this device...
2516 device_make_and_model
= NULL
;
2519 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2521 if (!strcmp(attr
->name
, "device-info") &&
2522 attr
->value_tag
== IPP_TAG_TEXT
)
2523 device_info
= attr
->values
[0].string
.text
;
2525 if (!strcmp(attr
->name
, "device-make-and-model") &&
2526 attr
->value_tag
== IPP_TAG_TEXT
)
2527 device_make_and_model
= attr
->values
[0].string
.text
;
2529 if (!strcmp(attr
->name
, "device-uri") &&
2530 attr
->value_tag
== IPP_TAG_URI
)
2531 device_uri
= attr
->values
[0].string
.text
;
2537 * See if we have everything needed...
2540 if (device_info
&& device_make_and_model
&& device_uri
&&
2541 strcasecmp(device_make_and_model
, "unknown") &&
2542 strchr(device_uri
, ':'))
2545 * Yes, now see if there is already a printer for this
2549 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2552 * Not found, so it must be a new printer...
2555 char option
[1024], /* Form variables for this device */
2556 *option_ptr
; /* Pointer into string */
2557 const char *ptr
; /* Pointer into device string */
2561 * Format the printer name variable for this device...
2563 * We use the device-info string first, then device-uri,
2564 * and finally device-make-and-model to come up with a
2568 if (strncasecmp(device_info
, "unknown", 7))
2570 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2573 ptr
= device_make_and_model
;
2575 for (option_ptr
= option
;
2576 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2578 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2580 *option_ptr
++ = *ptr
;
2581 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
[-1] != '_')
2582 *option_ptr
++ = '_';
2583 else if (*ptr
== '?' || *ptr
== '(')
2588 cgiSetArray("TEMPLATE_NAME", i
, option
);
2591 * Finally, set the form variables for this printer...
2594 cgiSetArray("device_info", i
, device_info
);
2595 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2596 cgiSetArray("device_uri", i
, device_uri
);
2605 ippDelete(response
);
2608 * Free the device list...
2611 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2613 printer_device
= (char *)cupsArrayNext(printer_devices
))
2614 free(printer_device
);
2616 cupsArrayDelete(printer_devices
);
2621 * Finally, show the printer list...
2624 cgiCopyTemplateLang("list-available-printers.tmpl");
2631 * 'do_menu()' - Show the main menu.
2635 do_menu(http_t
*http
) /* I - HTTP connection */
2637 int num_settings
; /* Number of server settings */
2638 cups_option_t
*settings
; /* Server settings */
2639 const char *val
; /* Setting value */
2640 char filename
[1024]; /* Temporary filename */
2641 const char *datadir
; /* Location of data files */
2642 ipp_t
*request
, /* IPP request */
2643 *response
; /* IPP response */
2647 * Get the current server settings...
2650 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2652 cgiSetVariable("SETTINGS_MESSAGE",
2653 cgiText(_("Unable to open cupsd.conf file:")));
2654 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2657 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2658 settings
)) != NULL
&& atoi(val
))
2659 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2661 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2662 settings
)) != NULL
&& atoi(val
))
2663 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2665 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2666 settings
)) != NULL
&& atoi(val
))
2667 cgiSetVariable("REMOTE_ANY", "CHECKED");
2669 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2670 settings
)) != NULL
&& atoi(val
))
2671 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2673 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2674 settings
)) != NULL
&& atoi(val
))
2675 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2677 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2678 settings
)) != NULL
&& atoi(val
))
2679 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2682 cgiSetVariable("HAVE_GSSAPI", "1");
2684 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2685 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2686 cgiSetVariable("KERBEROS", "CHECKED");
2688 #endif /* HAVE_GSSAPI */
2689 cgiSetVariable("KERBEROS", "");
2692 cgiSetVariable("HAVE_DNSSD", "1");
2693 #endif /* HAVE_DNSSD */
2696 cgiSetVariable("HAVE_LDAP", "1");
2697 #endif /* HAVE_LDAP */
2700 cgiSetVariable("HAVE_LIBSLP", "1");
2701 #endif /* HAVE_LIBSLP */
2703 if ((val
= cupsGetOption("BrowseRemoteProtocols", num_settings
,
2705 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2707 val
= CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS
;
2709 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2710 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2712 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2713 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2715 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2716 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2718 if ((val
= cupsGetOption("BrowseLocalProtocols", num_settings
,
2720 if ((val
= cupsGetOption("BrowseProtocols", num_settings
,
2722 val
= CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS
;
2724 if (strstr(val
, "cups") || strstr(val
, "CUPS"))
2725 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2727 if (strstr(val
, "dnssd") || strstr(val
, "DNSSD") ||
2728 strstr(val
, "dns-sd") || strstr(val
, "DNS-SD") ||
2729 strstr(val
, "bonjour") || strstr(val
, "BONJOUR"))
2730 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2732 if (strstr(val
, "ldap") || strstr(val
, "LDAP"))
2733 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2735 if (strstr(val
, "slp") || strstr(val
, "SLP"))
2736 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2738 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2742 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2743 !strcasecmp(val
, "true"))
2744 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2746 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2750 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2751 !strcasecmp(val
, "true"))
2753 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2755 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2759 if (!strcasecmp(val
, "yes") || !strcasecmp(val
, "on") ||
2760 !strcasecmp(val
, "true"))
2761 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2764 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2767 cgiSetVariable("MAX_CLIENTS", val
);
2769 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2772 cgiSetVariable("MAX_JOBS", val
);
2774 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2777 cgiSetVariable("MAX_LOG_SIZE", val
);
2779 cupsFreeOptions(num_settings
, settings
);
2782 * See if Samba and the Windows drivers are installed...
2785 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2786 datadir
= CUPS_DATADIR
;
2788 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2789 if (!access(filename
, R_OK
))
2792 * Found Windows 2000 driver file, see if we have smbclient and
2796 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2797 sizeof(filename
)) &&
2798 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2800 cgiSetVariable("HAVE_SAMBA", "Y");
2803 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2805 fputs("ERROR: smbclient not found!\n", stderr
);
2807 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2809 fputs("ERROR: rpcclient not found!\n", stderr
);
2819 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2821 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2822 NULL
, "ipp://localhost/");
2824 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2826 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2827 ippDelete(response
);
2831 * Finally, show the main menu template...
2834 cgiStartHTML(cgiText(_("Administration")));
2836 cgiCopyTemplateLang("admin.tmpl");
2843 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2847 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2849 int i
; /* Looping var */
2850 ipp_t
*request
, /* IPP request */
2851 *response
; /* IPP response */
2852 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2853 const char *printer
, /* Printer name (purge-jobs) */
2854 *is_class
, /* Is a class? */
2855 *users
, /* List of users or groups */
2856 *type
; /* Allow/deny type */
2857 int num_users
; /* Number of users */
2858 char *ptr
, /* Pointer into users string */
2859 *end
, /* Pointer to end of users string */
2860 quote
; /* Quote character */
2861 ipp_attribute_t
*attr
; /* Attribute */
2862 static const char * const attrs
[] = /* Requested attributes */
2864 "requesting-user-name-allowed",
2865 "requesting-user-name-denied"
2869 is_class
= cgiGetVariable("IS_CLASS");
2870 printer
= cgiGetVariable("PRINTER_NAME");
2874 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2875 cgiStartHTML(cgiText(_("Set Allowed Users")));
2876 cgiCopyTemplateLang("error.tmpl");
2881 users
= cgiGetVariable("users");
2882 type
= cgiGetVariable("type");
2884 if (!users
|| !type
||
2885 (strcmp(type
, "requesting-user-name-allowed") &&
2886 strcmp(type
, "requesting-user-name-denied")))
2889 * Build a Get-Printer-Attributes request, which requires the following
2892 * attributes-charset
2893 * attributes-natural-language
2895 * requested-attributes
2898 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2900 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2901 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2903 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2906 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2907 "requested-attributes",
2908 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2911 * Do the request and get back a response...
2914 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2916 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2918 ippDelete(response
);
2921 cgiStartHTML(cgiText(_("Set Allowed Users")));
2923 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2925 puts("Status: 401\n");
2928 else if (cupsLastError() > IPP_OK_CONFLICT
)
2929 cgiShowIPPError(_("Unable to get printer attributes:"));
2931 cgiCopyTemplateLang("users.tmpl");
2938 * Save the changes...
2941 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2944 * Skip whitespace and commas...
2947 while (*ptr
== ',' || isspace(*ptr
& 255))
2953 if (*ptr
== '\'' || *ptr
== '\"')
2956 * Scan quoted name...
2961 for (end
= ptr
; *end
; end
++)
2968 * Scan space or comma-delimited name...
2971 for (end
= ptr
; *end
; end
++)
2972 if (isspace(*end
& 255) || *end
== ',')
2977 * Advance to the next name...
2984 * Build a CUPS-Add-Printer/Class request, which requires the following
2987 * attributes-charset
2988 * attributes-natural-language
2990 * requesting-user-name-{allowed,denied}
2993 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2995 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2996 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2998 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3002 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3003 "requesting-user-name-allowed", NULL
, "all");
3006 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3007 type
, num_users
, NULL
, NULL
);
3009 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
3012 * Skip whitespace and commas...
3015 while (*ptr
== ',' || isspace(*ptr
& 255))
3021 if (*ptr
== '\'' || *ptr
== '\"')
3024 * Scan quoted name...
3029 for (end
= ptr
; *end
; end
++)
3036 * Scan space or comma-delimited name...
3039 for (end
= ptr
; *end
; end
++)
3040 if (isspace(*end
& 255) || *end
== ',')
3045 * Terminate the name...
3055 attr
->values
[i
].string
.text
= strdup(ptr
);
3058 * Advance to the next name...
3066 * Do the request and get back a response...
3069 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3071 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3073 puts("Status: 401\n");
3076 else if (cupsLastError() > IPP_OK_CONFLICT
)
3078 cgiStartHTML(cgiText(_("Set Allowed Users")));
3079 cgiShowIPPError(_("Unable to change printer:"));
3084 * Redirect successful updates back to the printer page...
3087 char url
[1024], /* Printer/class URL */
3088 refresh
[1024]; /* Refresh URL */
3091 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3092 cgiFormEncode(uri
, url
, sizeof(uri
));
3093 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
3095 cgiSetVariable("refresh_page", refresh
);
3097 cgiStartHTML(cgiText(_("Set Allowed Users")));
3099 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3100 "printer-modified.tmpl");
3109 * 'do_set_default()' - Set the server default printer/class.
3113 do_set_default(http_t
*http
) /* I - HTTP connection */
3115 const char *title
; /* Page title */
3116 ipp_t
*request
; /* IPP request */
3117 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3118 const char *printer
, /* Printer name (purge-jobs) */
3119 *is_class
; /* Is a class? */
3122 is_class
= cgiGetVariable("IS_CLASS");
3123 printer
= cgiGetVariable("PRINTER_NAME");
3124 title
= cgiText(_("Set As Server Default"));
3128 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3129 cgiStartHTML(title
);
3130 cgiCopyTemplateLang("error.tmpl");
3136 * Build a printer request, which requires the following
3139 * attributes-charset
3140 * attributes-natural-language
3144 request
= ippNewRequest(CUPS_SET_DEFAULT
);
3146 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3147 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3149 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3153 * Do the request and get back a response...
3156 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3158 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3160 puts("Status: 401\n");
3163 else if (cupsLastError() > IPP_OK_CONFLICT
)
3165 cgiStartHTML(title
);
3166 cgiShowIPPError(_("Unable to set server default:"));
3171 * Redirect successful updates back to the printer page...
3174 char url
[1024], /* Printer/class URL */
3175 refresh
[1024]; /* Refresh URL */
3178 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3179 cgiFormEncode(uri
, url
, sizeof(uri
));
3180 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3181 cgiSetVariable("refresh_page", refresh
);
3183 cgiStartHTML(title
);
3184 cgiCopyTemplateLang("printer-default.tmpl");
3192 * 'do_set_options()' - Configure the default options for a queue.
3196 do_set_options(http_t
*http
, /* I - HTTP connection */
3197 int is_class
) /* I - Set options for class? */
3199 int i
, j
, k
, m
; /* Looping vars */
3200 int have_options
; /* Have options? */
3201 ipp_t
*request
, /* IPP request */
3202 *response
; /* IPP response */
3203 ipp_attribute_t
*attr
; /* IPP attribute */
3204 char uri
[HTTP_MAX_URI
]; /* Job URI */
3205 const char *var
; /* Variable value */
3206 const char *printer
; /* Printer printer name */
3207 const char *filename
; /* PPD filename */
3208 char tempfile
[1024]; /* Temporary filename */
3209 cups_file_t
*in
, /* Input file */
3210 *out
; /* Output file */
3211 char line
[1024], /* Line from PPD file */
3212 value
[1024], /* Option value */
3213 keyword
[1024], /* Keyword from Default line */
3214 *keyptr
; /* Pointer into keyword... */
3215 ppd_file_t
*ppd
; /* PPD file */
3216 ppd_group_t
*group
; /* Option group */
3217 ppd_option_t
*option
; /* Option */
3218 ppd_coption_t
*coption
; /* Custom option */
3219 ppd_cparam_t
*cparam
; /* Custom parameter */
3220 ppd_attr_t
*ppdattr
; /* PPD attribute */
3221 const char *title
; /* Page title */
3224 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
3226 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
3230 * Get the printer name...
3233 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
3234 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3235 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3239 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3240 cgiStartHTML(title
);
3241 cgiCopyTemplateLang("error.tmpl");
3246 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
3249 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3250 * command file to the printer...
3253 if (cgiGetVariable("AUTOCONFIGURE"))
3255 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
3260 * Get the PPD file...
3266 filename
= cupsGetPPD2(http
, printer
);
3270 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
3272 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
3274 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
3275 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3276 cgiStartHTML(title
);
3277 cgiCopyTemplateLang("error.tmpl");
3284 fputs("DEBUG: No PPD file\n", stderr
);
3288 if (cgiGetVariable("job_sheets_start") != NULL
||
3289 cgiGetVariable("job_sheets_end") != NULL
)
3296 ppdMarkDefaults(ppd
);
3298 for (option
= ppdFirstOption(ppd
);
3300 option
= ppdNextOption(ppd
))
3302 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
3305 ppdMarkOption(ppd
, option
->keyword
, var
);
3306 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
3309 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
3313 if (!have_options
|| ppdConflicts(ppd
))
3316 * Show the options to the user...
3319 fputs("DEBUG: Showing options...\n", stderr
);
3322 * Show auto-configure button if supported...
3327 if (ppd
->num_filters
== 0 ||
3328 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
3329 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
3330 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3333 for (i
= 0; i
< ppd
->num_filters
; i
++)
3334 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
3336 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3343 * Get the printer attributes...
3346 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3348 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3349 "localhost", 0, "/printers/%s", printer
);
3350 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3353 response
= cupsDoRequest(http
, request
, "/");
3356 * List the groups used as "tabs"...
3363 for (group
= ppd
->groups
;
3364 i
< ppd
->num_groups
;
3367 cgiSetArray("GROUP_ID", i
, group
->name
);
3369 if (!strcmp(group
->name
, "InstallableOptions"))
3370 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
3372 cgiSetArray("GROUP", i
, group
->text
);
3376 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
3378 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
3379 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
3382 if (ippFindAttribute(response
, "printer-error-policy-supported",
3384 ippFindAttribute(response
, "printer-op-policy-supported",
3387 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
3388 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3391 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3392 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3394 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3395 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3398 cgiStartHTML(cgiText(_("Set Printer Options")));
3399 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3405 if (ppdConflicts(ppd
))
3407 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3410 for (j
= group
->num_options
, option
= group
->options
;
3413 if (option
->conflicted
)
3415 cgiSetArray("ckeyword", k
, option
->keyword
);
3416 cgiSetArray("ckeytext", k
, option
->text
);
3418 for (m
= 0; m
< option
->num_choices
; m
++)
3420 if (option
->choices
[m
].marked
)
3422 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3430 cgiCopyTemplateLang("option-conflict.tmpl");
3433 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3437 cgiSetVariable("GROUP_ID", group
->name
);
3439 if (!strcmp(group
->name
, "InstallableOptions"))
3440 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3442 cgiSetVariable("GROUP", group
->text
);
3444 cgiCopyTemplateLang("option-header.tmpl");
3446 for (j
= group
->num_options
, option
= group
->options
;
3450 if (!strcmp(option
->keyword
, "PageRegion"))
3453 cgiSetVariable("KEYWORD", option
->keyword
);
3454 cgiSetVariable("KEYTEXT", option
->text
);
3456 if (option
->conflicted
)
3457 cgiSetVariable("CONFLICTED", "1");
3459 cgiSetVariable("CONFLICTED", "0");
3461 cgiSetSize("CHOICES", 0);
3462 cgiSetSize("TEXT", 0);
3463 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3465 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3466 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3470 if (option
->choices
[k
].marked
)
3471 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3474 cgiSetSize("PARAMS", 0);
3475 cgiSetSize("PARAMTEXT", 0);
3476 cgiSetSize("PARAMVALUE", 0);
3477 cgiSetSize("INPUTTYPE", 0);
3479 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3481 const char *units
= NULL
; /* Units value, if any */
3484 cgiSetVariable("ISCUSTOM", "1");
3486 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3488 cparam
= ppdNextCustomParam(coption
), m
++)
3490 if (!strcasecmp(option
->keyword
, "PageSize") &&
3491 strcasecmp(cparam
->name
, "Width") &&
3492 strcasecmp(cparam
->name
, "Height"))
3498 cgiSetArray("PARAMS", m
, cparam
->name
);
3499 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3500 cgiSetArray("INPUTTYPE", m
, "text");
3502 switch (cparam
->type
)
3504 case PPD_CUSTOM_POINTS
:
3505 if (!strncasecmp(option
->defchoice
, "Custom.", 7))
3507 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3509 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3510 strcmp(units
, "in") && strcmp(units
, "ft"))
3512 if (units
[1] == 'm')
3521 if (!strcmp(units
, "mm"))
3522 snprintf(value
, sizeof(value
), "%g",
3523 cparam
->current
.custom_points
/ 72.0 * 25.4);
3524 else if (!strcmp(units
, "cm"))
3525 snprintf(value
, sizeof(value
), "%g",
3526 cparam
->current
.custom_points
/ 72.0 * 2.54);
3527 else if (!strcmp(units
, "in"))
3528 snprintf(value
, sizeof(value
), "%g",
3529 cparam
->current
.custom_points
/ 72.0);
3530 else if (!strcmp(units
, "ft"))
3531 snprintf(value
, sizeof(value
), "%g",
3532 cparam
->current
.custom_points
/ 72.0 / 12.0);
3533 else if (!strcmp(units
, "m"))
3534 snprintf(value
, sizeof(value
), "%g",
3535 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3537 snprintf(value
, sizeof(value
), "%g",
3538 cparam
->current
.custom_points
);
3539 cgiSetArray("PARAMVALUE", m
, value
);
3542 case PPD_CUSTOM_CURVE
:
3543 case PPD_CUSTOM_INVCURVE
:
3544 case PPD_CUSTOM_REAL
:
3545 snprintf(value
, sizeof(value
), "%g",
3546 cparam
->current
.custom_real
);
3547 cgiSetArray("PARAMVALUE", m
, value
);
3550 case PPD_CUSTOM_INT
:
3551 snprintf(value
, sizeof(value
), "%d",
3552 cparam
->current
.custom_int
);
3553 cgiSetArray("PARAMVALUE", m
, value
);
3556 case PPD_CUSTOM_PASSCODE
:
3557 case PPD_CUSTOM_PASSWORD
:
3558 if (cparam
->current
.custom_password
)
3559 cgiSetArray("PARAMVALUE", m
,
3560 cparam
->current
.custom_password
);
3562 cgiSetArray("PARAMVALUE", m
, "");
3563 cgiSetArray("INPUTTYPE", m
, "password");
3566 case PPD_CUSTOM_STRING
:
3567 if (cparam
->current
.custom_string
)
3568 cgiSetArray("PARAMVALUE", m
,
3569 cparam
->current
.custom_string
);
3571 cgiSetArray("PARAMVALUE", m
, "");
3578 cgiSetArray("PARAMS", m
, "Units");
3579 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3580 cgiSetArray("PARAMVALUE", m
, units
);
3584 cgiSetVariable("ISCUSTOM", "0");
3588 case PPD_UI_BOOLEAN
:
3589 cgiCopyTemplateLang("option-boolean.tmpl");
3591 case PPD_UI_PICKONE
:
3592 cgiCopyTemplateLang("option-pickone.tmpl");
3594 case PPD_UI_PICKMANY
:
3595 cgiCopyTemplateLang("option-pickmany.tmpl");
3600 cgiCopyTemplateLang("option-trailer.tmpl");
3604 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3605 IPP_TAG_ZERO
)) != NULL
)
3608 * Add the job sheets options...
3611 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3612 cgiSetVariable("GROUP", cgiText(_("Banners")));
3613 cgiCopyTemplateLang("option-header.tmpl");
3615 cgiSetSize("CHOICES", attr
->num_values
);
3616 cgiSetSize("TEXT", attr
->num_values
);
3617 for (k
= 0; k
< attr
->num_values
; k
++)
3619 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3620 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3623 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3625 cgiSetVariable("KEYWORD", "job_sheets_start");
3626 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3627 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3628 attr
->values
[0].string
.text
: "");
3630 cgiCopyTemplateLang("option-pickone.tmpl");
3632 cgiSetVariable("KEYWORD", "job_sheets_end");
3633 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3634 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3635 attr
->values
[1].string
.text
: "");
3637 cgiCopyTemplateLang("option-pickone.tmpl");
3639 cgiCopyTemplateLang("option-trailer.tmpl");
3642 if (ippFindAttribute(response
, "printer-error-policy-supported",
3644 ippFindAttribute(response
, "printer-op-policy-supported",
3648 * Add the error and operation policy options...
3651 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3652 cgiSetVariable("GROUP", cgiText(_("Policies")));
3653 cgiCopyTemplateLang("option-header.tmpl");
3659 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3664 cgiSetSize("CHOICES", attr
->num_values
);
3665 cgiSetSize("TEXT", attr
->num_values
);
3666 for (k
= 0; k
< attr
->num_values
; k
++)
3668 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3669 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3672 attr
= ippFindAttribute(response
, "printer-error-policy",
3675 cgiSetVariable("KEYWORD", "printer_error_policy");
3676 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3677 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3678 "" : attr
->values
[0].string
.text
);
3681 cgiCopyTemplateLang("option-pickone.tmpl");
3684 * Operation policy...
3687 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3692 cgiSetSize("CHOICES", attr
->num_values
);
3693 cgiSetSize("TEXT", attr
->num_values
);
3694 for (k
= 0; k
< attr
->num_values
; k
++)
3696 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3697 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3700 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3702 cgiSetVariable("KEYWORD", "printer_op_policy");
3703 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3704 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3705 "" : attr
->values
[0].string
.text
);
3707 cgiCopyTemplateLang("option-pickone.tmpl");
3710 cgiCopyTemplateLang("option-trailer.tmpl");
3714 * Binary protocol support...
3717 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3718 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3720 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3721 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3723 cgiSetSize("CHOICES", attr
->num_values
);
3724 cgiSetSize("TEXT", attr
->num_values
);
3726 for (i
= 0; i
< attr
->num_values
; i
++)
3728 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3729 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3732 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3733 cgiSetVariable("KEYWORD", "port_monitor");
3734 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3735 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3737 cgiCopyTemplateLang("option-header.tmpl");
3738 cgiCopyTemplateLang("option-pickone.tmpl");
3739 cgiCopyTemplateLang("option-trailer.tmpl");
3742 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3745 ippDelete(response
);
3750 * Set default options...
3753 fputs("DEBUG: Setting options...\n", stderr
);
3757 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3758 in
= cupsFileOpen(filename
, "r");
3762 cgiSetVariable("ERROR", strerror(errno
));
3763 cgiStartHTML(cgiText(_("Set Printer Options")));
3764 cgiCopyTemplateLang("error.tmpl");
3780 while (cupsFileGets(in
, line
, sizeof(line
)))
3782 if (!strncmp(line
, "*cupsProtocol:", 14))
3784 else if (strncmp(line
, "*Default", 8))
3785 cupsFilePrintf(out
, "%s\n", line
);
3789 * Get default option name...
3792 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3794 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3795 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3800 if (!strcmp(keyword
, "PageRegion") ||
3801 !strcmp(keyword
, "PaperDimension") ||
3802 !strcmp(keyword
, "ImageableArea"))
3803 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3805 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3808 cupsFilePrintf(out
, "%s\n", line
);
3810 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3820 * Make sure temporary filename is cleared when there is no PPD...
3827 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3828 * following attributes:
3830 * attributes-charset
3831 * attributes-natural-language
3833 * job-sheets-default
3834 * printer-error-policy
3839 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3840 CUPS_ADD_MODIFY_PRINTER
);
3842 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3845 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3846 "job-sheets-default", 2, NULL
, NULL
);
3847 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3848 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3850 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3851 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3852 "printer-error-policy", NULL
, var
);
3854 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3855 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3856 "printer-op-policy", NULL
, var
);
3858 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3859 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3860 "port-monitor", NULL
, var
);
3863 * Do the request and get back a response...
3867 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3869 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3871 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3873 puts("Status: 401\n");
3876 else if (cupsLastError() > IPP_OK_CONFLICT
)
3878 cgiStartHTML(title
);
3879 cgiShowIPPError(_("Unable to set options:"));
3884 * Redirect successful updates back to the printer page...
3887 char refresh
[1024]; /* Refresh URL */
3890 cgiFormEncode(uri
, printer
, sizeof(uri
));
3891 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3892 is_class
? "classes" : "printers", uri
);
3893 cgiSetVariable("refresh_page", refresh
);
3895 cgiStartHTML(title
);
3897 cgiCopyTemplateLang("printer-configured.tmpl");
3912 * 'do_set_sharing()' - Set printer-is-shared value.
3916 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3918 ipp_t
*request
, /* IPP request */
3919 *response
; /* IPP response */
3920 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3921 const char *printer
, /* Printer name */
3922 *is_class
, /* Is a class? */
3923 *shared
; /* Sharing value */
3926 is_class
= cgiGetVariable("IS_CLASS");
3927 printer
= cgiGetVariable("PRINTER_NAME");
3928 shared
= cgiGetVariable("SHARED");
3930 if (!printer
|| !shared
)
3932 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3933 cgiStartHTML(cgiText(_("Set Publishing")));
3934 cgiCopyTemplateLang("error.tmpl");
3940 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3941 * following attributes:
3943 * attributes-charset
3944 * attributes-natural-language
3949 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3951 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3952 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3954 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3957 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3960 * Do the request and get back a response...
3963 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3965 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3967 ippDelete(response
);
3970 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3972 puts("Status: 401\n");
3975 else if (cupsLastError() > IPP_OK_CONFLICT
)
3977 cgiStartHTML(cgiText(_("Set Publishing")));
3978 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3983 * Redirect successful updates back to the printer page...
3986 char url
[1024], /* Printer/class URL */
3987 refresh
[1024]; /* Refresh URL */
3990 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3991 cgiFormEncode(uri
, url
, sizeof(uri
));
3992 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3993 cgiSetVariable("refresh_page", refresh
);
3995 cgiStartHTML(cgiText(_("Set Publishing")));
3996 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3997 "printer-modified.tmpl");
4005 * 'get_option_value()' - Return the value of an option.
4007 * This function also handles generation of custom option values.
4010 static char * /* O - Value string or NULL on error */
4012 ppd_file_t
*ppd
, /* I - PPD file */
4013 const char *name
, /* I - Option name */
4014 char *buffer
, /* I - String buffer */
4015 size_t bufsize
) /* I - Size of buffer */
4017 char *bufptr
, /* Pointer into buffer */
4018 *bufend
; /* End of buffer */
4019 ppd_coption_t
*coption
; /* Custom option */
4020 ppd_cparam_t
*cparam
; /* Current custom parameter */
4021 char keyword
[256]; /* Parameter name */
4022 const char *val
, /* Parameter value */
4023 *uval
; /* Units value */
4024 long integer
; /* Integer value */
4025 double number
, /* Number value */
4026 number_points
; /* Number in points */
4030 * See if we have a custom option choice...
4033 if ((val
= cgiGetVariable(name
)) == NULL
)
4041 else if (strcasecmp(val
, "Custom") ||
4042 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
4045 * Not a custom choice...
4048 strlcpy(buffer
, val
, bufsize
);
4053 * OK, we have a custom option choice, format it...
4058 if (!strcmp(coption
->keyword
, "PageSize"))
4060 const char *lval
; /* Length string value */
4061 double width
, /* Width value */
4062 width_points
, /* Width in points */
4063 length
, /* Length value */
4064 length_points
; /* Length in points */
4067 val
= cgiGetVariable("PageSize.Width");
4068 lval
= cgiGetVariable("PageSize.Height");
4069 uval
= cgiGetVariable("PageSize.Units");
4071 if (!val
|| !lval
|| !uval
||
4072 (width
= strtod(val
, NULL
)) == 0.0 ||
4073 (length
= strtod(lval
, NULL
)) == 0.0 ||
4074 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4075 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4078 width_points
= get_points(width
, uval
);
4079 length_points
= get_points(length
, uval
);
4081 if (width_points
< ppd
->custom_min
[0] ||
4082 width_points
> ppd
->custom_max
[0] ||
4083 length_points
< ppd
->custom_min
[1] ||
4084 length_points
> ppd
->custom_max
[1])
4087 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
4089 else if (cupsArrayCount(coption
->params
) == 1)
4091 cparam
= ppdFirstCustomParam(coption
);
4092 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
4094 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4097 switch (cparam
->type
)
4099 case PPD_CUSTOM_CURVE
:
4100 case PPD_CUSTOM_INVCURVE
:
4101 case PPD_CUSTOM_REAL
:
4102 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4103 number
< cparam
->minimum
.custom_real
||
4104 number
> cparam
->maximum
.custom_real
)
4107 snprintf(buffer
, bufsize
, "Custom.%g", number
);
4110 case PPD_CUSTOM_INT
:
4111 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4112 integer
== LONG_MAX
||
4113 integer
< cparam
->minimum
.custom_int
||
4114 integer
> cparam
->maximum
.custom_int
)
4117 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
4120 case PPD_CUSTOM_POINTS
:
4121 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4123 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4124 (uval
= cgiGetVariable(keyword
)) == NULL
||
4125 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4126 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4129 number_points
= get_points(number
, uval
);
4130 if (number_points
< cparam
->minimum
.custom_points
||
4131 number_points
> cparam
->maximum
.custom_points
)
4134 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
4137 case PPD_CUSTOM_PASSCODE
:
4138 for (uval
= val
; *uval
; uval
++)
4139 if (!isdigit(*uval
& 255))
4142 case PPD_CUSTOM_PASSWORD
:
4143 case PPD_CUSTOM_STRING
:
4144 integer
= (long)strlen(val
);
4145 if (integer
< cparam
->minimum
.custom_string
||
4146 integer
> cparam
->maximum
.custom_string
)
4149 snprintf(buffer
, bufsize
, "Custom.%s", val
);
4155 const char *prefix
= "{"; /* Prefix string */
4159 bufend
= buffer
+ bufsize
;
4161 for (cparam
= ppdFirstCustomParam(coption
);
4163 cparam
= ppdNextCustomParam(coption
))
4165 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
4168 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4171 snprintf(bufptr
, bufend
- bufptr
, "%s%s=", prefix
, cparam
->name
);
4172 bufptr
+= strlen(bufptr
);
4175 switch (cparam
->type
)
4177 case PPD_CUSTOM_CURVE
:
4178 case PPD_CUSTOM_INVCURVE
:
4179 case PPD_CUSTOM_REAL
:
4180 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4181 number
< cparam
->minimum
.custom_real
||
4182 number
> cparam
->maximum
.custom_real
)
4185 snprintf(bufptr
, bufend
- bufptr
, "%g", number
);
4188 case PPD_CUSTOM_INT
:
4189 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4190 integer
== LONG_MAX
||
4191 integer
< cparam
->minimum
.custom_int
||
4192 integer
> cparam
->maximum
.custom_int
)
4195 snprintf(bufptr
, bufend
- bufptr
, "%ld", integer
);
4198 case PPD_CUSTOM_POINTS
:
4199 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4201 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4202 (uval
= cgiGetVariable(keyword
)) == NULL
||
4203 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
4204 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
4205 strcmp(uval
, "mm") && strcmp(uval
, "m")))
4208 number_points
= get_points(number
, uval
);
4209 if (number_points
< cparam
->minimum
.custom_points
||
4210 number_points
> cparam
->maximum
.custom_points
)
4213 snprintf(bufptr
, bufend
- bufptr
, "%g%s", number
, uval
);
4216 case PPD_CUSTOM_PASSCODE
:
4217 for (uval
= val
; *uval
; uval
++)
4218 if (!isdigit(*uval
& 255))
4221 case PPD_CUSTOM_PASSWORD
:
4222 case PPD_CUSTOM_STRING
:
4223 integer
= (long)strlen(val
);
4224 if (integer
< cparam
->minimum
.custom_string
||
4225 integer
> cparam
->maximum
.custom_string
)
4228 if ((bufptr
+ 2) > bufend
)
4234 while (*val
&& bufptr
< bufend
)
4236 if (*val
== '\\' || *val
== '\"')
4238 if ((bufptr
+ 1) >= bufend
)
4247 if (bufptr
>= bufend
)
4256 bufptr
+= strlen(bufptr
);
4259 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
4262 strcpy(bufptr
, "}");
4270 * 'get_points()' - Get a value in points.
4273 static double /* O - Number in points */
4274 get_points(double number
, /* I - Original number */
4275 const char *uval
) /* I - Units */
4277 if (!strcmp(uval
, "mm")) /* Millimeters */
4278 return (number
* 72.0 / 25.4);
4279 else if (!strcmp(uval
, "cm")) /* Centimeters */
4280 return (number
* 72.0 / 2.54);
4281 else if (!strcmp(uval
, "in")) /* Inches */
4282 return (number
* 72.0);
4283 else if (!strcmp(uval
, "ft")) /* Feet */
4284 return (number
* 72.0 * 12.0);
4285 else if (!strcmp(uval
, "m")) /* Meters */
4286 return (number
* 72.0 / 0.0254);
4293 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".