2 * "$Id: admin.c 6649 2007-07-11 21:46:42Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 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 * match_string() - Return the number of matching characters.
36 * Include necessary headers...
39 #include "cgi-private.h"
40 #include <cups/adminutil.h>
41 #include <cups/file.h>
52 static void do_add_rss_subscription(http_t
*http
);
53 static void do_am_class(http_t
*http
, int modify
);
54 static void do_am_printer(http_t
*http
, int modify
);
55 static void do_cancel_subscription(http_t
*http
);
56 static void do_set_options(http_t
*http
, int is_class
);
57 static void do_config_server(http_t
*http
);
58 static void do_delete_class(http_t
*http
);
59 static void do_delete_printer(http_t
*http
);
60 static void do_export(http_t
*http
);
61 static void do_list_printers(http_t
*http
);
62 static void do_menu(http_t
*http
);
63 static void do_printer_op(http_t
*http
,
64 ipp_op_t op
, const char *title
);
65 static void do_set_allowed_users(http_t
*http
);
66 static void do_set_sharing(http_t
*http
);
67 static int match_string(const char *a
, const char *b
);
71 * 'main()' - Main entry for CGI.
74 int /* O - Exit status */
75 main(int argc
, /* I - Number of command-line arguments */
76 char *argv
[]) /* I - Command-line arguments */
78 http_t
*http
; /* Connection to the server */
79 const char *op
; /* Operation name */
83 * Connect to the HTTP server...
86 fputs("DEBUG: admin.cgi started...\n", stderr
);
88 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
92 perror("ERROR: Unable to connect to cupsd");
93 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
94 cupsServer() ? cupsServer() : "(null)");
95 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
96 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
100 fprintf(stderr
, "DEBUG: http=%p\n", http
);
103 * Set the web interface section...
106 cgiSetVariable("SECTION", "admin");
109 * See if we have form data...
112 if (!cgiInitialize())
115 * Nope, send the administration menu...
118 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
122 else if ((op
= cgiGetVariable("OP")) != NULL
)
125 * Do the operation...
128 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
130 if (!strcmp(op
, "redirect"))
132 const char *url
; /* Redirection URL... */
133 char prefix
[1024]; /* URL prefix */
137 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
138 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
140 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
141 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
143 if ((url
= cgiGetVariable("URL")) != NULL
)
144 printf("Location: %s%s\n\n", prefix
, url
);
146 printf("Location: %s/admin\n\n", prefix
);
148 else if (!strcmp(op
, "start-printer"))
149 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
150 else if (!strcmp(op
, "stop-printer"))
151 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
152 else if (!strcmp(op
, "start-class"))
153 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
154 else if (!strcmp(op
, "stop-class"))
155 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
156 else if (!strcmp(op
, "accept-jobs"))
157 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
158 else if (!strcmp(op
, "reject-jobs"))
159 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
160 else if (!strcmp(op
, "purge-jobs"))
161 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
162 else if (!strcmp(op
, "set-allowed-users"))
163 do_set_allowed_users(http
);
164 else if (!strcmp(op
, "set-as-default"))
165 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
166 else if (!strcmp(op
, "set-sharing"))
167 do_set_sharing(http
);
168 else if (!strcmp(op
, "list-available-printers"))
169 do_list_printers(http
);
170 else if (!strcmp(op
, "add-class"))
171 do_am_class(http
, 0);
172 else if (!strcmp(op
, "add-printer"))
173 do_am_printer(http
, 0);
174 else if (!strcmp(op
, "modify-class"))
175 do_am_class(http
, 1);
176 else if (!strcmp(op
, "modify-printer"))
177 do_am_printer(http
, 1);
178 else if (!strcmp(op
, "delete-class"))
179 do_delete_class(http
);
180 else if (!strcmp(op
, "delete-printer"))
181 do_delete_printer(http
);
182 else if (!strcmp(op
, "set-class-options"))
183 do_set_options(http
, 1);
184 else if (!strcmp(op
, "set-printer-options"))
185 do_set_options(http
, 0);
186 else if (!strcmp(op
, "config-server"))
187 do_config_server(http
);
188 else if (!strcmp(op
, "export-samba"))
190 else if (!strcmp(op
, "add-rss-subscription"))
191 do_add_rss_subscription(http
);
192 else if (!strcmp(op
, "cancel-subscription"))
193 do_cancel_subscription(http
);
197 * Bad operation code... Display an error...
200 cgiStartHTML(cgiText(_("Administration")));
201 cgiCopyTemplateLang("error-op.tmpl");
208 * Form data but no operation code... Display an error...
211 cgiStartHTML(cgiText(_("Administration")));
212 cgiCopyTemplateLang("error-op.tmpl");
217 * Close the HTTP server connection...
223 * Return with no errors...
231 * 'do_add_rss_subscription()' - Add a RSS subscription.
235 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
237 ipp_t
*request
, /* IPP request data */
238 *response
; /* IPP response data */
239 char rss_uri
[1024]; /* RSS notify-recipient URI */
240 int num_events
; /* Number of events */
241 const char *events
[12], /* Subscribed events */
242 *subscription_name
, /* Subscription name */
243 *printer_uri
, /* Printer URI */
244 *ptr
, /* Pointer into name */
245 *user
; /* Username */
246 int max_events
; /* Maximum number of events */
250 * See if we have all of the required information...
253 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
254 printer_uri
= cgiGetVariable("PRINTER_URI");
257 if (cgiGetVariable("EVENT_JOB_CREATED"))
258 events
[num_events
++] = "job-created";
259 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
260 events
[num_events
++] = "job-completed";
261 if (cgiGetVariable("EVENT_JOB_STOPPED"))
262 events
[num_events
++] = "job-stopped";
263 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
264 events
[num_events
++] = "job-config-changed";
265 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
266 events
[num_events
++] = "printer-stopped";
267 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
268 events
[num_events
++] = "printer-added";
269 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
270 events
[num_events
++] = "printer-modified";
271 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
272 events
[num_events
++] = "printer-deleted";
273 if (cgiGetVariable("EVENT_SERVER_STARTED"))
274 events
[num_events
++] = "server-started";
275 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
276 events
[num_events
++] = "server-stopped";
277 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
278 events
[num_events
++] = "server-restarted";
279 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
280 events
[num_events
++] = "server-audit";
282 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
283 max_events
= atoi(ptr
);
287 if (!subscription_name
|| !printer_uri
|| !num_events
||
288 max_events
<= 0 || max_events
> 9999)
291 * Don't have everything we need, so get the available printers
292 * and classes and (re)show the add page...
295 request
= ippNewRequest(CUPS_GET_PRINTERS
);
296 response
= cupsDoRequest(http
, request
, "/");
298 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
302 cgiStartHTML(cgiText(_("Add RSS Subscription")));
304 cgiCopyTemplateLang("add-rss-subscription.tmpl");
311 * Validate the subscription name...
314 for (ptr
= subscription_name
; *ptr
; ptr
++)
315 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
316 *ptr
== '?' || *ptr
== '#')
321 cgiSetVariable("ERROR",
322 cgiText(_("The subscription name may not "
323 "contain spaces, slashes (/), question marks (?), "
324 "or the pound sign (#).")));
325 cgiStartHTML(_("Add RSS Subscription"));
326 cgiCopyTemplateLang("error.tmpl");
332 * Add the subscription...
335 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
336 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
337 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
338 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
341 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
342 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
345 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
347 if (!strcasecmp(printer_uri
, "#ALL#"))
348 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
349 NULL
, "ipp://localhost/");
351 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
354 if ((user
= getenv("REMOTE_USER")) == NULL
)
357 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
360 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
361 "notify-recipient-uri", NULL
, rss_uri
);
362 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
363 num_events
, NULL
, events
);
364 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
365 "notify-lease-duration", 0);
367 ippDelete(cupsDoRequest(http
, request
, "/"));
369 if (cupsLastError() > IPP_OK_CONFLICT
)
371 cgiStartHTML(_("Add RSS Subscription"));
372 cgiShowIPPError(_("Unable to add RSS subscription:"));
377 * Redirect successful updates back to the admin page...
380 cgiSetVariable("refresh_page", "5;URL=/admin");
381 cgiStartHTML(_("Add RSS Subscription"));
382 cgiCopyTemplateLang("subscription-added.tmpl");
390 * 'do_am_class()' - Add or modify a class.
394 do_am_class(http_t
*http
, /* I - HTTP connection */
395 int modify
) /* I - Modify the printer? */
397 int i
, j
; /* Looping vars */
398 int element
; /* Element number */
399 int num_printers
; /* Number of printers */
400 ipp_t
*request
, /* IPP request */
401 *response
; /* IPP response */
402 ipp_attribute_t
*attr
; /* member-uris attribute */
403 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
404 const char *name
, /* Pointer to class name */
405 *ptr
; /* Pointer to CGI variable */
406 const char *title
; /* Title of page */
407 static const char * const pattrs
[] = /* Requested printer attributes */
415 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
416 name
= cgiGetVariable("PRINTER_NAME");
418 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
421 * Build a CUPS_GET_PRINTERS request, which requires the
422 * following attributes:
425 * attributes-natural-language
428 request
= ippNewRequest(CUPS_GET_PRINTERS
);
431 * Do the request and get back a response...
434 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
437 * Create MEMBER_URIS and MEMBER_NAMES arrays...
440 for (element
= 0, attr
= response
->attrs
;
443 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
445 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
446 (!name
|| strcasecmp(name
, ptr
+ 1)))
449 * Don't show the current class...
452 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
457 for (element
= 0, attr
= response
->attrs
;
460 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
462 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
465 * Don't show the current class...
468 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
473 num_printers
= cgiGetSize("MEMBER_URIS");
483 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
484 * following attributes:
487 * attributes-natural-language
491 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
493 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
494 "localhost", 0, "/classes/%s", name
);
495 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
498 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
499 "requested-attributes",
500 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
504 * Do the request and get back a response...
507 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
509 if ((attr
= ippFindAttribute(response
, "member-names",
510 IPP_TAG_NAME
)) != NULL
)
513 * Mark any current members in the class...
516 for (j
= 0; j
< num_printers
; j
++)
517 cgiSetArray("MEMBER_SELECTED", j
, "");
519 for (i
= 0; i
< attr
->num_values
; i
++)
521 for (j
= 0; j
< num_printers
; j
++)
523 if (!strcasecmp(attr
->values
[i
].string
.text
,
524 cgiGetArray("MEMBER_NAMES", j
)))
526 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
533 if ((attr
= ippFindAttribute(response
, "printer-info",
534 IPP_TAG_TEXT
)) != NULL
)
535 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
537 if ((attr
= ippFindAttribute(response
, "printer-location",
538 IPP_TAG_TEXT
)) != NULL
)
539 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
545 * Update the location and description of an existing printer...
549 cgiCopyTemplateLang("modify-class.tmpl");
554 * Get the name, location, and description for a new printer...
558 cgiCopyTemplateLang("add-class.tmpl");
566 for (ptr
= name
; *ptr
; ptr
++)
567 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
570 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
572 cgiSetVariable("ERROR",
573 cgiText(_("The class name may only contain up to "
574 "127 printable characters and may not "
575 "contain spaces, slashes (/), or the "
576 "pound sign (#).")));
578 cgiCopyTemplateLang("error.tmpl");
584 * Build a CUPS_ADD_CLASS request, which requires the following
588 * attributes-natural-language
592 * printer-is-accepting-jobs
597 request
= ippNewRequest(CUPS_ADD_CLASS
);
599 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
600 "localhost", 0, "/classes/%s",
601 cgiGetVariable("PRINTER_NAME"));
602 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
605 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
606 NULL
, cgiGetVariable("PRINTER_LOCATION"));
608 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
609 NULL
, cgiGetVariable("PRINTER_INFO"));
611 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
613 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
616 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
618 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
619 num_printers
, NULL
, NULL
);
620 for (i
= 0; i
< num_printers
; i
++)
621 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
625 * Do the request and get back a response...
628 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
630 if (cupsLastError() > IPP_OK_CONFLICT
)
633 cgiShowIPPError(modify
? _("Unable to modify class:") :
634 _("Unable to add class:"));
639 * Redirect successful updates back to the class page...
642 char refresh
[1024]; /* Refresh URL */
644 cgiFormEncode(uri
, name
, sizeof(uri
));
645 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
647 cgiSetVariable("refresh_page", refresh
);
652 cgiCopyTemplateLang("class-modified.tmpl");
654 cgiCopyTemplateLang("class-added.tmpl");
662 * 'do_am_printer()' - Add or modify a printer.
666 do_am_printer(http_t
*http
, /* I - HTTP connection */
667 int modify
) /* I - Modify the printer? */
669 int i
; /* Looping var */
670 ipp_attribute_t
*attr
; /* Current attribute */
671 ipp_t
*request
, /* IPP request */
672 *response
, /* IPP response */
673 *oldinfo
; /* Old printer information */
674 const cgi_file_t
*file
; /* Uploaded file, if any */
675 const char *var
; /* CGI variable */
676 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
677 *uriptr
; /* Pointer into URI */
678 int maxrate
; /* Maximum baud rate */
679 char baudrate
[255]; /* Baud rate string */
680 const char *name
, /* Pointer to class name */
681 *ptr
; /* Pointer to CGI variable */
682 const char *title
; /* Title of page */
683 static int baudrates
[] = /* Baud rates */
698 ptr
= cgiGetVariable("DEVICE_URI");
699 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
700 ptr
? ptr
: "(null)");
702 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
707 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
708 * following attributes:
711 * attributes-natural-language
715 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
717 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
718 "localhost", 0, "/printers/%s",
719 cgiGetVariable("PRINTER_NAME"));
720 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
724 * Do the request and get back a response...
727 oldinfo
= cupsDoRequest(http
, request
, "/");
732 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
733 cgiGetVariable("PRINTER_LOCATION") == NULL
)
740 * Update the location and description of an existing printer...
744 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
746 cgiCopyTemplateLang("modify-printer.tmpl");
751 * Get the name, location, and description for a new printer...
754 cgiCopyTemplateLang("add-printer.tmpl");
765 for (ptr
= name
; *ptr
; ptr
++)
766 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
769 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
771 cgiSetVariable("ERROR",
772 cgiText(_("The printer name may only contain up to "
773 "127 printable characters and may not "
774 "contain spaces, slashes (/), or the "
775 "pound sign (#).")));
777 cgiCopyTemplateLang("error.tmpl");
786 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
787 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
788 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
789 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
792 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
795 * Build a CUPS_GET_DEVICES request, which requires the following
799 * attributes-natural-language
803 fputs("DEBUG: Getting list of devices...\n", stderr
);
805 request
= ippNewRequest(CUPS_GET_DEVICES
);
807 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
808 NULL
, "ipp://localhost/printers/");
811 * Do the request and get back a response...
814 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
816 fputs("DEBUG: Got device list!\n", stderr
);
818 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
823 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
824 cupsLastError(), cupsLastErrorString());
827 * Let the user choose...
830 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
832 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
833 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
836 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
837 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
841 cgiCopyTemplateLang("choose-device.tmpl");
844 else if (strchr(var
, '/') == NULL
)
846 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
849 * Set the current device URI for the form to the old one...
852 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
853 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
857 * User needs to set the full URI...
861 cgiCopyTemplateLang("choose-uri.tmpl");
864 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
867 * Need baud rate, parity, etc.
870 if ((var
= strchr(var
, '?')) != NULL
&&
871 strncmp(var
, "?baud=", 6) == 0)
872 maxrate
= atoi(var
+ 6);
876 for (i
= 0; i
< 10; i
++)
877 if (baudrates
[i
] > maxrate
)
881 sprintf(baudrate
, "%d", baudrates
[i
]);
882 cgiSetArray("BAUDRATES", i
, baudrate
);
886 cgiCopyTemplateLang("choose-serial.tmpl");
889 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
894 * Get the PPD file...
897 int fd
; /* PPD file */
898 char filename
[1024]; /* PPD filename */
899 ppd_file_t
*ppd
; /* PPD information */
900 char buffer
[1024]; /* Buffer */
901 int bytes
; /* Number of bytes */
902 http_status_t get_status
; /* Status of GET */
905 /* TODO: Use cupsGetFile() API... */
906 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
908 if (httpGet(http
, uri
))
911 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
913 if (get_status
!= HTTP_OK
)
915 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
916 uri
, get_status
, httpStatus(get_status
));
918 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
920 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
921 write(fd
, buffer
, bytes
);
925 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
927 if (ppd
->manufacturer
)
928 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
931 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
938 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
939 filename
, ppdErrorString(ppdLastError(&bytes
)));
947 "ERROR: Unable to create temporary file for PPD file: %s\n",
951 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
954 * Extract make and make/model from device URI string...
957 char make
[1024], /* Make string */
958 *makeptr
; /* Pointer into make */
963 strlcpy(make
, uriptr
, sizeof(make
));
965 if ((makeptr
= strchr(make
, ' ')) != NULL
)
967 else if ((makeptr
= strchr(make
, '-')) != NULL
)
969 else if (!strncasecmp(make
, "laserjet", 8) ||
970 !strncasecmp(make
, "deskjet", 7) ||
971 !strncasecmp(make
, "designjet", 9))
973 else if (!strncasecmp(make
, "phaser", 6))
974 strcpy(make
, "Xerox");
975 else if (!strncasecmp(make
, "stylus", 6))
976 strcpy(make
, "Epson");
978 strcpy(make
, "Generic");
980 cgiSetVariable("CURRENT_MAKE", make
);
981 cgiSetVariable("PPD_MAKE", make
);
982 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
986 * Build a CUPS_GET_PPDS request, which requires the following
990 * attributes-natural-language
994 request
= ippNewRequest(CUPS_GET_PPDS
);
996 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
997 NULL
, "ipp://localhost/printers/");
999 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
1000 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1001 "ppd-make", NULL
, var
);
1003 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1004 "requested-attributes", NULL
, "ppd-make");
1007 * Do the request and get back a response...
1010 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1013 * Got the list of PPDs, see if the user has selected a make...
1016 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
1019 * No PPD files with this make, try again with all makes...
1022 ippDelete(response
);
1024 request
= ippNewRequest(CUPS_GET_PPDS
);
1026 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1027 NULL
, "ipp://localhost/printers/");
1029 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1030 "requested-attributes", NULL
, "ppd-make");
1032 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1033 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1035 cgiStartHTML(title
);
1036 cgiCopyTemplateLang("choose-make.tmpl");
1041 cgiStartHTML(title
);
1042 cgiCopyTemplateLang("choose-make.tmpl");
1048 * Let the user choose a model...
1051 const char *make_model
; /* Current make/model string */
1054 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1057 * Scan for "close" matches...
1060 int match
, /* Current match */
1061 best_match
, /* Best match so far */
1062 count
; /* Number of drivers */
1063 const char *best
, /* Best matching string */
1064 *current
; /* Current string */
1067 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
1069 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
1071 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
1072 match
= match_string(make_model
, current
);
1074 if (match
> best_match
)
1081 if (best_match
> strlen(var
))
1084 * Found a match longer than the make...
1087 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
1091 cgiStartHTML(title
);
1092 cgiCopyTemplateLang("choose-model.tmpl");
1096 ippDelete(response
);
1100 cgiStartHTML(title
);
1101 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1102 cgiCopyTemplateLang("error.tmpl");
1109 * Build a CUPS_ADD_PRINTER request, which requires the following
1112 * attributes-charset
1113 * attributes-natural-language
1119 * printer-is-accepting-jobs
1123 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1125 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1126 "localhost", 0, "/printers/%s",
1127 cgiGetVariable("PRINTER_NAME"));
1128 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1131 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1132 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1134 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1135 NULL
, cgiGetVariable("PRINTER_INFO"));
1138 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1139 NULL
, cgiGetVariable("PPD_NAME"));
1141 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1144 * Strip make and model from URI...
1147 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1150 if (!strncmp(uri
, "serial:", 7))
1153 * Update serial port URI to include baud rate, etc.
1156 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1157 uriptr
= uri
+ strlen(uri
);
1159 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1160 "?baud=%s+bits=%s+parity=%s+flow=%s",
1161 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1162 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1165 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1168 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1170 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1174 * Do the request and get back a response...
1178 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1180 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1182 if (cupsLastError() > IPP_OK_CONFLICT
)
1184 cgiStartHTML(title
);
1185 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1186 _("Unable to add printer:"));
1191 * Redirect successful updates back to the printer or set-options pages...
1194 char refresh
[1024]; /* Refresh URL */
1197 cgiFormEncode(uri
, name
, sizeof(uri
));
1200 snprintf(refresh
, sizeof(refresh
),
1201 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1203 snprintf(refresh
, sizeof(refresh
),
1204 "5;URL=/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1206 cgiSetVariable("refresh_page", refresh
);
1208 cgiStartHTML(title
);
1211 cgiCopyTemplateLang("printer-modified.tmpl");
1213 cgiCopyTemplateLang("printer-added.tmpl");
1225 * 'do_cancel_subscription()' - Cancel a subscription.
1229 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1231 ipp_t
*request
; /* IPP request data */
1232 const char *var
, /* Form variable */
1233 *user
; /* Username */
1234 int id
; /* Subscription ID */
1238 * See if we have all of the required information...
1241 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1248 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1249 cgiStartHTML(_("Cancel RSS Subscription"));
1250 cgiCopyTemplateLang("error.tmpl");
1256 * Cancel the subscription...
1259 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1261 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1262 NULL
, "ipp://localhost/");
1263 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1264 "notify-subscription-id", id
);
1266 if ((user
= getenv("REMOTE_USER")) == NULL
)
1269 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1272 ippDelete(cupsDoRequest(http
, request
, "/"));
1274 if (cupsLastError() > IPP_OK_CONFLICT
)
1276 cgiStartHTML(_("Cancel RSS Subscription"));
1277 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1282 * Redirect successful updates back to the admin page...
1285 cgiSetVariable("refresh_page", "5;URL=/admin");
1286 cgiStartHTML(_("Cancel RSS Subscription"));
1287 cgiCopyTemplateLang("subscription-canceled.tmpl");
1295 * 'do_config_server()' - Configure server settings.
1299 do_config_server(http_t
*http
) /* I - HTTP connection */
1301 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1304 * Save basic setting changes...
1307 int num_settings
; /* Number of server settings */
1308 cups_option_t
*settings
; /* Server settings */
1309 const char *debug_logging
, /* DEBUG_LOGGING value */
1310 *remote_admin
, /* REMOTE_ADMIN value */
1311 *remote_any
, /* REMOTE_ANY value */
1313 /* REMOTE_PRINTERS value */
1314 *share_printers
,/* SHARE_PRINTERS value */
1317 /* DefaultAuthType value */
1318 #endif /* HAVE_GSSAPI */
1320 /* USER_CANCEL_ANY value */
1324 * Get the checkbox values from the form...
1327 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1328 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1329 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1330 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1331 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1332 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1334 default_auth_type
= cgiGetVariable("KERBEROS") ? "Negotiate" : "Basic";
1336 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1337 #endif /* HAVE_GSSAPI */
1340 * Get the current server settings...
1343 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1345 cgiStartHTML(cgiText(_("Change Settings")));
1346 cgiSetVariable("MESSAGE",
1347 cgiText(_("Unable to change server settings:")));
1348 cgiSetVariable("ERROR", cupsLastErrorString());
1349 cgiCopyTemplateLang("error.tmpl");
1355 * See if the settings have changed...
1358 if (strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1359 num_settings
, settings
)) ||
1360 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1361 num_settings
, settings
)) ||
1362 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1363 num_settings
, settings
)) ||
1364 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1365 num_settings
, settings
)) ||
1366 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1367 num_settings
, settings
)) ||
1369 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1370 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1371 num_settings
, settings
)) ||
1372 #endif /* HAVE_GSSAPI */
1373 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1374 num_settings
, settings
)))
1377 * Settings *have* changed, so save the changes...
1380 cupsFreeOptions(num_settings
, settings
);
1383 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1384 debug_logging
, num_settings
, &settings
);
1385 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1386 remote_admin
, num_settings
, &settings
);
1387 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1388 remote_any
, num_settings
, &settings
);
1389 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1390 remote_printers
, num_settings
, &settings
);
1391 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1392 share_printers
, num_settings
, &settings
);
1393 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1394 user_cancel_any
, num_settings
, &settings
);
1396 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1397 num_settings
, &settings
);
1398 #endif /* HAVE_GSSAPI */
1400 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1402 cgiStartHTML(cgiText(_("Change Settings")));
1403 cgiSetVariable("MESSAGE",
1404 cgiText(_("Unable to change server settings:")));
1405 cgiSetVariable("ERROR", cupsLastErrorString());
1406 cgiCopyTemplateLang("error.tmpl");
1410 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1411 cgiStartHTML(cgiText(_("Change Settings")));
1412 cgiCopyTemplateLang("restart.tmpl");
1421 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1422 cgiStartHTML(cgiText(_("Change Settings")));
1423 cgiCopyTemplateLang("norestart.tmpl");
1426 cupsFreeOptions(num_settings
, settings
);
1430 else if (cgiIsPOST())
1433 * Save hand-edited config file...
1436 http_status_t status
; /* PUT status */
1437 char tempfile
[1024]; /* Temporary new cupsd.conf */
1438 int tempfd
; /* Temporary file descriptor */
1439 cups_file_t
*temp
; /* Temporary file */
1440 const char *start
, /* Start of line */
1441 *end
; /* End of line */
1445 * Create a temporary file for the new cupsd.conf file...
1448 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1450 cgiStartHTML(cgiText(_("Edit Configuration File")));
1451 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1452 cgiSetVariable("ERROR", strerror(errno
));
1453 cgiCopyTemplateLang("error.tmpl");
1460 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1462 cgiStartHTML(cgiText(_("Edit Configuration File")));
1463 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1464 cgiSetVariable("ERROR", strerror(errno
));
1465 cgiCopyTemplateLang("error.tmpl");
1475 * Copy the cupsd.conf text from the form variable...
1478 start
= cgiGetVariable("CUPSDCONF");
1481 if ((end
= strstr(start
, "\r\n")) == NULL
)
1482 if ((end
= strstr(start
, "\n")) == NULL
)
1483 end
= start
+ strlen(start
);
1485 cupsFileWrite(temp
, start
, end
- start
);
1486 cupsFilePutChar(temp
, '\n');
1490 else if (*end
== '\n')
1496 cupsFileClose(temp
);
1499 * Upload the configuration file to the server...
1502 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1504 if (status
!= HTTP_CREATED
)
1506 cgiSetVariable("MESSAGE",
1507 cgiText(_("Unable to upload cupsd.conf file:")));
1508 cgiSetVariable("ERROR", httpStatus(status
));
1510 cgiStartHTML(cgiText(_("Edit Configuration File")));
1511 cgiCopyTemplateLang("error.tmpl");
1515 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1517 cgiStartHTML(cgiText(_("Edit Configuration File")));
1518 cgiCopyTemplateLang("restart.tmpl");
1527 struct stat info
; /* cupsd.conf information */
1528 cups_file_t
*cupsd
; /* cupsd.conf file */
1529 char *buffer
; /* Buffer for entire file */
1530 char filename
[1024]; /* Filename */
1531 const char *server_root
; /* Location of config files */
1535 * Locate the cupsd.conf file...
1538 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1539 server_root
= CUPS_SERVERROOT
;
1541 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1544 * Figure out the size...
1547 if (stat(filename
, &info
))
1549 cgiStartHTML(cgiText(_("Edit Configuration File")));
1550 cgiSetVariable("MESSAGE",
1551 cgiText(_("Unable to access cupsd.conf file:")));
1552 cgiSetVariable("ERROR", strerror(errno
));
1553 cgiCopyTemplateLang("error.tmpl");
1560 if (info
.st_size
> (1024 * 1024))
1562 cgiStartHTML(cgiText(_("Edit Configuration File")));
1563 cgiSetVariable("MESSAGE",
1564 cgiText(_("Unable to access cupsd.conf file:")));
1565 cgiSetVariable("ERROR",
1566 cgiText(_("Unable to edit cupsd.conf files larger than "
1568 cgiCopyTemplateLang("error.tmpl");
1571 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1572 (long)info
.st_size
);
1577 * Open the cupsd.conf file...
1580 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1583 * Unable to open - log an error...
1586 cgiStartHTML(cgiText(_("Edit Configuration File")));
1587 cgiSetVariable("MESSAGE",
1588 cgiText(_("Unable to access cupsd.conf file:")));
1589 cgiSetVariable("ERROR", strerror(errno
));
1590 cgiCopyTemplateLang("error.tmpl");
1598 * Allocate memory and load the file into a string buffer...
1601 buffer
= calloc(1, info
.st_size
+ 1);
1603 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1604 cupsFileClose(cupsd
);
1606 cgiSetVariable("CUPSDCONF", buffer
);
1610 * Show the current config file...
1613 cgiStartHTML(cgiText(_("Edit Configuration File")));
1615 printf("<!-- \"%s\" -->\n", filename
);
1617 cgiCopyTemplateLang("edit-config.tmpl");
1625 * 'do_delete_class()' - Delete a class...
1629 do_delete_class(http_t
*http
) /* I - HTTP connection */
1631 ipp_t
*request
; /* IPP request */
1632 char uri
[HTTP_MAX_URI
]; /* Job URI */
1633 const char *pclass
; /* Printer class name */
1637 * Get form variables...
1640 if (cgiGetVariable("CONFIRM") == NULL
)
1642 cgiStartHTML(cgiText(_("Delete Class")));
1643 cgiCopyTemplateLang("class-confirm.tmpl");
1648 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1649 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1650 "localhost", 0, "/classes/%s", pclass
);
1653 cgiStartHTML(cgiText(_("Delete Class")));
1654 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1655 cgiCopyTemplateLang("error.tmpl");
1661 * Build a CUPS_DELETE_CLASS request, which requires the following
1664 * attributes-charset
1665 * attributes-natural-language
1669 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1671 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1675 * Do the request and get back a response...
1678 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1681 * Show the results...
1684 if (cupsLastError() <= IPP_OK_CONFLICT
)
1687 * Redirect successful updates back to the classes page...
1690 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1693 cgiStartHTML(cgiText(_("Delete Class")));
1695 if (cupsLastError() > IPP_OK_CONFLICT
)
1696 cgiShowIPPError(_("Unable to delete class:"));
1698 cgiCopyTemplateLang("class-deleted.tmpl");
1705 * 'do_delete_printer()' - Delete a printer...
1709 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1711 ipp_t
*request
; /* IPP request */
1712 char uri
[HTTP_MAX_URI
]; /* Job URI */
1713 const char *printer
; /* Printer printer name */
1717 * Get form variables...
1720 if (cgiGetVariable("CONFIRM") == NULL
)
1722 cgiStartHTML(cgiText(_("Delete Printer")));
1723 cgiCopyTemplateLang("printer-confirm.tmpl");
1728 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1729 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1730 "localhost", 0, "/printers/%s", printer
);
1733 cgiStartHTML(cgiText(_("Delete Printer")));
1734 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1735 cgiCopyTemplateLang("error.tmpl");
1741 * Build a CUPS_DELETE_PRINTER request, which requires the following
1744 * attributes-charset
1745 * attributes-natural-language
1749 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1751 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1755 * Do the request and get back a response...
1758 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1761 * Show the results...
1764 if (cupsLastError() <= IPP_OK_CONFLICT
)
1767 * Redirect successful updates back to the printers page...
1770 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1773 cgiStartHTML(cgiText(_("Delete Printer")));
1775 if (cupsLastError() > IPP_OK_CONFLICT
)
1776 cgiShowIPPError(_("Unable to delete printer:"));
1778 cgiCopyTemplateLang("printer-deleted.tmpl");
1785 * 'do_export()' - Export printers to Samba...
1789 do_export(http_t
*http
) /* I - HTTP connection */
1791 int i
, j
; /* Looping vars */
1792 ipp_t
*request
, /* IPP request */
1793 *response
; /* IPP response */
1794 const char *username
, /* Samba username */
1795 *password
, /* Samba password */
1796 *export_all
; /* Export all printers? */
1797 int export_count
, /* Number of printers to export */
1798 printer_count
; /* Number of available printers */
1799 const char *name
, /* What name to pull */
1800 *dest
; /* Current destination */
1801 char ppd
[1024]; /* PPD file */
1808 username
= cgiGetVariable("USERNAME");
1809 password
= cgiGetVariable("PASSWORD");
1810 export_all
= cgiGetVariable("EXPORT_ALL");
1811 export_count
= cgiGetSize("EXPORT_NAME");
1814 * Get list of available printers...
1817 cgiSetSize("PRINTER_NAME", 0);
1818 cgiSetSize("PRINTER_EXPORT", 0);
1820 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1822 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1825 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1826 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
1827 CUPS_PRINTER_IMPLICIT
);
1829 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1830 "requested-attributes", NULL
, "printer-name");
1832 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1834 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1835 ippDelete(response
);
1839 printer_count
= cgiGetSize("PRINTER_NAME");
1841 for (i
= 0; i
< printer_count
; i
++)
1843 dest
= cgiGetArray("PRINTER_NAME", i
);
1845 for (j
= 0; j
< export_count
; j
++)
1846 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
1849 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
1855 * Export or get the printers to export...
1858 if (username
&& *username
&& password
&& *password
&&
1859 (export_all
|| export_count
> 0))
1865 fputs("DEBUG: Export printers...\n", stderr
);
1869 name
= "PRINTER_NAME";
1870 export_count
= cgiGetSize("PRINTER_NAME");
1873 name
= "EXPORT_NAME";
1875 for (i
= 0; i
< export_count
; i
++)
1877 dest
= cgiGetArray(name
, i
);
1879 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
1882 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
1891 if (i
< export_count
)
1892 cgiSetVariable("ERROR", cupsLastErrorString());
1895 cgiStartHTML(cgiText(_("Export Printers to Samba")));
1896 cgiCopyTemplateLang("samba-exported.tmpl");
1901 else if (username
&& !*username
)
1902 cgiSetVariable("ERROR",
1903 cgiText(_("A Samba username is required to export "
1904 "printer drivers!")));
1905 else if (username
&& (!password
|| !*password
))
1906 cgiSetVariable("ERROR",
1907 cgiText(_("A Samba password is required to export "
1908 "printer drivers!")));
1914 cgiStartHTML(cgiText(_("Export Printers to Samba")));
1915 cgiCopyTemplateLang("samba-export.tmpl");
1921 * 'do_list_printers()' - List available printers...
1925 do_list_printers(http_t
*http
) /* I - HTTP connection */
1927 ipp_t
*request
, /* IPP request */
1928 *response
; /* IPP response */
1929 ipp_attribute_t
*attr
; /* IPP attribute */
1932 cgiStartHTML(cgiText(_("List Available Printers")));
1936 * Get the list of printers and their devices...
1939 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1941 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1942 "requested-attributes", NULL
, "device-uri");
1944 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
1945 CUPS_PRINTER_LOCAL
);
1946 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
1947 CUPS_PRINTER_LOCAL
);
1949 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1952 * Got the printer list, now load the devices...
1955 int i
; /* Looping var */
1956 cups_array_t
*printer_devices
; /* Printer devices for local printers */
1957 char *printer_device
; /* Current printer device */
1961 * Allocate an array and copy the device strings...
1964 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
1966 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
1968 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
1970 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
1974 * Free the printer list and get the device list...
1977 ippDelete(response
);
1979 request
= ippNewRequest(CUPS_GET_DEVICES
);
1981 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1984 * Got the device list, let's parse it...
1987 const char *device_uri
, /* device-uri attribute value */
1988 *device_make_and_model
, /* device-make-and-model value */
1989 *device_info
; /* device-info value */
1992 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
1995 * Skip leading attributes until we hit a device...
1998 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2005 * Pull the needed attributes from this device...
2009 device_make_and_model
= NULL
;
2012 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2014 if (!strcmp(attr
->name
, "device-info") &&
2015 attr
->value_tag
== IPP_TAG_TEXT
)
2016 device_info
= attr
->values
[0].string
.text
;
2018 if (!strcmp(attr
->name
, "device-make-and-model") &&
2019 attr
->value_tag
== IPP_TAG_TEXT
)
2020 device_make_and_model
= attr
->values
[0].string
.text
;
2022 if (!strcmp(attr
->name
, "device-uri") &&
2023 attr
->value_tag
== IPP_TAG_URI
)
2024 device_uri
= attr
->values
[0].string
.text
;
2030 * See if we have everything needed...
2033 if (device_info
&& device_make_and_model
&& device_uri
&&
2034 strcasecmp(device_make_and_model
, "unknown") &&
2035 strchr(device_uri
, ':'))
2038 * Yes, now see if there is already a printer for this
2042 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2045 * Not found, so it must be a new printer...
2048 char options
[1024], /* Form variables for this device */
2049 *options_ptr
; /* Pointer into string */
2050 const char *ptr
; /* Pointer into device string */
2054 * Format the printer name variable for this device...
2056 * We use the device-info string first, then device-uri,
2057 * and finally device-make-and-model to come up with a
2061 strcpy(options
, "TEMPLATE_NAME=");
2062 options_ptr
= options
+ strlen(options
);
2064 if (strncasecmp(device_info
, "unknown", 7))
2066 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2069 ptr
= device_make_and_model
;
2072 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2074 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2076 *options_ptr
++ = *ptr
;
2077 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2078 *options_ptr
++ = '_';
2079 else if (*ptr
== '?' || *ptr
== '(')
2083 * Then add the make and model in the printer info, so
2084 * that MacOS clients see something reasonable...
2087 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2089 sizeof(options
) - (options_ptr
- options
));
2090 options_ptr
+= strlen(options_ptr
);
2092 cgiFormEncode(options_ptr
, device_make_and_model
,
2093 sizeof(options
) - (options_ptr
- options
));
2094 options_ptr
+= strlen(options_ptr
);
2097 * Then copy the device URI...
2100 strlcpy(options_ptr
, "&DEVICE_URI=",
2101 sizeof(options
) - (options_ptr
- options
));
2102 options_ptr
+= strlen(options_ptr
);
2104 cgiFormEncode(options_ptr
, device_uri
,
2105 sizeof(options
) - (options_ptr
- options
));
2106 options_ptr
+= strlen(options_ptr
);
2108 if (options_ptr
< (options
+ sizeof(options
) - 1))
2110 *options_ptr
++ = '|';
2111 cgiFormEncode(options_ptr
, device_make_and_model
,
2112 sizeof(options
) - (options_ptr
- options
));
2116 * Finally, set the form variables for this printer...
2119 cgiSetArray("device_info", i
, device_info
);
2120 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2121 cgiSetArray("device_options", i
, options
);
2122 cgiSetArray("device_uri", i
, device_uri
);
2131 ippDelete(response
);
2134 * Free the device list...
2137 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2139 printer_device
= (char *)cupsArrayNext(printer_devices
))
2140 free(printer_device
);
2142 cupsArrayDelete(printer_devices
);
2147 * Finally, show the printer list...
2150 cgiCopyTemplateLang("list-available-printers.tmpl");
2157 * 'do_menu()' - Show the main menu...
2161 do_menu(http_t
*http
) /* I - HTTP connection */
2163 int num_settings
; /* Number of server settings */
2164 cups_option_t
*settings
; /* Server settings */
2165 const char *val
; /* Setting value */
2166 char filename
[1024]; /* Temporary filename */
2167 const char *datadir
; /* Location of data files */
2168 ipp_t
*request
, /* IPP request */
2169 *response
; /* IPP response */
2173 * Get the current server settings...
2176 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2178 cgiSetVariable("SETTINGS_MESSAGE",
2179 cgiText(_("Unable to open cupsd.conf file:")));
2180 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2183 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2184 settings
)) != NULL
&& atoi(val
))
2185 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2187 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2188 settings
)) != NULL
&& atoi(val
))
2189 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2191 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2192 settings
)) != NULL
&& atoi(val
))
2193 cgiSetVariable("REMOTE_ANY", "CHECKED");
2195 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2196 settings
)) != NULL
&& atoi(val
))
2197 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2199 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2200 settings
)) != NULL
&& atoi(val
))
2201 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2203 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2204 settings
)) != NULL
&& atoi(val
))
2205 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2208 cgiSetVariable("HAVE_GSSAPI", "1");
2210 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2211 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2212 cgiSetVariable("KERBEROS", "CHECKED");
2213 #endif /* HAVE_GSSAPI */
2215 cupsFreeOptions(num_settings
, settings
);
2218 * See if Samba and the Windows drivers are installed...
2221 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2222 datadir
= CUPS_DATADIR
;
2224 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2225 if (!access(filename
, R_OK
))
2228 * Found Windows 2000 driver file, see if we have smbclient and
2232 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2233 sizeof(filename
)) &&
2234 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2236 cgiSetVariable("HAVE_SAMBA", "Y");
2239 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2241 fputs("ERROR: smbclient not found!\n", stderr
);
2243 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2245 fputs("ERROR: rpcclient not found!\n", stderr
);
2255 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2257 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2258 NULL
, "ipp://localhost/");
2260 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2262 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2263 ippDelete(response
);
2267 * Finally, show the main menu template...
2270 cgiStartHTML(cgiText(_("Administration")));
2272 cgiCopyTemplateLang("admin.tmpl");
2279 * 'do_printer_op()' - Do a printer operation.
2283 do_printer_op(http_t
*http
, /* I - HTTP connection */
2284 ipp_op_t op
, /* I - Operation to perform */
2285 const char *title
) /* I - Title of page */
2287 ipp_t
*request
; /* IPP request */
2288 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2289 const char *printer
, /* Printer name (purge-jobs) */
2290 *is_class
; /* Is a class? */
2293 is_class
= cgiGetVariable("IS_CLASS");
2294 printer
= cgiGetVariable("PRINTER_NAME");
2298 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2299 cgiStartHTML(title
);
2300 cgiCopyTemplateLang("error.tmpl");
2306 * Build a printer request, which requires the following
2309 * attributes-charset
2310 * attributes-natural-language
2314 request
= ippNewRequest(op
);
2316 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2317 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2319 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2323 * Do the request and get back a response...
2326 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2328 if (cupsLastError() > IPP_OK_CONFLICT
)
2330 cgiStartHTML(title
);
2331 cgiShowIPPError(_("Unable to change printer:"));
2336 * Redirect successful updates back to the printer page...
2339 char url
[1024], /* Printer/class URL */
2340 refresh
[1024]; /* Refresh URL */
2343 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2344 cgiFormEncode(uri
, url
, sizeof(uri
));
2345 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2346 cgiSetVariable("refresh_page", refresh
);
2348 cgiStartHTML(title
);
2350 if (op
== IPP_PAUSE_PRINTER
)
2351 cgiCopyTemplateLang("printer-stop.tmpl");
2352 else if (op
== IPP_RESUME_PRINTER
)
2353 cgiCopyTemplateLang("printer-start.tmpl");
2354 else if (op
== CUPS_ACCEPT_JOBS
)
2355 cgiCopyTemplateLang("printer-accept.tmpl");
2356 else if (op
== CUPS_REJECT_JOBS
)
2357 cgiCopyTemplateLang("printer-reject.tmpl");
2358 else if (op
== IPP_PURGE_JOBS
)
2359 cgiCopyTemplateLang("printer-purge.tmpl");
2360 else if (op
== CUPS_SET_DEFAULT
)
2361 cgiCopyTemplateLang("printer-default.tmpl");
2369 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2373 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2375 int i
; /* Looping var */
2376 ipp_t
*request
, /* IPP request */
2377 *response
; /* IPP response */
2378 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2379 const char *printer
, /* Printer name (purge-jobs) */
2380 *is_class
, /* Is a class? */
2381 *users
, /* List of users or groups */
2382 *type
; /* Allow/deny type */
2383 int num_users
; /* Number of users */
2384 char *ptr
, /* Pointer into users string */
2385 *end
, /* Pointer to end of users string */
2386 quote
; /* Quote character */
2387 ipp_attribute_t
*attr
; /* Attribute */
2388 static const char * const attrs
[] = /* Requested attributes */
2390 "requesting-user-name-allowed",
2391 "requesting-user-name-denied"
2395 is_class
= cgiGetVariable("IS_CLASS");
2396 printer
= cgiGetVariable("PRINTER_NAME");
2400 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2401 cgiStartHTML(cgiText(_("Set Allowed Users")));
2402 cgiCopyTemplateLang("error.tmpl");
2407 users
= cgiGetVariable("users");
2408 type
= cgiGetVariable("type");
2410 if (!users
|| !type
||
2411 (strcmp(type
, "requesting-user-name-allowed") &&
2412 strcmp(type
, "requesting-user-name-denied")))
2415 * Build a Get-Printer-Attributes request, which requires the following
2418 * attributes-charset
2419 * attributes-natural-language
2421 * requested-attributes
2424 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2426 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2427 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2429 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2432 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2433 "requested-attributes",
2434 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2437 * Do the request and get back a response...
2440 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2442 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2444 ippDelete(response
);
2447 cgiStartHTML(cgiText(_("Set Allowed Users")));
2449 if (cupsLastError() > IPP_OK_CONFLICT
)
2450 cgiShowIPPError(_("Unable to get printer attributes:"));
2452 cgiCopyTemplateLang("users.tmpl");
2459 * Save the changes...
2462 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2465 * Skip whitespace and commas...
2468 while (*ptr
== ',' || isspace(*ptr
& 255))
2471 if (*ptr
== '\'' || *ptr
== '\"')
2474 * Scan quoted name...
2479 for (end
= ptr
; *end
; end
++)
2486 * Scan space or comma-delimited name...
2489 for (end
= ptr
; *end
; end
++)
2490 if (isspace(*end
& 255) || *end
== ',')
2495 * Advance to the next name...
2502 * Build a CUPS-Add-Printer/Class request, which requires the following
2505 * attributes-charset
2506 * attributes-natural-language
2508 * requesting-user-name-{allowed,denied}
2511 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2513 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2514 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2516 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2520 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2521 "requesting-user-name-allowed", NULL
, "all");
2524 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2525 type
, num_users
, NULL
, NULL
);
2527 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2530 * Skip whitespace and commas...
2533 while (*ptr
== ',' || isspace(*ptr
& 255))
2536 if (*ptr
== '\'' || *ptr
== '\"')
2539 * Scan quoted name...
2544 for (end
= ptr
; *end
; end
++)
2551 * Scan space or comma-delimited name...
2554 for (end
= ptr
; *end
; end
++)
2555 if (isspace(*end
& 255) || *end
== ',')
2560 * Terminate the name...
2570 attr
->values
[i
].string
.text
= strdup(ptr
);
2573 * Advance to the next name...
2581 * Do the request and get back a response...
2584 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2586 if (cupsLastError() > IPP_OK_CONFLICT
)
2588 cgiStartHTML(cgiText(_("Set Allowed Users")));
2589 cgiShowIPPError(_("Unable to change printer:"));
2594 * Redirect successful updates back to the printer page...
2597 char url
[1024], /* Printer/class URL */
2598 refresh
[1024]; /* Refresh URL */
2601 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2602 cgiFormEncode(uri
, url
, sizeof(uri
));
2603 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2605 cgiSetVariable("refresh_page", refresh
);
2607 cgiStartHTML(cgiText(_("Set Allowed Users")));
2609 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2610 "printer-modified.tmpl");
2619 * 'do_set_options()' - Configure the default options for a queue.
2623 do_set_options(http_t
*http
, /* I - HTTP connection */
2624 int is_class
) /* I - Set options for class? */
2626 int i
, j
, k
, m
; /* Looping vars */
2627 int have_options
; /* Have options? */
2628 ipp_t
*request
, /* IPP request */
2629 *response
; /* IPP response */
2630 ipp_attribute_t
*attr
; /* IPP attribute */
2631 char uri
[HTTP_MAX_URI
]; /* Job URI */
2632 const char *var
; /* Variable value */
2633 const char *printer
; /* Printer printer name */
2634 const char *filename
; /* PPD filename */
2635 char tempfile
[1024]; /* Temporary filename */
2636 cups_file_t
*in
, /* Input file */
2637 *out
; /* Output file */
2638 char line
[1024]; /* Line from PPD file */
2639 char keyword
[1024], /* Keyword from Default line */
2640 *keyptr
; /* Pointer into keyword... */
2641 ppd_file_t
*ppd
; /* PPD file */
2642 ppd_group_t
*group
; /* Option group */
2643 ppd_option_t
*option
; /* Option */
2644 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
2645 const char *title
; /* Page title */
2648 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2650 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2654 * Get the printer name...
2657 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2658 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2659 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2663 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2664 cgiStartHTML(title
);
2665 cgiCopyTemplateLang("error.tmpl");
2670 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2673 * Get the PPD file...
2679 filename
= cupsGetPPD2(http
, printer
);
2683 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2685 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2687 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2688 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2689 cgiStartHTML(title
);
2690 cgiCopyTemplateLang("error.tmpl");
2697 fputs("DEBUG: No PPD file\n", stderr
);
2701 if (cgiGetVariable("job_sheets_start") != NULL
||
2702 cgiGetVariable("job_sheets_end") != NULL
)
2709 ppdMarkDefaults(ppd
);
2711 DEBUG_printf(("<P>ppd->num_groups = %d\n"
2712 "<UL>\n", ppd
->num_groups
));
2714 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2716 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
2718 for (j
= group
->num_options
, option
= group
->options
;
2721 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2723 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
2725 ppdMarkOption(ppd
, option
->keyword
, var
);
2729 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
2732 DEBUG_puts("</UL></LI>");
2735 DEBUG_printf(("</UL>\n"
2736 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
2739 if (!have_options
|| ppdConflicts(ppd
))
2742 * Show the options to the user...
2745 fputs("DEBUG: Showing options...\n", stderr
);
2747 cgiStartHTML(cgiText(_("Set Printer Options")));
2748 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2754 if (ppdConflicts(ppd
))
2756 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
2759 for (j
= group
->num_options
, option
= group
->options
;
2762 if (option
->conflicted
)
2764 cgiSetArray("ckeyword", k
, option
->keyword
);
2765 cgiSetArray("ckeytext", k
, option
->text
);
2769 cgiCopyTemplateLang("option-conflict.tmpl");
2772 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2776 if (!strcmp(group
->name
, "InstallableOptions"))
2777 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2779 cgiSetVariable("GROUP", group
->text
);
2781 cgiCopyTemplateLang("option-header.tmpl");
2783 for (j
= group
->num_options
, option
= group
->options
;
2787 if (!strcmp(option
->keyword
, "PageRegion"))
2790 cgiSetVariable("KEYWORD", option
->keyword
);
2791 cgiSetVariable("KEYTEXT", option
->text
);
2793 if (option
->conflicted
)
2794 cgiSetVariable("CONFLICTED", "1");
2796 cgiSetVariable("CONFLICTED", "0");
2798 cgiSetSize("CHOICES", 0);
2799 cgiSetSize("TEXT", 0);
2800 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
2803 * Hide custom option values...
2806 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
2809 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
2810 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
2814 if (option
->choices
[k
].marked
)
2815 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
2820 case PPD_UI_BOOLEAN
:
2821 cgiCopyTemplateLang("option-boolean.tmpl");
2823 case PPD_UI_PICKONE
:
2824 cgiCopyTemplateLang("option-pickone.tmpl");
2826 case PPD_UI_PICKMANY
:
2827 cgiCopyTemplateLang("option-pickmany.tmpl");
2832 cgiCopyTemplateLang("option-trailer.tmpl");
2837 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
2838 * following attributes:
2840 * attributes-charset
2841 * attributes-natural-language
2845 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2847 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2848 "localhost", 0, "/printers/%s", printer
);
2849 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2853 * Do the request and get back a response...
2856 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2858 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
2859 IPP_TAG_ZERO
)) != NULL
)
2862 * Add the job sheets options...
2865 cgiSetVariable("GROUP", cgiText(_("Banners")));
2866 cgiCopyTemplateLang("option-header.tmpl");
2868 cgiSetSize("CHOICES", attr
->num_values
);
2869 cgiSetSize("TEXT", attr
->num_values
);
2870 for (k
= 0; k
< attr
->num_values
; k
++)
2872 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
2873 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
2876 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
2878 cgiSetVariable("KEYWORD", "job_sheets_start");
2879 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
2880 cgiSetVariable("DEFCHOICE", attr
== NULL
?
2881 "" : attr
->values
[0].string
.text
);
2883 cgiCopyTemplateLang("option-pickone.tmpl");
2885 cgiSetVariable("KEYWORD", "job_sheets_end");
2886 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
2887 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
2888 "" : attr
->values
[1].string
.text
);
2890 cgiCopyTemplateLang("option-pickone.tmpl");
2892 cgiCopyTemplateLang("option-trailer.tmpl");
2895 if (ippFindAttribute(response
, "printer-error-policy-supported",
2897 ippFindAttribute(response
, "printer-op-policy-supported",
2901 * Add the error and operation policy options...
2904 cgiSetVariable("GROUP", cgiText(_("Policies")));
2905 cgiCopyTemplateLang("option-header.tmpl");
2911 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
2916 cgiSetSize("CHOICES", attr
->num_values
);
2917 cgiSetSize("TEXT", attr
->num_values
);
2918 for (k
= 0; k
< attr
->num_values
; k
++)
2920 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
2921 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
2924 attr
= ippFindAttribute(response
, "printer-error-policy",
2927 cgiSetVariable("KEYWORD", "printer_error_policy");
2928 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
2929 cgiSetVariable("DEFCHOICE", attr
== NULL
?
2930 "" : attr
->values
[0].string
.text
);
2933 cgiCopyTemplateLang("option-pickone.tmpl");
2936 * Operation policy...
2939 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
2944 cgiSetSize("CHOICES", attr
->num_values
);
2945 cgiSetSize("TEXT", attr
->num_values
);
2946 for (k
= 0; k
< attr
->num_values
; k
++)
2948 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
2949 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
2952 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
2954 cgiSetVariable("KEYWORD", "printer_op_policy");
2955 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
2956 cgiSetVariable("DEFCHOICE", attr
== NULL
?
2957 "" : attr
->values
[0].string
.text
);
2959 cgiCopyTemplateLang("option-pickone.tmpl");
2962 cgiCopyTemplateLang("option-trailer.tmpl");
2965 ippDelete(response
);
2969 * Binary protocol support...
2972 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
2974 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
2976 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
2977 cgiCopyTemplateLang("option-header.tmpl");
2979 cgiSetSize("CHOICES", 2);
2980 cgiSetSize("TEXT", 2);
2981 cgiSetArray("CHOICES", 0, "None");
2982 cgiSetArray("TEXT", 0, cgiText(_("None")));
2984 if (strstr(ppd
->protocols
, "TBCP"))
2986 cgiSetArray("CHOICES", 1, "TBCP");
2987 cgiSetArray("TEXT", 1, "TBCP");
2991 cgiSetArray("CHOICES", 1, "BCP");
2992 cgiSetArray("TEXT", 1, "BCP");
2995 cgiSetVariable("KEYWORD", "protocol");
2996 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
2997 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
2999 cgiCopyTemplateLang("option-pickone.tmpl");
3001 cgiCopyTemplateLang("option-trailer.tmpl");
3004 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3010 * Set default options...
3013 fputs("DEBUG: Setting options...\n", stderr
);
3017 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3018 in
= cupsFileOpen(filename
, "r");
3022 cgiSetVariable("ERROR", strerror(errno
));
3023 cgiStartHTML(cgiText(_("Set Printer Options")));
3024 cgiCopyTemplateLang("error.tmpl");
3040 while (cupsFileGets(in
, line
, sizeof(line
)))
3042 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3044 else if (strncmp(line
, "*Default", 8))
3045 cupsFilePrintf(out
, "%s\n", line
);
3049 * Get default option name...
3052 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3054 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3055 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3060 if (!strcmp(keyword
, "PageRegion") ||
3061 !strcmp(keyword
, "PaperDimension") ||
3062 !strcmp(keyword
, "ImageableArea"))
3063 var
= cgiGetVariable("PageSize");
3065 var
= cgiGetVariable(keyword
);
3068 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3070 cupsFilePrintf(out
, "%s\n", line
);
3074 if ((var
= cgiGetVariable("protocol")) != NULL
)
3075 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
3083 * Make sure temporary filename is cleared when there is no PPD...
3090 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3091 * following attributes:
3093 * attributes-charset
3094 * attributes-natural-language
3096 * job-sheets-default
3097 * printer-error-policy
3102 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3103 CUPS_ADD_MODIFY_PRINTER
);
3105 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3108 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3109 "job-sheets-default", 2, NULL
, NULL
);
3110 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3111 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3113 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3114 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3115 "printer-error-policy", NULL
, var
);
3117 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3118 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3119 "printer-op-policy", NULL
, var
);
3122 * Do the request and get back a response...
3126 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3128 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3130 if (cupsLastError() > IPP_OK_CONFLICT
)
3132 cgiStartHTML(title
);
3133 cgiShowIPPError(_("Unable to set options:"));
3138 * Redirect successful updates back to the printer page...
3141 char refresh
[1024]; /* Refresh URL */
3144 cgiFormEncode(uri
, printer
, sizeof(uri
));
3145 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3146 is_class
? "classes" : "printers", uri
);
3147 cgiSetVariable("refresh_page", refresh
);
3149 cgiStartHTML(title
);
3151 cgiCopyTemplateLang("printer-configured.tmpl");
3166 * 'do_set_sharing()' - Set printer-is-shared value...
3170 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3172 ipp_t
*request
, /* IPP request */
3173 *response
; /* IPP response */
3174 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3175 const char *printer
, /* Printer name */
3176 *is_class
, /* Is a class? */
3177 *shared
; /* Sharing value */
3180 is_class
= cgiGetVariable("IS_CLASS");
3181 printer
= cgiGetVariable("PRINTER_NAME");
3182 shared
= cgiGetVariable("SHARED");
3184 if (!printer
|| !shared
)
3186 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3187 cgiStartHTML(cgiText(_("Set Publishing")));
3188 cgiCopyTemplateLang("error.tmpl");
3194 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3195 * following attributes:
3197 * attributes-charset
3198 * attributes-natural-language
3203 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3205 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3206 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3208 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3211 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3214 * Do the request and get back a response...
3217 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3219 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3221 ippDelete(response
);
3224 if (cupsLastError() > IPP_OK_CONFLICT
)
3226 cgiStartHTML(cgiText(_("Set Publishing")));
3227 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3232 * Redirect successful updates back to the printer page...
3235 char url
[1024], /* Printer/class URL */
3236 refresh
[1024]; /* Refresh URL */
3239 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3240 cgiFormEncode(uri
, url
, sizeof(uri
));
3241 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3242 cgiSetVariable("refresh_page", refresh
);
3244 cgiStartHTML(cgiText(_("Set Publishing")));
3245 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3246 "printer-modified.tmpl");
3254 * 'match_string()' - Return the number of matching characters.
3257 static int /* O - Number of matching characters */
3258 match_string(const char *a
, /* I - First string */
3259 const char *b
) /* I - Second string */
3261 int count
; /* Number of matching characters */
3265 * Loop through both strings until we hit the end of either or we find
3266 * a non-matching character. For the purposes of comparison, we ignore
3267 * whitespace and do a case-insensitive comparison so that we have a
3268 * better chance of finding a match...
3271 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
3274 * Skip leading whitespace characters...
3277 while (isspace(*a
& 255))
3280 while (isspace(*b
& 255))
3284 * Break out if we run out of characters...
3291 * Do a case-insensitive comparison of the next two chars...
3294 if (tolower(*a
& 255) != tolower(*b
& 255))
3303 * End of "$Id: admin.c 6649 2007-07-11 21:46:42Z mike $".