2 * "$Id: admin.c 6733 2007-07-26 18:09:46Z 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
, "find-new-printers") ||
169 !strcmp(op
, "list-available-printers"))
170 do_list_printers(http
);
171 else if (!strcmp(op
, "add-class"))
172 do_am_class(http
, 0);
173 else if (!strcmp(op
, "add-printer"))
174 do_am_printer(http
, 0);
175 else if (!strcmp(op
, "modify-class"))
176 do_am_class(http
, 1);
177 else if (!strcmp(op
, "modify-printer"))
178 do_am_printer(http
, 1);
179 else if (!strcmp(op
, "delete-class"))
180 do_delete_class(http
);
181 else if (!strcmp(op
, "delete-printer"))
182 do_delete_printer(http
);
183 else if (!strcmp(op
, "set-class-options"))
184 do_set_options(http
, 1);
185 else if (!strcmp(op
, "set-printer-options"))
186 do_set_options(http
, 0);
187 else if (!strcmp(op
, "config-server"))
188 do_config_server(http
);
189 else if (!strcmp(op
, "export-samba"))
191 else if (!strcmp(op
, "add-rss-subscription"))
192 do_add_rss_subscription(http
);
193 else if (!strcmp(op
, "cancel-subscription"))
194 do_cancel_subscription(http
);
198 * Bad operation code... Display an error...
201 cgiStartHTML(cgiText(_("Administration")));
202 cgiCopyTemplateLang("error-op.tmpl");
209 * Form data but no operation code... Display an error...
212 cgiStartHTML(cgiText(_("Administration")));
213 cgiCopyTemplateLang("error-op.tmpl");
218 * Close the HTTP server connection...
224 * Return with no errors...
232 * 'do_add_rss_subscription()' - Add a RSS subscription.
236 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
238 ipp_t
*request
, /* IPP request data */
239 *response
; /* IPP response data */
240 char rss_uri
[1024]; /* RSS notify-recipient URI */
241 int num_events
; /* Number of events */
242 const char *events
[12], /* Subscribed events */
243 *subscription_name
, /* Subscription name */
244 *printer_uri
, /* Printer URI */
245 *ptr
, /* Pointer into name */
246 *user
; /* Username */
247 int max_events
; /* Maximum number of events */
251 * See if we have all of the required information...
254 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
255 printer_uri
= cgiGetVariable("PRINTER_URI");
258 if (cgiGetVariable("EVENT_JOB_CREATED"))
259 events
[num_events
++] = "job-created";
260 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
261 events
[num_events
++] = "job-completed";
262 if (cgiGetVariable("EVENT_JOB_STOPPED"))
263 events
[num_events
++] = "job-stopped";
264 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
265 events
[num_events
++] = "job-config-changed";
266 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
267 events
[num_events
++] = "printer-stopped";
268 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
269 events
[num_events
++] = "printer-added";
270 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
271 events
[num_events
++] = "printer-modified";
272 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
273 events
[num_events
++] = "printer-deleted";
274 if (cgiGetVariable("EVENT_SERVER_STARTED"))
275 events
[num_events
++] = "server-started";
276 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
277 events
[num_events
++] = "server-stopped";
278 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
279 events
[num_events
++] = "server-restarted";
280 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
281 events
[num_events
++] = "server-audit";
283 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
284 max_events
= atoi(ptr
);
288 if (!subscription_name
|| !printer_uri
|| !num_events
||
289 max_events
<= 0 || max_events
> 9999)
292 * Don't have everything we need, so get the available printers
293 * and classes and (re)show the add page...
296 request
= ippNewRequest(CUPS_GET_PRINTERS
);
297 response
= cupsDoRequest(http
, request
, "/");
299 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
303 cgiStartHTML(cgiText(_("Add RSS Subscription")));
305 cgiCopyTemplateLang("add-rss-subscription.tmpl");
312 * Validate the subscription name...
315 for (ptr
= subscription_name
; *ptr
; ptr
++)
316 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
317 *ptr
== '?' || *ptr
== '#')
322 cgiSetVariable("ERROR",
323 cgiText(_("The subscription name may not "
324 "contain spaces, slashes (/), question marks (?), "
325 "or the pound sign (#).")));
326 cgiStartHTML(_("Add RSS Subscription"));
327 cgiCopyTemplateLang("error.tmpl");
333 * Add the subscription...
336 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
337 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
338 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
339 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
342 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
343 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
346 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
348 if (!strcasecmp(printer_uri
, "#ALL#"))
349 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
350 NULL
, "ipp://localhost/");
352 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
355 if ((user
= getenv("REMOTE_USER")) == NULL
)
358 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
361 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
362 "notify-recipient-uri", NULL
, rss_uri
);
363 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
364 num_events
, NULL
, events
);
365 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
366 "notify-lease-duration", 0);
368 ippDelete(cupsDoRequest(http
, request
, "/"));
370 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
372 puts("Status: 401\n");
375 else if (cupsLastError() > IPP_OK_CONFLICT
)
377 cgiStartHTML(_("Add RSS Subscription"));
378 cgiShowIPPError(_("Unable to add RSS subscription:"));
383 * Redirect successful updates back to the admin page...
386 cgiSetVariable("refresh_page", "5;URL=/admin");
387 cgiStartHTML(_("Add RSS Subscription"));
388 cgiCopyTemplateLang("subscription-added.tmpl");
396 * 'do_am_class()' - Add or modify a class.
400 do_am_class(http_t
*http
, /* I - HTTP connection */
401 int modify
) /* I - Modify the printer? */
403 int i
, j
; /* Looping vars */
404 int element
; /* Element number */
405 int num_printers
; /* Number of printers */
406 ipp_t
*request
, /* IPP request */
407 *response
; /* IPP response */
408 ipp_attribute_t
*attr
; /* member-uris attribute */
409 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
410 const char *name
, /* Pointer to class name */
411 *ptr
; /* Pointer to CGI variable */
412 const char *title
; /* Title of page */
413 static const char * const pattrs
[] = /* Requested printer attributes */
421 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
422 name
= cgiGetVariable("PRINTER_NAME");
424 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
427 * Build a CUPS_GET_PRINTERS request, which requires the
428 * following attributes:
431 * attributes-natural-language
434 request
= ippNewRequest(CUPS_GET_PRINTERS
);
437 * Do the request and get back a response...
440 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
443 * Create MEMBER_URIS and MEMBER_NAMES arrays...
446 for (element
= 0, attr
= response
->attrs
;
449 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
451 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
452 (!name
|| strcasecmp(name
, ptr
+ 1)))
455 * Don't show the current class...
458 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
463 for (element
= 0, attr
= response
->attrs
;
466 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
468 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
471 * Don't show the current class...
474 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
479 num_printers
= cgiGetSize("MEMBER_URIS");
489 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
490 * following attributes:
493 * attributes-natural-language
497 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
499 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
500 "localhost", 0, "/classes/%s", name
);
501 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
504 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
505 "requested-attributes",
506 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
510 * Do the request and get back a response...
513 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
515 if ((attr
= ippFindAttribute(response
, "member-names",
516 IPP_TAG_NAME
)) != NULL
)
519 * Mark any current members in the class...
522 for (j
= 0; j
< num_printers
; j
++)
523 cgiSetArray("MEMBER_SELECTED", j
, "");
525 for (i
= 0; i
< attr
->num_values
; i
++)
527 for (j
= 0; j
< num_printers
; j
++)
529 if (!strcasecmp(attr
->values
[i
].string
.text
,
530 cgiGetArray("MEMBER_NAMES", j
)))
532 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
539 if ((attr
= ippFindAttribute(response
, "printer-info",
540 IPP_TAG_TEXT
)) != NULL
)
541 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
543 if ((attr
= ippFindAttribute(response
, "printer-location",
544 IPP_TAG_TEXT
)) != NULL
)
545 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
551 * Update the location and description of an existing printer...
555 cgiCopyTemplateLang("modify-class.tmpl");
560 * Get the name, location, and description for a new printer...
564 cgiCopyTemplateLang("add-class.tmpl");
572 for (ptr
= name
; *ptr
; ptr
++)
573 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
576 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
578 cgiSetVariable("ERROR",
579 cgiText(_("The class name may only contain up to "
580 "127 printable characters and may not "
581 "contain spaces, slashes (/), or the "
582 "pound sign (#).")));
584 cgiCopyTemplateLang("error.tmpl");
590 * Build a CUPS_ADD_CLASS request, which requires the following
594 * attributes-natural-language
598 * printer-is-accepting-jobs
603 request
= ippNewRequest(CUPS_ADD_CLASS
);
605 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
606 "localhost", 0, "/classes/%s",
607 cgiGetVariable("PRINTER_NAME"));
608 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
611 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
612 NULL
, cgiGetVariable("PRINTER_LOCATION"));
614 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
615 NULL
, cgiGetVariable("PRINTER_INFO"));
617 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
619 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
622 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
624 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
625 num_printers
, NULL
, NULL
);
626 for (i
= 0; i
< num_printers
; i
++)
627 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
631 * Do the request and get back a response...
634 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
636 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
638 puts("Status: 401\n");
641 else if (cupsLastError() > IPP_OK_CONFLICT
)
644 cgiShowIPPError(modify
? _("Unable to modify class:") :
645 _("Unable to add class:"));
650 * Redirect successful updates back to the class page...
653 char refresh
[1024]; /* Refresh URL */
655 cgiFormEncode(uri
, name
, sizeof(uri
));
656 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
658 cgiSetVariable("refresh_page", refresh
);
663 cgiCopyTemplateLang("class-modified.tmpl");
665 cgiCopyTemplateLang("class-added.tmpl");
673 * 'do_am_printer()' - Add or modify a printer.
677 do_am_printer(http_t
*http
, /* I - HTTP connection */
678 int modify
) /* I - Modify the printer? */
680 int i
; /* Looping var */
681 ipp_attribute_t
*attr
; /* Current attribute */
682 ipp_t
*request
, /* IPP request */
683 *response
, /* IPP response */
684 *oldinfo
; /* Old printer information */
685 const cgi_file_t
*file
; /* Uploaded file, if any */
686 const char *var
; /* CGI variable */
687 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
688 *uriptr
; /* Pointer into URI */
689 int maxrate
; /* Maximum baud rate */
690 char baudrate
[255]; /* Baud rate string */
691 const char *name
, /* Pointer to class name */
692 *ptr
; /* Pointer to CGI variable */
693 const char *title
; /* Title of page */
694 static int baudrates
[] = /* Baud rates */
709 ptr
= cgiGetVariable("DEVICE_URI");
710 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
711 ptr
? ptr
: "(null)");
713 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
718 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
719 * following attributes:
722 * attributes-natural-language
726 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
728 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
729 "localhost", 0, "/printers/%s",
730 cgiGetVariable("PRINTER_NAME"));
731 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
735 * Do the request and get back a response...
738 oldinfo
= cupsDoRequest(http
, request
, "/");
743 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
744 cgiGetVariable("PRINTER_LOCATION") == NULL
)
751 * Update the location and description of an existing printer...
755 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
757 cgiCopyTemplateLang("modify-printer.tmpl");
762 * Get the name, location, and description for a new printer...
765 cgiCopyTemplateLang("add-printer.tmpl");
776 for (ptr
= name
; *ptr
; ptr
++)
777 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
780 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
782 cgiSetVariable("ERROR",
783 cgiText(_("The printer name may only contain up to "
784 "127 printable characters and may not "
785 "contain spaces, slashes (/), or the "
786 "pound sign (#).")));
788 cgiCopyTemplateLang("error.tmpl");
797 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
798 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
799 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
800 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
803 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
806 * Build a CUPS_GET_DEVICES request, which requires the following
810 * attributes-natural-language
814 fputs("DEBUG: Getting list of devices...\n", stderr
);
816 request
= ippNewRequest(CUPS_GET_DEVICES
);
818 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
819 NULL
, "ipp://localhost/printers/");
822 * Do the request and get back a response...
825 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
827 fputs("DEBUG: Got device list!\n", stderr
);
829 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
834 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
835 cupsLastError(), cupsLastErrorString());
838 * Let the user choose...
841 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
843 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
844 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
847 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
848 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
852 cgiCopyTemplateLang("choose-device.tmpl");
855 else if (strchr(var
, '/') == NULL
)
857 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
860 * Set the current device URI for the form to the old one...
863 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
864 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
868 * User needs to set the full URI...
872 cgiCopyTemplateLang("choose-uri.tmpl");
875 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
878 * Need baud rate, parity, etc.
881 if ((var
= strchr(var
, '?')) != NULL
&&
882 strncmp(var
, "?baud=", 6) == 0)
883 maxrate
= atoi(var
+ 6);
887 for (i
= 0; i
< 10; i
++)
888 if (baudrates
[i
] > maxrate
)
892 sprintf(baudrate
, "%d", baudrates
[i
]);
893 cgiSetArray("BAUDRATES", i
, baudrate
);
897 cgiCopyTemplateLang("choose-serial.tmpl");
900 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
905 * Get the PPD file...
908 int fd
; /* PPD file */
909 char filename
[1024]; /* PPD filename */
910 ppd_file_t
*ppd
; /* PPD information */
911 char buffer
[1024]; /* Buffer */
912 int bytes
; /* Number of bytes */
913 http_status_t get_status
; /* Status of GET */
916 /* TODO: Use cupsGetFile() API... */
917 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
919 if (httpGet(http
, uri
))
922 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
924 if (get_status
!= HTTP_OK
)
926 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
927 uri
, get_status
, httpStatus(get_status
));
929 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
931 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
932 write(fd
, buffer
, bytes
);
936 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
938 if (ppd
->manufacturer
)
939 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
942 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
949 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
950 filename
, ppdErrorString(ppdLastError(&bytes
)));
958 "ERROR: Unable to create temporary file for PPD file: %s\n",
962 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
965 * Extract make and make/model from device URI string...
968 char make
[1024], /* Make string */
969 *makeptr
; /* Pointer into make */
974 strlcpy(make
, uriptr
, sizeof(make
));
976 if ((makeptr
= strchr(make
, ' ')) != NULL
)
978 else if ((makeptr
= strchr(make
, '-')) != NULL
)
980 else if (!strncasecmp(make
, "laserjet", 8) ||
981 !strncasecmp(make
, "deskjet", 7) ||
982 !strncasecmp(make
, "designjet", 9))
984 else if (!strncasecmp(make
, "phaser", 6))
985 strcpy(make
, "Xerox");
986 else if (!strncasecmp(make
, "stylus", 6))
987 strcpy(make
, "Epson");
989 strcpy(make
, "Generic");
991 cgiSetVariable("CURRENT_MAKE", make
);
992 cgiSetVariable("PPD_MAKE", make
);
993 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
997 * Build a CUPS_GET_PPDS request, which requires the following
1000 * attributes-charset
1001 * attributes-natural-language
1005 request
= ippNewRequest(CUPS_GET_PPDS
);
1007 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1008 NULL
, "ipp://localhost/printers/");
1010 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
1011 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1012 "ppd-make", NULL
, var
);
1014 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1015 "requested-attributes", NULL
, "ppd-make");
1018 * Do the request and get back a response...
1021 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1024 * Got the list of PPDs, see if the user has selected a make...
1027 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
1030 * No PPD files with this make, try again with all makes...
1033 ippDelete(response
);
1035 request
= ippNewRequest(CUPS_GET_PPDS
);
1037 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1038 NULL
, "ipp://localhost/printers/");
1040 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1041 "requested-attributes", NULL
, "ppd-make");
1043 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1044 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1046 cgiStartHTML(title
);
1047 cgiCopyTemplateLang("choose-make.tmpl");
1052 cgiStartHTML(title
);
1053 cgiCopyTemplateLang("choose-make.tmpl");
1059 * Let the user choose a model...
1062 const char *make_model
; /* Current make/model string */
1065 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1068 * Scan for "close" matches...
1071 int match
, /* Current match */
1072 best_match
, /* Best match so far */
1073 count
; /* Number of drivers */
1074 const char *best
, /* Best matching string */
1075 *current
; /* Current string */
1078 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
1080 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
1082 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
1083 match
= match_string(make_model
, current
);
1085 if (match
> best_match
)
1092 if (best_match
> strlen(var
))
1095 * Found a match longer than the make...
1098 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
1102 cgiStartHTML(title
);
1103 cgiCopyTemplateLang("choose-model.tmpl");
1107 ippDelete(response
);
1111 cgiStartHTML(title
);
1112 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1113 cgiCopyTemplateLang("error.tmpl");
1120 * Build a CUPS_ADD_PRINTER request, which requires the following
1123 * attributes-charset
1124 * attributes-natural-language
1130 * printer-is-accepting-jobs
1134 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1136 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1137 "localhost", 0, "/printers/%s",
1138 cgiGetVariable("PRINTER_NAME"));
1139 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1142 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1143 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1145 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1146 NULL
, cgiGetVariable("PRINTER_INFO"));
1149 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1150 NULL
, cgiGetVariable("PPD_NAME"));
1152 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1155 * Strip make and model from URI...
1158 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1161 if (!strncmp(uri
, "serial:", 7))
1164 * Update serial port URI to include baud rate, etc.
1167 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1168 uriptr
= uri
+ strlen(uri
);
1170 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1171 "?baud=%s+bits=%s+parity=%s+flow=%s",
1172 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1173 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1176 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1179 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1181 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1185 * Do the request and get back a response...
1189 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1191 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1193 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1195 puts("Status: 401\n");
1198 else if (cupsLastError() > IPP_OK_CONFLICT
)
1200 cgiStartHTML(title
);
1201 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1202 _("Unable to add printer:"));
1207 * Redirect successful updates back to the printer or set-options pages...
1210 char refresh
[1024]; /* Refresh URL */
1213 cgiFormEncode(uri
, name
, sizeof(uri
));
1216 snprintf(refresh
, sizeof(refresh
),
1217 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1219 snprintf(refresh
, sizeof(refresh
),
1220 "5;URL=/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1222 cgiSetVariable("refresh_page", refresh
);
1224 cgiStartHTML(title
);
1227 cgiCopyTemplateLang("printer-modified.tmpl");
1229 cgiCopyTemplateLang("printer-added.tmpl");
1241 * 'do_cancel_subscription()' - Cancel a subscription.
1245 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1247 ipp_t
*request
; /* IPP request data */
1248 const char *var
, /* Form variable */
1249 *user
; /* Username */
1250 int id
; /* Subscription ID */
1254 * See if we have all of the required information...
1257 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1264 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1265 cgiStartHTML(_("Cancel RSS Subscription"));
1266 cgiCopyTemplateLang("error.tmpl");
1272 * Cancel the subscription...
1275 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1277 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1278 NULL
, "ipp://localhost/");
1279 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1280 "notify-subscription-id", id
);
1282 if ((user
= getenv("REMOTE_USER")) == NULL
)
1285 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1288 ippDelete(cupsDoRequest(http
, request
, "/"));
1290 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1292 puts("Status: 401\n");
1295 else if (cupsLastError() > IPP_OK_CONFLICT
)
1297 cgiStartHTML(_("Cancel RSS Subscription"));
1298 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1303 * Redirect successful updates back to the admin page...
1306 cgiSetVariable("refresh_page", "5;URL=/admin");
1307 cgiStartHTML(_("Cancel RSS Subscription"));
1308 cgiCopyTemplateLang("subscription-canceled.tmpl");
1316 * 'do_config_server()' - Configure server settings.
1320 do_config_server(http_t
*http
) /* I - HTTP connection */
1322 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1325 * Save basic setting changes...
1328 int num_settings
; /* Number of server settings */
1329 cups_option_t
*settings
; /* Server settings */
1330 const char *debug_logging
, /* DEBUG_LOGGING value */
1331 *remote_admin
, /* REMOTE_ADMIN value */
1332 *remote_any
, /* REMOTE_ANY value */
1334 /* REMOTE_PRINTERS value */
1335 *share_printers
,/* SHARE_PRINTERS value */
1338 /* DefaultAuthType value */
1339 #endif /* HAVE_GSSAPI */
1341 /* USER_CANCEL_ANY value */
1345 * Get the checkbox values from the form...
1348 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1349 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1350 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1351 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1352 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1353 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1355 default_auth_type
= cgiGetVariable("KERBEROS") ? "Negotiate" : "Basic";
1357 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1358 #endif /* HAVE_GSSAPI */
1361 * Get the current server settings...
1364 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1366 cgiStartHTML(cgiText(_("Change Settings")));
1367 cgiSetVariable("MESSAGE",
1368 cgiText(_("Unable to change server settings:")));
1369 cgiSetVariable("ERROR", cupsLastErrorString());
1370 cgiCopyTemplateLang("error.tmpl");
1376 * See if the settings have changed...
1379 if (strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1380 num_settings
, settings
)) ||
1381 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1382 num_settings
, settings
)) ||
1383 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1384 num_settings
, settings
)) ||
1385 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1386 num_settings
, settings
)) ||
1387 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1388 num_settings
, settings
)) ||
1390 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1391 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1392 num_settings
, settings
)) ||
1393 #endif /* HAVE_GSSAPI */
1394 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1395 num_settings
, settings
)))
1398 * Settings *have* changed, so save the changes...
1401 cupsFreeOptions(num_settings
, settings
);
1404 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1405 debug_logging
, num_settings
, &settings
);
1406 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1407 remote_admin
, num_settings
, &settings
);
1408 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1409 remote_any
, num_settings
, &settings
);
1410 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1411 remote_printers
, num_settings
, &settings
);
1412 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1413 share_printers
, num_settings
, &settings
);
1414 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1415 user_cancel_any
, num_settings
, &settings
);
1417 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1418 num_settings
, &settings
);
1419 #endif /* HAVE_GSSAPI */
1421 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1423 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1425 puts("Status: 401\n");
1429 cgiStartHTML(cgiText(_("Change Settings")));
1430 cgiSetVariable("MESSAGE",
1431 cgiText(_("Unable to change server settings:")));
1432 cgiSetVariable("ERROR", cupsLastErrorString());
1433 cgiCopyTemplateLang("error.tmpl");
1437 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1438 cgiStartHTML(cgiText(_("Change Settings")));
1439 cgiCopyTemplateLang("restart.tmpl");
1448 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1449 cgiStartHTML(cgiText(_("Change Settings")));
1450 cgiCopyTemplateLang("norestart.tmpl");
1453 cupsFreeOptions(num_settings
, settings
);
1457 else if (cgiIsPOST())
1460 * Save hand-edited config file...
1463 http_status_t status
; /* PUT status */
1464 char tempfile
[1024]; /* Temporary new cupsd.conf */
1465 int tempfd
; /* Temporary file descriptor */
1466 cups_file_t
*temp
; /* Temporary file */
1467 const char *start
, /* Start of line */
1468 *end
; /* End of line */
1472 * Create a temporary file for the new cupsd.conf file...
1475 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1477 cgiStartHTML(cgiText(_("Edit Configuration File")));
1478 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1479 cgiSetVariable("ERROR", strerror(errno
));
1480 cgiCopyTemplateLang("error.tmpl");
1487 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1489 cgiStartHTML(cgiText(_("Edit Configuration File")));
1490 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1491 cgiSetVariable("ERROR", strerror(errno
));
1492 cgiCopyTemplateLang("error.tmpl");
1502 * Copy the cupsd.conf text from the form variable...
1505 start
= cgiGetVariable("CUPSDCONF");
1508 if ((end
= strstr(start
, "\r\n")) == NULL
)
1509 if ((end
= strstr(start
, "\n")) == NULL
)
1510 end
= start
+ strlen(start
);
1512 cupsFileWrite(temp
, start
, end
- start
);
1513 cupsFilePutChar(temp
, '\n');
1517 else if (*end
== '\n')
1523 cupsFileClose(temp
);
1526 * Upload the configuration file to the server...
1529 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1531 if (status
== HTTP_UNAUTHORIZED
)
1533 puts("Status: 401\n");
1537 else if (status
!= HTTP_CREATED
)
1539 cgiSetVariable("MESSAGE",
1540 cgiText(_("Unable to upload cupsd.conf file:")));
1541 cgiSetVariable("ERROR", httpStatus(status
));
1543 cgiStartHTML(cgiText(_("Edit Configuration File")));
1544 cgiCopyTemplateLang("error.tmpl");
1548 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1550 cgiStartHTML(cgiText(_("Edit Configuration File")));
1551 cgiCopyTemplateLang("restart.tmpl");
1560 struct stat info
; /* cupsd.conf information */
1561 cups_file_t
*cupsd
; /* cupsd.conf file */
1562 char *buffer
, /* Buffer for entire file */
1563 *bufptr
, /* Pointer into buffer */
1564 *bufend
; /* End of buffer */
1565 int ch
; /* Character from file */
1566 char filename
[1024]; /* Filename */
1567 const char *server_root
; /* Location of config files */
1571 * Locate the cupsd.conf file...
1574 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1575 server_root
= CUPS_SERVERROOT
;
1577 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1580 * Figure out the size...
1583 if (stat(filename
, &info
))
1585 cgiStartHTML(cgiText(_("Edit Configuration File")));
1586 cgiSetVariable("MESSAGE",
1587 cgiText(_("Unable to access cupsd.conf file:")));
1588 cgiSetVariable("ERROR", strerror(errno
));
1589 cgiCopyTemplateLang("error.tmpl");
1596 if (info
.st_size
> (1024 * 1024))
1598 cgiStartHTML(cgiText(_("Edit Configuration File")));
1599 cgiSetVariable("MESSAGE",
1600 cgiText(_("Unable to access cupsd.conf file:")));
1601 cgiSetVariable("ERROR",
1602 cgiText(_("Unable to edit cupsd.conf files larger than "
1604 cgiCopyTemplateLang("error.tmpl");
1607 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1608 (long)info
.st_size
);
1613 * Open the cupsd.conf file...
1616 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1619 * Unable to open - log an error...
1622 cgiStartHTML(cgiText(_("Edit Configuration File")));
1623 cgiSetVariable("MESSAGE",
1624 cgiText(_("Unable to access cupsd.conf file:")));
1625 cgiSetVariable("ERROR", strerror(errno
));
1626 cgiCopyTemplateLang("error.tmpl");
1634 * Allocate memory and load the file into a string buffer...
1637 buffer
= calloc(1, info
.st_size
+ 1);
1639 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1640 cupsFileClose(cupsd
);
1642 cgiSetVariable("CUPSDCONF", buffer
);
1646 * Then get the default cupsd.conf file and put that into a string as
1650 strlcat(filename
, ".default", sizeof(filename
));
1652 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1653 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1655 buffer
= calloc(1, 2 * info
.st_size
+ 1);
1656 bufend
= buffer
+ 2 * info
.st_size
- 1;
1658 for (bufptr
= buffer
;
1659 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1661 if (ch
== '\\' || ch
== '\"')
1666 else if (ch
== '\n')
1671 else if (ch
== '\t')
1682 cupsFileClose(cupsd
);
1684 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1689 * Show the current config file...
1692 cgiStartHTML(cgiText(_("Edit Configuration File")));
1694 cgiCopyTemplateLang("edit-config.tmpl");
1702 * 'do_delete_class()' - Delete a class...
1706 do_delete_class(http_t
*http
) /* I - HTTP connection */
1708 ipp_t
*request
; /* IPP request */
1709 char uri
[HTTP_MAX_URI
]; /* Job URI */
1710 const char *pclass
; /* Printer class name */
1714 * Get form variables...
1717 if (cgiGetVariable("CONFIRM") == NULL
)
1719 cgiStartHTML(cgiText(_("Delete Class")));
1720 cgiCopyTemplateLang("class-confirm.tmpl");
1725 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1726 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1727 "localhost", 0, "/classes/%s", pclass
);
1730 cgiStartHTML(cgiText(_("Delete Class")));
1731 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1732 cgiCopyTemplateLang("error.tmpl");
1738 * Build a CUPS_DELETE_CLASS request, which requires the following
1741 * attributes-charset
1742 * attributes-natural-language
1746 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1748 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1752 * Do the request and get back a response...
1755 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1758 * Show the results...
1761 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1763 puts("Status: 401\n");
1766 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1769 * Redirect successful updates back to the classes page...
1772 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1775 cgiStartHTML(cgiText(_("Delete Class")));
1777 if (cupsLastError() > IPP_OK_CONFLICT
)
1778 cgiShowIPPError(_("Unable to delete class:"));
1780 cgiCopyTemplateLang("class-deleted.tmpl");
1787 * 'do_delete_printer()' - Delete a printer...
1791 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1793 ipp_t
*request
; /* IPP request */
1794 char uri
[HTTP_MAX_URI
]; /* Job URI */
1795 const char *printer
; /* Printer printer name */
1799 * Get form variables...
1802 if (cgiGetVariable("CONFIRM") == NULL
)
1804 cgiStartHTML(cgiText(_("Delete Printer")));
1805 cgiCopyTemplateLang("printer-confirm.tmpl");
1810 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1811 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1812 "localhost", 0, "/printers/%s", printer
);
1815 cgiStartHTML(cgiText(_("Delete Printer")));
1816 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1817 cgiCopyTemplateLang("error.tmpl");
1823 * Build a CUPS_DELETE_PRINTER request, which requires the following
1826 * attributes-charset
1827 * attributes-natural-language
1831 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1833 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1837 * Do the request and get back a response...
1840 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1843 * Show the results...
1846 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1848 puts("Status: 401\n");
1851 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1854 * Redirect successful updates back to the printers page...
1857 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1860 cgiStartHTML(cgiText(_("Delete Printer")));
1862 if (cupsLastError() > IPP_OK_CONFLICT
)
1863 cgiShowIPPError(_("Unable to delete printer:"));
1865 cgiCopyTemplateLang("printer-deleted.tmpl");
1872 * 'do_export()' - Export printers to Samba...
1876 do_export(http_t
*http
) /* I - HTTP connection */
1878 int i
, j
; /* Looping vars */
1879 ipp_t
*request
, /* IPP request */
1880 *response
; /* IPP response */
1881 const char *username
, /* Samba username */
1882 *password
, /* Samba password */
1883 *export_all
; /* Export all printers? */
1884 int export_count
, /* Number of printers to export */
1885 printer_count
; /* Number of available printers */
1886 const char *name
, /* What name to pull */
1887 *dest
; /* Current destination */
1888 char ppd
[1024]; /* PPD file */
1895 username
= cgiGetVariable("USERNAME");
1896 password
= cgiGetVariable("PASSWORD");
1897 export_all
= cgiGetVariable("EXPORT_ALL");
1898 export_count
= cgiGetSize("EXPORT_NAME");
1901 * Get list of available printers...
1904 cgiSetSize("PRINTER_NAME", 0);
1905 cgiSetSize("PRINTER_EXPORT", 0);
1907 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1909 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1912 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1913 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
1914 CUPS_PRINTER_IMPLICIT
);
1916 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1917 "requested-attributes", NULL
, "printer-name");
1919 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1921 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1922 ippDelete(response
);
1926 printer_count
= cgiGetSize("PRINTER_NAME");
1928 for (i
= 0; i
< printer_count
; i
++)
1930 dest
= cgiGetArray("PRINTER_NAME", i
);
1932 for (j
= 0; j
< export_count
; j
++)
1933 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
1936 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
1942 * Export or get the printers to export...
1945 if (username
&& *username
&& password
&& *password
&&
1946 (export_all
|| export_count
> 0))
1952 fputs("DEBUG: Export printers...\n", stderr
);
1956 name
= "PRINTER_NAME";
1957 export_count
= cgiGetSize("PRINTER_NAME");
1960 name
= "EXPORT_NAME";
1962 for (i
= 0; i
< export_count
; i
++)
1964 dest
= cgiGetArray(name
, i
);
1966 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
1969 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
1978 if (i
< export_count
)
1979 cgiSetVariable("ERROR", cupsLastErrorString());
1982 cgiStartHTML(cgiText(_("Export Printers to Samba")));
1983 cgiCopyTemplateLang("samba-exported.tmpl");
1988 else if (username
&& !*username
)
1989 cgiSetVariable("ERROR",
1990 cgiText(_("A Samba username is required to export "
1991 "printer drivers!")));
1992 else if (username
&& (!password
|| !*password
))
1993 cgiSetVariable("ERROR",
1994 cgiText(_("A Samba password is required to export "
1995 "printer drivers!")));
2001 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2002 cgiCopyTemplateLang("samba-export.tmpl");
2008 * 'do_list_printers()' - List available printers...
2012 do_list_printers(http_t
*http
) /* I - HTTP connection */
2014 ipp_t
*request
, /* IPP request */
2015 *response
; /* IPP response */
2016 ipp_attribute_t
*attr
; /* IPP attribute */
2019 cgiStartHTML(cgiText(_("List Available Printers")));
2023 * Get the list of printers and their devices...
2026 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2028 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2029 "requested-attributes", NULL
, "device-uri");
2031 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2032 CUPS_PRINTER_LOCAL
);
2033 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2034 CUPS_PRINTER_LOCAL
);
2036 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2039 * Got the printer list, now load the devices...
2042 int i
; /* Looping var */
2043 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2044 char *printer_device
; /* Current printer device */
2048 * Allocate an array and copy the device strings...
2051 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2053 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2055 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2057 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2061 * Free the printer list and get the device list...
2064 ippDelete(response
);
2066 request
= ippNewRequest(CUPS_GET_DEVICES
);
2068 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2071 * Got the device list, let's parse it...
2074 const char *device_uri
, /* device-uri attribute value */
2075 *device_make_and_model
, /* device-make-and-model value */
2076 *device_info
; /* device-info value */
2079 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2082 * Skip leading attributes until we hit a device...
2085 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2092 * Pull the needed attributes from this device...
2096 device_make_and_model
= NULL
;
2099 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2101 if (!strcmp(attr
->name
, "device-info") &&
2102 attr
->value_tag
== IPP_TAG_TEXT
)
2103 device_info
= attr
->values
[0].string
.text
;
2105 if (!strcmp(attr
->name
, "device-make-and-model") &&
2106 attr
->value_tag
== IPP_TAG_TEXT
)
2107 device_make_and_model
= attr
->values
[0].string
.text
;
2109 if (!strcmp(attr
->name
, "device-uri") &&
2110 attr
->value_tag
== IPP_TAG_URI
)
2111 device_uri
= attr
->values
[0].string
.text
;
2117 * See if we have everything needed...
2120 if (device_info
&& device_make_and_model
&& device_uri
&&
2121 strcasecmp(device_make_and_model
, "unknown") &&
2122 strchr(device_uri
, ':'))
2125 * Yes, now see if there is already a printer for this
2129 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2132 * Not found, so it must be a new printer...
2135 char options
[1024], /* Form variables for this device */
2136 *options_ptr
; /* Pointer into string */
2137 const char *ptr
; /* Pointer into device string */
2141 * Format the printer name variable for this device...
2143 * We use the device-info string first, then device-uri,
2144 * and finally device-make-and-model to come up with a
2148 strcpy(options
, "TEMPLATE_NAME=");
2149 options_ptr
= options
+ strlen(options
);
2151 if (strncasecmp(device_info
, "unknown", 7))
2153 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2156 ptr
= device_make_and_model
;
2159 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2161 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2163 *options_ptr
++ = *ptr
;
2164 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2165 *options_ptr
++ = '_';
2166 else if (*ptr
== '?' || *ptr
== '(')
2170 * Then add the make and model in the printer info, so
2171 * that MacOS clients see something reasonable...
2174 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2176 sizeof(options
) - (options_ptr
- options
));
2177 options_ptr
+= strlen(options_ptr
);
2179 cgiFormEncode(options_ptr
, device_make_and_model
,
2180 sizeof(options
) - (options_ptr
- options
));
2181 options_ptr
+= strlen(options_ptr
);
2184 * Then copy the device URI...
2187 strlcpy(options_ptr
, "&DEVICE_URI=",
2188 sizeof(options
) - (options_ptr
- options
));
2189 options_ptr
+= strlen(options_ptr
);
2191 cgiFormEncode(options_ptr
, device_uri
,
2192 sizeof(options
) - (options_ptr
- options
));
2193 options_ptr
+= strlen(options_ptr
);
2195 if (options_ptr
< (options
+ sizeof(options
) - 1))
2197 *options_ptr
++ = '|';
2198 cgiFormEncode(options_ptr
, device_make_and_model
,
2199 sizeof(options
) - (options_ptr
- options
));
2203 * Finally, set the form variables for this printer...
2206 cgiSetArray("device_info", i
, device_info
);
2207 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2208 cgiSetArray("device_options", i
, options
);
2209 cgiSetArray("device_uri", i
, device_uri
);
2218 ippDelete(response
);
2221 * Free the device list...
2224 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2226 printer_device
= (char *)cupsArrayNext(printer_devices
))
2227 free(printer_device
);
2229 cupsArrayDelete(printer_devices
);
2234 * Finally, show the printer list...
2237 cgiCopyTemplateLang("list-available-printers.tmpl");
2244 * 'do_menu()' - Show the main menu...
2248 do_menu(http_t
*http
) /* I - HTTP connection */
2250 int num_settings
; /* Number of server settings */
2251 cups_option_t
*settings
; /* Server settings */
2252 const char *val
; /* Setting value */
2253 char filename
[1024]; /* Temporary filename */
2254 const char *datadir
; /* Location of data files */
2255 ipp_t
*request
, /* IPP request */
2256 *response
; /* IPP response */
2260 * Get the current server settings...
2263 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2265 cgiSetVariable("SETTINGS_MESSAGE",
2266 cgiText(_("Unable to open cupsd.conf file:")));
2267 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2270 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2271 settings
)) != NULL
&& atoi(val
))
2272 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2274 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2275 settings
)) != NULL
&& atoi(val
))
2276 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2278 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2279 settings
)) != NULL
&& atoi(val
))
2280 cgiSetVariable("REMOTE_ANY", "CHECKED");
2282 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2283 settings
)) != NULL
&& atoi(val
))
2284 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2286 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2287 settings
)) != NULL
&& atoi(val
))
2288 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2290 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2291 settings
)) != NULL
&& atoi(val
))
2292 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2295 cgiSetVariable("HAVE_GSSAPI", "1");
2297 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2298 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2299 cgiSetVariable("KERBEROS", "CHECKED");
2300 #endif /* HAVE_GSSAPI */
2302 cupsFreeOptions(num_settings
, settings
);
2305 * See if Samba and the Windows drivers are installed...
2308 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2309 datadir
= CUPS_DATADIR
;
2311 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2312 if (!access(filename
, R_OK
))
2315 * Found Windows 2000 driver file, see if we have smbclient and
2319 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2320 sizeof(filename
)) &&
2321 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2323 cgiSetVariable("HAVE_SAMBA", "Y");
2326 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2328 fputs("ERROR: smbclient not found!\n", stderr
);
2330 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2332 fputs("ERROR: rpcclient not found!\n", stderr
);
2342 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2344 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2345 NULL
, "ipp://localhost/");
2347 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2349 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2350 ippDelete(response
);
2354 * Finally, show the main menu template...
2357 cgiStartHTML(cgiText(_("Administration")));
2359 cgiCopyTemplateLang("admin.tmpl");
2366 * 'do_printer_op()' - Do a printer operation.
2370 do_printer_op(http_t
*http
, /* I - HTTP connection */
2371 ipp_op_t op
, /* I - Operation to perform */
2372 const char *title
) /* I - Title of page */
2374 ipp_t
*request
; /* IPP request */
2375 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2376 const char *printer
, /* Printer name (purge-jobs) */
2377 *is_class
; /* Is a class? */
2380 is_class
= cgiGetVariable("IS_CLASS");
2381 printer
= cgiGetVariable("PRINTER_NAME");
2385 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2386 cgiStartHTML(title
);
2387 cgiCopyTemplateLang("error.tmpl");
2393 * Build a printer request, which requires the following
2396 * attributes-charset
2397 * attributes-natural-language
2401 request
= ippNewRequest(op
);
2403 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2404 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2406 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2410 * Do the request and get back a response...
2413 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2415 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2417 puts("Status: 401\n");
2420 else if (cupsLastError() > IPP_OK_CONFLICT
)
2422 cgiStartHTML(title
);
2423 cgiShowIPPError(_("Unable to change printer:"));
2428 * Redirect successful updates back to the printer page...
2431 char url
[1024], /* Printer/class URL */
2432 refresh
[1024]; /* Refresh URL */
2435 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2436 cgiFormEncode(uri
, url
, sizeof(uri
));
2437 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2438 cgiSetVariable("refresh_page", refresh
);
2440 cgiStartHTML(title
);
2442 if (op
== IPP_PAUSE_PRINTER
)
2443 cgiCopyTemplateLang("printer-stop.tmpl");
2444 else if (op
== IPP_RESUME_PRINTER
)
2445 cgiCopyTemplateLang("printer-start.tmpl");
2446 else if (op
== CUPS_ACCEPT_JOBS
)
2447 cgiCopyTemplateLang("printer-accept.tmpl");
2448 else if (op
== CUPS_REJECT_JOBS
)
2449 cgiCopyTemplateLang("printer-reject.tmpl");
2450 else if (op
== IPP_PURGE_JOBS
)
2451 cgiCopyTemplateLang("printer-purge.tmpl");
2452 else if (op
== CUPS_SET_DEFAULT
)
2453 cgiCopyTemplateLang("printer-default.tmpl");
2461 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2465 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2467 int i
; /* Looping var */
2468 ipp_t
*request
, /* IPP request */
2469 *response
; /* IPP response */
2470 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2471 const char *printer
, /* Printer name (purge-jobs) */
2472 *is_class
, /* Is a class? */
2473 *users
, /* List of users or groups */
2474 *type
; /* Allow/deny type */
2475 int num_users
; /* Number of users */
2476 char *ptr
, /* Pointer into users string */
2477 *end
, /* Pointer to end of users string */
2478 quote
; /* Quote character */
2479 ipp_attribute_t
*attr
; /* Attribute */
2480 static const char * const attrs
[] = /* Requested attributes */
2482 "requesting-user-name-allowed",
2483 "requesting-user-name-denied"
2487 is_class
= cgiGetVariable("IS_CLASS");
2488 printer
= cgiGetVariable("PRINTER_NAME");
2492 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2493 cgiStartHTML(cgiText(_("Set Allowed Users")));
2494 cgiCopyTemplateLang("error.tmpl");
2499 users
= cgiGetVariable("users");
2500 type
= cgiGetVariable("type");
2502 if (!users
|| !type
||
2503 (strcmp(type
, "requesting-user-name-allowed") &&
2504 strcmp(type
, "requesting-user-name-denied")))
2507 * Build a Get-Printer-Attributes request, which requires the following
2510 * attributes-charset
2511 * attributes-natural-language
2513 * requested-attributes
2516 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2518 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2519 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2521 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2524 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2525 "requested-attributes",
2526 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2529 * Do the request and get back a response...
2532 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2534 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2536 ippDelete(response
);
2539 cgiStartHTML(cgiText(_("Set Allowed Users")));
2541 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2543 puts("Status: 401\n");
2546 else if (cupsLastError() > IPP_OK_CONFLICT
)
2547 cgiShowIPPError(_("Unable to get printer attributes:"));
2549 cgiCopyTemplateLang("users.tmpl");
2556 * Save the changes...
2559 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2562 * Skip whitespace and commas...
2565 while (*ptr
== ',' || isspace(*ptr
& 255))
2568 if (*ptr
== '\'' || *ptr
== '\"')
2571 * Scan quoted name...
2576 for (end
= ptr
; *end
; end
++)
2583 * Scan space or comma-delimited name...
2586 for (end
= ptr
; *end
; end
++)
2587 if (isspace(*end
& 255) || *end
== ',')
2592 * Advance to the next name...
2599 * Build a CUPS-Add-Printer/Class request, which requires the following
2602 * attributes-charset
2603 * attributes-natural-language
2605 * requesting-user-name-{allowed,denied}
2608 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2610 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2611 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2613 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2617 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2618 "requesting-user-name-allowed", NULL
, "all");
2621 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2622 type
, num_users
, NULL
, NULL
);
2624 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2627 * Skip whitespace and commas...
2630 while (*ptr
== ',' || isspace(*ptr
& 255))
2633 if (*ptr
== '\'' || *ptr
== '\"')
2636 * Scan quoted name...
2641 for (end
= ptr
; *end
; end
++)
2648 * Scan space or comma-delimited name...
2651 for (end
= ptr
; *end
; end
++)
2652 if (isspace(*end
& 255) || *end
== ',')
2657 * Terminate the name...
2667 attr
->values
[i
].string
.text
= strdup(ptr
);
2670 * Advance to the next name...
2678 * Do the request and get back a response...
2681 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2683 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2685 puts("Status: 401\n");
2688 else if (cupsLastError() > IPP_OK_CONFLICT
)
2690 cgiStartHTML(cgiText(_("Set Allowed Users")));
2691 cgiShowIPPError(_("Unable to change printer:"));
2696 * Redirect successful updates back to the printer page...
2699 char url
[1024], /* Printer/class URL */
2700 refresh
[1024]; /* Refresh URL */
2703 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2704 cgiFormEncode(uri
, url
, sizeof(uri
));
2705 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2707 cgiSetVariable("refresh_page", refresh
);
2709 cgiStartHTML(cgiText(_("Set Allowed Users")));
2711 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2712 "printer-modified.tmpl");
2721 * 'do_set_options()' - Configure the default options for a queue.
2725 do_set_options(http_t
*http
, /* I - HTTP connection */
2726 int is_class
) /* I - Set options for class? */
2728 int i
, j
, k
, m
; /* Looping vars */
2729 int have_options
; /* Have options? */
2730 ipp_t
*request
, /* IPP request */
2731 *response
; /* IPP response */
2732 ipp_attribute_t
*attr
; /* IPP attribute */
2733 char uri
[HTTP_MAX_URI
]; /* Job URI */
2734 const char *var
; /* Variable value */
2735 const char *printer
; /* Printer printer name */
2736 const char *filename
; /* PPD filename */
2737 char tempfile
[1024]; /* Temporary filename */
2738 cups_file_t
*in
, /* Input file */
2739 *out
; /* Output file */
2740 char line
[1024]; /* Line from PPD file */
2741 char keyword
[1024], /* Keyword from Default line */
2742 *keyptr
; /* Pointer into keyword... */
2743 ppd_file_t
*ppd
; /* PPD file */
2744 ppd_group_t
*group
; /* Option group */
2745 ppd_option_t
*option
; /* Option */
2746 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
2747 const char *title
; /* Page title */
2750 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2752 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2756 * Get the printer name...
2759 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2760 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2761 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2765 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2766 cgiStartHTML(title
);
2767 cgiCopyTemplateLang("error.tmpl");
2772 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2775 * Get the PPD file...
2781 filename
= cupsGetPPD2(http
, printer
);
2785 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2787 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2789 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2790 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2791 cgiStartHTML(title
);
2792 cgiCopyTemplateLang("error.tmpl");
2799 fputs("DEBUG: No PPD file\n", stderr
);
2803 if (cgiGetVariable("job_sheets_start") != NULL
||
2804 cgiGetVariable("job_sheets_end") != NULL
)
2811 ppdMarkDefaults(ppd
);
2813 DEBUG_printf(("<P>ppd->num_groups = %d\n"
2814 "<UL>\n", ppd
->num_groups
));
2816 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2818 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
2820 for (j
= group
->num_options
, option
= group
->options
;
2823 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2825 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
2827 ppdMarkOption(ppd
, option
->keyword
, var
);
2831 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
2834 DEBUG_puts("</UL></LI>");
2837 DEBUG_printf(("</UL>\n"
2838 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
2841 if (!have_options
|| ppdConflicts(ppd
))
2844 * Show the options to the user...
2847 fputs("DEBUG: Showing options...\n", stderr
);
2849 cgiStartHTML(cgiText(_("Set Printer Options")));
2850 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2856 if (ppdConflicts(ppd
))
2858 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
2861 for (j
= group
->num_options
, option
= group
->options
;
2864 if (option
->conflicted
)
2866 cgiSetArray("ckeyword", k
, option
->keyword
);
2867 cgiSetArray("ckeytext", k
, option
->text
);
2871 cgiCopyTemplateLang("option-conflict.tmpl");
2874 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2878 if (!strcmp(group
->name
, "InstallableOptions"))
2879 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2881 cgiSetVariable("GROUP", group
->text
);
2883 cgiCopyTemplateLang("option-header.tmpl");
2885 for (j
= group
->num_options
, option
= group
->options
;
2889 if (!strcmp(option
->keyword
, "PageRegion"))
2892 cgiSetVariable("KEYWORD", option
->keyword
);
2893 cgiSetVariable("KEYTEXT", option
->text
);
2895 if (option
->conflicted
)
2896 cgiSetVariable("CONFLICTED", "1");
2898 cgiSetVariable("CONFLICTED", "0");
2900 cgiSetSize("CHOICES", 0);
2901 cgiSetSize("TEXT", 0);
2902 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
2905 * Hide custom option values...
2908 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
2911 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
2912 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
2916 if (option
->choices
[k
].marked
)
2917 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
2922 case PPD_UI_BOOLEAN
:
2923 cgiCopyTemplateLang("option-boolean.tmpl");
2925 case PPD_UI_PICKONE
:
2926 cgiCopyTemplateLang("option-pickone.tmpl");
2928 case PPD_UI_PICKMANY
:
2929 cgiCopyTemplateLang("option-pickmany.tmpl");
2934 cgiCopyTemplateLang("option-trailer.tmpl");
2939 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
2940 * following attributes:
2942 * attributes-charset
2943 * attributes-natural-language
2947 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2949 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2950 "localhost", 0, "/printers/%s", printer
);
2951 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2955 * Do the request and get back a response...
2958 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2960 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
2961 IPP_TAG_ZERO
)) != NULL
)
2964 * Add the job sheets options...
2967 cgiSetVariable("GROUP", cgiText(_("Banners")));
2968 cgiCopyTemplateLang("option-header.tmpl");
2970 cgiSetSize("CHOICES", attr
->num_values
);
2971 cgiSetSize("TEXT", attr
->num_values
);
2972 for (k
= 0; k
< attr
->num_values
; k
++)
2974 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
2975 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
2978 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
2980 cgiSetVariable("KEYWORD", "job_sheets_start");
2981 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
2982 cgiSetVariable("DEFCHOICE", attr
== NULL
?
2983 "" : attr
->values
[0].string
.text
);
2985 cgiCopyTemplateLang("option-pickone.tmpl");
2987 cgiSetVariable("KEYWORD", "job_sheets_end");
2988 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
2989 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
2990 "" : attr
->values
[1].string
.text
);
2992 cgiCopyTemplateLang("option-pickone.tmpl");
2994 cgiCopyTemplateLang("option-trailer.tmpl");
2997 if (ippFindAttribute(response
, "printer-error-policy-supported",
2999 ippFindAttribute(response
, "printer-op-policy-supported",
3003 * Add the error and operation policy options...
3006 cgiSetVariable("GROUP", cgiText(_("Policies")));
3007 cgiCopyTemplateLang("option-header.tmpl");
3013 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3018 cgiSetSize("CHOICES", attr
->num_values
);
3019 cgiSetSize("TEXT", attr
->num_values
);
3020 for (k
= 0; k
< attr
->num_values
; k
++)
3022 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3023 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3026 attr
= ippFindAttribute(response
, "printer-error-policy",
3029 cgiSetVariable("KEYWORD", "printer_error_policy");
3030 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3031 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3032 "" : attr
->values
[0].string
.text
);
3035 cgiCopyTemplateLang("option-pickone.tmpl");
3038 * Operation policy...
3041 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3046 cgiSetSize("CHOICES", attr
->num_values
);
3047 cgiSetSize("TEXT", attr
->num_values
);
3048 for (k
= 0; k
< attr
->num_values
; k
++)
3050 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3051 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3054 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3056 cgiSetVariable("KEYWORD", "printer_op_policy");
3057 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3058 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3059 "" : attr
->values
[0].string
.text
);
3061 cgiCopyTemplateLang("option-pickone.tmpl");
3064 cgiCopyTemplateLang("option-trailer.tmpl");
3067 ippDelete(response
);
3071 * Binary protocol support...
3074 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
3076 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
3078 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
3079 cgiCopyTemplateLang("option-header.tmpl");
3081 cgiSetSize("CHOICES", 2);
3082 cgiSetSize("TEXT", 2);
3083 cgiSetArray("CHOICES", 0, "None");
3084 cgiSetArray("TEXT", 0, cgiText(_("None")));
3086 if (strstr(ppd
->protocols
, "TBCP"))
3088 cgiSetArray("CHOICES", 1, "TBCP");
3089 cgiSetArray("TEXT", 1, "TBCP");
3093 cgiSetArray("CHOICES", 1, "BCP");
3094 cgiSetArray("TEXT", 1, "BCP");
3097 cgiSetVariable("KEYWORD", "protocol");
3098 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
3099 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
3101 cgiCopyTemplateLang("option-pickone.tmpl");
3103 cgiCopyTemplateLang("option-trailer.tmpl");
3106 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3112 * Set default options...
3115 fputs("DEBUG: Setting options...\n", stderr
);
3119 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3120 in
= cupsFileOpen(filename
, "r");
3124 cgiSetVariable("ERROR", strerror(errno
));
3125 cgiStartHTML(cgiText(_("Set Printer Options")));
3126 cgiCopyTemplateLang("error.tmpl");
3142 while (cupsFileGets(in
, line
, sizeof(line
)))
3144 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3146 else if (strncmp(line
, "*Default", 8))
3147 cupsFilePrintf(out
, "%s\n", line
);
3151 * Get default option name...
3154 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3156 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3157 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3162 if (!strcmp(keyword
, "PageRegion") ||
3163 !strcmp(keyword
, "PaperDimension") ||
3164 !strcmp(keyword
, "ImageableArea"))
3165 var
= cgiGetVariable("PageSize");
3167 var
= cgiGetVariable(keyword
);
3170 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3172 cupsFilePrintf(out
, "%s\n", line
);
3176 if ((var
= cgiGetVariable("protocol")) != NULL
)
3177 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
3185 * Make sure temporary filename is cleared when there is no PPD...
3192 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3193 * following attributes:
3195 * attributes-charset
3196 * attributes-natural-language
3198 * job-sheets-default
3199 * printer-error-policy
3204 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3205 CUPS_ADD_MODIFY_PRINTER
);
3207 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3210 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3211 "job-sheets-default", 2, NULL
, NULL
);
3212 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3213 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3215 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3216 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3217 "printer-error-policy", NULL
, var
);
3219 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3220 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3221 "printer-op-policy", NULL
, var
);
3224 * Do the request and get back a response...
3228 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3230 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3232 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3234 puts("Status: 401\n");
3237 else if (cupsLastError() > IPP_OK_CONFLICT
)
3239 cgiStartHTML(title
);
3240 cgiShowIPPError(_("Unable to set options:"));
3245 * Redirect successful updates back to the printer page...
3248 char refresh
[1024]; /* Refresh URL */
3251 cgiFormEncode(uri
, printer
, sizeof(uri
));
3252 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3253 is_class
? "classes" : "printers", uri
);
3254 cgiSetVariable("refresh_page", refresh
);
3256 cgiStartHTML(title
);
3258 cgiCopyTemplateLang("printer-configured.tmpl");
3273 * 'do_set_sharing()' - Set printer-is-shared value...
3277 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3279 ipp_t
*request
, /* IPP request */
3280 *response
; /* IPP response */
3281 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3282 const char *printer
, /* Printer name */
3283 *is_class
, /* Is a class? */
3284 *shared
; /* Sharing value */
3287 is_class
= cgiGetVariable("IS_CLASS");
3288 printer
= cgiGetVariable("PRINTER_NAME");
3289 shared
= cgiGetVariable("SHARED");
3291 if (!printer
|| !shared
)
3293 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3294 cgiStartHTML(cgiText(_("Set Publishing")));
3295 cgiCopyTemplateLang("error.tmpl");
3301 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3302 * following attributes:
3304 * attributes-charset
3305 * attributes-natural-language
3310 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3312 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3313 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3315 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3318 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3321 * Do the request and get back a response...
3324 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3326 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3328 ippDelete(response
);
3331 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3333 puts("Status: 401\n");
3336 else if (cupsLastError() > IPP_OK_CONFLICT
)
3338 cgiStartHTML(cgiText(_("Set Publishing")));
3339 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3344 * Redirect successful updates back to the printer page...
3347 char url
[1024], /* Printer/class URL */
3348 refresh
[1024]; /* Refresh URL */
3351 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3352 cgiFormEncode(uri
, url
, sizeof(uri
));
3353 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3354 cgiSetVariable("refresh_page", refresh
);
3356 cgiStartHTML(cgiText(_("Set Publishing")));
3357 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3358 "printer-modified.tmpl");
3366 * 'match_string()' - Return the number of matching characters.
3369 static int /* O - Number of matching characters */
3370 match_string(const char *a
, /* I - First string */
3371 const char *b
) /* I - Second string */
3373 int count
; /* Number of matching characters */
3377 * Loop through both strings until we hit the end of either or we find
3378 * a non-matching character. For the purposes of comparison, we ignore
3379 * whitespace and do a case-insensitive comparison so that we have a
3380 * better chance of finding a match...
3383 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
3386 * Skip leading whitespace characters...
3389 while (isspace(*a
& 255))
3392 while (isspace(*b
& 255))
3396 * Break out if we run out of characters...
3403 * Do a case-insensitive comparison of the next two chars...
3406 if (tolower(*a
& 255) != tolower(*b
& 255))
3415 * End of "$Id: admin.c 6733 2007-07-26 18:09:46Z mike $".