2 * "$Id: admin.c 7012 2007-10-10 21:22:45Z 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
&& cgiIsPOST())
125 * Do the operation...
128 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
130 if (!strcmp(op
, "start-printer"))
131 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
132 else if (!strcmp(op
, "stop-printer"))
133 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
134 else if (!strcmp(op
, "start-class"))
135 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
136 else if (!strcmp(op
, "stop-class"))
137 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
138 else if (!strcmp(op
, "accept-jobs"))
139 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
140 else if (!strcmp(op
, "reject-jobs"))
141 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
142 else if (!strcmp(op
, "purge-jobs"))
143 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
144 else if (!strcmp(op
, "set-allowed-users"))
145 do_set_allowed_users(http
);
146 else if (!strcmp(op
, "set-as-default"))
147 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
148 else if (!strcmp(op
, "set-sharing"))
149 do_set_sharing(http
);
150 else if (!strcmp(op
, "find-new-printers") ||
151 !strcmp(op
, "list-available-printers"))
152 do_list_printers(http
);
153 else if (!strcmp(op
, "add-class"))
154 do_am_class(http
, 0);
155 else if (!strcmp(op
, "add-printer"))
156 do_am_printer(http
, 0);
157 else if (!strcmp(op
, "modify-class"))
158 do_am_class(http
, 1);
159 else if (!strcmp(op
, "modify-printer"))
160 do_am_printer(http
, 1);
161 else if (!strcmp(op
, "delete-class"))
162 do_delete_class(http
);
163 else if (!strcmp(op
, "delete-printer"))
164 do_delete_printer(http
);
165 else if (!strcmp(op
, "set-class-options"))
166 do_set_options(http
, 1);
167 else if (!strcmp(op
, "set-printer-options"))
168 do_set_options(http
, 0);
169 else if (!strcmp(op
, "config-server"))
170 do_config_server(http
);
171 else if (!strcmp(op
, "export-samba"))
173 else if (!strcmp(op
, "add-rss-subscription"))
174 do_add_rss_subscription(http
);
175 else if (!strcmp(op
, "cancel-subscription"))
176 do_cancel_subscription(http
);
180 * Bad operation code... Display an error...
183 cgiStartHTML(cgiText(_("Administration")));
184 cgiCopyTemplateLang("error-op.tmpl");
188 else if (op
&& !strcmp(op
, "redirect"))
190 const char *url
; /* Redirection URL... */
191 char prefix
[1024]; /* URL prefix */
195 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
196 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
198 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
199 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
201 if ((url
= cgiGetVariable("URL")) != NULL
)
202 printf("Location: %s%s\n\n", prefix
, url
);
204 printf("Location: %s/admin\n\n", prefix
);
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
, "/");
747 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
748 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
749 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
750 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
753 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
755 for (ptr
= name
; *ptr
; ptr
++)
756 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
759 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
761 cgiSetVariable("ERROR",
762 cgiText(_("The printer name may only contain up to "
763 "127 printable characters and may not "
764 "contain spaces, slashes (/), or the "
765 "pound sign (#).")));
767 cgiCopyTemplateLang("error.tmpl");
773 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
775 if ((uriptr
= strrchr(var
, '|')) != NULL
)
778 * Extract make and make/model from device URI string...
781 char make
[1024], /* Make string */
782 *makeptr
; /* Pointer into make */
787 strlcpy(make
, uriptr
, sizeof(make
));
789 if ((makeptr
= strchr(make
, ' ')) != NULL
)
791 else if ((makeptr
= strchr(make
, '-')) != NULL
)
793 else if (!strncasecmp(make
, "laserjet", 8) ||
794 !strncasecmp(make
, "deskjet", 7) ||
795 !strncasecmp(make
, "designjet", 9))
797 else if (!strncasecmp(make
, "phaser", 6))
798 strcpy(make
, "Xerox");
799 else if (!strncasecmp(make
, "stylus", 6))
800 strcpy(make
, "Epson");
802 strcpy(make
, "Generic");
804 if (!cgiGetVariable("CURRENT_MAKE"))
805 cgiSetVariable("CURRENT_MAKE", make
);
807 cgiSetVariable("PPD_MAKE", make
);
809 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
810 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
814 char template[128], /* Template name */
815 *tptr
; /* Pointer into template name */
817 cgiSetVariable("PRINTER_INFO", uriptr
);
819 for (tptr
= template;
820 tptr
< (template + sizeof(template) - 1) && *uriptr
;
822 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
825 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
[-1] != '_')
827 else if (*uriptr
== '?' || *uriptr
== '(')
832 cgiSetVariable("TEMPLATE_NAME", template);
840 * Build a CUPS_GET_DEVICES request, which requires the following
844 * attributes-natural-language
848 fputs("DEBUG: Getting list of devices...\n", stderr
);
850 request
= ippNewRequest(CUPS_GET_DEVICES
);
852 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
853 NULL
, "ipp://localhost/printers/");
856 * Do the request and get back a response...
859 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
861 fputs("DEBUG: Got device list!\n", stderr
);
863 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
868 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
869 cupsLastError(), cupsLastErrorString());
872 * Let the user choose...
875 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
877 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
878 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
881 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
882 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
886 cgiCopyTemplateLang("choose-device.tmpl");
889 else if (strchr(var
, '/') == NULL
)
891 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
894 * Set the current device URI for the form to the old one...
897 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
898 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
902 * User needs to set the full URI...
906 cgiCopyTemplateLang("choose-uri.tmpl");
909 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
912 * Need baud rate, parity, etc.
915 if ((var
= strchr(var
, '?')) != NULL
&&
916 strncmp(var
, "?baud=", 6) == 0)
917 maxrate
= atoi(var
+ 6);
921 for (i
= 0; i
< 10; i
++)
922 if (baudrates
[i
] > maxrate
)
926 sprintf(baudrate
, "%d", baudrates
[i
]);
927 cgiSetArray("BAUDRATES", i
, baudrate
);
931 cgiCopyTemplateLang("choose-serial.tmpl");
934 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
941 * Update the location and description of an existing printer...
945 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
947 cgiCopyTemplateLang("modify-printer.tmpl");
952 * Get the name, location, and description for a new printer...
955 cgiCopyTemplateLang("add-printer.tmpl");
965 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
970 * Get the PPD file...
973 int fd
; /* PPD file */
974 char filename
[1024]; /* PPD filename */
975 ppd_file_t
*ppd
; /* PPD information */
976 char buffer
[1024]; /* Buffer */
977 int bytes
; /* Number of bytes */
978 http_status_t get_status
; /* Status of GET */
981 /* TODO: Use cupsGetFile() API... */
982 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
984 if (httpGet(http
, uri
))
987 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
989 if (get_status
!= HTTP_OK
)
991 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
992 uri
, get_status
, httpStatus(get_status
));
994 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
996 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
997 write(fd
, buffer
, bytes
);
1001 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1003 if (ppd
->manufacturer
)
1004 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1007 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1014 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1015 filename
, ppdErrorString(ppdLastError(&bytes
)));
1023 "ERROR: Unable to create temporary file for PPD file: %s\n",
1029 * Build a CUPS_GET_PPDS request, which requires the following
1032 * attributes-charset
1033 * attributes-natural-language
1037 request
= ippNewRequest(CUPS_GET_PPDS
);
1039 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1040 NULL
, "ipp://localhost/printers/");
1042 if ((var
= cgiGetVariable("CURRENT_MAKE")) == NULL
)
1043 var
= cgiGetVariable("PPD_MAKE");
1045 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1046 "ppd-make", NULL
, var
);
1048 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1049 "requested-attributes", NULL
, "ppd-make");
1052 * Do the request and get back a response...
1055 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1058 * Got the list of PPDs, see if the user has selected a make...
1061 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
1064 * No PPD files with this make, try again with all makes...
1067 ippDelete(response
);
1069 request
= ippNewRequest(CUPS_GET_PPDS
);
1071 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1072 NULL
, "ipp://localhost/printers/");
1074 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1075 "requested-attributes", NULL
, "ppd-make");
1077 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1078 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1080 cgiStartHTML(title
);
1081 cgiCopyTemplateLang("choose-make.tmpl");
1084 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1086 cgiStartHTML(title
);
1087 cgiCopyTemplateLang("choose-make.tmpl");
1093 * Let the user choose a model...
1096 const char *make_model
; /* Current make/model string */
1099 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1102 * Scan for "close" matches...
1105 int match
, /* Current match */
1106 best_match
, /* Best match so far */
1107 count
; /* Number of drivers */
1108 const char *best
, /* Best matching string */
1109 *current
; /* Current string */
1112 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
1114 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
1116 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
1117 match
= match_string(make_model
, current
);
1119 if (match
> best_match
)
1126 if (best_match
> strlen(var
))
1129 * Found a match longer than the make...
1132 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
1136 cgiStartHTML(title
);
1137 cgiCopyTemplateLang("choose-model.tmpl");
1141 ippDelete(response
);
1145 cgiStartHTML(title
);
1146 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1147 cgiCopyTemplateLang("error.tmpl");
1154 * Build a CUPS_ADD_PRINTER request, which requires the following
1157 * attributes-charset
1158 * attributes-natural-language
1164 * printer-is-accepting-jobs
1168 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1170 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1171 "localhost", 0, "/printers/%s",
1172 cgiGetVariable("PRINTER_NAME"));
1173 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1176 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1177 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1179 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1180 NULL
, cgiGetVariable("PRINTER_INFO"));
1183 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1184 NULL
, cgiGetVariable("PPD_NAME"));
1186 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1189 * Strip make and model from URI...
1192 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1195 if (!strncmp(uri
, "serial:", 7))
1198 * Update serial port URI to include baud rate, etc.
1201 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1202 uriptr
= uri
+ strlen(uri
);
1204 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1205 "?baud=%s+bits=%s+parity=%s+flow=%s",
1206 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1207 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1210 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1213 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1215 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1219 * Do the request and get back a response...
1223 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1225 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1227 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1229 puts("Status: 401\n");
1232 else if (cupsLastError() > IPP_OK_CONFLICT
)
1234 cgiStartHTML(title
);
1235 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1236 _("Unable to add printer:"));
1241 * Redirect successful updates back to the printer page...
1244 char refresh
[1024]; /* Refresh URL */
1247 cgiFormEncode(uri
, name
, sizeof(uri
));
1249 snprintf(refresh
, sizeof(refresh
),
1250 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1252 cgiSetVariable("refresh_page", refresh
);
1254 cgiStartHTML(title
);
1256 cgiCopyTemplateLang("printer-modified.tmpl");
1261 * Set the printer options...
1264 cgiSetVariable("OP", "set-printer-options");
1265 do_set_options(http
, 0);
1278 * 'do_cancel_subscription()' - Cancel a subscription.
1282 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1284 ipp_t
*request
; /* IPP request data */
1285 const char *var
, /* Form variable */
1286 *user
; /* Username */
1287 int id
; /* Subscription ID */
1291 * See if we have all of the required information...
1294 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1301 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1302 cgiStartHTML(_("Cancel RSS Subscription"));
1303 cgiCopyTemplateLang("error.tmpl");
1309 * Cancel the subscription...
1312 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1314 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1315 NULL
, "ipp://localhost/");
1316 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1317 "notify-subscription-id", id
);
1319 if ((user
= getenv("REMOTE_USER")) == NULL
)
1322 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1325 ippDelete(cupsDoRequest(http
, request
, "/"));
1327 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1329 puts("Status: 401\n");
1332 else if (cupsLastError() > IPP_OK_CONFLICT
)
1334 cgiStartHTML(_("Cancel RSS Subscription"));
1335 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1340 * Redirect successful updates back to the admin page...
1343 cgiSetVariable("refresh_page", "5;URL=/admin");
1344 cgiStartHTML(_("Cancel RSS Subscription"));
1345 cgiCopyTemplateLang("subscription-canceled.tmpl");
1353 * 'do_config_server()' - Configure server settings.
1357 do_config_server(http_t
*http
) /* I - HTTP connection */
1359 if (cgiGetVariable("CHANGESETTINGS"))
1362 * Save basic setting changes...
1365 int num_settings
; /* Number of server settings */
1366 cups_option_t
*settings
; /* Server settings */
1367 const char *debug_logging
, /* DEBUG_LOGGING value */
1368 *remote_admin
, /* REMOTE_ADMIN value */
1369 *remote_any
, /* REMOTE_ANY value */
1371 /* REMOTE_PRINTERS value */
1372 *share_printers
,/* SHARE_PRINTERS value */
1375 /* DefaultAuthType value */
1376 #endif /* HAVE_GSSAPI */
1378 /* USER_CANCEL_ANY value */
1382 * Get the checkbox values from the form...
1385 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1386 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1387 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1388 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1389 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1390 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1393 * Get the current server settings...
1396 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1398 cgiStartHTML(cgiText(_("Change Settings")));
1399 cgiSetVariable("MESSAGE",
1400 cgiText(_("Unable to change server settings:")));
1401 cgiSetVariable("ERROR", cupsLastErrorString());
1402 cgiCopyTemplateLang("error.tmpl");
1409 * Get authentication settings...
1412 if (cgiGetVariable("KERBEROS"))
1413 default_auth_type
= "Negotiate";
1416 default_auth_type
= cupsGetOption("DefaultAuthType", num_settings
,
1418 if (!strcasecmp(default_auth_type
, "Negotiate"))
1419 default_auth_type
= "Basic";
1422 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1423 #endif /* HAVE_GSSAPI */
1426 * See if the settings have changed...
1429 if (strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1430 num_settings
, settings
)) ||
1431 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1432 num_settings
, settings
)) ||
1433 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1434 num_settings
, settings
)) ||
1435 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1436 num_settings
, settings
)) ||
1437 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1438 num_settings
, settings
)) ||
1440 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1441 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1442 num_settings
, settings
)) ||
1443 #endif /* HAVE_GSSAPI */
1444 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1445 num_settings
, settings
)))
1448 * Settings *have* changed, so save the changes...
1451 cupsFreeOptions(num_settings
, settings
);
1454 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1455 debug_logging
, num_settings
, &settings
);
1456 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1457 remote_admin
, num_settings
, &settings
);
1458 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1459 remote_any
, num_settings
, &settings
);
1460 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1461 remote_printers
, num_settings
, &settings
);
1462 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1463 share_printers
, num_settings
, &settings
);
1464 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1465 user_cancel_any
, num_settings
, &settings
);
1467 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1468 num_settings
, &settings
);
1469 #endif /* HAVE_GSSAPI */
1471 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1473 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1475 puts("Status: 401\n");
1479 cgiStartHTML(cgiText(_("Change Settings")));
1480 cgiSetVariable("MESSAGE",
1481 cgiText(_("Unable to change server settings:")));
1482 cgiSetVariable("ERROR", cupsLastErrorString());
1483 cgiCopyTemplateLang("error.tmpl");
1487 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1488 cgiStartHTML(cgiText(_("Change Settings")));
1489 cgiCopyTemplateLang("restart.tmpl");
1498 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1499 cgiStartHTML(cgiText(_("Change Settings")));
1500 cgiCopyTemplateLang("norestart.tmpl");
1503 cupsFreeOptions(num_settings
, settings
);
1507 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1510 * Save hand-edited config file...
1513 http_status_t status
; /* PUT status */
1514 char tempfile
[1024]; /* Temporary new cupsd.conf */
1515 int tempfd
; /* Temporary file descriptor */
1516 cups_file_t
*temp
; /* Temporary file */
1517 const char *start
, /* Start of line */
1518 *end
; /* End of line */
1522 * Create a temporary file for the new cupsd.conf file...
1525 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1527 cgiStartHTML(cgiText(_("Edit Configuration File")));
1528 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1529 cgiSetVariable("ERROR", strerror(errno
));
1530 cgiCopyTemplateLang("error.tmpl");
1537 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1539 cgiStartHTML(cgiText(_("Edit Configuration File")));
1540 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1541 cgiSetVariable("ERROR", strerror(errno
));
1542 cgiCopyTemplateLang("error.tmpl");
1552 * Copy the cupsd.conf text from the form variable...
1555 start
= cgiGetVariable("CUPSDCONF");
1558 if ((end
= strstr(start
, "\r\n")) == NULL
)
1559 if ((end
= strstr(start
, "\n")) == NULL
)
1560 end
= start
+ strlen(start
);
1562 cupsFileWrite(temp
, start
, end
- start
);
1563 cupsFilePutChar(temp
, '\n');
1567 else if (*end
== '\n')
1573 cupsFileClose(temp
);
1576 * Upload the configuration file to the server...
1579 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1581 if (status
== HTTP_UNAUTHORIZED
)
1583 puts("Status: 401\n");
1587 else if (status
!= HTTP_CREATED
)
1589 cgiSetVariable("MESSAGE",
1590 cgiText(_("Unable to upload cupsd.conf file:")));
1591 cgiSetVariable("ERROR", httpStatus(status
));
1593 cgiStartHTML(cgiText(_("Edit Configuration File")));
1594 cgiCopyTemplateLang("error.tmpl");
1598 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1600 cgiStartHTML(cgiText(_("Edit Configuration File")));
1601 cgiCopyTemplateLang("restart.tmpl");
1610 struct stat info
; /* cupsd.conf information */
1611 cups_file_t
*cupsd
; /* cupsd.conf file */
1612 char *buffer
, /* Buffer for entire file */
1613 *bufptr
, /* Pointer into buffer */
1614 *bufend
; /* End of buffer */
1615 int ch
; /* Character from file */
1616 char filename
[1024]; /* Filename */
1617 const char *server_root
; /* Location of config files */
1621 * Locate the cupsd.conf file...
1624 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1625 server_root
= CUPS_SERVERROOT
;
1627 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1630 * Figure out the size...
1633 if (stat(filename
, &info
))
1635 cgiStartHTML(cgiText(_("Edit Configuration File")));
1636 cgiSetVariable("MESSAGE",
1637 cgiText(_("Unable to access cupsd.conf file:")));
1638 cgiSetVariable("ERROR", strerror(errno
));
1639 cgiCopyTemplateLang("error.tmpl");
1646 if (info
.st_size
> (1024 * 1024))
1648 cgiStartHTML(cgiText(_("Edit Configuration File")));
1649 cgiSetVariable("MESSAGE",
1650 cgiText(_("Unable to access cupsd.conf file:")));
1651 cgiSetVariable("ERROR",
1652 cgiText(_("Unable to edit cupsd.conf files larger than "
1654 cgiCopyTemplateLang("error.tmpl");
1657 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1658 (long)info
.st_size
);
1663 * Open the cupsd.conf file...
1666 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1669 * Unable to open - log an error...
1672 cgiStartHTML(cgiText(_("Edit Configuration File")));
1673 cgiSetVariable("MESSAGE",
1674 cgiText(_("Unable to access cupsd.conf file:")));
1675 cgiSetVariable("ERROR", strerror(errno
));
1676 cgiCopyTemplateLang("error.tmpl");
1684 * Allocate memory and load the file into a string buffer...
1687 buffer
= calloc(1, info
.st_size
+ 1);
1689 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1690 cupsFileClose(cupsd
);
1692 cgiSetVariable("CUPSDCONF", buffer
);
1696 * Then get the default cupsd.conf file and put that into a string as
1700 strlcat(filename
, ".default", sizeof(filename
));
1702 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1703 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1705 buffer
= calloc(1, 2 * info
.st_size
+ 1);
1706 bufend
= buffer
+ 2 * info
.st_size
- 1;
1708 for (bufptr
= buffer
;
1709 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1711 if (ch
== '\\' || ch
== '\"')
1716 else if (ch
== '\n')
1721 else if (ch
== '\t')
1732 cupsFileClose(cupsd
);
1734 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1739 * Show the current config file...
1742 cgiStartHTML(cgiText(_("Edit Configuration File")));
1744 cgiCopyTemplateLang("edit-config.tmpl");
1752 * 'do_delete_class()' - Delete a class...
1756 do_delete_class(http_t
*http
) /* I - HTTP connection */
1758 ipp_t
*request
; /* IPP request */
1759 char uri
[HTTP_MAX_URI
]; /* Job URI */
1760 const char *pclass
; /* Printer class name */
1764 * Get form variables...
1767 if (cgiGetVariable("CONFIRM") == NULL
)
1769 cgiStartHTML(cgiText(_("Delete Class")));
1770 cgiCopyTemplateLang("class-confirm.tmpl");
1775 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1776 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1777 "localhost", 0, "/classes/%s", pclass
);
1780 cgiStartHTML(cgiText(_("Delete Class")));
1781 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1782 cgiCopyTemplateLang("error.tmpl");
1788 * Build a CUPS_DELETE_CLASS request, which requires the following
1791 * attributes-charset
1792 * attributes-natural-language
1796 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1798 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1802 * Do the request and get back a response...
1805 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1808 * Show the results...
1811 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1813 puts("Status: 401\n");
1816 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1819 * Redirect successful updates back to the classes page...
1822 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1825 cgiStartHTML(cgiText(_("Delete Class")));
1827 if (cupsLastError() > IPP_OK_CONFLICT
)
1828 cgiShowIPPError(_("Unable to delete class:"));
1830 cgiCopyTemplateLang("class-deleted.tmpl");
1837 * 'do_delete_printer()' - Delete a printer...
1841 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1843 ipp_t
*request
; /* IPP request */
1844 char uri
[HTTP_MAX_URI
]; /* Job URI */
1845 const char *printer
; /* Printer printer name */
1849 * Get form variables...
1852 if (cgiGetVariable("CONFIRM") == NULL
)
1854 cgiStartHTML(cgiText(_("Delete Printer")));
1855 cgiCopyTemplateLang("printer-confirm.tmpl");
1860 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1861 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1862 "localhost", 0, "/printers/%s", printer
);
1865 cgiStartHTML(cgiText(_("Delete Printer")));
1866 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1867 cgiCopyTemplateLang("error.tmpl");
1873 * Build a CUPS_DELETE_PRINTER request, which requires the following
1876 * attributes-charset
1877 * attributes-natural-language
1881 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1883 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1887 * Do the request and get back a response...
1890 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1893 * Show the results...
1896 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1898 puts("Status: 401\n");
1901 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1904 * Redirect successful updates back to the printers page...
1907 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1910 cgiStartHTML(cgiText(_("Delete Printer")));
1912 if (cupsLastError() > IPP_OK_CONFLICT
)
1913 cgiShowIPPError(_("Unable to delete printer:"));
1915 cgiCopyTemplateLang("printer-deleted.tmpl");
1922 * 'do_export()' - Export printers to Samba...
1926 do_export(http_t
*http
) /* I - HTTP connection */
1928 int i
, j
; /* Looping vars */
1929 ipp_t
*request
, /* IPP request */
1930 *response
; /* IPP response */
1931 const char *username
, /* Samba username */
1932 *password
, /* Samba password */
1933 *export_all
; /* Export all printers? */
1934 int export_count
, /* Number of printers to export */
1935 printer_count
; /* Number of available printers */
1936 const char *name
, /* What name to pull */
1937 *dest
; /* Current destination */
1938 char ppd
[1024]; /* PPD file */
1945 username
= cgiGetVariable("USERNAME");
1946 password
= cgiGetVariable("PASSWORD");
1947 export_all
= cgiGetVariable("EXPORT_ALL");
1948 export_count
= cgiGetSize("EXPORT_NAME");
1951 * Get list of available printers...
1954 cgiSetSize("PRINTER_NAME", 0);
1955 cgiSetSize("PRINTER_EXPORT", 0);
1957 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1959 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1962 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1963 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
1964 CUPS_PRINTER_IMPLICIT
);
1966 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1967 "requested-attributes", NULL
, "printer-name");
1969 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1971 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1972 ippDelete(response
);
1976 printer_count
= cgiGetSize("PRINTER_NAME");
1978 for (i
= 0; i
< printer_count
; i
++)
1980 dest
= cgiGetArray("PRINTER_NAME", i
);
1982 for (j
= 0; j
< export_count
; j
++)
1983 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
1986 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
1992 * Export or get the printers to export...
1995 if (username
&& *username
&& password
&& *password
&&
1996 (export_all
|| export_count
> 0))
2002 fputs("DEBUG: Export printers...\n", stderr
);
2006 name
= "PRINTER_NAME";
2007 export_count
= cgiGetSize("PRINTER_NAME");
2010 name
= "EXPORT_NAME";
2012 for (i
= 0; i
< export_count
; i
++)
2014 dest
= cgiGetArray(name
, i
);
2016 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2019 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2028 if (i
< export_count
)
2029 cgiSetVariable("ERROR", cupsLastErrorString());
2032 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2033 cgiCopyTemplateLang("samba-exported.tmpl");
2038 else if (username
&& !*username
)
2039 cgiSetVariable("ERROR",
2040 cgiText(_("A Samba username is required to export "
2041 "printer drivers!")));
2042 else if (username
&& (!password
|| !*password
))
2043 cgiSetVariable("ERROR",
2044 cgiText(_("A Samba password is required to export "
2045 "printer drivers!")));
2051 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2052 cgiCopyTemplateLang("samba-export.tmpl");
2058 * 'do_list_printers()' - List available printers...
2062 do_list_printers(http_t
*http
) /* I - HTTP connection */
2064 ipp_t
*request
, /* IPP request */
2065 *response
; /* IPP response */
2066 ipp_attribute_t
*attr
; /* IPP attribute */
2069 cgiStartHTML(cgiText(_("List Available Printers")));
2073 * Get the list of printers and their devices...
2076 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2078 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2079 "requested-attributes", NULL
, "device-uri");
2081 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2082 CUPS_PRINTER_LOCAL
);
2083 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2084 CUPS_PRINTER_LOCAL
);
2086 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2089 * Got the printer list, now load the devices...
2092 int i
; /* Looping var */
2093 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2094 char *printer_device
; /* Current printer device */
2098 * Allocate an array and copy the device strings...
2101 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2103 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2105 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2107 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2111 * Free the printer list and get the device list...
2114 ippDelete(response
);
2116 request
= ippNewRequest(CUPS_GET_DEVICES
);
2118 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2121 * Got the device list, let's parse it...
2124 const char *device_uri
, /* device-uri attribute value */
2125 *device_make_and_model
, /* device-make-and-model value */
2126 *device_info
; /* device-info value */
2129 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2132 * Skip leading attributes until we hit a device...
2135 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2142 * Pull the needed attributes from this device...
2146 device_make_and_model
= NULL
;
2149 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2151 if (!strcmp(attr
->name
, "device-info") &&
2152 attr
->value_tag
== IPP_TAG_TEXT
)
2153 device_info
= attr
->values
[0].string
.text
;
2155 if (!strcmp(attr
->name
, "device-make-and-model") &&
2156 attr
->value_tag
== IPP_TAG_TEXT
)
2157 device_make_and_model
= attr
->values
[0].string
.text
;
2159 if (!strcmp(attr
->name
, "device-uri") &&
2160 attr
->value_tag
== IPP_TAG_URI
)
2161 device_uri
= attr
->values
[0].string
.text
;
2167 * See if we have everything needed...
2170 if (device_info
&& device_make_and_model
&& device_uri
&&
2171 strcasecmp(device_make_and_model
, "unknown") &&
2172 strchr(device_uri
, ':'))
2175 * Yes, now see if there is already a printer for this
2179 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2182 * Not found, so it must be a new printer...
2185 char option
[1024], /* Form variables for this device */
2186 *option_ptr
; /* Pointer into string */
2187 const char *ptr
; /* Pointer into device string */
2191 * Format the printer name variable for this device...
2193 * We use the device-info string first, then device-uri,
2194 * and finally device-make-and-model to come up with a
2198 if (strncasecmp(device_info
, "unknown", 7))
2200 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2203 ptr
= device_make_and_model
;
2205 for (option_ptr
= option
;
2206 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2208 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2210 *option_ptr
++ = *ptr
;
2211 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
[-1] != '_')
2212 *option_ptr
++ = '_';
2213 else if (*ptr
== '?' || *ptr
== '(')
2218 cgiSetArray("TEMPLATE_NAME", i
, option
);
2221 * Finally, set the form variables for this printer...
2224 cgiSetArray("device_info", i
, device_info
);
2225 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2226 cgiSetArray("device_uri", i
, device_uri
);
2235 ippDelete(response
);
2238 * Free the device list...
2241 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2243 printer_device
= (char *)cupsArrayNext(printer_devices
))
2244 free(printer_device
);
2246 cupsArrayDelete(printer_devices
);
2251 * Finally, show the printer list...
2254 cgiCopyTemplateLang("list-available-printers.tmpl");
2261 * 'do_menu()' - Show the main menu...
2265 do_menu(http_t
*http
) /* I - HTTP connection */
2267 int num_settings
; /* Number of server settings */
2268 cups_option_t
*settings
; /* Server settings */
2269 const char *val
; /* Setting value */
2270 char filename
[1024]; /* Temporary filename */
2271 const char *datadir
; /* Location of data files */
2272 ipp_t
*request
, /* IPP request */
2273 *response
; /* IPP response */
2277 * Get the current server settings...
2280 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2282 cgiSetVariable("SETTINGS_MESSAGE",
2283 cgiText(_("Unable to open cupsd.conf file:")));
2284 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2287 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2288 settings
)) != NULL
&& atoi(val
))
2289 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2291 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2292 settings
)) != NULL
&& atoi(val
))
2293 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2295 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2296 settings
)) != NULL
&& atoi(val
))
2297 cgiSetVariable("REMOTE_ANY", "CHECKED");
2299 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2300 settings
)) != NULL
&& atoi(val
))
2301 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2303 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2304 settings
)) != NULL
&& atoi(val
))
2305 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2307 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2308 settings
)) != NULL
&& atoi(val
))
2309 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2312 cgiSetVariable("HAVE_GSSAPI", "1");
2314 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2315 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2316 cgiSetVariable("KERBEROS", "CHECKED");
2317 #endif /* HAVE_GSSAPI */
2319 cupsFreeOptions(num_settings
, settings
);
2322 * See if Samba and the Windows drivers are installed...
2325 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2326 datadir
= CUPS_DATADIR
;
2328 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2329 if (!access(filename
, R_OK
))
2332 * Found Windows 2000 driver file, see if we have smbclient and
2336 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2337 sizeof(filename
)) &&
2338 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2340 cgiSetVariable("HAVE_SAMBA", "Y");
2343 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2345 fputs("ERROR: smbclient not found!\n", stderr
);
2347 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2349 fputs("ERROR: rpcclient not found!\n", stderr
);
2359 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2361 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2362 NULL
, "ipp://localhost/");
2364 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2366 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2367 ippDelete(response
);
2371 * Finally, show the main menu template...
2374 cgiStartHTML(cgiText(_("Administration")));
2376 cgiCopyTemplateLang("admin.tmpl");
2383 * 'do_printer_op()' - Do a printer operation.
2387 do_printer_op(http_t
*http
, /* I - HTTP connection */
2388 ipp_op_t op
, /* I - Operation to perform */
2389 const char *title
) /* I - Title of page */
2391 ipp_t
*request
; /* IPP request */
2392 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2393 const char *printer
, /* Printer name (purge-jobs) */
2394 *is_class
; /* Is a class? */
2397 is_class
= cgiGetVariable("IS_CLASS");
2398 printer
= cgiGetVariable("PRINTER_NAME");
2402 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2403 cgiStartHTML(title
);
2404 cgiCopyTemplateLang("error.tmpl");
2410 * Build a printer request, which requires the following
2413 * attributes-charset
2414 * attributes-natural-language
2418 request
= ippNewRequest(op
);
2420 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2421 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2423 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2427 * Do the request and get back a response...
2430 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2432 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2434 puts("Status: 401\n");
2437 else if (cupsLastError() > IPP_OK_CONFLICT
)
2439 cgiStartHTML(title
);
2440 cgiShowIPPError(_("Unable to change printer:"));
2445 * Redirect successful updates back to the printer page...
2448 char url
[1024], /* Printer/class URL */
2449 refresh
[1024]; /* Refresh URL */
2452 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2453 cgiFormEncode(uri
, url
, sizeof(uri
));
2454 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2455 cgiSetVariable("refresh_page", refresh
);
2457 cgiStartHTML(title
);
2459 if (op
== IPP_PAUSE_PRINTER
)
2460 cgiCopyTemplateLang("printer-stop.tmpl");
2461 else if (op
== IPP_RESUME_PRINTER
)
2462 cgiCopyTemplateLang("printer-start.tmpl");
2463 else if (op
== CUPS_ACCEPT_JOBS
)
2464 cgiCopyTemplateLang("printer-accept.tmpl");
2465 else if (op
== CUPS_REJECT_JOBS
)
2466 cgiCopyTemplateLang("printer-reject.tmpl");
2467 else if (op
== IPP_PURGE_JOBS
)
2468 cgiCopyTemplateLang("printer-purge.tmpl");
2469 else if (op
== CUPS_SET_DEFAULT
)
2470 cgiCopyTemplateLang("printer-default.tmpl");
2478 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2482 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2484 int i
; /* Looping var */
2485 ipp_t
*request
, /* IPP request */
2486 *response
; /* IPP response */
2487 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2488 const char *printer
, /* Printer name (purge-jobs) */
2489 *is_class
, /* Is a class? */
2490 *users
, /* List of users or groups */
2491 *type
; /* Allow/deny type */
2492 int num_users
; /* Number of users */
2493 char *ptr
, /* Pointer into users string */
2494 *end
, /* Pointer to end of users string */
2495 quote
; /* Quote character */
2496 ipp_attribute_t
*attr
; /* Attribute */
2497 static const char * const attrs
[] = /* Requested attributes */
2499 "requesting-user-name-allowed",
2500 "requesting-user-name-denied"
2504 is_class
= cgiGetVariable("IS_CLASS");
2505 printer
= cgiGetVariable("PRINTER_NAME");
2509 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2510 cgiStartHTML(cgiText(_("Set Allowed Users")));
2511 cgiCopyTemplateLang("error.tmpl");
2516 users
= cgiGetVariable("users");
2517 type
= cgiGetVariable("type");
2519 if (!users
|| !type
||
2520 (strcmp(type
, "requesting-user-name-allowed") &&
2521 strcmp(type
, "requesting-user-name-denied")))
2524 * Build a Get-Printer-Attributes request, which requires the following
2527 * attributes-charset
2528 * attributes-natural-language
2530 * requested-attributes
2533 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2535 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2536 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2538 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2541 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2542 "requested-attributes",
2543 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2546 * Do the request and get back a response...
2549 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2551 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2553 ippDelete(response
);
2556 cgiStartHTML(cgiText(_("Set Allowed Users")));
2558 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2560 puts("Status: 401\n");
2563 else if (cupsLastError() > IPP_OK_CONFLICT
)
2564 cgiShowIPPError(_("Unable to get printer attributes:"));
2566 cgiCopyTemplateLang("users.tmpl");
2573 * Save the changes...
2576 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2579 * Skip whitespace and commas...
2582 while (*ptr
== ',' || isspace(*ptr
& 255))
2585 if (*ptr
== '\'' || *ptr
== '\"')
2588 * Scan quoted name...
2593 for (end
= ptr
; *end
; end
++)
2600 * Scan space or comma-delimited name...
2603 for (end
= ptr
; *end
; end
++)
2604 if (isspace(*end
& 255) || *end
== ',')
2609 * Advance to the next name...
2616 * Build a CUPS-Add-Printer/Class request, which requires the following
2619 * attributes-charset
2620 * attributes-natural-language
2622 * requesting-user-name-{allowed,denied}
2625 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2627 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2628 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2630 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2634 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2635 "requesting-user-name-allowed", NULL
, "all");
2638 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2639 type
, num_users
, NULL
, NULL
);
2641 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2644 * Skip whitespace and commas...
2647 while (*ptr
== ',' || isspace(*ptr
& 255))
2650 if (*ptr
== '\'' || *ptr
== '\"')
2653 * Scan quoted name...
2658 for (end
= ptr
; *end
; end
++)
2665 * Scan space or comma-delimited name...
2668 for (end
= ptr
; *end
; end
++)
2669 if (isspace(*end
& 255) || *end
== ',')
2674 * Terminate the name...
2684 attr
->values
[i
].string
.text
= strdup(ptr
);
2687 * Advance to the next name...
2695 * Do the request and get back a response...
2698 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2700 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2702 puts("Status: 401\n");
2705 else if (cupsLastError() > IPP_OK_CONFLICT
)
2707 cgiStartHTML(cgiText(_("Set Allowed Users")));
2708 cgiShowIPPError(_("Unable to change printer:"));
2713 * Redirect successful updates back to the printer page...
2716 char url
[1024], /* Printer/class URL */
2717 refresh
[1024]; /* Refresh URL */
2720 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2721 cgiFormEncode(uri
, url
, sizeof(uri
));
2722 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2724 cgiSetVariable("refresh_page", refresh
);
2726 cgiStartHTML(cgiText(_("Set Allowed Users")));
2728 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2729 "printer-modified.tmpl");
2738 * 'do_set_options()' - Configure the default options for a queue.
2742 do_set_options(http_t
*http
, /* I - HTTP connection */
2743 int is_class
) /* I - Set options for class? */
2745 int i
, j
, k
, m
; /* Looping vars */
2746 int have_options
; /* Have options? */
2747 ipp_t
*request
, /* IPP request */
2748 *response
; /* IPP response */
2749 ipp_attribute_t
*attr
; /* IPP attribute */
2750 char uri
[HTTP_MAX_URI
]; /* Job URI */
2751 const char *var
; /* Variable value */
2752 const char *printer
; /* Printer printer name */
2753 const char *filename
; /* PPD filename */
2754 char tempfile
[1024]; /* Temporary filename */
2755 cups_file_t
*in
, /* Input file */
2756 *out
; /* Output file */
2757 char line
[1024]; /* Line from PPD file */
2758 char keyword
[1024], /* Keyword from Default line */
2759 *keyptr
; /* Pointer into keyword... */
2760 ppd_file_t
*ppd
; /* PPD file */
2761 ppd_group_t
*group
; /* Option group */
2762 ppd_option_t
*option
; /* Option */
2763 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
2764 const char *title
; /* Page title */
2767 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2769 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2773 * Get the printer name...
2776 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2777 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2778 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2782 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2783 cgiStartHTML(title
);
2784 cgiCopyTemplateLang("error.tmpl");
2789 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2792 * Get the PPD file...
2798 filename
= cupsGetPPD2(http
, printer
);
2802 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2804 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2806 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2807 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2808 cgiStartHTML(title
);
2809 cgiCopyTemplateLang("error.tmpl");
2816 fputs("DEBUG: No PPD file\n", stderr
);
2820 if (cgiGetVariable("job_sheets_start") != NULL
||
2821 cgiGetVariable("job_sheets_end") != NULL
)
2828 ppdMarkDefaults(ppd
);
2830 DEBUG_printf(("<P>ppd->num_groups = %d\n"
2831 "<UL>\n", ppd
->num_groups
));
2833 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2835 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
2837 for (j
= group
->num_options
, option
= group
->options
;
2840 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2842 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
2844 ppdMarkOption(ppd
, option
->keyword
, var
);
2848 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
2851 DEBUG_puts("</UL></LI>");
2854 DEBUG_printf(("</UL>\n"
2855 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
2858 if (!have_options
|| ppdConflicts(ppd
))
2861 * Show the options to the user...
2864 fputs("DEBUG: Showing options...\n", stderr
);
2866 cgiStartHTML(cgiText(_("Set Printer Options")));
2867 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2873 if (ppdConflicts(ppd
))
2875 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
2878 for (j
= group
->num_options
, option
= group
->options
;
2881 if (option
->conflicted
)
2883 cgiSetArray("ckeyword", k
, option
->keyword
);
2884 cgiSetArray("ckeytext", k
, option
->text
);
2888 cgiCopyTemplateLang("option-conflict.tmpl");
2891 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2895 if (!strcmp(group
->name
, "InstallableOptions"))
2896 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2898 cgiSetVariable("GROUP", group
->text
);
2900 cgiCopyTemplateLang("option-header.tmpl");
2902 for (j
= group
->num_options
, option
= group
->options
;
2906 if (!strcmp(option
->keyword
, "PageRegion"))
2909 cgiSetVariable("KEYWORD", option
->keyword
);
2910 cgiSetVariable("KEYTEXT", option
->text
);
2912 if (option
->conflicted
)
2913 cgiSetVariable("CONFLICTED", "1");
2915 cgiSetVariable("CONFLICTED", "0");
2917 cgiSetSize("CHOICES", 0);
2918 cgiSetSize("TEXT", 0);
2919 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
2922 * Hide custom option values...
2925 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
2928 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
2929 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
2933 if (option
->choices
[k
].marked
)
2934 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
2939 case PPD_UI_BOOLEAN
:
2940 cgiCopyTemplateLang("option-boolean.tmpl");
2942 case PPD_UI_PICKONE
:
2943 cgiCopyTemplateLang("option-pickone.tmpl");
2945 case PPD_UI_PICKMANY
:
2946 cgiCopyTemplateLang("option-pickmany.tmpl");
2951 cgiCopyTemplateLang("option-trailer.tmpl");
2956 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
2957 * following attributes:
2959 * attributes-charset
2960 * attributes-natural-language
2964 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2966 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2967 "localhost", 0, "/printers/%s", printer
);
2968 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2972 * Do the request and get back a response...
2975 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2977 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
2978 IPP_TAG_ZERO
)) != NULL
)
2981 * Add the job sheets options...
2984 cgiSetVariable("GROUP", cgiText(_("Banners")));
2985 cgiCopyTemplateLang("option-header.tmpl");
2987 cgiSetSize("CHOICES", attr
->num_values
);
2988 cgiSetSize("TEXT", attr
->num_values
);
2989 for (k
= 0; k
< attr
->num_values
; k
++)
2991 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
2992 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
2995 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
2997 cgiSetVariable("KEYWORD", "job_sheets_start");
2998 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
2999 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3000 "" : attr
->values
[0].string
.text
);
3002 cgiCopyTemplateLang("option-pickone.tmpl");
3004 cgiSetVariable("KEYWORD", "job_sheets_end");
3005 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3006 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
3007 "" : attr
->values
[1].string
.text
);
3009 cgiCopyTemplateLang("option-pickone.tmpl");
3011 cgiCopyTemplateLang("option-trailer.tmpl");
3014 if (ippFindAttribute(response
, "printer-error-policy-supported",
3016 ippFindAttribute(response
, "printer-op-policy-supported",
3020 * Add the error and operation policy options...
3023 cgiSetVariable("GROUP", cgiText(_("Policies")));
3024 cgiCopyTemplateLang("option-header.tmpl");
3030 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3035 cgiSetSize("CHOICES", attr
->num_values
);
3036 cgiSetSize("TEXT", attr
->num_values
);
3037 for (k
= 0; k
< attr
->num_values
; k
++)
3039 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3040 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3043 attr
= ippFindAttribute(response
, "printer-error-policy",
3046 cgiSetVariable("KEYWORD", "printer_error_policy");
3047 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3048 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3049 "" : attr
->values
[0].string
.text
);
3052 cgiCopyTemplateLang("option-pickone.tmpl");
3055 * Operation policy...
3058 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3063 cgiSetSize("CHOICES", attr
->num_values
);
3064 cgiSetSize("TEXT", attr
->num_values
);
3065 for (k
= 0; k
< attr
->num_values
; k
++)
3067 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3068 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3071 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3073 cgiSetVariable("KEYWORD", "printer_op_policy");
3074 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3075 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3076 "" : attr
->values
[0].string
.text
);
3078 cgiCopyTemplateLang("option-pickone.tmpl");
3081 cgiCopyTemplateLang("option-trailer.tmpl");
3084 ippDelete(response
);
3088 * Binary protocol support...
3091 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
3093 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
3095 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
3096 cgiCopyTemplateLang("option-header.tmpl");
3098 cgiSetSize("CHOICES", 2);
3099 cgiSetSize("TEXT", 2);
3100 cgiSetArray("CHOICES", 0, "None");
3101 cgiSetArray("TEXT", 0, cgiText(_("None")));
3103 if (strstr(ppd
->protocols
, "TBCP"))
3105 cgiSetArray("CHOICES", 1, "TBCP");
3106 cgiSetArray("TEXT", 1, "TBCP");
3110 cgiSetArray("CHOICES", 1, "BCP");
3111 cgiSetArray("TEXT", 1, "BCP");
3114 cgiSetVariable("KEYWORD", "protocol");
3115 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
3116 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
3118 cgiCopyTemplateLang("option-pickone.tmpl");
3120 cgiCopyTemplateLang("option-trailer.tmpl");
3123 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3129 * Set default options...
3132 fputs("DEBUG: Setting options...\n", stderr
);
3136 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3137 in
= cupsFileOpen(filename
, "r");
3141 cgiSetVariable("ERROR", strerror(errno
));
3142 cgiStartHTML(cgiText(_("Set Printer Options")));
3143 cgiCopyTemplateLang("error.tmpl");
3159 while (cupsFileGets(in
, line
, sizeof(line
)))
3161 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3163 else if (strncmp(line
, "*Default", 8))
3164 cupsFilePrintf(out
, "%s\n", line
);
3168 * Get default option name...
3171 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3173 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3174 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3179 if (!strcmp(keyword
, "PageRegion") ||
3180 !strcmp(keyword
, "PaperDimension") ||
3181 !strcmp(keyword
, "ImageableArea"))
3182 var
= cgiGetVariable("PageSize");
3184 var
= cgiGetVariable(keyword
);
3187 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3189 cupsFilePrintf(out
, "%s\n", line
);
3193 if ((var
= cgiGetVariable("protocol")) != NULL
)
3194 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
3202 * Make sure temporary filename is cleared when there is no PPD...
3209 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3210 * following attributes:
3212 * attributes-charset
3213 * attributes-natural-language
3215 * job-sheets-default
3216 * printer-error-policy
3221 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3222 CUPS_ADD_MODIFY_PRINTER
);
3224 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3227 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3228 "job-sheets-default", 2, NULL
, NULL
);
3229 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3230 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3232 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3233 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3234 "printer-error-policy", NULL
, var
);
3236 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3237 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3238 "printer-op-policy", NULL
, var
);
3241 * Do the request and get back a response...
3245 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3247 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3249 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3251 puts("Status: 401\n");
3254 else if (cupsLastError() > IPP_OK_CONFLICT
)
3256 cgiStartHTML(title
);
3257 cgiShowIPPError(_("Unable to set options:"));
3262 * Redirect successful updates back to the printer page...
3265 char refresh
[1024]; /* Refresh URL */
3268 cgiFormEncode(uri
, printer
, sizeof(uri
));
3269 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3270 is_class
? "classes" : "printers", uri
);
3271 cgiSetVariable("refresh_page", refresh
);
3273 cgiStartHTML(title
);
3275 cgiCopyTemplateLang("printer-configured.tmpl");
3290 * 'do_set_sharing()' - Set printer-is-shared value...
3294 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3296 ipp_t
*request
, /* IPP request */
3297 *response
; /* IPP response */
3298 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3299 const char *printer
, /* Printer name */
3300 *is_class
, /* Is a class? */
3301 *shared
; /* Sharing value */
3304 is_class
= cgiGetVariable("IS_CLASS");
3305 printer
= cgiGetVariable("PRINTER_NAME");
3306 shared
= cgiGetVariable("SHARED");
3308 if (!printer
|| !shared
)
3310 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3311 cgiStartHTML(cgiText(_("Set Publishing")));
3312 cgiCopyTemplateLang("error.tmpl");
3318 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3319 * following attributes:
3321 * attributes-charset
3322 * attributes-natural-language
3327 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3329 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3330 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3332 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3335 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3338 * Do the request and get back a response...
3341 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3343 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3345 ippDelete(response
);
3348 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3350 puts("Status: 401\n");
3353 else if (cupsLastError() > IPP_OK_CONFLICT
)
3355 cgiStartHTML(cgiText(_("Set Publishing")));
3356 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3361 * Redirect successful updates back to the printer page...
3364 char url
[1024], /* Printer/class URL */
3365 refresh
[1024]; /* Refresh URL */
3368 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3369 cgiFormEncode(uri
, url
, sizeof(uri
));
3370 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3371 cgiSetVariable("refresh_page", refresh
);
3373 cgiStartHTML(cgiText(_("Set Publishing")));
3374 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3375 "printer-modified.tmpl");
3383 * 'match_string()' - Return the number of matching characters.
3386 static int /* O - Number of matching characters */
3387 match_string(const char *a
, /* I - First string */
3388 const char *b
) /* I - Second string */
3390 int count
; /* Number of matching characters */
3394 * Loop through both strings until we hit the end of either or we find
3395 * a non-matching character. For the purposes of comparison, we ignore
3396 * whitespace and do a case-insensitive comparison so that we have a
3397 * better chance of finding a match...
3400 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
3403 * Skip leading whitespace characters...
3406 while (isspace(*a
& 255))
3409 while (isspace(*b
& 255))
3413 * Break out if we run out of characters...
3420 * Do a case-insensitive comparison of the next two chars...
3423 if (tolower(*a
& 255) != tolower(*b
& 255))
3432 * End of "$Id: admin.c 7012 2007-10-10 21:22:45Z mike $".