2 * "$Id: admin.c 5290 2006-03-14 21:43:57Z 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",
341 IPP_TAG_NAME
)) != NULL
)
344 * Mark any current members in the class...
347 for (j
= 0; j
< num_printers
; j
++)
348 cgiSetArray("MEMBER_SELECTED", j
, "");
350 for (i
= 0; i
< attr
->num_values
; i
++)
352 for (j
= 0; j
< num_printers
; j
++)
354 if (!strcasecmp(attr
->values
[i
].string
.text
,
355 cgiGetArray("MEMBER_NAMES", j
)))
357 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
364 if ((attr
= ippFindAttribute(response
, "printer-info",
365 IPP_TAG_TEXT
)) != NULL
)
366 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
368 if ((attr
= ippFindAttribute(response
, "printer-location",
369 IPP_TAG_TEXT
)) != NULL
)
370 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
376 * Update the location and description of an existing printer...
380 cgiCopyTemplateLang("modify-class.tmpl");
385 * Get the name, location, and description for a new printer...
389 cgiCopyTemplateLang("add-class.tmpl");
397 for (ptr
= name
; *ptr
; ptr
++)
398 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
401 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
403 cgiSetVariable("ERROR",
404 cgiText(_("The class name may only contain up to "
405 "127 printable characters and may not "
406 "contain spaces, slashes (/), or the "
407 "pound sign (#).")));
409 cgiCopyTemplateLang("error.tmpl");
415 * Build a CUPS_ADD_CLASS request, which requires the following
419 * attributes-natural-language
423 * printer-is-accepting-jobs
428 request
= ippNewRequest(CUPS_ADD_CLASS
);
430 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
431 "localhost", 0, "/classes/%s",
432 cgiGetVariable("PRINTER_NAME"));
433 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
436 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
437 NULL
, cgiGetVariable("PRINTER_LOCATION"));
439 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
440 NULL
, cgiGetVariable("PRINTER_INFO"));
442 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
444 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
447 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
449 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
450 num_printers
, NULL
, NULL
);
451 for (i
= 0; i
< num_printers
; i
++)
452 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
456 * Do the request and get back a response...
459 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
461 if (cupsLastError() > IPP_OK_CONFLICT
)
464 cgiShowIPPError(modify
? _("Unable to modify class:") :
465 _("Unable to add class:"));
470 * Redirect successful updates back to the class page...
473 char refresh
[1024]; /* Refresh URL */
475 cgiFormEncode(uri
, name
, sizeof(uri
));
476 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=/classes/%s",
478 cgiSetVariable("refresh_page", refresh
);
483 cgiCopyTemplateLang("class-modified.tmpl");
485 cgiCopyTemplateLang("class-added.tmpl");
493 * 'do_am_printer()' - Add or modify a printer.
497 do_am_printer(http_t
*http
, /* I - HTTP connection */
498 int modify
) /* I - Modify the printer? */
500 int i
; /* Looping var */
501 int element
; /* Element number */
502 ipp_attribute_t
*attr
, /* Current attribute */
503 *last
; /* Last attribute */
504 ipp_t
*request
, /* IPP request */
505 *response
, /* IPP response */
506 *oldinfo
; /* Old printer information */
507 const cgi_file_t
*file
; /* Uploaded file, if any */
508 const char *var
; /* CGI variable */
509 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
510 *uriptr
; /* Pointer into URI */
511 int maxrate
; /* Maximum baud rate */
512 char baudrate
[255]; /* Baud rate string */
513 const char *name
, /* Pointer to class name */
514 *ptr
; /* Pointer to CGI variable */
515 const char *title
; /* Title of page */
516 static int baudrates
[] = /* Baud rates */
531 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
532 cgiGetVariable("DEVICE_URI"));
534 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
539 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
540 * following attributes:
543 * attributes-natural-language
547 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
549 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
550 "localhost", 0, "/printers/%s",
551 cgiGetVariable("PRINTER_NAME"));
552 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
556 * Do the request and get back a response...
559 oldinfo
= cupsDoRequest(http
, request
, "/");
564 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
565 cgiGetVariable("PRINTER_LOCATION") == NULL
)
572 * Update the location and description of an existing printer...
576 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
578 cgiCopyTemplateLang("modify-printer.tmpl");
583 * Get the name, location, and description for a new printer...
586 cgiCopyTemplateLang("add-printer.tmpl");
597 for (ptr
= name
; *ptr
; ptr
++)
598 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
601 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
603 cgiSetVariable("ERROR",
604 cgiText(_("The printer name may only contain up to "
605 "127 printable characters and may not "
606 "contain spaces, slashes (/), or the "
607 "pound sign (#).")));
609 cgiCopyTemplateLang("error.tmpl");
618 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
619 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
620 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
621 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
624 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
627 * Build a CUPS_GET_DEVICES request, which requires the following
631 * attributes-natural-language
635 fputs("DEBUG: Getting list of devices...\n", stderr
);
637 request
= ippNewRequest(CUPS_GET_DEVICES
);
639 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
640 NULL
, "ipp://localhost/printers/");
643 * Do the request and get back a response...
646 fprintf(stderr
, "DEBUG: http=%p (%s)\n", http
, http
->hostname
);
648 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
650 fputs("DEBUG: Got device list!\n", stderr
);
652 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
657 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
658 cupsLastError(), cupsLastErrorString());
661 * Let the user choose...
664 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
666 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
667 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
670 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
671 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
675 cgiCopyTemplateLang("choose-device.tmpl");
678 else if (strchr(var
, '/') == NULL
)
680 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
683 * Set the current device URI for the form to the old one...
686 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
687 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
691 * User needs to set the full URI...
695 cgiCopyTemplateLang("choose-uri.tmpl");
698 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
701 * Need baud rate, parity, etc.
704 if ((var
= strchr(var
, '?')) != NULL
&&
705 strncmp(var
, "?baud=", 6) == 0)
706 maxrate
= atoi(var
+ 6);
710 for (i
= 0; i
< 10; i
++)
711 if (baudrates
[i
] > maxrate
)
715 sprintf(baudrate
, "%d", baudrates
[i
]);
716 cgiSetArray("BAUDRATES", i
, baudrate
);
720 cgiCopyTemplateLang("choose-serial.tmpl");
723 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
728 * Get the PPD file...
731 int fd
; /* PPD file */
732 char filename
[1024]; /* PPD filename */
733 ppd_file_t
*ppd
; /* PPD information */
734 char buffer
[1024]; /* Buffer */
735 int bytes
; /* Number of bytes */
736 http_status_t get_status
; /* Status of GET */
739 /* TODO: Use cupsGetFile() API... */
740 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
742 if (httpGet(http
, uri
))
745 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
747 if (get_status
!= HTTP_OK
)
749 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
750 uri
, get_status
, httpStatus(get_status
));
752 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
754 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
755 write(fd
, buffer
, bytes
);
759 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
761 if (ppd
->manufacturer
)
762 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
765 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
772 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
773 filename
, ppdErrorString(ppdLastError(&bytes
)));
781 "ERROR: Unable to create temporary file for PPD file: %s\n",
785 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
788 * Extract make and make/model from device URI string...
791 char make
[1024], /* Make string */
792 *makeptr
; /* Pointer into make */
797 strlcpy(make
, uriptr
, sizeof(make
));
799 if ((makeptr
= strchr(make
, ' ')) != NULL
)
801 else if ((makeptr
= strchr(make
, '-')) != NULL
)
803 else if (!strncasecmp(make
, "laserjet", 8) ||
804 !strncasecmp(make
, "deskjet", 7) ||
805 !strncasecmp(make
, "designjet", 9))
807 else if (!strncasecmp(make
, "phaser", 6))
808 strcpy(make
, "Xerox");
809 else if (!strncasecmp(make
, "stylus", 6))
810 strcpy(make
, "Epson");
812 strcpy(make
, "Generic");
814 cgiSetVariable("CURRENT_MAKE", make
);
815 cgiSetVariable("PPD_MAKE", make
);
816 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
820 * Build a CUPS_GET_PPDS request, which requires the following
824 * attributes-natural-language
828 request
= ippNewRequest(CUPS_GET_PPDS
);
830 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
831 NULL
, "ipp://localhost/printers/");
833 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
834 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
835 "ppd-make", NULL
, var
);
837 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
838 "requested-attributes", NULL
, "ppd-make");
841 * Do the request and get back a response...
844 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
847 * Got the list of PPDs, see if the user has selected a make...
850 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
855 * Let the user choose a make...
858 for (element
= 0, attr
= response
->attrs
, last
= NULL
;
861 if (attr
->name
&& strcmp(attr
->name
, "ppd-make") == 0)
863 strcasecmp(last
->values
[0].string
.text
,
864 attr
->values
[0].string
.text
) != 0)
866 cgiSetArray("PPD_MAKE", element
, attr
->values
[0].string
.text
);
872 cgiCopyTemplateLang("choose-make.tmpl");
878 * Let the user choose a model...
881 const char *make_model
; /* Current make/model string */
884 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
887 * Scan for "close" matches...
890 int match
, /* Current match */
891 best_match
, /* Best match so far */
892 count
; /* Number of drivers */
893 const char *best
, /* Best matching string */
894 *current
; /* Current string */
897 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
899 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
901 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
902 match
= match_string(make_model
, current
);
904 if (match
> best_match
)
911 if (best_match
> strlen(var
))
914 * Found a match longer than the make...
917 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
922 cgiCopyTemplateLang("choose-model.tmpl");
932 cgiShowIPPError(_("Unable to get list of printer drivers:"));
933 cgiCopyTemplateLang("error.tmpl");
940 * Build a CUPS_ADD_PRINTER request, which requires the following
944 * attributes-natural-language
950 * printer-is-accepting-jobs
954 request
= ippNewRequest(CUPS_ADD_PRINTER
);
956 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
957 "localhost", 0, "/printers/%s",
958 cgiGetVariable("PRINTER_NAME"));
959 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
962 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
963 NULL
, cgiGetVariable("PRINTER_LOCATION"));
965 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
966 NULL
, cgiGetVariable("PRINTER_INFO"));
969 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
970 NULL
, cgiGetVariable("PPD_NAME"));
972 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
975 * Strip make and model from URI...
978 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
981 if (!strncmp(uri
, "serial:", 7))
984 * Update serial port URI to include baud rate, etc.
987 if ((uriptr
= strchr(uri
, '?')) == NULL
)
988 uriptr
= uri
+ strlen(uri
);
990 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
991 "?baud=%s+bits=%s+parity=%s+flow=%s",
992 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
993 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
996 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
999 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1001 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1005 * Do the request and get back a response...
1009 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1011 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1013 if (cupsLastError() > IPP_OK_CONFLICT
)
1015 cgiStartHTML(title
);
1016 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1017 _("Unable to add printer:"));
1022 * Redirect successful updates back to the printer or set-options pages...
1025 char refresh
[1024]; /* Refresh URL */
1028 cgiFormEncode(uri
, name
, sizeof(uri
));
1031 snprintf(refresh
, sizeof(refresh
),
1032 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1034 snprintf(refresh
, sizeof(refresh
),
1035 "5;/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1037 cgiSetVariable("refresh_page", refresh
);
1039 cgiStartHTML(title
);
1042 cgiCopyTemplateLang("printer-modified.tmpl");
1044 cgiCopyTemplateLang("printer-added.tmpl");
1056 * 'do_config_printer()' - Configure the default options for a printer.
1060 do_config_printer(http_t
*http
) /* I - HTTP connection */
1062 int i
, j
, k
, m
; /* Looping vars */
1063 int have_options
; /* Have options? */
1064 ipp_t
*request
, /* IPP request */
1065 *response
; /* IPP response */
1066 ipp_attribute_t
*attr
; /* IPP attribute */
1067 char uri
[HTTP_MAX_URI
]; /* Job URI */
1068 const char *var
; /* Variable value */
1069 const char *printer
; /* Printer printer name */
1070 const char *filename
; /* PPD filename */
1071 char tempfile
[1024]; /* Temporary filename */
1072 cups_file_t
*in
, /* Input file */
1073 *out
; /* Output file */
1074 char line
[1024]; /* Line from PPD file */
1075 char keyword
[1024], /* Keyword from Default line */
1076 *keyptr
; /* Pointer into keyword... */
1077 ppd_file_t
*ppd
; /* PPD file */
1078 ppd_group_t
*group
; /* Option group */
1079 ppd_option_t
*option
; /* Option */
1080 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
1081 const char *title
; /* Page title */
1084 title
= cgiText(_("Set Printer Options"));
1086 fprintf(stderr
, "DEBUG: do_config_printer(http=%p)\n", http
);
1089 * Get the printer name...
1092 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1093 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1094 "localhost", 0, "/printers/%s", printer
);
1097 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1098 cgiStartHTML(title
);
1099 cgiCopyTemplateLang("error.tmpl");
1104 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
1107 * Get the PPD file...
1110 if ((filename
= cupsGetPPD2(http
, printer
)) == NULL
)
1112 fputs("DEBUG: No PPD file!?!\n", stderr
);
1114 cgiStartHTML(title
);
1115 cgiShowIPPError(_("Unable to get PPD file!"));
1120 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
1122 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
1124 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
1125 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1126 cgiStartHTML(title
);
1127 cgiCopyTemplateLang("error.tmpl");
1132 if (cgiGetVariable("job_sheets_start") != NULL
||
1133 cgiGetVariable("job_sheets_end") != NULL
)
1138 ppdMarkDefaults(ppd
);
1140 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1141 "<UL>\n", ppd
->num_groups
));
1143 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
1145 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
1147 for (j
= group
->num_options
, option
= group
->options
;
1150 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
1152 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
1154 ppdMarkOption(ppd
, option
->keyword
, var
);
1158 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
1161 DEBUG_puts("</UL></LI>");
1164 DEBUG_printf(("</UL>\n"
1165 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
1167 if (!have_options
|| ppdConflicts(ppd
))
1170 * Show the options to the user...
1173 fputs("DEBUG: Showing options...\n", stderr
);
1177 cgiStartHTML("Set Printer Options");
1178 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1180 if (ppdConflicts(ppd
))
1182 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
1185 for (j
= group
->num_options
, option
= group
->options
;
1188 if (option
->conflicted
)
1190 cgiSetArray("ckeyword", k
, option
->keyword
);
1191 cgiSetArray("ckeytext", k
, option
->text
);
1195 cgiCopyTemplateLang("option-conflict.tmpl");
1198 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1202 if (!strcmp(group
->name
, "InstallableOptions"))
1203 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
1205 cgiSetVariable("GROUP", group
->text
);
1207 cgiCopyTemplateLang("option-header.tmpl");
1209 for (j
= group
->num_options
, option
= group
->options
;
1213 if (!strcmp(option
->keyword
, "PageRegion"))
1216 cgiSetVariable("KEYWORD", option
->keyword
);
1217 cgiSetVariable("KEYTEXT", option
->text
);
1219 if (option
->conflicted
)
1220 cgiSetVariable("CONFLICTED", "1");
1222 cgiSetVariable("CONFLICTED", "0");
1224 cgiSetSize("CHOICES", 0);
1225 cgiSetSize("TEXT", 0);
1226 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
1229 * Hide custom option values...
1232 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
1235 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
1236 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
1240 if (option
->choices
[k
].marked
)
1241 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
1246 case PPD_UI_BOOLEAN
:
1247 cgiCopyTemplateLang("option-boolean.tmpl");
1249 case PPD_UI_PICKONE
:
1250 cgiCopyTemplateLang("option-pickone.tmpl");
1252 case PPD_UI_PICKMANY
:
1253 cgiCopyTemplateLang("option-pickmany.tmpl");
1258 cgiCopyTemplateLang("option-trailer.tmpl");
1262 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1263 * following attributes:
1265 * attributes-charset
1266 * attributes-natural-language
1270 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
1272 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1273 "localhost", 0, "/printers/%s", printer
);
1274 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1278 * Do the request and get back a response...
1281 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1283 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
1284 IPP_TAG_ZERO
)) != NULL
)
1287 * Add the job sheets options...
1290 cgiSetVariable("GROUP", cgiText(_("Banners")));
1291 cgiCopyTemplateLang("option-header.tmpl");
1293 cgiSetSize("CHOICES", attr
->num_values
);
1294 cgiSetSize("TEXT", attr
->num_values
);
1295 for (k
= 0; k
< attr
->num_values
; k
++)
1297 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1298 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1301 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
1303 cgiSetVariable("KEYWORD", "job_sheets_start");
1304 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
1305 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1306 "" : attr
->values
[0].string
.text
);
1308 cgiCopyTemplateLang("option-pickone.tmpl");
1310 cgiSetVariable("KEYWORD", "job_sheets_end");
1311 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
1312 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
1313 "" : attr
->values
[1].string
.text
);
1315 cgiCopyTemplateLang("option-pickone.tmpl");
1317 cgiCopyTemplateLang("option-trailer.tmpl");
1320 if (ippFindAttribute(response
, "printer-error-policy-supported",
1322 ippFindAttribute(response
, "printer-op-policy-supported",
1326 * Add the error and operation policy options...
1329 cgiSetVariable("GROUP", cgiText(_("Policies")));
1330 cgiCopyTemplateLang("option-header.tmpl");
1336 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
1341 cgiSetSize("CHOICES", attr
->num_values
);
1342 cgiSetSize("TEXT", attr
->num_values
);
1343 for (k
= 0; k
< attr
->num_values
; k
++)
1345 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1346 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1349 attr
= ippFindAttribute(response
, "printer-error-policy",
1352 cgiSetVariable("KEYWORD", "printer_error_policy");
1353 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
1354 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1355 "" : attr
->values
[0].string
.text
);
1358 cgiCopyTemplateLang("option-pickone.tmpl");
1361 * Operation policy...
1364 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
1369 cgiSetSize("CHOICES", attr
->num_values
);
1370 cgiSetSize("TEXT", attr
->num_values
);
1371 for (k
= 0; k
< attr
->num_values
; k
++)
1373 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1374 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1377 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
1379 cgiSetVariable("KEYWORD", "printer_op_policy");
1380 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
1381 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1382 "" : attr
->values
[0].string
.text
);
1384 cgiCopyTemplateLang("option-pickone.tmpl");
1387 cgiCopyTemplateLang("option-trailer.tmpl");
1390 ippDelete(response
);
1394 * Binary protocol support...
1397 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
1399 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
1401 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
1402 cgiCopyTemplateLang("option-header.tmpl");
1404 cgiSetSize("CHOICES", 2);
1405 cgiSetSize("TEXT", 2);
1406 cgiSetArray("CHOICES", 0, "None");
1407 cgiSetArray("TEXT", 0, cgiText(_("None")));
1409 if (strstr(ppd
->protocols
, "TBCP"))
1411 cgiSetArray("CHOICES", 1, "TBCP");
1412 cgiSetArray("TEXT", 1, "TBCP");
1416 cgiSetArray("CHOICES", 1, "BCP");
1417 cgiSetArray("TEXT", 1, "BCP");
1420 cgiSetVariable("KEYWORD", "protocol");
1421 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
1422 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
1424 cgiCopyTemplateLang("option-pickone.tmpl");
1426 cgiCopyTemplateLang("option-trailer.tmpl");
1429 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1435 * Set default options...
1438 fputs("DEBUG: Setting options...\n", stderr
);
1440 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
1441 in
= cupsFileOpen(filename
, "r");
1445 cgiSetVariable("ERROR", strerror(errno
));
1446 cgiStartHTML("Set Printer Options");
1447 cgiCopyTemplateLang("error.tmpl");
1463 while (cupsFileGets(in
, line
, sizeof(line
)))
1465 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1467 else if (strncmp(line
, "*Default", 8))
1468 cupsFilePrintf(out
, "%s\n", line
);
1472 * Get default option name...
1475 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
1477 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1478 if (*keyptr
== ':' || isspace(*keyptr
& 255))
1483 if (!strcmp(keyword
, "PageRegion"))
1484 var
= cgiGetVariable("PageSize");
1486 var
= cgiGetVariable(keyword
);
1489 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
1491 cupsFilePrintf(out
, "%s\n", line
);
1495 if ((var
= cgiGetVariable("protocol")) != NULL
)
1496 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1502 * Build a CUPS_ADD_PRINTER request, which requires the following
1505 * attributes-charset
1506 * attributes-natural-language
1508 * job-sheets-default
1512 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1514 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1515 "localhost", 0, "/printers/%s",
1516 cgiGetVariable("PRINTER_NAME"));
1517 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1520 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1521 "job-sheets-default", 2, NULL
, NULL
);
1522 attr
->values
[0].string
.text
= strdup(cgiGetVariable("job_sheets_start"));
1523 attr
->values
[1].string
.text
= strdup(cgiGetVariable("job_sheets_end"));
1525 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
1526 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1527 "printer-error-policy", NULL
, var
);
1529 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
1530 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1531 "printer-op-policy", NULL
, var
);
1534 * Do the request and get back a response...
1537 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
1539 if (cupsLastError() > IPP_OK_CONFLICT
)
1541 cgiStartHTML(title
);
1542 cgiShowIPPError(_("Unable to set options:"));
1547 * Redirect successful updates back to the printer page...
1550 char refresh
[1024]; /* Refresh URL */
1553 cgiFormEncode(uri
, printer
, sizeof(uri
));
1554 snprintf(refresh
, sizeof(refresh
),
1555 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1556 cgiSetVariable("refresh_page", refresh
);
1558 cgiStartHTML(title
);
1560 cgiCopyTemplateLang("printer-configured.tmpl");
1573 * 'do_config_server()' - Configure server settings.
1577 do_config_server(http_t
*http
) /* I - HTTP connection */
1579 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1582 * Save basic setting changes...
1585 int num_settings
; /* Number of server settings */
1586 cups_option_t
*settings
; /* Server settings */
1590 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1591 cgiGetVariable("DEBUG_LOGGING") ? "1" : "0",
1592 num_settings
, &settings
);
1593 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1594 cgiGetVariable("REMOTE_ADMIN") ? "1" : "0",
1595 num_settings
, &settings
);
1596 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1597 cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0",
1598 num_settings
, &settings
);
1599 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1600 cgiGetVariable("SHARE_PRINTERS") ? "1" : "0",
1601 num_settings
, &settings
);
1602 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1603 cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0",
1604 num_settings
, &settings
);
1607 if (!_cupsAdminSetServerSettings(http
, num_settings
, settings
))
1609 cgiStartHTML(cgiText(_("Change Settings")));
1610 cgiSetVariable("MESSAGE",
1611 cgiText(_("Unable to change server settings:")));
1612 cgiSetVariable("ERROR", cupsLastErrorString());
1613 cgiCopyTemplateLang("error.tmpl");
1617 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1618 cgiStartHTML(cgiText(_("Change Settings")));
1619 cgiCopyTemplateLang("restart.tmpl");
1622 cupsFreeOptions(num_settings
, settings
);
1626 else if (cgiIsPOST())
1629 * Save hand-edited config file...
1632 http_status_t status
; /* PUT status */
1633 char tempfile
[1024]; /* Temporary new cupsd.conf */
1634 int tempfd
; /* Temporary file descriptor */
1635 cups_file_t
*temp
; /* Temporary file */
1636 const char *start
, /* Start of line */
1637 *end
; /* End of line */
1641 * Create a temporary file for the new cupsd.conf file...
1644 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1646 cgiStartHTML(cgiText(_("Edit Configuration File")));
1647 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1648 cgiSetVariable("ERROR", strerror(errno
));
1649 cgiCopyTemplateLang("error.tmpl");
1656 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1658 cgiStartHTML(cgiText(_("Edit Configuration File")));
1659 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1660 cgiSetVariable("ERROR", strerror(errno
));
1661 cgiCopyTemplateLang("error.tmpl");
1671 * Copy the cupsd.conf text from the form variable...
1674 start
= cgiGetVariable("CUPSDCONF");
1677 if ((end
= strstr(start
, "\r\n")) == NULL
)
1678 if ((end
= strstr(start
, "\n")) == NULL
)
1679 end
= start
+ strlen(start
);
1681 cupsFileWrite(temp
, start
, end
- start
);
1682 cupsFilePutChar(temp
, '\n');
1686 else if (*end
== '\n')
1692 cupsFileClose(temp
);
1695 * Upload the configuration file to the server...
1698 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1700 if (status
!= HTTP_CREATED
)
1702 cgiSetVariable("MESSAGE",
1703 cgiText(_("Unable to upload cupsd.conf file:")));
1704 cgiSetVariable("ERROR", httpStatus(status
));
1706 cgiStartHTML(cgiText(_("Edit Configuration File")));
1707 cgiCopyTemplateLang("error.tmpl");
1711 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1713 cgiStartHTML(cgiText(_("Edit Configuration File")));
1714 cgiCopyTemplateLang("restart.tmpl");
1723 struct stat info
; /* cupsd.conf information */
1724 cups_file_t
*cupsd
; /* cupsd.conf file */
1725 char *buffer
; /* Buffer for entire file */
1726 char filename
[1024]; /* Filename */
1727 const char *server_root
; /* Location of config files */
1731 * Locate the cupsd.conf file...
1734 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1735 server_root
= CUPS_SERVERROOT
;
1737 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1740 * Figure out the size...
1743 if (stat(filename
, &info
))
1745 cgiStartHTML(cgiText(_("Edit Configuration File")));
1746 cgiSetVariable("MESSAGE",
1747 cgiText(_("Unable to access cupsd.conf file:")));
1748 cgiSetVariable("ERROR", strerror(errno
));
1749 cgiCopyTemplateLang("error.tmpl");
1756 if (info
.st_size
> (1024 * 1024))
1758 cgiStartHTML(cgiText(_("Edit Configuration File")));
1759 cgiSetVariable("MESSAGE",
1760 cgiText(_("Unable to access cupsd.conf file:")));
1761 cgiSetVariable("ERROR",
1762 cgiText(_("Unable to edit cupsd.conf files larger than "
1764 cgiCopyTemplateLang("error.tmpl");
1767 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1768 (long)info
.st_size
);
1773 * Open the cupsd.conf file...
1776 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1779 * Unable to open - log an error...
1782 cgiStartHTML(cgiText(_("Edit Configuration File")));
1783 cgiSetVariable("MESSAGE",
1784 cgiText(_("Unable to access cupsd.conf file:")));
1785 cgiSetVariable("ERROR", strerror(errno
));
1786 cgiCopyTemplateLang("error.tmpl");
1794 * Allocate memory and load the file into a string buffer...
1797 buffer
= calloc(1, info
.st_size
+ 1);
1799 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1800 cupsFileClose(cupsd
);
1802 cgiSetVariable("CUPSDCONF", buffer
);
1806 * Show the current config file...
1809 cgiStartHTML("Edit Configuration File");
1811 printf("<!-- \"%s\" -->\n", filename
);
1813 cgiCopyTemplateLang("edit-config.tmpl");
1821 * 'do_delete_class()' - Delete a class...
1825 do_delete_class(http_t
*http
) /* I - HTTP connection */
1827 ipp_t
*request
; /* IPP request */
1828 char uri
[HTTP_MAX_URI
]; /* Job URI */
1829 const char *pclass
; /* Printer class name */
1832 cgiStartHTML(cgiText(_("Delete Class")));
1834 if (cgiGetVariable("CONFIRM") == NULL
)
1836 cgiCopyTemplateLang("class-confirm.tmpl");
1841 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1842 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1843 "localhost", 0, "/classes/%s", pclass
);
1846 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1847 cgiCopyTemplateLang("error.tmpl");
1853 * Build a CUPS_DELETE_CLASS request, which requires the following
1856 * attributes-charset
1857 * attributes-natural-language
1861 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1863 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1867 * Do the request and get back a response...
1870 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1872 if (cupsLastError() > IPP_OK_CONFLICT
)
1873 cgiShowIPPError(_("Unable to delete class:"));
1875 cgiCopyTemplateLang("class-deleted.tmpl");
1882 * 'do_delete_printer()' - Delete a printer...
1886 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1888 ipp_t
*request
; /* IPP request */
1889 char uri
[HTTP_MAX_URI
]; /* Job URI */
1890 const char *printer
; /* Printer printer name */
1893 cgiStartHTML(cgiText(_("Delete Printer")));
1895 if (cgiGetVariable("CONFIRM") == NULL
)
1897 cgiCopyTemplateLang("printer-confirm.tmpl");
1902 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1903 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1904 "localhost", 0, "/printers/%s", printer
);
1907 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1908 cgiCopyTemplateLang("error.tmpl");
1914 * Build a CUPS_DELETE_PRINTER request, which requires the following
1917 * attributes-charset
1918 * attributes-natural-language
1922 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1924 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1928 * Do the request and get back a response...
1931 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1933 if (cupsLastError() > IPP_OK_CONFLICT
)
1934 cgiShowIPPError(_("Unable to delete printer:"));
1936 cgiCopyTemplateLang("printer-deleted.tmpl");
1943 * 'do_export()' - Export printers to Samba...
1947 do_export(http_t
*http
) /* I - HTTP connection */
1949 int i
, j
; /* Looping vars */
1950 ipp_t
*request
, /* IPP request */
1951 *response
; /* IPP response */
1952 const char *username
, /* Samba username */
1953 *password
, /* Samba password */
1954 *export_all
; /* Export all printers? */
1955 int export_count
, /* Number of printers to export */
1956 printer_count
; /* Number of available printers */
1957 const char *name
, /* What name to pull */
1958 *dest
; /* Current destination */
1959 char ppd
[1024]; /* PPD file */
1966 username
= cgiGetVariable("USERNAME");
1967 password
= cgiGetVariable("PASSWORD");
1968 export_all
= cgiGetVariable("EXPORT_ALL");
1969 export_count
= cgiGetSize("EXPORT_NAME");
1972 * Get list of available printers...
1975 cgiSetSize("PRINTER_NAME", 0);
1976 cgiSetSize("PRINTER_EXPORT", 0);
1978 request
= ippNewRequest(CUPS_GET_PRINTERS
);
1980 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1983 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1984 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
1985 CUPS_PRINTER_IMPLICIT
);
1987 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1988 "requested-attributes", NULL
, "printer-name");
1990 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1992 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1993 ippDelete(response
);
1997 printer_count
= cgiGetSize("PRINTER_NAME");
1999 for (i
= 0; i
< printer_count
; i
++)
2001 dest
= cgiGetArray("PRINTER_NAME", i
);
2003 for (j
= 0; j
< export_count
; j
++)
2004 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2007 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2013 * Export or get the printers to export...
2016 if (username
&& *username
&& password
&& *password
&&
2017 (export_all
|| export_count
> 0))
2023 fputs("DEBUG: Export printers...\n", stderr
);
2027 name
= "PRINTER_NAME";
2028 export_count
= cgiGetSize("PRINTER_NAME");
2031 name
= "EXPORT_NAME";
2033 for (i
= 0; i
< export_count
; i
++)
2035 dest
= cgiGetArray(name
, i
);
2037 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2040 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2049 if (i
< export_count
)
2050 cgiSetVariable("ERROR", cupsLastErrorString());
2053 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2054 cgiCopyTemplateLang("samba-exported.tmpl");
2059 else if (username
&& !*username
)
2060 cgiSetVariable("ERROR",
2061 cgiText(_("A Samba username is required to export "
2062 "printer drivers!")));
2063 else if (username
&& (!password
|| !*password
))
2064 cgiSetVariable("ERROR",
2065 cgiText(_("A Samba password is required to export "
2066 "printer drivers!")));
2072 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2073 cgiCopyTemplateLang("samba-export.tmpl");
2079 * 'do_menu()' - Show the main menu...
2083 do_menu(http_t
*http
) /* I - HTTP connection */
2085 int num_settings
; /* Number of server settings */
2086 cups_option_t
*settings
; /* Server settings */
2087 const char *val
; /* Setting value */
2088 char filename
[1024]; /* Temporary filename */
2089 const char *datadir
; /* Location of data files */
2090 ipp_t
*request
, /* IPP request */
2091 *response
; /* IPP response */
2092 ipp_attribute_t
*attr
; /* IPP attribute */
2096 * Get the current server settings...
2099 if (!_cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2101 cgiSetVariable("SETTINGS_MESSAGE",
2102 cgiText(_("Unable to open cupsd.conf file:")));
2103 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2106 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2107 settings
)) != NULL
&& atoi(val
))
2108 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2110 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2111 settings
)) != NULL
&& atoi(val
))
2112 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2114 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2115 settings
)) != NULL
&& atoi(val
))
2116 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2118 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2119 settings
)) != NULL
&& atoi(val
))
2120 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2122 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2123 settings
)) != NULL
&& atoi(val
))
2124 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2126 cupsFreeOptions(num_settings
, settings
);
2129 * Get the list of printers and their devices...
2132 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2134 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2135 "requested-attributes", NULL
, "device-uri");
2137 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2138 CUPS_PRINTER_LOCAL
);
2139 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2140 CUPS_PRINTER_LOCAL
);
2142 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2145 * Got the printer list, now load the devices...
2148 int i
; /* Looping var */
2149 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2150 char *printer_device
; /* Current printer device */
2154 * Allocate an array and copy the device strings...
2157 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2159 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2161 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2163 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2167 * Free the printer list and get the device list...
2170 ippDelete(response
);
2172 request
= ippNewRequest(CUPS_GET_DEVICES
);
2174 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2177 * Got the device list, let's parse it...
2180 const char *device_uri
, /* device-uri attribute value */
2181 *device_make_and_model
, /* device-make-and-model value */
2182 *device_info
; /* device-info value */
2185 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2188 * Skip leading attributes until we hit a device...
2191 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2198 * Pull the needed attributes from this device...
2202 device_make_and_model
= NULL
;
2205 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2207 if (!strcmp(attr
->name
, "device-info") &&
2208 attr
->value_tag
== IPP_TAG_TEXT
)
2209 device_info
= attr
->values
[0].string
.text
;
2211 if (!strcmp(attr
->name
, "device-make-and-model") &&
2212 attr
->value_tag
== IPP_TAG_TEXT
)
2213 device_make_and_model
= attr
->values
[0].string
.text
;
2215 if (!strcmp(attr
->name
, "device-uri") &&
2216 attr
->value_tag
== IPP_TAG_URI
)
2217 device_uri
= attr
->values
[0].string
.text
;
2223 * See if we have everything needed...
2226 if (device_info
&& device_make_and_model
&& device_uri
&&
2227 strcasecmp(device_make_and_model
, "unknown") &&
2228 strchr(device_uri
, ':'))
2231 * Yes, now see if there is already a printer for this
2235 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2238 * Not found, so it must be a new printer...
2241 char options
[1024], /* Form variables for this device */
2242 *options_ptr
; /* Pointer into string */
2243 const char *ptr
; /* Pointer into device string */
2247 * Format the printer name variable for this device...
2249 * We use the device-info string first, then device-uri,
2250 * and finally device-make-and-model to come up with a
2254 strcpy(options
, "PRINTER_NAME=");
2255 options_ptr
= options
+ strlen(options
);
2257 if (strncasecmp(device_info
, "unknown", 7))
2259 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2262 ptr
= device_make_and_model
;
2265 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2267 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2269 *options_ptr
++ = *ptr
;
2270 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2271 *options_ptr
++ = '_';
2272 else if (*ptr
== '?' || *ptr
== '(')
2276 * Then add the make and model in the printer info, so
2277 * that MacOS clients see something reasonable...
2280 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2282 sizeof(options
) - (options_ptr
- options
));
2283 options_ptr
+= strlen(options_ptr
);
2285 cgiFormEncode(options_ptr
, device_make_and_model
,
2286 sizeof(options
) - (options_ptr
- options
));
2287 options_ptr
+= strlen(options_ptr
);
2290 * Then copy the device URI...
2293 strlcpy(options_ptr
, "&DEVICE_URI=",
2294 sizeof(options
) - (options_ptr
- options
));
2295 options_ptr
+= strlen(options_ptr
);
2297 cgiFormEncode(options_ptr
, device_uri
,
2298 sizeof(options
) - (options_ptr
- options
));
2299 options_ptr
+= strlen(options_ptr
);
2301 if (options_ptr
< (options
+ sizeof(options
) - 1))
2303 *options_ptr
++ = '|';
2304 cgiFormEncode(options_ptr
, device_make_and_model
,
2305 sizeof(options
) - (options_ptr
- options
));
2309 * Finally, set the form variables for this printer...
2312 cgiSetArray("device_info", i
, device_info
);
2313 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2314 cgiSetArray("device_options", i
, options
);
2315 cgiSetArray("device_uri", i
, device_uri
);
2324 ippDelete(response
);
2327 * Free the device list...
2330 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2332 printer_device
= (char *)cupsArrayNext(printer_devices
))
2333 free(printer_device
);
2335 cupsArrayDelete(printer_devices
);
2340 * See if Samba and the Windows drivers are installed...
2343 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2344 datadir
= CUPS_DATADIR
;
2346 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2347 if (!access(filename
, R_OK
))
2350 * Found Windows 2000 driver file, see if we have smbclient and
2354 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2355 sizeof(filename
)) &&
2356 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2358 cgiSetVariable("HAVE_SAMBA", "Y");
2361 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2363 fputs("ERROR: smbclient not found!\n", stderr
);
2365 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2367 fputs("ERROR: rpcclient not found!\n", stderr
);
2374 * Finally, show the main menu template...
2377 cgiStartHTML(cgiText(_("Administration")));
2379 cgiCopyTemplateLang("admin.tmpl");
2386 * 'do_printer_op()' - Do a printer operation.
2390 do_printer_op(http_t
*http
, /* I - HTTP connection */
2391 ipp_op_t op
, /* I - Operation to perform */
2392 const char *title
) /* I - Title of page */
2394 ipp_t
*request
; /* IPP request */
2395 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2396 const char *printer
, /* Printer name (purge-jobs) */
2397 *is_class
; /* Is a class? */
2400 is_class
= cgiGetVariable("IS_CLASS");
2401 printer
= cgiGetVariable("PRINTER_NAME");
2405 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2406 cgiStartHTML(title
);
2407 cgiCopyTemplateLang("error.tmpl");
2413 * Build a printer request, which requires the following
2416 * attributes-charset
2417 * attributes-natural-language
2421 request
= ippNewRequest(op
);
2423 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2424 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2426 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2430 * Do the request and get back a response...
2433 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2435 if (cupsLastError() > IPP_OK_CONFLICT
)
2437 cgiStartHTML(title
);
2438 cgiShowIPPError(_("Unable to change printer:"));
2443 * Redirect successful updates back to the printer page...
2446 char url
[1024], /* Printer/class URL */
2447 refresh
[1024]; /* Refresh URL */
2450 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2451 cgiFormEncode(uri
, url
, sizeof(uri
));
2452 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2453 cgiSetVariable("refresh_page", refresh
);
2455 cgiStartHTML(title
);
2457 if (op
== IPP_PAUSE_PRINTER
)
2458 cgiCopyTemplateLang("printer-stop.tmpl");
2459 else if (op
== IPP_RESUME_PRINTER
)
2460 cgiCopyTemplateLang("printer-start.tmpl");
2461 else if (op
== CUPS_ACCEPT_JOBS
)
2462 cgiCopyTemplateLang("printer-accept.tmpl");
2463 else if (op
== CUPS_REJECT_JOBS
)
2464 cgiCopyTemplateLang("printer-reject.tmpl");
2465 else if (op
== IPP_PURGE_JOBS
)
2466 cgiCopyTemplateLang("printer-purge.tmpl");
2467 else if (op
== CUPS_SET_DEFAULT
)
2468 cgiCopyTemplateLang("printer-default.tmpl");
2476 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2480 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2482 int i
; /* Looping var */
2483 ipp_t
*request
, /* IPP request */
2484 *response
; /* IPP response */
2485 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2486 const char *printer
, /* Printer name (purge-jobs) */
2487 *is_class
, /* Is a class? */
2488 *users
, /* List of users or groups */
2489 *type
; /* Allow/deny type */
2490 int num_users
; /* Number of users */
2491 char *ptr
, /* Pointer into users string */
2492 *end
, /* Pointer to end of users string */
2493 quote
; /* Quote character */
2494 ipp_attribute_t
*attr
; /* Attribute */
2495 static const char * const attrs
[] = /* Requested attributes */
2497 "requesting-user-name-allowed",
2498 "requesting-user-name-denied"
2502 is_class
= cgiGetVariable("IS_CLASS");
2503 printer
= cgiGetVariable("PRINTER_NAME");
2507 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2508 cgiStartHTML(cgiText(_("Set Allowed Users")));
2509 cgiCopyTemplateLang("error.tmpl");
2514 users
= cgiGetVariable("users");
2515 type
= cgiGetVariable("type");
2517 if (!users
|| !type
||
2518 (strcmp(type
, "requesting-user-name-allowed") &&
2519 strcmp(type
, "requesting-user-name-denied")))
2522 * Build a Get-Printer-Attributes request, which requires the following
2525 * attributes-charset
2526 * attributes-natural-language
2528 * requested-attributes
2531 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2533 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2534 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2536 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2539 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2540 "requested-attributes",
2541 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2544 * Do the request and get back a response...
2547 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2549 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2551 ippDelete(response
);
2554 cgiStartHTML(cgiText(_("Set Allowed Users")));
2556 if (cupsLastError() > IPP_OK_CONFLICT
)
2557 cgiShowIPPError(_("Unable to get printer attributes:"));
2559 cgiCopyTemplateLang("users.tmpl");
2566 * Save the changes...
2569 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2572 * Skip whitespace and commas...
2575 while (*ptr
== ',' || isspace(*ptr
& 255))
2578 if (*ptr
== '\'' || *ptr
== '\"')
2581 * Scan quoted name...
2586 for (end
= ptr
; *end
; end
++)
2593 * Scan space or comma-delimited name...
2596 for (end
= ptr
; *end
; end
++)
2597 if (isspace(*end
& 255) || *end
== ',')
2602 * Advance to the next name...
2609 * Build a CUPS-Add-Printer/Class request, which requires the following
2612 * attributes-charset
2613 * attributes-natural-language
2615 * requesting-user-name-{allowed,denied}
2618 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2620 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2621 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2623 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2627 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2628 "requesting-user-name-allowed", NULL
, "all");
2631 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2632 type
, num_users
, NULL
, NULL
);
2634 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2637 * Skip whitespace and commas...
2640 while (*ptr
== ',' || isspace(*ptr
& 255))
2643 if (*ptr
== '\'' || *ptr
== '\"')
2646 * Scan quoted name...
2651 for (end
= ptr
; *end
; end
++)
2658 * Scan space or comma-delimited name...
2661 for (end
= ptr
; *end
; end
++)
2662 if (isspace(*end
& 255) || *end
== ',')
2667 * Terminate the name...
2677 attr
->values
[i
].string
.text
= strdup(ptr
);
2680 * Advance to the next name...
2688 * Do the request and get back a response...
2691 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2693 if (cupsLastError() > IPP_OK_CONFLICT
)
2695 cgiStartHTML(cgiText(_("Set Allowed Users")));
2696 cgiShowIPPError(_("Unable to change printer:"));
2701 * Redirect successful updates back to the printer page...
2704 char url
[1024], /* Printer/class URL */
2705 refresh
[1024]; /* Refresh URL */
2708 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2709 cgiFormEncode(uri
, url
, sizeof(uri
));
2710 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2711 cgiSetVariable("refresh_page", refresh
);
2713 cgiStartHTML(cgiText(_("Set Allowed Users")));
2715 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2716 "printer-modified.tmpl");
2725 * 'do_set_sharing()' - Set printer-is-shared value...
2729 do_set_sharing(http_t
*http
) /* I - HTTP connection */
2731 ipp_t
*request
, /* IPP request */
2732 *response
; /* IPP response */
2733 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2734 const char *printer
, /* Printer name */
2735 *is_class
, /* Is a class? */
2736 *shared
; /* Sharing value */
2739 is_class
= cgiGetVariable("IS_CLASS");
2740 printer
= cgiGetVariable("PRINTER_NAME");
2741 shared
= cgiGetVariable("SHARED");
2743 if (!printer
|| !shared
)
2745 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2746 cgiStartHTML(cgiText(_("Set Publishing")));
2747 cgiCopyTemplateLang("error.tmpl");
2753 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
2754 * following attributes:
2756 * attributes-charset
2757 * attributes-natural-language
2762 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2764 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2765 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2767 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2770 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
2773 * Do the request and get back a response...
2776 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
2778 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2780 ippDelete(response
);
2783 if (cupsLastError() > IPP_OK_CONFLICT
)
2785 cgiStartHTML(cgiText(_("Set Publishing")));
2786 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
2791 * Redirect successful updates back to the printer page...
2794 char url
[1024], /* Printer/class URL */
2795 refresh
[1024]; /* Refresh URL */
2798 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2799 cgiFormEncode(uri
, url
, sizeof(uri
));
2800 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2801 cgiSetVariable("refresh_page", refresh
);
2803 cgiStartHTML(cgiText(_("Set Publishing")));
2804 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2805 "printer-modified.tmpl");
2813 * 'match_string()' - Return the number of matching characters.
2816 static int /* O - Number of matching characters */
2817 match_string(const char *a
, /* I - First string */
2818 const char *b
) /* I - Second string */
2820 int count
; /* Number of matching characters */
2824 * Loop through both strings until we hit the end of either or we find
2825 * a non-matching character. For the purposes of comparison, we ignore
2826 * whitespace and do a case-insensitive comparison so that we have a
2827 * better chance of finding a match...
2830 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
2833 * Skip leading whitespace characters...
2836 while (isspace(*a
& 255))
2839 while (isspace(*b
& 255))
2843 * Break out if we run out of characters...
2850 * Do a case-insensitive comparison of the next two chars...
2853 if (tolower(*a
& 255) != tolower(*b
& 255))
2862 * End of "$Id: admin.c 5290 2006-03-14 21:43:57Z mike $".