2 * "$Id: admin.c 5425 2006-04-18 19:59:05Z 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... */
135 char prefix
[1024]; /* URL prefix */
139 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
140 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
142 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
143 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
145 if ((url
= cgiGetVariable("URL")) != NULL
)
146 printf("Location: %s%s\n\n", prefix
, url
);
148 printf("Location: %s/admin\n\n", prefix
);
150 else if (!strcmp(op
, "start-printer"))
151 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
152 else if (!strcmp(op
, "stop-printer"))
153 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
154 else if (!strcmp(op
, "start-class"))
155 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
156 else if (!strcmp(op
, "stop-class"))
157 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
158 else if (!strcmp(op
, "accept-jobs"))
159 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
160 else if (!strcmp(op
, "reject-jobs"))
161 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
162 else if (!strcmp(op
, "purge-jobs"))
163 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
164 else if (!strcmp(op
, "set-allowed-users"))
165 do_set_allowed_users(http
);
166 else if (!strcmp(op
, "set-as-default"))
167 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
168 else if (!strcmp(op
, "set-sharing"))
169 do_set_sharing(http
);
170 else if (!strcmp(op
, "add-class"))
171 do_am_class(http
, 0);
172 else if (!strcmp(op
, "add-printer"))
173 do_am_printer(http
, 0);
174 else if (!strcmp(op
, "modify-class"))
175 do_am_class(http
, 1);
176 else if (!strcmp(op
, "modify-printer"))
177 do_am_printer(http
, 1);
178 else if (!strcmp(op
, "delete-class"))
179 do_delete_class(http
);
180 else if (!strcmp(op
, "delete-printer"))
181 do_delete_printer(http
);
182 else if (!strcmp(op
, "set-printer-options"))
183 do_config_printer(http
);
184 else if (!strcmp(op
, "config-server"))
185 do_config_server(http
);
186 else if (!strcmp(op
, "export-samba"))
191 * Bad operation code... Display an error...
194 cgiStartHTML(cgiText(_("Administration")));
195 cgiCopyTemplateLang("error-op.tmpl");
202 * Form data but no operation code... Display an error...
205 cgiStartHTML(cgiText(_("Administration")));
206 cgiCopyTemplateLang("error-op.tmpl");
211 * Close the HTTP server connection...
217 * Return with no errors...
225 * 'do_am_class()' - Add or modify a class.
229 do_am_class(http_t
*http
, /* I - HTTP connection */
230 int modify
) /* I - Modify the printer? */
232 int i
, j
; /* Looping vars */
233 int element
; /* Element number */
234 int num_printers
; /* Number of printers */
235 ipp_t
*request
, /* IPP request */
236 *response
; /* IPP response */
237 ipp_attribute_t
*attr
; /* member-uris attribute */
238 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
239 const char *name
, /* Pointer to class name */
240 *ptr
; /* Pointer to CGI variable */
241 const char *title
; /* Title of page */
242 static const char * const pattrs
[] = /* Requested printer attributes */
250 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
251 name
= cgiGetVariable("PRINTER_NAME");
253 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
256 * Build a CUPS_GET_PRINTERS request, which requires the
257 * following attributes:
260 * attributes-natural-language
264 request
= ippNewRequest(CUPS_GET_PRINTERS
);
266 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
267 NULL
, "ipp://localhost/printers");
270 * Do the request and get back a response...
273 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
276 * Create MEMBER_URIS and MEMBER_NAMES arrays...
279 for (element
= 0, attr
= response
->attrs
;
282 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
284 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
285 (!name
|| strcasecmp(name
, ptr
+ 1)))
288 * Don't show the current class...
291 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
296 for (element
= 0, attr
= response
->attrs
;
299 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
301 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
304 * Don't show the current class...
307 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
312 num_printers
= cgiGetSize("MEMBER_URIS");
322 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
323 * following attributes:
326 * attributes-natural-language
330 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
332 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
333 "localhost", 0, "/classes/%s", name
);
334 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
337 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
338 "requested-attributes",
339 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
343 * Do the request and get back a response...
346 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
348 if ((attr
= ippFindAttribute(response
, "member-names",
349 IPP_TAG_NAME
)) != NULL
)
352 * Mark any current members in the class...
355 for (j
= 0; j
< num_printers
; j
++)
356 cgiSetArray("MEMBER_SELECTED", j
, "");
358 for (i
= 0; i
< attr
->num_values
; i
++)
360 for (j
= 0; j
< num_printers
; j
++)
362 if (!strcasecmp(attr
->values
[i
].string
.text
,
363 cgiGetArray("MEMBER_NAMES", j
)))
365 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
372 if ((attr
= ippFindAttribute(response
, "printer-info",
373 IPP_TAG_TEXT
)) != NULL
)
374 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
376 if ((attr
= ippFindAttribute(response
, "printer-location",
377 IPP_TAG_TEXT
)) != NULL
)
378 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
384 * Update the location and description of an existing printer...
388 cgiCopyTemplateLang("modify-class.tmpl");
393 * Get the name, location, and description for a new printer...
397 cgiCopyTemplateLang("add-class.tmpl");
405 for (ptr
= name
; *ptr
; ptr
++)
406 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
409 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
411 cgiSetVariable("ERROR",
412 cgiText(_("The class name may only contain up to "
413 "127 printable characters and may not "
414 "contain spaces, slashes (/), or the "
415 "pound sign (#).")));
417 cgiCopyTemplateLang("error.tmpl");
423 * Build a CUPS_ADD_CLASS request, which requires the following
427 * attributes-natural-language
431 * printer-is-accepting-jobs
436 request
= ippNewRequest(CUPS_ADD_CLASS
);
438 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
439 "localhost", 0, "/classes/%s",
440 cgiGetVariable("PRINTER_NAME"));
441 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
444 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
445 NULL
, cgiGetVariable("PRINTER_LOCATION"));
447 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
448 NULL
, cgiGetVariable("PRINTER_INFO"));
450 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
452 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
455 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
457 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
458 num_printers
, NULL
, NULL
);
459 for (i
= 0; i
< num_printers
; i
++)
460 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
464 * Do the request and get back a response...
467 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
469 if (cupsLastError() > IPP_OK_CONFLICT
)
472 cgiShowIPPError(modify
? _("Unable to modify class:") :
473 _("Unable to add class:"));
478 * Redirect successful updates back to the class page...
481 char refresh
[1024]; /* Refresh URL */
483 cgiFormEncode(uri
, name
, sizeof(uri
));
484 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=/classes/%s",
486 cgiSetVariable("refresh_page", refresh
);
491 cgiCopyTemplateLang("class-modified.tmpl");
493 cgiCopyTemplateLang("class-added.tmpl");
501 * 'do_am_printer()' - Add or modify a printer.
505 do_am_printer(http_t
*http
, /* I - HTTP connection */
506 int modify
) /* I - Modify the printer? */
508 int i
; /* Looping var */
509 ipp_attribute_t
*attr
; /* Current attribute */
510 ipp_t
*request
, /* IPP request */
511 *response
, /* IPP response */
512 *oldinfo
; /* Old printer information */
513 const cgi_file_t
*file
; /* Uploaded file, if any */
514 const char *var
; /* CGI variable */
515 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
516 *uriptr
; /* Pointer into URI */
517 int maxrate
; /* Maximum baud rate */
518 char baudrate
[255]; /* Baud rate string */
519 const char *name
, /* Pointer to class name */
520 *ptr
; /* Pointer to CGI variable */
521 const char *title
; /* Title of page */
522 static int baudrates
[] = /* Baud rates */
537 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
538 cgiGetVariable("DEVICE_URI"));
540 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
545 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
546 * following attributes:
549 * attributes-natural-language
553 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
555 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
556 "localhost", 0, "/printers/%s",
557 cgiGetVariable("PRINTER_NAME"));
558 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
562 * Do the request and get back a response...
565 oldinfo
= cupsDoRequest(http
, request
, "/");
570 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
571 cgiGetVariable("PRINTER_LOCATION") == NULL
)
578 * Update the location and description of an existing printer...
582 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
584 cgiCopyTemplateLang("modify-printer.tmpl");
589 * Get the name, location, and description for a new printer...
592 cgiCopyTemplateLang("add-printer.tmpl");
603 for (ptr
= name
; *ptr
; ptr
++)
604 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
607 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
609 cgiSetVariable("ERROR",
610 cgiText(_("The printer name may only contain up to "
611 "127 printable characters and may not "
612 "contain spaces, slashes (/), or the "
613 "pound sign (#).")));
615 cgiCopyTemplateLang("error.tmpl");
624 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
625 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
626 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
627 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
630 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
633 * Build a CUPS_GET_DEVICES request, which requires the following
637 * attributes-natural-language
641 fputs("DEBUG: Getting list of devices...\n", stderr
);
643 request
= ippNewRequest(CUPS_GET_DEVICES
);
645 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
646 NULL
, "ipp://localhost/printers/");
649 * Do the request and get back a response...
652 fprintf(stderr
, "DEBUG: http=%p (%s)\n", http
, http
->hostname
);
654 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
656 fputs("DEBUG: Got device list!\n", stderr
);
658 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
663 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
664 cupsLastError(), cupsLastErrorString());
667 * Let the user choose...
670 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
672 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
673 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
676 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
677 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
681 cgiCopyTemplateLang("choose-device.tmpl");
684 else if (strchr(var
, '/') == NULL
)
686 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
689 * Set the current device URI for the form to the old one...
692 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
693 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
697 * User needs to set the full URI...
701 cgiCopyTemplateLang("choose-uri.tmpl");
704 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
707 * Need baud rate, parity, etc.
710 if ((var
= strchr(var
, '?')) != NULL
&&
711 strncmp(var
, "?baud=", 6) == 0)
712 maxrate
= atoi(var
+ 6);
716 for (i
= 0; i
< 10; i
++)
717 if (baudrates
[i
] > maxrate
)
721 sprintf(baudrate
, "%d", baudrates
[i
]);
722 cgiSetArray("BAUDRATES", i
, baudrate
);
726 cgiCopyTemplateLang("choose-serial.tmpl");
729 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
734 * Get the PPD file...
737 int fd
; /* PPD file */
738 char filename
[1024]; /* PPD filename */
739 ppd_file_t
*ppd
; /* PPD information */
740 char buffer
[1024]; /* Buffer */
741 int bytes
; /* Number of bytes */
742 http_status_t get_status
; /* Status of GET */
745 /* TODO: Use cupsGetFile() API... */
746 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
748 if (httpGet(http
, uri
))
751 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
753 if (get_status
!= HTTP_OK
)
755 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
756 uri
, get_status
, httpStatus(get_status
));
758 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
760 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
761 write(fd
, buffer
, bytes
);
765 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
767 if (ppd
->manufacturer
)
768 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
771 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
778 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
779 filename
, ppdErrorString(ppdLastError(&bytes
)));
787 "ERROR: Unable to create temporary file for PPD file: %s\n",
791 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
794 * Extract make and make/model from device URI string...
797 char make
[1024], /* Make string */
798 *makeptr
; /* Pointer into make */
803 strlcpy(make
, uriptr
, sizeof(make
));
805 if ((makeptr
= strchr(make
, ' ')) != NULL
)
807 else if ((makeptr
= strchr(make
, '-')) != NULL
)
809 else if (!strncasecmp(make
, "laserjet", 8) ||
810 !strncasecmp(make
, "deskjet", 7) ||
811 !strncasecmp(make
, "designjet", 9))
813 else if (!strncasecmp(make
, "phaser", 6))
814 strcpy(make
, "Xerox");
815 else if (!strncasecmp(make
, "stylus", 6))
816 strcpy(make
, "Epson");
818 strcpy(make
, "Generic");
820 cgiSetVariable("CURRENT_MAKE", make
);
821 cgiSetVariable("PPD_MAKE", make
);
822 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
826 * Build a CUPS_GET_PPDS request, which requires the following
830 * attributes-natural-language
834 request
= ippNewRequest(CUPS_GET_PPDS
);
836 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
837 NULL
, "ipp://localhost/printers/");
839 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
840 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
841 "ppd-make", NULL
, var
);
843 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
844 "requested-attributes", NULL
, "ppd-make");
847 * Do the request and get back a response...
850 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
853 * Got the list of PPDs, see if the user has selected a make...
856 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
859 * No PPD files with this make, try again with all makes...
864 request
= ippNewRequest(CUPS_GET_PPDS
);
866 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
867 NULL
, "ipp://localhost/printers/");
869 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
870 "requested-attributes", NULL
, "ppd-make");
872 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
873 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
876 cgiCopyTemplateLang("choose-make.tmpl");
882 cgiCopyTemplateLang("choose-make.tmpl");
888 * Let the user choose a model...
891 const char *make_model
; /* Current make/model string */
894 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
897 * Scan for "close" matches...
900 int match
, /* Current match */
901 best_match
, /* Best match so far */
902 count
; /* Number of drivers */
903 const char *best
, /* Best matching string */
904 *current
; /* Current string */
907 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
909 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
911 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
912 match
= match_string(make_model
, current
);
914 if (match
> best_match
)
921 if (best_match
> strlen(var
))
924 * Found a match longer than the make...
927 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
932 cgiCopyTemplateLang("choose-model.tmpl");
941 cgiShowIPPError(_("Unable to get list of printer drivers:"));
942 cgiCopyTemplateLang("error.tmpl");
949 * Build a CUPS_ADD_PRINTER request, which requires the following
953 * attributes-natural-language
959 * printer-is-accepting-jobs
963 request
= ippNewRequest(CUPS_ADD_PRINTER
);
965 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
966 "localhost", 0, "/printers/%s",
967 cgiGetVariable("PRINTER_NAME"));
968 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
971 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
972 NULL
, cgiGetVariable("PRINTER_LOCATION"));
974 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
975 NULL
, cgiGetVariable("PRINTER_INFO"));
978 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
979 NULL
, cgiGetVariable("PPD_NAME"));
981 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
984 * Strip make and model from URI...
987 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
990 if (!strncmp(uri
, "serial:", 7))
993 * Update serial port URI to include baud rate, etc.
996 if ((uriptr
= strchr(uri
, '?')) == NULL
)
997 uriptr
= uri
+ strlen(uri
);
999 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1000 "?baud=%s+bits=%s+parity=%s+flow=%s",
1001 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1002 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1005 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1008 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1010 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1014 * Do the request and get back a response...
1018 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1020 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1022 if (cupsLastError() > IPP_OK_CONFLICT
)
1024 cgiStartHTML(title
);
1025 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1026 _("Unable to add printer:"));
1031 * Redirect successful updates back to the printer or set-options pages...
1034 char refresh
[1024]; /* Refresh URL */
1037 cgiFormEncode(uri
, name
, sizeof(uri
));
1040 snprintf(refresh
, sizeof(refresh
),
1041 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1043 snprintf(refresh
, sizeof(refresh
),
1044 "5;/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1046 cgiSetVariable("refresh_page", refresh
);
1048 cgiStartHTML(title
);
1051 cgiCopyTemplateLang("printer-modified.tmpl");
1053 cgiCopyTemplateLang("printer-added.tmpl");
1065 * 'do_config_printer()' - Configure the default options for a printer.
1069 do_config_printer(http_t
*http
) /* I - HTTP connection */
1071 int i
, j
, k
, m
; /* Looping vars */
1072 int have_options
; /* Have options? */
1073 ipp_t
*request
, /* IPP request */
1074 *response
; /* IPP response */
1075 ipp_attribute_t
*attr
; /* IPP attribute */
1076 char uri
[HTTP_MAX_URI
]; /* Job URI */
1077 const char *var
; /* Variable value */
1078 const char *printer
; /* Printer printer name */
1079 const char *filename
; /* PPD filename */
1080 char tempfile
[1024]; /* Temporary filename */
1081 cups_file_t
*in
, /* Input file */
1082 *out
; /* Output file */
1083 char line
[1024]; /* Line from PPD file */
1084 char keyword
[1024], /* Keyword from Default line */
1085 *keyptr
; /* Pointer into keyword... */
1086 ppd_file_t
*ppd
; /* PPD file */
1087 ppd_group_t
*group
; /* Option group */
1088 ppd_option_t
*option
; /* Option */
1089 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
1090 const char *title
; /* Page title */
1093 title
= cgiText(_("Set Printer Options"));
1095 fprintf(stderr
, "DEBUG: do_config_printer(http=%p)\n", http
);
1098 * Get the printer name...
1101 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1102 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1103 "localhost", 0, "/printers/%s", printer
);
1106 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1107 cgiStartHTML(title
);
1108 cgiCopyTemplateLang("error.tmpl");
1113 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
1116 * Get the PPD file...
1119 if ((filename
= cupsGetPPD2(http
, printer
)) == NULL
)
1121 fputs("DEBUG: No PPD file!?!\n", stderr
);
1123 cgiStartHTML(title
);
1124 cgiShowIPPError(_("Unable to get PPD file!"));
1129 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
1131 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
1133 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
1134 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1135 cgiStartHTML(title
);
1136 cgiCopyTemplateLang("error.tmpl");
1141 if (cgiGetVariable("job_sheets_start") != NULL
||
1142 cgiGetVariable("job_sheets_end") != NULL
)
1147 ppdMarkDefaults(ppd
);
1149 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1150 "<UL>\n", ppd
->num_groups
));
1152 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
1154 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
1156 for (j
= group
->num_options
, option
= group
->options
;
1159 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
1161 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
1163 ppdMarkOption(ppd
, option
->keyword
, var
);
1167 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
1170 DEBUG_puts("</UL></LI>");
1173 DEBUG_printf(("</UL>\n"
1174 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
1176 if (!have_options
|| ppdConflicts(ppd
))
1179 * Show the options to the user...
1182 fputs("DEBUG: Showing options...\n", stderr
);
1186 cgiStartHTML(cgiText(_("Set Printer Options")));
1187 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1189 if (ppdConflicts(ppd
))
1191 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
1194 for (j
= group
->num_options
, option
= group
->options
;
1197 if (option
->conflicted
)
1199 cgiSetArray("ckeyword", k
, option
->keyword
);
1200 cgiSetArray("ckeytext", k
, option
->text
);
1204 cgiCopyTemplateLang("option-conflict.tmpl");
1207 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1211 if (!strcmp(group
->name
, "InstallableOptions"))
1212 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
1214 cgiSetVariable("GROUP", group
->text
);
1216 cgiCopyTemplateLang("option-header.tmpl");
1218 for (j
= group
->num_options
, option
= group
->options
;
1222 if (!strcmp(option
->keyword
, "PageRegion"))
1225 cgiSetVariable("KEYWORD", option
->keyword
);
1226 cgiSetVariable("KEYTEXT", option
->text
);
1228 if (option
->conflicted
)
1229 cgiSetVariable("CONFLICTED", "1");
1231 cgiSetVariable("CONFLICTED", "0");
1233 cgiSetSize("CHOICES", 0);
1234 cgiSetSize("TEXT", 0);
1235 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
1238 * Hide custom option values...
1241 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
1244 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
1245 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
1249 if (option
->choices
[k
].marked
)
1250 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
1255 case PPD_UI_BOOLEAN
:
1256 cgiCopyTemplateLang("option-boolean.tmpl");
1258 case PPD_UI_PICKONE
:
1259 cgiCopyTemplateLang("option-pickone.tmpl");
1261 case PPD_UI_PICKMANY
:
1262 cgiCopyTemplateLang("option-pickmany.tmpl");
1267 cgiCopyTemplateLang("option-trailer.tmpl");
1271 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1272 * following attributes:
1274 * attributes-charset
1275 * attributes-natural-language
1279 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
1281 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1282 "localhost", 0, "/printers/%s", printer
);
1283 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1287 * Do the request and get back a response...
1290 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1292 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
1293 IPP_TAG_ZERO
)) != NULL
)
1296 * Add the job sheets options...
1299 cgiSetVariable("GROUP", cgiText(_("Banners")));
1300 cgiCopyTemplateLang("option-header.tmpl");
1302 cgiSetSize("CHOICES", attr
->num_values
);
1303 cgiSetSize("TEXT", attr
->num_values
);
1304 for (k
= 0; k
< attr
->num_values
; k
++)
1306 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1307 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1310 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
1312 cgiSetVariable("KEYWORD", "job_sheets_start");
1313 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
1314 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1315 "" : attr
->values
[0].string
.text
);
1317 cgiCopyTemplateLang("option-pickone.tmpl");
1319 cgiSetVariable("KEYWORD", "job_sheets_end");
1320 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
1321 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
1322 "" : attr
->values
[1].string
.text
);
1324 cgiCopyTemplateLang("option-pickone.tmpl");
1326 cgiCopyTemplateLang("option-trailer.tmpl");
1329 if (ippFindAttribute(response
, "printer-error-policy-supported",
1331 ippFindAttribute(response
, "printer-op-policy-supported",
1335 * Add the error and operation policy options...
1338 cgiSetVariable("GROUP", cgiText(_("Policies")));
1339 cgiCopyTemplateLang("option-header.tmpl");
1345 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
1350 cgiSetSize("CHOICES", attr
->num_values
);
1351 cgiSetSize("TEXT", attr
->num_values
);
1352 for (k
= 0; k
< attr
->num_values
; k
++)
1354 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1355 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1358 attr
= ippFindAttribute(response
, "printer-error-policy",
1361 cgiSetVariable("KEYWORD", "printer_error_policy");
1362 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
1363 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1364 "" : attr
->values
[0].string
.text
);
1367 cgiCopyTemplateLang("option-pickone.tmpl");
1370 * Operation policy...
1373 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
1378 cgiSetSize("CHOICES", attr
->num_values
);
1379 cgiSetSize("TEXT", attr
->num_values
);
1380 for (k
= 0; k
< attr
->num_values
; k
++)
1382 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1383 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1386 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
1388 cgiSetVariable("KEYWORD", "printer_op_policy");
1389 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
1390 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1391 "" : attr
->values
[0].string
.text
);
1393 cgiCopyTemplateLang("option-pickone.tmpl");
1396 cgiCopyTemplateLang("option-trailer.tmpl");
1399 ippDelete(response
);
1403 * Binary protocol support...
1406 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
1408 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
1410 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
1411 cgiCopyTemplateLang("option-header.tmpl");
1413 cgiSetSize("CHOICES", 2);
1414 cgiSetSize("TEXT", 2);
1415 cgiSetArray("CHOICES", 0, "None");
1416 cgiSetArray("TEXT", 0, cgiText(_("None")));
1418 if (strstr(ppd
->protocols
, "TBCP"))
1420 cgiSetArray("CHOICES", 1, "TBCP");
1421 cgiSetArray("TEXT", 1, "TBCP");
1425 cgiSetArray("CHOICES", 1, "BCP");
1426 cgiSetArray("TEXT", 1, "BCP");
1429 cgiSetVariable("KEYWORD", "protocol");
1430 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
1431 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
1433 cgiCopyTemplateLang("option-pickone.tmpl");
1435 cgiCopyTemplateLang("option-trailer.tmpl");
1438 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1444 * Set default options...
1447 fputs("DEBUG: Setting options...\n", stderr
);
1449 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
1450 in
= cupsFileOpen(filename
, "r");
1454 cgiSetVariable("ERROR", strerror(errno
));
1455 cgiStartHTML(cgiText(_("Set Printer Options")));
1456 cgiCopyTemplateLang("error.tmpl");
1472 while (cupsFileGets(in
, line
, sizeof(line
)))
1474 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1476 else if (strncmp(line
, "*Default", 8))
1477 cupsFilePrintf(out
, "%s\n", line
);
1481 * Get default option name...
1484 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
1486 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1487 if (*keyptr
== ':' || isspace(*keyptr
& 255))
1492 if (!strcmp(keyword
, "PageRegion"))
1493 var
= cgiGetVariable("PageSize");
1495 var
= cgiGetVariable(keyword
);
1498 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
1500 cupsFilePrintf(out
, "%s\n", line
);
1504 if ((var
= cgiGetVariable("protocol")) != NULL
)
1505 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1511 * Build a CUPS_ADD_PRINTER request, which requires the following
1514 * attributes-charset
1515 * attributes-natural-language
1517 * job-sheets-default
1521 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1523 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1524 "localhost", 0, "/printers/%s",
1525 cgiGetVariable("PRINTER_NAME"));
1526 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1529 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1530 "job-sheets-default", 2, NULL
, NULL
);
1531 attr
->values
[0].string
.text
= strdup(cgiGetVariable("job_sheets_start"));
1532 attr
->values
[1].string
.text
= strdup(cgiGetVariable("job_sheets_end"));
1534 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
1535 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1536 "printer-error-policy", NULL
, var
);
1538 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
1539 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1540 "printer-op-policy", NULL
, var
);
1543 * Do the request and get back a response...
1546 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
1548 if (cupsLastError() > IPP_OK_CONFLICT
)
1550 cgiStartHTML(title
);
1551 cgiShowIPPError(_("Unable to set options:"));
1556 * Redirect successful updates back to the printer page...
1559 char refresh
[1024]; /* Refresh URL */
1562 cgiFormEncode(uri
, printer
, sizeof(uri
));
1563 snprintf(refresh
, sizeof(refresh
),
1564 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1565 cgiSetVariable("refresh_page", refresh
);
1567 cgiStartHTML(title
);
1569 cgiCopyTemplateLang("printer-configured.tmpl");
1582 * 'do_config_server()' - Configure server settings.
1586 do_config_server(http_t
*http
) /* I - HTTP connection */
1588 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1591 * Save basic setting changes...
1594 int num_settings
; /* Number of server settings */
1595 cups_option_t
*settings
; /* Server settings */
1599 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1600 cgiGetVariable("DEBUG_LOGGING") ? "1" : "0",
1601 num_settings
, &settings
);
1602 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1603 cgiGetVariable("REMOTE_ADMIN") ? "1" : "0",
1604 num_settings
, &settings
);
1605 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1606 cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0",
1607 num_settings
, &settings
);
1608 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1609 cgiGetVariable("SHARE_PRINTERS") ? "1" : "0",
1610 num_settings
, &settings
);
1611 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1612 cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0",
1613 num_settings
, &settings
);
1616 if (!_cupsAdminSetServerSettings(http
, num_settings
, settings
))
1618 cgiStartHTML(cgiText(_("Change Settings")));
1619 cgiSetVariable("MESSAGE",
1620 cgiText(_("Unable to change server settings:")));
1621 cgiSetVariable("ERROR", cupsLastErrorString());
1622 cgiCopyTemplateLang("error.tmpl");
1626 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1627 cgiStartHTML(cgiText(_("Change Settings")));
1628 cgiCopyTemplateLang("restart.tmpl");
1631 cupsFreeOptions(num_settings
, settings
);
1635 else if (cgiIsPOST())
1638 * Save hand-edited config file...
1641 http_status_t status
; /* PUT status */
1642 char tempfile
[1024]; /* Temporary new cupsd.conf */
1643 int tempfd
; /* Temporary file descriptor */
1644 cups_file_t
*temp
; /* Temporary file */
1645 const char *start
, /* Start of line */
1646 *end
; /* End of line */
1650 * Create a temporary file for the new cupsd.conf file...
1653 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1655 cgiStartHTML(cgiText(_("Edit Configuration File")));
1656 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1657 cgiSetVariable("ERROR", strerror(errno
));
1658 cgiCopyTemplateLang("error.tmpl");
1665 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1667 cgiStartHTML(cgiText(_("Edit Configuration File")));
1668 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1669 cgiSetVariable("ERROR", strerror(errno
));
1670 cgiCopyTemplateLang("error.tmpl");
1680 * Copy the cupsd.conf text from the form variable...
1683 start
= cgiGetVariable("CUPSDCONF");
1686 if ((end
= strstr(start
, "\r\n")) == NULL
)
1687 if ((end
= strstr(start
, "\n")) == NULL
)
1688 end
= start
+ strlen(start
);
1690 cupsFileWrite(temp
, start
, end
- start
);
1691 cupsFilePutChar(temp
, '\n');
1695 else if (*end
== '\n')
1701 cupsFileClose(temp
);
1704 * Upload the configuration file to the server...
1707 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1709 if (status
!= HTTP_CREATED
)
1711 cgiSetVariable("MESSAGE",
1712 cgiText(_("Unable to upload cupsd.conf file:")));
1713 cgiSetVariable("ERROR", httpStatus(status
));
1715 cgiStartHTML(cgiText(_("Edit Configuration File")));
1716 cgiCopyTemplateLang("error.tmpl");
1720 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
1722 cgiStartHTML(cgiText(_("Edit Configuration File")));
1723 cgiCopyTemplateLang("restart.tmpl");
1732 struct stat info
; /* cupsd.conf information */
1733 cups_file_t
*cupsd
; /* cupsd.conf file */
1734 char *buffer
; /* Buffer for entire file */
1735 char filename
[1024]; /* Filename */
1736 const char *server_root
; /* Location of config files */
1740 * Locate the cupsd.conf file...
1743 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1744 server_root
= CUPS_SERVERROOT
;
1746 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1749 * Figure out the size...
1752 if (stat(filename
, &info
))
1754 cgiStartHTML(cgiText(_("Edit Configuration File")));
1755 cgiSetVariable("MESSAGE",
1756 cgiText(_("Unable to access cupsd.conf file:")));
1757 cgiSetVariable("ERROR", strerror(errno
));
1758 cgiCopyTemplateLang("error.tmpl");
1765 if (info
.st_size
> (1024 * 1024))
1767 cgiStartHTML(cgiText(_("Edit Configuration File")));
1768 cgiSetVariable("MESSAGE",
1769 cgiText(_("Unable to access cupsd.conf file:")));
1770 cgiSetVariable("ERROR",
1771 cgiText(_("Unable to edit cupsd.conf files larger than "
1773 cgiCopyTemplateLang("error.tmpl");
1776 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1777 (long)info
.st_size
);
1782 * Open the cupsd.conf file...
1785 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1788 * Unable to open - log an error...
1791 cgiStartHTML(cgiText(_("Edit Configuration File")));
1792 cgiSetVariable("MESSAGE",
1793 cgiText(_("Unable to access cupsd.conf file:")));
1794 cgiSetVariable("ERROR", strerror(errno
));
1795 cgiCopyTemplateLang("error.tmpl");
1803 * Allocate memory and load the file into a string buffer...
1806 buffer
= calloc(1, info
.st_size
+ 1);
1808 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1809 cupsFileClose(cupsd
);
1811 cgiSetVariable("CUPSDCONF", buffer
);
1815 * Show the current config file...
1818 cgiStartHTML(cgiText(_("Edit Configuration File")));
1820 printf("<!-- \"%s\" -->\n", filename
);
1822 cgiCopyTemplateLang("edit-config.tmpl");
1830 * 'do_delete_class()' - Delete a class...
1834 do_delete_class(http_t
*http
) /* I - HTTP connection */
1836 ipp_t
*request
; /* IPP request */
1837 char uri
[HTTP_MAX_URI
]; /* Job URI */
1838 const char *pclass
; /* Printer class name */
1842 * Get form variables...
1845 if (cgiGetVariable("CONFIRM") == NULL
)
1847 cgiStartHTML(cgiText(_("Delete Class")));
1848 cgiCopyTemplateLang("class-confirm.tmpl");
1853 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1854 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1855 "localhost", 0, "/classes/%s", pclass
);
1858 cgiStartHTML(cgiText(_("Delete Class")));
1859 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1860 cgiCopyTemplateLang("error.tmpl");
1866 * Build a CUPS_DELETE_CLASS request, which requires the following
1869 * attributes-charset
1870 * attributes-natural-language
1874 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1876 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1880 * Do the request and get back a response...
1883 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1886 * Show the results...
1889 cgiStartHTML(cgiText(_("Delete Class")));
1891 if (cupsLastError() > IPP_OK_CONFLICT
)
1892 cgiShowIPPError(_("Unable to delete class:"));
1894 cgiCopyTemplateLang("class-deleted.tmpl");
1901 * 'do_delete_printer()' - Delete a printer...
1905 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1907 ipp_t
*request
; /* IPP request */
1908 char uri
[HTTP_MAX_URI
]; /* Job URI */
1909 const char *printer
; /* Printer printer name */
1913 * Get form variables...
1916 if (cgiGetVariable("CONFIRM") == NULL
)
1918 cgiStartHTML(cgiText(_("Delete Printer")));
1919 cgiCopyTemplateLang("printer-confirm.tmpl");
1924 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1925 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1926 "localhost", 0, "/printers/%s", printer
);
1929 cgiStartHTML(cgiText(_("Delete Printer")));
1930 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1931 cgiCopyTemplateLang("error.tmpl");
1937 * Build a CUPS_DELETE_PRINTER request, which requires the following
1940 * attributes-charset
1941 * attributes-natural-language
1945 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
1947 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1951 * Do the request and get back a response...
1954 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1957 * Show the results...
1960 cgiStartHTML(cgiText(_("Delete Printer")));
1962 if (cupsLastError() > IPP_OK_CONFLICT
)
1963 cgiShowIPPError(_("Unable to delete printer:"));
1965 cgiCopyTemplateLang("printer-deleted.tmpl");
1972 * 'do_export()' - Export printers to Samba...
1976 do_export(http_t
*http
) /* I - HTTP connection */
1978 int i
, j
; /* Looping vars */
1979 ipp_t
*request
, /* IPP request */
1980 *response
; /* IPP response */
1981 const char *username
, /* Samba username */
1982 *password
, /* Samba password */
1983 *export_all
; /* Export all printers? */
1984 int export_count
, /* Number of printers to export */
1985 printer_count
; /* Number of available printers */
1986 const char *name
, /* What name to pull */
1987 *dest
; /* Current destination */
1988 char ppd
[1024]; /* PPD file */
1995 username
= cgiGetVariable("USERNAME");
1996 password
= cgiGetVariable("PASSWORD");
1997 export_all
= cgiGetVariable("EXPORT_ALL");
1998 export_count
= cgiGetSize("EXPORT_NAME");
2001 * Get list of available printers...
2004 cgiSetSize("PRINTER_NAME", 0);
2005 cgiSetSize("PRINTER_EXPORT", 0);
2007 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2009 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2012 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2013 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2014 CUPS_PRINTER_IMPLICIT
);
2016 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2017 "requested-attributes", NULL
, "printer-name");
2019 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2021 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2022 ippDelete(response
);
2026 printer_count
= cgiGetSize("PRINTER_NAME");
2028 for (i
= 0; i
< printer_count
; i
++)
2030 dest
= cgiGetArray("PRINTER_NAME", i
);
2032 for (j
= 0; j
< export_count
; j
++)
2033 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2036 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2042 * Export or get the printers to export...
2045 if (username
&& *username
&& password
&& *password
&&
2046 (export_all
|| export_count
> 0))
2052 fputs("DEBUG: Export printers...\n", stderr
);
2056 name
= "PRINTER_NAME";
2057 export_count
= cgiGetSize("PRINTER_NAME");
2060 name
= "EXPORT_NAME";
2062 for (i
= 0; i
< export_count
; i
++)
2064 dest
= cgiGetArray(name
, i
);
2066 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2069 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2078 if (i
< export_count
)
2079 cgiSetVariable("ERROR", cupsLastErrorString());
2082 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2083 cgiCopyTemplateLang("samba-exported.tmpl");
2088 else if (username
&& !*username
)
2089 cgiSetVariable("ERROR",
2090 cgiText(_("A Samba username is required to export "
2091 "printer drivers!")));
2092 else if (username
&& (!password
|| !*password
))
2093 cgiSetVariable("ERROR",
2094 cgiText(_("A Samba password is required to export "
2095 "printer drivers!")));
2101 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2102 cgiCopyTemplateLang("samba-export.tmpl");
2108 * 'do_menu()' - Show the main menu...
2112 do_menu(http_t
*http
) /* I - HTTP connection */
2114 int num_settings
; /* Number of server settings */
2115 cups_option_t
*settings
; /* Server settings */
2116 const char *val
; /* Setting value */
2117 char filename
[1024]; /* Temporary filename */
2118 const char *datadir
; /* Location of data files */
2119 ipp_t
*request
, /* IPP request */
2120 *response
; /* IPP response */
2121 ipp_attribute_t
*attr
; /* IPP attribute */
2125 * Get the current server settings...
2128 if (!_cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2130 cgiSetVariable("SETTINGS_MESSAGE",
2131 cgiText(_("Unable to open cupsd.conf file:")));
2132 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2135 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2136 settings
)) != NULL
&& atoi(val
))
2137 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2139 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2140 settings
)) != NULL
&& atoi(val
))
2141 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2143 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2144 settings
)) != NULL
&& atoi(val
))
2145 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2147 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2148 settings
)) != NULL
&& atoi(val
))
2149 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2151 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2152 settings
)) != NULL
&& atoi(val
))
2153 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2155 cupsFreeOptions(num_settings
, settings
);
2158 * Get the list of printers and their devices...
2161 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2163 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2164 "requested-attributes", NULL
, "device-uri");
2166 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2167 CUPS_PRINTER_LOCAL
);
2168 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2169 CUPS_PRINTER_LOCAL
);
2171 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2174 * Got the printer list, now load the devices...
2177 int i
; /* Looping var */
2178 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2179 char *printer_device
; /* Current printer device */
2183 * Allocate an array and copy the device strings...
2186 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2188 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2190 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2192 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2196 * Free the printer list and get the device list...
2199 ippDelete(response
);
2201 request
= ippNewRequest(CUPS_GET_DEVICES
);
2203 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2206 * Got the device list, let's parse it...
2209 const char *device_uri
, /* device-uri attribute value */
2210 *device_make_and_model
, /* device-make-and-model value */
2211 *device_info
; /* device-info value */
2214 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2217 * Skip leading attributes until we hit a device...
2220 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2227 * Pull the needed attributes from this device...
2231 device_make_and_model
= NULL
;
2234 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2236 if (!strcmp(attr
->name
, "device-info") &&
2237 attr
->value_tag
== IPP_TAG_TEXT
)
2238 device_info
= attr
->values
[0].string
.text
;
2240 if (!strcmp(attr
->name
, "device-make-and-model") &&
2241 attr
->value_tag
== IPP_TAG_TEXT
)
2242 device_make_and_model
= attr
->values
[0].string
.text
;
2244 if (!strcmp(attr
->name
, "device-uri") &&
2245 attr
->value_tag
== IPP_TAG_URI
)
2246 device_uri
= attr
->values
[0].string
.text
;
2252 * See if we have everything needed...
2255 if (device_info
&& device_make_and_model
&& device_uri
&&
2256 strcasecmp(device_make_and_model
, "unknown") &&
2257 strchr(device_uri
, ':'))
2260 * Yes, now see if there is already a printer for this
2264 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2267 * Not found, so it must be a new printer...
2270 char options
[1024], /* Form variables for this device */
2271 *options_ptr
; /* Pointer into string */
2272 const char *ptr
; /* Pointer into device string */
2276 * Format the printer name variable for this device...
2278 * We use the device-info string first, then device-uri,
2279 * and finally device-make-and-model to come up with a
2283 strcpy(options
, "PRINTER_NAME=");
2284 options_ptr
= options
+ strlen(options
);
2286 if (strncasecmp(device_info
, "unknown", 7))
2288 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2291 ptr
= device_make_and_model
;
2294 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2296 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2298 *options_ptr
++ = *ptr
;
2299 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2300 *options_ptr
++ = '_';
2301 else if (*ptr
== '?' || *ptr
== '(')
2305 * Then add the make and model in the printer info, so
2306 * that MacOS clients see something reasonable...
2309 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2311 sizeof(options
) - (options_ptr
- options
));
2312 options_ptr
+= strlen(options_ptr
);
2314 cgiFormEncode(options_ptr
, device_make_and_model
,
2315 sizeof(options
) - (options_ptr
- options
));
2316 options_ptr
+= strlen(options_ptr
);
2319 * Then copy the device URI...
2322 strlcpy(options_ptr
, "&DEVICE_URI=",
2323 sizeof(options
) - (options_ptr
- options
));
2324 options_ptr
+= strlen(options_ptr
);
2326 cgiFormEncode(options_ptr
, device_uri
,
2327 sizeof(options
) - (options_ptr
- options
));
2328 options_ptr
+= strlen(options_ptr
);
2330 if (options_ptr
< (options
+ sizeof(options
) - 1))
2332 *options_ptr
++ = '|';
2333 cgiFormEncode(options_ptr
, device_make_and_model
,
2334 sizeof(options
) - (options_ptr
- options
));
2338 * Finally, set the form variables for this printer...
2341 cgiSetArray("device_info", i
, device_info
);
2342 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2343 cgiSetArray("device_options", i
, options
);
2344 cgiSetArray("device_uri", i
, device_uri
);
2353 ippDelete(response
);
2356 * Free the device list...
2359 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2361 printer_device
= (char *)cupsArrayNext(printer_devices
))
2362 free(printer_device
);
2364 cupsArrayDelete(printer_devices
);
2369 * See if Samba and the Windows drivers are installed...
2372 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2373 datadir
= CUPS_DATADIR
;
2375 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2376 if (!access(filename
, R_OK
))
2379 * Found Windows 2000 driver file, see if we have smbclient and
2383 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2384 sizeof(filename
)) &&
2385 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2387 cgiSetVariable("HAVE_SAMBA", "Y");
2390 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2392 fputs("ERROR: smbclient not found!\n", stderr
);
2394 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2396 fputs("ERROR: rpcclient not found!\n", stderr
);
2403 * Finally, show the main menu template...
2406 cgiStartHTML(cgiText(_("Administration")));
2408 cgiCopyTemplateLang("admin.tmpl");
2415 * 'do_printer_op()' - Do a printer operation.
2419 do_printer_op(http_t
*http
, /* I - HTTP connection */
2420 ipp_op_t op
, /* I - Operation to perform */
2421 const char *title
) /* I - Title of page */
2423 ipp_t
*request
; /* IPP request */
2424 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2425 const char *printer
, /* Printer name (purge-jobs) */
2426 *is_class
; /* Is a class? */
2429 is_class
= cgiGetVariable("IS_CLASS");
2430 printer
= cgiGetVariable("PRINTER_NAME");
2434 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2435 cgiStartHTML(title
);
2436 cgiCopyTemplateLang("error.tmpl");
2442 * Build a printer request, which requires the following
2445 * attributes-charset
2446 * attributes-natural-language
2450 request
= ippNewRequest(op
);
2452 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2453 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2455 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2459 * Do the request and get back a response...
2462 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2464 if (cupsLastError() > IPP_OK_CONFLICT
)
2466 cgiStartHTML(title
);
2467 cgiShowIPPError(_("Unable to change printer:"));
2472 * Redirect successful updates back to the printer page...
2475 char url
[1024], /* Printer/class URL */
2476 refresh
[1024]; /* Refresh URL */
2479 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2480 cgiFormEncode(uri
, url
, sizeof(uri
));
2481 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2482 cgiSetVariable("refresh_page", refresh
);
2484 cgiStartHTML(title
);
2486 if (op
== IPP_PAUSE_PRINTER
)
2487 cgiCopyTemplateLang("printer-stop.tmpl");
2488 else if (op
== IPP_RESUME_PRINTER
)
2489 cgiCopyTemplateLang("printer-start.tmpl");
2490 else if (op
== CUPS_ACCEPT_JOBS
)
2491 cgiCopyTemplateLang("printer-accept.tmpl");
2492 else if (op
== CUPS_REJECT_JOBS
)
2493 cgiCopyTemplateLang("printer-reject.tmpl");
2494 else if (op
== IPP_PURGE_JOBS
)
2495 cgiCopyTemplateLang("printer-purge.tmpl");
2496 else if (op
== CUPS_SET_DEFAULT
)
2497 cgiCopyTemplateLang("printer-default.tmpl");
2505 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2509 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2511 int i
; /* Looping var */
2512 ipp_t
*request
, /* IPP request */
2513 *response
; /* IPP response */
2514 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2515 const char *printer
, /* Printer name (purge-jobs) */
2516 *is_class
, /* Is a class? */
2517 *users
, /* List of users or groups */
2518 *type
; /* Allow/deny type */
2519 int num_users
; /* Number of users */
2520 char *ptr
, /* Pointer into users string */
2521 *end
, /* Pointer to end of users string */
2522 quote
; /* Quote character */
2523 ipp_attribute_t
*attr
; /* Attribute */
2524 static const char * const attrs
[] = /* Requested attributes */
2526 "requesting-user-name-allowed",
2527 "requesting-user-name-denied"
2531 is_class
= cgiGetVariable("IS_CLASS");
2532 printer
= cgiGetVariable("PRINTER_NAME");
2536 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2537 cgiStartHTML(cgiText(_("Set Allowed Users")));
2538 cgiCopyTemplateLang("error.tmpl");
2543 users
= cgiGetVariable("users");
2544 type
= cgiGetVariable("type");
2546 if (!users
|| !type
||
2547 (strcmp(type
, "requesting-user-name-allowed") &&
2548 strcmp(type
, "requesting-user-name-denied")))
2551 * Build a Get-Printer-Attributes request, which requires the following
2554 * attributes-charset
2555 * attributes-natural-language
2557 * requested-attributes
2560 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2562 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2563 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2565 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2568 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2569 "requested-attributes",
2570 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2573 * Do the request and get back a response...
2576 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2578 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2580 ippDelete(response
);
2583 cgiStartHTML(cgiText(_("Set Allowed Users")));
2585 if (cupsLastError() > IPP_OK_CONFLICT
)
2586 cgiShowIPPError(_("Unable to get printer attributes:"));
2588 cgiCopyTemplateLang("users.tmpl");
2595 * Save the changes...
2598 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2601 * Skip whitespace and commas...
2604 while (*ptr
== ',' || isspace(*ptr
& 255))
2607 if (*ptr
== '\'' || *ptr
== '\"')
2610 * Scan quoted name...
2615 for (end
= ptr
; *end
; end
++)
2622 * Scan space or comma-delimited name...
2625 for (end
= ptr
; *end
; end
++)
2626 if (isspace(*end
& 255) || *end
== ',')
2631 * Advance to the next name...
2638 * Build a CUPS-Add-Printer/Class request, which requires the following
2641 * attributes-charset
2642 * attributes-natural-language
2644 * requesting-user-name-{allowed,denied}
2647 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2649 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2650 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2652 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2656 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2657 "requesting-user-name-allowed", NULL
, "all");
2660 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2661 type
, num_users
, NULL
, NULL
);
2663 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2666 * Skip whitespace and commas...
2669 while (*ptr
== ',' || isspace(*ptr
& 255))
2672 if (*ptr
== '\'' || *ptr
== '\"')
2675 * Scan quoted name...
2680 for (end
= ptr
; *end
; end
++)
2687 * Scan space or comma-delimited name...
2690 for (end
= ptr
; *end
; end
++)
2691 if (isspace(*end
& 255) || *end
== ',')
2696 * Terminate the name...
2706 attr
->values
[i
].string
.text
= strdup(ptr
);
2709 * Advance to the next name...
2717 * Do the request and get back a response...
2720 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2722 if (cupsLastError() > IPP_OK_CONFLICT
)
2724 cgiStartHTML(cgiText(_("Set Allowed Users")));
2725 cgiShowIPPError(_("Unable to change printer:"));
2730 * Redirect successful updates back to the printer page...
2733 char url
[1024], /* Printer/class URL */
2734 refresh
[1024]; /* Refresh URL */
2737 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2738 cgiFormEncode(uri
, url
, sizeof(uri
));
2739 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2740 cgiSetVariable("refresh_page", refresh
);
2742 cgiStartHTML(cgiText(_("Set Allowed Users")));
2744 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2745 "printer-modified.tmpl");
2754 * 'do_set_sharing()' - Set printer-is-shared value...
2758 do_set_sharing(http_t
*http
) /* I - HTTP connection */
2760 ipp_t
*request
, /* IPP request */
2761 *response
; /* IPP response */
2762 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2763 const char *printer
, /* Printer name */
2764 *is_class
, /* Is a class? */
2765 *shared
; /* Sharing value */
2768 is_class
= cgiGetVariable("IS_CLASS");
2769 printer
= cgiGetVariable("PRINTER_NAME");
2770 shared
= cgiGetVariable("SHARED");
2772 if (!printer
|| !shared
)
2774 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2775 cgiStartHTML(cgiText(_("Set Publishing")));
2776 cgiCopyTemplateLang("error.tmpl");
2782 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
2783 * following attributes:
2785 * attributes-charset
2786 * attributes-natural-language
2791 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2793 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2794 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2796 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2799 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
2802 * Do the request and get back a response...
2805 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
2807 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2809 ippDelete(response
);
2812 if (cupsLastError() > IPP_OK_CONFLICT
)
2814 cgiStartHTML(cgiText(_("Set Publishing")));
2815 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
2820 * Redirect successful updates back to the printer page...
2823 char url
[1024], /* Printer/class URL */
2824 refresh
[1024]; /* Refresh URL */
2827 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2828 cgiFormEncode(uri
, url
, sizeof(uri
));
2829 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
2830 cgiSetVariable("refresh_page", refresh
);
2832 cgiStartHTML(cgiText(_("Set Publishing")));
2833 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2834 "printer-modified.tmpl");
2842 * 'match_string()' - Return the number of matching characters.
2845 static int /* O - Number of matching characters */
2846 match_string(const char *a
, /* I - First string */
2847 const char *b
) /* I - Second string */
2849 int count
; /* Number of matching characters */
2853 * Loop through both strings until we hit the end of either or we find
2854 * a non-matching character. For the purposes of comparison, we ignore
2855 * whitespace and do a case-insensitive comparison so that we have a
2856 * better chance of finding a match...
2859 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
2862 * Skip leading whitespace characters...
2865 while (isspace(*a
& 255))
2868 while (isspace(*b
& 255))
2872 * Break out if we run out of characters...
2879 * Do a case-insensitive comparison of the next two chars...
2882 if (tolower(*a
& 255) != tolower(*b
& 255))
2891 * End of "$Id: admin.c 5425 2006-04-18 19:59:05Z mike $".