2 * "$Id: admin.c 5878 2006-08-24 15:55:42Z 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",
97 cupsServer() ? cupsServer() : "(null)");
98 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
99 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
103 fprintf(stderr
, "DEBUG: http=%p\n", http
);
106 * Set the web interface section...
109 cgiSetVariable("SECTION", "admin");
112 * See if we have form data...
115 if (!cgiInitialize())
118 * Nope, send the administration menu...
121 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
125 else if ((op
= cgiGetVariable("OP")) != NULL
)
128 * Do the operation...
131 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
133 if (!strcmp(op
, "redirect"))
135 const char *url
; /* Redirection URL... */
136 char prefix
[1024]; /* URL prefix */
140 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
141 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
143 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
144 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
146 if ((url
= cgiGetVariable("URL")) != NULL
)
147 printf("Location: %s%s\n\n", prefix
, url
);
149 printf("Location: %s/admin\n\n", prefix
);
151 else if (!strcmp(op
, "start-printer"))
152 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
153 else if (!strcmp(op
, "stop-printer"))
154 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
155 else if (!strcmp(op
, "start-class"))
156 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
157 else if (!strcmp(op
, "stop-class"))
158 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
159 else if (!strcmp(op
, "accept-jobs"))
160 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
161 else if (!strcmp(op
, "reject-jobs"))
162 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
163 else if (!strcmp(op
, "purge-jobs"))
164 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
165 else if (!strcmp(op
, "set-allowed-users"))
166 do_set_allowed_users(http
);
167 else if (!strcmp(op
, "set-as-default"))
168 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
169 else if (!strcmp(op
, "set-sharing"))
170 do_set_sharing(http
);
171 else if (!strcmp(op
, "add-class"))
172 do_am_class(http
, 0);
173 else if (!strcmp(op
, "add-printer"))
174 do_am_printer(http
, 0);
175 else if (!strcmp(op
, "modify-class"))
176 do_am_class(http
, 1);
177 else if (!strcmp(op
, "modify-printer"))
178 do_am_printer(http
, 1);
179 else if (!strcmp(op
, "delete-class"))
180 do_delete_class(http
);
181 else if (!strcmp(op
, "delete-printer"))
182 do_delete_printer(http
);
183 else if (!strcmp(op
, "set-printer-options"))
184 do_config_printer(http
);
185 else if (!strcmp(op
, "config-server"))
186 do_config_server(http
);
187 else if (!strcmp(op
, "export-samba"))
192 * Bad operation code... Display an error...
195 cgiStartHTML(cgiText(_("Administration")));
196 cgiCopyTemplateLang("error-op.tmpl");
203 * Form data but no operation code... Display an error...
206 cgiStartHTML(cgiText(_("Administration")));
207 cgiCopyTemplateLang("error-op.tmpl");
212 * Close the HTTP server connection...
218 * Return with no errors...
226 * 'do_am_class()' - Add or modify a class.
230 do_am_class(http_t
*http
, /* I - HTTP connection */
231 int modify
) /* I - Modify the printer? */
233 int i
, j
; /* Looping vars */
234 int element
; /* Element number */
235 int num_printers
; /* Number of printers */
236 ipp_t
*request
, /* IPP request */
237 *response
; /* IPP response */
238 ipp_attribute_t
*attr
; /* member-uris attribute */
239 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
240 const char *name
, /* Pointer to class name */
241 *ptr
; /* Pointer to CGI variable */
242 const char *title
; /* Title of page */
243 static const char * const pattrs
[] = /* Requested printer attributes */
251 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
252 name
= cgiGetVariable("PRINTER_NAME");
254 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
257 * Build a CUPS_GET_PRINTERS request, which requires the
258 * following attributes:
261 * attributes-natural-language
265 request
= ippNewRequest(CUPS_GET_PRINTERS
);
267 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
268 NULL
, "ipp://localhost/printers");
271 * Do the request and get back a response...
274 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
277 * Create MEMBER_URIS and MEMBER_NAMES arrays...
280 for (element
= 0, attr
= response
->attrs
;
283 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
285 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
286 (!name
|| strcasecmp(name
, ptr
+ 1)))
289 * Don't show the current class...
292 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
297 for (element
= 0, attr
= response
->attrs
;
300 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
302 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
305 * Don't show the current class...
308 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
313 num_printers
= cgiGetSize("MEMBER_URIS");
323 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
324 * following attributes:
327 * attributes-natural-language
331 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
333 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
334 "localhost", 0, "/classes/%s", name
);
335 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
338 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
339 "requested-attributes",
340 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
344 * Do the request and get back a response...
347 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
349 if ((attr
= ippFindAttribute(response
, "member-names",
350 IPP_TAG_NAME
)) != NULL
)
353 * Mark any current members in the class...
356 for (j
= 0; j
< num_printers
; j
++)
357 cgiSetArray("MEMBER_SELECTED", j
, "");
359 for (i
= 0; i
< attr
->num_values
; i
++)
361 for (j
= 0; j
< num_printers
; j
++)
363 if (!strcasecmp(attr
->values
[i
].string
.text
,
364 cgiGetArray("MEMBER_NAMES", j
)))
366 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
373 if ((attr
= ippFindAttribute(response
, "printer-info",
374 IPP_TAG_TEXT
)) != NULL
)
375 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
377 if ((attr
= ippFindAttribute(response
, "printer-location",
378 IPP_TAG_TEXT
)) != NULL
)
379 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
385 * Update the location and description of an existing printer...
389 cgiCopyTemplateLang("modify-class.tmpl");
394 * Get the name, location, and description for a new printer...
398 cgiCopyTemplateLang("add-class.tmpl");
406 for (ptr
= name
; *ptr
; ptr
++)
407 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
410 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
412 cgiSetVariable("ERROR",
413 cgiText(_("The class name may only contain up to "
414 "127 printable characters and may not "
415 "contain spaces, slashes (/), or the "
416 "pound sign (#).")));
418 cgiCopyTemplateLang("error.tmpl");
424 * Build a CUPS_ADD_CLASS request, which requires the following
428 * attributes-natural-language
432 * printer-is-accepting-jobs
437 request
= ippNewRequest(CUPS_ADD_CLASS
);
439 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
440 "localhost", 0, "/classes/%s",
441 cgiGetVariable("PRINTER_NAME"));
442 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
445 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
446 NULL
, cgiGetVariable("PRINTER_LOCATION"));
448 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
449 NULL
, cgiGetVariable("PRINTER_INFO"));
451 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
453 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
456 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
458 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
459 num_printers
, NULL
, NULL
);
460 for (i
= 0; i
< num_printers
; i
++)
461 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
465 * Do the request and get back a response...
468 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
470 if (cupsLastError() > IPP_OK_CONFLICT
)
473 cgiShowIPPError(modify
? _("Unable to modify class:") :
474 _("Unable to add class:"));
479 * Redirect successful updates back to the class page...
482 char refresh
[1024]; /* Refresh URL */
484 cgiFormEncode(uri
, name
, sizeof(uri
));
485 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
487 cgiSetVariable("refresh_page", refresh
);
492 cgiCopyTemplateLang("class-modified.tmpl");
494 cgiCopyTemplateLang("class-added.tmpl");
502 * 'do_am_printer()' - Add or modify a printer.
506 do_am_printer(http_t
*http
, /* I - HTTP connection */
507 int modify
) /* I - Modify the printer? */
509 int i
; /* Looping var */
510 ipp_attribute_t
*attr
; /* Current attribute */
511 ipp_t
*request
, /* IPP request */
512 *response
, /* IPP response */
513 *oldinfo
; /* Old printer information */
514 const cgi_file_t
*file
; /* Uploaded file, if any */
515 const char *var
; /* CGI variable */
516 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
517 *uriptr
; /* Pointer into URI */
518 int maxrate
; /* Maximum baud rate */
519 char baudrate
[255]; /* Baud rate string */
520 const char *name
, /* Pointer to class name */
521 *ptr
; /* Pointer to CGI variable */
522 const char *title
; /* Title of page */
523 static int baudrates
[] = /* Baud rates */
538 ptr
= cgiGetVariable("DEVICE_URI");
539 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
540 ptr
? ptr
: "(null)");
542 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
547 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
548 * following attributes:
551 * attributes-natural-language
555 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
557 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
558 "localhost", 0, "/printers/%s",
559 cgiGetVariable("PRINTER_NAME"));
560 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
564 * Do the request and get back a response...
567 oldinfo
= cupsDoRequest(http
, request
, "/");
572 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
573 cgiGetVariable("PRINTER_LOCATION") == NULL
)
580 * Update the location and description of an existing printer...
584 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
586 cgiCopyTemplateLang("modify-printer.tmpl");
591 * Get the name, location, and description for a new printer...
594 cgiCopyTemplateLang("add-printer.tmpl");
605 for (ptr
= name
; *ptr
; ptr
++)
606 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
609 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
611 cgiSetVariable("ERROR",
612 cgiText(_("The printer name may only contain up to "
613 "127 printable characters and may not "
614 "contain spaces, slashes (/), or the "
615 "pound sign (#).")));
617 cgiCopyTemplateLang("error.tmpl");
626 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
627 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
628 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
629 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
632 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
635 * Build a CUPS_GET_DEVICES request, which requires the following
639 * attributes-natural-language
643 fputs("DEBUG: Getting list of devices...\n", stderr
);
645 request
= ippNewRequest(CUPS_GET_DEVICES
);
647 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
648 NULL
, "ipp://localhost/printers/");
651 * Do the request and get back a response...
654 fprintf(stderr
, "DEBUG: http=%p (%s)\n", http
, http
->hostname
);
656 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
658 fputs("DEBUG: Got device list!\n", stderr
);
660 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
665 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
666 cupsLastError(), cupsLastErrorString());
669 * Let the user choose...
672 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
674 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
675 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
678 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
679 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
683 cgiCopyTemplateLang("choose-device.tmpl");
686 else if (strchr(var
, '/') == NULL
)
688 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
691 * Set the current device URI for the form to the old one...
694 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
695 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
699 * User needs to set the full URI...
703 cgiCopyTemplateLang("choose-uri.tmpl");
706 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
709 * Need baud rate, parity, etc.
712 if ((var
= strchr(var
, '?')) != NULL
&&
713 strncmp(var
, "?baud=", 6) == 0)
714 maxrate
= atoi(var
+ 6);
718 for (i
= 0; i
< 10; i
++)
719 if (baudrates
[i
] > maxrate
)
723 sprintf(baudrate
, "%d", baudrates
[i
]);
724 cgiSetArray("BAUDRATES", i
, baudrate
);
728 cgiCopyTemplateLang("choose-serial.tmpl");
731 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
736 * Get the PPD file...
739 int fd
; /* PPD file */
740 char filename
[1024]; /* PPD filename */
741 ppd_file_t
*ppd
; /* PPD information */
742 char buffer
[1024]; /* Buffer */
743 int bytes
; /* Number of bytes */
744 http_status_t get_status
; /* Status of GET */
747 /* TODO: Use cupsGetFile() API... */
748 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
750 if (httpGet(http
, uri
))
753 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
755 if (get_status
!= HTTP_OK
)
757 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
758 uri
, get_status
, httpStatus(get_status
));
760 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
762 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
763 write(fd
, buffer
, bytes
);
767 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
769 if (ppd
->manufacturer
)
770 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
773 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
780 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
781 filename
, ppdErrorString(ppdLastError(&bytes
)));
789 "ERROR: Unable to create temporary file for PPD file: %s\n",
793 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
796 * Extract make and make/model from device URI string...
799 char make
[1024], /* Make string */
800 *makeptr
; /* Pointer into make */
805 strlcpy(make
, uriptr
, sizeof(make
));
807 if ((makeptr
= strchr(make
, ' ')) != NULL
)
809 else if ((makeptr
= strchr(make
, '-')) != NULL
)
811 else if (!strncasecmp(make
, "laserjet", 8) ||
812 !strncasecmp(make
, "deskjet", 7) ||
813 !strncasecmp(make
, "designjet", 9))
815 else if (!strncasecmp(make
, "phaser", 6))
816 strcpy(make
, "Xerox");
817 else if (!strncasecmp(make
, "stylus", 6))
818 strcpy(make
, "Epson");
820 strcpy(make
, "Generic");
822 cgiSetVariable("CURRENT_MAKE", make
);
823 cgiSetVariable("PPD_MAKE", make
);
824 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
828 * Build a CUPS_GET_PPDS request, which requires the following
832 * attributes-natural-language
836 request
= ippNewRequest(CUPS_GET_PPDS
);
838 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
839 NULL
, "ipp://localhost/printers/");
841 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
842 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
843 "ppd-make", NULL
, var
);
845 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
846 "requested-attributes", NULL
, "ppd-make");
849 * Do the request and get back a response...
852 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
855 * Got the list of PPDs, see if the user has selected a make...
858 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
861 * No PPD files with this make, try again with all makes...
866 request
= ippNewRequest(CUPS_GET_PPDS
);
868 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
869 NULL
, "ipp://localhost/printers/");
871 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
872 "requested-attributes", NULL
, "ppd-make");
874 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
875 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
878 cgiCopyTemplateLang("choose-make.tmpl");
884 cgiCopyTemplateLang("choose-make.tmpl");
890 * Let the user choose a model...
893 const char *make_model
; /* Current make/model string */
896 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
899 * Scan for "close" matches...
902 int match
, /* Current match */
903 best_match
, /* Best match so far */
904 count
; /* Number of drivers */
905 const char *best
, /* Best matching string */
906 *current
; /* Current string */
909 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
911 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
913 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
914 match
= match_string(make_model
, current
);
916 if (match
> best_match
)
923 if (best_match
> strlen(var
))
926 * Found a match longer than the make...
929 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
934 cgiCopyTemplateLang("choose-model.tmpl");
943 cgiShowIPPError(_("Unable to get list of printer drivers:"));
944 cgiCopyTemplateLang("error.tmpl");
951 * Build a CUPS_ADD_PRINTER request, which requires the following
955 * attributes-natural-language
961 * printer-is-accepting-jobs
965 request
= ippNewRequest(CUPS_ADD_PRINTER
);
967 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
968 "localhost", 0, "/printers/%s",
969 cgiGetVariable("PRINTER_NAME"));
970 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
973 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
974 NULL
, cgiGetVariable("PRINTER_LOCATION"));
976 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
977 NULL
, cgiGetVariable("PRINTER_INFO"));
980 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
981 NULL
, cgiGetVariable("PPD_NAME"));
983 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
986 * Strip make and model from URI...
989 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
992 if (!strncmp(uri
, "serial:", 7))
995 * Update serial port URI to include baud rate, etc.
998 if ((uriptr
= strchr(uri
, '?')) == NULL
)
999 uriptr
= uri
+ strlen(uri
);
1001 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1002 "?baud=%s+bits=%s+parity=%s+flow=%s",
1003 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1004 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1007 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1010 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1012 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1016 * Do the request and get back a response...
1020 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1022 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1024 if (cupsLastError() > IPP_OK_CONFLICT
)
1026 cgiStartHTML(title
);
1027 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1028 _("Unable to add printer:"));
1033 * Redirect successful updates back to the printer or set-options pages...
1036 char refresh
[1024]; /* Refresh URL */
1039 cgiFormEncode(uri
, name
, sizeof(uri
));
1042 snprintf(refresh
, sizeof(refresh
),
1043 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1045 snprintf(refresh
, sizeof(refresh
),
1046 "5;URL=/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1048 cgiSetVariable("refresh_page", refresh
);
1050 cgiStartHTML(title
);
1053 cgiCopyTemplateLang("printer-modified.tmpl");
1055 cgiCopyTemplateLang("printer-added.tmpl");
1067 * 'do_config_printer()' - Configure the default options for a printer.
1071 do_config_printer(http_t
*http
) /* I - HTTP connection */
1073 int i
, j
, k
, m
; /* Looping vars */
1074 int have_options
; /* Have options? */
1075 ipp_t
*request
, /* IPP request */
1076 *response
; /* IPP response */
1077 ipp_attribute_t
*attr
; /* IPP attribute */
1078 char uri
[HTTP_MAX_URI
]; /* Job URI */
1079 const char *var
; /* Variable value */
1080 const char *printer
; /* Printer printer name */
1081 const char *filename
; /* PPD filename */
1082 char tempfile
[1024]; /* Temporary filename */
1083 cups_file_t
*in
, /* Input file */
1084 *out
; /* Output file */
1085 char line
[1024]; /* Line from PPD file */
1086 char keyword
[1024], /* Keyword from Default line */
1087 *keyptr
; /* Pointer into keyword... */
1088 ppd_file_t
*ppd
; /* PPD file */
1089 ppd_group_t
*group
; /* Option group */
1090 ppd_option_t
*option
; /* Option */
1091 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
1092 const char *title
; /* Page title */
1095 title
= cgiText(_("Set Printer Options"));
1097 fprintf(stderr
, "DEBUG: do_config_printer(http=%p)\n", http
);
1100 * Get the printer name...
1103 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1104 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1105 "localhost", 0, "/printers/%s", printer
);
1108 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1109 cgiStartHTML(title
);
1110 cgiCopyTemplateLang("error.tmpl");
1115 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
1118 * Get the PPD file...
1121 if ((filename
= cupsGetPPD2(http
, printer
)) == NULL
)
1123 fputs("DEBUG: No PPD file!?!\n", stderr
);
1125 cgiStartHTML(title
);
1126 cgiShowIPPError(_("Unable to get PPD file!"));
1131 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
1133 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
1135 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
1136 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1137 cgiStartHTML(title
);
1138 cgiCopyTemplateLang("error.tmpl");
1143 if (cgiGetVariable("job_sheets_start") != NULL
||
1144 cgiGetVariable("job_sheets_end") != NULL
)
1149 ppdMarkDefaults(ppd
);
1151 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1152 "<UL>\n", ppd
->num_groups
));
1154 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
1156 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
1158 for (j
= group
->num_options
, option
= group
->options
;
1161 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
1163 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
1165 ppdMarkOption(ppd
, option
->keyword
, var
);
1169 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
1172 DEBUG_puts("</UL></LI>");
1175 DEBUG_printf(("</UL>\n"
1176 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
1178 if (!have_options
|| ppdConflicts(ppd
))
1181 * Show the options to the user...
1184 fputs("DEBUG: Showing options...\n", stderr
);
1188 cgiStartHTML(cgiText(_("Set Printer Options")));
1189 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1191 if (ppdConflicts(ppd
))
1193 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
1196 for (j
= group
->num_options
, option
= group
->options
;
1199 if (option
->conflicted
)
1201 cgiSetArray("ckeyword", k
, option
->keyword
);
1202 cgiSetArray("ckeytext", k
, option
->text
);
1206 cgiCopyTemplateLang("option-conflict.tmpl");
1209 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1213 if (!strcmp(group
->name
, "InstallableOptions"))
1214 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
1216 cgiSetVariable("GROUP", group
->text
);
1218 cgiCopyTemplateLang("option-header.tmpl");
1220 for (j
= group
->num_options
, option
= group
->options
;
1224 if (!strcmp(option
->keyword
, "PageRegion"))
1227 cgiSetVariable("KEYWORD", option
->keyword
);
1228 cgiSetVariable("KEYTEXT", option
->text
);
1230 if (option
->conflicted
)
1231 cgiSetVariable("CONFLICTED", "1");
1233 cgiSetVariable("CONFLICTED", "0");
1235 cgiSetSize("CHOICES", 0);
1236 cgiSetSize("TEXT", 0);
1237 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
1240 * Hide custom option values...
1243 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
1246 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
1247 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
1251 if (option
->choices
[k
].marked
)
1252 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
1257 case PPD_UI_BOOLEAN
:
1258 cgiCopyTemplateLang("option-boolean.tmpl");
1260 case PPD_UI_PICKONE
:
1261 cgiCopyTemplateLang("option-pickone.tmpl");
1263 case PPD_UI_PICKMANY
:
1264 cgiCopyTemplateLang("option-pickmany.tmpl");
1269 cgiCopyTemplateLang("option-trailer.tmpl");
1273 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1274 * following attributes:
1276 * attributes-charset
1277 * attributes-natural-language
1281 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
1283 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1284 "localhost", 0, "/printers/%s", printer
);
1285 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1289 * Do the request and get back a response...
1292 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1294 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
1295 IPP_TAG_ZERO
)) != NULL
)
1298 * Add the job sheets options...
1301 cgiSetVariable("GROUP", cgiText(_("Banners")));
1302 cgiCopyTemplateLang("option-header.tmpl");
1304 cgiSetSize("CHOICES", attr
->num_values
);
1305 cgiSetSize("TEXT", attr
->num_values
);
1306 for (k
= 0; k
< attr
->num_values
; k
++)
1308 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1309 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1312 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
1314 cgiSetVariable("KEYWORD", "job_sheets_start");
1315 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
1316 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1317 "" : attr
->values
[0].string
.text
);
1319 cgiCopyTemplateLang("option-pickone.tmpl");
1321 cgiSetVariable("KEYWORD", "job_sheets_end");
1322 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
1323 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
1324 "" : attr
->values
[1].string
.text
);
1326 cgiCopyTemplateLang("option-pickone.tmpl");
1328 cgiCopyTemplateLang("option-trailer.tmpl");
1331 if (ippFindAttribute(response
, "printer-error-policy-supported",
1333 ippFindAttribute(response
, "printer-op-policy-supported",
1337 * Add the error and operation policy options...
1340 cgiSetVariable("GROUP", cgiText(_("Policies")));
1341 cgiCopyTemplateLang("option-header.tmpl");
1347 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
1352 cgiSetSize("CHOICES", attr
->num_values
);
1353 cgiSetSize("TEXT", attr
->num_values
);
1354 for (k
= 0; k
< attr
->num_values
; k
++)
1356 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1357 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1360 attr
= ippFindAttribute(response
, "printer-error-policy",
1363 cgiSetVariable("KEYWORD", "printer_error_policy");
1364 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
1365 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1366 "" : attr
->values
[0].string
.text
);
1369 cgiCopyTemplateLang("option-pickone.tmpl");
1372 * Operation policy...
1375 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
1380 cgiSetSize("CHOICES", attr
->num_values
);
1381 cgiSetSize("TEXT", attr
->num_values
);
1382 for (k
= 0; k
< attr
->num_values
; k
++)
1384 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1385 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1388 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
1390 cgiSetVariable("KEYWORD", "printer_op_policy");
1391 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
1392 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1393 "" : attr
->values
[0].string
.text
);
1395 cgiCopyTemplateLang("option-pickone.tmpl");
1398 cgiCopyTemplateLang("option-trailer.tmpl");
1401 ippDelete(response
);
1405 * Binary protocol support...
1408 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
1410 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
1412 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
1413 cgiCopyTemplateLang("option-header.tmpl");
1415 cgiSetSize("CHOICES", 2);
1416 cgiSetSize("TEXT", 2);
1417 cgiSetArray("CHOICES", 0, "None");
1418 cgiSetArray("TEXT", 0, cgiText(_("None")));
1420 if (strstr(ppd
->protocols
, "TBCP"))
1422 cgiSetArray("CHOICES", 1, "TBCP");
1423 cgiSetArray("TEXT", 1, "TBCP");
1427 cgiSetArray("CHOICES", 1, "BCP");
1428 cgiSetArray("TEXT", 1, "BCP");
1431 cgiSetVariable("KEYWORD", "protocol");
1432 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
1433 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
1435 cgiCopyTemplateLang("option-pickone.tmpl");
1437 cgiCopyTemplateLang("option-trailer.tmpl");
1440 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1446 * Set default options...
1449 fputs("DEBUG: Setting options...\n", stderr
);
1451 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
1452 in
= cupsFileOpen(filename
, "r");
1456 cgiSetVariable("ERROR", strerror(errno
));
1457 cgiStartHTML(cgiText(_("Set Printer Options")));
1458 cgiCopyTemplateLang("error.tmpl");
1474 while (cupsFileGets(in
, line
, sizeof(line
)))
1476 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1478 else if (strncmp(line
, "*Default", 8))
1479 cupsFilePrintf(out
, "%s\n", line
);
1483 * Get default option name...
1486 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
1488 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1489 if (*keyptr
== ':' || isspace(*keyptr
& 255))
1494 if (!strcmp(keyword
, "PageRegion") ||
1495 !strcmp(keyword
, "PaperDimension") ||
1496 !strcmp(keyword
, "ImageableArea"))
1497 var
= cgiGetVariable("PageSize");
1499 var
= cgiGetVariable(keyword
);
1502 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
1504 cupsFilePrintf(out
, "%s\n", line
);
1508 if ((var
= cgiGetVariable("protocol")) != NULL
)
1509 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1515 * Build a CUPS_ADD_PRINTER request, which requires the following
1518 * attributes-charset
1519 * attributes-natural-language
1521 * job-sheets-default
1525 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1527 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1528 "localhost", 0, "/printers/%s",
1529 cgiGetVariable("PRINTER_NAME"));
1530 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1533 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1534 "job-sheets-default", 2, NULL
, NULL
);
1535 attr
->values
[0].string
.text
= strdup(cgiGetVariable("job_sheets_start"));
1536 attr
->values
[1].string
.text
= strdup(cgiGetVariable("job_sheets_end"));
1538 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
1539 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1540 "printer-error-policy", NULL
, var
);
1542 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
1543 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1544 "printer-op-policy", NULL
, var
);
1547 * Do the request and get back a response...
1550 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
1552 if (cupsLastError() > IPP_OK_CONFLICT
)
1554 cgiStartHTML(title
);
1555 cgiShowIPPError(_("Unable to set options:"));
1560 * Redirect successful updates back to the printer page...
1563 char refresh
[1024]; /* Refresh URL */
1566 cgiFormEncode(uri
, printer
, sizeof(uri
));
1567 snprintf(refresh
, sizeof(refresh
),
1568 "5;URL=/admin/?OP=redirect&URL=/printers/%s", uri
);
1569 cgiSetVariable("refresh_page", refresh
);
1571 cgiStartHTML(title
);
1573 cgiCopyTemplateLang("printer-configured.tmpl");
1586 * 'do_config_server()' - Configure server settings.
1590 do_config_server(http_t
*http
) /* I - HTTP connection */
1592 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1595 * Save basic setting changes...
1598 int num_settings
; /* Number of server settings */
1599 cups_option_t
*settings
; /* Server settings */
1600 const char *debug_logging
, /* DEBUG_LOGGING value */
1601 *remote_admin
, /* REMOTE_ADMIN value */
1603 /* REMOTE_PRINTERS value */
1604 *share_printers
,/* SHARE_PRINTERS value */
1606 /* USER_CANCEL_ANY value */
1610 * Get the checkbox values from the form...
1613 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1614 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1615 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1616 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1617 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1620 * Get the current server settings...
1623 if (!_cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1625 cgiStartHTML(cgiText(_("Change Settings")));
1626 cgiSetVariable("MESSAGE",
1627 cgiText(_("Unable to change server settings:")));
1628 cgiSetVariable("ERROR", cupsLastErrorString());
1629 cgiCopyTemplateLang("error.tmpl");
1635 * See if the settings have changed...
1638 if (strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1639 num_settings
, settings
)) ||
1640 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1641 num_settings
, settings
)) ||
1642 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1643 num_settings
, settings
)) ||
1644 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1645 num_settings
, settings
)) ||
1646 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1647 num_settings
, settings
)))
1650 * Settings *have* changed, so save the changes...
1653 cupsFreeOptions(num_settings
, settings
);
1656 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1657 debug_logging
, num_settings
, &settings
);
1658 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1659 remote_admin
, num_settings
, &settings
);
1660 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1661 remote_printers
, num_settings
, &settings
);
1662 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1663 share_printers
, num_settings
, &settings
);
1664 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1665 user_cancel_any
, num_settings
, &settings
);
1667 if (!_cupsAdminSetServerSettings(http
, num_settings
, settings
))
1669 cgiStartHTML(cgiText(_("Change Settings")));
1670 cgiSetVariable("MESSAGE",
1671 cgiText(_("Unable to change server settings:")));
1672 cgiSetVariable("ERROR", cupsLastErrorString());
1673 cgiCopyTemplateLang("error.tmpl");
1677 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1678 cgiStartHTML(cgiText(_("Change Settings")));
1679 cgiCopyTemplateLang("restart.tmpl");
1688 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1689 cgiStartHTML(cgiText(_("Change Settings")));
1690 cgiCopyTemplateLang("norestart.tmpl");
1693 cupsFreeOptions(num_settings
, settings
);
1697 else if (cgiIsPOST())
1700 * Save hand-edited config file...
1703 http_status_t status
; /* PUT status */
1704 char tempfile
[1024]; /* Temporary new cupsd.conf */
1705 int tempfd
; /* Temporary file descriptor */
1706 cups_file_t
*temp
; /* Temporary file */
1707 const char *start
, /* Start of line */
1708 *end
; /* End of line */
1712 * Create a temporary file for the new cupsd.conf file...
1715 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1717 cgiStartHTML(cgiText(_("Edit Configuration File")));
1718 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1719 cgiSetVariable("ERROR", strerror(errno
));
1720 cgiCopyTemplateLang("error.tmpl");
1727 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1729 cgiStartHTML(cgiText(_("Edit Configuration File")));
1730 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1731 cgiSetVariable("ERROR", strerror(errno
));
1732 cgiCopyTemplateLang("error.tmpl");
1742 * Copy the cupsd.conf text from the form variable...
1745 start
= cgiGetVariable("CUPSDCONF");
1748 if ((end
= strstr(start
, "\r\n")) == NULL
)
1749 if ((end
= strstr(start
, "\n")) == NULL
)
1750 end
= start
+ strlen(start
);
1752 cupsFileWrite(temp
, start
, end
- start
);
1753 cupsFilePutChar(temp
, '\n');
1757 else if (*end
== '\n')
1763 cupsFileClose(temp
);
1766 * Upload the configuration file to the server...
1769 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
1771 if (status
!= HTTP_CREATED
)
1773 cgiSetVariable("MESSAGE",
1774 cgiText(_("Unable to upload cupsd.conf file:")));
1775 cgiSetVariable("ERROR", httpStatus(status
));
1777 cgiStartHTML(cgiText(_("Edit Configuration File")));
1778 cgiCopyTemplateLang("error.tmpl");
1782 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1784 cgiStartHTML(cgiText(_("Edit Configuration File")));
1785 cgiCopyTemplateLang("restart.tmpl");
1794 struct stat info
; /* cupsd.conf information */
1795 cups_file_t
*cupsd
; /* cupsd.conf file */
1796 char *buffer
; /* Buffer for entire file */
1797 char filename
[1024]; /* Filename */
1798 const char *server_root
; /* Location of config files */
1802 * Locate the cupsd.conf file...
1805 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1806 server_root
= CUPS_SERVERROOT
;
1808 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
1811 * Figure out the size...
1814 if (stat(filename
, &info
))
1816 cgiStartHTML(cgiText(_("Edit Configuration File")));
1817 cgiSetVariable("MESSAGE",
1818 cgiText(_("Unable to access cupsd.conf file:")));
1819 cgiSetVariable("ERROR", strerror(errno
));
1820 cgiCopyTemplateLang("error.tmpl");
1827 if (info
.st_size
> (1024 * 1024))
1829 cgiStartHTML(cgiText(_("Edit Configuration File")));
1830 cgiSetVariable("MESSAGE",
1831 cgiText(_("Unable to access cupsd.conf file:")));
1832 cgiSetVariable("ERROR",
1833 cgiText(_("Unable to edit cupsd.conf files larger than "
1835 cgiCopyTemplateLang("error.tmpl");
1838 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
1839 (long)info
.st_size
);
1844 * Open the cupsd.conf file...
1847 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
1850 * Unable to open - log an error...
1853 cgiStartHTML(cgiText(_("Edit Configuration File")));
1854 cgiSetVariable("MESSAGE",
1855 cgiText(_("Unable to access cupsd.conf file:")));
1856 cgiSetVariable("ERROR", strerror(errno
));
1857 cgiCopyTemplateLang("error.tmpl");
1865 * Allocate memory and load the file into a string buffer...
1868 buffer
= calloc(1, info
.st_size
+ 1);
1870 cupsFileRead(cupsd
, buffer
, info
.st_size
);
1871 cupsFileClose(cupsd
);
1873 cgiSetVariable("CUPSDCONF", buffer
);
1877 * Show the current config file...
1880 cgiStartHTML(cgiText(_("Edit Configuration File")));
1882 printf("<!-- \"%s\" -->\n", filename
);
1884 cgiCopyTemplateLang("edit-config.tmpl");
1892 * 'do_delete_class()' - Delete a class...
1896 do_delete_class(http_t
*http
) /* I - HTTP connection */
1898 ipp_t
*request
; /* IPP request */
1899 char uri
[HTTP_MAX_URI
]; /* Job URI */
1900 const char *pclass
; /* Printer class name */
1904 * Get form variables...
1907 if (cgiGetVariable("CONFIRM") == NULL
)
1909 cgiStartHTML(cgiText(_("Delete Class")));
1910 cgiCopyTemplateLang("class-confirm.tmpl");
1915 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1916 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1917 "localhost", 0, "/classes/%s", pclass
);
1920 cgiStartHTML(cgiText(_("Delete Class")));
1921 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1922 cgiCopyTemplateLang("error.tmpl");
1928 * Build a CUPS_DELETE_CLASS request, which requires the following
1931 * attributes-charset
1932 * attributes-natural-language
1936 request
= ippNewRequest(CUPS_DELETE_CLASS
);
1938 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1942 * Do the request and get back a response...
1945 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1948 * Show the results...
1951 cgiStartHTML(cgiText(_("Delete Class")));
1953 if (cupsLastError() > IPP_OK_CONFLICT
)
1954 cgiShowIPPError(_("Unable to delete class:"));
1956 cgiCopyTemplateLang("class-deleted.tmpl");
1963 * 'do_delete_printer()' - Delete a printer...
1967 do_delete_printer(http_t
*http
) /* I - HTTP connection */
1969 ipp_t
*request
; /* IPP request */
1970 char uri
[HTTP_MAX_URI
]; /* Job URI */
1971 const char *printer
; /* Printer printer name */
1975 * Get form variables...
1978 if (cgiGetVariable("CONFIRM") == NULL
)
1980 cgiStartHTML(cgiText(_("Delete Printer")));
1981 cgiCopyTemplateLang("printer-confirm.tmpl");
1986 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1987 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1988 "localhost", 0, "/printers/%s", printer
);
1991 cgiStartHTML(cgiText(_("Delete Printer")));
1992 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1993 cgiCopyTemplateLang("error.tmpl");
1999 * Build a CUPS_DELETE_PRINTER request, which requires the following
2002 * attributes-charset
2003 * attributes-natural-language
2007 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2009 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2013 * Do the request and get back a response...
2016 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2019 * Show the results...
2022 cgiStartHTML(cgiText(_("Delete Printer")));
2024 if (cupsLastError() > IPP_OK_CONFLICT
)
2025 cgiShowIPPError(_("Unable to delete printer:"));
2027 cgiCopyTemplateLang("printer-deleted.tmpl");
2034 * 'do_export()' - Export printers to Samba...
2038 do_export(http_t
*http
) /* I - HTTP connection */
2040 int i
, j
; /* Looping vars */
2041 ipp_t
*request
, /* IPP request */
2042 *response
; /* IPP response */
2043 const char *username
, /* Samba username */
2044 *password
, /* Samba password */
2045 *export_all
; /* Export all printers? */
2046 int export_count
, /* Number of printers to export */
2047 printer_count
; /* Number of available printers */
2048 const char *name
, /* What name to pull */
2049 *dest
; /* Current destination */
2050 char ppd
[1024]; /* PPD file */
2057 username
= cgiGetVariable("USERNAME");
2058 password
= cgiGetVariable("PASSWORD");
2059 export_all
= cgiGetVariable("EXPORT_ALL");
2060 export_count
= cgiGetSize("EXPORT_NAME");
2063 * Get list of available printers...
2066 cgiSetSize("PRINTER_NAME", 0);
2067 cgiSetSize("PRINTER_EXPORT", 0);
2069 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2071 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2074 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2075 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2076 CUPS_PRINTER_IMPLICIT
);
2078 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2079 "requested-attributes", NULL
, "printer-name");
2081 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2083 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2084 ippDelete(response
);
2088 printer_count
= cgiGetSize("PRINTER_NAME");
2090 for (i
= 0; i
< printer_count
; i
++)
2092 dest
= cgiGetArray("PRINTER_NAME", i
);
2094 for (j
= 0; j
< export_count
; j
++)
2095 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2098 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2104 * Export or get the printers to export...
2107 if (username
&& *username
&& password
&& *password
&&
2108 (export_all
|| export_count
> 0))
2114 fputs("DEBUG: Export printers...\n", stderr
);
2118 name
= "PRINTER_NAME";
2119 export_count
= cgiGetSize("PRINTER_NAME");
2122 name
= "EXPORT_NAME";
2124 for (i
= 0; i
< export_count
; i
++)
2126 dest
= cgiGetArray(name
, i
);
2128 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2131 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2140 if (i
< export_count
)
2141 cgiSetVariable("ERROR", cupsLastErrorString());
2144 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2145 cgiCopyTemplateLang("samba-exported.tmpl");
2150 else if (username
&& !*username
)
2151 cgiSetVariable("ERROR",
2152 cgiText(_("A Samba username is required to export "
2153 "printer drivers!")));
2154 else if (username
&& (!password
|| !*password
))
2155 cgiSetVariable("ERROR",
2156 cgiText(_("A Samba password is required to export "
2157 "printer drivers!")));
2163 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2164 cgiCopyTemplateLang("samba-export.tmpl");
2170 * 'do_menu()' - Show the main menu...
2174 do_menu(http_t
*http
) /* I - HTTP connection */
2176 int num_settings
; /* Number of server settings */
2177 cups_option_t
*settings
; /* Server settings */
2178 const char *val
; /* Setting value */
2179 char filename
[1024]; /* Temporary filename */
2180 const char *datadir
; /* Location of data files */
2181 ipp_t
*request
, /* IPP request */
2182 *response
; /* IPP response */
2183 ipp_attribute_t
*attr
; /* IPP attribute */
2187 * Get the current server settings...
2190 if (!_cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2192 cgiSetVariable("SETTINGS_MESSAGE",
2193 cgiText(_("Unable to open cupsd.conf file:")));
2194 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2197 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2198 settings
)) != NULL
&& atoi(val
))
2199 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2201 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2202 settings
)) != NULL
&& atoi(val
))
2203 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2205 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2206 settings
)) != NULL
&& atoi(val
))
2207 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2209 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2210 settings
)) != NULL
&& atoi(val
))
2211 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2213 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2214 settings
)) != NULL
&& atoi(val
))
2215 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2217 cupsFreeOptions(num_settings
, settings
);
2220 * Get the list of printers and their devices...
2223 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2225 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2226 "requested-attributes", NULL
, "device-uri");
2228 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2229 CUPS_PRINTER_LOCAL
);
2230 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2231 CUPS_PRINTER_LOCAL
);
2233 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2236 * Got the printer list, now load the devices...
2239 int i
; /* Looping var */
2240 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2241 char *printer_device
; /* Current printer device */
2245 * Allocate an array and copy the device strings...
2248 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2250 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2252 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2254 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2258 * Free the printer list and get the device list...
2261 ippDelete(response
);
2263 request
= ippNewRequest(CUPS_GET_DEVICES
);
2265 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2268 * Got the device list, let's parse it...
2271 const char *device_uri
, /* device-uri attribute value */
2272 *device_make_and_model
, /* device-make-and-model value */
2273 *device_info
; /* device-info value */
2276 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2279 * Skip leading attributes until we hit a device...
2282 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2289 * Pull the needed attributes from this device...
2293 device_make_and_model
= NULL
;
2296 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2298 if (!strcmp(attr
->name
, "device-info") &&
2299 attr
->value_tag
== IPP_TAG_TEXT
)
2300 device_info
= attr
->values
[0].string
.text
;
2302 if (!strcmp(attr
->name
, "device-make-and-model") &&
2303 attr
->value_tag
== IPP_TAG_TEXT
)
2304 device_make_and_model
= attr
->values
[0].string
.text
;
2306 if (!strcmp(attr
->name
, "device-uri") &&
2307 attr
->value_tag
== IPP_TAG_URI
)
2308 device_uri
= attr
->values
[0].string
.text
;
2314 * See if we have everything needed...
2317 if (device_info
&& device_make_and_model
&& device_uri
&&
2318 strcasecmp(device_make_and_model
, "unknown") &&
2319 strchr(device_uri
, ':'))
2322 * Yes, now see if there is already a printer for this
2326 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2329 * Not found, so it must be a new printer...
2332 char options
[1024], /* Form variables for this device */
2333 *options_ptr
; /* Pointer into string */
2334 const char *ptr
; /* Pointer into device string */
2338 * Format the printer name variable for this device...
2340 * We use the device-info string first, then device-uri,
2341 * and finally device-make-and-model to come up with a
2345 strcpy(options
, "PRINTER_NAME=");
2346 options_ptr
= options
+ strlen(options
);
2348 if (strncasecmp(device_info
, "unknown", 7))
2350 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2353 ptr
= device_make_and_model
;
2356 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2358 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2360 *options_ptr
++ = *ptr
;
2361 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2362 *options_ptr
++ = '_';
2363 else if (*ptr
== '?' || *ptr
== '(')
2367 * Then add the make and model in the printer info, so
2368 * that MacOS clients see something reasonable...
2371 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2373 sizeof(options
) - (options_ptr
- options
));
2374 options_ptr
+= strlen(options_ptr
);
2376 cgiFormEncode(options_ptr
, device_make_and_model
,
2377 sizeof(options
) - (options_ptr
- options
));
2378 options_ptr
+= strlen(options_ptr
);
2381 * Then copy the device URI...
2384 strlcpy(options_ptr
, "&DEVICE_URI=",
2385 sizeof(options
) - (options_ptr
- options
));
2386 options_ptr
+= strlen(options_ptr
);
2388 cgiFormEncode(options_ptr
, device_uri
,
2389 sizeof(options
) - (options_ptr
- options
));
2390 options_ptr
+= strlen(options_ptr
);
2392 if (options_ptr
< (options
+ sizeof(options
) - 1))
2394 *options_ptr
++ = '|';
2395 cgiFormEncode(options_ptr
, device_make_and_model
,
2396 sizeof(options
) - (options_ptr
- options
));
2400 * Finally, set the form variables for this printer...
2403 cgiSetArray("device_info", i
, device_info
);
2404 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2405 cgiSetArray("device_options", i
, options
);
2406 cgiSetArray("device_uri", i
, device_uri
);
2415 ippDelete(response
);
2418 * Free the device list...
2421 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2423 printer_device
= (char *)cupsArrayNext(printer_devices
))
2424 free(printer_device
);
2426 cupsArrayDelete(printer_devices
);
2431 * See if Samba and the Windows drivers are installed...
2434 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2435 datadir
= CUPS_DATADIR
;
2437 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2438 if (!access(filename
, R_OK
))
2441 * Found Windows 2000 driver file, see if we have smbclient and
2445 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2446 sizeof(filename
)) &&
2447 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2449 cgiSetVariable("HAVE_SAMBA", "Y");
2452 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2454 fputs("ERROR: smbclient not found!\n", stderr
);
2456 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2458 fputs("ERROR: rpcclient not found!\n", stderr
);
2465 * Finally, show the main menu template...
2468 cgiStartHTML(cgiText(_("Administration")));
2470 cgiCopyTemplateLang("admin.tmpl");
2477 * 'do_printer_op()' - Do a printer operation.
2481 do_printer_op(http_t
*http
, /* I - HTTP connection */
2482 ipp_op_t op
, /* I - Operation to perform */
2483 const char *title
) /* I - Title of page */
2485 ipp_t
*request
; /* IPP request */
2486 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2487 const char *printer
, /* Printer name (purge-jobs) */
2488 *is_class
; /* Is a class? */
2491 is_class
= cgiGetVariable("IS_CLASS");
2492 printer
= cgiGetVariable("PRINTER_NAME");
2496 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2497 cgiStartHTML(title
);
2498 cgiCopyTemplateLang("error.tmpl");
2504 * Build a printer request, which requires the following
2507 * attributes-charset
2508 * attributes-natural-language
2512 request
= ippNewRequest(op
);
2514 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2515 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2517 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2521 * Do the request and get back a response...
2524 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2526 if (cupsLastError() > IPP_OK_CONFLICT
)
2528 cgiStartHTML(title
);
2529 cgiShowIPPError(_("Unable to change printer:"));
2534 * Redirect successful updates back to the printer page...
2537 char url
[1024], /* Printer/class URL */
2538 refresh
[1024]; /* Refresh URL */
2541 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2542 cgiFormEncode(uri
, url
, sizeof(uri
));
2543 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2544 cgiSetVariable("refresh_page", refresh
);
2546 cgiStartHTML(title
);
2548 if (op
== IPP_PAUSE_PRINTER
)
2549 cgiCopyTemplateLang("printer-stop.tmpl");
2550 else if (op
== IPP_RESUME_PRINTER
)
2551 cgiCopyTemplateLang("printer-start.tmpl");
2552 else if (op
== CUPS_ACCEPT_JOBS
)
2553 cgiCopyTemplateLang("printer-accept.tmpl");
2554 else if (op
== CUPS_REJECT_JOBS
)
2555 cgiCopyTemplateLang("printer-reject.tmpl");
2556 else if (op
== IPP_PURGE_JOBS
)
2557 cgiCopyTemplateLang("printer-purge.tmpl");
2558 else if (op
== CUPS_SET_DEFAULT
)
2559 cgiCopyTemplateLang("printer-default.tmpl");
2567 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2571 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2573 int i
; /* Looping var */
2574 ipp_t
*request
, /* IPP request */
2575 *response
; /* IPP response */
2576 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2577 const char *printer
, /* Printer name (purge-jobs) */
2578 *is_class
, /* Is a class? */
2579 *users
, /* List of users or groups */
2580 *type
; /* Allow/deny type */
2581 int num_users
; /* Number of users */
2582 char *ptr
, /* Pointer into users string */
2583 *end
, /* Pointer to end of users string */
2584 quote
; /* Quote character */
2585 ipp_attribute_t
*attr
; /* Attribute */
2586 static const char * const attrs
[] = /* Requested attributes */
2588 "requesting-user-name-allowed",
2589 "requesting-user-name-denied"
2593 is_class
= cgiGetVariable("IS_CLASS");
2594 printer
= cgiGetVariable("PRINTER_NAME");
2598 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2599 cgiStartHTML(cgiText(_("Set Allowed Users")));
2600 cgiCopyTemplateLang("error.tmpl");
2605 users
= cgiGetVariable("users");
2606 type
= cgiGetVariable("type");
2608 if (!users
|| !type
||
2609 (strcmp(type
, "requesting-user-name-allowed") &&
2610 strcmp(type
, "requesting-user-name-denied")))
2613 * Build a Get-Printer-Attributes request, which requires the following
2616 * attributes-charset
2617 * attributes-natural-language
2619 * requested-attributes
2622 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2624 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2625 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2627 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2630 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2631 "requested-attributes",
2632 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2635 * Do the request and get back a response...
2638 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2640 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2642 ippDelete(response
);
2645 cgiStartHTML(cgiText(_("Set Allowed Users")));
2647 if (cupsLastError() > IPP_OK_CONFLICT
)
2648 cgiShowIPPError(_("Unable to get printer attributes:"));
2650 cgiCopyTemplateLang("users.tmpl");
2657 * Save the changes...
2660 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2663 * Skip whitespace and commas...
2666 while (*ptr
== ',' || isspace(*ptr
& 255))
2669 if (*ptr
== '\'' || *ptr
== '\"')
2672 * Scan quoted name...
2677 for (end
= ptr
; *end
; end
++)
2684 * Scan space or comma-delimited name...
2687 for (end
= ptr
; *end
; end
++)
2688 if (isspace(*end
& 255) || *end
== ',')
2693 * Advance to the next name...
2700 * Build a CUPS-Add-Printer/Class request, which requires the following
2703 * attributes-charset
2704 * attributes-natural-language
2706 * requesting-user-name-{allowed,denied}
2709 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2711 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2712 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2714 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2718 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2719 "requesting-user-name-allowed", NULL
, "all");
2722 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
2723 type
, num_users
, NULL
, NULL
);
2725 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
2728 * Skip whitespace and commas...
2731 while (*ptr
== ',' || isspace(*ptr
& 255))
2734 if (*ptr
== '\'' || *ptr
== '\"')
2737 * Scan quoted name...
2742 for (end
= ptr
; *end
; end
++)
2749 * Scan space or comma-delimited name...
2752 for (end
= ptr
; *end
; end
++)
2753 if (isspace(*end
& 255) || *end
== ',')
2758 * Terminate the name...
2768 attr
->values
[i
].string
.text
= strdup(ptr
);
2771 * Advance to the next name...
2779 * Do the request and get back a response...
2782 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2784 if (cupsLastError() > IPP_OK_CONFLICT
)
2786 cgiStartHTML(cgiText(_("Set Allowed Users")));
2787 cgiShowIPPError(_("Unable to change printer:"));
2792 * Redirect successful updates back to the printer page...
2795 char url
[1024], /* Printer/class URL */
2796 refresh
[1024]; /* Refresh URL */
2799 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2800 cgiFormEncode(uri
, url
, sizeof(uri
));
2801 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
2803 cgiSetVariable("refresh_page", refresh
);
2805 cgiStartHTML(cgiText(_("Set Allowed Users")));
2807 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2808 "printer-modified.tmpl");
2817 * 'do_set_sharing()' - Set printer-is-shared value...
2821 do_set_sharing(http_t
*http
) /* I - HTTP connection */
2823 ipp_t
*request
, /* IPP request */
2824 *response
; /* IPP response */
2825 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2826 const char *printer
, /* Printer name */
2827 *is_class
, /* Is a class? */
2828 *shared
; /* Sharing value */
2831 is_class
= cgiGetVariable("IS_CLASS");
2832 printer
= cgiGetVariable("PRINTER_NAME");
2833 shared
= cgiGetVariable("SHARED");
2835 if (!printer
|| !shared
)
2837 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2838 cgiStartHTML(cgiText(_("Set Publishing")));
2839 cgiCopyTemplateLang("error.tmpl");
2845 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
2846 * following attributes:
2848 * attributes-charset
2849 * attributes-natural-language
2854 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
2856 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2857 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2859 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2862 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
2865 * Do the request and get back a response...
2868 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
2870 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2872 ippDelete(response
);
2875 if (cupsLastError() > IPP_OK_CONFLICT
)
2877 cgiStartHTML(cgiText(_("Set Publishing")));
2878 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
2883 * Redirect successful updates back to the printer page...
2886 char url
[1024], /* Printer/class URL */
2887 refresh
[1024]; /* Refresh URL */
2890 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2891 cgiFormEncode(uri
, url
, sizeof(uri
));
2892 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2893 cgiSetVariable("refresh_page", refresh
);
2895 cgiStartHTML(cgiText(_("Set Publishing")));
2896 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
2897 "printer-modified.tmpl");
2905 * 'match_string()' - Return the number of matching characters.
2908 static int /* O - Number of matching characters */
2909 match_string(const char *a
, /* I - First string */
2910 const char *b
) /* I - Second string */
2912 int count
; /* Number of matching characters */
2916 * Loop through both strings until we hit the end of either or we find
2917 * a non-matching character. For the purposes of comparison, we ignore
2918 * whitespace and do a case-insensitive comparison so that we have a
2919 * better chance of finding a match...
2922 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
2925 * Skip leading whitespace characters...
2928 while (isspace(*a
& 255))
2931 while (isspace(*b
& 255))
2935 * Break out if we run out of characters...
2942 * Do a case-insensitive comparison of the next two chars...
2945 if (tolower(*a
& 255) != tolower(*b
& 255))
2954 * End of "$Id: admin.c 5878 2006-08-24 15:55:42Z mike $".