2 * Administration CGI for CUPS.
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
18 #include "cgi-private.h"
19 #include <cups/http-private.h>
20 #include <cups/ppd-private.h>
21 #include <cups/adminutil.h>
34 static int current_device
= 0; /* Current device shown */
41 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
);
42 static void do_am_class(http_t
*http
, int modify
);
43 static void do_am_printer(http_t
*http
, int modify
);
44 static void do_config_server(http_t
*http
);
45 static void do_delete_class(http_t
*http
);
46 static void do_delete_printer(http_t
*http
);
47 static void do_export(http_t
*http
);
48 static void do_list_printers(http_t
*http
);
49 static void do_menu(http_t
*http
);
50 static void do_set_allowed_users(http_t
*http
);
51 static void do_set_default(http_t
*http
);
52 static void do_set_options(http_t
*http
, int is_class
);
53 static void do_set_sharing(http_t
*http
);
54 static char *get_option_value(ppd_file_t
*ppd
, const char *name
,
55 char *buffer
, size_t bufsize
);
56 static double get_points(double number
, const char *uval
);
57 static char *get_printer_ppd(const char *uri
, char *buffer
, size_t bufsize
);
61 * 'main()' - Main entry for CGI.
64 int /* O - Exit status */
67 http_t
*http
; /* Connection to the server */
68 const char *op
; /* Operation name */
72 * Connect to the HTTP server...
75 fputs("DEBUG: admin.cgi started...\n", stderr
);
77 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
81 perror("ERROR: Unable to connect to cupsd");
82 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
83 cupsServer() ? cupsServer() : "(null)");
84 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
85 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
89 fprintf(stderr
, "DEBUG: http=%p\n", http
);
92 * Set the web interface section...
95 cgiSetVariable("SECTION", "admin");
96 cgiSetVariable("REFRESH_PAGE", "");
99 * See if we have form data...
102 if (!cgiInitialize() || !cgiGetVariable("OP"))
105 * Nope, send the administration menu...
108 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
112 else if ((op
= cgiGetVariable("OP")) != NULL
&& cgiIsPOST())
115 * Do the operation...
118 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
122 const char *printer
= getenv("PRINTER_NAME"),
123 /* Printer or class name */
124 *server_port
= getenv("SERVER_PORT");
125 /* Port number string */
126 int port
= atoi(server_port
? server_port
: "0");
128 char uri
[1024]; /* URL */
131 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
132 getenv("HTTPS") ? "https" : "http", NULL
,
133 getenv("SERVER_NAME"), port
, "/%s/%s",
134 cgiGetVariable("IS_CLASS") ? "classes" : "printers",
137 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
),
138 getenv("HTTPS") ? "https" : "http", NULL
,
139 getenv("SERVER_NAME"), port
, "/admin");
141 printf("Location: %s\n\n", uri
);
143 else if (!strcmp(op
, "set-allowed-users"))
144 do_set_allowed_users(http
);
145 else if (!strcmp(op
, "set-as-default"))
146 do_set_default(http
);
147 else if (!strcmp(op
, "set-sharing"))
148 do_set_sharing(http
);
149 else if (!strcmp(op
, "find-new-printers") ||
150 !strcmp(op
, "list-available-printers"))
151 do_list_printers(http
);
152 else if (!strcmp(op
, "add-class"))
153 do_am_class(http
, 0);
154 else if (!strcmp(op
, "add-printer"))
155 do_am_printer(http
, 0);
156 else if (!strcmp(op
, "modify-class"))
157 do_am_class(http
, 1);
158 else if (!strcmp(op
, "modify-printer"))
159 do_am_printer(http
, 1);
160 else if (!strcmp(op
, "delete-class"))
161 do_delete_class(http
);
162 else if (!strcmp(op
, "delete-printer"))
163 do_delete_printer(http
);
164 else if (!strcmp(op
, "set-class-options"))
165 do_set_options(http
, 1);
166 else if (!strcmp(op
, "set-printer-options"))
167 do_set_options(http
, 0);
168 else if (!strcmp(op
, "config-server"))
169 do_config_server(http
);
170 else if (!strcmp(op
, "export-samba"))
175 * Bad operation code - display an error...
178 cgiStartHTML(cgiText(_("Administration")));
179 cgiCopyTemplateLang("error-op.tmpl");
183 else if (op
&& !strcmp(op
, "redirect"))
185 const char *url
; /* Redirection URL... */
186 char prefix
[1024]; /* URL prefix */
190 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
191 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
193 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
194 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
196 fprintf(stderr
, "DEBUG: redirecting with prefix %s!\n", prefix
);
198 if ((url
= cgiGetVariable("URL")) != NULL
)
200 char encoded
[1024], /* Encoded URL string */
201 *ptr
; /* Pointer into encoded string */
208 for (; *url
&& ptr
< (encoded
+ sizeof(encoded
) - 4); url
++)
210 if (strchr("%@&+ <>#=", *url
) || *url
< ' ' || *url
& 128)
213 * Percent-encode this character; safe because we have at least 4
214 * bytes left in the array...
217 sprintf(ptr
, "%%%02X", *url
& 255);
229 * URL was too long, just redirect to the admin page...
232 printf("Location: %s/admin\n\n", prefix
);
237 * URL is OK, redirect there...
240 printf("Location: %s%s\n\n", prefix
, encoded
);
244 printf("Location: %s/admin\n\n", prefix
);
249 * Form data but no operation code - display an error...
252 cgiStartHTML(cgiText(_("Administration")));
253 cgiCopyTemplateLang("error-op.tmpl");
258 * Close the HTTP server connection...
264 * Return with no errors...
272 * 'choose_device_cb()' - Add a device to the device selection page.
277 const char *device_class
, /* I - Class */
278 const char *device_id
, /* I - 1284 device ID */
279 const char *device_info
, /* I - Description */
280 const char *device_make_and_model
, /* I - Make and model */
281 const char *device_uri
, /* I - Device URI */
282 const char *device_location
, /* I - Location */
283 const char *title
) /* I - Page title */
286 * For modern browsers, start a multi-part page so we can show that something
287 * is happening. Non-modern browsers just get everything at the end...
290 if (current_device
== 0 && cgiSupportsMultipart())
294 cgiCopyTemplateLang("choose-device.tmpl");
301 * Add the device to the array...
304 cgiSetArray("device_class", current_device
, device_class
);
305 cgiSetArray("device_id", current_device
, device_id
);
306 cgiSetArray("device_info", current_device
, device_info
);
307 cgiSetArray("device_make_and_model", current_device
, device_make_and_model
);
308 cgiSetArray("device_uri", current_device
, device_uri
);
309 cgiSetArray("device_location", current_device
, device_location
);
316 * 'do_am_class()' - Add or modify a class.
320 do_am_class(http_t
*http
, /* I - HTTP connection */
321 int modify
) /* I - Modify the printer? */
323 int i
, j
; /* Looping vars */
324 int element
; /* Element number */
325 int num_printers
; /* Number of printers */
326 ipp_t
*request
, /* IPP request */
327 *response
; /* IPP response */
328 ipp_attribute_t
*attr
; /* member-uris attribute */
329 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
330 const char *name
, /* Pointer to class name */
331 *op
, /* Operation name */
332 *ptr
; /* Pointer to CGI variable */
333 const char *title
; /* Title of page */
334 static const char * const pattrs
[] = /* Requested printer attributes */
342 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
343 op
= cgiGetVariable("OP");
344 name
= cgiGetVariable("PRINTER_NAME");
346 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
349 * Build a CUPS_GET_PRINTERS request, which requires the
350 * following attributes:
353 * attributes-natural-language
356 request
= ippNewRequest(CUPS_GET_PRINTERS
);
358 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
360 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
361 CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
364 * Do the request and get back a response...
369 cgiSetVariable("OP", op
);
371 cgiSetVariable("PRINTER_NAME", name
);
373 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
376 * Create MEMBER_URIS and MEMBER_NAMES arrays...
379 for (element
= 0, attr
= response
->attrs
;
382 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
384 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
385 (!name
|| _cups_strcasecmp(name
, ptr
+ 1)))
388 * Don't show the current class...
391 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
396 for (element
= 0, attr
= response
->attrs
;
399 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
401 if (!name
|| _cups_strcasecmp(name
, attr
->values
[0].string
.text
))
404 * Don't show the current class...
407 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
412 num_printers
= cgiGetSize("MEMBER_URIS");
422 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
423 * following attributes:
426 * attributes-natural-language
430 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
432 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
433 "localhost", 0, "/classes/%s", name
);
434 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
437 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
438 "requested-attributes",
439 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
443 * Do the request and get back a response...
446 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
448 if ((attr
= ippFindAttribute(response
, "member-names",
449 IPP_TAG_NAME
)) != NULL
)
452 * Mark any current members in the class...
455 for (j
= 0; j
< num_printers
; j
++)
456 cgiSetArray("MEMBER_SELECTED", j
, "");
458 for (i
= 0; i
< attr
->num_values
; i
++)
460 for (j
= 0; j
< num_printers
; j
++)
462 if (!_cups_strcasecmp(attr
->values
[i
].string
.text
,
463 cgiGetArray("MEMBER_NAMES", j
)))
465 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
472 if ((attr
= ippFindAttribute(response
, "printer-info",
473 IPP_TAG_TEXT
)) != NULL
)
474 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
476 if ((attr
= ippFindAttribute(response
, "printer-location",
477 IPP_TAG_TEXT
)) != NULL
)
478 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
484 * Update the location and description of an existing printer...
488 cgiCopyTemplateLang("modify-class.tmpl");
493 * Get the name, location, and description for a new printer...
497 cgiCopyTemplateLang("add-class.tmpl");
508 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
509 cgiCopyTemplateLang("error.tmpl");
514 for (ptr
= name
; *ptr
; ptr
++)
515 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
518 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
520 cgiSetVariable("ERROR",
521 cgiText(_("The class name may only contain up to "
522 "127 printable characters and may not "
523 "contain spaces, slashes (/), or the "
524 "pound sign (#).")));
526 cgiCopyTemplateLang("error.tmpl");
532 * Build a CUPS_ADD_CLASS request, which requires the following
536 * attributes-natural-language
540 * printer-is-accepting-jobs
545 request
= ippNewRequest(CUPS_ADD_CLASS
);
547 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
548 "localhost", 0, "/classes/%s", name
);
549 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
552 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
553 NULL
, cgiGetVariable("PRINTER_LOCATION"));
555 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
556 NULL
, cgiGetVariable("PRINTER_INFO"));
558 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
560 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
563 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
565 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
566 num_printers
, NULL
, NULL
);
567 for (i
= 0; i
< num_printers
; i
++)
568 attr
->values
[i
].string
.text
= _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i
));
572 * Do the request and get back a response...
575 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
577 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
579 puts("Status: 401\n");
582 else if (cupsLastError() > IPP_OK_CONFLICT
)
585 cgiShowIPPError(modify
? _("Unable to modify class") :
586 _("Unable to add class"));
591 * Redirect successful updates back to the class page...
594 char refresh
[1024]; /* Refresh URL */
596 cgiFormEncode(uri
, name
, sizeof(uri
));
597 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
599 cgiSetVariable("refresh_page", refresh
);
604 cgiCopyTemplateLang("class-modified.tmpl");
606 cgiCopyTemplateLang("class-added.tmpl");
614 * 'do_am_printer()' - Add or modify a printer.
618 do_am_printer(http_t
*http
, /* I - HTTP connection */
619 int modify
) /* I - Modify the printer? */
621 int i
; /* Looping var */
622 ipp_attribute_t
*attr
; /* Current attribute */
623 ipp_t
*request
, /* IPP request */
624 *response
, /* IPP response */
625 *oldinfo
; /* Old printer information */
626 const cgi_file_t
*file
; /* Uploaded file, if any */
627 const char *var
; /* CGI variable */
628 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
629 *uriptr
, /* Pointer into URI */
630 evefile
[1024] = ""; /* IPP Everywhere PPD file */
631 int maxrate
; /* Maximum baud rate */
632 char baudrate
[255]; /* Baud rate string */
633 const char *name
, /* Pointer to class name */
634 *ptr
; /* Pointer to CGI variable */
635 const char *title
; /* Title of page */
636 static int baudrates
[] = /* Baud rates */
651 ptr
= cgiGetVariable("DEVICE_URI");
652 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
653 ptr
? ptr
: "(null)");
655 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
660 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
661 * following attributes:
664 * attributes-natural-language
668 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
670 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
671 "localhost", 0, "/printers/%s",
672 cgiGetVariable("PRINTER_NAME"));
673 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
677 * Do the request and get back a response...
680 oldinfo
= cupsDoRequest(http
, request
, "/");
689 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
690 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
691 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
692 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
695 if ((name
= cgiGetVariable("PRINTER_NAME")) != NULL
)
697 for (ptr
= name
; *ptr
; ptr
++)
698 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
701 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
703 cgiSetVariable("ERROR",
704 cgiText(_("The printer name may only contain up to "
705 "127 printable characters and may not "
706 "contain spaces, slashes (/), or the "
707 "pound sign (#).")));
709 cgiCopyTemplateLang("error.tmpl");
715 if ((var
= cgiGetVariable("DEVICE_URI")) != NULL
)
717 if ((uriptr
= strrchr(var
, '|')) != NULL
)
720 * Extract make and make/model from device URI string...
723 char make
[1024], /* Make string */
724 *makeptr
; /* Pointer into make */
729 strlcpy(make
, uriptr
, sizeof(make
));
731 if ((makeptr
= strchr(make
, ' ')) != NULL
)
733 else if ((makeptr
= strchr(make
, '-')) != NULL
)
735 else if (!_cups_strncasecmp(make
, "laserjet", 8) ||
736 !_cups_strncasecmp(make
, "deskjet", 7) ||
737 !_cups_strncasecmp(make
, "designjet", 9))
738 strlcpy(make
, "HP", sizeof(make
));
739 else if (!_cups_strncasecmp(make
, "phaser", 6))
740 strlcpy(make
, "Xerox", sizeof(make
));
741 else if (!_cups_strncasecmp(make
, "stylus", 6))
742 strlcpy(make
, "Epson", sizeof(make
));
744 strlcpy(make
, "Generic", sizeof(make
));
746 if (!cgiGetVariable("CURRENT_MAKE"))
747 cgiSetVariable("CURRENT_MAKE", make
);
749 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
750 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
754 char template[128], /* Template name */
755 *tptr
; /* Pointer into template name */
757 cgiSetVariable("PRINTER_INFO", uriptr
);
759 for (tptr
= template;
760 tptr
< (template + sizeof(template) - 1) && *uriptr
;
762 if (isalnum(*uriptr
& 255) || *uriptr
== '_' || *uriptr
== '-' ||
765 else if ((*uriptr
== ' ' || *uriptr
== '/') && tptr
> template &&
768 else if (*uriptr
== '?' || *uriptr
== '(')
773 cgiSetVariable("TEMPLATE_NAME", template);
781 * Look for devices so the user can pick something...
784 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
786 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
787 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
790 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
791 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
795 * Scan for devices for up to 30 seconds...
798 fputs("DEBUG: Getting list of devices...\n", stderr
);
801 if (cupsGetDevices(http
, 5, CUPS_INCLUDE_ALL
, CUPS_EXCLUDE_NONE
,
802 (cups_device_cb_t
)choose_device_cb
,
803 (void *)title
) == IPP_OK
)
805 fputs("DEBUG: Got device list!\n", stderr
);
807 if (cgiSupportsMultipart())
810 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
812 cgiCopyTemplateLang("choose-device.tmpl");
815 if (cgiSupportsMultipart())
821 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
822 cupsLastError(), cupsLastErrorString());
823 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
825 puts("Status: 401\n");
831 cgiShowIPPError(modify
? _("Unable to modify printer") :
832 _("Unable to add printer"));
838 else if (!strchr(var
, '/') ||
839 (!strncmp(var
, "lpd://", 6) && !strchr(var
+ 6, '/')))
841 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
844 * Set the current device URI for the form to the old one...
847 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
848 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
852 * User needs to set the full URI...
856 cgiCopyTemplateLang("choose-uri.tmpl");
859 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
862 * Need baud rate, parity, etc.
865 if ((var
= strchr(var
, '?')) != NULL
&&
866 strncmp(var
, "?baud=", 6) == 0)
867 maxrate
= atoi(var
+ 6);
871 for (i
= 0; i
< 10; i
++)
872 if (baudrates
[i
] > maxrate
)
876 sprintf(baudrate
, "%d", baudrates
[i
]);
877 cgiSetArray("BAUDRATES", i
, baudrate
);
881 cgiCopyTemplateLang("choose-serial.tmpl");
884 else if (!name
|| !cgiGetVariable("PRINTER_LOCATION"))
891 * Update the location and description of an existing printer...
896 if ((attr
= ippFindAttribute(oldinfo
, "printer-info",
897 IPP_TAG_TEXT
)) != NULL
)
898 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
900 if ((attr
= ippFindAttribute(oldinfo
, "printer-location",
901 IPP_TAG_TEXT
)) != NULL
)
902 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
904 if ((attr
= ippFindAttribute(oldinfo
, "printer-is-shared",
905 IPP_TAG_BOOLEAN
)) != NULL
)
906 cgiSetVariable("PRINTER_IS_SHARED",
907 attr
->values
[0].boolean
? "1" : "0");
910 cgiCopyTemplateLang("modify-printer.tmpl");
915 * Get the name, location, and description for a new printer...
919 if (!strncmp(var
, "usb:", 4))
920 cgiSetVariable("printer_is_shared", "1");
922 #endif /* __APPLE__ */
923 cgiSetVariable("printer_is_shared", "0");
925 cgiCopyTemplateLang("add-printer.tmpl");
936 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
938 if (modify
&& !cgiGetVariable("SELECT_MAKE"))
941 * Get the PPD file...
944 int fd
; /* PPD file */
945 char filename
[1024]; /* PPD filename */
946 ppd_file_t
*ppd
; /* PPD information */
947 char buffer
[1024]; /* Buffer */
948 ssize_t bytes
; /* Number of bytes */
949 http_status_t get_status
; /* Status of GET */
952 /* TODO: Use cupsGetFile() API... */
953 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
955 if (httpGet(http
, uri
))
958 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
960 if (get_status
!= HTTP_OK
)
964 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
965 uri
, get_status
, httpStatus(get_status
));
967 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
969 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
970 write(fd
, buffer
, (size_t)bytes
);
974 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
976 if (ppd
->manufacturer
)
977 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
980 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
987 int linenum
; /* Line number */
989 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
990 filename
, ppdErrorString(ppdLastError(&linenum
)));
998 "ERROR: Unable to create temporary file for PPD file: %s\n",
1004 * Build a CUPS_GET_PPDS request, which requires the following
1007 * attributes-charset
1008 * attributes-natural-language
1012 request
= ippNewRequest(CUPS_GET_PPDS
);
1014 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1015 NULL
, "ipp://localhost/printers/");
1017 if ((var
= cgiGetVariable("PPD_MAKE")) == NULL
)
1018 var
= cgiGetVariable("CURRENT_MAKE");
1019 if (var
&& !cgiGetVariable("SELECT_MAKE"))
1021 const char *make_model
; /* Make and model */
1024 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1025 "ppd-make", NULL
, var
);
1027 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1028 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1029 "ppd-make-and-model", NULL
, make_model
);
1032 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1033 "requested-attributes", NULL
, "ppd-make");
1036 * Do the request and get back a response...
1039 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1042 * Got the list of PPDs, see if the user has selected a make...
1045 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0 && !modify
)
1048 * No PPD files with this make, try again with all makes...
1051 ippDelete(response
);
1053 request
= ippNewRequest(CUPS_GET_PPDS
);
1055 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1056 NULL
, "ipp://localhost/printers/");
1058 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1059 "requested-attributes", NULL
, "ppd-make");
1061 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1062 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1064 cgiStartHTML(title
);
1065 cgiCopyTemplateLang("choose-make.tmpl");
1068 else if (!var
|| cgiGetVariable("SELECT_MAKE"))
1070 cgiStartHTML(title
);
1071 cgiCopyTemplateLang("choose-make.tmpl");
1077 * Let the user choose a model...
1080 cgiStartHTML(title
);
1081 if (!cgiGetVariable("PPD_MAKE"))
1082 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1084 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1085 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1086 cgiCopyTemplateLang("choose-model.tmpl");
1090 ippDelete(response
);
1094 cgiStartHTML(title
);
1095 cgiShowIPPError(_("Unable to get list of printer drivers"));
1096 cgiCopyTemplateLang("error.tmpl");
1103 * Build a CUPS_ADD_PRINTER request, which requires the following
1106 * attributes-charset
1107 * attributes-natural-language
1113 * printer-is-accepting-jobs
1118 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1120 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1121 "localhost", 0, "/printers/%s",
1122 cgiGetVariable("PRINTER_NAME"));
1123 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1128 var
= cgiGetVariable("PPD_NAME");
1129 if (!strcmp(var
, "everywhere"))
1130 get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile
, sizeof(evefile
));
1131 else if (strcmp(var
, "__no_change__"))
1132 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name",
1136 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1137 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1139 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1140 NULL
, cgiGetVariable("PRINTER_INFO"));
1142 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1145 * Strip make and model from URI...
1148 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1151 if (!strncmp(uri
, "serial:", 7))
1154 * Update serial port URI to include baud rate, etc.
1157 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1158 uriptr
= uri
+ strlen(uri
);
1160 snprintf(uriptr
, sizeof(uri
) - (size_t)(uriptr
- uri
),
1161 "?baud=%s+bits=%s+parity=%s+flow=%s",
1162 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1163 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1166 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1169 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1171 var
= cgiGetVariable("printer_is_shared");
1172 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-shared",
1173 var
&& (!strcmp(var
, "1") || !strcmp(var
, "on")));
1175 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1179 * Do the request and get back a response...
1183 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1184 else if (evefile
[0])
1186 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", evefile
));
1190 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1192 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1194 puts("Status: 401\n");
1197 else if (cupsLastError() > IPP_OK_CONFLICT
)
1199 cgiStartHTML(title
);
1200 cgiShowIPPError(modify
? _("Unable to modify printer") :
1201 _("Unable to add printer"));
1206 * Redirect successful updates back to the printer page...
1209 char refresh
[1024]; /* Refresh URL */
1212 cgiFormEncode(uri
, name
, sizeof(uri
));
1214 snprintf(refresh
, sizeof(refresh
),
1215 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1217 cgiSetVariable("refresh_page", refresh
);
1219 cgiStartHTML(title
);
1221 cgiCopyTemplateLang("printer-modified.tmpl");
1226 * Set the printer options...
1229 cgiSetVariable("OP", "set-printer-options");
1230 do_set_options(http
, 0);
1243 * 'do_config_server()' - Configure server settings.
1247 do_config_server(http_t
*http
) /* I - HTTP connection */
1249 if (cgiGetVariable("CHANGESETTINGS"))
1252 * Save basic setting changes...
1255 int num_settings
; /* Number of server settings */
1256 cups_option_t
*settings
; /* Server settings */
1257 int advanced
, /* Advanced settings shown? */
1258 changed
; /* Have settings changed? */
1259 const char *debug_logging
, /* DEBUG_LOGGING value */
1260 *preserve_jobs
= NULL
,
1261 /* PRESERVE_JOBS value */
1262 *remote_admin
, /* REMOTE_ADMIN value */
1263 *remote_any
, /* REMOTE_ANY value */
1264 *share_printers
,/* SHARE_PRINTERS value */
1266 /* USER_CANCEL_ANY value */
1267 *browse_web_if
= NULL
,
1268 /* BrowseWebIF value */
1269 *preserve_job_history
= NULL
,
1270 /* PreserveJobHistory value */
1271 *preserve_job_files
= NULL
,
1272 /* PreserveJobFiles value */
1273 *max_clients
= NULL
,
1274 /* MaxClients value */
1277 *max_log_size
= NULL
;
1278 /* MaxLogSize value */
1279 const char *current_browse_web_if
,
1280 /* BrowseWebIF value */
1281 *current_preserve_job_history
,
1282 /* PreserveJobHistory value */
1283 *current_preserve_job_files
,
1284 /* PreserveJobFiles value */
1285 *current_max_clients
,
1286 /* MaxClients value */
1289 *current_max_log_size
;
1290 /* MaxLogSize value */
1292 char default_auth_type
[255];
1293 /* DefaultAuthType value */
1294 const char *val
; /* Setting value */
1295 #endif /* HAVE_GSSAPI */
1299 * Get the checkbox values from the form...
1302 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1303 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1304 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1305 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1306 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1308 advanced
= cgiGetVariable("ADVANCEDSETTINGS") != NULL
;
1312 * Get advanced settings...
1315 browse_web_if
= cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1316 max_clients
= cgiGetVariable("MAX_CLIENTS");
1317 max_log_size
= cgiGetVariable("MAX_LOG_SIZE");
1318 preserve_jobs
= cgiGetVariable("PRESERVE_JOBS");
1322 max_jobs
= cgiGetVariable("MAX_JOBS");
1323 preserve_job_history
= cgiGetVariable("PRESERVE_JOB_HISTORY");
1324 preserve_job_files
= cgiGetVariable("PRESERVE_JOB_FILES");
1326 if (!max_jobs
|| atoi(max_jobs
) < 0)
1329 if (!preserve_job_history
)
1330 preserve_job_history
= "On";
1332 if (!preserve_job_files
)
1333 preserve_job_files
= "1d";
1338 preserve_job_history
= "No";
1339 preserve_job_files
= "No";
1342 if (!max_clients
|| atoi(max_clients
) <= 0)
1343 max_clients
= "100";
1345 if (!max_log_size
|| atoi(max_log_size
) <= 0.0)
1346 max_log_size
= "1m";
1350 * Get the current server settings...
1353 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1355 cgiStartHTML(cgiText(_("Change Settings")));
1356 cgiSetVariable("MESSAGE",
1357 cgiText(_("Unable to change server settings")));
1358 cgiSetVariable("ERROR", cupsLastErrorString());
1359 cgiCopyTemplateLang("error.tmpl");
1366 * Get authentication settings...
1369 if (cgiGetVariable("KERBEROS"))
1370 strlcpy(default_auth_type
, "Negotiate", sizeof(default_auth_type
));
1373 val
= cupsGetOption("DefaultAuthType", num_settings
, settings
);
1375 if (!val
|| !_cups_strcasecmp(val
, "Negotiate"))
1376 strlcpy(default_auth_type
, "Basic", sizeof(default_auth_type
));
1378 strlcpy(default_auth_type
, val
, sizeof(default_auth_type
));
1381 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1382 #endif /* HAVE_GSSAPI */
1384 if ((current_browse_web_if
= cupsGetOption("BrowseWebIF", num_settings
,
1386 current_browse_web_if
= "No";
1388 if ((current_preserve_job_history
= cupsGetOption("PreserveJobHistory",
1391 current_preserve_job_history
= "Yes";
1393 if ((current_preserve_job_files
= cupsGetOption("PreserveJobFiles",
1396 current_preserve_job_files
= "1d";
1398 if ((current_max_clients
= cupsGetOption("MaxClients", num_settings
,
1400 current_max_clients
= "100";
1402 if ((current_max_jobs
= cupsGetOption("MaxJobs", num_settings
,
1404 current_max_jobs
= "500";
1406 if ((current_max_log_size
= cupsGetOption("MaxLogSize", num_settings
,
1408 current_max_log_size
= "1m";
1411 * See if the settings have changed...
1414 changed
= strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1415 num_settings
, settings
)) ||
1416 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1417 num_settings
, settings
)) ||
1418 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1419 num_settings
, settings
)) ||
1420 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1421 num_settings
, settings
)) ||
1423 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1424 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1425 num_settings
, settings
)) ||
1426 #endif /* HAVE_GSSAPI */
1427 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1428 num_settings
, settings
));
1430 if (advanced
&& !changed
)
1431 changed
= _cups_strcasecmp(browse_web_if
, current_browse_web_if
) ||
1432 _cups_strcasecmp(preserve_job_history
, current_preserve_job_history
) ||
1433 _cups_strcasecmp(preserve_job_files
, current_preserve_job_files
) ||
1434 _cups_strcasecmp(max_clients
, current_max_clients
) ||
1435 _cups_strcasecmp(max_jobs
, current_max_jobs
) ||
1436 _cups_strcasecmp(max_log_size
, current_max_log_size
);
1441 * Settings *have* changed, so save the changes...
1444 cupsFreeOptions(num_settings
, settings
);
1447 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1448 debug_logging
, num_settings
, &settings
);
1449 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1450 remote_admin
, num_settings
, &settings
);
1451 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1452 remote_any
, num_settings
, &settings
);
1453 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1454 share_printers
, num_settings
, &settings
);
1455 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1456 user_cancel_any
, num_settings
, &settings
);
1458 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1459 num_settings
, &settings
);
1460 #endif /* HAVE_GSSAPI */
1465 * Add advanced settings...
1468 if (_cups_strcasecmp(browse_web_if
, current_browse_web_if
))
1469 num_settings
= cupsAddOption("BrowseWebIF", browse_web_if
,
1470 num_settings
, &settings
);
1471 if (_cups_strcasecmp(preserve_job_history
, current_preserve_job_history
))
1472 num_settings
= cupsAddOption("PreserveJobHistory",
1473 preserve_job_history
, num_settings
,
1475 if (_cups_strcasecmp(preserve_job_files
, current_preserve_job_files
))
1476 num_settings
= cupsAddOption("PreserveJobFiles", preserve_job_files
,
1477 num_settings
, &settings
);
1478 if (_cups_strcasecmp(max_clients
, current_max_clients
))
1479 num_settings
= cupsAddOption("MaxClients", max_clients
, num_settings
,
1481 if (_cups_strcasecmp(max_jobs
, current_max_jobs
))
1482 num_settings
= cupsAddOption("MaxJobs", max_jobs
, num_settings
,
1484 if (_cups_strcasecmp(max_log_size
, current_max_log_size
))
1485 num_settings
= cupsAddOption("MaxLogSize", max_log_size
, num_settings
,
1489 if (!cupsAdminSetServerSettings(http
, num_settings
, settings
))
1491 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1493 puts("Status: 401\n");
1497 cgiStartHTML(cgiText(_("Change Settings")));
1498 cgiSetVariable("MESSAGE",
1499 cgiText(_("Unable to change server settings")));
1500 cgiSetVariable("ERROR", cupsLastErrorString());
1501 cgiCopyTemplateLang("error.tmpl");
1506 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
1507 "URL=/admin/?ADVANCEDSETTINGS=YES");
1509 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1510 cgiStartHTML(cgiText(_("Change Settings")));
1511 cgiCopyTemplateLang("restart.tmpl");
1520 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1521 cgiStartHTML(cgiText(_("Change Settings")));
1522 cgiCopyTemplateLang("norestart.tmpl");
1525 cupsFreeOptions(num_settings
, settings
);
1529 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1532 * Save hand-edited config file...
1535 http_status_t status
; /* PUT status */
1536 char tempfile
[1024]; /* Temporary new cupsd.conf */
1537 int tempfd
; /* Temporary file descriptor */
1538 cups_file_t
*temp
; /* Temporary file */
1539 const char *start
, /* Start of line */
1540 *end
; /* End of line */
1544 * Create a temporary file for the new cupsd.conf file...
1547 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1549 cgiStartHTML(cgiText(_("Edit Configuration File")));
1550 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1551 cgiSetVariable("ERROR", strerror(errno
));
1552 cgiCopyTemplateLang("error.tmpl");
1559 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1561 cgiStartHTML(cgiText(_("Edit Configuration File")));
1562 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
1563 cgiSetVariable("ERROR", strerror(errno
));
1564 cgiCopyTemplateLang("error.tmpl");
1574 * Copy the cupsd.conf text from the form variable...
1577 start
= cgiGetVariable("CUPSDCONF");
1580 if ((end
= strstr(start
, "\r\n")) == NULL
)
1581 if ((end
= strstr(start
, "\n")) == NULL
)
1582 end
= start
+ strlen(start
);
1584 cupsFileWrite(temp
, start
, (size_t)(end
- start
));
1585 cupsFilePutChar(temp
, '\n');
1589 else if (*end
== '\n')
1595 cupsFileClose(temp
);
1598 * Upload the configuration file to the server...
1601 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1603 if (status
== HTTP_UNAUTHORIZED
)
1605 puts("Status: 401\n");
1609 else if (status
!= HTTP_CREATED
)
1611 cgiSetVariable("MESSAGE",
1612 cgiText(_("Unable to upload cupsd.conf file")));
1613 cgiSetVariable("ERROR", httpStatus(status
));
1615 cgiStartHTML(cgiText(_("Edit Configuration File")));
1616 cgiCopyTemplateLang("error.tmpl");
1620 cgiSetVariable("refresh_page", "5;URL=/admin/");
1622 cgiStartHTML(cgiText(_("Edit Configuration File")));
1623 cgiCopyTemplateLang("restart.tmpl");
1632 struct stat info
; /* cupsd.conf information */
1633 cups_file_t
*cupsd
; /* cupsd.conf file */
1634 char *buffer
, /* Buffer for entire file */
1635 *bufptr
, /* Pointer into buffer */
1636 *bufend
; /* End of buffer */
1637 int ch
; /* Character from file */
1638 char filename
[1024]; /* Filename */
1639 const char *server_root
; /* Location of config files */
1643 * Locate the cupsd.conf file...
1646 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1647 server_root
= CUPS_SERVERROOT
;
1649 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1652 * Figure out the size...
1655 if (stat(filename
, &info
))
1657 cgiStartHTML(cgiText(_("Edit Configuration File")));
1658 cgiSetVariable("MESSAGE",
1659 cgiText(_("Unable to access cupsd.conf file")));
1660 cgiSetVariable("ERROR", strerror(errno
));
1661 cgiCopyTemplateLang("error.tmpl");
1668 if (info
.st_size
> (1024 * 1024))
1670 cgiStartHTML(cgiText(_("Edit Configuration File")));
1671 cgiSetVariable("MESSAGE",
1672 cgiText(_("Unable to access cupsd.conf file")));
1673 cgiSetVariable("ERROR",
1674 cgiText(_("Unable to edit cupsd.conf files larger than "
1676 cgiCopyTemplateLang("error.tmpl");
1679 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1680 (long)info
.st_size
);
1685 * Open the cupsd.conf file...
1688 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1691 * Unable to open - log an error...
1694 cgiStartHTML(cgiText(_("Edit Configuration File")));
1695 cgiSetVariable("MESSAGE",
1696 cgiText(_("Unable to access cupsd.conf file")));
1697 cgiSetVariable("ERROR", strerror(errno
));
1698 cgiCopyTemplateLang("error.tmpl");
1706 * Allocate memory and load the file into a string buffer...
1709 if ((buffer
= calloc(1, (size_t)info
.st_size
+ 1)) != NULL
)
1711 cupsFileRead(cupsd
, buffer
, (size_t)info
.st_size
);
1712 cgiSetVariable("CUPSDCONF", buffer
);
1716 cupsFileClose(cupsd
);
1719 * Then get the default cupsd.conf file and put that into a string as
1723 strlcat(filename
, ".default", sizeof(filename
));
1725 if (!stat(filename
, &info
) && info
.st_size
< (1024 * 1024) &&
1726 (cupsd
= cupsFileOpen(filename
, "r")) != NULL
)
1728 if ((buffer
= calloc(1, 2 * (size_t)info
.st_size
+ 1)) != NULL
)
1730 bufend
= buffer
+ 2 * info
.st_size
- 1;
1732 for (bufptr
= buffer
;
1733 bufptr
< bufend
&& (ch
= cupsFileGetChar(cupsd
)) != EOF
;)
1735 if (ch
== '\\' || ch
== '\"')
1738 *bufptr
++ = (char)ch
;
1740 else if (ch
== '\n')
1745 else if (ch
== '\t')
1751 *bufptr
++ = (char)ch
;
1756 cgiSetVariable("CUPSDCONF_DEFAULT", buffer
);
1760 cupsFileClose(cupsd
);
1764 * Show the current config file...
1767 cgiStartHTML(cgiText(_("Edit Configuration File")));
1769 cgiCopyTemplateLang("edit-config.tmpl");
1777 * 'do_delete_class()' - Delete a class.
1781 do_delete_class(http_t
*http
) /* I - HTTP connection */
1783 ipp_t
*request
; /* IPP request */
1784 char uri
[HTTP_MAX_URI
]; /* Job URI */
1785 const char *pclass
; /* Printer class name */
1789 * Get form variables...
1792 if (cgiGetVariable("CONFIRM") == NULL
)
1794 cgiStartHTML(cgiText(_("Delete Class")));
1795 cgiCopyTemplateLang("class-confirm.tmpl");
1800 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1801 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1802 "localhost", 0, "/classes/%s", pclass
);
1805 cgiStartHTML(cgiText(_("Delete Class")));
1806 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1807 cgiCopyTemplateLang("error.tmpl");
1813 * Build a CUPS_DELETE_CLASS request, which requires the following
1816 * attributes-charset
1817 * attributes-natural-language
1821 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1823 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1827 * Do the request and get back a response...
1830 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1833 * Show the results...
1836 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1838 puts("Status: 401\n");
1841 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1844 * Redirect successful updates back to the classes page...
1847 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1850 cgiStartHTML(cgiText(_("Delete Class")));
1852 if (cupsLastError() > IPP_OK_CONFLICT
)
1853 cgiShowIPPError(_("Unable to delete class"));
1855 cgiCopyTemplateLang("class-deleted.tmpl");
1862 * 'do_delete_printer()' - Delete a printer.
1866 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1868 ipp_t
*request
; /* IPP request */
1869 char uri
[HTTP_MAX_URI
]; /* Job URI */
1870 const char *printer
; /* Printer printer name */
1874 * Get form variables...
1877 if (cgiGetVariable("CONFIRM") == NULL
)
1879 cgiStartHTML(cgiText(_("Delete Printer")));
1880 cgiCopyTemplateLang("printer-confirm.tmpl");
1885 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1886 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1887 "localhost", 0, "/printers/%s", printer
);
1890 cgiStartHTML(cgiText(_("Delete Printer")));
1891 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
1892 cgiCopyTemplateLang("error.tmpl");
1898 * Build a CUPS_DELETE_PRINTER request, which requires the following
1901 * attributes-charset
1902 * attributes-natural-language
1906 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1908 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1912 * Do the request and get back a response...
1915 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1918 * Show the results...
1921 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
1923 puts("Status: 401\n");
1926 else if (cupsLastError() <= IPP_OK_CONFLICT
)
1929 * Redirect successful updates back to the printers page...
1932 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1935 cgiStartHTML(cgiText(_("Delete Printer")));
1937 if (cupsLastError() > IPP_OK_CONFLICT
)
1938 cgiShowIPPError(_("Unable to delete printer"));
1940 cgiCopyTemplateLang("printer-deleted.tmpl");
1947 * 'do_export()' - Export printers to Samba.
1951 do_export(http_t
*http
) /* I - HTTP connection */
1953 int i
, j
; /* Looping vars */
1954 ipp_t
*request
, /* IPP request */
1955 *response
; /* IPP response */
1956 const char *username
, /* Samba username */
1957 *password
, /* Samba password */
1958 *export_all
; /* Export all printers? */
1959 int export_count
, /* Number of printers to export */
1960 printer_count
; /* Number of available printers */
1961 const char *name
, /* What name to pull */
1962 *dest
; /* Current destination */
1963 char ppd
[1024]; /* PPD file */
1970 username
= cgiGetVariable("USERNAME");
1971 password
= cgiGetVariable("PASSWORD");
1972 export_all
= cgiGetVariable("EXPORT_ALL");
1973 export_count
= cgiGetSize("EXPORT_NAME");
1976 * Get list of available printers...
1979 cgiSetSize("PRINTER_NAME", 0);
1980 cgiSetSize("PRINTER_EXPORT", 0);
1982 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1984 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1987 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1988 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
1990 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1991 "requested-attributes", NULL
, "printer-name");
1993 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1995 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1996 ippDelete(response
);
2000 printer_count
= cgiGetSize("PRINTER_NAME");
2002 for (i
= 0; i
< printer_count
; i
++)
2004 dest
= cgiGetArray("PRINTER_NAME", i
);
2006 for (j
= 0; j
< export_count
; j
++)
2007 if (!_cups_strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2010 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2016 * Export or get the printers to export...
2019 if (username
&& *username
&& password
&& *password
&&
2020 (export_all
|| export_count
> 0))
2026 fputs("DEBUG: Export printers...\n", stderr
);
2030 name
= "PRINTER_NAME";
2031 export_count
= cgiGetSize("PRINTER_NAME");
2034 name
= "EXPORT_NAME";
2036 for (i
= 0; i
< export_count
; i
++)
2038 dest
= cgiGetArray(name
, i
);
2040 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2043 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2052 if (i
< export_count
)
2053 cgiSetVariable("ERROR", cupsLastErrorString());
2056 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2057 cgiCopyTemplateLang("samba-exported.tmpl");
2062 else if (username
&& !*username
)
2063 cgiSetVariable("ERROR",
2064 cgiText(_("A Samba username is required to export "
2065 "printer drivers")));
2066 else if (username
&& (!password
|| !*password
))
2067 cgiSetVariable("ERROR",
2068 cgiText(_("A Samba password is required to export "
2069 "printer drivers")));
2075 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2076 cgiCopyTemplateLang("samba-export.tmpl");
2082 * 'do_list_printers()' - List available printers.
2086 do_list_printers(http_t
*http
) /* I - HTTP connection */
2088 ipp_t
*request
, /* IPP request */
2089 *response
; /* IPP response */
2090 ipp_attribute_t
*attr
; /* IPP attribute */
2093 cgiStartHTML(cgiText(_("List Available Printers")));
2097 * Get the list of printers and their devices...
2100 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2102 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2103 "requested-attributes", NULL
, "device-uri");
2105 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2106 CUPS_PRINTER_LOCAL
);
2107 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2108 CUPS_PRINTER_LOCAL
);
2110 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2113 * Got the printer list, now load the devices...
2116 int i
; /* Looping var */
2117 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2118 char *printer_device
; /* Current printer device */
2122 * Allocate an array and copy the device strings...
2125 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2127 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2129 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2131 cupsArrayAdd(printer_devices
, _cupsStrAlloc(attr
->values
[0].string
.text
));
2135 * Free the printer list and get the device list...
2138 ippDelete(response
);
2140 request
= ippNewRequest(CUPS_GET_DEVICES
);
2142 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2145 * Got the device list, let's parse it...
2148 const char *device_uri
, /* device-uri attribute value */
2149 *device_make_and_model
, /* device-make-and-model value */
2150 *device_info
; /* device-info value */
2153 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2156 * Skip leading attributes until we hit a device...
2159 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2166 * Pull the needed attributes from this device...
2170 device_make_and_model
= NULL
;
2173 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2175 if (!strcmp(attr
->name
, "device-info") &&
2176 attr
->value_tag
== IPP_TAG_TEXT
)
2177 device_info
= attr
->values
[0].string
.text
;
2179 if (!strcmp(attr
->name
, "device-make-and-model") &&
2180 attr
->value_tag
== IPP_TAG_TEXT
)
2181 device_make_and_model
= attr
->values
[0].string
.text
;
2183 if (!strcmp(attr
->name
, "device-uri") &&
2184 attr
->value_tag
== IPP_TAG_URI
)
2185 device_uri
= attr
->values
[0].string
.text
;
2191 * See if we have everything needed...
2194 if (device_info
&& device_make_and_model
&& device_uri
&&
2195 _cups_strcasecmp(device_make_and_model
, "unknown") &&
2196 strchr(device_uri
, ':'))
2199 * Yes, now see if there is already a printer for this
2203 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2206 * Not found, so it must be a new printer...
2209 char option
[1024], /* Form variables for this device */
2210 *option_ptr
; /* Pointer into string */
2211 const char *ptr
; /* Pointer into device string */
2215 * Format the printer name variable for this device...
2217 * We use the device-info string first, then device-uri,
2218 * and finally device-make-and-model to come up with a
2222 if (_cups_strncasecmp(device_info
, "unknown", 7))
2224 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2227 ptr
= device_make_and_model
;
2229 for (option_ptr
= option
;
2230 option_ptr
< (option
+ sizeof(option
) - 1) && *ptr
;
2232 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2234 *option_ptr
++ = *ptr
;
2235 else if ((*ptr
== ' ' || *ptr
== '/') && option_ptr
> option
&&
2236 option_ptr
[-1] != '_')
2237 *option_ptr
++ = '_';
2238 else if (*ptr
== '?' || *ptr
== '(')
2243 cgiSetArray("TEMPLATE_NAME", i
, option
);
2246 * Finally, set the form variables for this printer...
2249 cgiSetArray("device_info", i
, device_info
);
2250 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2251 cgiSetArray("device_uri", i
, device_uri
);
2260 ippDelete(response
);
2263 * Free the device list...
2266 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2268 printer_device
= (char *)cupsArrayNext(printer_devices
))
2269 _cupsStrFree(printer_device
);
2271 cupsArrayDelete(printer_devices
);
2276 * Finally, show the printer list...
2279 cgiCopyTemplateLang("list-available-printers.tmpl");
2286 * 'do_menu()' - Show the main menu.
2290 do_menu(http_t
*http
) /* I - HTTP connection */
2292 int num_settings
; /* Number of server settings */
2293 cups_option_t
*settings
; /* Server settings */
2294 const char *val
; /* Setting value */
2295 char filename
[1024]; /* Temporary filename */
2296 const char *datadir
; /* Location of data files */
2297 ipp_t
*request
, /* IPP request */
2298 *response
; /* IPP response */
2302 * Get the current server settings...
2305 if (!cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2307 cgiSetVariable("SETTINGS_MESSAGE",
2308 cgiText(_("Unable to open cupsd.conf file:")));
2309 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2312 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2313 settings
)) != NULL
&& atoi(val
))
2314 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2316 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2317 settings
)) != NULL
&& atoi(val
))
2318 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2320 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2321 settings
)) != NULL
&& atoi(val
))
2322 cgiSetVariable("REMOTE_ANY", "CHECKED");
2324 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2325 settings
)) != NULL
&& atoi(val
))
2326 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2328 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2329 settings
)) != NULL
&& atoi(val
))
2330 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2333 cgiSetVariable("HAVE_GSSAPI", "1");
2335 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2336 settings
)) != NULL
&& !_cups_strcasecmp(val
, "Negotiate"))
2337 cgiSetVariable("KERBEROS", "CHECKED");
2339 #endif /* HAVE_GSSAPI */
2340 cgiSetVariable("KERBEROS", "");
2342 if ((val
= cupsGetOption("BrowseWebIF", num_settings
,
2346 if (!_cups_strcasecmp(val
, "yes") || !_cups_strcasecmp(val
, "on") ||
2347 !_cups_strcasecmp(val
, "true"))
2348 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2350 if ((val
= cupsGetOption("PreserveJobHistory", num_settings
,
2355 (!_cups_strcasecmp(val
, "0") || !_cups_strcasecmp(val
, "no") ||
2356 !_cups_strcasecmp(val
, "off") || !_cups_strcasecmp(val
, "false") ||
2357 !_cups_strcasecmp(val
, "disabled")))
2359 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2360 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2364 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2365 cgiSetVariable("PRESERVE_JOB_HISTORY", val
);
2367 if ((val
= cupsGetOption("PreserveJobFiles", num_settings
,
2371 cgiSetVariable("PRESERVE_JOB_FILES", val
);
2375 if ((val
= cupsGetOption("MaxClients", num_settings
, settings
)) == NULL
)
2378 cgiSetVariable("MAX_CLIENTS", val
);
2380 if ((val
= cupsGetOption("MaxJobs", num_settings
, settings
)) == NULL
)
2383 cgiSetVariable("MAX_JOBS", val
);
2385 if ((val
= cupsGetOption("MaxLogSize", num_settings
, settings
)) == NULL
)
2388 cgiSetVariable("MAX_LOG_SIZE", val
);
2390 cupsFreeOptions(num_settings
, settings
);
2393 * See if Samba and the Windows drivers are installed...
2396 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2397 datadir
= CUPS_DATADIR
;
2399 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2400 if (!access(filename
, R_OK
))
2403 * Found Windows 2000 driver file, see if we have smbclient and
2407 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2408 sizeof(filename
)) &&
2409 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2411 cgiSetVariable("HAVE_SAMBA", "Y");
2414 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2416 fputs("ERROR: smbclient not found!\n", stderr
);
2418 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2420 fputs("ERROR: rpcclient not found!\n", stderr
);
2430 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2432 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2433 NULL
, "ipp://localhost/");
2435 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2437 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2438 ippDelete(response
);
2442 * Finally, show the main menu template...
2445 cgiStartHTML(cgiText(_("Administration")));
2447 cgiCopyTemplateLang("admin.tmpl");
2454 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2458 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2460 int i
; /* Looping var */
2461 ipp_t
*request
, /* IPP request */
2462 *response
; /* IPP response */
2463 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2464 const char *printer
, /* Printer name (purge-jobs) */
2465 *is_class
, /* Is a class? */
2466 *users
, /* List of users or groups */
2467 *type
; /* Allow/deny type */
2468 int num_users
; /* Number of users */
2469 char *ptr
, /* Pointer into users string */
2470 *end
, /* Pointer to end of users string */
2471 quote
; /* Quote character */
2472 ipp_attribute_t
*attr
; /* Attribute */
2473 static const char * const attrs
[] = /* Requested attributes */
2475 "requesting-user-name-allowed",
2476 "requesting-user-name-denied"
2480 is_class
= cgiGetVariable("IS_CLASS");
2481 printer
= cgiGetVariable("PRINTER_NAME");
2485 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2486 cgiStartHTML(cgiText(_("Set Allowed Users")));
2487 cgiCopyTemplateLang("error.tmpl");
2492 users
= cgiGetVariable("users");
2493 type
= cgiGetVariable("type");
2495 if (!users
|| !type
||
2496 (strcmp(type
, "requesting-user-name-allowed") &&
2497 strcmp(type
, "requesting-user-name-denied")))
2500 * Build a Get-Printer-Attributes request, which requires the following
2503 * attributes-charset
2504 * attributes-natural-language
2506 * requested-attributes
2509 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2511 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2512 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2514 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2517 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2518 "requested-attributes",
2519 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2522 * Do the request and get back a response...
2525 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2527 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2529 ippDelete(response
);
2532 cgiStartHTML(cgiText(_("Set Allowed Users")));
2534 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2536 puts("Status: 401\n");
2539 else if (cupsLastError() > IPP_OK_CONFLICT
)
2540 cgiShowIPPError(_("Unable to get printer attributes"));
2542 cgiCopyTemplateLang("users.tmpl");
2549 * Save the changes...
2552 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2555 * Skip whitespace and commas...
2558 while (*ptr
== ',' || isspace(*ptr
& 255))
2564 if (*ptr
== '\'' || *ptr
== '\"')
2567 * Scan quoted name...
2572 for (end
= ptr
; *end
; end
++)
2579 * Scan space or comma-delimited name...
2582 for (end
= ptr
; *end
; end
++)
2583 if (isspace(*end
& 255) || *end
== ',')
2588 * Advance to the next name...
2595 * Build a CUPS-Add-Printer/Class request, which requires the following
2598 * attributes-charset
2599 * attributes-natural-language
2601 * requesting-user-name-{allowed,denied}
2604 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2606 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2607 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2609 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2613 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2614 "requesting-user-name-allowed", NULL
, "all");
2617 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2618 type
, num_users
, NULL
, NULL
);
2620 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2623 * Skip whitespace and commas...
2626 while (*ptr
== ',' || isspace(*ptr
& 255))
2632 if (*ptr
== '\'' || *ptr
== '\"')
2635 * Scan quoted name...
2640 for (end
= ptr
; *end
; end
++)
2647 * Scan space or comma-delimited name...
2650 for (end
= ptr
; *end
; end
++)
2651 if (isspace(*end
& 255) || *end
== ',')
2656 * Terminate the name...
2666 attr
->values
[i
].string
.text
= _cupsStrAlloc(ptr
);
2669 * Advance to the next name...
2677 * Do the request and get back a response...
2680 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2682 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2684 puts("Status: 401\n");
2687 else if (cupsLastError() > IPP_OK_CONFLICT
)
2689 cgiStartHTML(cgiText(_("Set Allowed Users")));
2690 cgiShowIPPError(_("Unable to change printer"));
2695 * Redirect successful updates back to the printer page...
2698 char url
[1024], /* Printer/class URL */
2699 refresh
[1024]; /* Refresh URL */
2702 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2703 cgiFormEncode(uri
, url
, sizeof(uri
));
2704 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2706 cgiSetVariable("refresh_page", refresh
);
2708 cgiStartHTML(cgiText(_("Set Allowed Users")));
2710 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2711 "printer-modified.tmpl");
2720 * 'do_set_default()' - Set the server default printer/class.
2724 do_set_default(http_t
*http
) /* I - HTTP connection */
2726 const char *title
; /* Page title */
2727 ipp_t
*request
; /* IPP request */
2728 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2729 const char *printer
, /* Printer name (purge-jobs) */
2730 *is_class
; /* Is a class? */
2733 is_class
= cgiGetVariable("IS_CLASS");
2734 printer
= cgiGetVariable("PRINTER_NAME");
2735 title
= cgiText(_("Set As Server Default"));
2739 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2740 cgiStartHTML(title
);
2741 cgiCopyTemplateLang("error.tmpl");
2747 * Build a printer request, which requires the following
2750 * attributes-charset
2751 * attributes-natural-language
2755 request
= ippNewRequest(CUPS_SET_DEFAULT
);
2757 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2758 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2760 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2764 * Do the request and get back a response...
2767 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2769 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
2771 puts("Status: 401\n");
2774 else if (cupsLastError() > IPP_OK_CONFLICT
)
2776 cgiStartHTML(title
);
2777 cgiShowIPPError(_("Unable to set server default"));
2782 * Redirect successful updates back to the printer page...
2785 char url
[1024], /* Printer/class URL */
2786 refresh
[1024]; /* Refresh URL */
2789 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2790 cgiFormEncode(uri
, url
, sizeof(uri
));
2791 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2792 cgiSetVariable("refresh_page", refresh
);
2794 cgiStartHTML(title
);
2795 cgiCopyTemplateLang("printer-default.tmpl");
2803 * 'do_set_options()' - Configure the default options for a queue.
2807 do_set_options(http_t
*http
, /* I - HTTP connection */
2808 int is_class
) /* I - Set options for class? */
2810 int i
, j
, k
, m
; /* Looping vars */
2811 int have_options
; /* Have options? */
2812 ipp_t
*request
, /* IPP request */
2813 *response
; /* IPP response */
2814 ipp_attribute_t
*attr
; /* IPP attribute */
2815 char uri
[HTTP_MAX_URI
]; /* Job URI */
2816 const char *var
; /* Variable value */
2817 const char *printer
; /* Printer printer name */
2818 const char *filename
; /* PPD filename */
2819 char tempfile
[1024]; /* Temporary filename */
2820 cups_file_t
*in
, /* Input file */
2821 *out
; /* Output file */
2822 char line
[1024], /* Line from PPD file */
2823 value
[1024], /* Option value */
2824 keyword
[1024], /* Keyword from Default line */
2825 *keyptr
; /* Pointer into keyword... */
2826 ppd_file_t
*ppd
; /* PPD file */
2827 ppd_group_t
*group
; /* Option group */
2828 ppd_option_t
*option
; /* Option */
2829 ppd_coption_t
*coption
; /* Custom option */
2830 ppd_cparam_t
*cparam
; /* Custom parameter */
2831 ppd_attr_t
*ppdattr
; /* PPD attribute */
2832 const char *title
; /* Page title */
2835 title
= cgiText(is_class
? _("Set Class Options") : _("Set Printer Options"));
2837 fprintf(stderr
, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http
,
2841 * Get the printer name...
2844 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2845 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2846 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2850 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2851 cgiStartHTML(title
);
2852 cgiCopyTemplateLang("error.tmpl");
2857 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
2860 * If the user clicks on the Auto-Configure button, send an AutoConfigure
2861 * command file to the printer...
2864 if (cgiGetVariable("AUTOCONFIGURE"))
2866 cgiPrintCommand(http
, printer
, "AutoConfigure", "Set Default Options");
2871 * Get the PPD file...
2877 filename
= cupsGetPPD2(http
, printer
);
2881 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
2883 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
2885 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
2886 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
2887 cgiStartHTML(title
);
2888 cgiCopyTemplateLang("error.tmpl");
2895 fputs("DEBUG: No PPD file\n", stderr
);
2899 if (cgiGetVariable("job_sheets_start") != NULL
||
2900 cgiGetVariable("job_sheets_end") != NULL
)
2907 ppdMarkDefaults(ppd
);
2909 for (option
= ppdFirstOption(ppd
);
2911 option
= ppdNextOption(ppd
))
2913 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
2916 ppdMarkOption(ppd
, option
->keyword
, var
);
2917 fprintf(stderr
, "DEBUG: Set %s to %s...\n", option
->keyword
, var
);
2920 fprintf(stderr
, "DEBUG: Didn't find %s...\n", option
->keyword
);
2924 if (!have_options
|| ppdConflicts(ppd
))
2927 * Show the options to the user...
2930 fputs("DEBUG: Showing options...\n", stderr
);
2933 * Show auto-configure button if supported...
2938 if (ppd
->num_filters
== 0 ||
2939 ((ppdattr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) != NULL
&&
2940 ppdattr
->value
&& strstr(ppdattr
->value
, "AutoConfigure")))
2941 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2944 for (i
= 0; i
< ppd
->num_filters
; i
++)
2945 if (!strncmp(ppd
->filters
[i
], "application/vnd.cups-postscript", 31))
2947 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2954 * Get the printer attributes...
2957 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2959 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2960 "localhost", 0, "/printers/%s", printer
);
2961 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2964 response
= cupsDoRequest(http
, request
, "/");
2967 * List the groups used as "tabs"...
2974 for (group
= ppd
->groups
;
2975 i
< ppd
->num_groups
;
2978 cgiSetArray("GROUP_ID", i
, group
->name
);
2980 if (!strcmp(group
->name
, "InstallableOptions"))
2981 cgiSetArray("GROUP", i
, cgiText(_("Options Installed")));
2983 cgiSetArray("GROUP", i
, group
->text
);
2987 if (ippFindAttribute(response
, "job-sheets-supported", IPP_TAG_ZERO
))
2989 cgiSetArray("GROUP_ID", i
, "CUPS_BANNERS");
2990 cgiSetArray("GROUP", i
++, cgiText(_("Banners")));
2993 if (ippFindAttribute(response
, "printer-error-policy-supported",
2995 ippFindAttribute(response
, "printer-op-policy-supported",
2998 cgiSetArray("GROUP_ID", i
, "CUPS_POLICIES");
2999 cgiSetArray("GROUP", i
++, cgiText(_("Policies")));
3002 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3003 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3005 cgiSetArray("GROUP_ID", i
, "CUPS_PORT_MONITOR");
3006 cgiSetArray("GROUP", i
, cgiText(_("Port Monitor")));
3009 cgiStartHTML(cgiText(_("Set Printer Options")));
3010 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3016 if (ppdConflicts(ppd
))
3018 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
3021 for (j
= group
->num_options
, option
= group
->options
;
3024 if (option
->conflicted
)
3026 cgiSetArray("ckeyword", k
, option
->keyword
);
3027 cgiSetArray("ckeytext", k
, option
->text
);
3029 for (m
= 0; m
< option
->num_choices
; m
++)
3031 if (option
->choices
[m
].marked
)
3033 cgiSetArray("cchoice", k
, option
->choices
[m
].text
);
3041 cgiCopyTemplateLang("option-conflict.tmpl");
3044 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
3048 for (j
= group
->num_options
, option
= group
->options
;
3052 if (!strcmp(option
->keyword
, "PageRegion"))
3055 if (option
->num_choices
> 1)
3062 cgiSetVariable("GROUP_ID", group
->name
);
3064 if (!strcmp(group
->name
, "InstallableOptions"))
3065 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3067 cgiSetVariable("GROUP", group
->text
);
3069 cgiCopyTemplateLang("option-header.tmpl");
3071 for (j
= group
->num_options
, option
= group
->options
;
3075 if (!strcmp(option
->keyword
, "PageRegion") || option
->num_choices
< 2)
3078 cgiSetVariable("KEYWORD", option
->keyword
);
3079 cgiSetVariable("KEYTEXT", option
->text
);
3081 if (option
->conflicted
)
3082 cgiSetVariable("CONFLICTED", "1");
3084 cgiSetVariable("CONFLICTED", "0");
3086 cgiSetSize("CHOICES", 0);
3087 cgiSetSize("TEXT", 0);
3088 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
3090 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
3091 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
3095 if (option
->choices
[k
].marked
)
3096 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
3099 cgiSetSize("PARAMS", 0);
3100 cgiSetSize("PARAMTEXT", 0);
3101 cgiSetSize("PARAMVALUE", 0);
3102 cgiSetSize("INPUTTYPE", 0);
3104 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)))
3106 const char *units
= NULL
; /* Units value, if any */
3108 cgiSetVariable("ISCUSTOM", "1");
3110 for (cparam
= ppdFirstCustomParam(coption
), m
= 0;
3112 cparam
= ppdNextCustomParam(coption
), m
++)
3114 if (!_cups_strcasecmp(option
->keyword
, "PageSize") &&
3115 _cups_strcasecmp(cparam
->name
, "Width") &&
3116 _cups_strcasecmp(cparam
->name
, "Height"))
3122 cgiSetArray("PARAMS", m
, cparam
->name
);
3123 cgiSetArray("PARAMTEXT", m
, cparam
->text
);
3124 cgiSetArray("INPUTTYPE", m
, "text");
3126 switch (cparam
->type
)
3128 case PPD_CUSTOM_POINTS
:
3129 if (!_cups_strncasecmp(option
->defchoice
, "Custom.", 7))
3131 units
= option
->defchoice
+ strlen(option
->defchoice
) - 2;
3133 if (strcmp(units
, "mm") && strcmp(units
, "cm") &&
3134 strcmp(units
, "in") && strcmp(units
, "ft"))
3136 if (units
[1] == 'm')
3145 if (!strcmp(units
, "mm"))
3146 snprintf(value
, sizeof(value
), "%g",
3147 cparam
->current
.custom_points
/ 72.0 * 25.4);
3148 else if (!strcmp(units
, "cm"))
3149 snprintf(value
, sizeof(value
), "%g",
3150 cparam
->current
.custom_points
/ 72.0 * 2.54);
3151 else if (!strcmp(units
, "in"))
3152 snprintf(value
, sizeof(value
), "%g",
3153 cparam
->current
.custom_points
/ 72.0);
3154 else if (!strcmp(units
, "ft"))
3155 snprintf(value
, sizeof(value
), "%g",
3156 cparam
->current
.custom_points
/ 72.0 / 12.0);
3157 else if (!strcmp(units
, "m"))
3158 snprintf(value
, sizeof(value
), "%g",
3159 cparam
->current
.custom_points
/ 72.0 * 0.0254);
3161 snprintf(value
, sizeof(value
), "%g",
3162 cparam
->current
.custom_points
);
3163 cgiSetArray("PARAMVALUE", m
, value
);
3166 case PPD_CUSTOM_CURVE
:
3167 case PPD_CUSTOM_INVCURVE
:
3168 case PPD_CUSTOM_REAL
:
3169 snprintf(value
, sizeof(value
), "%g",
3170 cparam
->current
.custom_real
);
3171 cgiSetArray("PARAMVALUE", m
, value
);
3174 case PPD_CUSTOM_INT
:
3175 snprintf(value
, sizeof(value
), "%d",
3176 cparam
->current
.custom_int
);
3177 cgiSetArray("PARAMVALUE", m
, value
);
3180 case PPD_CUSTOM_PASSCODE
:
3181 case PPD_CUSTOM_PASSWORD
:
3182 if (cparam
->current
.custom_password
)
3183 cgiSetArray("PARAMVALUE", m
,
3184 cparam
->current
.custom_password
);
3186 cgiSetArray("PARAMVALUE", m
, "");
3187 cgiSetArray("INPUTTYPE", m
, "password");
3190 case PPD_CUSTOM_STRING
:
3191 if (cparam
->current
.custom_string
)
3192 cgiSetArray("PARAMVALUE", m
,
3193 cparam
->current
.custom_string
);
3195 cgiSetArray("PARAMVALUE", m
, "");
3202 cgiSetArray("PARAMS", m
, "Units");
3203 cgiSetArray("PARAMTEXT", m
, cgiText(_("Units")));
3204 cgiSetArray("PARAMVALUE", m
, units
);
3208 cgiSetVariable("ISCUSTOM", "0");
3212 case PPD_UI_BOOLEAN
:
3213 cgiCopyTemplateLang("option-boolean.tmpl");
3215 case PPD_UI_PICKONE
:
3216 cgiCopyTemplateLang("option-pickone.tmpl");
3218 case PPD_UI_PICKMANY
:
3219 cgiCopyTemplateLang("option-pickmany.tmpl");
3224 cgiCopyTemplateLang("option-trailer.tmpl");
3228 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
3229 IPP_TAG_ZERO
)) != NULL
)
3232 * Add the job sheets options...
3235 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3236 cgiSetVariable("GROUP", cgiText(_("Banners")));
3237 cgiCopyTemplateLang("option-header.tmpl");
3239 cgiSetSize("CHOICES", attr
->num_values
);
3240 cgiSetSize("TEXT", attr
->num_values
);
3241 for (k
= 0; k
< attr
->num_values
; k
++)
3243 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3244 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3247 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
3249 cgiSetVariable("KEYWORD", "job_sheets_start");
3250 cgiSetVariable("KEYTEXT",
3251 /* TRANSLATORS: Banner/cover sheet before the print job. */
3252 cgiText(_("Starting Banner")));
3253 cgiSetVariable("DEFCHOICE", attr
!= NULL
?
3254 attr
->values
[0].string
.text
: "");
3256 cgiCopyTemplateLang("option-pickone.tmpl");
3258 cgiSetVariable("KEYWORD", "job_sheets_end");
3259 cgiSetVariable("KEYTEXT",
3260 /* TRANSLATORS: Banner/cover sheet after the print job. */
3261 cgiText(_("Ending Banner")));
3262 cgiSetVariable("DEFCHOICE", attr
!= NULL
&& attr
->num_values
> 1 ?
3263 attr
->values
[1].string
.text
: "");
3265 cgiCopyTemplateLang("option-pickone.tmpl");
3267 cgiCopyTemplateLang("option-trailer.tmpl");
3270 if (ippFindAttribute(response
, "printer-error-policy-supported",
3272 ippFindAttribute(response
, "printer-op-policy-supported",
3276 * Add the error and operation policy options...
3279 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3280 cgiSetVariable("GROUP", cgiText(_("Policies")));
3281 cgiCopyTemplateLang("option-header.tmpl");
3287 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
3292 cgiSetSize("CHOICES", attr
->num_values
);
3293 cgiSetSize("TEXT", attr
->num_values
);
3294 for (k
= 0; k
< attr
->num_values
; k
++)
3296 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3297 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3300 attr
= ippFindAttribute(response
, "printer-error-policy",
3303 cgiSetVariable("KEYWORD", "printer_error_policy");
3304 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3305 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3306 "" : attr
->values
[0].string
.text
);
3309 cgiCopyTemplateLang("option-pickone.tmpl");
3312 * Operation policy...
3315 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
3320 cgiSetSize("CHOICES", attr
->num_values
);
3321 cgiSetSize("TEXT", attr
->num_values
);
3322 for (k
= 0; k
< attr
->num_values
; k
++)
3324 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
3325 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
3328 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
3330 cgiSetVariable("KEYWORD", "printer_op_policy");
3331 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3332 cgiSetVariable("DEFCHOICE", attr
== NULL
?
3333 "" : attr
->values
[0].string
.text
);
3335 cgiCopyTemplateLang("option-pickone.tmpl");
3338 cgiCopyTemplateLang("option-trailer.tmpl");
3342 * Binary protocol support...
3345 if ((attr
= ippFindAttribute(response
, "port-monitor-supported",
3346 IPP_TAG_NAME
)) != NULL
&& attr
->num_values
> 1)
3348 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3349 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3351 cgiSetSize("CHOICES", attr
->num_values
);
3352 cgiSetSize("TEXT", attr
->num_values
);
3354 for (i
= 0; i
< attr
->num_values
; i
++)
3356 cgiSetArray("CHOICES", i
, attr
->values
[i
].string
.text
);
3357 cgiSetArray("TEXT", i
, attr
->values
[i
].string
.text
);
3360 attr
= ippFindAttribute(response
, "port-monitor", IPP_TAG_NAME
);
3361 cgiSetVariable("KEYWORD", "port_monitor");
3362 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3363 cgiSetVariable("DEFCHOICE", attr
? attr
->values
[0].string
.text
: "none");
3365 cgiCopyTemplateLang("option-header.tmpl");
3366 cgiCopyTemplateLang("option-pickone.tmpl");
3367 cgiCopyTemplateLang("option-trailer.tmpl");
3370 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3373 ippDelete(response
);
3378 * Set default options...
3381 fputs("DEBUG: Setting options...\n", stderr
);
3385 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
3386 in
= cupsFileOpen(filename
, "r");
3390 cgiSetVariable("ERROR", strerror(errno
));
3391 cgiStartHTML(cgiText(_("Set Printer Options")));
3392 cgiCopyTemplateLang("error.tmpl");
3408 while (cupsFileGets(in
, line
, sizeof(line
)))
3410 if (!strncmp(line
, "*cupsProtocol:", 14))
3412 else if (strncmp(line
, "*Default", 8))
3413 cupsFilePrintf(out
, "%s\n", line
);
3417 * Get default option name...
3420 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
3422 for (keyptr
= keyword
; *keyptr
; keyptr
++)
3423 if (*keyptr
== ':' || isspace(*keyptr
& 255))
3428 if (!strcmp(keyword
, "PageRegion") ||
3429 !strcmp(keyword
, "PaperDimension") ||
3430 !strcmp(keyword
, "ImageableArea"))
3431 var
= get_option_value(ppd
, "PageSize", value
, sizeof(value
));
3433 var
= get_option_value(ppd
, keyword
, value
, sizeof(value
));
3436 cupsFilePrintf(out
, "%s\n", line
);
3438 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
3448 * Make sure temporary filename is cleared when there is no PPD...
3455 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3456 * following attributes:
3458 * attributes-charset
3459 * attributes-natural-language
3461 * job-sheets-default
3462 * printer-error-policy
3467 request
= ippNewRequest(is_class
? CUPS_ADD_MODIFY_CLASS
:
3468 CUPS_ADD_MODIFY_PRINTER
);
3470 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3473 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3474 "job-sheets-default", 2, NULL
, NULL
);
3475 attr
->values
[0].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3476 attr
->values
[1].string
.text
= _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3478 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
3479 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3480 "printer-error-policy", NULL
, var
);
3482 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
3483 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3484 "printer-op-policy", NULL
, var
);
3486 if ((var
= cgiGetVariable("port_monitor")) != NULL
)
3487 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3488 "port-monitor", NULL
, var
);
3491 * Do the request and get back a response...
3495 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
3497 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3499 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3501 puts("Status: 401\n");
3504 else if (cupsLastError() > IPP_OK_CONFLICT
)
3506 cgiStartHTML(title
);
3507 cgiShowIPPError(_("Unable to set options"));
3512 * Redirect successful updates back to the printer page...
3515 char refresh
[1024]; /* Refresh URL */
3518 cgiFormEncode(uri
, printer
, sizeof(uri
));
3519 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3520 is_class
? "classes" : "printers", uri
);
3521 cgiSetVariable("refresh_page", refresh
);
3523 cgiStartHTML(title
);
3525 cgiCopyTemplateLang("printer-configured.tmpl");
3540 * 'do_set_sharing()' - Set printer-is-shared value.
3544 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3546 ipp_t
*request
, /* IPP request */
3547 *response
; /* IPP response */
3548 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3549 const char *printer
, /* Printer name */
3550 *is_class
, /* Is a class? */
3551 *shared
; /* Sharing value */
3554 is_class
= cgiGetVariable("IS_CLASS");
3555 printer
= cgiGetVariable("PRINTER_NAME");
3556 shared
= cgiGetVariable("SHARED");
3558 if (!printer
|| !shared
)
3560 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3561 cgiStartHTML(cgiText(_("Set Publishing")));
3562 cgiCopyTemplateLang("error.tmpl");
3568 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3569 * following attributes:
3571 * attributes-charset
3572 * attributes-natural-language
3577 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3579 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3580 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3582 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3585 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", (char)atoi(shared
));
3588 * Do the request and get back a response...
3591 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3593 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3595 ippDelete(response
);
3598 if (cupsLastError() == IPP_NOT_AUTHORIZED
)
3600 puts("Status: 401\n");
3603 else if (cupsLastError() > IPP_OK_CONFLICT
)
3605 cgiStartHTML(cgiText(_("Set Publishing")));
3606 cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
3611 * Redirect successful updates back to the printer page...
3614 char url
[1024], /* Printer/class URL */
3615 refresh
[1024]; /* Refresh URL */
3618 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3619 cgiFormEncode(uri
, url
, sizeof(uri
));
3620 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3621 cgiSetVariable("refresh_page", refresh
);
3623 cgiStartHTML(cgiText(_("Set Publishing")));
3624 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3625 "printer-modified.tmpl");
3633 * 'get_option_value()' - Return the value of an option.
3635 * This function also handles generation of custom option values.
3638 static char * /* O - Value string or NULL on error */
3640 ppd_file_t
*ppd
, /* I - PPD file */
3641 const char *name
, /* I - Option name */
3642 char *buffer
, /* I - String buffer */
3643 size_t bufsize
) /* I - Size of buffer */
3645 char *bufptr
, /* Pointer into buffer */
3646 *bufend
; /* End of buffer */
3647 ppd_coption_t
*coption
; /* Custom option */
3648 ppd_cparam_t
*cparam
; /* Current custom parameter */
3649 char keyword
[256]; /* Parameter name */
3650 const char *val
, /* Parameter value */
3651 *uval
; /* Units value */
3652 long integer
; /* Integer value */
3653 double number
, /* Number value */
3654 number_points
; /* Number in points */
3658 * See if we have a custom option choice...
3661 if ((val
= cgiGetVariable(name
)) == NULL
)
3669 else if (_cups_strcasecmp(val
, "Custom") ||
3670 (coption
= ppdFindCustomOption(ppd
, name
)) == NULL
)
3673 * Not a custom choice...
3676 strlcpy(buffer
, val
, bufsize
);
3681 * OK, we have a custom option choice, format it...
3686 if (!strcmp(coption
->keyword
, "PageSize"))
3688 const char *lval
; /* Length string value */
3689 double width
, /* Width value */
3690 width_points
, /* Width in points */
3691 length
, /* Length value */
3692 length_points
; /* Length in points */
3695 val
= cgiGetVariable("PageSize.Width");
3696 lval
= cgiGetVariable("PageSize.Height");
3697 uval
= cgiGetVariable("PageSize.Units");
3699 if (!val
|| !lval
|| !uval
||
3700 (width
= strtod(val
, NULL
)) == 0.0 ||
3701 (length
= strtod(lval
, NULL
)) == 0.0 ||
3702 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3703 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3706 width_points
= get_points(width
, uval
);
3707 length_points
= get_points(length
, uval
);
3709 if (width_points
< ppd
->custom_min
[0] ||
3710 width_points
> ppd
->custom_max
[0] ||
3711 length_points
< ppd
->custom_min
[1] ||
3712 length_points
> ppd
->custom_max
[1])
3715 snprintf(buffer
, bufsize
, "Custom.%gx%g%s", width
, length
, uval
);
3717 else if (cupsArrayCount(coption
->params
) == 1)
3719 cparam
= ppdFirstCustomParam(coption
);
3720 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
, cparam
->name
);
3722 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3725 switch (cparam
->type
)
3727 case PPD_CUSTOM_CURVE
:
3728 case PPD_CUSTOM_INVCURVE
:
3729 case PPD_CUSTOM_REAL
:
3730 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3731 number
< cparam
->minimum
.custom_real
||
3732 number
> cparam
->maximum
.custom_real
)
3735 snprintf(buffer
, bufsize
, "Custom.%g", number
);
3738 case PPD_CUSTOM_INT
:
3739 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3740 integer
== LONG_MAX
||
3741 integer
< cparam
->minimum
.custom_int
||
3742 integer
> cparam
->maximum
.custom_int
)
3745 snprintf(buffer
, bufsize
, "Custom.%ld", integer
);
3748 case PPD_CUSTOM_POINTS
:
3749 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3751 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3752 (uval
= cgiGetVariable(keyword
)) == NULL
||
3753 (strcmp(uval
, "pt") && strcmp(uval
, "in") && strcmp(uval
, "ft") &&
3754 strcmp(uval
, "cm") && strcmp(uval
, "mm") && strcmp(uval
, "m")))
3757 number_points
= get_points(number
, uval
);
3758 if (number_points
< cparam
->minimum
.custom_points
||
3759 number_points
> cparam
->maximum
.custom_points
)
3762 snprintf(buffer
, bufsize
, "Custom.%g%s", number
, uval
);
3765 case PPD_CUSTOM_PASSCODE
:
3766 for (uval
= val
; *uval
; uval
++)
3767 if (!isdigit(*uval
& 255))
3770 case PPD_CUSTOM_PASSWORD
:
3771 case PPD_CUSTOM_STRING
:
3772 integer
= (long)strlen(val
);
3773 if (integer
< cparam
->minimum
.custom_string
||
3774 integer
> cparam
->maximum
.custom_string
)
3777 snprintf(buffer
, bufsize
, "Custom.%s", val
);
3783 const char *prefix
= "{"; /* Prefix string */
3787 bufend
= buffer
+ bufsize
;
3789 for (cparam
= ppdFirstCustomParam(coption
);
3791 cparam
= ppdNextCustomParam(coption
))
3793 snprintf(keyword
, sizeof(keyword
), "%s.%s", coption
->keyword
,
3796 if ((val
= cgiGetVariable(keyword
)) == NULL
)
3799 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%s%s=", prefix
, cparam
->name
);
3800 bufptr
+= strlen(bufptr
);
3803 switch (cparam
->type
)
3805 case PPD_CUSTOM_CURVE
:
3806 case PPD_CUSTOM_INVCURVE
:
3807 case PPD_CUSTOM_REAL
:
3808 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3809 number
< cparam
->minimum
.custom_real
||
3810 number
> cparam
->maximum
.custom_real
)
3813 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g", number
);
3816 case PPD_CUSTOM_INT
:
3817 if (!*val
|| (integer
= strtol(val
, NULL
, 10)) == LONG_MIN
||
3818 integer
== LONG_MAX
||
3819 integer
< cparam
->minimum
.custom_int
||
3820 integer
> cparam
->maximum
.custom_int
)
3823 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%ld", integer
);
3826 case PPD_CUSTOM_POINTS
:
3827 snprintf(keyword
, sizeof(keyword
), "%s.Units", coption
->keyword
);
3829 if ((number
= strtod(val
, NULL
)) == 0.0 ||
3830 (uval
= cgiGetVariable(keyword
)) == NULL
||
3831 (strcmp(uval
, "pt") && strcmp(uval
, "in") &&
3832 strcmp(uval
, "ft") && strcmp(uval
, "cm") &&
3833 strcmp(uval
, "mm") && strcmp(uval
, "m")))
3836 number_points
= get_points(number
, uval
);
3837 if (number_points
< cparam
->minimum
.custom_points
||
3838 number_points
> cparam
->maximum
.custom_points
)
3841 snprintf(bufptr
, (size_t)(bufend
- bufptr
), "%g%s", number
, uval
);
3844 case PPD_CUSTOM_PASSCODE
:
3845 for (uval
= val
; *uval
; uval
++)
3846 if (!isdigit(*uval
& 255))
3849 case PPD_CUSTOM_PASSWORD
:
3850 case PPD_CUSTOM_STRING
:
3851 integer
= (long)strlen(val
);
3852 if (integer
< cparam
->minimum
.custom_string
||
3853 integer
> cparam
->maximum
.custom_string
)
3856 if ((bufptr
+ 2) > bufend
)
3862 while (*val
&& bufptr
< bufend
)
3864 if (*val
== '\\' || *val
== '\"')
3866 if ((bufptr
+ 1) >= bufend
)
3875 if (bufptr
>= bufend
)
3884 bufptr
+= strlen(bufptr
);
3887 if (bufptr
== buffer
|| (bufend
- bufptr
) < 2)
3890 memcpy(bufptr
, "}", 2);
3898 * 'get_points()' - Get a value in points.
3901 static double /* O - Number in points */
3902 get_points(double number
, /* I - Original number */
3903 const char *uval
) /* I - Units */
3905 if (!strcmp(uval
, "mm")) /* Millimeters */
3906 return (number
* 72.0 / 25.4);
3907 else if (!strcmp(uval
, "cm")) /* Centimeters */
3908 return (number
* 72.0 / 2.54);
3909 else if (!strcmp(uval
, "in")) /* Inches */
3910 return (number
* 72.0);
3911 else if (!strcmp(uval
, "ft")) /* Feet */
3912 return (number
* 72.0 * 12.0);
3913 else if (!strcmp(uval
, "m")) /* Meters */
3914 return (number
* 72.0 / 0.0254);
3921 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
3924 static char * /* O - Filename or NULL */
3925 get_printer_ppd(const char *uri
, /* I - Printer URI */
3926 char *buffer
, /* I - Filename buffer */
3927 size_t bufsize
) /* I - Size of filename buffer */
3929 http_t
*http
; /* Connection to printer */
3930 ipp_t
*request
, /* Get-Printer-Attributes request */
3931 *response
; /* Get-Printer-Attributes response */
3932 char resolved
[1024], /* Resolved URI */
3933 scheme
[32], /* URI scheme */
3934 userpass
[256], /* Username:password */
3935 host
[256], /* Hostname */
3936 resource
[256]; /* Resource path */
3937 int port
; /* Port number */
3941 * Connect to the printer...
3944 if (strstr(uri
, "._tcp"))
3950 if (!_httpResolveURI(uri
, resolved
, sizeof(resolved
), _HTTP_RESOLVE_DEFAULT
, NULL
, NULL
))
3952 fprintf(stderr
, "ERROR: Unable to resolve \"%s\".\n", uri
);
3959 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), host
, sizeof(host
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
3961 fprintf(stderr
, "ERROR: Bad printer URI \"%s\".\n", uri
);
3965 http
= httpConnect2(host
, port
, NULL
, AF_UNSPEC
, !strcmp(scheme
, "ipps") ? HTTP_ENCRYPTION_ALWAYS
: HTTP_ENCRYPTION_IF_REQUESTED
, 1, 30000, NULL
);
3968 fprintf(stderr
, "ERROR: Unable to connect to \"%s:%d\": %s\n", host
, port
, cupsLastErrorString());
3973 * Send a Get-Printer-Attributes request...
3976 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
3977 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
3978 response
= cupsDoRequest(http
, request
, resource
);
3980 if (!_ppdCreateFromIPP(buffer
, bufsize
, response
))
3981 fprintf(stderr
, "ERROR: Unable to create PPD file: %s\n", strerror(errno
));
3983 ippDelete(response
);