2 * "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 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 * do_add_rss_subscription() - Add a RSS subscription.
19 * do_am_class() - Add or modify a class.
20 * do_am_printer() - Add or modify a printer.
21 * do_cancel_subscription() - Cancel a subscription.
22 * do_config_server() - Configure server settings.
23 * do_delete_class() - Delete a class.
24 * do_delete_printer() - Delete a printer.
25 * do_export() - Export printers to Samba.
26 * do_list_printers() - List available printers.
27 * do_menu() - Show the main menu.
28 * do_printer_op() - Do a printer operation.
29 * do_set_allowed_users() - Set the allowed/denied users for a queue.
30 * do_set_options() - Configure the default options for a queue.
31 * do_set_sharing() - Set printer-is-shared value.
32 * get_option_value() - Return the value of an option.
33 * get_points() - Get a value in points.
34 * match_string() - Return the number of matching characters.
38 * Include necessary headers...
41 #include "cgi-private.h"
42 #include <cups/adminutil.h>
43 #include <cups/file.h>
55 static void do_add_rss_subscription(http_t
*http
);
56 static void do_am_class(http_t
*http
, int modify
);
57 static void do_am_printer(http_t
*http
, int modify
);
58 static void do_cancel_subscription(http_t
*http
);
59 static void do_set_options(http_t
*http
, int is_class
);
60 static void do_config_server(http_t
*http
);
61 static void do_delete_class(http_t
*http
);
62 static void do_delete_printer(http_t
*http
);
63 static void do_export(http_t
*http
);
64 static void do_list_printers(http_t
*http
);
65 static void do_menu(http_t
*http
);
66 static void do_printer_op(http_t
*http
,
67 ipp_op_t op
, const char *title
);
68 static void do_set_allowed_users(http_t
*http
);
69 static void do_set_sharing(http_t
*http
);
70 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
71 char *buffer
, size_t bufsize
);
72 static double get_points(double number
, const char *uval
);
73 static int match_string(const char *a
, const char *b
);
77 * 'main()' - Main entry for CGI.
80 int /* O - Exit status */
81 main(int argc
, /* I - Number of command-line arguments */
82 char *argv
[]) /* I - Command-line arguments */
84 http_t
*http
; /* Connection to the server */
85 const char *op
; /* Operation name */
89 * Connect to the HTTP server...
92 fputs("DEBUG: admin.cgi started...\n", stderr
);
94 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
98 perror("ERROR: Unable to connect to cupsd");
99 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
100 cupsServer() ? cupsServer() : "(null)");
101 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
102 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
106 fprintf(stderr
, "DEBUG: http=%p\n", http
);
109 * Set the web interface section...
112 cgiSetVariable("SECTION", "admin");
115 * See if we have form data...
118 if (!cgiInitialize())
121 * Nope, send the administration menu...
124 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
128 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
131 * Do the operation...
134 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
136 if (!strcmp(op
, "start-printer"))
137 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
138 else if (!strcmp(op
, "stop-printer"))
139 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
140 else if (!strcmp(op
, "start-class"))
141 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
142 else if (!strcmp(op
, "stop-class"))
143 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
144 else if (!strcmp(op
, "accept-jobs"))
145 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
146 else if (!strcmp(op
, "reject-jobs"))
147 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
148 else if (!strcmp(op
, "purge-jobs"))
149 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
150 else if (!strcmp(op
, "set-allowed-users"))
151 do_set_allowed_users(http
);
152 else if (!strcmp(op
, "set-as-default"))
153 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
154 else if (!strcmp(op
, "set-sharing"))
155 do_set_sharing(http
);
156 else if (!strcmp(op
, "find-new-printers") ||
157 !strcmp(op
, "list-available-printers"))
158 do_list_printers(http
);
159 else if (!strcmp(op
, "add-class"))
160 do_am_class(http
, 0);
161 else if (!strcmp(op
, "add-printer"))
162 do_am_printer(http
, 0);
163 else if (!strcmp(op
, "modify-class"))
164 do_am_class(http
, 1);
165 else if (!strcmp(op
, "modify-printer"))
166 do_am_printer(http
, 1);
167 else if (!strcmp(op
, "delete-class"))
168 do_delete_class(http
);
169 else if (!strcmp(op
, "delete-printer"))
170 do_delete_printer(http
);
171 else if (!strcmp(op
, "set-class-options"))
172 do_set_options(http
, 1);
173 else if (!strcmp(op
, "set-printer-options"))
174 do_set_options(http
, 0);
175 else if (!strcmp(op
, "config-server"))
176 do_config_server(http
);
177 else if (!strcmp(op
, "export-samba"))
179 else if (!strcmp(op
, "add-rss-subscription"))
180 do_add_rss_subscription(http
);
181 else if (!strcmp(op
, "cancel-subscription"))
182 do_cancel_subscription(http
);
186 * Bad operation code - display an error...
189 cgiStartHTML(cgiText(_("Administration")));
190 cgiCopyTemplateLang("error-op.tmpl");
194 else if (op
&& !strcmp(op
, "redirect"))
196 const char *url
; /* Redirection URL... */
197 char prefix
[1024]; /* URL prefix */
201 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
202 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
204 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
205 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
207 if ((url
= cgiGetVariable("URL")) != NULL
)
208 printf("Location: %s%s\n\n", prefix
, url
);
210 printf("Location: %s/admin\n\n", prefix
);
215 * Form data but no operation code - display an error...
218 cgiStartHTML(cgiText(_("Administration")));
219 cgiCopyTemplateLang("error-op.tmpl");
224 * Close the HTTP server connection...
230 * Return with no errors...
238 * 'do_add_rss_subscription()' - Add a RSS subscription.
242 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
244 ipp_t
*request
, /* IPP request data */
245 *response
; /* IPP response data */
246 char rss_uri
[1024]; /* RSS notify-recipient URI */
247 int num_events
; /* Number of events */
248 const char *events
[12], /* Subscribed events */
249 *subscription_name
, /* Subscription name */
250 *printer_uri
, /* Printer URI */
251 *ptr
, /* Pointer into name */
252 *user
; /* Username */
253 int max_events
; /* Maximum number of events */
257 * See if we have all of the required information...
260 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
261 printer_uri
= cgiGetVariable("PRINTER_URI");
264 if (cgiGetVariable("EVENT_JOB_CREATED"))
265 events
[num_events
++] = "job-created";
266 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
267 events
[num_events
++] = "job-completed";
268 if (cgiGetVariable("EVENT_JOB_STOPPED"))
269 events
[num_events
++] = "job-stopped";
270 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
271 events
[num_events
++] = "job-config-changed";
272 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
273 events
[num_events
++] = "printer-stopped";
274 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
275 events
[num_events
++] = "printer-added";
276 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
277 events
[num_events
++] = "printer-modified";
278 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
279 events
[num_events
++] = "printer-deleted";
280 if (cgiGetVariable("EVENT_SERVER_STARTED"))
281 events
[num_events
++] = "server-started";
282 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
283 events
[num_events
++] = "server-stopped";
284 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
285 events
[num_events
++] = "server-restarted";
286 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
287 events
[num_events
++] = "server-audit";
289 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
290 max_events
= atoi(ptr
);
294 if (!subscription_name
|| !printer_uri
|| !num_events
||
295 max_events
<= 0 || max_events
> 9999)
298 * Don't have everything we need, so get the available printers
299 * and classes and (re)show the add page...
302 request
= ippNewRequest(CUPS_GET_PRINTERS
);
303 response
= cupsDoRequest(http
, request
, "/");
305 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
309 cgiStartHTML(cgiText(_("Add RSS Subscription")));
311 cgiCopyTemplateLang("add-rss-subscription.tmpl");
318 * Make sure we have a username...
321 if ((user
= getenv("REMOTE_USER")) == NULL
)
323 puts("Status: 401\n");
328 * Validate the subscription name...
331 for (ptr
= subscription_name
; *ptr
; ptr
++)
332 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
333 *ptr
== '?' || *ptr
== '#')
338 cgiSetVariable("ERROR",
339 cgiText(_("The subscription name may not "
340 "contain spaces, slashes (/), question marks (?), "
341 "or the pound sign (#).")));
342 cgiStartHTML(_("Add RSS Subscription"));
343 cgiCopyTemplateLang("error.tmpl");
349 * Add the subscription...
352 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
353 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
354 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
355 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
358 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
359 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
362 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
364 if (!strcasecmp(printer_uri
, "#ALL#"))
365 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
366 NULL
, "ipp://localhost/");
368 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
371 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
374 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
375 "notify-recipient-uri", NULL
, rss_uri
);
376 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
377 num_events
, NULL
, events
);
378 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
379 "notify-lease-duration", 0);
381 ippDelete(cupsDoRequest(http
, request
, "/"));
383 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
385 puts("Status: 401\n");
388 else if (cupsLastError() > IPP_OK_CONFLICT
)
390 cgiStartHTML(_("Add RSS Subscription"));
391 cgiShowIPPError(_("Unable to add RSS subscription:"));
396 * Redirect successful updates back to the admin page...
399 cgiSetVariable("refresh_page", "5;URL=/admin");
400 cgiStartHTML(_("Add RSS Subscription"));
401 cgiCopyTemplateLang("subscription-added.tmpl");
409 * 'do_am_class()' - Add or modify a class.
413 do_am_class(http_t
*http
, /* I - HTTP connection */
414 int modify
) /* I - Modify the printer? */
416 int i
, j
; /* Looping vars */
417 int element
; /* Element number */
418 int num_printers
; /* Number of printers */
419 ipp_t
*request
, /* IPP request */
420 *response
; /* IPP response */
421 ipp_attribute_t
*attr
; /* member-uris attribute */
422 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
423 const char *name
, /* Pointer to class name */
424 *ptr
; /* Pointer to CGI variable */
425 const char *title
; /* Title of page */
426 static const char * const pattrs
[] = /* Requested printer attributes */
434 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
435 name
= cgiGetVariable("PRINTER_NAME");
437 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
440 * Build a CUPS_GET_PRINTERS request, which requires the
441 * following attributes:
444 * attributes-natural-language
447 request
= ippNewRequest(CUPS_GET_PRINTERS
);
450 * Do the request and get back a response...
453 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
456 * Create MEMBER_URIS and MEMBER_NAMES arrays...
459 for (element
= 0, attr
= response
->attrs
;
462 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
464 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
465 (!name
|| strcasecmp(name
, ptr
+ 1)))
468 * Don't show the current class...
471 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
476 for (element
= 0, attr
= response
->attrs
;
479 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
481 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
484 * Don't show the current class...
487 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
492 num_printers
= cgiGetSize("MEMBER_URIS");
502 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
503 * following attributes:
506 * attributes-natural-language
510 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
512 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
513 "localhost", 0, "/classes/%s", name
);
514 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
517 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
518 "requested-attributes",
519 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
523 * Do the request and get back a response...
526 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
528 if ((attr
= ippFindAttribute(response
, "member-names",
529 IPP_TAG_NAME
)) != NULL
)
532 * Mark any current members in the class...
535 for (j
= 0; j
< num_printers
; j
++)
536 cgiSetArray("MEMBER_SELECTED", j
, "");
538 for (i
= 0; i
< attr
->num_values
; i
++)
540 for (j
= 0; j
< num_printers
; j
++)
542 if (!strcasecmp(attr
->values
[i
].string
.text
,
543 cgiGetArray("MEMBER_NAMES", j
)))
545 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
552 if ((attr
= ippFindAttribute(response
, "printer-info",
553 IPP_TAG_TEXT
)) != NULL
)
554 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
556 if ((attr
= ippFindAttribute(response
, "printer-location",
557 IPP_TAG_TEXT
)) != NULL
)
558 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
564 * Update the location and description of an existing printer...
568 cgiCopyTemplateLang("modify-class.tmpl");
573 * Get the name, location, and description for a new printer...
577 cgiCopyTemplateLang("add-class.tmpl");
585 for (ptr
= name
; *ptr
; ptr
++)
586 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
589 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
591 cgiSetVariable("ERROR",
592 cgiText(_("The class name may only contain up to "
593 "127 printable characters and may not "
594 "contain spaces, slashes (/), or the "
595 "pound sign (#).")));
597 cgiCopyTemplateLang("error.tmpl");
603 * Build a CUPS_ADD_CLASS request, which requires the following
607 * attributes-natural-language
611 * printer-is-accepting-jobs
616 request
= ippNewRequest(CUPS_ADD_CLASS
);
618 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
619 "localhost", 0, "/classes/%s",
620 cgiGetVariable("PRINTER_NAME"));
621 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
624 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
625 NULL
, cgiGetVariable("PRINTER_LOCATION"));
627 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
628 NULL
, cgiGetVariable("PRINTER_INFO"));
630 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
632 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
635 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
637 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
638 num_printers
, NULL
, NULL
);
639 for (i
= 0; i
< num_printers
; i
++)
640 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
644 * Do the request and get back a response...
647 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
649 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
651 puts("Status: 401\n");
654 else if (cupsLastError() > IPP_OK_CONFLICT
)
657 cgiShowIPPError(modify
? _("Unable to modify class:") :
658 _("Unable to add class:"));
663 * Redirect successful updates back to the class page...
666 char refresh
[1024]; /* Refresh URL */
668 cgiFormEncode(uri
, name
, sizeof(uri
));
669 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
671 cgiSetVariable("refresh_page", refresh
);
676 cgiCopyTemplateLang("class-modified.tmpl");
678 cgiCopyTemplateLang("class-added.tmpl");
686 * 'do_am_printer()' - Add or modify a printer.
690 do_am_printer(http_t
*http
, /* I - HTTP connection */
691 int modify
) /* I - Modify the printer? */
693 int i
; /* Looping var */
694 ipp_attribute_t
*attr
; /* Current attribute */
695 ipp_t
*request
, /* IPP request */
696 *response
, /* IPP response */
697 *oldinfo
; /* Old printer information */
698 const cgi_file_t
*file
; /* Uploaded file, if any */
699 const char *var
; /* CGI variable */
700 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
701 *uriptr
; /* Pointer into URI */
702 int maxrate
; /* Maximum baud rate */
703 char baudrate
[255]; /* Baud rate string */
704 const char *name
, /* Pointer to class name */
705 *ptr
; /* Pointer to CGI variable */
706 const char *title
; /* Title of page */
707 static int baudrates
[] = /* Baud rates */
722 ptr
= cgiGetVariable("DEVICE_URI");
723 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
724 ptr
? ptr
: "(null)");
726 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
731 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
732 * following attributes:
735 * attributes-natural-language
739 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
741 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
742 "localhost", 0, "/printers/%s",
743 cgiGetVariable("PRINTER_NAME"));
744 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
748 * Do the request and get back a response...
751 oldinfo
= cupsDoRequest(http
, request
, "/");
760 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
761 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
762 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
763 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
766 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
768 for (ptr
= name
; *ptr
; ptr
++)
769 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
772 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
774 cgiSetVariable("ERROR",
775 cgiText(_("The printer name may only contain up to "
776 "127 printable characters and may not "
777 "contain spaces, slashes (/), or the "
778 "pound sign (#).")));
780 cgiCopyTemplateLang("error.tmpl");
786 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
788 if ((uriptr
= strrchr(var
, '|')) != NULL
)
791 * Extract make and make/model from device URI string...
794 char make
[1024], /* Make string */
795 *makeptr
; /* Pointer into make */
800 strlcpy(make
, uriptr
, sizeof(make
));
802 if ((makeptr
= strchr(make
, ' ')) != NULL
)
804 else if ((makeptr
= strchr(make
, '-')) != NULL
)
806 else if (!strncasecmp(make
, "laserjet", 8) ||
807 !strncasecmp(make
, "deskjet", 7) ||
808 !strncasecmp(make
, "designjet", 9))
810 else if (!strncasecmp(make
, "phaser", 6))
811 strcpy(make
, "Xerox");
812 else if (!strncasecmp(make
, "stylus", 6))
813 strcpy(make
, "Epson");
815 strcpy(make
, "Generic");
817 if (!cgiGetVariable("CURRENT_MAKE"))
818 cgiSetVariable("CURRENT_MAKE", make
);
820 cgiSetVariable("PPD_MAKE", make
);
822 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
823 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
827 char template[128], /* Template name */
828 *tptr
; /* Pointer into template name */
830 cgiSetVariable("PRINTER_INFO", uriptr
);
832 for (tptr
= template;
833 tptr
< (template + sizeof(template) - 1) && *uriptr
;
835 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
838 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
[-1] != '_')
840 else if (*uriptr
== '?' || *uriptr
== '(')
845 cgiSetVariable("TEMPLATE_NAME", template);
853 * Build a CUPS_GET_DEVICES request, which requires the following
857 * attributes-natural-language
861 fputs("DEBUG: Getting list of devices...\n", stderr
);
863 request
= ippNewRequest(CUPS_GET_DEVICES
);
865 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
866 NULL
, "ipp://localhost/printers/");
869 * Do the request and get back a response...
872 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
874 fputs("DEBUG: Got device list!\n", stderr
);
876 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
881 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
882 cupsLastError(), cupsLastErrorString());
885 * Let the user choose...
888 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
890 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
891 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
894 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
895 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
899 cgiCopyTemplateLang("choose-device.tmpl");
902 else if (strchr(var
, '/') == NULL
)
904 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
907 * Set the current device URI for the form to the old one...
910 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
911 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
915 * User needs to set the full URI...
919 cgiCopyTemplateLang("choose-uri.tmpl");
922 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
925 * Need baud rate, parity, etc.
928 if ((var
= strchr(var
, '?')) != NULL
&&
929 strncmp(var
, "?baud=", 6) == 0)
930 maxrate
= atoi(var
+ 6);
934 for (i
= 0; i
< 10; i
++)
935 if (baudrates
[i
] > maxrate
)
939 sprintf(baudrate
, "%d", baudrates
[i
]);
940 cgiSetArray("BAUDRATES", i
, baudrate
);
944 cgiCopyTemplateLang("choose-serial.tmpl");
947 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
954 * Update the location and description of an existing printer...
958 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
960 cgiCopyTemplateLang("modify-printer.tmpl");
965 * Get the name, location, and description for a new printer...
969 if (!strncmp(var
, "usb:", 4))
970 cgiSetVariable("printer_is_shared", "1");
972 #endif /* __APPLE__ */
973 cgiSetVariable("printer_is_shared", "0");
975 cgiCopyTemplateLang("add-printer.tmpl");
985 else if (!file
&& !cgiGetVariable("PPD_NAME"))
990 * Get the PPD file...
993 int fd
; /* PPD file */
994 char filename
[1024]; /* PPD filename */
995 ppd_file_t
*ppd
; /* PPD information */
996 char buffer
[1024]; /* Buffer */
997 int bytes
; /* Number of bytes */
998 http_status_t get_status
; /* Status of GET */
1001 /* TODO: Use cupsGetFile() API... */
1002 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1004 if (httpGet(http
, uri
))
1007 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1009 if (get_status
!= HTTP_OK
)
1011 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1012 uri
, get_status
, httpStatus(get_status
));
1014 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1016 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1017 write(fd
, buffer
, bytes
);
1021 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1023 if (ppd
->manufacturer
)
1024 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1027 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1034 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1035 filename
, ppdErrorString(ppdLastError(&bytes
)));
1043 "ERROR: Unable to create temporary file for PPD file: %s\n",
1049 * Build a CUPS_GET_PPDS request, which requires the following
1052 * attributes-charset
1053 * attributes-natural-language
1057 request
= ippNewRequest(CUPS_GET_PPDS
);
1059 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1060 NULL
, "ipp://localhost/printers/");
1062 if ((var
= cgiGetVariable("CURRENT_MAKE")) == NULL
)
1063 var
= cgiGetVariable("PPD_MAKE");
1065 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1066 "ppd-make", NULL
, var
);
1068 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1069 "requested-attributes", NULL
, "ppd-make");
1072 * Do the request and get back a response...
1075 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1078 * Got the list of PPDs, see if the user has selected a make...
1081 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
1084 * No PPD files with this make, try again with all makes...
1087 ippDelete(response
);
1089 request
= ippNewRequest(CUPS_GET_PPDS
);
1091 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1092 NULL
, "ipp://localhost/printers/");
1094 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1095 "requested-attributes", NULL
, "ppd-make");
1097 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1098 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1100 cgiStartHTML(title
);
1101 cgiCopyTemplateLang("choose-make.tmpl");
1104 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1106 cgiStartHTML(title
);
1107 cgiCopyTemplateLang("choose-make.tmpl");
1113 * Let the user choose a model...
1116 const char *make_model
; /* Current make/model string */
1119 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1122 * Scan for "close" matches...
1125 int match
, /* Current match */
1126 best_match
, /* Best match so far */
1127 count
; /* Number of drivers */
1128 const char *best
, /* Best matching string */
1129 *current
; /* Current string */
1132 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
1134 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
1136 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
1137 match
= match_string(make_model
, current
);
1139 if (match
> best_match
)
1146 if (best_match
> strlen(var
))
1149 * Found a match longer than the make...
1152 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
1156 cgiStartHTML(title
);
1157 cgiCopyTemplateLang("choose-model.tmpl");
1161 ippDelete(response
);
1165 cgiStartHTML(title
);
1166 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1167 cgiCopyTemplateLang("error.tmpl");
1174 * Build a CUPS_ADD_PRINTER request, which requires the following
1177 * attributes-charset
1178 * attributes-natural-language
1184 * printer-is-accepting-jobs
1189 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1191 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1192 "localhost", 0, "/printers/%s",
1193 cgiGetVariable("PRINTER_NAME"));
1194 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1197 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1198 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1200 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1201 NULL
, cgiGetVariable("PRINTER_INFO"));
1204 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1205 NULL
, cgiGetVariable("PPD_NAME"));
1207 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1210 * Strip make and model from URI...
1213 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1216 if (!strncmp(uri
, "serial:", 7))
1219 * Update serial port URI to include baud rate, etc.
1222 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1223 uriptr
= uri
+ strlen(uri
);
1225 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1226 "?baud=%s+bits=%s+parity=%s+flow=%s",
1227 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1228 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1231 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1234 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1236 var
= cgiGetVariable("printer_is_shared");
1237 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1238 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1240 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1244 * Do the request and get back a response...
1248 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1250 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1252 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1254 puts("Status: 401\n");
1257 else if (cupsLastError() > IPP_OK_CONFLICT
)
1259 cgiStartHTML(title
);
1260 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1261 _("Unable to add printer:"));
1266 * Redirect successful updates back to the printer page...
1269 char refresh
[1024]; /* Refresh URL */
1272 cgiFormEncode(uri
, name
, sizeof(uri
));
1274 snprintf(refresh
, sizeof(refresh
),
1275 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1277 cgiSetVariable("refresh_page", refresh
);
1279 cgiStartHTML(title
);
1281 cgiCopyTemplateLang("printer-modified.tmpl");
1286 * Set the printer options...
1289 cgiSetVariable("OP", "set-printer-options");
1290 do_set_options(http
, 0);
1303 * 'do_cancel_subscription()' - Cancel a subscription.
1307 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1309 ipp_t
*request
; /* IPP request data */
1310 const char *var
, /* Form variable */
1311 *user
; /* Username */
1312 int id
; /* Subscription ID */
1316 * See if we have all of the required information...
1319 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1326 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1327 cgiStartHTML(_("Cancel RSS Subscription"));
1328 cgiCopyTemplateLang("error.tmpl");
1334 * Require a username...
1337 if ((user
= getenv("REMOTE_USER")) == NULL
)
1339 puts("Status: 401\n");
1344 * Cancel the subscription...
1347 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1349 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1350 NULL
, "ipp://localhost/");
1351 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1352 "notify-subscription-id", id
);
1354 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1357 ippDelete(cupsDoRequest(http
, request
, "/"));
1359 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1361 puts("Status: 401\n");
1364 else if (cupsLastError() > IPP_OK_CONFLICT
)
1366 cgiStartHTML(_("Cancel RSS Subscription"));
1367 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1372 * Redirect successful updates back to the admin page...
1375 cgiSetVariable("refresh_page", "5;URL=/admin");
1376 cgiStartHTML(_("Cancel RSS Subscription"));
1377 cgiCopyTemplateLang("subscription-canceled.tmpl");
1385 * 'do_config_server()' - Configure server settings.
1389 do_config_server(http_t
*http
) /* I - HTTP connection */
1391 if (cgiGetVariable("CHANGESETTINGS"))
1394 * Save basic setting changes...
1397 int num_settings
; /* Number of server settings */
1398 cups_option_t
*settings
; /* Server settings */
1399 const char *debug_logging
, /* DEBUG_LOGGING value */
1400 *remote_admin
, /* REMOTE_ADMIN value */
1401 *remote_any
, /* REMOTE_ANY value */
1403 /* REMOTE_PRINTERS value */
1404 *share_printers
,/* SHARE_PRINTERS value */
1406 /* USER_CANCEL_ANY value */
1408 char default_auth_type
[255];
1409 /* DefaultAuthType value */
1410 #endif /* HAVE_GSSAPI */
1414 * Get the checkbox values from the form...
1417 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1418 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1419 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1420 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1421 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1422 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1425 * Get the current server settings...
1428 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1430 cgiStartHTML(cgiText(_("Change Settings")));
1431 cgiSetVariable("MESSAGE",
1432 cgiText(_("Unable to change server settings:")));
1433 cgiSetVariable("ERROR", cupsLastErrorString());
1434 cgiCopyTemplateLang("error.tmpl");
1441 * Get authentication settings...
1444 if (cgiGetVariable("KERBEROS"))
1445 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1448 const char *val
= cupsGetOption("DefaultAuthType", num_settings
,
1451 if (val
&& !strcasecmp(val
, "Negotiate"))
1452 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1454 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1457 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1458 #endif /* HAVE_GSSAPI */
1461 * See if the settings have changed...
1464 if (strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1465 num_settings
, settings
)) ||
1466 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1467 num_settings
, settings
)) ||
1468 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1469 num_settings
, settings
)) ||
1470 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1471 num_settings
, settings
)) ||
1472 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1473 num_settings
, settings
)) ||
1475 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1476 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1477 num_settings
, settings
)) ||
1478 #endif /* HAVE_GSSAPI */
1479 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1480 num_settings
, settings
)))
1483 * Settings *have* changed, so save the changes...
1486 cupsFreeOptions(num_settings
, settings
);
1489 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1490 debug_logging
, num_settings
, &settings
);
1491 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1492 remote_admin
, num_settings
, &settings
);
1493 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1494 remote_any
, num_settings
, &settings
);
1495 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1496 remote_printers
, num_settings
, &settings
);
1497 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1498 share_printers
, num_settings
, &settings
);
1499 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1500 user_cancel_any
, num_settings
, &settings
);
1502 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1503 num_settings
, &settings
);
1504 #endif /* HAVE_GSSAPI */
1506 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1508 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1510 puts("Status: 401\n");
1514 cgiStartHTML(cgiText(_("Change Settings")));
1515 cgiSetVariable("MESSAGE",
1516 cgiText(_("Unable to change server settings:")));
1517 cgiSetVariable("ERROR", cupsLastErrorString());
1518 cgiCopyTemplateLang("error.tmpl");
1522 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1523 cgiStartHTML(cgiText(_("Change Settings")));
1524 cgiCopyTemplateLang("restart.tmpl");
1533 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1534 cgiStartHTML(cgiText(_("Change Settings")));
1535 cgiCopyTemplateLang("norestart.tmpl");
1538 cupsFreeOptions(num_settings
, settings
);
1542 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1545 * Save hand-edited config file...
1548 http_status_t status
; /* PUT status */
1549 char tempfile
[1024]; /* Temporary new cupsd.conf */
1550 int tempfd
; /* Temporary file descriptor */
1551 cups_file_t
*temp
; /* Temporary file */
1552 const char *start
, /* Start of line */
1553 *end
; /* End of line */
1557 * Create a temporary file for the new cupsd.conf file...
1560 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1562 cgiStartHTML(cgiText(_("Edit Configuration File")));
1563 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1564 cgiSetVariable("ERROR", strerror(errno
));
1565 cgiCopyTemplateLang("error.tmpl");
1572 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1574 cgiStartHTML(cgiText(_("Edit Configuration File")));
1575 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1576 cgiSetVariable("ERROR", strerror(errno
));
1577 cgiCopyTemplateLang("error.tmpl");
1587 * Copy the cupsd.conf text from the form variable...
1590 start
= cgiGetVariable("CUPSDCONF");
1593 if ((end
= strstr(start
, "\r\n")) == NULL
)
1594 if ((end
= strstr(start
, "\n")) == NULL
)
1595 end
= start
+ strlen(start
);
1597 cupsFileWrite(temp
, start
, end
- start
);
1598 cupsFilePutChar(temp
, '\n');
1602 else if (*end
== '\n')
1608 cupsFileClose(temp
);
1611 * Upload the configuration file to the server...
1614 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1616 if (status
== HTTP_UNAUTHORIZED
)
1618 puts("Status: 401\n");
1622 else if (status
!= HTTP_CREATED
)
1624 cgiSetVariable("MESSAGE",
1625 cgiText(_("Unable to upload cupsd.conf file:")));
1626 cgiSetVariable("ERROR", httpStatus(status
));
1628 cgiStartHTML(cgiText(_("Edit Configuration File")));
1629 cgiCopyTemplateLang("error.tmpl");
1633 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1635 cgiStartHTML(cgiText(_("Edit Configuration File")));
1636 cgiCopyTemplateLang("restart.tmpl");
1645 struct stat info
; /* cupsd.conf information */
1646 cups_file_t
*cupsd
; /* cupsd.conf file */
1647 char *buffer
, /* Buffer for entire file */
1648 *bufptr
, /* Pointer into buffer */
1649 *bufend
; /* End of buffer */
1650 int ch
; /* Character from file */
1651 char filename
[1024]; /* Filename */
1652 const char *server_root
; /* Location of config files */
1656 * Locate the cupsd.conf file...
1659 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1660 server_root
= CUPS_SERVERROOT
;
1662 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1665 * Figure out the size...
1668 if (stat(filename
, &info
))
1670 cgiStartHTML(cgiText(_("Edit Configuration File")));
1671 cgiSetVariable("MESSAGE",
1672 cgiText(_("Unable to access cupsd.conf file:")));
1673 cgiSetVariable("ERROR", strerror(errno
));
1674 cgiCopyTemplateLang("error.tmpl");
1681 if (info
.st_size
> (1024 * 1024))
1683 cgiStartHTML(cgiText(_("Edit Configuration File")));
1684 cgiSetVariable("MESSAGE",
1685 cgiText(_("Unable to access cupsd.conf file:")));
1686 cgiSetVariable("ERROR",
1687 cgiText(_("Unable to edit cupsd.conf files larger than "
1689 cgiCopyTemplateLang("error.tmpl");
1692 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1693 (long)info
.st_size
);
1698 * Open the cupsd.conf file...
1701 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1704 * Unable to open - log an error...
1707 cgiStartHTML(cgiText(_("Edit Configuration File")));
1708 cgiSetVariable("MESSAGE",
1709 cgiText(_("Unable to access cupsd.conf file:")));
1710 cgiSetVariable("ERROR", strerror(errno
));
1711 cgiCopyTemplateLang("error.tmpl");
1719 * Allocate memory and load the file into a string buffer...
1722 if ((buffer
= calloc(1, info
.st_size
+ 1)) != NULL
)
1724 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1725 cgiSetVariable("CUPSDCONF", buffer
);
1729 cupsFileClose(cupsd
);
1732 * Then get the default cupsd.conf file and put that into a string as
1736 strlcat(filename
, ".default", sizeof(filename
));
1738 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1739 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1741 if ((buffer
= calloc(1, 2 * info
.st_size
+ 1)) != NULL
)
1743 bufend
= buffer
+ 2 * info
.st_size
- 1;
1745 for (bufptr
= buffer
;
1746 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1748 if (ch
== '\\' || ch
== '\"')
1753 else if (ch
== '\n')
1758 else if (ch
== '\t')
1769 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1773 cupsFileClose(cupsd
);
1777 * Show the current config file...
1780 cgiStartHTML(cgiText(_("Edit Configuration File")));
1782 cgiCopyTemplateLang("edit-config.tmpl");
1790 * 'do_delete_class()' - Delete a class.
1794 do_delete_class(http_t
*http
) /* I - HTTP connection */
1796 ipp_t
*request
; /* IPP request */
1797 char uri
[HTTP_MAX_URI
]; /* Job URI */
1798 const char *pclass
; /* Printer class name */
1802 * Get form variables...
1805 if (cgiGetVariable("CONFIRM") == NULL
)
1807 cgiStartHTML(cgiText(_("Delete Class")));
1808 cgiCopyTemplateLang("class-confirm.tmpl");
1813 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1814 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1815 "localhost", 0, "/classes/%s", pclass
);
1818 cgiStartHTML(cgiText(_("Delete Class")));
1819 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1820 cgiCopyTemplateLang("error.tmpl");
1826 * Build a CUPS_DELETE_CLASS request, which requires the following
1829 * attributes-charset
1830 * attributes-natural-language
1834 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1836 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1840 * Do the request and get back a response...
1843 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1846 * Show the results...
1849 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1851 puts("Status: 401\n");
1854 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1857 * Redirect successful updates back to the classes page...
1860 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1863 cgiStartHTML(cgiText(_("Delete Class")));
1865 if (cupsLastError() > IPP_OK_CONFLICT
)
1866 cgiShowIPPError(_("Unable to delete class:"));
1868 cgiCopyTemplateLang("class-deleted.tmpl");
1875 * 'do_delete_printer()' - Delete a printer.
1879 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1881 ipp_t
*request
; /* IPP request */
1882 char uri
[HTTP_MAX_URI
]; /* Job URI */
1883 const char *printer
; /* Printer printer name */
1887 * Get form variables...
1890 if (cgiGetVariable("CONFIRM") == NULL
)
1892 cgiStartHTML(cgiText(_("Delete Printer")));
1893 cgiCopyTemplateLang("printer-confirm.tmpl");
1898 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1899 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1900 "localhost", 0, "/printers/%s", printer
);
1903 cgiStartHTML(cgiText(_("Delete Printer")));
1904 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1905 cgiCopyTemplateLang("error.tmpl");
1911 * Build a CUPS_DELETE_PRINTER request, which requires the following
1914 * attributes-charset
1915 * attributes-natural-language
1919 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1921 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1925 * Do the request and get back a response...
1928 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1931 * Show the results...
1934 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1936 puts("Status: 401\n");
1939 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1942 * Redirect successful updates back to the printers page...
1945 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1948 cgiStartHTML(cgiText(_("Delete Printer")));
1950 if (cupsLastError() > IPP_OK_CONFLICT
)
1951 cgiShowIPPError(_("Unable to delete printer:"));
1953 cgiCopyTemplateLang("printer-deleted.tmpl");
1960 * 'do_export()' - Export printers to Samba.
1964 do_export(http_t
*http
) /* I - HTTP connection */
1966 int i
, j
; /* Looping vars */
1967 ipp_t
*request
, /* IPP request */
1968 *response
; /* IPP response */
1969 const char *username
, /* Samba username */
1970 *password
, /* Samba password */
1971 *export_all
; /* Export all printers? */
1972 int export_count
, /* Number of printers to export */
1973 printer_count
; /* Number of available printers */
1974 const char *name
, /* What name to pull */
1975 *dest
; /* Current destination */
1976 char ppd
[1024]; /* PPD file */
1983 username
= cgiGetVariable("USERNAME");
1984 password
= cgiGetVariable("PASSWORD");
1985 export_all
= cgiGetVariable("EXPORT_ALL");
1986 export_count
= cgiGetSize("EXPORT_NAME");
1989 * Get list of available printers...
1992 cgiSetSize("PRINTER_NAME", 0);
1993 cgiSetSize("PRINTER_EXPORT", 0);
1995 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1997 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2000 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2001 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2002 CUPS_PRINTER_IMPLICIT
);
2004 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2005 "requested-attributes", NULL
, "printer-name");
2007 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2009 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2010 ippDelete(response
);
2014 printer_count
= cgiGetSize("PRINTER_NAME");
2016 for (i
= 0; i
< printer_count
; i
++)
2018 dest
= cgiGetArray("PRINTER_NAME", i
);
2020 for (j
= 0; j
< export_count
; j
++)
2021 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2024 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2030 * Export or get the printers to export...
2033 if (username
&& *username
&& password
&& *password
&&
2034 (export_all
|| export_count
> 0))
2040 fputs("DEBUG: Export printers...\n", stderr
);
2044 name
= "PRINTER_NAME";
2045 export_count
= cgiGetSize("PRINTER_NAME");
2048 name
= "EXPORT_NAME";
2050 for (i
= 0; i
< export_count
; i
++)
2052 dest
= cgiGetArray(name
, i
);
2054 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2057 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2066 if (i
< export_count
)
2067 cgiSetVariable("ERROR", cupsLastErrorString());
2070 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2071 cgiCopyTemplateLang("samba-exported.tmpl");
2076 else if (username
&& !*username
)
2077 cgiSetVariable("ERROR",
2078 cgiText(_("A Samba username is required to export "
2079 "printer drivers!")));
2080 else if (username
&& (!password
|| !*password
))
2081 cgiSetVariable("ERROR",
2082 cgiText(_("A Samba password is required to export "
2083 "printer drivers!")));
2089 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2090 cgiCopyTemplateLang("samba-export.tmpl");
2096 * 'do_list_printers()' - List available printers.
2100 do_list_printers(http_t
*http
) /* I - HTTP connection */
2102 ipp_t
*request
, /* IPP request */
2103 *response
; /* IPP response */
2104 ipp_attribute_t
*attr
; /* IPP attribute */
2107 cgiStartHTML(cgiText(_("List Available Printers")));
2111 * Get the list of printers and their devices...
2114 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2116 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2117 "requested-attributes", NULL
, "device-uri");
2119 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2120 CUPS_PRINTER_LOCAL
);
2121 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2122 CUPS_PRINTER_LOCAL
);
2124 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2127 * Got the printer list, now load the devices...
2130 int i
; /* Looping var */
2131 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2132 char *printer_device
; /* Current printer device */
2136 * Allocate an array and copy the device strings...
2139 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2141 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2143 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2145 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2149 * Free the printer list and get the device list...
2152 ippDelete(response
);
2154 request
= ippNewRequest(CUPS_GET_DEVICES
);
2156 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2159 * Got the device list, let's parse it...
2162 const char *device_uri
, /* device-uri attribute value */
2163 *device_make_and_model
, /* device-make-and-model value */
2164 *device_info
; /* device-info value */
2167 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2170 * Skip leading attributes until we hit a device...
2173 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2180 * Pull the needed attributes from this device...
2184 device_make_and_model
= NULL
;
2187 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2189 if (!strcmp(attr
->name
, "device-info") &&
2190 attr
->value_tag
== IPP_TAG_TEXT
)
2191 device_info
= attr
->values
[0].string
.text
;
2193 if (!strcmp(attr
->name
, "device-make-and-model") &&
2194 attr
->value_tag
== IPP_TAG_TEXT
)
2195 device_make_and_model
= attr
->values
[0].string
.text
;
2197 if (!strcmp(attr
->name
, "device-uri") &&
2198 attr
->value_tag
== IPP_TAG_URI
)
2199 device_uri
= attr
->values
[0].string
.text
;
2205 * See if we have everything needed...
2208 if (device_info
&& device_make_and_model
&& device_uri
&&
2209 strcasecmp(device_make_and_model
, "unknown") &&
2210 strchr(device_uri
, ':'))
2213 * Yes, now see if there is already a printer for this
2217 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2220 * Not found, so it must be a new printer...
2223 char option
[1024], /* Form variables for this device */
2224 *option_ptr
; /* Pointer into string */
2225 const char *ptr
; /* Pointer into device string */
2229 * Format the printer name variable for this device...
2231 * We use the device-info string first, then device-uri,
2232 * and finally device-make-and-model to come up with a
2236 if (strncasecmp(device_info
, "unknown", 7))
2238 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2241 ptr
= device_make_and_model
;
2243 for (option_ptr
= option
;
2244 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2246 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2248 *option_ptr
++ = *ptr
;
2249 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
[-1] != '_')
2250 *option_ptr
++ = '_';
2251 else if (*ptr
== '?' || *ptr
== '(')
2256 cgiSetArray("TEMPLATE_NAME", i
, option
);
2259 * Finally, set the form variables for this printer...
2262 cgiSetArray("device_info", i
, device_info
);
2263 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2264 cgiSetArray("device_uri", i
, device_uri
);
2273 ippDelete(response
);
2276 * Free the device list...
2279 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2281 printer_device
= (char *)cupsArrayNext(printer_devices
))
2282 free(printer_device
);
2284 cupsArrayDelete(printer_devices
);
2289 * Finally, show the printer list...
2292 cgiCopyTemplateLang("list-available-printers.tmpl");
2299 * 'do_menu()' - Show the main menu.
2303 do_menu(http_t
*http
) /* I - HTTP connection */
2305 int num_settings
; /* Number of server settings */
2306 cups_option_t
*settings
; /* Server settings */
2307 const char *val
; /* Setting value */
2308 char filename
[1024]; /* Temporary filename */
2309 const char *datadir
; /* Location of data files */
2310 ipp_t
*request
, /* IPP request */
2311 *response
; /* IPP response */
2315 * Get the current server settings...
2318 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2320 cgiSetVariable("SETTINGS_MESSAGE",
2321 cgiText(_("Unable to open cupsd.conf file:")));
2322 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2325 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2326 settings
)) != NULL
&& atoi(val
))
2327 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2329 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2330 settings
)) != NULL
&& atoi(val
))
2331 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2333 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2334 settings
)) != NULL
&& atoi(val
))
2335 cgiSetVariable("REMOTE_ANY", "CHECKED");
2337 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2338 settings
)) != NULL
&& atoi(val
))
2339 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2341 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2342 settings
)) != NULL
&& atoi(val
))
2343 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2345 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2346 settings
)) != NULL
&& atoi(val
))
2347 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2350 cgiSetVariable("HAVE_GSSAPI", "1");
2352 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2353 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2354 cgiSetVariable("KERBEROS", "CHECKED");
2355 #endif /* HAVE_GSSAPI */
2357 cupsFreeOptions(num_settings
, settings
);
2360 * See if Samba and the Windows drivers are installed...
2363 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2364 datadir
= CUPS_DATADIR
;
2366 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2367 if (!access(filename
, R_OK
))
2370 * Found Windows 2000 driver file, see if we have smbclient and
2374 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2375 sizeof(filename
)) &&
2376 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2378 cgiSetVariable("HAVE_SAMBA", "Y");
2381 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2383 fputs("ERROR: smbclient not found!\n", stderr
);
2385 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2387 fputs("ERROR: rpcclient not found!\n", stderr
);
2397 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2399 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2400 NULL
, "ipp://localhost/");
2402 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2404 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2405 ippDelete(response
);
2409 * Finally, show the main menu template...
2412 cgiStartHTML(cgiText(_("Administration")));
2414 cgiCopyTemplateLang("admin.tmpl");
2421 * 'do_printer_op()' - Do a printer operation.
2425 do_printer_op(http_t
*http
, /* I - HTTP connection */
2426 ipp_op_t op
, /* I - Operation to perform */
2427 const char *title
) /* I - Title of page */
2429 ipp_t
*request
; /* IPP request */
2430 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2431 const char *printer
, /* Printer name (purge-jobs) */
2432 *is_class
; /* Is a class? */
2435 is_class
= cgiGetVariable("IS_CLASS");
2436 printer
= cgiGetVariable("PRINTER_NAME");
2440 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2441 cgiStartHTML(title
);
2442 cgiCopyTemplateLang("error.tmpl");
2448 * Build a printer request, which requires the following
2451 * attributes-charset
2452 * attributes-natural-language
2456 request
= ippNewRequest(op
);
2458 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2459 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2461 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2465 * Do the request and get back a response...
2468 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2470 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2472 puts("Status: 401\n");
2475 else if (cupsLastError() > IPP_OK_CONFLICT
)
2477 cgiStartHTML(title
);
2478 cgiShowIPPError(_("Unable to change printer:"));
2483 * Redirect successful updates back to the printer page...
2486 char url
[1024], /* Printer/class URL */
2487 refresh
[1024]; /* Refresh URL */
2490 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2491 cgiFormEncode(uri
, url
, sizeof(uri
));
2492 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2493 cgiSetVariable("refresh_page", refresh
);
2495 cgiStartHTML(title
);
2497 if (op
== IPP_PAUSE_PRINTER
)
2498 cgiCopyTemplateLang("printer-stop.tmpl");
2499 else if (op
== IPP_RESUME_PRINTER
)
2500 cgiCopyTemplateLang("printer-start.tmpl");
2501 else if (op
== CUPS_ACCEPT_JOBS
)
2502 cgiCopyTemplateLang("printer-accept.tmpl");
2503 else if (op
== CUPS_REJECT_JOBS
)
2504 cgiCopyTemplateLang("printer-reject.tmpl");
2505 else if (op
== IPP_PURGE_JOBS
)
2506 cgiCopyTemplateLang("printer-purge.tmpl");
2507 else if (op
== CUPS_SET_DEFAULT
)
2508 cgiCopyTemplateLang("printer-default.tmpl");
2516 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2520 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2522 int i
; /* Looping var */
2523 ipp_t
*request
, /* IPP request */
2524 *response
; /* IPP response */
2525 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2526 const char *printer
, /* Printer name (purge-jobs) */
2527 *is_class
, /* Is a class? */
2528 *users
, /* List of users or groups */
2529 *type
; /* Allow/deny type */
2530 int num_users
; /* Number of users */
2531 char *ptr
, /* Pointer into users string */
2532 *end
, /* Pointer to end of users string */
2533 quote
; /* Quote character */
2534 ipp_attribute_t
*attr
; /* Attribute */
2535 static const char * const attrs
[] = /* Requested attributes */
2537 "requesting-user-name-allowed",
2538 "requesting-user-name-denied"
2542 is_class
= cgiGetVariable("IS_CLASS");
2543 printer
= cgiGetVariable("PRINTER_NAME");
2547 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2548 cgiStartHTML(cgiText(_("Set Allowed Users")));
2549 cgiCopyTemplateLang("error.tmpl");
2554 users
= cgiGetVariable("users");
2555 type
= cgiGetVariable("type");
2557 if (!users
|| !type
||
2558 (strcmp(type
, "requesting-user-name-allowed") &&
2559 strcmp(type
, "requesting-user-name-denied")))
2562 * Build a Get-Printer-Attributes request, which requires the following
2565 * attributes-charset
2566 * attributes-natural-language
2568 * requested-attributes
2571 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2573 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2574 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2576 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2579 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2580 "requested-attributes",
2581 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2584 * Do the request and get back a response...
2587 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2589 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2591 ippDelete(response
);
2594 cgiStartHTML(cgiText(_("Set Allowed Users")));
2596 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2598 puts("Status: 401\n");
2601 else if (cupsLastError() > IPP_OK_CONFLICT
)
2602 cgiShowIPPError(_("Unable to get printer attributes:"));
2604 cgiCopyTemplateLang("users.tmpl");
2611 * Save the changes...
2614 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2617 * Skip whitespace and commas...
2620 while (*ptr
== ',' || isspace(*ptr
& 255))
2623 if (*ptr
== '\'' || *ptr
== '\"')
2626 * Scan quoted name...
2631 for (end
= ptr
; *end
; end
++)
2638 * Scan space or comma-delimited name...
2641 for (end
= ptr
; *end
; end
++)
2642 if (isspace(*end
& 255) || *end
== ',')
2647 * Advance to the next name...
2654 * Build a CUPS-Add-Printer/Class request, which requires the following
2657 * attributes-charset
2658 * attributes-natural-language
2660 * requesting-user-name-{allowed,denied}
2663 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2665 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2666 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2668 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2672 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2673 "requesting-user-name-allowed", NULL
, "all");
2676 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2677 type
, num_users
, NULL
, NULL
);
2679 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2682 * Skip whitespace and commas...
2685 while (*ptr
== ',' || isspace(*ptr
& 255))
2688 if (*ptr
== '\'' || *ptr
== '\"')
2691 * Scan quoted name...
2696 for (end
= ptr
; *end
; end
++)
2703 * Scan space or comma-delimited name...
2706 for (end
= ptr
; *end
; end
++)
2707 if (isspace(*end
& 255) || *end
== ',')
2712 * Terminate the name...
2722 attr
->values
[i
].string
.text
= strdup(ptr
);
2725 * Advance to the next name...
2733 * Do the request and get back a response...
2736 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2738 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2740 puts("Status: 401\n");
2743 else if (cupsLastError() > IPP_OK_CONFLICT
)
2745 cgiStartHTML(cgiText(_("Set Allowed Users")));
2746 cgiShowIPPError(_("Unable to change printer:"));
2751 * Redirect successful updates back to the printer page...
2754 char url
[1024], /* Printer/class URL */
2755 refresh
[1024]; /* Refresh URL */
2758 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2759 cgiFormEncode(uri
, url
, sizeof(uri
));
2760 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2762 cgiSetVariable("refresh_page", refresh
);
2764 cgiStartHTML(cgiText(_("Set Allowed Users")));
2766 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2767 "printer-modified.tmpl");
2776 * 'do_set_options()' - Configure the default options for a queue.
2780 do_set_options(http_t
*http
, /* I - HTTP connection */
2781 int is_class
) /* I - Set options for class? */
2783 int i
, j
, k
, m
; /* Looping vars */
2784 int have_options
; /* Have options? */
2785 ipp_t
*request
, /* IPP request */
2786 *response
; /* IPP response */
2787 ipp_attribute_t
*attr
; /* IPP attribute */
2788 char uri
[HTTP_MAX_URI
]; /* Job URI */
2789 const char *var
; /* Variable value */
2790 const char *printer
; /* Printer printer name */
2791 const char *filename
; /* PPD filename */
2792 char tempfile
[1024]; /* Temporary filename */
2793 cups_file_t
*in
, /* Input file */
2794 *out
; /* Output file */
2795 char line
[1024], /* Line from PPD file */
2796 value
[1024], /* Option value */
2797 keyword
[1024], /* Keyword from Default line */
2798 *keyptr
; /* Pointer into keyword... */
2799 ppd_file_t
*ppd
; /* PPD file */
2800 ppd_group_t
*group
; /* Option group */
2801 ppd_option_t
*option
; /* Option */
2802 ppd_coption_t
*coption
; /* Custom option */
2803 ppd_cparam_t
*cparam
; /* Custom parameter */
2804 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
2805 const char *title
; /* Page title */
2808 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2810 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2814 * Get the printer name...
2817 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2818 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2819 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2823 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2824 cgiStartHTML(title
);
2825 cgiCopyTemplateLang("error.tmpl");
2830 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2833 * Get the PPD file...
2839 filename
= cupsGetPPD2(http
, printer
);
2843 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2845 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2847 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2848 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2849 cgiStartHTML(title
);
2850 cgiCopyTemplateLang("error.tmpl");
2857 fputs("DEBUG: No PPD file\n", stderr
);
2861 if (cgiGetVariable("job_sheets_start") != NULL
||
2862 cgiGetVariable("job_sheets_end") != NULL
)
2869 ppdMarkDefaults(ppd
);
2871 for (option
= ppdFirstOption(ppd
);
2873 option
= ppdNextOption(ppd
))
2874 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2877 ppdMarkOption(ppd
, option
->keyword
, var
);
2881 if (!have_options
|| ppdConflicts(ppd
))
2884 * Show the options to the user...
2887 fputs("DEBUG: Showing options...\n", stderr
);
2889 cgiStartHTML(cgiText(_("Set Printer Options")));
2890 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2896 if (ppdConflicts(ppd
))
2898 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
2901 for (j
= group
->num_options
, option
= group
->options
;
2904 if (option
->conflicted
)
2906 cgiSetArray("ckeyword", k
, option
->keyword
);
2907 cgiSetArray("ckeytext", k
, option
->text
);
2911 cgiCopyTemplateLang("option-conflict.tmpl");
2914 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2918 if (!strcmp(group
->name
, "InstallableOptions"))
2919 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2921 cgiSetVariable("GROUP", group
->text
);
2923 cgiCopyTemplateLang("option-header.tmpl");
2925 for (j
= group
->num_options
, option
= group
->options
;
2929 if (!strcmp(option
->keyword
, "PageRegion"))
2932 cgiSetVariable("KEYWORD", option
->keyword
);
2933 cgiSetVariable("KEYTEXT", option
->text
);
2935 if (option
->conflicted
)
2936 cgiSetVariable("CONFLICTED", "1");
2938 cgiSetVariable("CONFLICTED", "0");
2940 cgiSetSize("CHOICES", 0);
2941 cgiSetSize("TEXT", 0);
2942 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
2944 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
2945 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
2949 if (option
->choices
[k
].marked
)
2950 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
2953 cgiSetSize("PARAMS", 0);
2954 cgiSetSize("PARAMTEXT", 0);
2955 cgiSetSize("PARAMVALUE", 0);
2956 cgiSetSize("INPUTTYPE", 0);
2958 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
2960 const char *units
= NULL
; /* Units value, if any */
2963 cgiSetVariable("ISCUSTOM", "1");
2965 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
2967 cparam
= ppdNextCustomParam(coption
), m
++)
2969 if (!strcasecmp(option
->keyword
, "PageSize") &&
2970 strcasecmp(cparam
->name
, "Width") &&
2971 strcasecmp(cparam
->name
, "Height"))
2977 cgiSetArray("PARAMS", m
, cparam
->name
);
2978 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
2979 cgiSetArray("INPUTTYPE", m
, "text");
2981 switch (cparam
->type
)
2983 case PPD_CUSTOM_POINTS
:
2984 if (!strncasecmp(option
->defchoice
, "Custom.", 7))
2986 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
2988 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
2989 strcmp(units
, "in") && strcmp(units
, "ft"))
2991 if (units
[1] == 'm')
3000 if (!strcmp(units
, "mm"))
3001 snprintf(value
, sizeof(value
), "%g",
3002 cparam
->current
.custom_points
/ 72.0 * 25.4);
3003 else if (!strcmp(units
, "cm"))
3004 snprintf(value
, sizeof(value
), "%g",
3005 cparam
->current
.custom_points
/ 72.0 * 2.54);
3006 else if (!strcmp(units
, "in"))
3007 snprintf(value
, sizeof(value
), "%g",
3008 cparam
->current
.custom_points
/ 72.0);
3009 else if (!strcmp(units
, "ft"))
3010 snprintf(value
, sizeof(value
), "%g",
3011 cparam
->current
.custom_points
/ 72.0 / 12.0);
3012 else if (!strcmp(units
, "m"))
3013 snprintf(value
, sizeof(value
), "%g",
3014 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3016 snprintf(value
, sizeof(value
), "%g",
3017 cparam
->current
.custom_points
);
3018 cgiSetArray("PARAMVALUE", m
, value
);
3021 case PPD_CUSTOM_CURVE
:
3022 case PPD_CUSTOM_INVCURVE
:
3023 case PPD_CUSTOM_REAL
:
3024 snprintf(value
, sizeof(value
), "%g",
3025 cparam
->current
.custom_real
);
3026 cgiSetArray("PARAMVALUE", m
, value
);
3029 case PPD_CUSTOM_INT
:
3030 snprintf(value
, sizeof(value
), "%d",
3031 cparam
->current
.custom_int
);
3032 cgiSetArray("PARAMVALUE", m
, value
);
3035 case PPD_CUSTOM_PASSCODE
:
3036 case PPD_CUSTOM_PASSWORD
:
3037 if (cparam
->current
.custom_password
)
3038 cgiSetArray("PARAMVALUE", m
,
3039 cparam
->current
.custom_password
);
3041 cgiSetArray("PARAMVALUE", m
, "");
3042 cgiSetArray("INPUTTYPE", m
, "password");
3045 case PPD_CUSTOM_STRING
:
3046 if (cparam
->current
.custom_string
)
3047 cgiSetArray("PARAMVALUE", m
,
3048 cparam
->current
.custom_string
);
3050 cgiSetArray("PARAMVALUE", m
, "");
3057 cgiSetArray("PARAMS", m
, "Units");
3058 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3059 cgiSetArray("PARAMVALUE", m
, units
);
3063 cgiSetVariable("ISCUSTOM", "0");
3067 case PPD_UI_BOOLEAN
:
3068 cgiCopyTemplateLang("option-boolean.tmpl");
3070 case PPD_UI_PICKONE
:
3071 cgiCopyTemplateLang("option-pickone.tmpl");
3073 case PPD_UI_PICKMANY
:
3074 cgiCopyTemplateLang("option-pickmany.tmpl");
3079 cgiCopyTemplateLang("option-trailer.tmpl");
3084 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
3085 * following attributes:
3087 * attributes-charset
3088 * attributes-natural-language
3092 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3094 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3095 "localhost", 0, "/printers/%s", printer
);
3096 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3100 * Do the request and get back a response...
3103 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
3105 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3106 IPP_TAG_ZERO
)) != NULL
)
3109 * Add the job sheets options...
3112 cgiSetVariable("GROUP", cgiText(_("Banners")));
3113 cgiCopyTemplateLang("option-header.tmpl");
3115 cgiSetSize("CHOICES", attr
->num_values
);
3116 cgiSetSize("TEXT", attr
->num_values
);
3117 for (k
= 0; k
< attr
->num_values
; k
++)
3119 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3120 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3123 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3125 cgiSetVariable("KEYWORD", "job_sheets_start");
3126 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3127 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3128 attr
->values
[0].string
.text
: "");
3130 cgiCopyTemplateLang("option-pickone.tmpl");
3132 cgiSetVariable("KEYWORD", "job_sheets_end");
3133 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3134 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3135 attr
->values
[1].string
.text
: "");
3137 cgiCopyTemplateLang("option-pickone.tmpl");
3139 cgiCopyTemplateLang("option-trailer.tmpl");
3142 if (ippFindAttribute(response
, "printer-error-policy-supported",
3144 ippFindAttribute(response
, "printer-op-policy-supported",
3148 * Add the error and operation policy options...
3151 cgiSetVariable("GROUP", cgiText(_("Policies")));
3152 cgiCopyTemplateLang("option-header.tmpl");
3158 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3163 cgiSetSize("CHOICES", attr
->num_values
);
3164 cgiSetSize("TEXT", attr
->num_values
);
3165 for (k
= 0; k
< attr
->num_values
; k
++)
3167 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3168 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3171 attr
= ippFindAttribute(response
, "printer-error-policy",
3174 cgiSetVariable("KEYWORD", "printer_error_policy");
3175 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3176 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3177 "" : attr
->values
[0].string
.text
);
3180 cgiCopyTemplateLang("option-pickone.tmpl");
3183 * Operation policy...
3186 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3191 cgiSetSize("CHOICES", attr
->num_values
);
3192 cgiSetSize("TEXT", attr
->num_values
);
3193 for (k
= 0; k
< attr
->num_values
; k
++)
3195 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3196 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3199 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3201 cgiSetVariable("KEYWORD", "printer_op_policy");
3202 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3203 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3204 "" : attr
->values
[0].string
.text
);
3206 cgiCopyTemplateLang("option-pickone.tmpl");
3209 cgiCopyTemplateLang("option-trailer.tmpl");
3212 ippDelete(response
);
3216 * Binary protocol support...
3219 if (ppd
&& ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
3221 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
3223 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
3224 cgiCopyTemplateLang("option-header.tmpl");
3226 cgiSetSize("CHOICES", 2);
3227 cgiSetSize("TEXT", 2);
3228 cgiSetArray("CHOICES", 0, "None");
3229 cgiSetArray("TEXT", 0, cgiText(_("None")));
3231 if (strstr(ppd
->protocols
, "TBCP"))
3233 cgiSetArray("CHOICES", 1, "TBCP");
3234 cgiSetArray("TEXT", 1, "TBCP");
3238 cgiSetArray("CHOICES", 1, "BCP");
3239 cgiSetArray("TEXT", 1, "BCP");
3242 cgiSetVariable("KEYWORD", "protocol");
3243 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
3244 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
3246 cgiCopyTemplateLang("option-pickone.tmpl");
3248 cgiCopyTemplateLang("option-trailer.tmpl");
3251 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3257 * Set default options...
3260 fputs("DEBUG: Setting options...\n", stderr
);
3264 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3265 in
= cupsFileOpen(filename
, "r");
3269 cgiSetVariable("ERROR", strerror(errno
));
3270 cgiStartHTML(cgiText(_("Set Printer Options")));
3271 cgiCopyTemplateLang("error.tmpl");
3287 while (cupsFileGets(in
, line
, sizeof(line
)))
3289 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3291 else if (strncmp(line
, "*Default", 8))
3292 cupsFilePrintf(out
, "%s\n", line
);
3296 * Get default option name...
3299 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3301 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3302 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3307 if (!strcmp(keyword
, "PageRegion") ||
3308 !strcmp(keyword
, "PaperDimension") ||
3309 !strcmp(keyword
, "ImageableArea"))
3310 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3312 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3315 cupsFilePrintf(out
, "%s\n", line
);
3317 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3322 * TODO: We need to set the port-monitor attribute!
3325 if ((var
= cgiGetVariable("protocol")) != NULL
)
3326 cupsFilePrintf(out
, "*cupsProtocol: %s\n", var
);
3334 * Make sure temporary filename is cleared when there is no PPD...
3341 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3342 * following attributes:
3344 * attributes-charset
3345 * attributes-natural-language
3347 * job-sheets-default
3348 * printer-error-policy
3353 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3354 CUPS_ADD_MODIFY_PRINTER
);
3356 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3359 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3360 "job-sheets-default", 2, NULL
, NULL
);
3361 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3362 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3364 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3365 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3366 "printer-error-policy", NULL
, var
);
3368 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3369 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3370 "printer-op-policy", NULL
, var
);
3373 * Do the request and get back a response...
3377 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3379 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3381 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3383 puts("Status: 401\n");
3386 else if (cupsLastError() > IPP_OK_CONFLICT
)
3388 cgiStartHTML(title
);
3389 cgiShowIPPError(_("Unable to set options:"));
3394 * Redirect successful updates back to the printer page...
3397 char refresh
[1024]; /* Refresh URL */
3400 cgiFormEncode(uri
, printer
, sizeof(uri
));
3401 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3402 is_class
? "classes" : "printers", uri
);
3403 cgiSetVariable("refresh_page", refresh
);
3405 cgiStartHTML(title
);
3407 cgiCopyTemplateLang("printer-configured.tmpl");
3422 * 'do_set_sharing()' - Set printer-is-shared value.
3426 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3428 ipp_t
*request
, /* IPP request */
3429 *response
; /* IPP response */
3430 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3431 const char *printer
, /* Printer name */
3432 *is_class
, /* Is a class? */
3433 *shared
; /* Sharing value */
3436 is_class
= cgiGetVariable("IS_CLASS");
3437 printer
= cgiGetVariable("PRINTER_NAME");
3438 shared
= cgiGetVariable("SHARED");
3440 if (!printer
|| !shared
)
3442 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3443 cgiStartHTML(cgiText(_("Set Publishing")));
3444 cgiCopyTemplateLang("error.tmpl");
3450 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3451 * following attributes:
3453 * attributes-charset
3454 * attributes-natural-language
3459 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3461 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3462 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3464 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3467 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3470 * Do the request and get back a response...
3473 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3475 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3477 ippDelete(response
);
3480 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3482 puts("Status: 401\n");
3485 else if (cupsLastError() > IPP_OK_CONFLICT
)
3487 cgiStartHTML(cgiText(_("Set Publishing")));
3488 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3493 * Redirect successful updates back to the printer page...
3496 char url
[1024], /* Printer/class URL */
3497 refresh
[1024]; /* Refresh URL */
3500 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3501 cgiFormEncode(uri
, url
, sizeof(uri
));
3502 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3503 cgiSetVariable("refresh_page", refresh
);
3505 cgiStartHTML(cgiText(_("Set Publishing")));
3506 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3507 "printer-modified.tmpl");
3515 * 'get_option_value()' - Return the value of an option.
3517 * This function also handles generation of custom option values.
3520 static char * /* O - Value string or NULL on error */
3522 ppd_file_t
*ppd
, /* I - PPD file */
3523 const char *name
, /* I - Option name */
3524 char *buffer
, /* I - String buffer */
3525 size_t bufsize
) /* I - Size of buffer */
3527 char *bufptr
, /* Pointer into buffer */
3528 *bufend
; /* End of buffer */
3529 ppd_coption_t
*coption
; /* Custom option */
3530 ppd_cparam_t
*cparam
; /* Current custom parameter */
3531 char keyword
[256]; /* Parameter name */
3532 const char *val
, /* Parameter value */
3533 *uval
; /* Units value */
3534 long integer
; /* Integer value */
3535 double number
, /* Number value */
3536 number_points
; /* Number in points */
3540 * See if we have a custom option choice...
3543 if ((val
= cgiGetVariable(name
)) == NULL
)
3551 else if (strcasecmp(val
, "Custom") ||
3552 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3555 * Not a custom choice...
3558 strlcpy(buffer
, val
, bufsize
);
3563 * OK, we have a custom option choice, format it...
3568 if (!strcmp(coption
->keyword
, "PageSize"))
3570 const char *lval
; /* Length string value */
3571 double width
, /* Width value */
3572 width_points
, /* Width in points */
3573 length
, /* Length value */
3574 length_points
; /* Length in points */
3577 val
= cgiGetVariable("PageSize.Width");
3578 lval
= cgiGetVariable("PageSize.Height");
3579 uval
= cgiGetVariable("PageSize.Units");
3581 if (!val
|| !lval
|| !uval
||
3582 (width
= strtod(val
, NULL
)) == 0.0 ||
3583 (length
= strtod(lval
, NULL
)) == 0.0 ||
3584 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3585 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3588 width_points
= get_points(width
, uval
);
3589 length_points
= get_points(length
, uval
);
3591 if (width_points
< ppd
->custom_min
[0] ||
3592 width_points
> ppd
->custom_max
[0] ||
3593 length_points
< ppd
->custom_min
[1] ||
3594 length_points
> ppd
->custom_max
[1])
3597 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
3599 else if (cupsArrayCount(coption
->params
) == 1)
3601 cparam
= ppdFirstCustomParam(coption
);
3602 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
3604 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3607 switch (cparam
->type
)
3609 case PPD_CUSTOM_CURVE
:
3610 case PPD_CUSTOM_INVCURVE
:
3611 case PPD_CUSTOM_REAL
:
3612 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3613 number
< cparam
->minimum
.custom_real
||
3614 number
> cparam
->maximum
.custom_real
)
3617 snprintf(buffer
, bufsize
, "Custom.%g", number
);
3620 case PPD_CUSTOM_INT
:
3621 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3622 integer
== LONG_MAX
||
3623 integer
< cparam
->minimum
.custom_int
||
3624 integer
> cparam
->maximum
.custom_int
)
3627 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
3630 case PPD_CUSTOM_POINTS
:
3631 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3633 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3634 (uval
= cgiGetVariable(keyword
)) == NULL
||
3635 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3636 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3639 number_points
= get_points(number
, uval
);
3640 if (number_points
< cparam
->minimum
.custom_points
||
3641 number_points
> cparam
->maximum
.custom_points
)
3644 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
3647 case PPD_CUSTOM_PASSCODE
:
3648 for (uval
= val
; *uval
; uval
++)
3649 if (!isdigit(*uval
& 255))
3652 case PPD_CUSTOM_PASSWORD
:
3653 case PPD_CUSTOM_STRING
:
3654 integer
= (long)strlen(val
);
3655 if (integer
< cparam
->minimum
.custom_string
||
3656 integer
> cparam
->maximum
.custom_string
)
3659 snprintf(buffer
, bufsize
, "Custom.%s", val
);
3665 const char *prefix
= "{"; /* Prefix string */
3669 bufend
= buffer
+ bufsize
;
3671 for (cparam
= ppdFirstCustomParam(coption
);
3673 cparam
= ppdNextCustomParam(coption
))
3675 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
3678 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3681 snprintf(bufptr
, bufend
- bufptr
, "%s%s=", prefix
, cparam
->name
);
3682 bufptr
+= strlen(bufptr
);
3685 switch (cparam
->type
)
3687 case PPD_CUSTOM_CURVE
:
3688 case PPD_CUSTOM_INVCURVE
:
3689 case PPD_CUSTOM_REAL
:
3690 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3691 number
< cparam
->minimum
.custom_real
||
3692 number
> cparam
->maximum
.custom_real
)
3695 snprintf(bufptr
, bufend
- bufptr
, "%g", number
);
3698 case PPD_CUSTOM_INT
:
3699 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3700 integer
== LONG_MAX
||
3701 integer
< cparam
->minimum
.custom_int
||
3702 integer
> cparam
->maximum
.custom_int
)
3705 snprintf(bufptr
, bufend
- bufptr
, "%ld", integer
);
3708 case PPD_CUSTOM_POINTS
:
3709 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3711 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3712 (uval
= cgiGetVariable(keyword
)) == NULL
||
3713 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
3714 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
3715 strcmp(uval
, "mm") && strcmp(uval
, "m")))
3718 number_points
= get_points(number
, uval
);
3719 if (number_points
< cparam
->minimum
.custom_points
||
3720 number_points
> cparam
->maximum
.custom_points
)
3723 snprintf(bufptr
, bufend
- bufptr
, "%g%s", number
, uval
);
3726 case PPD_CUSTOM_PASSCODE
:
3727 for (uval
= val
; *uval
; uval
++)
3728 if (!isdigit(*uval
& 255))
3731 case PPD_CUSTOM_PASSWORD
:
3732 case PPD_CUSTOM_STRING
:
3733 integer
= (long)strlen(val
);
3734 if (integer
< cparam
->minimum
.custom_string
||
3735 integer
> cparam
->maximum
.custom_string
)
3738 if ((bufptr
+ 2) > bufend
)
3744 while (*val
&& bufptr
< bufend
)
3746 if (*val
== '\\' || *val
== '\"')
3748 if ((bufptr
+ 1) >= bufend
)
3757 if (bufptr
>= bufend
)
3766 bufptr
+= strlen(bufptr
);
3769 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
3772 strcpy(bufptr
, "}");
3780 * 'get_points()' - Get a value in points.
3783 static double /* O - Number in points */
3784 get_points(double number
, /* I - Original number */
3785 const char *uval
) /* I - Units */
3787 if (!strcmp(uval
, "mm")) /* Millimeters */
3788 return (number
* 72.0 / 25.4);
3789 else if (!strcmp(uval
, "cm")) /* Centimeters */
3790 return (number
* 72.0 / 2.54);
3791 else if (!strcmp(uval
, "in")) /* Inches */
3792 return (number
* 72.0);
3793 else if (!strcmp(uval
, "ft")) /* Feet */
3794 return (number
* 72.0 * 12.0);
3795 else if (!strcmp(uval
, "m")) /* Meters */
3796 return (number
* 72.0 / 0.0254);
3803 * 'match_string()' - Return the number of matching characters.
3806 static int /* O - Number of matching characters */
3807 match_string(const char *a
, /* I - First string */
3808 const char *b
) /* I - Second string */
3810 int count
; /* Number of matching characters */
3814 * Loop through both strings until we hit the end of either or we find
3815 * a non-matching character. For the purposes of comparison, we ignore
3816 * whitespace and do a case-insensitive comparison so that we have a
3817 * better chance of finding a match...
3820 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
3823 * Skip leading whitespace characters...
3826 while (isspace(*a
& 255))
3829 while (isspace(*b
& 255))
3833 * Break out if we run out of characters...
3840 * Do a case-insensitive comparison of the next two chars...
3843 if (tolower(*a
& 255) != tolower(*b
& 255))
3852 * End of "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $".