4 * Administration CGI for CUPS.
6 * Copyright 2007-2015 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 * Include necessary headers...
20 #include "cgi-private.h"
21 #include <cups/http-private.h>
22 #include <cups/ppd-private.h>
23 #include <cups/adminutil.h>
36 static int current_device
= 0; /* Current device shown */
43 static void choose_device_cb(const char *device_class
, const char *device_id
, const char *device_info
, const char *device_make_and_model
, const char *device_uri
, const char *device_location
, const char *title
);
44 static void do_add_rss_subscription(http_t
*http
);
45 static void do_am_class(http_t
*http
, int modify
);
46 static void do_am_printer(http_t
*http
, int modify
);
47 static void do_cancel_subscription(http_t
*http
);
48 static void do_config_server(http_t
*http
);
49 static void do_delete_class(http_t
*http
);
50 static void do_delete_printer(http_t
*http
);
51 static void do_export(http_t
*http
);
52 static void do_list_printers(http_t
*http
);
53 static void do_menu(http_t
*http
);
54 static void do_set_allowed_users(http_t
*http
);
55 static void do_set_default(http_t
*http
);
56 static void do_set_options(http_t
*http
, int is_class
);
57 static void do_set_sharing(http_t
*http
);
58 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
59 char *buffer
, size_t bufsize
);
60 static double get_points(double number
, const char *uval
);
61 static char *get_printer_ppd(const char *uri
, char *buffer
, size_t bufsize
);
65 * 'main()' - Main entry for CGI.
68 int /* O - Exit status */
71 http_t
*http
; /* Connection to the server */
72 const char *op
; /* Operation name */
76 * Connect to the HTTP server...
79 fputs("DEBUG: admin.cgi started...\n", stderr
);
81 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
85 perror("ERROR: Unable to connect to cupsd");
86 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
87 cupsServer() ? cupsServer() : "(null)");
88 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
89 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
93 fprintf(stderr
, "DEBUG: http=%p\n", http
);
96 * Set the web interface section...
99 cgiSetVariable("SECTION", "admin");
100 cgiSetVariable("REFRESH_PAGE", "");
103 * See if we have form data...
106 if (!cgiInitialize() || !cgiGetVariable("OP"))
109 * Nope, send the administration menu...
112 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
116 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
119 * Do the operation...
122 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
126 const char *printer
= getenv("PRINTER_NAME"),
127 /* Printer or class name */
128 *server_port
= getenv("SERVER_PORT");
129 /* Port number string */
130 int port
= atoi(server_port
? server_port
: "0");
132 char uri
[1024]; /* URL */
135 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
136 getenv("HTTPS") ? "https" : "http", NULL
,
137 getenv("SERVER_NAME"), port
, "/%s/%s",
138 cgiGetVariable("IS_CLASS") ? "classes" : "printers",
141 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
142 getenv("HTTPS") ? "https" : "http", NULL
,
143 getenv("SERVER_NAME"), port
, "/admin");
145 printf("Location: %s\n\n", uri
);
147 else if (!strcmp(op
, "set-allowed-users"))
148 do_set_allowed_users(http
);
149 else if (!strcmp(op
, "set-as-default"))
150 do_set_default(http
);
151 else if (!strcmp(op
, "set-sharing"))
152 do_set_sharing(http
);
153 else if (!strcmp(op
, "find-new-printers") ||
154 !strcmp(op
, "list-available-printers"))
155 do_list_printers(http
);
156 else if (!strcmp(op
, "add-class"))
157 do_am_class(http
, 0);
158 else if (!strcmp(op
, "add-printer"))
159 do_am_printer(http
, 0);
160 else if (!strcmp(op
, "modify-class"))
161 do_am_class(http
, 1);
162 else if (!strcmp(op
, "modify-printer"))
163 do_am_printer(http
, 1);
164 else if (!strcmp(op
, "delete-class"))
165 do_delete_class(http
);
166 else if (!strcmp(op
, "delete-printer"))
167 do_delete_printer(http
);
168 else if (!strcmp(op
, "set-class-options"))
169 do_set_options(http
, 1);
170 else if (!strcmp(op
, "set-printer-options"))
171 do_set_options(http
, 0);
172 else if (!strcmp(op
, "config-server"))
173 do_config_server(http
);
174 else if (!strcmp(op
, "export-samba"))
176 else if (!strcmp(op
, "add-rss-subscription"))
177 do_add_rss_subscription(http
);
178 else if (!strcmp(op
, "cancel-subscription"))
179 do_cancel_subscription(http
);
183 * Bad operation code - display an error...
186 cgiStartHTML(cgiText(_("Administration")));
187 cgiCopyTemplateLang("error-op.tmpl");
191 else if (op
&& !strcmp(op
, "redirect"))
193 const char *url
; /* Redirection URL... */
194 char prefix
[1024]; /* URL prefix */
198 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
199 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
201 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
202 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
204 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
206 if ((url
= cgiGetVariable("URL")) != NULL
)
208 char encoded
[1024], /* Encoded URL string */
209 *ptr
; /* Pointer into encoded string */
216 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
218 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
221 * Percent-encode this character; safe because we have at least 4
222 * bytes left in the array...
225 sprintf(ptr
, "%%%02X", *url
& 255);
237 * URL was too long, just redirect to the admin page...
240 printf("Location: %s/admin\n\n", prefix
);
245 * URL is OK, redirect there...
248 printf("Location: %s%s\n\n", prefix
, encoded
);
252 printf("Location: %s/admin\n\n", prefix
);
257 * Form data but no operation code - display an error...
260 cgiStartHTML(cgiText(_("Administration")));
261 cgiCopyTemplateLang("error-op.tmpl");
266 * Close the HTTP server connection...
272 * Return with no errors...
280 * 'choose_device_cb()' - Add a device to the device selection page.
285 const char *device_class
, /* I - Class */
286 const char *device_id
, /* I - 1284 device ID */
287 const char *device_info
, /* I - Description */
288 const char *device_make_and_model
, /* I - Make and model */
289 const char *device_uri
, /* I - Device URI */
290 const char *device_location
, /* I - Location */
291 const char *title
) /* I - Page title */
294 * For modern browsers, start a multi-part page so we can show that something
295 * is happening. Non-modern browsers just get everything at the end...
298 if (current_device
== 0 && cgiSupportsMultipart())
302 cgiCopyTemplateLang("choose-device.tmpl");
309 * Add the device to the array...
312 cgiSetArray("device_class", current_device
, device_class
);
313 cgiSetArray("device_id", current_device
, device_id
);
314 cgiSetArray("device_info", current_device
, device_info
);
315 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
316 cgiSetArray("device_uri", current_device
, device_uri
);
317 cgiSetArray("device_location", current_device
, device_location
);
324 * 'do_add_rss_subscription()' - Add a RSS subscription.
328 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
330 ipp_t
*request
, /* IPP request data */
331 *response
; /* IPP response data */
332 char rss_uri
[1024]; /* RSS notify-recipient URI */
333 int num_events
; /* Number of events */
334 const char *events
[12], /* Subscribed events */
335 *subscription_name
, /* Subscription name */
336 *printer_uri
, /* Printer URI */
337 *ptr
, /* Pointer into name */
338 *user
; /* Username */
339 int max_events
; /* Maximum number of events */
343 * See if we have all of the required information...
346 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
347 printer_uri
= cgiGetVariable("PRINTER_URI");
350 if (cgiGetVariable("EVENT_JOB_CREATED"))
351 events
[num_events
++] = "job-created";
352 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
353 events
[num_events
++] = "job-completed";
354 if (cgiGetVariable("EVENT_JOB_STOPPED"))
355 events
[num_events
++] = "job-stopped";
356 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
357 events
[num_events
++] = "job-config-changed";
358 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
359 events
[num_events
++] = "printer-stopped";
360 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
361 events
[num_events
++] = "printer-added";
362 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
363 events
[num_events
++] = "printer-modified";
364 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
365 events
[num_events
++] = "printer-deleted";
366 if (cgiGetVariable("EVENT_SERVER_STARTED"))
367 events
[num_events
++] = "server-started";
368 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
369 events
[num_events
++] = "server-stopped";
370 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
371 events
[num_events
++] = "server-restarted";
372 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
373 events
[num_events
++] = "server-audit";
375 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
376 max_events
= atoi(ptr
);
380 if (!subscription_name
|| !printer_uri
|| !num_events
||
381 max_events
<= 0 || max_events
> 9999)
384 * Don't have everything we need, so get the available printers
385 * and classes and (re)show the add page...
388 if (cgiGetVariable("EVENT_JOB_CREATED"))
389 cgiSetVariable("EVENT_JOB_CREATED", "CHECKED");
390 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
391 cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED");
392 if (cgiGetVariable("EVENT_JOB_STOPPED"))
393 cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED");
394 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
395 cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED");
396 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
397 cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED");
398 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
399 cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED");
400 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
401 cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED");
402 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
403 cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED");
404 if (cgiGetVariable("EVENT_SERVER_STARTED"))
405 cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED");
406 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
407 cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED");
408 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
409 cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED");
410 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
411 cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED");
413 request
= ippNewRequest(CUPS_GET_PRINTERS
);
414 response
= cupsDoRequest(http
, request
, "/");
416 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
420 cgiStartHTML(cgiText(_("Add RSS Subscription")));
422 cgiCopyTemplateLang("add-rss-subscription.tmpl");
429 * Make sure we have a username...
432 if ((user
= getenv("REMOTE_USER")) == NULL
)
434 puts("Status: 401\n");
439 * Validate the subscription name...
442 for (ptr
= subscription_name
; *ptr
; ptr
++)
443 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
444 *ptr
== '?' || *ptr
== '#')
449 cgiSetVariable("ERROR",
450 cgiText(_("The subscription name may not "
451 "contain spaces, slashes (/), question marks (?), "
452 "or the pound sign (#).")));
453 cgiStartHTML(_("Add RSS Subscription"));
454 cgiCopyTemplateLang("error.tmpl");
460 * Add the subscription...
463 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
464 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
465 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
466 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
469 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
470 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
473 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
475 if (!_cups_strcasecmp(printer_uri
, "#ALL#"))
476 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
477 NULL
, "ipp://localhost/");
479 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
482 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
485 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
486 "notify-recipient-uri", NULL
, rss_uri
);
487 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
488 num_events
, NULL
, events
);
489 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
490 "notify-lease-duration", 0);
492 ippDelete(cupsDoRequest(http
, request
, "/"));
494 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
496 puts("Status: 401\n");
499 else if (cupsLastError() > IPP_OK_CONFLICT
)
501 cgiStartHTML(_("Add RSS Subscription"));
502 cgiShowIPPError(_("Unable to add RSS subscription"));
507 * Redirect successful updates back to the admin page...
510 cgiSetVariable("refresh_page", "5;URL=/admin");
511 cgiStartHTML(_("Add RSS Subscription"));
512 cgiCopyTemplateLang("subscription-added.tmpl");
520 * 'do_am_class()' - Add or modify a class.
524 do_am_class(http_t
*http
, /* I - HTTP connection */
525 int modify
) /* I - Modify the printer? */
527 int i
, j
; /* Looping vars */
528 int element
; /* Element number */
529 int num_printers
; /* Number of printers */
530 ipp_t
*request
, /* IPP request */
531 *response
; /* IPP response */
532 ipp_attribute_t
*attr
; /* member-uris attribute */
533 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
534 const char *name
, /* Pointer to class name */
535 *op
, /* Operation name */
536 *ptr
; /* Pointer to CGI variable */
537 const char *title
; /* Title of page */
538 static const char * const pattrs
[] = /* Requested printer attributes */
546 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
547 op
= cgiGetVariable("OP");
548 name
= cgiGetVariable("PRINTER_NAME");
550 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
553 * Build a CUPS_GET_PRINTERS request, which requires the
554 * following attributes:
557 * attributes-natural-language
560 request
= ippNewRequest(CUPS_GET_PRINTERS
);
562 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
564 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
565 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
568 * Do the request and get back a response...
573 cgiSetVariable("OP", op
);
575 cgiSetVariable("PRINTER_NAME", name
);
577 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
580 * Create MEMBER_URIS and MEMBER_NAMES arrays...
583 for (element
= 0, attr
= response
->attrs
;
586 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
588 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
589 (!name
|| _cups_strcasecmp(name
, ptr
+ 1)))
592 * Don't show the current class...
595 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
600 for (element
= 0, attr
= response
->attrs
;
603 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
605 if (!name
|| _cups_strcasecmp(name
, attr
->values
[0].string
.text
))
608 * Don't show the current class...
611 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
616 num_printers
= cgiGetSize("MEMBER_URIS");
626 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
627 * following attributes:
630 * attributes-natural-language
634 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
636 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
637 "localhost", 0, "/classes/%s", name
);
638 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
641 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
642 "requested-attributes",
643 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
647 * Do the request and get back a response...
650 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
652 if ((attr
= ippFindAttribute(response
, "member-names",
653 IPP_TAG_NAME
)) != NULL
)
656 * Mark any current members in the class...
659 for (j
= 0; j
< num_printers
; j
++)
660 cgiSetArray("MEMBER_SELECTED", j
, "");
662 for (i
= 0; i
< attr
->num_values
; i
++)
664 for (j
= 0; j
< num_printers
; j
++)
666 if (!_cups_strcasecmp(attr
->values
[i
].string
.text
,
667 cgiGetArray("MEMBER_NAMES", j
)))
669 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
676 if ((attr
= ippFindAttribute(response
, "printer-info",
677 IPP_TAG_TEXT
)) != NULL
)
678 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
680 if ((attr
= ippFindAttribute(response
, "printer-location",
681 IPP_TAG_TEXT
)) != NULL
)
682 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
688 * Update the location and description of an existing printer...
692 cgiCopyTemplateLang("modify-class.tmpl");
697 * Get the name, location, and description for a new printer...
701 cgiCopyTemplateLang("add-class.tmpl");
712 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
713 cgiCopyTemplateLang("error.tmpl");
718 for (ptr
= name
; *ptr
; ptr
++)
719 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
722 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
724 cgiSetVariable("ERROR",
725 cgiText(_("The class name may only contain up to "
726 "127 printable characters and may not "
727 "contain spaces, slashes (/), or the "
728 "pound sign (#).")));
730 cgiCopyTemplateLang("error.tmpl");
736 * Build a CUPS_ADD_CLASS request, which requires the following
740 * attributes-natural-language
744 * printer-is-accepting-jobs
749 request
= ippNewRequest(CUPS_ADD_CLASS
);
751 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
752 "localhost", 0, "/classes/%s", name
);
753 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
756 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
757 NULL
, cgiGetVariable("PRINTER_LOCATION"));
759 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
760 NULL
, cgiGetVariable("PRINTER_INFO"));
762 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
764 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
767 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
769 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
770 num_printers
, NULL
, NULL
);
771 for (i
= 0; i
< num_printers
; i
++)
772 attr
->values
[i
].string
.text
= _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i
));
776 * Do the request and get back a response...
779 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
781 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
783 puts("Status: 401\n");
786 else if (cupsLastError() > IPP_OK_CONFLICT
)
789 cgiShowIPPError(modify
? _("Unable to modify class") :
790 _("Unable to add class"));
795 * Redirect successful updates back to the class page...
798 char refresh
[1024]; /* Refresh URL */
800 cgiFormEncode(uri
, name
, sizeof(uri
));
801 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
803 cgiSetVariable("refresh_page", refresh
);
808 cgiCopyTemplateLang("class-modified.tmpl");
810 cgiCopyTemplateLang("class-added.tmpl");
818 * 'do_am_printer()' - Add or modify a printer.
822 do_am_printer(http_t
*http
, /* I - HTTP connection */
823 int modify
) /* I - Modify the printer? */
825 int i
; /* Looping var */
826 ipp_attribute_t
*attr
; /* Current attribute */
827 ipp_t
*request
, /* IPP request */
828 *response
, /* IPP response */
829 *oldinfo
; /* Old printer information */
830 const cgi_file_t
*file
; /* Uploaded file, if any */
831 const char *var
; /* CGI variable */
832 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
833 *uriptr
, /* Pointer into URI */
834 evefile
[1024] = ""; /* IPP Everywhere PPD file */
835 int maxrate
; /* Maximum baud rate */
836 char baudrate
[255]; /* Baud rate string */
837 const char *name
, /* Pointer to class name */
838 *ptr
; /* Pointer to CGI variable */
839 const char *title
; /* Title of page */
840 static int baudrates
[] = /* Baud rates */
855 ptr
= cgiGetVariable("DEVICE_URI");
856 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
857 ptr
? ptr
: "(null)");
859 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
864 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
865 * following attributes:
868 * attributes-natural-language
872 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
874 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
875 "localhost", 0, "/printers/%s",
876 cgiGetVariable("PRINTER_NAME"));
877 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
881 * Do the request and get back a response...
884 oldinfo
= cupsDoRequest(http
, request
, "/");
893 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
894 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
895 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
896 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
899 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
901 for (ptr
= name
; *ptr
; ptr
++)
902 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
905 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
907 cgiSetVariable("ERROR",
908 cgiText(_("The printer name may only contain up to "
909 "127 printable characters and may not "
910 "contain spaces, slashes (/), or the "
911 "pound sign (#).")));
913 cgiCopyTemplateLang("error.tmpl");
919 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
921 if ((uriptr
= strrchr(var
, '|')) != NULL
)
924 * Extract make and make/model from device URI string...
927 char make
[1024], /* Make string */
928 *makeptr
; /* Pointer into make */
933 strlcpy(make
, uriptr
, sizeof(make
));
935 if ((makeptr
= strchr(make
, ' ')) != NULL
)
937 else if ((makeptr
= strchr(make
, '-')) != NULL
)
939 else if (!_cups_strncasecmp(make
, "laserjet", 8) ||
940 !_cups_strncasecmp(make
, "deskjet", 7) ||
941 !_cups_strncasecmp(make
, "designjet", 9))
942 strlcpy(make
, "HP", sizeof(make
));
943 else if (!_cups_strncasecmp(make
, "phaser", 6))
944 strlcpy(make
, "Xerox", sizeof(make
));
945 else if (!_cups_strncasecmp(make
, "stylus", 6))
946 strlcpy(make
, "Epson", sizeof(make
));
948 strlcpy(make
, "Generic", sizeof(make
));
950 if (!cgiGetVariable("CURRENT_MAKE"))
951 cgiSetVariable("CURRENT_MAKE", make
);
953 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
954 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
958 char template[128], /* Template name */
959 *tptr
; /* Pointer into template name */
961 cgiSetVariable("PRINTER_INFO", uriptr
);
963 for (tptr
= template;
964 tptr
< (template + sizeof(template) - 1) && *uriptr
;
966 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
969 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
972 else if (*uriptr
== '?' || *uriptr
== '(')
977 cgiSetVariable("TEMPLATE_NAME", template);
985 * Look for devices so the user can pick something...
988 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
990 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
991 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
994 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
995 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
999 * Scan for devices for up to 30 seconds...
1002 fputs("DEBUG: Getting list of devices...\n", stderr
);
1005 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
1006 (cups_device_cb_t
)choose_device_cb
,
1007 (void *)title
) == IPP_OK
)
1009 fputs("DEBUG: Got device list!\n", stderr
);
1011 if (cgiSupportsMultipart())
1012 cgiStartMultipart();
1014 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1015 cgiStartHTML(title
);
1016 cgiCopyTemplateLang("choose-device.tmpl");
1019 if (cgiSupportsMultipart())
1025 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1026 cupsLastError(), cupsLastErrorString());
1027 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1029 puts("Status: 401\n");
1034 cgiStartHTML(title
);
1035 cgiShowIPPError(modify
? _("Unable to modify printer") :
1036 _("Unable to add printer"));
1042 else if (!strchr(var
, '/') ||
1043 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
1045 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
1048 * Set the current device URI for the form to the old one...
1051 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
1052 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
1056 * User needs to set the full URI...
1059 cgiStartHTML(title
);
1060 cgiCopyTemplateLang("choose-uri.tmpl");
1063 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1066 * Need baud rate, parity, etc.
1069 if ((var
= strchr(var
, '?')) != NULL
&&
1070 strncmp(var
, "?baud=", 6) == 0)
1071 maxrate
= atoi(var
+ 6);
1075 for (i
= 0; i
< 10; i
++)
1076 if (baudrates
[i
] > maxrate
)
1080 sprintf(baudrate
, "%d", baudrates
[i
]);
1081 cgiSetArray("BAUDRATES", i
, baudrate
);
1084 cgiStartHTML(title
);
1085 cgiCopyTemplateLang("choose-serial.tmpl");
1088 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
1090 cgiStartHTML(title
);
1095 * Update the location and description of an existing printer...
1100 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
1101 IPP_TAG_TEXT
)) != NULL
)
1102 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
1104 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
1105 IPP_TAG_TEXT
)) != NULL
)
1106 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
1108 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
1109 IPP_TAG_BOOLEAN
)) != NULL
)
1110 cgiSetVariable("PRINTER_IS_SHARED",
1111 attr
->values
[0].boolean
? "1" : "0");
1114 cgiCopyTemplateLang("modify-printer.tmpl");
1119 * Get the name, location, and description for a new printer...
1123 if (!strncmp(var
, "usb:", 4))
1124 cgiSetVariable("printer_is_shared", "1");
1126 #endif /* __APPLE__ */
1127 cgiSetVariable("printer_is_shared", "0");
1129 cgiCopyTemplateLang("add-printer.tmpl");
1140 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1142 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
1145 * Get the PPD file...
1148 int fd
; /* PPD file */
1149 char filename
[1024]; /* PPD filename */
1150 ppd_file_t
*ppd
; /* PPD information */
1151 char buffer
[1024]; /* Buffer */
1152 ssize_t bytes
; /* Number of bytes */
1153 http_status_t get_status
; /* Status of GET */
1156 /* TODO: Use cupsGetFile() API... */
1157 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
1159 if (httpGet(http
, uri
))
1162 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
1164 if (get_status
!= HTTP_OK
)
1168 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
1169 uri
, get_status
, httpStatus(get_status
));
1171 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
1173 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
1174 write(fd
, buffer
, (size_t)bytes
);
1178 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
1180 if (ppd
->manufacturer
)
1181 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
1184 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
1191 int linenum
; /* Line number */
1193 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
1194 filename
, ppdErrorString(ppdLastError(&linenum
)));
1202 "ERROR: Unable to create temporary file for PPD file: %s\n",
1208 * Build a CUPS_GET_PPDS request, which requires the following
1211 * attributes-charset
1212 * attributes-natural-language
1216 request
= ippNewRequest(CUPS_GET_PPDS
);
1218 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1219 NULL
, "ipp://localhost/printers/");
1221 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1222 var
= cgiGetVariable("CURRENT_MAKE");
1223 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1225 const char *make_model
; /* Make and model */
1228 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1229 "ppd-make", NULL
, var
);
1231 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1232 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1233 "ppd-make-and-model", NULL
, make_model
);
1236 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1237 "requested-attributes", NULL
, "ppd-make");
1240 * Do the request and get back a response...
1243 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1246 * Got the list of PPDs, see if the user has selected a make...
1249 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1252 * No PPD files with this make, try again with all makes...
1255 ippDelete(response
);
1257 request
= ippNewRequest(CUPS_GET_PPDS
);
1259 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1260 NULL
, "ipp://localhost/printers/");
1262 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1263 "requested-attributes", NULL
, "ppd-make");
1265 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1266 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1268 cgiStartHTML(title
);
1269 cgiCopyTemplateLang("choose-make.tmpl");
1272 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1274 cgiStartHTML(title
);
1275 cgiCopyTemplateLang("choose-make.tmpl");
1281 * Let the user choose a model...
1284 cgiStartHTML(title
);
1285 if (!cgiGetVariable("PPD_MAKE"))
1286 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1288 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1289 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1290 cgiCopyTemplateLang("choose-model.tmpl");
1294 ippDelete(response
);
1298 cgiStartHTML(title
);
1299 cgiShowIPPError(_("Unable to get list of printer drivers"));
1300 cgiCopyTemplateLang("error.tmpl");
1307 * Build a CUPS_ADD_PRINTER request, which requires the following
1310 * attributes-charset
1311 * attributes-natural-language
1317 * printer-is-accepting-jobs
1322 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1324 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1325 "localhost", 0, "/printers/%s",
1326 cgiGetVariable("PRINTER_NAME"));
1327 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1332 var
= cgiGetVariable("PPD_NAME");
1333 if (!strcmp(var
, "everywhere"))
1334 get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile
, sizeof(evefile
));
1335 else if (strcmp(var
, "__no_change__"))
1336 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name",
1340 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1341 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1343 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1344 NULL
, cgiGetVariable("PRINTER_INFO"));
1346 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1349 * Strip make and model from URI...
1352 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1355 if (!strncmp(uri
, "serial:", 7))
1358 * Update serial port URI to include baud rate, etc.
1361 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1362 uriptr
= uri
+ strlen(uri
);
1364 snprintf(uriptr
, sizeof(uri
) - (size_t)(uriptr
- uri
),
1365 "?baud=%s+bits=%s+parity=%s+flow=%s",
1366 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1367 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1370 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1373 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1375 var
= cgiGetVariable("printer_is_shared");
1376 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1377 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1379 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1383 * Do the request and get back a response...
1387 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1388 else if (evefile
[0])
1390 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", evefile
));
1394 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1396 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1398 puts("Status: 401\n");
1401 else if (cupsLastError() > IPP_OK_CONFLICT
)
1403 cgiStartHTML(title
);
1404 cgiShowIPPError(modify
? _("Unable to modify printer") :
1405 _("Unable to add printer"));
1410 * Redirect successful updates back to the printer page...
1413 char refresh
[1024]; /* Refresh URL */
1416 cgiFormEncode(uri
, name
, sizeof(uri
));
1418 snprintf(refresh
, sizeof(refresh
),
1419 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1421 cgiSetVariable("refresh_page", refresh
);
1423 cgiStartHTML(title
);
1425 cgiCopyTemplateLang("printer-modified.tmpl");
1430 * Set the printer options...
1433 cgiSetVariable("OP", "set-printer-options");
1434 do_set_options(http
, 0);
1447 * 'do_cancel_subscription()' - Cancel a subscription.
1451 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1453 ipp_t
*request
; /* IPP request data */
1454 const char *var
, /* Form variable */
1455 *user
; /* Username */
1456 int id
; /* Subscription ID */
1460 * See if we have all of the required information...
1463 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1470 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1471 cgiStartHTML(_("Cancel RSS Subscription"));
1472 cgiCopyTemplateLang("error.tmpl");
1478 * Require a username...
1481 if ((user
= getenv("REMOTE_USER")) == NULL
)
1483 puts("Status: 401\n");
1488 * Cancel the subscription...
1491 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1493 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1494 NULL
, "ipp://localhost/");
1495 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1496 "notify-subscription-id", id
);
1498 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1501 ippDelete(cupsDoRequest(http
, request
, "/"));
1503 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1505 puts("Status: 401\n");
1508 else if (cupsLastError() > IPP_OK_CONFLICT
)
1510 cgiStartHTML(_("Cancel RSS Subscription"));
1511 cgiShowIPPError(_("Unable to cancel RSS subscription"));
1516 * Redirect successful updates back to the admin page...
1519 cgiSetVariable("refresh_page", "5;URL=/admin");
1520 cgiStartHTML(_("Cancel RSS Subscription"));
1521 cgiCopyTemplateLang("subscription-canceled.tmpl");
1529 * 'do_config_server()' - Configure server settings.
1533 do_config_server(http_t
*http
) /* I - HTTP connection */
1535 if (cgiGetVariable("CHANGESETTINGS"))
1538 * Save basic setting changes...
1541 int num_settings
; /* Number of server settings */
1542 cups_option_t
*settings
; /* Server settings */
1543 int advanced
, /* Advanced settings shown? */
1544 changed
; /* Have settings changed? */
1545 const char *debug_logging
, /* DEBUG_LOGGING value */
1546 *preserve_jobs
= NULL
,
1547 /* PRESERVE_JOBS value */
1548 *remote_admin
, /* REMOTE_ADMIN value */
1549 *remote_any
, /* REMOTE_ANY value */
1550 *share_printers
,/* SHARE_PRINTERS value */
1552 /* USER_CANCEL_ANY value */
1553 *browse_web_if
= NULL
,
1554 /* BrowseWebIF value */
1555 *preserve_job_history
= NULL
,
1556 /* PreserveJobHistory value */
1557 *preserve_job_files
= NULL
,
1558 /* PreserveJobFiles value */
1559 *max_clients
= NULL
,
1560 /* MaxClients value */
1563 *max_log_size
= NULL
;
1564 /* MaxLogSize value */
1565 const char *current_browse_web_if
,
1566 /* BrowseWebIF value */
1567 *current_preserve_job_history
,
1568 /* PreserveJobHistory value */
1569 *current_preserve_job_files
,
1570 /* PreserveJobFiles value */
1571 *current_max_clients
,
1572 /* MaxClients value */
1575 *current_max_log_size
;
1576 /* MaxLogSize value */
1578 char default_auth_type
[255];
1579 /* DefaultAuthType value */
1580 const char *val
; /* Setting value */
1581 #endif /* HAVE_GSSAPI */
1585 * Get the checkbox values from the form...
1588 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1589 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1590 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1591 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1592 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1594 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1598 * Get advanced settings...
1601 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1602 max_clients
= cgiGetVariable("MAX_CLIENTS");
1603 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1604 preserve_jobs
= cgiGetVariable("PRESERVE_JOBS");
1608 max_jobs
= cgiGetVariable("MAX_JOBS");
1609 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY");
1610 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES");
1612 if (!max_jobs
|| atoi(max_jobs
) < 0)
1615 if (!preserve_job_history
)
1616 preserve_job_history
= "On";
1618 if (!preserve_job_files
)
1619 preserve_job_files
= "1d";
1624 preserve_job_history
= "No";
1625 preserve_job_files
= "No";
1628 if (!max_clients
|| atoi(max_clients
) <= 0)
1629 max_clients
= "100";
1631 if (!max_log_size
|| atoi(max_log_size
) <= 0.0)
1632 max_log_size
= "1m";
1636 * Get the current server settings...
1639 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1641 cgiStartHTML(cgiText(_("Change Settings")));
1642 cgiSetVariable("MESSAGE",
1643 cgiText(_("Unable to change server settings")));
1644 cgiSetVariable("ERROR", cupsLastErrorString());
1645 cgiCopyTemplateLang("error.tmpl");
1652 * Get authentication settings...
1655 if (cgiGetVariable("KERBEROS"))
1656 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1659 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1661 if (!val
|| !_cups_strcasecmp(val
, "Negotiate"))
1662 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1664 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1667 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1668 #endif /* HAVE_GSSAPI */
1670 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1672 current_browse_web_if
= "No";
1674 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1677 current_preserve_job_history
= "Yes";
1679 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1682 current_preserve_job_files
= "1d";
1684 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1686 current_max_clients
= "100";
1688 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1690 current_max_jobs
= "500";
1692 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1694 current_max_log_size
= "1m";
1697 * See if the settings have changed...
1700 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1701 num_settings
, settings
)) ||
1702 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1703 num_settings
, settings
)) ||
1704 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1705 num_settings
, settings
)) ||
1706 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1707 num_settings
, settings
)) ||
1709 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1710 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1711 num_settings
, settings
)) ||
1712 #endif /* HAVE_GSSAPI */
1713 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1714 num_settings
, settings
));
1716 if (advanced
&& !changed
)
1717 changed
= _cups_strcasecmp(browse_web_if
, current_browse_web_if
) ||
1718 _cups_strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1719 _cups_strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1720 _cups_strcasecmp(max_clients
, current_max_clients
) ||
1721 _cups_strcasecmp(max_jobs
, current_max_jobs
) ||
1722 _cups_strcasecmp(max_log_size
, current_max_log_size
);
1727 * Settings *have* changed, so save the changes...
1730 cupsFreeOptions(num_settings
, settings
);
1733 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1734 debug_logging
, num_settings
, &settings
);
1735 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1736 remote_admin
, num_settings
, &settings
);
1737 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1738 remote_any
, num_settings
, &settings
);
1739 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1740 share_printers
, num_settings
, &settings
);
1741 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1742 user_cancel_any
, num_settings
, &settings
);
1744 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1745 num_settings
, &settings
);
1746 #endif /* HAVE_GSSAPI */
1751 * Add advanced settings...
1754 if (_cups_strcasecmp(browse_web_if
, current_browse_web_if
))
1755 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1756 num_settings
, &settings
);
1757 if (_cups_strcasecmp(preserve_job_history
, current_preserve_job_history
))
1758 num_settings
= cupsAddOption("PreserveJobHistory",
1759 preserve_job_history
, num_settings
,
1761 if (_cups_strcasecmp(preserve_job_files
, current_preserve_job_files
))
1762 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1763 num_settings
, &settings
);
1764 if (_cups_strcasecmp(max_clients
, current_max_clients
))
1765 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1767 if (_cups_strcasecmp(max_jobs
, current_max_jobs
))
1768 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1770 if (_cups_strcasecmp(max_log_size
, current_max_log_size
))
1771 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1775 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1777 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1779 puts("Status: 401\n");
1783 cgiStartHTML(cgiText(_("Change Settings")));
1784 cgiSetVariable("MESSAGE",
1785 cgiText(_("Unable to change server settings")));
1786 cgiSetVariable("ERROR", cupsLastErrorString());
1787 cgiCopyTemplateLang("error.tmpl");
1792 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1793 "URL=/admin/?ADVANCEDSETTINGS=YES");
1795 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1796 cgiStartHTML(cgiText(_("Change Settings")));
1797 cgiCopyTemplateLang("restart.tmpl");
1806 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1807 cgiStartHTML(cgiText(_("Change Settings")));
1808 cgiCopyTemplateLang("norestart.tmpl");
1811 cupsFreeOptions(num_settings
, settings
);
1815 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1818 * Save hand-edited config file...
1821 http_status_t status
; /* PUT status */
1822 char tempfile
[1024]; /* Temporary new cupsd.conf */
1823 int tempfd
; /* Temporary file descriptor */
1824 cups_file_t
*temp
; /* Temporary file */
1825 const char *start
, /* Start of line */
1826 *end
; /* End of line */
1830 * Create a temporary file for the new cupsd.conf file...
1833 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1835 cgiStartHTML(cgiText(_("Edit Configuration File")));
1836 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1837 cgiSetVariable("ERROR", strerror(errno
));
1838 cgiCopyTemplateLang("error.tmpl");
1845 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1847 cgiStartHTML(cgiText(_("Edit Configuration File")));
1848 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1849 cgiSetVariable("ERROR", strerror(errno
));
1850 cgiCopyTemplateLang("error.tmpl");
1860 * Copy the cupsd.conf text from the form variable...
1863 start
= cgiGetVariable("CUPSDCONF");
1866 if ((end
= strstr(start
, "\r\n")) == NULL
)
1867 if ((end
= strstr(start
, "\n")) == NULL
)
1868 end
= start
+ strlen(start
);
1870 cupsFileWrite(temp
, start
, (size_t)(end
- start
));
1871 cupsFilePutChar(temp
, '\n');
1875 else if (*end
== '\n')
1881 cupsFileClose(temp
);
1884 * Upload the configuration file to the server...
1887 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1889 if (status
== HTTP_UNAUTHORIZED
)
1891 puts("Status: 401\n");
1895 else if (status
!= HTTP_CREATED
)
1897 cgiSetVariable("MESSAGE",
1898 cgiText(_("Unable to upload cupsd.conf file")));
1899 cgiSetVariable("ERROR", httpStatus(status
));
1901 cgiStartHTML(cgiText(_("Edit Configuration File")));
1902 cgiCopyTemplateLang("error.tmpl");
1906 cgiSetVariable("refresh_page", "5;URL=/admin/");
1908 cgiStartHTML(cgiText(_("Edit Configuration File")));
1909 cgiCopyTemplateLang("restart.tmpl");
1918 struct stat info
; /* cupsd.conf information */
1919 cups_file_t
*cupsd
; /* cupsd.conf file */
1920 char *buffer
, /* Buffer for entire file */
1921 *bufptr
, /* Pointer into buffer */
1922 *bufend
; /* End of buffer */
1923 int ch
; /* Character from file */
1924 char filename
[1024]; /* Filename */
1925 const char *server_root
; /* Location of config files */
1929 * Locate the cupsd.conf file...
1932 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1933 server_root
= CUPS_SERVERROOT
;
1935 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1938 * Figure out the size...
1941 if (stat(filename
, &info
))
1943 cgiStartHTML(cgiText(_("Edit Configuration File")));
1944 cgiSetVariable("MESSAGE",
1945 cgiText(_("Unable to access cupsd.conf file")));
1946 cgiSetVariable("ERROR", strerror(errno
));
1947 cgiCopyTemplateLang("error.tmpl");
1954 if (info
.st_size
> (1024 * 1024))
1956 cgiStartHTML(cgiText(_("Edit Configuration File")));
1957 cgiSetVariable("MESSAGE",
1958 cgiText(_("Unable to access cupsd.conf file")));
1959 cgiSetVariable("ERROR",
1960 cgiText(_("Unable to edit cupsd.conf files larger than "
1962 cgiCopyTemplateLang("error.tmpl");
1965 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1966 (long)info
.st_size
);
1971 * Open the cupsd.conf file...
1974 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1977 * Unable to open - log an error...
1980 cgiStartHTML(cgiText(_("Edit Configuration File")));
1981 cgiSetVariable("MESSAGE",
1982 cgiText(_("Unable to access cupsd.conf file")));
1983 cgiSetVariable("ERROR", strerror(errno
));
1984 cgiCopyTemplateLang("error.tmpl");
1992 * Allocate memory and load the file into a string buffer...
1995 if ((buffer
= calloc(1, (size_t)info
.st_size
+ 1)) != NULL
)
1997 cupsFileRead(cupsd
, buffer
, (size_t)info
.st_size
);
1998 cgiSetVariable("CUPSDCONF", buffer
);
2002 cupsFileClose(cupsd
);
2005 * Then get the default cupsd.conf file and put that into a string as
2009 strlcat(filename
, ".default", sizeof(filename
));
2011 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
2012 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
2014 if ((buffer
= calloc(1, 2 * (size_t)info
.st_size
+ 1)) != NULL
)
2016 bufend
= buffer
+ 2 * info
.st_size
- 1;
2018 for (bufptr
= buffer
;
2019 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
2021 if (ch
== '\\' || ch
== '\"')
2024 *bufptr
++ = (char)ch
;
2026 else if (ch
== '\n')
2031 else if (ch
== '\t')
2037 *bufptr
++ = (char)ch
;
2042 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
2046 cupsFileClose(cupsd
);
2050 * Show the current config file...
2053 cgiStartHTML(cgiText(_("Edit Configuration File")));
2055 cgiCopyTemplateLang("edit-config.tmpl");
2063 * 'do_delete_class()' - Delete a class.
2067 do_delete_class(http_t
*http
) /* I - HTTP connection */
2069 ipp_t
*request
; /* IPP request */
2070 char uri
[HTTP_MAX_URI
]; /* Job URI */
2071 const char *pclass
; /* Printer class name */
2075 * Get form variables...
2078 if (cgiGetVariable("CONFIRM") == NULL
)
2080 cgiStartHTML(cgiText(_("Delete Class")));
2081 cgiCopyTemplateLang("class-confirm.tmpl");
2086 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2087 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2088 "localhost", 0, "/classes/%s", pclass
);
2091 cgiStartHTML(cgiText(_("Delete Class")));
2092 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2093 cgiCopyTemplateLang("error.tmpl");
2099 * Build a CUPS_DELETE_CLASS request, which requires the following
2102 * attributes-charset
2103 * attributes-natural-language
2107 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2109 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2113 * Do the request and get back a response...
2116 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2119 * Show the results...
2122 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2124 puts("Status: 401\n");
2127 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2130 * Redirect successful updates back to the classes page...
2133 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2136 cgiStartHTML(cgiText(_("Delete Class")));
2138 if (cupsLastError() > IPP_OK_CONFLICT
)
2139 cgiShowIPPError(_("Unable to delete class"));
2141 cgiCopyTemplateLang("class-deleted.tmpl");
2148 * 'do_delete_printer()' - Delete a printer.
2152 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2154 ipp_t
*request
; /* IPP request */
2155 char uri
[HTTP_MAX_URI
]; /* Job URI */
2156 const char *printer
; /* Printer printer name */
2160 * Get form variables...
2163 if (cgiGetVariable("CONFIRM") == NULL
)
2165 cgiStartHTML(cgiText(_("Delete Printer")));
2166 cgiCopyTemplateLang("printer-confirm.tmpl");
2171 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2172 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2173 "localhost", 0, "/printers/%s", printer
);
2176 cgiStartHTML(cgiText(_("Delete Printer")));
2177 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2178 cgiCopyTemplateLang("error.tmpl");
2184 * Build a CUPS_DELETE_PRINTER request, which requires the following
2187 * attributes-charset
2188 * attributes-natural-language
2192 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2194 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2198 * Do the request and get back a response...
2201 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2204 * Show the results...
2207 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2209 puts("Status: 401\n");
2212 else if (cupsLastError() <= IPP_OK_CONFLICT
)
2215 * Redirect successful updates back to the printers page...
2218 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2221 cgiStartHTML(cgiText(_("Delete Printer")));
2223 if (cupsLastError() > IPP_OK_CONFLICT
)
2224 cgiShowIPPError(_("Unable to delete printer"));
2226 cgiCopyTemplateLang("printer-deleted.tmpl");
2233 * 'do_export()' - Export printers to Samba.
2237 do_export(http_t
*http
) /* I - HTTP connection */
2239 int i
, j
; /* Looping vars */
2240 ipp_t
*request
, /* IPP request */
2241 *response
; /* IPP response */
2242 const char *username
, /* Samba username */
2243 *password
, /* Samba password */
2244 *export_all
; /* Export all printers? */
2245 int export_count
, /* Number of printers to export */
2246 printer_count
; /* Number of available printers */
2247 const char *name
, /* What name to pull */
2248 *dest
; /* Current destination */
2249 char ppd
[1024]; /* PPD file */
2256 username
= cgiGetVariable("USERNAME");
2257 password
= cgiGetVariable("PASSWORD");
2258 export_all
= cgiGetVariable("EXPORT_ALL");
2259 export_count
= cgiGetSize("EXPORT_NAME");
2262 * Get list of available printers...
2265 cgiSetSize("PRINTER_NAME", 0);
2266 cgiSetSize("PRINTER_EXPORT", 0);
2268 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2270 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2273 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2274 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
2276 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2277 "requested-attributes", NULL
, "printer-name");
2279 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2281 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2282 ippDelete(response
);
2286 printer_count
= cgiGetSize("PRINTER_NAME");
2288 for (i
= 0; i
< printer_count
; i
++)
2290 dest
= cgiGetArray("PRINTER_NAME", i
);
2292 for (j
= 0; j
< export_count
; j
++)
2293 if (!_cups_strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2296 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2302 * Export or get the printers to export...
2305 if (username
&& *username
&& password
&& *password
&&
2306 (export_all
|| export_count
> 0))
2312 fputs("DEBUG: Export printers...\n", stderr
);
2316 name
= "PRINTER_NAME";
2317 export_count
= cgiGetSize("PRINTER_NAME");
2320 name
= "EXPORT_NAME";
2322 for (i
= 0; i
< export_count
; i
++)
2324 dest
= cgiGetArray(name
, i
);
2326 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2329 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2338 if (i
< export_count
)
2339 cgiSetVariable("ERROR", cupsLastErrorString());
2342 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2343 cgiCopyTemplateLang("samba-exported.tmpl");
2348 else if (username
&& !*username
)
2349 cgiSetVariable("ERROR",
2350 cgiText(_("A Samba username is required to export "
2351 "printer drivers")));
2352 else if (username
&& (!password
|| !*password
))
2353 cgiSetVariable("ERROR",
2354 cgiText(_("A Samba password is required to export "
2355 "printer drivers")));
2361 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2362 cgiCopyTemplateLang("samba-export.tmpl");
2368 * 'do_list_printers()' - List available printers.
2372 do_list_printers(http_t
*http
) /* I - HTTP connection */
2374 ipp_t
*request
, /* IPP request */
2375 *response
; /* IPP response */
2376 ipp_attribute_t
*attr
; /* IPP attribute */
2379 cgiStartHTML(cgiText(_("List Available Printers")));
2383 * Get the list of printers and their devices...
2386 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2388 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2389 "requested-attributes", NULL
, "device-uri");
2391 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2392 CUPS_PRINTER_LOCAL
);
2393 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2394 CUPS_PRINTER_LOCAL
);
2396 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2399 * Got the printer list, now load the devices...
2402 int i
; /* Looping var */
2403 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2404 char *printer_device
; /* Current printer device */
2408 * Allocate an array and copy the device strings...
2411 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2413 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2415 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2417 cupsArrayAdd(printer_devices
, _cupsStrAlloc(attr
->values
[0].string
.text
));
2421 * Free the printer list and get the device list...
2424 ippDelete(response
);
2426 request
= ippNewRequest(CUPS_GET_DEVICES
);
2428 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2431 * Got the device list, let's parse it...
2434 const char *device_uri
, /* device-uri attribute value */
2435 *device_make_and_model
, /* device-make-and-model value */
2436 *device_info
; /* device-info value */
2439 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2442 * Skip leading attributes until we hit a device...
2445 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2452 * Pull the needed attributes from this device...
2456 device_make_and_model
= NULL
;
2459 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2461 if (!strcmp(attr
->name
, "device-info") &&
2462 attr
->value_tag
== IPP_TAG_TEXT
)
2463 device_info
= attr
->values
[0].string
.text
;
2465 if (!strcmp(attr
->name
, "device-make-and-model") &&
2466 attr
->value_tag
== IPP_TAG_TEXT
)
2467 device_make_and_model
= attr
->values
[0].string
.text
;
2469 if (!strcmp(attr
->name
, "device-uri") &&
2470 attr
->value_tag
== IPP_TAG_URI
)
2471 device_uri
= attr
->values
[0].string
.text
;
2477 * See if we have everything needed...
2480 if (device_info
&& device_make_and_model
&& device_uri
&&
2481 _cups_strcasecmp(device_make_and_model
, "unknown") &&
2482 strchr(device_uri
, ':'))
2485 * Yes, now see if there is already a printer for this
2489 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2492 * Not found, so it must be a new printer...
2495 char option
[1024], /* Form variables for this device */
2496 *option_ptr
; /* Pointer into string */
2497 const char *ptr
; /* Pointer into device string */
2501 * Format the printer name variable for this device...
2503 * We use the device-info string first, then device-uri,
2504 * and finally device-make-and-model to come up with a
2508 if (_cups_strncasecmp(device_info
, "unknown", 7))
2510 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2513 ptr
= device_make_and_model
;
2515 for (option_ptr
= option
;
2516 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2518 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2520 *option_ptr
++ = *ptr
;
2521 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2522 option_ptr
[-1] != '_')
2523 *option_ptr
++ = '_';
2524 else if (*ptr
== '?' || *ptr
== '(')
2529 cgiSetArray("TEMPLATE_NAME", i
, option
);
2532 * Finally, set the form variables for this printer...
2535 cgiSetArray("device_info", i
, device_info
);
2536 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2537 cgiSetArray("device_uri", i
, device_uri
);
2546 ippDelete(response
);
2549 * Free the device list...
2552 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2554 printer_device
= (char *)cupsArrayNext(printer_devices
))
2555 _cupsStrFree(printer_device
);
2557 cupsArrayDelete(printer_devices
);
2562 * Finally, show the printer list...
2565 cgiCopyTemplateLang("list-available-printers.tmpl");
2572 * 'do_menu()' - Show the main menu.
2576 do_menu(http_t
*http
) /* I - HTTP connection */
2578 int num_settings
; /* Number of server settings */
2579 cups_option_t
*settings
; /* Server settings */
2580 const char *val
; /* Setting value */
2581 char filename
[1024]; /* Temporary filename */
2582 const char *datadir
; /* Location of data files */
2583 ipp_t
*request
, /* IPP request */
2584 *response
; /* IPP response */
2588 * Get the current server settings...
2591 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2593 cgiSetVariable("SETTINGS_MESSAGE",
2594 cgiText(_("Unable to open cupsd.conf file:")));
2595 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2598 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2599 settings
)) != NULL
&& atoi(val
))
2600 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2602 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2603 settings
)) != NULL
&& atoi(val
))
2604 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2606 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2607 settings
)) != NULL
&& atoi(val
))
2608 cgiSetVariable("REMOTE_ANY", "CHECKED");
2610 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2611 settings
)) != NULL
&& atoi(val
))
2612 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2614 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2615 settings
)) != NULL
&& atoi(val
))
2616 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2619 cgiSetVariable("HAVE_GSSAPI", "1");
2621 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2622 settings
)) != NULL
&& !_cups_strcasecmp(val
, "Negotiate"))
2623 cgiSetVariable("KERBEROS", "CHECKED");
2625 #endif /* HAVE_GSSAPI */
2626 cgiSetVariable("KERBEROS", "");
2628 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2632 if (!_cups_strcasecmp(val
, "yes") || !_cups_strcasecmp(val
, "on") ||
2633 !_cups_strcasecmp(val
, "true"))
2634 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2636 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2641 (!_cups_strcasecmp(val
, "0") || !_cups_strcasecmp(val
, "no") ||
2642 !_cups_strcasecmp(val
, "off") || !_cups_strcasecmp(val
, "false") ||
2643 !_cups_strcasecmp(val
, "disabled")))
2645 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2646 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2650 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2651 cgiSetVariable("PRESERVE_JOB_HISTORY", val
);
2653 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2657 cgiSetVariable("PRESERVE_JOB_FILES", val
);
2661 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2664 cgiSetVariable("MAX_CLIENTS", val
);
2666 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2669 cgiSetVariable("MAX_JOBS", val
);
2671 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2674 cgiSetVariable("MAX_LOG_SIZE", val
);
2676 cupsFreeOptions(num_settings
, settings
);
2679 * See if Samba and the Windows drivers are installed...
2682 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2683 datadir
= CUPS_DATADIR
;
2685 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2686 if (!access(filename
, R_OK
))
2689 * Found Windows 2000 driver file, see if we have smbclient and
2693 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2694 sizeof(filename
)) &&
2695 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2697 cgiSetVariable("HAVE_SAMBA", "Y");
2700 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2702 fputs("ERROR: smbclient not found!\n", stderr
);
2704 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2706 fputs("ERROR: rpcclient not found!\n", stderr
);
2716 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2718 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2719 NULL
, "ipp://localhost/");
2721 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2723 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2724 ippDelete(response
);
2728 * Finally, show the main menu template...
2731 cgiStartHTML(cgiText(_("Administration")));
2733 cgiCopyTemplateLang("admin.tmpl");
2740 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2744 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2746 int i
; /* Looping var */
2747 ipp_t
*request
, /* IPP request */
2748 *response
; /* IPP response */
2749 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2750 const char *printer
, /* Printer name (purge-jobs) */
2751 *is_class
, /* Is a class? */
2752 *users
, /* List of users or groups */
2753 *type
; /* Allow/deny type */
2754 int num_users
; /* Number of users */
2755 char *ptr
, /* Pointer into users string */
2756 *end
, /* Pointer to end of users string */
2757 quote
; /* Quote character */
2758 ipp_attribute_t
*attr
; /* Attribute */
2759 static const char * const attrs
[] = /* Requested attributes */
2761 "requesting-user-name-allowed",
2762 "requesting-user-name-denied"
2766 is_class
= cgiGetVariable("IS_CLASS");
2767 printer
= cgiGetVariable("PRINTER_NAME");
2771 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2772 cgiStartHTML(cgiText(_("Set Allowed Users")));
2773 cgiCopyTemplateLang("error.tmpl");
2778 users
= cgiGetVariable("users");
2779 type
= cgiGetVariable("type");
2781 if (!users
|| !type
||
2782 (strcmp(type
, "requesting-user-name-allowed") &&
2783 strcmp(type
, "requesting-user-name-denied")))
2786 * Build a Get-Printer-Attributes request, which requires the following
2789 * attributes-charset
2790 * attributes-natural-language
2792 * requested-attributes
2795 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2797 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2798 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2800 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2803 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2804 "requested-attributes",
2805 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2808 * Do the request and get back a response...
2811 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2813 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2815 ippDelete(response
);
2818 cgiStartHTML(cgiText(_("Set Allowed Users")));
2820 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2822 puts("Status: 401\n");
2825 else if (cupsLastError() > IPP_OK_CONFLICT
)
2826 cgiShowIPPError(_("Unable to get printer attributes"));
2828 cgiCopyTemplateLang("users.tmpl");
2835 * Save the changes...
2838 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2841 * Skip whitespace and commas...
2844 while (*ptr
== ',' || isspace(*ptr
& 255))
2850 if (*ptr
== '\'' || *ptr
== '\"')
2853 * Scan quoted name...
2858 for (end
= ptr
; *end
; end
++)
2865 * Scan space or comma-delimited name...
2868 for (end
= ptr
; *end
; end
++)
2869 if (isspace(*end
& 255) || *end
== ',')
2874 * Advance to the next name...
2881 * Build a CUPS-Add-Printer/Class request, which requires the following
2884 * attributes-charset
2885 * attributes-natural-language
2887 * requesting-user-name-{allowed,denied}
2890 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2892 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2893 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2895 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2899 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2900 "requesting-user-name-allowed", NULL
, "all");
2903 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2904 type
, num_users
, NULL
, NULL
);
2906 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2909 * Skip whitespace and commas...
2912 while (*ptr
== ',' || isspace(*ptr
& 255))
2918 if (*ptr
== '\'' || *ptr
== '\"')
2921 * Scan quoted name...
2926 for (end
= ptr
; *end
; end
++)
2933 * Scan space or comma-delimited name...
2936 for (end
= ptr
; *end
; end
++)
2937 if (isspace(*end
& 255) || *end
== ',')
2942 * Terminate the name...
2952 attr
->values
[i
].string
.text
= _cupsStrAlloc(ptr
);
2955 * Advance to the next name...
2963 * Do the request and get back a response...
2966 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2968 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2970 puts("Status: 401\n");
2973 else if (cupsLastError() > IPP_OK_CONFLICT
)
2975 cgiStartHTML(cgiText(_("Set Allowed Users")));
2976 cgiShowIPPError(_("Unable to change printer"));
2981 * Redirect successful updates back to the printer page...
2984 char url
[1024], /* Printer/class URL */
2985 refresh
[1024]; /* Refresh URL */
2988 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2989 cgiFormEncode(uri
, url
, sizeof(uri
));
2990 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2992 cgiSetVariable("refresh_page", refresh
);
2994 cgiStartHTML(cgiText(_("Set Allowed Users")));
2996 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2997 "printer-modified.tmpl");
3006 * 'do_set_default()' - Set the server default printer/class.
3010 do_set_default(http_t
*http
) /* I - HTTP connection */
3012 const char *title
; /* Page title */
3013 ipp_t
*request
; /* IPP request */
3014 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3015 const char *printer
, /* Printer name (purge-jobs) */
3016 *is_class
; /* Is a class? */
3019 is_class
= cgiGetVariable("IS_CLASS");
3020 printer
= cgiGetVariable("PRINTER_NAME");
3021 title
= cgiText(_("Set As Server Default"));
3025 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3026 cgiStartHTML(title
);
3027 cgiCopyTemplateLang("error.tmpl");
3033 * Build a printer request, which requires the following
3036 * attributes-charset
3037 * attributes-natural-language
3041 request
= ippNewRequest(CUPS_SET_DEFAULT
);
3043 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3044 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3046 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3050 * Do the request and get back a response...
3053 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3055 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3057 puts("Status: 401\n");
3060 else if (cupsLastError() > IPP_OK_CONFLICT
)
3062 cgiStartHTML(title
);
3063 cgiShowIPPError(_("Unable to set server default"));
3068 * Redirect successful updates back to the printer page...
3071 char url
[1024], /* Printer/class URL */
3072 refresh
[1024]; /* Refresh URL */
3075 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3076 cgiFormEncode(uri
, url
, sizeof(uri
));
3077 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3078 cgiSetVariable("refresh_page", refresh
);
3080 cgiStartHTML(title
);
3081 cgiCopyTemplateLang("printer-default.tmpl");
3089 * 'do_set_options()' - Configure the default options for a queue.
3093 do_set_options(http_t
*http
, /* I - HTTP connection */
3094 int is_class
) /* I - Set options for class? */
3096 int i
, j
, k
, m
; /* Looping vars */
3097 int have_options
; /* Have options? */
3098 ipp_t
*request
, /* IPP request */
3099 *response
; /* IPP response */
3100 ipp_attribute_t
*attr
; /* IPP attribute */
3101 char uri
[HTTP_MAX_URI
]; /* Job URI */
3102 const char *var
; /* Variable value */
3103 const char *printer
; /* Printer printer name */
3104 const char *filename
; /* PPD filename */
3105 char tempfile
[1024]; /* Temporary filename */
3106 cups_file_t
*in
, /* Input file */
3107 *out
; /* Output file */
3108 char line
[1024], /* Line from PPD file */
3109 value
[1024], /* Option value */
3110 keyword
[1024], /* Keyword from Default line */
3111 *keyptr
; /* Pointer into keyword... */
3112 ppd_file_t
*ppd
; /* PPD file */
3113 ppd_group_t
*group
; /* Option group */
3114 ppd_option_t
*option
; /* Option */
3115 ppd_coption_t
*coption
; /* Custom option */
3116 ppd_cparam_t
*cparam
; /* Custom parameter */
3117 ppd_attr_t
*ppdattr
; /* PPD attribute */
3118 const char *title
; /* Page title */
3121 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
3123 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
3127 * Get the printer name...
3130 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
3131 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3132 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3136 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3137 cgiStartHTML(title
);
3138 cgiCopyTemplateLang("error.tmpl");
3143 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
3146 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3147 * command file to the printer...
3150 if (cgiGetVariable("AUTOCONFIGURE"))
3152 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
3157 * Get the PPD file...
3163 filename
= cupsGetPPD2(http
, printer
);
3167 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
3169 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
3171 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
3172 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
3173 cgiStartHTML(title
);
3174 cgiCopyTemplateLang("error.tmpl");
3181 fputs("DEBUG: No PPD file\n", stderr
);
3185 if (cgiGetVariable("job_sheets_start") != NULL
||
3186 cgiGetVariable("job_sheets_end") != NULL
)
3193 ppdMarkDefaults(ppd
);
3195 for (option
= ppdFirstOption(ppd
);
3197 option
= ppdNextOption(ppd
))
3199 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
3202 ppdMarkOption(ppd
, option
->keyword
, var
);
3203 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
3206 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
3210 if (!have_options
|| ppdConflicts(ppd
))
3213 * Show the options to the user...
3216 fputs("DEBUG: Showing options...\n", stderr
);
3219 * Show auto-configure button if supported...
3224 if (ppd
->num_filters
== 0 ||
3225 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
3226 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
3227 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3230 for (i
= 0; i
< ppd
->num_filters
; i
++)
3231 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
3233 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3240 * Get the printer attributes...
3243 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3245 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3246 "localhost", 0, "/printers/%s", printer
);
3247 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3250 response
= cupsDoRequest(http
, request
, "/");
3253 * List the groups used as "tabs"...
3260 for (group
= ppd
->groups
;
3261 i
< ppd
->num_groups
;
3264 cgiSetArray("GROUP_ID", i
, group
->name
);
3266 if (!strcmp(group
->name
, "InstallableOptions"))
3267 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
3269 cgiSetArray("GROUP", i
, group
->text
);
3273 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
3275 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
3276 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
3279 if (ippFindAttribute(response
, "printer-error-policy-supported",
3281 ippFindAttribute(response
, "printer-op-policy-supported",
3284 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
3285 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3288 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3289 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3291 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3292 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3295 cgiStartHTML(cgiText(_("Set Printer Options")));
3296 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3302 if (ppdConflicts(ppd
))
3304 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3307 for (j
= group
->num_options
, option
= group
->options
;
3310 if (option
->conflicted
)
3312 cgiSetArray("ckeyword", k
, option
->keyword
);
3313 cgiSetArray("ckeytext", k
, option
->text
);
3315 for (m
= 0; m
< option
->num_choices
; m
++)
3317 if (option
->choices
[m
].marked
)
3319 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3327 cgiCopyTemplateLang("option-conflict.tmpl");
3330 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3334 for (j
= group
->num_options
, option
= group
->options
;
3338 if (!strcmp(option
->keyword
, "PageRegion"))
3341 if (option
->num_choices
> 1)
3348 cgiSetVariable("GROUP_ID", group
->name
);
3350 if (!strcmp(group
->name
, "InstallableOptions"))
3351 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3353 cgiSetVariable("GROUP", group
->text
);
3355 cgiCopyTemplateLang("option-header.tmpl");
3357 for (j
= group
->num_options
, option
= group
->options
;
3361 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
3364 cgiSetVariable("KEYWORD", option
->keyword
);
3365 cgiSetVariable("KEYTEXT", option
->text
);
3367 if (option
->conflicted
)
3368 cgiSetVariable("CONFLICTED", "1");
3370 cgiSetVariable("CONFLICTED", "0");
3372 cgiSetSize("CHOICES", 0);
3373 cgiSetSize("TEXT", 0);
3374 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3376 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3377 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3381 if (option
->choices
[k
].marked
)
3382 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3385 cgiSetSize("PARAMS", 0);
3386 cgiSetSize("PARAMTEXT", 0);
3387 cgiSetSize("PARAMVALUE", 0);
3388 cgiSetSize("INPUTTYPE", 0);
3390 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3392 const char *units
= NULL
; /* Units value, if any */
3394 cgiSetVariable("ISCUSTOM", "1");
3396 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3398 cparam
= ppdNextCustomParam(coption
), m
++)
3400 if (!_cups_strcasecmp(option
->keyword
, "PageSize") &&
3401 _cups_strcasecmp(cparam
->name
, "Width") &&
3402 _cups_strcasecmp(cparam
->name
, "Height"))
3408 cgiSetArray("PARAMS", m
, cparam
->name
);
3409 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3410 cgiSetArray("INPUTTYPE", m
, "text");
3412 switch (cparam
->type
)
3414 case PPD_CUSTOM_POINTS
:
3415 if (!_cups_strncasecmp(option
->defchoice
, "Custom.", 7))
3417 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3419 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3420 strcmp(units
, "in") && strcmp(units
, "ft"))
3422 if (units
[1] == 'm')
3431 if (!strcmp(units
, "mm"))
3432 snprintf(value
, sizeof(value
), "%g",
3433 cparam
->current
.custom_points
/ 72.0 * 25.4);
3434 else if (!strcmp(units
, "cm"))
3435 snprintf(value
, sizeof(value
), "%g",
3436 cparam
->current
.custom_points
/ 72.0 * 2.54);
3437 else if (!strcmp(units
, "in"))
3438 snprintf(value
, sizeof(value
), "%g",
3439 cparam
->current
.custom_points
/ 72.0);
3440 else if (!strcmp(units
, "ft"))
3441 snprintf(value
, sizeof(value
), "%g",
3442 cparam
->current
.custom_points
/ 72.0 / 12.0);
3443 else if (!strcmp(units
, "m"))
3444 snprintf(value
, sizeof(value
), "%g",
3445 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3447 snprintf(value
, sizeof(value
), "%g",
3448 cparam
->current
.custom_points
);
3449 cgiSetArray("PARAMVALUE", m
, value
);
3452 case PPD_CUSTOM_CURVE
:
3453 case PPD_CUSTOM_INVCURVE
:
3454 case PPD_CUSTOM_REAL
:
3455 snprintf(value
, sizeof(value
), "%g",
3456 cparam
->current
.custom_real
);
3457 cgiSetArray("PARAMVALUE", m
, value
);
3460 case PPD_CUSTOM_INT
:
3461 snprintf(value
, sizeof(value
), "%d",
3462 cparam
->current
.custom_int
);
3463 cgiSetArray("PARAMVALUE", m
, value
);
3466 case PPD_CUSTOM_PASSCODE
:
3467 case PPD_CUSTOM_PASSWORD
:
3468 if (cparam
->current
.custom_password
)
3469 cgiSetArray("PARAMVALUE", m
,
3470 cparam
->current
.custom_password
);
3472 cgiSetArray("PARAMVALUE", m
, "");
3473 cgiSetArray("INPUTTYPE", m
, "password");
3476 case PPD_CUSTOM_STRING
:
3477 if (cparam
->current
.custom_string
)
3478 cgiSetArray("PARAMVALUE", m
,
3479 cparam
->current
.custom_string
);
3481 cgiSetArray("PARAMVALUE", m
, "");
3488 cgiSetArray("PARAMS", m
, "Units");
3489 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3490 cgiSetArray("PARAMVALUE", m
, units
);
3494 cgiSetVariable("ISCUSTOM", "0");
3498 case PPD_UI_BOOLEAN
:
3499 cgiCopyTemplateLang("option-boolean.tmpl");
3501 case PPD_UI_PICKONE
:
3502 cgiCopyTemplateLang("option-pickone.tmpl");
3504 case PPD_UI_PICKMANY
:
3505 cgiCopyTemplateLang("option-pickmany.tmpl");
3510 cgiCopyTemplateLang("option-trailer.tmpl");
3514 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3515 IPP_TAG_ZERO
)) != NULL
)
3518 * Add the job sheets options...
3521 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3522 cgiSetVariable("GROUP", cgiText(_("Banners")));
3523 cgiCopyTemplateLang("option-header.tmpl");
3525 cgiSetSize("CHOICES", attr
->num_values
);
3526 cgiSetSize("TEXT", attr
->num_values
);
3527 for (k
= 0; k
< attr
->num_values
; k
++)
3529 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3530 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3533 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3535 cgiSetVariable("KEYWORD", "job_sheets_start");
3536 cgiSetVariable("KEYTEXT",
3537 /* TRANSLATORS: Banner/cover sheet before the print job. */
3538 cgiText(_("Starting Banner")));
3539 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3540 attr
->values
[0].string
.text
: "");
3542 cgiCopyTemplateLang("option-pickone.tmpl");
3544 cgiSetVariable("KEYWORD", "job_sheets_end");
3545 cgiSetVariable("KEYTEXT",
3546 /* TRANSLATORS: Banner/cover sheet after the print job. */
3547 cgiText(_("Ending Banner")));
3548 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3549 attr
->values
[1].string
.text
: "");
3551 cgiCopyTemplateLang("option-pickone.tmpl");
3553 cgiCopyTemplateLang("option-trailer.tmpl");
3556 if (ippFindAttribute(response
, "printer-error-policy-supported",
3558 ippFindAttribute(response
, "printer-op-policy-supported",
3562 * Add the error and operation policy options...
3565 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3566 cgiSetVariable("GROUP", cgiText(_("Policies")));
3567 cgiCopyTemplateLang("option-header.tmpl");
3573 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3578 cgiSetSize("CHOICES", attr
->num_values
);
3579 cgiSetSize("TEXT", attr
->num_values
);
3580 for (k
= 0; k
< attr
->num_values
; k
++)
3582 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3583 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3586 attr
= ippFindAttribute(response
, "printer-error-policy",
3589 cgiSetVariable("KEYWORD", "printer_error_policy");
3590 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3591 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3592 "" : attr
->values
[0].string
.text
);
3595 cgiCopyTemplateLang("option-pickone.tmpl");
3598 * Operation policy...
3601 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3606 cgiSetSize("CHOICES", attr
->num_values
);
3607 cgiSetSize("TEXT", attr
->num_values
);
3608 for (k
= 0; k
< attr
->num_values
; k
++)
3610 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3611 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3614 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3616 cgiSetVariable("KEYWORD", "printer_op_policy");
3617 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3618 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3619 "" : attr
->values
[0].string
.text
);
3621 cgiCopyTemplateLang("option-pickone.tmpl");
3624 cgiCopyTemplateLang("option-trailer.tmpl");
3628 * Binary protocol support...
3631 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3632 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3634 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3635 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3637 cgiSetSize("CHOICES", attr
->num_values
);
3638 cgiSetSize("TEXT", attr
->num_values
);
3640 for (i
= 0; i
< attr
->num_values
; i
++)
3642 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3643 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3646 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3647 cgiSetVariable("KEYWORD", "port_monitor");
3648 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3649 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3651 cgiCopyTemplateLang("option-header.tmpl");
3652 cgiCopyTemplateLang("option-pickone.tmpl");
3653 cgiCopyTemplateLang("option-trailer.tmpl");
3656 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3659 ippDelete(response
);
3664 * Set default options...
3667 fputs("DEBUG: Setting options...\n", stderr
);
3671 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3672 in
= cupsFileOpen(filename
, "r");
3676 cgiSetVariable("ERROR", strerror(errno
));
3677 cgiStartHTML(cgiText(_("Set Printer Options")));
3678 cgiCopyTemplateLang("error.tmpl");
3694 while (cupsFileGets(in
, line
, sizeof(line
)))
3696 if (!strncmp(line
, "*cupsProtocol:", 14))
3698 else if (strncmp(line
, "*Default", 8))
3699 cupsFilePrintf(out
, "%s\n", line
);
3703 * Get default option name...
3706 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3708 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3709 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3714 if (!strcmp(keyword
, "PageRegion") ||
3715 !strcmp(keyword
, "PaperDimension") ||
3716 !strcmp(keyword
, "ImageableArea"))
3717 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3719 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3722 cupsFilePrintf(out
, "%s\n", line
);
3724 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3734 * Make sure temporary filename is cleared when there is no PPD...
3741 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3742 * following attributes:
3744 * attributes-charset
3745 * attributes-natural-language
3747 * job-sheets-default
3748 * printer-error-policy
3753 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3754 CUPS_ADD_MODIFY_PRINTER
);
3756 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3759 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3760 "job-sheets-default", 2, NULL
, NULL
);
3761 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3762 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3764 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3765 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3766 "printer-error-policy", NULL
, var
);
3768 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3769 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3770 "printer-op-policy", NULL
, var
);
3772 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3773 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3774 "port-monitor", NULL
, var
);
3777 * Do the request and get back a response...
3781 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3783 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3785 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3787 puts("Status: 401\n");
3790 else if (cupsLastError() > IPP_OK_CONFLICT
)
3792 cgiStartHTML(title
);
3793 cgiShowIPPError(_("Unable to set options"));
3798 * Redirect successful updates back to the printer page...
3801 char refresh
[1024]; /* Refresh URL */
3804 cgiFormEncode(uri
, printer
, sizeof(uri
));
3805 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3806 is_class
? "classes" : "printers", uri
);
3807 cgiSetVariable("refresh_page", refresh
);
3809 cgiStartHTML(title
);
3811 cgiCopyTemplateLang("printer-configured.tmpl");
3826 * 'do_set_sharing()' - Set printer-is-shared value.
3830 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3832 ipp_t
*request
, /* IPP request */
3833 *response
; /* IPP response */
3834 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3835 const char *printer
, /* Printer name */
3836 *is_class
, /* Is a class? */
3837 *shared
; /* Sharing value */
3840 is_class
= cgiGetVariable("IS_CLASS");
3841 printer
= cgiGetVariable("PRINTER_NAME");
3842 shared
= cgiGetVariable("SHARED");
3844 if (!printer
|| !shared
)
3846 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3847 cgiStartHTML(cgiText(_("Set Publishing")));
3848 cgiCopyTemplateLang("error.tmpl");
3854 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3855 * following attributes:
3857 * attributes-charset
3858 * attributes-natural-language
3863 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3865 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3866 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3868 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3871 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", (char)atoi(shared
));
3874 * Do the request and get back a response...
3877 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3879 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3881 ippDelete(response
);
3884 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3886 puts("Status: 401\n");
3889 else if (cupsLastError() > IPP_OK_CONFLICT
)
3891 cgiStartHTML(cgiText(_("Set Publishing")));
3892 cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
3897 * Redirect successful updates back to the printer page...
3900 char url
[1024], /* Printer/class URL */
3901 refresh
[1024]; /* Refresh URL */
3904 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3905 cgiFormEncode(uri
, url
, sizeof(uri
));
3906 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3907 cgiSetVariable("refresh_page", refresh
);
3909 cgiStartHTML(cgiText(_("Set Publishing")));
3910 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3911 "printer-modified.tmpl");
3919 * 'get_option_value()' - Return the value of an option.
3921 * This function also handles generation of custom option values.
3924 static char * /* O - Value string or NULL on error */
3926 ppd_file_t
*ppd
, /* I - PPD file */
3927 const char *name
, /* I - Option name */
3928 char *buffer
, /* I - String buffer */
3929 size_t bufsize
) /* I - Size of buffer */
3931 char *bufptr
, /* Pointer into buffer */
3932 *bufend
; /* End of buffer */
3933 ppd_coption_t
*coption
; /* Custom option */
3934 ppd_cparam_t
*cparam
; /* Current custom parameter */
3935 char keyword
[256]; /* Parameter name */
3936 const char *val
, /* Parameter value */
3937 *uval
; /* Units value */
3938 long integer
; /* Integer value */
3939 double number
, /* Number value */
3940 number_points
; /* Number in points */
3944 * See if we have a custom option choice...
3947 if ((val
= cgiGetVariable(name
)) == NULL
)
3955 else if (_cups_strcasecmp(val
, "Custom") ||
3956 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3959 * Not a custom choice...
3962 strlcpy(buffer
, val
, bufsize
);
3967 * OK, we have a custom option choice, format it...
3972 if (!strcmp(coption
->keyword
, "PageSize"))
3974 const char *lval
; /* Length string value */
3975 double width
, /* Width value */
3976 width_points
, /* Width in points */
3977 length
, /* Length value */
3978 length_points
; /* Length in points */
3981 val
= cgiGetVariable("PageSize.Width");
3982 lval
= cgiGetVariable("PageSize.Height");
3983 uval
= cgiGetVariable("PageSize.Units");
3985 if (!val
|| !lval
|| !uval
||
3986 (width
= strtod(val
, NULL
)) == 0.0 ||
3987 (length
= strtod(lval
, NULL
)) == 0.0 ||
3988 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3989 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3992 width_points
= get_points(width
, uval
);
3993 length_points
= get_points(length
, uval
);
3995 if (width_points
< ppd
->custom_min
[0] ||
3996 width_points
> ppd
->custom_max
[0] ||
3997 length_points
< ppd
->custom_min
[1] ||
3998 length_points
> ppd
->custom_max
[1])
4001 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
4003 else if (cupsArrayCount(coption
->params
) == 1)
4005 cparam
= ppdFirstCustomParam(coption
);
4006 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
4008 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4011 switch (cparam
->type
)
4013 case PPD_CUSTOM_CURVE
:
4014 case PPD_CUSTOM_INVCURVE
:
4015 case PPD_CUSTOM_REAL
:
4016 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4017 number
< cparam
->minimum
.custom_real
||
4018 number
> cparam
->maximum
.custom_real
)
4021 snprintf(buffer
, bufsize
, "Custom.%g", number
);
4024 case PPD_CUSTOM_INT
:
4025 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4026 integer
== LONG_MAX
||
4027 integer
< cparam
->minimum
.custom_int
||
4028 integer
> cparam
->maximum
.custom_int
)
4031 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
4034 case PPD_CUSTOM_POINTS
:
4035 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4037 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4038 (uval
= cgiGetVariable(keyword
)) == NULL
||
4039 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
4040 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
4043 number_points
= get_points(number
, uval
);
4044 if (number_points
< cparam
->minimum
.custom_points
||
4045 number_points
> cparam
->maximum
.custom_points
)
4048 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
4051 case PPD_CUSTOM_PASSCODE
:
4052 for (uval
= val
; *uval
; uval
++)
4053 if (!isdigit(*uval
& 255))
4056 case PPD_CUSTOM_PASSWORD
:
4057 case PPD_CUSTOM_STRING
:
4058 integer
= (long)strlen(val
);
4059 if (integer
< cparam
->minimum
.custom_string
||
4060 integer
> cparam
->maximum
.custom_string
)
4063 snprintf(buffer
, bufsize
, "Custom.%s", val
);
4069 const char *prefix
= "{"; /* Prefix string */
4073 bufend
= buffer
+ bufsize
;
4075 for (cparam
= ppdFirstCustomParam(coption
);
4077 cparam
= ppdNextCustomParam(coption
))
4079 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
4082 if ((val
= cgiGetVariable(keyword
)) == NULL
)
4085 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%s%s=", prefix
, cparam
->name
);
4086 bufptr
+= strlen(bufptr
);
4089 switch (cparam
->type
)
4091 case PPD_CUSTOM_CURVE
:
4092 case PPD_CUSTOM_INVCURVE
:
4093 case PPD_CUSTOM_REAL
:
4094 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4095 number
< cparam
->minimum
.custom_real
||
4096 number
> cparam
->maximum
.custom_real
)
4099 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g", number
);
4102 case PPD_CUSTOM_INT
:
4103 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
4104 integer
== LONG_MAX
||
4105 integer
< cparam
->minimum
.custom_int
||
4106 integer
> cparam
->maximum
.custom_int
)
4109 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%ld", integer
);
4112 case PPD_CUSTOM_POINTS
:
4113 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
4115 if ((number
= strtod(val
, NULL
)) == 0.0 ||
4116 (uval
= cgiGetVariable(keyword
)) == NULL
||
4117 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
4118 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
4119 strcmp(uval
, "mm") && strcmp(uval
, "m")))
4122 number_points
= get_points(number
, uval
);
4123 if (number_points
< cparam
->minimum
.custom_points
||
4124 number_points
> cparam
->maximum
.custom_points
)
4127 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g%s", number
, uval
);
4130 case PPD_CUSTOM_PASSCODE
:
4131 for (uval
= val
; *uval
; uval
++)
4132 if (!isdigit(*uval
& 255))
4135 case PPD_CUSTOM_PASSWORD
:
4136 case PPD_CUSTOM_STRING
:
4137 integer
= (long)strlen(val
);
4138 if (integer
< cparam
->minimum
.custom_string
||
4139 integer
> cparam
->maximum
.custom_string
)
4142 if ((bufptr
+ 2) > bufend
)
4148 while (*val
&& bufptr
< bufend
)
4150 if (*val
== '\\' || *val
== '\"')
4152 if ((bufptr
+ 1) >= bufend
)
4161 if (bufptr
>= bufend
)
4170 bufptr
+= strlen(bufptr
);
4173 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
4176 memcpy(bufptr
, "}", 2);
4184 * 'get_points()' - Get a value in points.
4187 static double /* O - Number in points */
4188 get_points(double number
, /* I - Original number */
4189 const char *uval
) /* I - Units */
4191 if (!strcmp(uval
, "mm")) /* Millimeters */
4192 return (number
* 72.0 / 25.4);
4193 else if (!strcmp(uval
, "cm")) /* Centimeters */
4194 return (number
* 72.0 / 2.54);
4195 else if (!strcmp(uval
, "in")) /* Inches */
4196 return (number
* 72.0);
4197 else if (!strcmp(uval
, "ft")) /* Feet */
4198 return (number
* 72.0 * 12.0);
4199 else if (!strcmp(uval
, "m")) /* Meters */
4200 return (number
* 72.0 / 0.0254);
4207 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
4210 static char * /* O - Filename or NULL */
4211 get_printer_ppd(const char *uri
, /* I - Printer URI */
4212 char *buffer
, /* I - Filename buffer */
4213 size_t bufsize
) /* I - Size of filename buffer */
4215 http_t
*http
; /* Connection to printer */
4216 ipp_t
*request
, /* Get-Printer-Attributes request */
4217 *response
; /* Get-Printer-Attributes response */
4218 char resolved
[1024], /* Resolved URI */
4219 scheme
[32], /* URI scheme */
4220 userpass
[256], /* Username:password */
4221 host
[256], /* Hostname */
4222 resource
[256]; /* Resource path */
4223 int port
; /* Port number */
4227 * Connect to the printer...
4230 if (strstr(uri
, "._tcp"))
4236 if (!_httpResolveURI(uri
, resolved
, sizeof(resolved
), _HTTP_RESOLVE_DEFAULT
, NULL
, NULL
))
4238 fprintf(stderr
, "ERROR: Unable to resolve \"%s\".\n", uri
);
4245 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), host
, sizeof(host
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
4247 fprintf(stderr
, "ERROR: Bad printer URI \"%s\".\n", uri
);
4251 http
= httpConnect2(host
, port
, NULL
, AF_UNSPEC
, !strcmp(scheme
, "ipps") ? HTTP_ENCRYPTION_ALWAYS
: HTTP_ENCRYPTION_IF_REQUESTED
, 1, 30000, NULL
);
4254 fprintf(stderr
, "ERROR: Unable to connect to \"%s:%d\": %s\n", host
, port
, cupsLastErrorString());
4259 * Send a Get-Printer-Attributes request...
4262 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
4263 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
4264 response
= cupsDoRequest(http
, request
, resource
);
4266 if (!_ppdCreateFromIPP(buffer
, bufsize
, response
))
4267 fprintf(stderr
, "ERROR: Unable to create PPD file: %s\n", strerror(errno
));
4269 ippDelete(response
);