2 * "$Id: admin.c 5240 2006-03-07 21:55:29Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Main entry for CGI.
27 * do_am_class() - Add or modify a class.
28 * do_am_printer() - Add or modify a printer.
29 * do_config_printer() - Configure the default options for a printer.
30 * do_config_server() - Configure server settings.
31 * do_delete_class() - Delete a class...
32 * do_delete_printer() - Delete a printer...
33 * do_export() - Export printers to Samba...
34 * do_menu() - Show the main menu...
35 * do_printer_op() - Do a printer operation.
36 * do_set_allowed_users() - Set the allowed/denied users for a queue.
37 * do_set_sharing() - Set printer-is-shared value...
38 * match_string() - Return the number of matching characters.
42 * Include necessary headers...
45 #include "cgi-private.h"
46 #include <cups/adminutil.h>
47 #include <cups/file.h>
58 static void do_am_class(http_t
*http
, int modify
);
59 static void do_am_printer(http_t
*http
, int modify
);
60 static void do_config_printer(http_t
*http
);
61 static void do_config_server(http_t
*http
);
62 static void do_delete_class(http_t
*http
);
63 static void do_delete_printer(http_t
*http
);
64 static void do_export(http_t
*http
);
65 static void do_menu(http_t
*http
);
66 static void do_printer_op(http_t
*http
,
67 ipp_op_t op
, const char *title
);
68 static void do_set_allowed_users(http_t
*http
);
69 static void do_set_sharing(http_t
*http
);
70 static int match_string(const char *a
, const char *b
);
74 * 'main()' - Main entry for CGI.
77 int /* O - Exit status */
78 main(int argc
, /* I - Number of command-line arguments */
79 char *argv
[]) /* I - Command-line arguments */
81 http_t
*http
; /* Connection to the server */
82 const char *op
; /* Operation name */
86 * Connect to the HTTP server...
89 fputs("DEBUG: admin.cgi started...\n", stderr
);
91 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
95 perror("ERROR: Unable to connect to cupsd");
96 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n", cupsServer());
97 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
98 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
102 fprintf(stderr
, "DEBUG: http=%p\n", http
);
105 * Set the web interface section...
108 cgiSetVariable("SECTION", "admin");
111 * See if we have form data...
114 if (!cgiInitialize())
117 * Nope, send the administration menu...
120 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
124 else if ((op
= cgiGetVariable("OP")) != NULL
)
127 * Do the operation...
130 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
132 if (!strcmp(op
, "redirect"))
134 const char *url
; /* Redirection URL... */
137 if ((url
= cgiGetVariable("URL")) != NULL
)
138 printf("Location: %s\n\n", url
);
140 puts("Location: /admin\n");
142 else if (!strcmp(op
, "start-printer"))
143 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
144 else if (!strcmp(op
, "stop-printer"))
145 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
146 else if (!strcmp(op
, "start-class"))
147 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
148 else if (!strcmp(op
, "stop-class"))
149 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
150 else if (!strcmp(op
, "accept-jobs"))
151 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
152 else if (!strcmp(op
, "reject-jobs"))
153 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
154 else if (!strcmp(op
, "purge-jobs"))
155 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
156 else if (!strcmp(op
, "set-allowed-users"))
157 do_set_allowed_users(http
);
158 else if (!strcmp(op
, "set-as-default"))
159 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
160 else if (!strcmp(op
, "set-sharing"))
161 do_set_sharing(http
);
162 else if (!strcmp(op
, "add-class"))
163 do_am_class(http
, 0);
164 else if (!strcmp(op
, "add-printer"))
165 do_am_printer(http
, 0);
166 else if (!strcmp(op
, "modify-class"))
167 do_am_class(http
, 1);
168 else if (!strcmp(op
, "modify-printer"))
169 do_am_printer(http
, 1);
170 else if (!strcmp(op
, "delete-class"))
171 do_delete_class(http
);
172 else if (!strcmp(op
, "delete-printer"))
173 do_delete_printer(http
);
174 else if (!strcmp(op
, "set-printer-options"))
175 do_config_printer(http
);
176 else if (!strcmp(op
, "config-server"))
177 do_config_server(http
);
178 else if (!strcmp(op
, "export-samba"))
183 * Bad operation code... Display an error...
186 cgiStartHTML(cgiText(_("Administration")));
187 cgiCopyTemplateLang("error-op.tmpl");
194 * Form data but no operation code... Display an error...
197 cgiStartHTML(cgiText(_("Administration")));
198 cgiCopyTemplateLang("error-op.tmpl");
203 * Close the HTTP server connection...
209 * Return with no errors...
217 * 'do_am_class()' - Add or modify a class.
221 do_am_class(http_t
*http
, /* I - HTTP connection */
222 int modify
) /* I - Modify the printer? */
224 int i
, j
; /* Looping vars */
225 int element
; /* Element number */
226 int num_printers
; /* Number of printers */
227 ipp_t
*request
, /* IPP request */
228 *response
; /* IPP response */
229 ipp_attribute_t
*attr
; /* member-uris attribute */
230 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
231 const char *name
, /* Pointer to class name */
232 *ptr
; /* Pointer to CGI variable */
233 const char *title
; /* Title of page */
234 static const char * const pattrs
[] = /* Requested printer attributes */
242 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
243 name
= cgiGetVariable("PRINTER_NAME");
245 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
248 * Build a CUPS_GET_PRINTERS request, which requires the
249 * following attributes:
252 * attributes-natural-language
256 request
= ippNewRequest(CUPS_GET_PRINTERS
);
258 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
259 NULL
, "ipp://localhost/printers");
262 * Do the request and get back a response...
265 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
268 * Create MEMBER_URIS and MEMBER_NAMES arrays...
271 for (element
= 0, attr
= response
->attrs
;
274 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
276 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
277 (!name
|| strcasecmp(name
, ptr
+ 1)))
280 * Don't show the current class...
283 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
288 for (element
= 0, attr
= response
->attrs
;
291 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
293 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
296 * Don't show the current class...
299 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
304 num_printers
= cgiGetSize("MEMBER_URIS");
314 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
315 * following attributes:
318 * attributes-natural-language
322 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
324 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
325 "localhost", 0, "/classes/%s", name
);
326 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
329 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
330 "requested-attributes",
331 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
335 * Do the request and get back a response...
338 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
340 if ((attr
= ippFindAttribute(response
, "member-names", IPP_TAG_NAME
)) != NULL
)
343 * Mark any current members in the class...
346 for (j
= 0; j
< num_printers
; j
++)
347 cgiSetArray("MEMBER_SELECTED", j
, "");
349 for (i
= 0; i
< attr
->num_values
; i
++)
351 for (j
= 0; j
< num_printers
; j
++)
353 if (!strcasecmp(attr
->values
[i
].string
.text
,
354 cgiGetArray("MEMBER_NAMES", j
)))
356 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
363 if ((attr
= ippFindAttribute(response
, "printer-info",
364 IPP_TAG_TEXT
)) != NULL
)
365 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
367 if ((attr
= ippFindAttribute(response
, "printer-location",
368 IPP_TAG_TEXT
)) != NULL
)
369 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
375 * Update the location and description of an existing printer...
379 cgiCopyTemplateLang("modify-class.tmpl");
384 * Get the name, location, and description for a new printer...
388 cgiCopyTemplateLang("add-class.tmpl");
396 for (ptr
= name
; *ptr
; ptr
++)
397 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
400 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
402 cgiSetVariable("ERROR",
403 cgiText(_("The class name may only contain up to "
404 "127 printable characters and may not "
405 "contain spaces, slashes (/), or the "
406 "pound sign (#).")));
408 cgiCopyTemplateLang("error.tmpl");
414 * Build a CUPS_ADD_CLASS request, which requires the following
418 * attributes-natural-language
422 * printer-is-accepting-jobs
427 request
= ippNewRequest(CUPS_ADD_CLASS
);
429 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
430 "localhost", 0, "/classes/%s",
431 cgiGetVariable("PRINTER_NAME"));
432 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
435 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
436 NULL
, cgiGetVariable("PRINTER_LOCATION"));
438 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
439 NULL
, cgiGetVariable("PRINTER_INFO"));
441 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
443 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
446 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
448 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
449 num_printers
, NULL
, NULL
);
450 for (i
= 0; i
< num_printers
; i
++)
451 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
455 * Do the request and get back a response...
458 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
460 if (cupsLastError() > IPP_OK_CONFLICT
)
463 cgiShowIPPError(modify
? _("Unable to modify class:") :
464 _("Unable to add class:"));
469 * Redirect successful updates back to the class page...
472 char refresh
[1024]; /* Refresh URL */
474 cgiFormEncode(uri
, name
, sizeof(uri
));
475 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=/classes/%s",
477 cgiSetVariable("refresh_page", refresh
);
482 cgiCopyTemplateLang("class-modified.tmpl");
484 cgiCopyTemplateLang("class-added.tmpl");
492 * 'do_am_printer()' - Add or modify a printer.
496 do_am_printer(http_t
*http
, /* I - HTTP connection */
497 int modify
) /* I - Modify the printer? */
499 int i
; /* Looping var */
500 int element
; /* Element number */
501 ipp_attribute_t
*attr
, /* Current attribute */
502 *last
; /* Last attribute */
503 ipp_t
*request
, /* IPP request */
504 *response
, /* IPP response */
505 *oldinfo
; /* Old printer information */
506 const cgi_file_t
*file
; /* Uploaded file, if any */
507 const char *var
; /* CGI variable */
508 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
509 *uriptr
; /* Pointer into URI */
510 int maxrate
; /* Maximum baud rate */
511 char baudrate
[255]; /* Baud rate string */
512 const char *name
, /* Pointer to class name */
513 *ptr
; /* Pointer to CGI variable */
514 const char *title
; /* Title of page */
515 static int baudrates
[] = /* Baud rates */
530 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
531 cgiGetVariable("DEVICE_URI"));
533 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
538 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
539 * following attributes:
542 * attributes-natural-language
546 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
548 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
549 "localhost", 0, "/printers/%s",
550 cgiGetVariable("PRINTER_NAME"));
551 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
555 * Do the request and get back a response...
558 oldinfo
= cupsDoRequest(http
, request
, "/");
563 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
564 cgiGetVariable("PRINTER_LOCATION") == NULL
)
571 * Update the location and description of an existing printer...
575 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
577 cgiCopyTemplateLang("modify-printer.tmpl");
582 * Get the name, location, and description for a new printer...
585 cgiCopyTemplateLang("add-printer.tmpl");
596 for (ptr
= name
; *ptr
; ptr
++)
597 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
600 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
602 cgiSetVariable("ERROR",
603 cgiText(_("The printer name may only contain up to "
604 "127 printable characters and may not "
605 "contain spaces, slashes (/), or the "
606 "pound sign (#).")));
608 cgiCopyTemplateLang("error.tmpl");
617 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
618 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
619 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
620 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
623 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
626 * Build a CUPS_GET_DEVICES request, which requires the following
630 * attributes-natural-language
634 fputs("DEBUG: Getting list of devices...\n", stderr
);
636 request
= ippNewRequest(CUPS_GET_DEVICES
);
638 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
639 NULL
, "ipp://localhost/printers/");
642 * Do the request and get back a response...
645 fprintf(stderr
, "DEBUG: http=%p (%s)\n", http
, http
->hostname
);
647 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
649 fputs("DEBUG: Got device list!\n", stderr
);
651 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
656 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
657 cupsLastError(), cupsLastErrorString());
660 * Let the user choose...
663 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
665 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
666 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
669 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
670 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
674 cgiCopyTemplateLang("choose-device.tmpl");
677 else if (strchr(var
, '/') == NULL
)
679 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
682 * Set the current device URI for the form to the old one...
685 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
686 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
690 * User needs to set the full URI...
694 cgiCopyTemplateLang("choose-uri.tmpl");
697 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
700 * Need baud rate, parity, etc.
703 if ((var
= strchr(var
, '?')) != NULL
&&
704 strncmp(var
, "?baud=", 6) == 0)
705 maxrate
= atoi(var
+ 6);
709 for (i
= 0; i
< 10; i
++)
710 if (baudrates
[i
] > maxrate
)
714 sprintf(baudrate
, "%d", baudrates
[i
]);
715 cgiSetArray("BAUDRATES", i
, baudrate
);
719 cgiCopyTemplateLang("choose-serial.tmpl");
722 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
727 * Get the PPD file...
730 int fd
; /* PPD file */
731 char filename
[1024]; /* PPD filename */
732 ppd_file_t
*ppd
; /* PPD information */
733 char buffer
[1024]; /* Buffer */
734 int bytes
; /* Number of bytes */
735 http_status_t get_status
; /* Status of GET */
738 /* TODO: Use cupsGetFile() API... */
739 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
741 if (httpGet(http
, uri
))
744 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
746 if (get_status
!= HTTP_OK
)
748 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
749 uri
, get_status
, httpStatus(get_status
));
751 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
753 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
754 write(fd
, buffer
, bytes
);
758 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
760 if (ppd
->manufacturer
)
761 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
764 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
771 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
772 filename
, ppdErrorString(ppdLastError(&bytes
)));
780 "ERROR: Unable to create temporary file for PPD file: %s\n",
784 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
787 * Extract make and make/model from device URI string...
790 char make
[1024], /* Make string */
791 *makeptr
; /* Pointer into make */
796 strlcpy(make
, uriptr
, sizeof(make
));
798 if ((makeptr
= strchr(make
, ' ')) != NULL
)
800 else if ((makeptr
= strchr(make
, '-')) != NULL
)
802 else if (!strncasecmp(make
, "laserjet", 8) ||
803 !strncasecmp(make
, "deskjet", 7) ||
804 !strncasecmp(make
, "designjet", 9))
806 else if (!strncasecmp(make
, "phaser", 6))
807 strcpy(make
, "Xerox");
808 else if (!strncasecmp(make
, "stylus", 6))
809 strcpy(make
, "Epson");
811 strcpy(make
, "Generic");
813 cgiSetVariable("CURRENT_MAKE", make
);
814 cgiSetVariable("PPD_MAKE", make
);
815 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
819 * Build a CUPS_GET_PPDS request, which requires the following
823 * attributes-natural-language
827 request
= ippNewRequest(CUPS_GET_PPDS
);
829 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
830 NULL
, "ipp://localhost/printers/");
832 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
833 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
834 "ppd-make", NULL
, var
);
836 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
837 "requested-attributes", NULL
, "ppd-make");
840 * Do the request and get back a response...
843 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
846 * Got the list of PPDs, see if the user has selected a make...
849 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
854 * Let the user choose a make...
857 for (element
= 0, attr
= response
->attrs
, last
= NULL
;
860 if (attr
->name
&& strcmp(attr
->name
, "ppd-make") == 0)
862 strcasecmp(last
->values
[0].string
.text
,
863 attr
->values
[0].string
.text
) != 0)
865 cgiSetArray("PPD_MAKE", element
, attr
->values
[0].string
.text
);
871 cgiCopyTemplateLang("choose-make.tmpl");
877 * Let the user choose a model...
880 const char *make_model
; /* Current make/model string */
883 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
886 * Scan for "close" matches...
889 int match
, /* Current match */
890 best_match
, /* Best match so far */
891 count
; /* Number of drivers */
892 const char *best
, /* Best matching string */
893 *current
; /* Current string */
896 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
898 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
900 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
901 match
= match_string(make_model
, current
);
903 if (match
> best_match
)
910 if (best_match
> strlen(var
))
913 * Found a match longer than the make...
916 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
921 cgiCopyTemplateLang("choose-model.tmpl");
931 cgiShowIPPError(_("Unable to get list of printer drivers:"));
932 cgiCopyTemplateLang("error.tmpl");
939 * Build a CUPS_ADD_PRINTER request, which requires the following
943 * attributes-natural-language
949 * printer-is-accepting-jobs
953 request
= ippNewRequest(CUPS_ADD_PRINTER
);
955 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
956 "localhost", 0, "/printers/%s",
957 cgiGetVariable("PRINTER_NAME"));
958 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
961 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
962 NULL
, cgiGetVariable("PRINTER_LOCATION"));
964 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
965 NULL
, cgiGetVariable("PRINTER_INFO"));
968 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
969 NULL
, cgiGetVariable("PPD_NAME"));
971 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
974 * Strip make and model from URI...
977 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
980 if (!strncmp(uri
, "serial:", 7))
983 * Update serial port URI to include baud rate, etc.
986 if ((uriptr
= strchr(uri
, '?')) == NULL
)
987 uriptr
= uri
+ strlen(uri
);
989 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
990 "?baud=%s+bits=%s+parity=%s+flow=%s",
991 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
992 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
995 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
998 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1000 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1004 * Do the request and get back a response...
1008 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1010 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1012 if (cupsLastError() > IPP_OK_CONFLICT
)
1014 cgiStartHTML(title
);
1015 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1016 _("Unable to add printer:"));
1021 * Redirect successful updates back to the printer or set-options pages...
1024 char refresh
[1024]; /* Refresh URL */
1027 cgiFormEncode(uri
, name
, sizeof(uri
));
1030 snprintf(refresh
, sizeof(refresh
),
1031 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1033 snprintf(refresh
, sizeof(refresh
),
1034 "5;/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1036 cgiSetVariable("refresh_page", refresh
);
1038 cgiStartHTML(title
);
1041 cgiCopyTemplateLang("printer-modified.tmpl");
1043 cgiCopyTemplateLang("printer-added.tmpl");
1055 * 'do_config_printer()' - Configure the default options for a printer.
1059 do_config_printer(http_t
*http
) /* I - HTTP connection */
1061 int i
, j
, k
, m
; /* Looping vars */
1062 int have_options
; /* Have options? */
1063 ipp_t
*request
, /* IPP request */
1064 *response
; /* IPP response */
1065 ipp_attribute_t
*attr
; /* IPP attribute */
1066 char uri
[HTTP_MAX_URI
]; /* Job URI */
1067 const char *var
; /* Variable value */
1068 const char *printer
; /* Printer printer name */
1069 const char *filename
; /* PPD filename */
1070 char tempfile
[1024]; /* Temporary filename */
1071 cups_file_t
*in
, /* Input file */
1072 *out
; /* Output file */
1073 char line
[1024]; /* Line from PPD file */
1074 char keyword
[1024], /* Keyword from Default line */
1075 *keyptr
; /* Pointer into keyword... */
1076 ppd_file_t
*ppd
; /* PPD file */
1077 ppd_group_t
*group
; /* Option group */
1078 ppd_option_t
*option
; /* Option */
1079 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
1080 const char *title
; /* Page title */
1083 title
= cgiText(_("Set Printer Options"));
1085 fprintf(stderr
, "DEBUG: do_config_printer(http=%p)\n", http
);
1088 * Get the printer name...
1091 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1092 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1093 "localhost", 0, "/printers/%s", printer
);
1096 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1097 cgiStartHTML(title
);
1098 cgiCopyTemplateLang("error.tmpl");
1103 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
1106 * Get the PPD file...
1109 if ((filename
= cupsGetPPD2(http
, printer
)) == NULL
)
1111 fputs("DEBUG: No PPD file!?!\n", stderr
);
1113 cgiStartHTML(title
);
1114 cgiShowIPPError(_("Unable to get PPD file!"));
1119 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
1121 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
1123 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
1124 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1125 cgiStartHTML(title
);
1126 cgiCopyTemplateLang("error.tmpl");
1131 if (cgiGetVariable("job_sheets_start") != NULL
||
1132 cgiGetVariable("job_sheets_end") != NULL
)
1137 ppdMarkDefaults(ppd
);
1139 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1140 "<UL>\n", ppd
->num_groups
));
1142 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
1144 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
1146 for (j
= group
->num_options
, option
= group
->options
; j
> 0; j
--, option
++)
1147 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
1149 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
1151 ppdMarkOption(ppd
, option
->keyword
, var
);
1155 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
1158 DEBUG_puts("</UL></LI>");
1161 DEBUG_printf(("</UL>\n"
1162 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
1164 if (!have_options
|| ppdConflicts(ppd
))
1167 * Show the options to the user...
1170 fputs("DEBUG: Showing options...\n", stderr
);
1174 cgiStartHTML("Set Printer Options");
1175 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1177 if (ppdConflicts(ppd
))
1179 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
; i
> 0; i
--, group
++)
1180 for (j
= group
->num_options
, option
= group
->options
; j
> 0; j
--, option
++)
1181 if (option
->conflicted
)
1183 cgiSetArray("ckeyword", k
, option
->keyword
);
1184 cgiSetArray("ckeytext", k
, option
->text
);
1188 cgiCopyTemplateLang("option-conflict.tmpl");
1191 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1195 if (!strcmp(group
->name
, "InstallableOptions"))
1196 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
1198 cgiSetVariable("GROUP", group
->text
);
1200 cgiCopyTemplateLang("option-header.tmpl");
1202 for (j
= group
->num_options
, option
= group
->options
;
1206 if (!strcmp(option
->keyword
, "PageRegion"))
1209 cgiSetVariable("KEYWORD", option
->keyword
);
1210 cgiSetVariable("KEYTEXT", option
->text
);
1212 if (option
->conflicted
)
1213 cgiSetVariable("CONFLICTED", "1");
1215 cgiSetVariable("CONFLICTED", "0");
1217 cgiSetSize("CHOICES", 0);
1218 cgiSetSize("TEXT", 0);
1219 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
1222 * Hide custom option values...
1225 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
1228 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
1229 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
1233 if (option
->choices
[k
].marked
)
1234 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
1239 case PPD_UI_BOOLEAN
:
1240 cgiCopyTemplateLang("option-boolean.tmpl");
1242 case PPD_UI_PICKONE
:
1243 cgiCopyTemplateLang("option-pickone.tmpl");
1245 case PPD_UI_PICKMANY
:
1246 cgiCopyTemplateLang("option-pickmany.tmpl");
1251 cgiCopyTemplateLang("option-trailer.tmpl");
1255 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1256 * following attributes:
1258 * attributes-charset
1259 * attributes-natural-language
1263 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
1265 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1266 "localhost", 0, "/printers/%s", printer
);
1267 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1271 * Do the request and get back a response...
1274 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1276 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
1277 IPP_TAG_ZERO
)) != NULL
)
1280 * Add the job sheets options...
1283 cgiSetVariable("GROUP", cgiText(_("Banners")));
1284 cgiCopyTemplateLang("option-header.tmpl");
1286 cgiSetSize("CHOICES", attr
->num_values
);
1287 cgiSetSize("TEXT", attr
->num_values
);
1288 for (k
= 0; k
< attr
->num_values
; k
++)
1290 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1291 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1294 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
1296 cgiSetVariable("KEYWORD", "job_sheets_start");
1297 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
1298 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1299 "" : attr
->values
[0].string
.text
);
1301 cgiCopyTemplateLang("option-pickone.tmpl");
1303 cgiSetVariable("KEYWORD", "job_sheets_end");
1304 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
1305 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
1306 "" : attr
->values
[1].string
.text
);
1308 cgiCopyTemplateLang("option-pickone.tmpl");
1310 cgiCopyTemplateLang("option-trailer.tmpl");
1313 if (ippFindAttribute(response
, "printer-error-policy-supported",
1315 ippFindAttribute(response
, "printer-op-policy-supported",
1319 * Add the error and operation policy options...
1322 cgiSetVariable("GROUP", cgiText(_("Policies")));
1323 cgiCopyTemplateLang("option-header.tmpl");
1329 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
1334 cgiSetSize("CHOICES", attr
->num_values
);
1335 cgiSetSize("TEXT", attr
->num_values
);
1336 for (k
= 0; k
< attr
->num_values
; k
++)
1338 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1339 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1342 attr
= ippFindAttribute(response
, "printer-error-policy",
1345 cgiSetVariable("KEYWORD", "printer_error_policy");
1346 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
1347 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1348 "" : attr
->values
[0].string
.text
);
1351 cgiCopyTemplateLang("option-pickone.tmpl");
1354 * Operation policy...
1357 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
1362 cgiSetSize("CHOICES", attr
->num_values
);
1363 cgiSetSize("TEXT", attr
->num_values
);
1364 for (k
= 0; k
< attr
->num_values
; k
++)
1366 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1367 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1370 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
1372 cgiSetVariable("KEYWORD", "printer_op_policy");
1373 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
1374 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1375 "" : attr
->values
[0].string
.text
);
1377 cgiCopyTemplateLang("option-pickone.tmpl");
1380 cgiCopyTemplateLang("option-trailer.tmpl");
1383 ippDelete(response
);
1387 * Binary protocol support...
1390 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
1392 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
1394 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
1395 cgiCopyTemplateLang("option-header.tmpl");
1397 cgiSetSize("CHOICES", 2);
1398 cgiSetSize("TEXT", 2);
1399 cgiSetArray("CHOICES", 0, "None");
1400 cgiSetArray("TEXT", 0, cgiText(_("None")));
1402 if (strstr(ppd
->protocols
, "TBCP"))
1404 cgiSetArray("CHOICES", 1, "TBCP");
1405 cgiSetArray("TEXT", 1, "TBCP");
1409 cgiSetArray("CHOICES", 1, "BCP");
1410 cgiSetArray("TEXT", 1, "BCP");
1413 cgiSetVariable("KEYWORD", "protocol");
1414 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
1415 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
1417 cgiCopyTemplateLang("option-pickone.tmpl");
1419 cgiCopyTemplateLang("option-trailer.tmpl");
1422 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1428 * Set default options...
1431 fputs("DEBUG: Setting options...\n", stderr
);
1433 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
1434 in
= cupsFileOpen(filename
, "r");
1438 cgiSetVariable("ERROR", strerror(errno
));
1439 cgiStartHTML("Set Printer Options");
1440 cgiCopyTemplateLang("error.tmpl");
1456 while (cupsFileGets(in
, line
, sizeof(line
)))
1458 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1460 else if (strncmp(line
, "*Default", 8))
1461 cupsFilePrintf(out
, "%s\n", line
);
1465 * Get default option name...
1468 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
1470 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1471 if (*keyptr
== ':' || isspace(*keyptr
& 255))
1476 if (!strcmp(keyword
, "PageRegion"))
1477 var
= cgiGetVariable("PageSize");
1479 var
= cgiGetVariable(keyword
);
1482 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
1484 cupsFilePrintf(out
, "%s\n", line
);
1488 if ((var
= cgiGetVariable("protocol")) != NULL
)
1489 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1495 * Build a CUPS_ADD_PRINTER request, which requires the following
1498 * attributes-charset
1499 * attributes-natural-language
1501 * job-sheets-default
1505 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1507 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1508 "localhost", 0, "/printers/%s",
1509 cgiGetVariable("PRINTER_NAME"));
1510 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1513 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1514 "job-sheets-default", 2, NULL
, NULL
);
1515 attr
->values
[0].string
.text
= strdup(cgiGetVariable("job_sheets_start"));
1516 attr
->values
[1].string
.text
= strdup(cgiGetVariable("job_sheets_end"));
1518 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
1519 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1520 "printer-error-policy", NULL
, var
);
1522 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
1523 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1524 "printer-op-policy", NULL
, var
);
1527 * Do the request and get back a response...
1530 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
1532 if (cupsLastError() > IPP_OK_CONFLICT
)
1534 cgiStartHTML(title
);
1535 cgiShowIPPError(_("Unable to set options:"));
1540 * Redirect successful updates back to the printer page...
1543 char refresh
[1024]; /* Refresh URL */
1546 cgiFormEncode(uri
, printer
, sizeof(uri
));
1547 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=/printers/%s",
1549 cgiSetVariable("refresh_page", refresh
);
1551 cgiStartHTML(title
);
1553 cgiCopyTemplateLang("printer-configured.tmpl");
1566 * 'do_config_server()' - Configure server settings.
1570 do_config_server(http_t
*http
) /* I - HTTP connection */
1572 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1575 * Save basic setting changes...
1578 int num_settings
; /* Number of server settings */
1579 cups_option_t
*settings
; /* Server settings */
1583 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1584 cgiGetVariable("DEBUG_LOGGING") ? "1" : "0",
1585 num_settings
, &settings
);
1586 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1587 cgiGetVariable("REMOTE_ADMIN") ? "1" : "0",
1588 num_settings
, &settings
);
1589 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1590 cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0",
1591 num_settings
, &settings
);
1592 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1593 cgiGetVariable("SHARE_PRINTERS") ? "1" : "0",
1594 num_settings
, &settings
);
1595 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1596 cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0",
1597 num_settings
, &settings
);
1600 if (!_cupsAdminSetServerSettings(http
, num_settings
, settings
))
1602 cgiStartHTML(cgiText(_("Change Settings")));
1603 cgiSetVariable("MESSAGE", cgiText(_("Unable to change server settings:")));
1604 cgiSetVariable("ERROR", cupsLastErrorString());
1605 cgiCopyTemplateLang("error.tmpl");
1609 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1610 cgiStartHTML(cgiText(_("Change Settings")));
1611 cgiCopyTemplateLang("restart.tmpl");
1614 cupsFreeOptions(num_settings
, settings
);
1618 else if (cgiIsPOST())
1621 * Save hand-edited config file...
1624 http_status_t status
; /* PUT status */
1625 char tempfile
[1024]; /* Temporary new cupsd.conf */
1626 int tempfd
; /* Temporary file descriptor */
1627 cups_file_t
*temp
; /* Temporary file */
1628 const char *start
, /* Start of line */
1629 *end
; /* End of line */
1633 * Create a temporary file for the new cupsd.conf file...
1636 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1638 cgiStartHTML(cgiText(_("Edit Configuration File")));
1639 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1640 cgiSetVariable("ERROR", strerror(errno
));
1641 cgiCopyTemplateLang("error.tmpl");
1648 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1650 cgiStartHTML(cgiText(_("Edit Configuration File")));
1651 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1652 cgiSetVariable("ERROR", strerror(errno
));
1653 cgiCopyTemplateLang("error.tmpl");
1663 * Copy the cupsd.conf text from the form variable...
1666 start
= cgiGetVariable("CUPSDCONF");
1669 if ((end
= strstr(start
, "\r\n")) == NULL
)
1670 if ((end
= strstr(start
, "\n")) == NULL
)
1671 end
= start
+ strlen(start
);
1673 cupsFileWrite(temp
, start
, end
- start
);
1674 cupsFilePutChar(temp
, '\n');
1678 else if (*end
== '\n')
1684 cupsFileClose(temp
);
1687 * Upload the configuration file to the server...
1690 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1692 if (status
!= HTTP_CREATED
)
1694 cgiSetVariable("MESSAGE", cgiText(_("Unable to upload cupsd.conf file:")));
1695 cgiSetVariable("ERROR", httpStatus(status
));
1697 cgiStartHTML(cgiText(_("Edit Configuration File")));
1698 cgiCopyTemplateLang("error.tmpl");
1702 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1704 cgiStartHTML(cgiText(_("Edit Configuration File")));
1705 cgiCopyTemplateLang("restart.tmpl");
1714 struct stat info
; /* cupsd.conf information */
1715 cups_file_t
*cupsd
; /* cupsd.conf file */
1716 char *buffer
; /* Buffer for entire file */
1717 char filename
[1024]; /* Filename */
1718 const char *server_root
; /* Location of config files */
1722 * Locate the cupsd.conf file...
1725 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1726 server_root
= CUPS_SERVERROOT
;
1728 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1731 * Figure out the size...
1734 if (stat(filename
, &info
))
1736 cgiStartHTML(cgiText(_("Edit Configuration File")));
1737 cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:")));
1738 cgiSetVariable("ERROR", strerror(errno
));
1739 cgiCopyTemplateLang("error.tmpl");
1746 if (info
.st_size
> (1024 * 1024))
1748 cgiStartHTML(cgiText(_("Edit Configuration File")));
1749 cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:")));
1750 cgiSetVariable("ERROR",
1751 cgiText(_("Unable to edit cupsd.conf files larger than "
1753 cgiCopyTemplateLang("error.tmpl");
1756 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1757 (long)info
.st_size
);
1762 * Open the cupsd.conf file...
1765 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1768 * Unable to open - log an error...
1771 cgiStartHTML(cgiText(_("Edit Configuration File")));
1772 cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:")));
1773 cgiSetVariable("ERROR", strerror(errno
));
1774 cgiCopyTemplateLang("error.tmpl");
1782 * Allocate memory and load the file into a string buffer...
1785 buffer
= calloc(1, info
.st_size
+ 1);
1787 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1788 cupsFileClose(cupsd
);
1790 cgiSetVariable("CUPSDCONF", buffer
);
1794 * Show the current config file...
1797 cgiStartHTML("Edit Configuration File");
1799 printf("<!-- \"%s\" -->\n", filename
);
1801 cgiCopyTemplateLang("edit-config.tmpl");
1809 * 'do_delete_class()' - Delete a class...
1813 do_delete_class(http_t
*http
) /* I - HTTP connection */
1815 ipp_t
*request
; /* IPP request */
1816 char uri
[HTTP_MAX_URI
]; /* Job URI */
1817 const char *pclass
; /* Printer class name */
1820 cgiStartHTML(cgiText(_("Delete Class")));
1822 if (cgiGetVariable("CONFIRM") == NULL
)
1824 cgiCopyTemplateLang("class-confirm.tmpl");
1829 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1830 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1831 "localhost", 0, "/classes/%s", pclass
);
1834 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1835 cgiCopyTemplateLang("error.tmpl");
1841 * Build a CUPS_DELETE_CLASS request, which requires the following
1844 * attributes-charset
1845 * attributes-natural-language
1849 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1851 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1855 * Do the request and get back a response...
1858 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1860 if (cupsLastError() > IPP_OK_CONFLICT
)
1861 cgiShowIPPError(_("Unable to delete class:"));
1863 cgiCopyTemplateLang("class-deleted.tmpl");
1870 * 'do_delete_printer()' - Delete a printer...
1874 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1876 ipp_t
*request
; /* IPP request */
1877 char uri
[HTTP_MAX_URI
]; /* Job URI */
1878 const char *printer
; /* Printer printer name */
1881 cgiStartHTML(cgiText(_("Delete Printer")));
1883 if (cgiGetVariable("CONFIRM") == NULL
)
1885 cgiCopyTemplateLang("printer-confirm.tmpl");
1890 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1891 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1892 "localhost", 0, "/printers/%s", printer
);
1895 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1896 cgiCopyTemplateLang("error.tmpl");
1902 * Build a CUPS_DELETE_PRINTER request, which requires the following
1905 * attributes-charset
1906 * attributes-natural-language
1910 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1912 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1916 * Do the request and get back a response...
1919 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1921 if (cupsLastError() > IPP_OK_CONFLICT
)
1922 cgiShowIPPError(_("Unable to delete printer:"));
1924 cgiCopyTemplateLang("printer-deleted.tmpl");
1931 * 'do_export()' - Export printers to Samba...
1935 do_export(http_t
*http
) /* I - HTTP connection */
1937 int i
, j
; /* Looping vars */
1938 ipp_t
*request
, /* IPP request */
1939 *response
; /* IPP response */
1940 const char *username
, /* Samba username */
1941 *password
, /* Samba password */
1942 *export_all
; /* Export all printers? */
1943 int export_count
, /* Number of printers to export */
1944 printer_count
; /* Number of available printers */
1945 const char *name
, /* What name to pull */
1946 *dest
; /* Current destination */
1947 char ppd
[1024]; /* PPD file */
1954 username
= cgiGetVariable("USERNAME");
1955 password
= cgiGetVariable("PASSWORD");
1956 export_all
= cgiGetVariable("EXPORT_ALL");
1957 export_count
= cgiGetSize("EXPORT_NAME");
1960 * Get list of available printers...
1963 cgiSetSize("PRINTER_NAME", 0);
1964 cgiSetSize("PRINTER_EXPORT", 0);
1966 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1968 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1971 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1972 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
1973 CUPS_PRINTER_IMPLICIT
);
1975 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1976 "requested-attributes", NULL
, "printer-name");
1978 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1980 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1981 ippDelete(response
);
1985 printer_count
= cgiGetSize("PRINTER_NAME");
1987 for (i
= 0; i
< printer_count
; i
++)
1989 dest
= cgiGetArray("PRINTER_NAME", i
);
1991 for (j
= 0; j
< export_count
; j
++)
1992 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
1995 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2001 * Export or get the printers to export...
2004 if (username
&& *username
&& password
&& *password
&&
2005 (export_all
|| export_count
> 0))
2011 fputs("DEBUG: Export printers...\n", stderr
);
2015 name
= "PRINTER_NAME";
2016 export_count
= cgiGetSize("PRINTER_NAME");
2019 name
= "EXPORT_NAME";
2021 for (i
= 0; i
< export_count
; i
++)
2023 dest
= cgiGetArray(name
, i
);
2025 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2028 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2037 if (i
< export_count
)
2038 cgiSetVariable("ERROR", cupsLastErrorString());
2041 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2042 cgiCopyTemplateLang("samba-exported.tmpl");
2047 else if (username
&& !*username
)
2048 cgiSetVariable("ERROR",
2049 cgiText(_("A Samba username is required to export "
2050 "printer drivers!")));
2051 else if (username
&& (!password
|| !*password
))
2052 cgiSetVariable("ERROR",
2053 cgiText(_("A Samba password is required to export "
2054 "printer drivers!")));
2060 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2061 cgiCopyTemplateLang("samba-export.tmpl");
2067 * 'do_menu()' - Show the main menu...
2071 do_menu(http_t
*http
) /* I - HTTP connection */
2073 int num_settings
; /* Number of server settings */
2074 cups_option_t
*settings
; /* Server settings */
2075 const char *val
; /* Setting value */
2076 char filename
[1024]; /* Temporary filename */
2077 const char *datadir
; /* Location of data files */
2078 ipp_t
*request
, /* IPP request */
2079 *response
; /* IPP response */
2080 ipp_attribute_t
*attr
; /* IPP attribute */
2084 * Get the current server settings...
2087 if (!_cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2089 cgiStartHTML(cgiText(_("Administration")));
2090 cgiSetVariable("MESSAGE", cgiText(_("Unable to open cupsd.conf file:")));
2091 cgiSetVariable("ERROR", cupsLastErrorString());
2092 cgiCopyTemplateLang("error.tmpl");
2096 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2097 settings
)) != NULL
&& atoi(val
))
2098 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2100 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2101 settings
)) != NULL
&& atoi(val
))
2102 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2104 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2105 settings
)) != NULL
&& atoi(val
))
2106 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2108 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2109 settings
)) != NULL
&& atoi(val
))
2110 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2112 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2113 settings
)) != NULL
&& atoi(val
))
2114 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2117 * Get the list of printers and their devices...
2120 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2122 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2123 "requested-attributes", NULL
, "device-uri");
2125 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2126 CUPS_PRINTER_LOCAL
);
2127 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2128 CUPS_PRINTER_LOCAL
);
2130 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2133 * Got the printer list, now load the devices...
2136 int i
; /* Looping var */
2137 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2138 char *printer_device
; /* Current printer device */
2142 * Allocate an array and copy the device strings...
2145 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2147 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2149 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2151 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2155 * Free the printer list and get the device list...
2158 ippDelete(response
);
2160 request
= ippNewRequest(CUPS_GET_DEVICES
);
2162 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2165 * Got the device list, let's parse it...
2168 const char *device_uri
, /* device-uri attribute value */
2169 *device_make_and_model
, /* device-make-and-model value */
2170 *device_info
; /* device-info value */
2173 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2176 * Skip leading attributes until we hit a device...
2179 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2186 * Pull the needed attributes from this device...
2190 device_make_and_model
= NULL
;
2193 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2195 if (!strcmp(attr
->name
, "device-info") &&
2196 attr
->value_tag
== IPP_TAG_TEXT
)
2197 device_info
= attr
->values
[0].string
.text
;
2199 if (!strcmp(attr
->name
, "device-make-and-model") &&
2200 attr
->value_tag
== IPP_TAG_TEXT
)
2201 device_make_and_model
= attr
->values
[0].string
.text
;
2203 if (!strcmp(attr
->name
, "device-uri") &&
2204 attr
->value_tag
== IPP_TAG_URI
)
2205 device_uri
= attr
->values
[0].string
.text
;
2211 * See if we have everything needed...
2214 if (device_info
&& device_make_and_model
&& device_uri
&&
2215 strcasecmp(device_make_and_model
, "unknown") &&
2216 strchr(device_uri
, ':'))
2219 * Yes, now see if there is already a printer for this
2223 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2226 * Not found, so it must be a new printer...
2229 char options
[1024], /* Form variables for this device */
2230 *options_ptr
; /* Pointer into string */
2231 const char *ptr
; /* Pointer into device string */
2235 * Format the printer name variable for this device...
2237 * We use the device-info string first, then device-uri,
2238 * and finally device-make-and-model to come up with a
2242 strcpy(options
, "PRINTER_NAME=");
2243 options_ptr
= options
+ strlen(options
);
2245 if (strncasecmp(device_info
, "unknown", 7))
2247 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2250 ptr
= device_make_and_model
;
2253 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2255 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' || *ptr
== '.')
2256 *options_ptr
++ = *ptr
;
2257 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2258 *options_ptr
++ = '_';
2259 else if (*ptr
== '?' || *ptr
== '(')
2263 * Then add the make and model in the printer info, so
2264 * that MacOS clients see something reasonable...
2267 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2269 sizeof(options
) - (options_ptr
- options
));
2270 options_ptr
+= strlen(options_ptr
);
2272 cgiFormEncode(options_ptr
, device_make_and_model
,
2273 sizeof(options
) - (options_ptr
- options
));
2274 options_ptr
+= strlen(options_ptr
);
2277 * Then copy the device URI...
2280 strlcpy(options_ptr
, "&DEVICE_URI=",
2281 sizeof(options
) - (options_ptr
- options
));
2282 options_ptr
+= strlen(options_ptr
);
2284 cgiFormEncode(options_ptr
, device_uri
,
2285 sizeof(options
) - (options_ptr
- options
));
2286 options_ptr
+= strlen(options_ptr
);
2288 if (options_ptr
< (options
+ sizeof(options
) - 1))
2290 *options_ptr
++ = '|';
2291 cgiFormEncode(options_ptr
, device_make_and_model
,
2292 sizeof(options
) - (options_ptr
- options
));
2296 * Finally, set the form variables for this printer...
2299 cgiSetArray("device_info", i
, device_info
);
2300 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2301 cgiSetArray("device_options", i
, options
);
2302 cgiSetArray("device_uri", i
, device_uri
);
2311 ippDelete(response
);
2314 * Free the device list...
2317 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2319 printer_device
= (char *)cupsArrayNext(printer_devices
))
2320 free(printer_device
);
2322 cupsArrayDelete(printer_devices
);
2327 * See if Samba and the Windows drivers are installed...
2330 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2331 datadir
= CUPS_DATADIR
;
2333 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2334 if (!access(filename
, R_OK
))
2337 * Found Windows 2000 driver file, see if we have smbclient and
2341 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2342 sizeof(filename
)) &&
2343 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2345 cgiSetVariable("HAVE_SAMBA", "Y");
2348 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2350 fputs("ERROR: smbclient not found!\n", stderr
);
2352 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2354 fputs("ERROR: rpcclient not found!\n", stderr
);
2361 * Finally, show the main menu template...
2364 cgiStartHTML(cgiText(_("Administration")));
2366 cgiCopyTemplateLang("admin.tmpl");
2373 * 'do_printer_op()' - Do a printer operation.
2377 do_printer_op(http_t
*http
, /* I - HTTP connection */
2378 ipp_op_t op
, /* I - Operation to perform */
2379 const char *title
) /* I - Title of page */
2381 ipp_t
*request
; /* IPP request */
2382 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2383 const char *printer
, /* Printer name (purge-jobs) */
2384 *is_class
; /* Is a class? */
2387 is_class
= cgiGetVariable("IS_CLASS");
2388 printer
= cgiGetVariable("PRINTER_NAME");
2392 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2393 cgiStartHTML(title
);
2394 cgiCopyTemplateLang("error.tmpl");
2400 * Build a printer request, which requires the following
2403 * attributes-charset
2404 * attributes-natural-language
2408 request
= ippNewRequest(op
);
2410 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2411 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2413 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2417 * Do the request and get back a response...
2420 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2422 if (cupsLastError() > IPP_OK_CONFLICT
)
2424 cgiStartHTML(title
);
2425 cgiShowIPPError(_("Unable to change printer:"));
2430 * Redirect successful updates back to the printer page...
2433 char url
[1024], /* Printer/class URL */
2434 refresh
[1024]; /* Refresh URL */
2437 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2438 cgiFormEncode(uri
, url
, sizeof(uri
));
2439 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2440 cgiSetVariable("refresh_page", refresh
);
2442 cgiStartHTML(title
);
2444 if (op
== IPP_PAUSE_PRINTER
)
2445 cgiCopyTemplateLang("printer-stop.tmpl");
2446 else if (op
== IPP_RESUME_PRINTER
)
2447 cgiCopyTemplateLang("printer-start.tmpl");
2448 else if (op
== CUPS_ACCEPT_JOBS
)
2449 cgiCopyTemplateLang("printer-accept.tmpl");
2450 else if (op
== CUPS_REJECT_JOBS
)
2451 cgiCopyTemplateLang("printer-reject.tmpl");
2452 else if (op
== IPP_PURGE_JOBS
)
2453 cgiCopyTemplateLang("printer-purge.tmpl");
2454 else if (op
== CUPS_SET_DEFAULT
)
2455 cgiCopyTemplateLang("printer-default.tmpl");
2463 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2467 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2469 int i
; /* Looping var */
2470 ipp_t
*request
, /* IPP request */
2471 *response
; /* IPP response */
2472 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2473 const char *printer
, /* Printer name (purge-jobs) */
2474 *is_class
, /* Is a class? */
2475 *users
, /* List of users or groups */
2476 *type
; /* Allow/deny type */
2477 int num_users
; /* Number of users */
2478 char *ptr
, /* Pointer into users string */
2479 *end
, /* Pointer to end of users string */
2480 quote
; /* Quote character */
2481 ipp_attribute_t
*attr
; /* Attribute */
2482 static const char * const attrs
[] = /* Requested attributes */
2484 "requesting-user-name-allowed",
2485 "requesting-user-name-denied"
2489 is_class
= cgiGetVariable("IS_CLASS");
2490 printer
= cgiGetVariable("PRINTER_NAME");
2494 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2495 cgiStartHTML(cgiText(_("Set Allowed Users")));
2496 cgiCopyTemplateLang("error.tmpl");
2501 users
= cgiGetVariable("users");
2502 type
= cgiGetVariable("type");
2504 if (!users
|| !type
||
2505 (strcmp(type
, "requesting-user-name-allowed") &&
2506 strcmp(type
, "requesting-user-name-denied")))
2509 * Build a Get-Printer-Attributes request, which requires the following
2512 * attributes-charset
2513 * attributes-natural-language
2515 * requested-attributes
2518 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2520 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2521 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2523 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2526 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2527 "requested-attributes",
2528 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2531 * Do the request and get back a response...
2534 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2536 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2538 ippDelete(response
);
2541 cgiStartHTML(cgiText(_("Set Allowed Users")));
2543 if (cupsLastError() > IPP_OK_CONFLICT
)
2544 cgiShowIPPError(_("Unable to get printer attributes:"));
2546 cgiCopyTemplateLang("users.tmpl");
2553 * Save the changes...
2556 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2559 * Skip whitespace and commas...
2562 while (*ptr
== ',' || isspace(*ptr
& 255))
2565 if (*ptr
== '\'' || *ptr
== '\"')
2568 * Scan quoted name...
2573 for (end
= ptr
; *end
; end
++)
2580 * Scan space or comma-delimited name...
2583 for (end
= ptr
; *end
; end
++)
2584 if (isspace(*end
& 255) || *end
== ',')
2589 * Advance to the next name...
2596 * Build a CUPS-Add-Printer/Class request, which requires the following
2599 * attributes-charset
2600 * attributes-natural-language
2602 * requesting-user-name-{allowed,denied}
2605 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2607 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2608 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2610 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2614 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
2615 "requesting-user-name-allowed", NULL
, "all");
2618 attr
= ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
2619 type
, num_users
, NULL
, NULL
);
2621 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2624 * Skip whitespace and commas...
2627 while (*ptr
== ',' || isspace(*ptr
& 255))
2630 if (*ptr
== '\'' || *ptr
== '\"')
2633 * Scan quoted name...
2638 for (end
= ptr
; *end
; end
++)
2645 * Scan space or comma-delimited name...
2648 for (end
= ptr
; *end
; end
++)
2649 if (isspace(*end
& 255) || *end
== ',')
2654 * Terminate the name...
2664 attr
->values
[i
].string
.text
= strdup(ptr
);
2667 * Advance to the next name...
2675 * Do the request and get back a response...
2678 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2680 if (cupsLastError() > IPP_OK_CONFLICT
)
2682 cgiStartHTML(cgiText(_("Set Allowed Users")));
2683 cgiShowIPPError(_("Unable to change printer:"));
2688 * Redirect successful updates back to the printer page...
2691 char url
[1024], /* Printer/class URL */
2692 refresh
[1024]; /* Refresh URL */
2695 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2696 cgiFormEncode(uri
, url
, sizeof(uri
));
2697 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2698 cgiSetVariable("refresh_page", refresh
);
2700 cgiStartHTML(cgiText(_("Set Allowed Users")));
2702 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2703 "printer-modified.tmpl");
2712 * 'do_set_sharing()' - Set printer-is-shared value...
2716 do_set_sharing(http_t
*http
) /* I - HTTP connection */
2718 ipp_t
*request
, /* IPP request */
2719 *response
; /* IPP response */
2720 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2721 const char *printer
, /* Printer name */
2722 *is_class
, /* Is a class? */
2723 *shared
; /* Sharing value */
2726 is_class
= cgiGetVariable("IS_CLASS");
2727 printer
= cgiGetVariable("PRINTER_NAME");
2728 shared
= cgiGetVariable("SHARED");
2730 if (!printer
|| !shared
)
2732 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2733 cgiStartHTML(cgiText(_("Set Publishing")));
2734 cgiCopyTemplateLang("error.tmpl");
2740 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
2741 * following attributes:
2743 * attributes-charset
2744 * attributes-natural-language
2749 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2751 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2752 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2754 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2757 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
2760 * Do the request and get back a response...
2763 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
2765 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2767 ippDelete(response
);
2770 if (cupsLastError() > IPP_OK_CONFLICT
)
2772 cgiStartHTML(cgiText(_("Set Publishing")));
2773 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
2778 * Redirect successful updates back to the printer page...
2781 char url
[1024], /* Printer/class URL */
2782 refresh
[1024]; /* Refresh URL */
2785 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2786 cgiFormEncode(uri
, url
, sizeof(uri
));
2787 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2788 cgiSetVariable("refresh_page", refresh
);
2790 cgiStartHTML(cgiText(_("Set Publishing")));
2791 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2792 "printer-modified.tmpl");
2800 * 'match_string()' - Return the number of matching characters.
2803 static int /* O - Number of matching characters */
2804 match_string(const char *a
, /* I - First string */
2805 const char *b
) /* I - Second string */
2807 int count
; /* Number of matching characters */
2811 * Loop through both strings until we hit the end of either or we find
2812 * a non-matching character. For the purposes of comparison, we ignore
2813 * whitespace and do a case-insensitive comparison so that we have a
2814 * better chance of finding a match...
2817 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
2820 * Skip leading whitespace characters...
2823 while (isspace(*a
& 255))
2826 while (isspace(*b
& 255))
2830 * Break out if we run out of characters...
2837 * Do a case-insensitive comparison of the next two chars...
2840 if (tolower(*a
& 255) != tolower(*b
& 255))
2849 * End of "$Id: admin.c 5240 2006-03-07 21:55:29Z mike $".