2 * "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * main() - Main entry for CGI.
18 * do_add_rss_subscription() - Add a RSS subscription.
19 * do_am_class() - Add or modify a class.
20 * do_am_printer() - Add or modify a printer.
21 * do_cancel_subscription() - Cancel a subscription.
22 * do_config_server() - Configure server settings.
23 * do_delete_class() - Delete a class...
24 * do_delete_printer() - Delete a printer...
25 * do_export() - Export printers to Samba...
26 * do_list_printers() - List available printers...
27 * do_menu() - Show the main menu...
28 * do_printer_op() - Do a printer operation.
29 * do_set_allowed_users() - Set the allowed/denied users for a queue.
30 * do_set_options() - Configure the default options for a queue.
31 * do_set_sharing() - Set printer-is-shared value...
32 * 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 * Make sure we have a username...
315 if ((user
= getenv("REMOTE_USER")) == NULL
)
317 puts("Status: 401\n");
322 * Validate the subscription name...
325 for (ptr
= subscription_name
; *ptr
; ptr
++)
326 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
327 *ptr
== '?' || *ptr
== '#')
332 cgiSetVariable("ERROR",
333 cgiText(_("The subscription name may not "
334 "contain spaces, slashes (/), question marks (?), "
335 "or the pound sign (#).")));
336 cgiStartHTML(_("Add RSS Subscription"));
337 cgiCopyTemplateLang("error.tmpl");
343 * Add the subscription...
346 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
347 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
348 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
349 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
352 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
353 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
356 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
358 if (!strcasecmp(printer_uri
, "#ALL#"))
359 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
360 NULL
, "ipp://localhost/");
362 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
365 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
368 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
369 "notify-recipient-uri", NULL
, rss_uri
);
370 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
371 num_events
, NULL
, events
);
372 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
373 "notify-lease-duration", 0);
375 ippDelete(cupsDoRequest(http
, request
, "/"));
377 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
379 puts("Status: 401\n");
382 else if (cupsLastError() > IPP_OK_CONFLICT
)
384 cgiStartHTML(_("Add RSS Subscription"));
385 cgiShowIPPError(_("Unable to add RSS subscription:"));
390 * Redirect successful updates back to the admin page...
393 cgiSetVariable("refresh_page", "5;URL=/admin");
394 cgiStartHTML(_("Add RSS Subscription"));
395 cgiCopyTemplateLang("subscription-added.tmpl");
403 * 'do_am_class()' - Add or modify a class.
407 do_am_class(http_t
*http
, /* I - HTTP connection */
408 int modify
) /* I - Modify the printer? */
410 int i
, j
; /* Looping vars */
411 int element
; /* Element number */
412 int num_printers
; /* Number of printers */
413 ipp_t
*request
, /* IPP request */
414 *response
; /* IPP response */
415 ipp_attribute_t
*attr
; /* member-uris attribute */
416 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
417 const char *name
, /* Pointer to class name */
418 *ptr
; /* Pointer to CGI variable */
419 const char *title
; /* Title of page */
420 static const char * const pattrs
[] = /* Requested printer attributes */
428 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
429 name
= cgiGetVariable("PRINTER_NAME");
431 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
434 * Build a CUPS_GET_PRINTERS request, which requires the
435 * following attributes:
438 * attributes-natural-language
441 request
= ippNewRequest(CUPS_GET_PRINTERS
);
444 * Do the request and get back a response...
447 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
450 * Create MEMBER_URIS and MEMBER_NAMES arrays...
453 for (element
= 0, attr
= response
->attrs
;
456 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
458 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
459 (!name
|| strcasecmp(name
, ptr
+ 1)))
462 * Don't show the current class...
465 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
470 for (element
= 0, attr
= response
->attrs
;
473 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
475 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
478 * Don't show the current class...
481 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
486 num_printers
= cgiGetSize("MEMBER_URIS");
496 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
497 * following attributes:
500 * attributes-natural-language
504 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
506 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
507 "localhost", 0, "/classes/%s", name
);
508 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
511 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
512 "requested-attributes",
513 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
517 * Do the request and get back a response...
520 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
522 if ((attr
= ippFindAttribute(response
, "member-names",
523 IPP_TAG_NAME
)) != NULL
)
526 * Mark any current members in the class...
529 for (j
= 0; j
< num_printers
; j
++)
530 cgiSetArray("MEMBER_SELECTED", j
, "");
532 for (i
= 0; i
< attr
->num_values
; i
++)
534 for (j
= 0; j
< num_printers
; j
++)
536 if (!strcasecmp(attr
->values
[i
].string
.text
,
537 cgiGetArray("MEMBER_NAMES", j
)))
539 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
546 if ((attr
= ippFindAttribute(response
, "printer-info",
547 IPP_TAG_TEXT
)) != NULL
)
548 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
550 if ((attr
= ippFindAttribute(response
, "printer-location",
551 IPP_TAG_TEXT
)) != NULL
)
552 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
558 * Update the location and description of an existing printer...
562 cgiCopyTemplateLang("modify-class.tmpl");
567 * Get the name, location, and description for a new printer...
571 cgiCopyTemplateLang("add-class.tmpl");
579 for (ptr
= name
; *ptr
; ptr
++)
580 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
583 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
585 cgiSetVariable("ERROR",
586 cgiText(_("The class name may only contain up to "
587 "127 printable characters and may not "
588 "contain spaces, slashes (/), or the "
589 "pound sign (#).")));
591 cgiCopyTemplateLang("error.tmpl");
597 * Build a CUPS_ADD_CLASS request, which requires the following
601 * attributes-natural-language
605 * printer-is-accepting-jobs
610 request
= ippNewRequest(CUPS_ADD_CLASS
);
612 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
613 "localhost", 0, "/classes/%s",
614 cgiGetVariable("PRINTER_NAME"));
615 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
618 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
619 NULL
, cgiGetVariable("PRINTER_LOCATION"));
621 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
622 NULL
, cgiGetVariable("PRINTER_INFO"));
624 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
626 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
629 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
631 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
632 num_printers
, NULL
, NULL
);
633 for (i
= 0; i
< num_printers
; i
++)
634 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
638 * Do the request and get back a response...
641 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
643 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
645 puts("Status: 401\n");
648 else if (cupsLastError() > IPP_OK_CONFLICT
)
651 cgiShowIPPError(modify
? _("Unable to modify class:") :
652 _("Unable to add class:"));
657 * Redirect successful updates back to the class page...
660 char refresh
[1024]; /* Refresh URL */
662 cgiFormEncode(uri
, name
, sizeof(uri
));
663 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
665 cgiSetVariable("refresh_page", refresh
);
670 cgiCopyTemplateLang("class-modified.tmpl");
672 cgiCopyTemplateLang("class-added.tmpl");
680 * 'do_am_printer()' - Add or modify a printer.
684 do_am_printer(http_t
*http
, /* I - HTTP connection */
685 int modify
) /* I - Modify the printer? */
687 int i
; /* Looping var */
688 ipp_attribute_t
*attr
; /* Current attribute */
689 ipp_t
*request
, /* IPP request */
690 *response
, /* IPP response */
691 *oldinfo
; /* Old printer information */
692 const cgi_file_t
*file
; /* Uploaded file, if any */
693 const char *var
; /* CGI variable */
694 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
695 *uriptr
; /* Pointer into URI */
696 int maxrate
; /* Maximum baud rate */
697 char baudrate
[255]; /* Baud rate string */
698 const char *name
, /* Pointer to class name */
699 *ptr
; /* Pointer to CGI variable */
700 const char *title
; /* Title of page */
701 static int baudrates
[] = /* Baud rates */
716 ptr
= cgiGetVariable("DEVICE_URI");
717 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
718 ptr
? ptr
: "(null)");
720 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
725 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
726 * following attributes:
729 * attributes-natural-language
733 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
735 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
736 "localhost", 0, "/printers/%s",
737 cgiGetVariable("PRINTER_NAME"));
738 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
742 * Do the request and get back a response...
745 oldinfo
= cupsDoRequest(http
, request
, "/");
754 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
755 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
756 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
757 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
760 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
762 for (ptr
= name
; *ptr
; ptr
++)
763 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
766 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
768 cgiSetVariable("ERROR",
769 cgiText(_("The printer name may only contain up to "
770 "127 printable characters and may not "
771 "contain spaces, slashes (/), or the "
772 "pound sign (#).")));
774 cgiCopyTemplateLang("error.tmpl");
780 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
782 if ((uriptr
= strrchr(var
, '|')) != NULL
)
785 * Extract make and make/model from device URI string...
788 char make
[1024], /* Make string */
789 *makeptr
; /* Pointer into make */
794 strlcpy(make
, uriptr
, sizeof(make
));
796 if ((makeptr
= strchr(make
, ' ')) != NULL
)
798 else if ((makeptr
= strchr(make
, '-')) != NULL
)
800 else if (!strncasecmp(make
, "laserjet", 8) ||
801 !strncasecmp(make
, "deskjet", 7) ||
802 !strncasecmp(make
, "designjet", 9))
804 else if (!strncasecmp(make
, "phaser", 6))
805 strcpy(make
, "Xerox");
806 else if (!strncasecmp(make
, "stylus", 6))
807 strcpy(make
, "Epson");
809 strcpy(make
, "Generic");
811 if (!cgiGetVariable("CURRENT_MAKE"))
812 cgiSetVariable("CURRENT_MAKE", make
);
814 cgiSetVariable("PPD_MAKE", make
);
816 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
817 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
821 char template[128], /* Template name */
822 *tptr
; /* Pointer into template name */
824 cgiSetVariable("PRINTER_INFO", uriptr
);
826 for (tptr
= template;
827 tptr
< (template + sizeof(template) - 1) && *uriptr
;
829 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
832 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
[-1] != '_')
834 else if (*uriptr
== '?' || *uriptr
== '(')
839 cgiSetVariable("TEMPLATE_NAME", template);
847 * Build a CUPS_GET_DEVICES request, which requires the following
851 * attributes-natural-language
855 fputs("DEBUG: Getting list of devices...\n", stderr
);
857 request
= ippNewRequest(CUPS_GET_DEVICES
);
859 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
860 NULL
, "ipp://localhost/printers/");
863 * Do the request and get back a response...
866 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
868 fputs("DEBUG: Got device list!\n", stderr
);
870 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
875 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
876 cupsLastError(), cupsLastErrorString());
879 * Let the user choose...
882 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
884 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
885 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
888 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
889 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
893 cgiCopyTemplateLang("choose-device.tmpl");
896 else if (strchr(var
, '/') == NULL
)
898 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
901 * Set the current device URI for the form to the old one...
904 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
905 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
909 * User needs to set the full URI...
913 cgiCopyTemplateLang("choose-uri.tmpl");
916 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
919 * Need baud rate, parity, etc.
922 if ((var
= strchr(var
, '?')) != NULL
&&
923 strncmp(var
, "?baud=", 6) == 0)
924 maxrate
= atoi(var
+ 6);
928 for (i
= 0; i
< 10; i
++)
929 if (baudrates
[i
] > maxrate
)
933 sprintf(baudrate
, "%d", baudrates
[i
]);
934 cgiSetArray("BAUDRATES", i
, baudrate
);
938 cgiCopyTemplateLang("choose-serial.tmpl");
941 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
948 * Update the location and description of an existing printer...
952 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
954 cgiCopyTemplateLang("modify-printer.tmpl");
959 * Get the name, location, and description for a new printer...
962 cgiCopyTemplateLang("add-printer.tmpl");
972 else if (!file
&& !cgiGetVariable("PPD_NAME"))
977 * Get the PPD file...
980 int fd
; /* PPD file */
981 char filename
[1024]; /* PPD filename */
982 ppd_file_t
*ppd
; /* PPD information */
983 char buffer
[1024]; /* Buffer */
984 int bytes
; /* Number of bytes */
985 http_status_t get_status
; /* Status of GET */
988 /* TODO: Use cupsGetFile() API... */
989 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
991 if (httpGet(http
, uri
))
994 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
996 if (get_status
!= HTTP_OK
)
998 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
999 uri
, get_status
, httpStatus(get_status
));
1001 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1003 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1004 write(fd
, buffer
, bytes
);
1008 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1010 if (ppd
->manufacturer
)
1011 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1014 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1021 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1022 filename
, ppdErrorString(ppdLastError(&bytes
)));
1030 "ERROR: Unable to create temporary file for PPD file: %s\n",
1036 * Build a CUPS_GET_PPDS request, which requires the following
1039 * attributes-charset
1040 * attributes-natural-language
1044 request
= ippNewRequest(CUPS_GET_PPDS
);
1046 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1047 NULL
, "ipp://localhost/printers/");
1049 if ((var
= cgiGetVariable("CURRENT_MAKE")) == NULL
)
1050 var
= cgiGetVariable("PPD_MAKE");
1052 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1053 "ppd-make", NULL
, var
);
1055 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1056 "requested-attributes", NULL
, "ppd-make");
1059 * Do the request and get back a response...
1062 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1065 * Got the list of PPDs, see if the user has selected a make...
1068 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
1071 * No PPD files with this make, try again with all makes...
1074 ippDelete(response
);
1076 request
= ippNewRequest(CUPS_GET_PPDS
);
1078 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1079 NULL
, "ipp://localhost/printers/");
1081 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1082 "requested-attributes", NULL
, "ppd-make");
1084 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1085 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1087 cgiStartHTML(title
);
1088 cgiCopyTemplateLang("choose-make.tmpl");
1091 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1093 cgiStartHTML(title
);
1094 cgiCopyTemplateLang("choose-make.tmpl");
1100 * Let the user choose a model...
1103 const char *make_model
; /* Current make/model string */
1106 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1109 * Scan for "close" matches...
1112 int match
, /* Current match */
1113 best_match
, /* Best match so far */
1114 count
; /* Number of drivers */
1115 const char *best
, /* Best matching string */
1116 *current
; /* Current string */
1119 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
1121 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
1123 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
1124 match
= match_string(make_model
, current
);
1126 if (match
> best_match
)
1133 if (best_match
> strlen(var
))
1136 * Found a match longer than the make...
1139 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
1143 cgiStartHTML(title
);
1144 cgiCopyTemplateLang("choose-model.tmpl");
1148 ippDelete(response
);
1152 cgiStartHTML(title
);
1153 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1154 cgiCopyTemplateLang("error.tmpl");
1161 * Build a CUPS_ADD_PRINTER request, which requires the following
1164 * attributes-charset
1165 * attributes-natural-language
1171 * printer-is-accepting-jobs
1175 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1177 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1178 "localhost", 0, "/printers/%s",
1179 cgiGetVariable("PRINTER_NAME"));
1180 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1183 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1184 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1186 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1187 NULL
, cgiGetVariable("PRINTER_INFO"));
1190 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1191 NULL
, cgiGetVariable("PPD_NAME"));
1193 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1196 * Strip make and model from URI...
1199 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1202 if (!strncmp(uri
, "serial:", 7))
1205 * Update serial port URI to include baud rate, etc.
1208 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1209 uriptr
= uri
+ strlen(uri
);
1211 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1212 "?baud=%s+bits=%s+parity=%s+flow=%s",
1213 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1214 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1217 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1220 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1222 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1226 * Do the request and get back a response...
1230 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1232 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1234 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1236 puts("Status: 401\n");
1239 else if (cupsLastError() > IPP_OK_CONFLICT
)
1241 cgiStartHTML(title
);
1242 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1243 _("Unable to add printer:"));
1248 * Redirect successful updates back to the printer page...
1251 char refresh
[1024]; /* Refresh URL */
1254 cgiFormEncode(uri
, name
, sizeof(uri
));
1256 snprintf(refresh
, sizeof(refresh
),
1257 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1259 cgiSetVariable("refresh_page", refresh
);
1261 cgiStartHTML(title
);
1263 cgiCopyTemplateLang("printer-modified.tmpl");
1268 * Set the printer options...
1271 cgiSetVariable("OP", "set-printer-options");
1272 do_set_options(http
, 0);
1285 * 'do_cancel_subscription()' - Cancel a subscription.
1289 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1291 ipp_t
*request
; /* IPP request data */
1292 const char *var
, /* Form variable */
1293 *user
; /* Username */
1294 int id
; /* Subscription ID */
1298 * See if we have all of the required information...
1301 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1308 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1309 cgiStartHTML(_("Cancel RSS Subscription"));
1310 cgiCopyTemplateLang("error.tmpl");
1316 * Require a username...
1319 if ((user
= getenv("REMOTE_USER")) == NULL
)
1321 puts("Status: 401\n");
1326 * Cancel the subscription...
1329 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1331 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1332 NULL
, "ipp://localhost/");
1333 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1334 "notify-subscription-id", id
);
1336 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1339 ippDelete(cupsDoRequest(http
, request
, "/"));
1341 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1343 puts("Status: 401\n");
1346 else if (cupsLastError() > IPP_OK_CONFLICT
)
1348 cgiStartHTML(_("Cancel RSS Subscription"));
1349 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1354 * Redirect successful updates back to the admin page...
1357 cgiSetVariable("refresh_page", "5;URL=/admin");
1358 cgiStartHTML(_("Cancel RSS Subscription"));
1359 cgiCopyTemplateLang("subscription-canceled.tmpl");
1367 * 'do_config_server()' - Configure server settings.
1371 do_config_server(http_t
*http
) /* I - HTTP connection */
1373 if (cgiGetVariable("CHANGESETTINGS"))
1376 * Save basic setting changes...
1379 int num_settings
; /* Number of server settings */
1380 cups_option_t
*settings
; /* Server settings */
1381 const char *debug_logging
, /* DEBUG_LOGGING value */
1382 *remote_admin
, /* REMOTE_ADMIN value */
1383 *remote_any
, /* REMOTE_ANY value */
1385 /* REMOTE_PRINTERS value */
1386 *share_printers
,/* SHARE_PRINTERS value */
1388 /* USER_CANCEL_ANY value */
1390 char default_auth_type
[255];
1391 /* DefaultAuthType value */
1392 #endif /* HAVE_GSSAPI */
1396 * Get the checkbox values from the form...
1399 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1400 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1401 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1402 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1403 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1404 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1407 * Get the current server settings...
1410 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1412 cgiStartHTML(cgiText(_("Change Settings")));
1413 cgiSetVariable("MESSAGE",
1414 cgiText(_("Unable to change server settings:")));
1415 cgiSetVariable("ERROR", cupsLastErrorString());
1416 cgiCopyTemplateLang("error.tmpl");
1423 * Get authentication settings...
1426 if (cgiGetVariable("KERBEROS"))
1427 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1430 const char *val
= cupsGetOption("DefaultAuthType", num_settings
,
1433 if (val
&& !strcasecmp(val
, "Negotiate"))
1434 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1436 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1439 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1440 #endif /* HAVE_GSSAPI */
1443 * See if the settings have changed...
1446 if (strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1447 num_settings
, settings
)) ||
1448 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1449 num_settings
, settings
)) ||
1450 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1451 num_settings
, settings
)) ||
1452 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1453 num_settings
, settings
)) ||
1454 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1455 num_settings
, settings
)) ||
1457 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1458 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1459 num_settings
, settings
)) ||
1460 #endif /* HAVE_GSSAPI */
1461 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1462 num_settings
, settings
)))
1465 * Settings *have* changed, so save the changes...
1468 cupsFreeOptions(num_settings
, settings
);
1471 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1472 debug_logging
, num_settings
, &settings
);
1473 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1474 remote_admin
, num_settings
, &settings
);
1475 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1476 remote_any
, num_settings
, &settings
);
1477 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1478 remote_printers
, num_settings
, &settings
);
1479 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1480 share_printers
, num_settings
, &settings
);
1481 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1482 user_cancel_any
, num_settings
, &settings
);
1484 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1485 num_settings
, &settings
);
1486 #endif /* HAVE_GSSAPI */
1488 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1490 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1492 puts("Status: 401\n");
1496 cgiStartHTML(cgiText(_("Change Settings")));
1497 cgiSetVariable("MESSAGE",
1498 cgiText(_("Unable to change server settings:")));
1499 cgiSetVariable("ERROR", cupsLastErrorString());
1500 cgiCopyTemplateLang("error.tmpl");
1504 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1505 cgiStartHTML(cgiText(_("Change Settings")));
1506 cgiCopyTemplateLang("restart.tmpl");
1515 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1516 cgiStartHTML(cgiText(_("Change Settings")));
1517 cgiCopyTemplateLang("norestart.tmpl");
1520 cupsFreeOptions(num_settings
, settings
);
1524 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1527 * Save hand-edited config file...
1530 http_status_t status
; /* PUT status */
1531 char tempfile
[1024]; /* Temporary new cupsd.conf */
1532 int tempfd
; /* Temporary file descriptor */
1533 cups_file_t
*temp
; /* Temporary file */
1534 const char *start
, /* Start of line */
1535 *end
; /* End of line */
1539 * Create a temporary file for the new cupsd.conf file...
1542 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1544 cgiStartHTML(cgiText(_("Edit Configuration File")));
1545 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1546 cgiSetVariable("ERROR", strerror(errno
));
1547 cgiCopyTemplateLang("error.tmpl");
1554 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1556 cgiStartHTML(cgiText(_("Edit Configuration File")));
1557 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1558 cgiSetVariable("ERROR", strerror(errno
));
1559 cgiCopyTemplateLang("error.tmpl");
1569 * Copy the cupsd.conf text from the form variable...
1572 start
= cgiGetVariable("CUPSDCONF");
1575 if ((end
= strstr(start
, "\r\n")) == NULL
)
1576 if ((end
= strstr(start
, "\n")) == NULL
)
1577 end
= start
+ strlen(start
);
1579 cupsFileWrite(temp
, start
, end
- start
);
1580 cupsFilePutChar(temp
, '\n');
1584 else if (*end
== '\n')
1590 cupsFileClose(temp
);
1593 * Upload the configuration file to the server...
1596 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1598 if (status
== HTTP_UNAUTHORIZED
)
1600 puts("Status: 401\n");
1604 else if (status
!= HTTP_CREATED
)
1606 cgiSetVariable("MESSAGE",
1607 cgiText(_("Unable to upload cupsd.conf file:")));
1608 cgiSetVariable("ERROR", httpStatus(status
));
1610 cgiStartHTML(cgiText(_("Edit Configuration File")));
1611 cgiCopyTemplateLang("error.tmpl");
1615 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1617 cgiStartHTML(cgiText(_("Edit Configuration File")));
1618 cgiCopyTemplateLang("restart.tmpl");
1627 struct stat info
; /* cupsd.conf information */
1628 cups_file_t
*cupsd
; /* cupsd.conf file */
1629 char *buffer
, /* Buffer for entire file */
1630 *bufptr
, /* Pointer into buffer */
1631 *bufend
; /* End of buffer */
1632 int ch
; /* Character from file */
1633 char filename
[1024]; /* Filename */
1634 const char *server_root
; /* Location of config files */
1638 * Locate the cupsd.conf file...
1641 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1642 server_root
= CUPS_SERVERROOT
;
1644 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1647 * Figure out the size...
1650 if (stat(filename
, &info
))
1652 cgiStartHTML(cgiText(_("Edit Configuration File")));
1653 cgiSetVariable("MESSAGE",
1654 cgiText(_("Unable to access cupsd.conf file:")));
1655 cgiSetVariable("ERROR", strerror(errno
));
1656 cgiCopyTemplateLang("error.tmpl");
1663 if (info
.st_size
> (1024 * 1024))
1665 cgiStartHTML(cgiText(_("Edit Configuration File")));
1666 cgiSetVariable("MESSAGE",
1667 cgiText(_("Unable to access cupsd.conf file:")));
1668 cgiSetVariable("ERROR",
1669 cgiText(_("Unable to edit cupsd.conf files larger than "
1671 cgiCopyTemplateLang("error.tmpl");
1674 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1675 (long)info
.st_size
);
1680 * Open the cupsd.conf file...
1683 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1686 * Unable to open - log an error...
1689 cgiStartHTML(cgiText(_("Edit Configuration File")));
1690 cgiSetVariable("MESSAGE",
1691 cgiText(_("Unable to access cupsd.conf file:")));
1692 cgiSetVariable("ERROR", strerror(errno
));
1693 cgiCopyTemplateLang("error.tmpl");
1701 * Allocate memory and load the file into a string buffer...
1704 if ((buffer
= calloc(1, info
.st_size
+ 1)) != NULL
)
1706 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1707 cgiSetVariable("CUPSDCONF", buffer
);
1711 cupsFileClose(cupsd
);
1714 * Then get the default cupsd.conf file and put that into a string as
1718 strlcat(filename
, ".default", sizeof(filename
));
1720 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1721 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1723 if ((buffer
= calloc(1, 2 * info
.st_size
+ 1)) != NULL
)
1725 bufend
= buffer
+ 2 * info
.st_size
- 1;
1727 for (bufptr
= buffer
;
1728 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1730 if (ch
== '\\' || ch
== '\"')
1735 else if (ch
== '\n')
1740 else if (ch
== '\t')
1751 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1755 cupsFileClose(cupsd
);
1759 * Show the current config file...
1762 cgiStartHTML(cgiText(_("Edit Configuration File")));
1764 cgiCopyTemplateLang("edit-config.tmpl");
1772 * 'do_delete_class()' - Delete a class...
1776 do_delete_class(http_t
*http
) /* I - HTTP connection */
1778 ipp_t
*request
; /* IPP request */
1779 char uri
[HTTP_MAX_URI
]; /* Job URI */
1780 const char *pclass
; /* Printer class name */
1784 * Get form variables...
1787 if (cgiGetVariable("CONFIRM") == NULL
)
1789 cgiStartHTML(cgiText(_("Delete Class")));
1790 cgiCopyTemplateLang("class-confirm.tmpl");
1795 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1796 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1797 "localhost", 0, "/classes/%s", pclass
);
1800 cgiStartHTML(cgiText(_("Delete Class")));
1801 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1802 cgiCopyTemplateLang("error.tmpl");
1808 * Build a CUPS_DELETE_CLASS request, which requires the following
1811 * attributes-charset
1812 * attributes-natural-language
1816 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1818 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1822 * Do the request and get back a response...
1825 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1828 * Show the results...
1831 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1833 puts("Status: 401\n");
1836 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1839 * Redirect successful updates back to the classes page...
1842 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1845 cgiStartHTML(cgiText(_("Delete Class")));
1847 if (cupsLastError() > IPP_OK_CONFLICT
)
1848 cgiShowIPPError(_("Unable to delete class:"));
1850 cgiCopyTemplateLang("class-deleted.tmpl");
1857 * 'do_delete_printer()' - Delete a printer...
1861 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1863 ipp_t
*request
; /* IPP request */
1864 char uri
[HTTP_MAX_URI
]; /* Job URI */
1865 const char *printer
; /* Printer printer name */
1869 * Get form variables...
1872 if (cgiGetVariable("CONFIRM") == NULL
)
1874 cgiStartHTML(cgiText(_("Delete Printer")));
1875 cgiCopyTemplateLang("printer-confirm.tmpl");
1880 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1881 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1882 "localhost", 0, "/printers/%s", printer
);
1885 cgiStartHTML(cgiText(_("Delete Printer")));
1886 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1887 cgiCopyTemplateLang("error.tmpl");
1893 * Build a CUPS_DELETE_PRINTER request, which requires the following
1896 * attributes-charset
1897 * attributes-natural-language
1901 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1903 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1907 * Do the request and get back a response...
1910 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1913 * Show the results...
1916 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1918 puts("Status: 401\n");
1921 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1924 * Redirect successful updates back to the printers page...
1927 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1930 cgiStartHTML(cgiText(_("Delete Printer")));
1932 if (cupsLastError() > IPP_OK_CONFLICT
)
1933 cgiShowIPPError(_("Unable to delete printer:"));
1935 cgiCopyTemplateLang("printer-deleted.tmpl");
1942 * 'do_export()' - Export printers to Samba...
1946 do_export(http_t
*http
) /* I - HTTP connection */
1948 int i
, j
; /* Looping vars */
1949 ipp_t
*request
, /* IPP request */
1950 *response
; /* IPP response */
1951 const char *username
, /* Samba username */
1952 *password
, /* Samba password */
1953 *export_all
; /* Export all printers? */
1954 int export_count
, /* Number of printers to export */
1955 printer_count
; /* Number of available printers */
1956 const char *name
, /* What name to pull */
1957 *dest
; /* Current destination */
1958 char ppd
[1024]; /* PPD file */
1965 username
= cgiGetVariable("USERNAME");
1966 password
= cgiGetVariable("PASSWORD");
1967 export_all
= cgiGetVariable("EXPORT_ALL");
1968 export_count
= cgiGetSize("EXPORT_NAME");
1971 * Get list of available printers...
1974 cgiSetSize("PRINTER_NAME", 0);
1975 cgiSetSize("PRINTER_EXPORT", 0);
1977 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1979 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1982 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1983 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
1984 CUPS_PRINTER_IMPLICIT
);
1986 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1987 "requested-attributes", NULL
, "printer-name");
1989 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1991 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1992 ippDelete(response
);
1996 printer_count
= cgiGetSize("PRINTER_NAME");
1998 for (i
= 0; i
< printer_count
; i
++)
2000 dest
= cgiGetArray("PRINTER_NAME", i
);
2002 for (j
= 0; j
< export_count
; j
++)
2003 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2006 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2012 * Export or get the printers to export...
2015 if (username
&& *username
&& password
&& *password
&&
2016 (export_all
|| export_count
> 0))
2022 fputs("DEBUG: Export printers...\n", stderr
);
2026 name
= "PRINTER_NAME";
2027 export_count
= cgiGetSize("PRINTER_NAME");
2030 name
= "EXPORT_NAME";
2032 for (i
= 0; i
< export_count
; i
++)
2034 dest
= cgiGetArray(name
, i
);
2036 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2039 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2048 if (i
< export_count
)
2049 cgiSetVariable("ERROR", cupsLastErrorString());
2052 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2053 cgiCopyTemplateLang("samba-exported.tmpl");
2058 else if (username
&& !*username
)
2059 cgiSetVariable("ERROR",
2060 cgiText(_("A Samba username is required to export "
2061 "printer drivers!")));
2062 else if (username
&& (!password
|| !*password
))
2063 cgiSetVariable("ERROR",
2064 cgiText(_("A Samba password is required to export "
2065 "printer drivers!")));
2071 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2072 cgiCopyTemplateLang("samba-export.tmpl");
2078 * 'do_list_printers()' - List available printers...
2082 do_list_printers(http_t
*http
) /* I - HTTP connection */
2084 ipp_t
*request
, /* IPP request */
2085 *response
; /* IPP response */
2086 ipp_attribute_t
*attr
; /* IPP attribute */
2089 cgiStartHTML(cgiText(_("List Available Printers")));
2093 * Get the list of printers and their devices...
2096 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2098 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2099 "requested-attributes", NULL
, "device-uri");
2101 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2102 CUPS_PRINTER_LOCAL
);
2103 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2104 CUPS_PRINTER_LOCAL
);
2106 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2109 * Got the printer list, now load the devices...
2112 int i
; /* Looping var */
2113 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2114 char *printer_device
; /* Current printer device */
2118 * Allocate an array and copy the device strings...
2121 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2123 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2125 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2127 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2131 * Free the printer list and get the device list...
2134 ippDelete(response
);
2136 request
= ippNewRequest(CUPS_GET_DEVICES
);
2138 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2141 * Got the device list, let's parse it...
2144 const char *device_uri
, /* device-uri attribute value */
2145 *device_make_and_model
, /* device-make-and-model value */
2146 *device_info
; /* device-info value */
2149 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2152 * Skip leading attributes until we hit a device...
2155 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2162 * Pull the needed attributes from this device...
2166 device_make_and_model
= NULL
;
2169 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2171 if (!strcmp(attr
->name
, "device-info") &&
2172 attr
->value_tag
== IPP_TAG_TEXT
)
2173 device_info
= attr
->values
[0].string
.text
;
2175 if (!strcmp(attr
->name
, "device-make-and-model") &&
2176 attr
->value_tag
== IPP_TAG_TEXT
)
2177 device_make_and_model
= attr
->values
[0].string
.text
;
2179 if (!strcmp(attr
->name
, "device-uri") &&
2180 attr
->value_tag
== IPP_TAG_URI
)
2181 device_uri
= attr
->values
[0].string
.text
;
2187 * See if we have everything needed...
2190 if (device_info
&& device_make_and_model
&& device_uri
&&
2191 strcasecmp(device_make_and_model
, "unknown") &&
2192 strchr(device_uri
, ':'))
2195 * Yes, now see if there is already a printer for this
2199 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2202 * Not found, so it must be a new printer...
2205 char option
[1024], /* Form variables for this device */
2206 *option_ptr
; /* Pointer into string */
2207 const char *ptr
; /* Pointer into device string */
2211 * Format the printer name variable for this device...
2213 * We use the device-info string first, then device-uri,
2214 * and finally device-make-and-model to come up with a
2218 if (strncasecmp(device_info
, "unknown", 7))
2220 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2223 ptr
= device_make_and_model
;
2225 for (option_ptr
= option
;
2226 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2228 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2230 *option_ptr
++ = *ptr
;
2231 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
[-1] != '_')
2232 *option_ptr
++ = '_';
2233 else if (*ptr
== '?' || *ptr
== '(')
2238 cgiSetArray("TEMPLATE_NAME", i
, option
);
2241 * Finally, set the form variables for this printer...
2244 cgiSetArray("device_info", i
, device_info
);
2245 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2246 cgiSetArray("device_uri", i
, device_uri
);
2255 ippDelete(response
);
2258 * Free the device list...
2261 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2263 printer_device
= (char *)cupsArrayNext(printer_devices
))
2264 free(printer_device
);
2266 cupsArrayDelete(printer_devices
);
2271 * Finally, show the printer list...
2274 cgiCopyTemplateLang("list-available-printers.tmpl");
2281 * 'do_menu()' - Show the main menu...
2285 do_menu(http_t
*http
) /* I - HTTP connection */
2287 int num_settings
; /* Number of server settings */
2288 cups_option_t
*settings
; /* Server settings */
2289 const char *val
; /* Setting value */
2290 char filename
[1024]; /* Temporary filename */
2291 const char *datadir
; /* Location of data files */
2292 ipp_t
*request
, /* IPP request */
2293 *response
; /* IPP response */
2297 * Get the current server settings...
2300 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2302 cgiSetVariable("SETTINGS_MESSAGE",
2303 cgiText(_("Unable to open cupsd.conf file:")));
2304 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2307 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2308 settings
)) != NULL
&& atoi(val
))
2309 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2311 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2312 settings
)) != NULL
&& atoi(val
))
2313 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2315 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2316 settings
)) != NULL
&& atoi(val
))
2317 cgiSetVariable("REMOTE_ANY", "CHECKED");
2319 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2320 settings
)) != NULL
&& atoi(val
))
2321 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2323 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2324 settings
)) != NULL
&& atoi(val
))
2325 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2327 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2328 settings
)) != NULL
&& atoi(val
))
2329 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2332 cgiSetVariable("HAVE_GSSAPI", "1");
2334 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2335 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2336 cgiSetVariable("KERBEROS", "CHECKED");
2337 #endif /* HAVE_GSSAPI */
2339 cupsFreeOptions(num_settings
, settings
);
2342 * See if Samba and the Windows drivers are installed...
2345 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2346 datadir
= CUPS_DATADIR
;
2348 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2349 if (!access(filename
, R_OK
))
2352 * Found Windows 2000 driver file, see if we have smbclient and
2356 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2357 sizeof(filename
)) &&
2358 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2360 cgiSetVariable("HAVE_SAMBA", "Y");
2363 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2365 fputs("ERROR: smbclient not found!\n", stderr
);
2367 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2369 fputs("ERROR: rpcclient not found!\n", stderr
);
2379 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2381 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2382 NULL
, "ipp://localhost/");
2384 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2386 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2387 ippDelete(response
);
2391 * Finally, show the main menu template...
2394 cgiStartHTML(cgiText(_("Administration")));
2396 cgiCopyTemplateLang("admin.tmpl");
2403 * 'do_printer_op()' - Do a printer operation.
2407 do_printer_op(http_t
*http
, /* I - HTTP connection */
2408 ipp_op_t op
, /* I - Operation to perform */
2409 const char *title
) /* I - Title of page */
2411 ipp_t
*request
; /* IPP request */
2412 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2413 const char *printer
, /* Printer name (purge-jobs) */
2414 *is_class
; /* Is a class? */
2417 is_class
= cgiGetVariable("IS_CLASS");
2418 printer
= cgiGetVariable("PRINTER_NAME");
2422 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2423 cgiStartHTML(title
);
2424 cgiCopyTemplateLang("error.tmpl");
2430 * Build a printer request, which requires the following
2433 * attributes-charset
2434 * attributes-natural-language
2438 request
= ippNewRequest(op
);
2440 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2441 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2443 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2447 * Do the request and get back a response...
2450 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2452 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2454 puts("Status: 401\n");
2457 else if (cupsLastError() > IPP_OK_CONFLICT
)
2459 cgiStartHTML(title
);
2460 cgiShowIPPError(_("Unable to change printer:"));
2465 * Redirect successful updates back to the printer page...
2468 char url
[1024], /* Printer/class URL */
2469 refresh
[1024]; /* Refresh URL */
2472 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2473 cgiFormEncode(uri
, url
, sizeof(uri
));
2474 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2475 cgiSetVariable("refresh_page", refresh
);
2477 cgiStartHTML(title
);
2479 if (op
== IPP_PAUSE_PRINTER
)
2480 cgiCopyTemplateLang("printer-stop.tmpl");
2481 else if (op
== IPP_RESUME_PRINTER
)
2482 cgiCopyTemplateLang("printer-start.tmpl");
2483 else if (op
== CUPS_ACCEPT_JOBS
)
2484 cgiCopyTemplateLang("printer-accept.tmpl");
2485 else if (op
== CUPS_REJECT_JOBS
)
2486 cgiCopyTemplateLang("printer-reject.tmpl");
2487 else if (op
== IPP_PURGE_JOBS
)
2488 cgiCopyTemplateLang("printer-purge.tmpl");
2489 else if (op
== CUPS_SET_DEFAULT
)
2490 cgiCopyTemplateLang("printer-default.tmpl");
2498 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2502 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2504 int i
; /* Looping var */
2505 ipp_t
*request
, /* IPP request */
2506 *response
; /* IPP response */
2507 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2508 const char *printer
, /* Printer name (purge-jobs) */
2509 *is_class
, /* Is a class? */
2510 *users
, /* List of users or groups */
2511 *type
; /* Allow/deny type */
2512 int num_users
; /* Number of users */
2513 char *ptr
, /* Pointer into users string */
2514 *end
, /* Pointer to end of users string */
2515 quote
; /* Quote character */
2516 ipp_attribute_t
*attr
; /* Attribute */
2517 static const char * const attrs
[] = /* Requested attributes */
2519 "requesting-user-name-allowed",
2520 "requesting-user-name-denied"
2524 is_class
= cgiGetVariable("IS_CLASS");
2525 printer
= cgiGetVariable("PRINTER_NAME");
2529 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2530 cgiStartHTML(cgiText(_("Set Allowed Users")));
2531 cgiCopyTemplateLang("error.tmpl");
2536 users
= cgiGetVariable("users");
2537 type
= cgiGetVariable("type");
2539 if (!users
|| !type
||
2540 (strcmp(type
, "requesting-user-name-allowed") &&
2541 strcmp(type
, "requesting-user-name-denied")))
2544 * Build a Get-Printer-Attributes request, which requires the following
2547 * attributes-charset
2548 * attributes-natural-language
2550 * requested-attributes
2553 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2555 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2556 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2558 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2561 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2562 "requested-attributes",
2563 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2566 * Do the request and get back a response...
2569 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2571 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2573 ippDelete(response
);
2576 cgiStartHTML(cgiText(_("Set Allowed Users")));
2578 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2580 puts("Status: 401\n");
2583 else if (cupsLastError() > IPP_OK_CONFLICT
)
2584 cgiShowIPPError(_("Unable to get printer attributes:"));
2586 cgiCopyTemplateLang("users.tmpl");
2593 * Save the changes...
2596 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2599 * Skip whitespace and commas...
2602 while (*ptr
== ',' || isspace(*ptr
& 255))
2605 if (*ptr
== '\'' || *ptr
== '\"')
2608 * Scan quoted name...
2613 for (end
= ptr
; *end
; end
++)
2620 * Scan space or comma-delimited name...
2623 for (end
= ptr
; *end
; end
++)
2624 if (isspace(*end
& 255) || *end
== ',')
2629 * Advance to the next name...
2636 * Build a CUPS-Add-Printer/Class request, which requires the following
2639 * attributes-charset
2640 * attributes-natural-language
2642 * requesting-user-name-{allowed,denied}
2645 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2647 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2648 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2650 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2654 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2655 "requesting-user-name-allowed", NULL
, "all");
2658 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2659 type
, num_users
, NULL
, NULL
);
2661 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2664 * Skip whitespace and commas...
2667 while (*ptr
== ',' || isspace(*ptr
& 255))
2670 if (*ptr
== '\'' || *ptr
== '\"')
2673 * Scan quoted name...
2678 for (end
= ptr
; *end
; end
++)
2685 * Scan space or comma-delimited name...
2688 for (end
= ptr
; *end
; end
++)
2689 if (isspace(*end
& 255) || *end
== ',')
2694 * Terminate the name...
2704 attr
->values
[i
].string
.text
= strdup(ptr
);
2707 * Advance to the next name...
2715 * Do the request and get back a response...
2718 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2720 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2722 puts("Status: 401\n");
2725 else if (cupsLastError() > IPP_OK_CONFLICT
)
2727 cgiStartHTML(cgiText(_("Set Allowed Users")));
2728 cgiShowIPPError(_("Unable to change printer:"));
2733 * Redirect successful updates back to the printer page...
2736 char url
[1024], /* Printer/class URL */
2737 refresh
[1024]; /* Refresh URL */
2740 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2741 cgiFormEncode(uri
, url
, sizeof(uri
));
2742 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2744 cgiSetVariable("refresh_page", refresh
);
2746 cgiStartHTML(cgiText(_("Set Allowed Users")));
2748 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2749 "printer-modified.tmpl");
2758 * 'do_set_options()' - Configure the default options for a queue.
2762 do_set_options(http_t
*http
, /* I - HTTP connection */
2763 int is_class
) /* I - Set options for class? */
2765 int i
, j
, k
, m
; /* Looping vars */
2766 int have_options
; /* Have options? */
2767 ipp_t
*request
, /* IPP request */
2768 *response
; /* IPP response */
2769 ipp_attribute_t
*attr
; /* IPP attribute */
2770 char uri
[HTTP_MAX_URI
]; /* Job URI */
2771 const char *var
; /* Variable value */
2772 const char *printer
; /* Printer printer name */
2773 const char *filename
; /* PPD filename */
2774 char tempfile
[1024]; /* Temporary filename */
2775 cups_file_t
*in
, /* Input file */
2776 *out
; /* Output file */
2777 char line
[1024]; /* Line from PPD file */
2778 char keyword
[1024], /* Keyword from Default line */
2779 *keyptr
; /* Pointer into keyword... */
2780 ppd_file_t
*ppd
; /* PPD file */
2781 ppd_group_t
*group
; /* Option group */
2782 ppd_option_t
*option
; /* Option */
2783 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
2784 const char *title
; /* Page title */
2787 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2789 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2793 * Get the printer name...
2796 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2797 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2798 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2802 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2803 cgiStartHTML(title
);
2804 cgiCopyTemplateLang("error.tmpl");
2809 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2812 * Get the PPD file...
2818 filename
= cupsGetPPD2(http
, printer
);
2822 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2824 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2826 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2827 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2828 cgiStartHTML(title
);
2829 cgiCopyTemplateLang("error.tmpl");
2836 fputs("DEBUG: No PPD file\n", stderr
);
2840 if (cgiGetVariable("job_sheets_start") != NULL
||
2841 cgiGetVariable("job_sheets_end") != NULL
)
2848 ppdMarkDefaults(ppd
);
2850 DEBUG_printf(("<P>ppd->num_groups = %d\n"
2851 "<UL>\n", ppd
->num_groups
));
2853 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2855 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
2857 for (j
= group
->num_options
, option
= group
->options
;
2860 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2862 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
2864 ppdMarkOption(ppd
, option
->keyword
, var
);
2868 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
2871 DEBUG_puts("</UL></LI>");
2874 DEBUG_printf(("</UL>\n"
2875 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
2878 if (!have_options
|| ppdConflicts(ppd
))
2881 * Show the options to the user...
2884 fputs("DEBUG: Showing options...\n", stderr
);
2886 cgiStartHTML(cgiText(_("Set Printer Options")));
2887 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2893 if (ppdConflicts(ppd
))
2895 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
2898 for (j
= group
->num_options
, option
= group
->options
;
2901 if (option
->conflicted
)
2903 cgiSetArray("ckeyword", k
, option
->keyword
);
2904 cgiSetArray("ckeytext", k
, option
->text
);
2908 cgiCopyTemplateLang("option-conflict.tmpl");
2911 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2915 if (!strcmp(group
->name
, "InstallableOptions"))
2916 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2918 cgiSetVariable("GROUP", group
->text
);
2920 cgiCopyTemplateLang("option-header.tmpl");
2922 for (j
= group
->num_options
, option
= group
->options
;
2926 if (!strcmp(option
->keyword
, "PageRegion"))
2929 cgiSetVariable("KEYWORD", option
->keyword
);
2930 cgiSetVariable("KEYTEXT", option
->text
);
2932 if (option
->conflicted
)
2933 cgiSetVariable("CONFLICTED", "1");
2935 cgiSetVariable("CONFLICTED", "0");
2937 cgiSetSize("CHOICES", 0);
2938 cgiSetSize("TEXT", 0);
2939 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
2942 * Hide custom option values...
2945 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
2948 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
2949 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
2953 if (option
->choices
[k
].marked
)
2954 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
2959 case PPD_UI_BOOLEAN
:
2960 cgiCopyTemplateLang("option-boolean.tmpl");
2962 case PPD_UI_PICKONE
:
2963 cgiCopyTemplateLang("option-pickone.tmpl");
2965 case PPD_UI_PICKMANY
:
2966 cgiCopyTemplateLang("option-pickmany.tmpl");
2971 cgiCopyTemplateLang("option-trailer.tmpl");
2976 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
2977 * following attributes:
2979 * attributes-charset
2980 * attributes-natural-language
2984 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2986 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2987 "localhost", 0, "/printers/%s", printer
);
2988 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2992 * Do the request and get back a response...
2995 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2997 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
2998 IPP_TAG_ZERO
)) != NULL
)
3001 * Add the job sheets options...
3004 cgiSetVariable("GROUP", cgiText(_("Banners")));
3005 cgiCopyTemplateLang("option-header.tmpl");
3007 cgiSetSize("CHOICES", attr
->num_values
);
3008 cgiSetSize("TEXT", attr
->num_values
);
3009 for (k
= 0; k
< attr
->num_values
; k
++)
3011 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3012 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3015 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3017 cgiSetVariable("KEYWORD", "job_sheets_start");
3018 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3019 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3020 attr
->values
[0].string
.text
: "");
3022 cgiCopyTemplateLang("option-pickone.tmpl");
3024 cgiSetVariable("KEYWORD", "job_sheets_end");
3025 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3026 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3027 attr
->values
[1].string
.text
: "");
3029 cgiCopyTemplateLang("option-pickone.tmpl");
3031 cgiCopyTemplateLang("option-trailer.tmpl");
3034 if (ippFindAttribute(response
, "printer-error-policy-supported",
3036 ippFindAttribute(response
, "printer-op-policy-supported",
3040 * Add the error and operation policy options...
3043 cgiSetVariable("GROUP", cgiText(_("Policies")));
3044 cgiCopyTemplateLang("option-header.tmpl");
3050 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3055 cgiSetSize("CHOICES", attr
->num_values
);
3056 cgiSetSize("TEXT", attr
->num_values
);
3057 for (k
= 0; k
< attr
->num_values
; k
++)
3059 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3060 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3063 attr
= ippFindAttribute(response
, "printer-error-policy",
3066 cgiSetVariable("KEYWORD", "printer_error_policy");
3067 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3068 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3069 "" : attr
->values
[0].string
.text
);
3072 cgiCopyTemplateLang("option-pickone.tmpl");
3075 * Operation policy...
3078 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3083 cgiSetSize("CHOICES", attr
->num_values
);
3084 cgiSetSize("TEXT", attr
->num_values
);
3085 for (k
= 0; k
< attr
->num_values
; k
++)
3087 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3088 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3091 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3093 cgiSetVariable("KEYWORD", "printer_op_policy");
3094 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3095 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3096 "" : attr
->values
[0].string
.text
);
3098 cgiCopyTemplateLang("option-pickone.tmpl");
3101 cgiCopyTemplateLang("option-trailer.tmpl");
3104 ippDelete(response
);
3108 * Binary protocol support...
3111 if (ppd
&& ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
3113 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
3115 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
3116 cgiCopyTemplateLang("option-header.tmpl");
3118 cgiSetSize("CHOICES", 2);
3119 cgiSetSize("TEXT", 2);
3120 cgiSetArray("CHOICES", 0, "None");
3121 cgiSetArray("TEXT", 0, cgiText(_("None")));
3123 if (strstr(ppd
->protocols
, "TBCP"))
3125 cgiSetArray("CHOICES", 1, "TBCP");
3126 cgiSetArray("TEXT", 1, "TBCP");
3130 cgiSetArray("CHOICES", 1, "BCP");
3131 cgiSetArray("TEXT", 1, "BCP");
3134 cgiSetVariable("KEYWORD", "protocol");
3135 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
3136 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
3138 cgiCopyTemplateLang("option-pickone.tmpl");
3140 cgiCopyTemplateLang("option-trailer.tmpl");
3143 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3149 * Set default options...
3152 fputs("DEBUG: Setting options...\n", stderr
);
3156 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3157 in
= cupsFileOpen(filename
, "r");
3161 cgiSetVariable("ERROR", strerror(errno
));
3162 cgiStartHTML(cgiText(_("Set Printer Options")));
3163 cgiCopyTemplateLang("error.tmpl");
3179 while (cupsFileGets(in
, line
, sizeof(line
)))
3181 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3183 else if (strncmp(line
, "*Default", 8))
3184 cupsFilePrintf(out
, "%s\n", line
);
3188 * Get default option name...
3191 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3193 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3194 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3199 if (!strcmp(keyword
, "PageRegion") ||
3200 !strcmp(keyword
, "PaperDimension") ||
3201 !strcmp(keyword
, "ImageableArea"))
3202 var
= cgiGetVariable("PageSize");
3204 var
= cgiGetVariable(keyword
);
3207 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3209 cupsFilePrintf(out
, "%s\n", line
);
3213 if ((var
= cgiGetVariable("protocol")) != NULL
)
3214 cupsFilePrintf(out
, "*cupsProtocol: %s\n", var
);
3222 * Make sure temporary filename is cleared when there is no PPD...
3229 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3230 * following attributes:
3232 * attributes-charset
3233 * attributes-natural-language
3235 * job-sheets-default
3236 * printer-error-policy
3241 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3242 CUPS_ADD_MODIFY_PRINTER
);
3244 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3247 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3248 "job-sheets-default", 2, NULL
, NULL
);
3249 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3250 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3252 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3253 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3254 "printer-error-policy", NULL
, var
);
3256 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3257 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3258 "printer-op-policy", NULL
, var
);
3261 * Do the request and get back a response...
3265 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3267 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3269 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3271 puts("Status: 401\n");
3274 else if (cupsLastError() > IPP_OK_CONFLICT
)
3276 cgiStartHTML(title
);
3277 cgiShowIPPError(_("Unable to set options:"));
3282 * Redirect successful updates back to the printer page...
3285 char refresh
[1024]; /* Refresh URL */
3288 cgiFormEncode(uri
, printer
, sizeof(uri
));
3289 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3290 is_class
? "classes" : "printers", uri
);
3291 cgiSetVariable("refresh_page", refresh
);
3293 cgiStartHTML(title
);
3295 cgiCopyTemplateLang("printer-configured.tmpl");
3310 * 'do_set_sharing()' - Set printer-is-shared value...
3314 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3316 ipp_t
*request
, /* IPP request */
3317 *response
; /* IPP response */
3318 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3319 const char *printer
, /* Printer name */
3320 *is_class
, /* Is a class? */
3321 *shared
; /* Sharing value */
3324 is_class
= cgiGetVariable("IS_CLASS");
3325 printer
= cgiGetVariable("PRINTER_NAME");
3326 shared
= cgiGetVariable("SHARED");
3328 if (!printer
|| !shared
)
3330 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3331 cgiStartHTML(cgiText(_("Set Publishing")));
3332 cgiCopyTemplateLang("error.tmpl");
3338 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3339 * following attributes:
3341 * attributes-charset
3342 * attributes-natural-language
3347 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3349 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3350 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3352 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3355 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3358 * Do the request and get back a response...
3361 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3363 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3365 ippDelete(response
);
3368 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3370 puts("Status: 401\n");
3373 else if (cupsLastError() > IPP_OK_CONFLICT
)
3375 cgiStartHTML(cgiText(_("Set Publishing")));
3376 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3381 * Redirect successful updates back to the printer page...
3384 char url
[1024], /* Printer/class URL */
3385 refresh
[1024]; /* Refresh URL */
3388 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3389 cgiFormEncode(uri
, url
, sizeof(uri
));
3390 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3391 cgiSetVariable("refresh_page", refresh
);
3393 cgiStartHTML(cgiText(_("Set Publishing")));
3394 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3395 "printer-modified.tmpl");
3403 * 'match_string()' - Return the number of matching characters.
3406 static int /* O - Number of matching characters */
3407 match_string(const char *a
, /* I - First string */
3408 const char *b
) /* I - Second string */
3410 int count
; /* Number of matching characters */
3414 * Loop through both strings until we hit the end of either or we find
3415 * a non-matching character. For the purposes of comparison, we ignore
3416 * whitespace and do a case-insensitive comparison so that we have a
3417 * better chance of finding a match...
3420 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
3423 * Skip leading whitespace characters...
3426 while (isspace(*a
& 255))
3429 while (isspace(*b
& 255))
3433 * Break out if we run out of characters...
3440 * Do a case-insensitive comparison of the next two chars...
3443 if (tolower(*a
& 255) != tolower(*b
& 255))
3452 * End of "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $".