2 * "$Id: admin.c 4943 2006-01-18 20:30: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/file.h>
57 static void do_am_class(http_t
*http
, int modify
);
58 static void do_am_printer(http_t
*http
, int modify
);
59 static void do_config_printer(http_t
*http
);
60 static void do_config_server(http_t
*http
);
61 static void do_delete_class(http_t
*http
);
62 static void do_delete_printer(http_t
*http
);
63 static void do_export(http_t
*http
);
64 static void do_menu(http_t
*http
);
65 static void do_printer_op(http_t
*http
,
66 ipp_op_t op
, const char *title
);
67 static void do_set_allowed_users(http_t
*http
);
68 static void do_set_sharing(http_t
*http
);
69 static int match_string(const char *a
, const char *b
);
73 * 'main()' - Main entry for CGI.
76 int /* O - Exit status */
77 main(int argc
, /* I - Number of command-line arguments */
78 char *argv
[]) /* I - Command-line arguments */
80 http_t
*http
; /* Connection to the server */
81 const char *op
; /* Operation name */
85 * Connect to the HTTP server...
88 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
91 * Set the web interface section...
94 cgiSetVariable("SECTION", "admin");
97 * See if we have form data...
100 if (!cgiInitialize())
103 * Nope, send the administration menu...
108 else if ((op
= cgiGetVariable("OP")) != NULL
)
111 * Do the operation...
114 if (!strcmp(op
, "redirect"))
116 const char *url
; /* Redirection URL... */
119 if ((url
= cgiGetVariable("URL")) != NULL
)
120 printf("Location: %s\n\n", url
);
122 puts("Location: /admin\n");
124 else if (!strcmp(op
, "start-printer"))
125 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
126 else if (!strcmp(op
, "stop-printer"))
127 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
128 else if (!strcmp(op
, "start-class"))
129 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
130 else if (!strcmp(op
, "stop-class"))
131 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
132 else if (!strcmp(op
, "accept-jobs"))
133 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
134 else if (!strcmp(op
, "reject-jobs"))
135 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
136 else if (!strcmp(op
, "purge-jobs"))
137 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
138 else if (!strcmp(op
, "set-allowed-users"))
139 do_set_allowed_users(http
);
140 else if (!strcmp(op
, "set-as-default"))
141 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
142 else if (!strcmp(op
, "set-sharing"))
143 do_set_sharing(http
);
144 else if (!strcmp(op
, "add-class"))
145 do_am_class(http
, 0);
146 else if (!strcmp(op
, "add-printer"))
147 do_am_printer(http
, 0);
148 else if (!strcmp(op
, "modify-class"))
149 do_am_class(http
, 1);
150 else if (!strcmp(op
, "modify-printer"))
151 do_am_printer(http
, 1);
152 else if (!strcmp(op
, "delete-class"))
153 do_delete_class(http
);
154 else if (!strcmp(op
, "delete-printer"))
155 do_delete_printer(http
);
156 else if (!strcmp(op
, "set-printer-options"))
157 do_config_printer(http
);
158 else if (!strcmp(op
, "config-server"))
159 do_config_server(http
);
160 else if (!strcmp(op
, "export-samba"))
165 * Bad operation code... Display an error...
168 cgiStartHTML(cgiText(_("Administration")));
169 cgiCopyTemplateLang("error-op.tmpl");
176 * Form data but no operation code... Display an error...
179 cgiStartHTML(cgiText(_("Administration")));
180 cgiCopyTemplateLang("error-op.tmpl");
185 * Close the HTTP server connection...
191 * Return with no errors...
199 * 'do_am_class()' - Add or modify a class.
203 do_am_class(http_t
*http
, /* I - HTTP connection */
204 int modify
) /* I - Modify the printer? */
206 int i
, j
; /* Looping vars */
207 int element
; /* Element number */
208 int num_printers
; /* Number of printers */
209 ipp_t
*request
, /* IPP request */
210 *response
; /* IPP response */
211 ipp_attribute_t
*attr
; /* member-uris attribute */
212 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
213 const char *name
, /* Pointer to class name */
214 *ptr
; /* Pointer to CGI variable */
215 const char *title
; /* Title of page */
216 static const char * const pattrs
[] = /* Requested printer attributes */
224 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
225 name
= cgiGetVariable("PRINTER_NAME");
227 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
230 * Build a CUPS_GET_PRINTERS request, which requires the
231 * following attributes:
234 * attributes-natural-language
238 request
= ippNewRequest(CUPS_GET_PRINTERS
);
240 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
241 NULL
, "ipp://localhost/printers");
244 * Do the request and get back a response...
247 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
250 * Create MEMBER_URIS and MEMBER_NAMES arrays...
253 for (element
= 0, attr
= response
->attrs
;
256 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
258 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
259 (!name
|| strcasecmp(name
, ptr
+ 1)))
262 * Don't show the current class...
265 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
270 for (element
= 0, attr
= response
->attrs
;
273 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
275 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
278 * Don't show the current class...
281 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
286 num_printers
= cgiGetSize("MEMBER_URIS");
296 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
297 * following attributes:
300 * attributes-natural-language
304 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
306 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
307 "/classes/%s", name
);
308 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
311 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
312 "requested-attributes",
313 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
317 * Do the request and get back a response...
320 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
322 if ((attr
= ippFindAttribute(response
, "member-names", IPP_TAG_NAME
)) != NULL
)
325 * Mark any current members in the class...
328 for (j
= 0; j
< num_printers
; j
++)
329 cgiSetArray("MEMBER_SELECTED", j
, "");
331 for (i
= 0; i
< attr
->num_values
; i
++)
333 for (j
= 0; j
< num_printers
; j
++)
335 if (!strcasecmp(attr
->values
[i
].string
.text
,
336 cgiGetArray("MEMBER_NAMES", j
)))
338 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
345 if ((attr
= ippFindAttribute(response
, "printer-info",
346 IPP_TAG_TEXT
)) != NULL
)
347 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
349 if ((attr
= ippFindAttribute(response
, "printer-location",
350 IPP_TAG_TEXT
)) != NULL
)
351 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
357 * Update the location and description of an existing printer...
361 cgiCopyTemplateLang("modify-class.tmpl");
366 * Get the name, location, and description for a new printer...
370 cgiCopyTemplateLang("add-class.tmpl");
378 for (ptr
= name
; *ptr
; ptr
++)
379 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
382 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
384 cgiSetVariable("ERROR",
385 cgiText(_("The class name may only contain up to "
386 "127 printable characters and may not "
387 "contain spaces, slashes (/), or the "
388 "pound sign (#).")));
390 cgiCopyTemplateLang("error.tmpl");
396 * Build a CUPS_ADD_CLASS request, which requires the following
400 * attributes-natural-language
404 * printer-is-accepting-jobs
409 request
= ippNewRequest(CUPS_ADD_CLASS
);
411 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
412 "/classes/%s", cgiGetVariable("PRINTER_NAME"));
413 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
416 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
417 NULL
, cgiGetVariable("PRINTER_LOCATION"));
419 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
420 NULL
, cgiGetVariable("PRINTER_INFO"));
422 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
424 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
427 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
429 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
430 num_printers
, NULL
, NULL
);
431 for (i
= 0; i
< num_printers
; i
++)
432 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
436 * Do the request and get back a response...
439 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
441 if (cupsLastError() > IPP_OK_CONFLICT
)
444 cgiShowIPPError(modify
? _("Unable to modify class:") :
445 _("Unable to add class:"));
450 * Redirect successful updates back to the class page...
453 char refresh
[1024]; /* Refresh URL */
455 cgiFormEncode(uri
, name
, sizeof(uri
));
456 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=/classes/%s",
458 cgiSetVariable("refresh_page", refresh
);
463 cgiCopyTemplateLang("class-modified.tmpl");
465 cgiCopyTemplateLang("class-added.tmpl");
473 * 'do_am_printer()' - Add or modify a printer.
477 do_am_printer(http_t
*http
, /* I - HTTP connection */
478 int modify
) /* I - Modify the printer? */
480 int i
; /* Looping var */
481 int element
; /* Element number */
482 ipp_attribute_t
*attr
, /* Current attribute */
483 *last
; /* Last attribute */
484 ipp_t
*request
, /* IPP request */
485 *response
, /* IPP response */
486 *oldinfo
; /* Old printer information */
487 const cgi_file_t
*file
; /* Uploaded file, if any */
488 const char *var
; /* CGI variable */
489 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
490 *uriptr
; /* Pointer into URI */
491 int maxrate
; /* Maximum baud rate */
492 char baudrate
[255]; /* Baud rate string */
493 const char *name
, /* Pointer to class name */
494 *ptr
; /* Pointer to CGI variable */
495 const char *title
; /* Title of page */
496 static int baudrates
[] = /* Baud rates */
511 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
512 cgiGetVariable("DEVICE_URI"));
514 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
519 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
520 * following attributes:
523 * attributes-natural-language
527 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
529 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
530 "/printers/%s", cgiGetVariable("PRINTER_NAME"));
531 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
535 * Do the request and get back a response...
538 oldinfo
= cupsDoRequest(http
, request
, "/");
543 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
544 cgiGetVariable("PRINTER_LOCATION") == NULL
)
551 * Update the location and description of an existing printer...
555 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
557 cgiCopyTemplateLang("modify-printer.tmpl");
562 * Get the name, location, and description for a new printer...
565 cgiCopyTemplateLang("add-printer.tmpl");
576 for (ptr
= name
; *ptr
; ptr
++)
577 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
580 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
582 cgiSetVariable("ERROR",
583 cgiText(_("The printer name may only contain up to "
584 "127 printable characters and may not "
585 "contain spaces, slashes (/), or the "
586 "pound sign (#).")));
588 cgiCopyTemplateLang("error.tmpl");
597 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
598 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
599 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
600 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
603 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
606 * Build a CUPS_GET_DEVICES request, which requires the following
610 * attributes-natural-language
614 request
= ippNewRequest(CUPS_GET_DEVICES
);
616 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
617 NULL
, "ipp://localhost/printers/");
620 * Do the request and get back a response...
623 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
625 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
630 * Let the user choose...
633 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
635 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
636 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
639 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
640 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
644 cgiCopyTemplateLang("choose-device.tmpl");
647 else if (strchr(var
, '/') == NULL
)
649 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
652 * Set the current device URI for the form to the old one...
655 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
656 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
660 * User needs to set the full URI...
664 cgiCopyTemplateLang("choose-uri.tmpl");
667 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
670 * Need baud rate, parity, etc.
673 if ((var
= strchr(var
, '?')) != NULL
&&
674 strncmp(var
, "?baud=", 6) == 0)
675 maxrate
= atoi(var
+ 6);
679 for (i
= 0; i
< 10; i
++)
680 if (baudrates
[i
] > maxrate
)
684 sprintf(baudrate
, "%d", baudrates
[i
]);
685 cgiSetArray("BAUDRATES", i
, baudrate
);
689 cgiCopyTemplateLang("choose-serial.tmpl");
692 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
697 * Get the PPD file...
700 int fd
; /* PPD file */
701 char filename
[1024]; /* PPD filename */
702 ppd_file_t
*ppd
; /* PPD information */
703 char buffer
[1024]; /* Buffer */
704 int bytes
; /* Number of bytes */
705 http_status_t get_status
; /* Status of GET */
708 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
710 if (httpGet(http
, uri
))
713 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
715 if (get_status
!= HTTP_OK
)
717 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
718 uri
, get_status
, httpStatus(get_status
));
720 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
722 while ((bytes
= httpRead(http
, buffer
, sizeof(buffer
))) > 0)
723 write(fd
, buffer
, bytes
);
727 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
729 if (ppd
->manufacturer
)
730 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
733 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
740 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
741 filename
, ppdErrorString(ppdLastError(&bytes
)));
749 "ERROR: Unable to create temporary file for PPD file: %s\n",
753 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
756 * Extract make and make/model from device URI string...
759 char make
[1024], /* Make string */
760 *makeptr
; /* Pointer into make */
765 strlcpy(make
, uriptr
, sizeof(make
));
767 if ((makeptr
= strchr(make
, ' ')) != NULL
)
769 else if ((makeptr
= strchr(make
, '-')) != NULL
)
771 else if (!strncasecmp(make
, "laserjet", 8) ||
772 !strncasecmp(make
, "deskjet", 7) ||
773 !strncasecmp(make
, "designjet", 9))
775 else if (!strncasecmp(make
, "phaser", 6))
776 strcpy(make
, "Xerox");
777 else if (!strncasecmp(make
, "stylus", 6))
778 strcpy(make
, "Epson");
780 strcpy(make
, "Generic");
782 cgiSetVariable("CURRENT_MAKE", make
);
783 cgiSetVariable("PPD_MAKE", make
);
784 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
788 * Build a CUPS_GET_PPDS request, which requires the following
792 * attributes-natural-language
796 request
= ippNewRequest(CUPS_GET_PPDS
);
798 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
799 NULL
, "ipp://localhost/printers/");
801 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
802 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
803 "ppd-make", NULL
, var
);
805 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
806 "requested-attributes", NULL
, "ppd-make");
809 * Do the request and get back a response...
812 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
815 * Got the list of PPDs, see if the user has selected a make...
818 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
823 * Let the user choose a make...
826 for (element
= 0, attr
= response
->attrs
, last
= NULL
;
829 if (attr
->name
&& strcmp(attr
->name
, "ppd-make") == 0)
831 strcasecmp(last
->values
[0].string
.text
,
832 attr
->values
[0].string
.text
) != 0)
834 cgiSetArray("PPD_MAKE", element
, attr
->values
[0].string
.text
);
840 cgiCopyTemplateLang("choose-make.tmpl");
846 * Let the user choose a model...
849 const char *make_model
; /* Current make/model string */
852 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
855 * Scan for "close" matches...
858 int match
, /* Current match */
859 best_match
, /* Best match so far */
860 count
; /* Number of drivers */
861 const char *best
, /* Best matching string */
862 *current
; /* Current string */
865 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
867 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
869 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
870 match
= match_string(make_model
, current
);
872 if (match
> best_match
)
879 if (best_match
> strlen(var
))
882 * Found a match longer than the make...
885 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
890 cgiCopyTemplateLang("choose-model.tmpl");
900 cgiShowIPPError(_("Unable to get list of printer drivers:"));
901 cgiCopyTemplateLang("error.tmpl");
908 * Build a CUPS_ADD_PRINTER request, which requires the following
912 * attributes-natural-language
918 * printer-is-accepting-jobs
922 request
= ippNewRequest(CUPS_ADD_PRINTER
);
924 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
925 "/printers/%s", cgiGetVariable("PRINTER_NAME"));
926 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
929 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
930 NULL
, cgiGetVariable("PRINTER_LOCATION"));
932 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
933 NULL
, cgiGetVariable("PRINTER_INFO"));
936 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
937 NULL
, cgiGetVariable("PPD_NAME"));
939 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
942 * Strip make and model from URI...
945 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
948 if (!strncmp(uri
, "serial:", 7))
951 * Update serial port URI to include baud rate, etc.
954 if ((uriptr
= strchr(uri
, '?')) == NULL
)
955 uriptr
= uri
+ strlen(uri
);
957 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
958 "?baud=%s+bits=%s+parity=%s+flow=%s",
959 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
960 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
963 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
966 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
968 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
972 * Do the request and get back a response...
976 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
978 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
980 if (cupsLastError() > IPP_OK_CONFLICT
)
983 cgiShowIPPError(modify
? _("Unable to modify printer:") :
984 _("Unable to add printer:"));
989 * Redirect successful updates back to the printer or set-options pages...
992 char refresh
[1024]; /* Refresh URL */
995 cgiFormEncode(uri
, name
, sizeof(uri
));
998 snprintf(refresh
, sizeof(refresh
),
999 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1001 snprintf(refresh
, sizeof(refresh
),
1002 "5;/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1004 cgiSetVariable("refresh_page", refresh
);
1006 cgiStartHTML(title
);
1009 cgiCopyTemplateLang("printer-modified.tmpl");
1011 cgiCopyTemplateLang("printer-added.tmpl");
1023 * 'do_config_printer()' - Configure the default options for a printer.
1027 do_config_printer(http_t
*http
) /* I - HTTP connection */
1029 int i
, j
, k
, m
; /* Looping vars */
1030 int have_options
; /* Have options? */
1031 ipp_t
*request
, /* IPP request */
1032 *response
; /* IPP response */
1033 ipp_attribute_t
*attr
; /* IPP attribute */
1034 char uri
[HTTP_MAX_URI
]; /* Job URI */
1035 const char *var
; /* Variable value */
1036 const char *printer
; /* Printer printer name */
1037 const char *filename
; /* PPD filename */
1038 char tempfile
[1024]; /* Temporary filename */
1039 cups_file_t
*in
, /* Input file */
1040 *out
; /* Output file */
1041 char line
[1024]; /* Line from PPD file */
1042 char keyword
[1024], /* Keyword from Default line */
1043 *keyptr
; /* Pointer into keyword... */
1044 ppd_file_t
*ppd
; /* PPD file */
1045 ppd_group_t
*group
; /* Option group */
1046 ppd_option_t
*option
; /* Option */
1047 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
1048 const char *title
; /* Page title */
1051 title
= cgiText(_("Set Printer Options"));
1054 * Get the printer name...
1057 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1058 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
1059 "/printers/%s", printer
);
1062 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1063 cgiStartHTML(title
);
1064 cgiCopyTemplateLang("error.tmpl");
1070 * Get the PPD file...
1073 if ((filename
= cupsGetPPD(printer
)) == NULL
)
1075 cgiStartHTML(title
);
1076 cgiShowIPPError(_("Unable to get PPD file!"));
1081 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
1083 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
1084 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1085 cgiStartHTML(title
);
1086 cgiCopyTemplateLang("error.tmpl");
1091 if (cgiGetVariable("job_sheets_start") != NULL
||
1092 cgiGetVariable("job_sheets_end") != NULL
)
1097 ppdMarkDefaults(ppd
);
1099 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1100 "<UL>\n", ppd
->num_groups
));
1102 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
1104 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
1106 for (j
= group
->num_options
, option
= group
->options
; j
> 0; j
--, option
++)
1107 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
1109 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
1111 ppdMarkOption(ppd
, option
->keyword
, var
);
1115 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
1118 DEBUG_puts("</UL></LI>");
1121 DEBUG_printf(("</UL>\n"
1122 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
1124 if (!have_options
|| ppdConflicts(ppd
))
1127 * Show the options to the user...
1132 cgiStartHTML("Set Printer Options");
1133 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1135 if (ppdConflicts(ppd
))
1137 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
; i
> 0; i
--, group
++)
1138 for (j
= group
->num_options
, option
= group
->options
; j
> 0; j
--, option
++)
1139 if (option
->conflicted
)
1141 cgiSetArray("ckeyword", k
, option
->keyword
);
1142 cgiSetArray("ckeytext", k
, option
->text
);
1146 cgiCopyTemplateLang("option-conflict.tmpl");
1149 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1153 if (!strcmp(group
->name
, "InstallableOptions"))
1154 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
1156 cgiSetVariable("GROUP", group
->text
);
1158 cgiCopyTemplateLang("option-header.tmpl");
1160 for (j
= group
->num_options
, option
= group
->options
;
1164 if (!strcmp(option
->keyword
, "PageRegion"))
1167 cgiSetVariable("KEYWORD", option
->keyword
);
1168 cgiSetVariable("KEYTEXT", option
->text
);
1170 if (option
->conflicted
)
1171 cgiSetVariable("CONFLICTED", "1");
1173 cgiSetVariable("CONFLICTED", "0");
1175 cgiSetSize("CHOICES", 0);
1176 cgiSetSize("TEXT", 0);
1177 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
1180 * Hide custom option values...
1183 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
1186 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
1187 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
1191 if (option
->choices
[k
].marked
)
1192 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
1197 case PPD_UI_BOOLEAN
:
1198 cgiCopyTemplateLang("option-boolean.tmpl");
1200 case PPD_UI_PICKONE
:
1201 cgiCopyTemplateLang("option-pickone.tmpl");
1203 case PPD_UI_PICKMANY
:
1204 cgiCopyTemplateLang("option-pickmany.tmpl");
1209 cgiCopyTemplateLang("option-trailer.tmpl");
1213 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1214 * following attributes:
1216 * attributes-charset
1217 * attributes-natural-language
1221 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
1223 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
1224 "/printers/%s", printer
);
1225 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1229 * Do the request and get back a response...
1232 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1234 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
1235 IPP_TAG_ZERO
)) != NULL
)
1238 * Add the job sheets options...
1241 cgiSetVariable("GROUP", cgiText(_("Banners")));
1242 cgiCopyTemplateLang("option-header.tmpl");
1244 cgiSetSize("CHOICES", attr
->num_values
);
1245 cgiSetSize("TEXT", attr
->num_values
);
1246 for (k
= 0; k
< attr
->num_values
; k
++)
1248 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1249 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1252 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
1254 cgiSetVariable("KEYWORD", "job_sheets_start");
1255 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
1256 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1257 "" : attr
->values
[0].string
.text
);
1259 cgiCopyTemplateLang("option-pickone.tmpl");
1261 cgiSetVariable("KEYWORD", "job_sheets_end");
1262 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
1263 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
1264 "" : attr
->values
[1].string
.text
);
1266 cgiCopyTemplateLang("option-pickone.tmpl");
1268 cgiCopyTemplateLang("option-trailer.tmpl");
1271 if (ippFindAttribute(response
, "printer-error-policy-supported",
1273 ippFindAttribute(response
, "printer-op-policy-supported",
1277 * Add the error and operation policy options...
1280 cgiSetVariable("GROUP", cgiText(_("Policies")));
1281 cgiCopyTemplateLang("option-header.tmpl");
1287 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
1292 cgiSetSize("CHOICES", attr
->num_values
);
1293 cgiSetSize("TEXT", attr
->num_values
);
1294 for (k
= 0; k
< attr
->num_values
; k
++)
1296 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1297 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1300 attr
= ippFindAttribute(response
, "printer-error-policy",
1303 cgiSetVariable("KEYWORD", "printer_error_policy");
1304 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
1305 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1306 "" : attr
->values
[0].string
.text
);
1309 cgiCopyTemplateLang("option-pickone.tmpl");
1312 * Operation policy...
1315 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
1320 cgiSetSize("CHOICES", attr
->num_values
);
1321 cgiSetSize("TEXT", attr
->num_values
);
1322 for (k
= 0; k
< attr
->num_values
; k
++)
1324 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1325 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1328 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
1330 cgiSetVariable("KEYWORD", "printer_op_policy");
1331 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
1332 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1333 "" : attr
->values
[0].string
.text
);
1335 cgiCopyTemplateLang("option-pickone.tmpl");
1338 cgiCopyTemplateLang("option-trailer.tmpl");
1341 ippDelete(response
);
1345 * Binary protocol support...
1348 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
1350 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
1352 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
1353 cgiCopyTemplateLang("option-header.tmpl");
1355 cgiSetSize("CHOICES", 2);
1356 cgiSetSize("TEXT", 2);
1357 cgiSetArray("CHOICES", 0, "None");
1358 cgiSetArray("TEXT", 0, cgiText(_("None")));
1360 if (strstr(ppd
->protocols
, "TBCP"))
1362 cgiSetArray("CHOICES", 1, "TBCP");
1363 cgiSetArray("TEXT", 1, "TBCP");
1367 cgiSetArray("CHOICES", 1, "BCP");
1368 cgiSetArray("TEXT", 1, "BCP");
1371 cgiSetVariable("KEYWORD", "protocol");
1372 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
1373 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
1375 cgiCopyTemplateLang("option-pickone.tmpl");
1377 cgiCopyTemplateLang("option-trailer.tmpl");
1380 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1386 * Set default options...
1389 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
1390 in
= cupsFileOpen(filename
, "r");
1394 cgiSetVariable("ERROR", strerror(errno
));
1395 cgiStartHTML("Set Printer Options");
1396 cgiCopyTemplateLang("error.tmpl");
1412 while (cupsFileGets(in
, line
, sizeof(line
)))
1414 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1416 else if (strncmp(line
, "*Default", 8))
1417 cupsFilePrintf(out
, "%s\n", line
);
1421 * Get default option name...
1424 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
1426 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1427 if (*keyptr
== ':' || isspace(*keyptr
& 255))
1432 if (!strcmp(keyword
, "PageRegion"))
1433 var
= cgiGetVariable("PageSize");
1435 var
= cgiGetVariable(keyword
);
1438 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
1440 cupsFilePrintf(out
, "%s\n", line
);
1444 if ((var
= cgiGetVariable("protocol")) != NULL
)
1445 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1451 * Build a CUPS_ADD_PRINTER request, which requires the following
1454 * attributes-charset
1455 * attributes-natural-language
1457 * job-sheets-default
1461 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1463 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
1464 "/printers/%s", cgiGetVariable("PRINTER_NAME"));
1465 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1468 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1469 "job-sheets-default", 2, NULL
, NULL
);
1470 attr
->values
[0].string
.text
= strdup(cgiGetVariable("job_sheets_start"));
1471 attr
->values
[1].string
.text
= strdup(cgiGetVariable("job_sheets_end"));
1473 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
1474 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1475 "printer-error-policy", NULL
, var
);
1477 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
1478 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1479 "printer-op-policy", NULL
, var
);
1482 * Do the request and get back a response...
1485 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
1487 if (cupsLastError() > IPP_OK_CONFLICT
)
1489 cgiStartHTML(title
);
1490 cgiShowIPPError(_("Unable to set options:"));
1495 * Redirect successful updates back to the printer page...
1498 char refresh
[1024]; /* Refresh URL */
1501 cgiFormEncode(uri
, printer
, sizeof(uri
));
1502 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=/printers/%s",
1504 cgiSetVariable("refresh_page", refresh
);
1506 cgiStartHTML(title
);
1508 cgiCopyTemplateLang("printer-configured.tmpl");
1521 * 'do_config_server()' - Configure server settings.
1525 do_config_server(http_t
*http
) /* I - HTTP connection */
1527 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1530 * Save basic setting changes...
1533 http_status_t status
; /* PUT status */
1534 cups_file_t
*cupsd
; /* cupsd.conf file */
1535 char tempfile
[1024]; /* Temporary new cupsd.conf */
1536 int tempfd
; /* Temporary file descriptor */
1537 cups_file_t
*temp
; /* Temporary file */
1538 char line
[1024], /* Line from cupsd.conf file */
1539 *value
; /* Value on line */
1540 const char *server_root
; /* Location of config files */
1541 int linenum
, /* Line number in file */
1542 in_policy
, /* In a policy section? */
1543 in_cancel_job
, /* In a cancel-job section? */
1544 in_admin_location
, /* In the /admin location? */
1545 in_conf_location
, /* In the /admin/conf location? */
1546 in_root_location
; /* In the / location? */
1547 int remote_printers
, /* Show remote printers */
1548 share_printers
, /* Share local printers */
1549 remote_admin
, /* Remote administration allowed? */
1550 user_cancel_any
, /* Cancel-job policy set? */
1551 debug_logging
; /* LogLevel debug set? */
1552 int wrote_port_listen
, /* Wrote the port/listen lines? */
1553 wrote_browsing
, /* Wrote the browsing lines? */
1554 wrote_policy
, /* Wrote the policy? */
1555 wrote_loglevel
, /* Wrote the LogLevel line? */
1556 wrote_admin_location
, /* Wrote the /admin location? */
1557 wrote_conf_location
, /* Wrote the /admin/conf location? */
1558 wrote_root_location
; /* Wrote the / location? */
1559 int indent
; /* Indentation */
1563 * Get form variables...
1566 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") != NULL
;
1567 share_printers
= cgiGetVariable("SHARE_PRINTERS") != NULL
;
1568 remote_admin
= cgiGetVariable("REMOTE_ADMIN") != NULL
;
1569 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") != NULL
;
1570 debug_logging
= cgiGetVariable("DEBUG_LOGGING") != NULL
;
1573 * Locate the cupsd.conf file...
1576 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
1577 server_root
= CUPS_SERVERROOT
;
1579 snprintf(line
, sizeof(line
), "%s/cupsd.conf", server_root
);
1582 * Open the cupsd.conf file...
1585 if ((cupsd
= cupsFileOpen(line
, "r")) == NULL
)
1588 * Unable to open - log an error...
1591 cgiStartHTML(cgiText(_("Change Settings")));
1592 cgiSetVariable("MESSAGE", cgiText(_("Unable to change server settings:")));
1593 cgiSetVariable("ERROR", strerror(errno
));
1594 cgiCopyTemplateLang("error.tmpl");
1602 * Create a temporary file for the new cupsd.conf file...
1605 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1607 cgiStartHTML(cgiText(_("Change Settings")));
1608 cgiSetVariable("MESSAGE", cgiText(_("Unable to change server settings:")));
1609 cgiSetVariable("ERROR", strerror(errno
));
1610 cgiCopyTemplateLang("error.tmpl");
1614 cupsFileClose(cupsd
);
1618 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1620 cgiStartHTML(cgiText(_("Change Settings")));
1621 cgiSetVariable("MESSAGE", cgiText(_("Unable to change server settings:")));
1622 cgiSetVariable("ERROR", strerror(errno
));
1623 cgiCopyTemplateLang("error.tmpl");
1629 cupsFileClose(cupsd
);
1634 * Copy the old file to the new, making changes along the way...
1637 in_admin_location
= 0;
1639 in_conf_location
= 0;
1641 in_root_location
= 0;
1643 wrote_admin_location
= 0;
1645 wrote_conf_location
= 0;
1648 wrote_port_listen
= 0;
1649 wrote_root_location
= 0;
1652 while (cupsFileGetConf(cupsd
, line
, sizeof(line
), &value
, &linenum
))
1654 if (!strcasecmp(line
, "Port") || !strcasecmp(line
, "Listen"))
1656 if (!wrote_port_listen
)
1658 wrote_port_listen
= 1;
1660 if (share_printers
|| remote_admin
)
1662 cupsFilePuts(temp
, "# Allow remote access\n");
1663 cupsFilePrintf(temp
, "Listen *:%d\n", ippPort());
1667 cupsFilePuts(temp
, "# Only listen for connections from the local machine.\n");
1668 cupsFilePrintf(temp
, "Listen localhost:%d\n", ippPort());
1671 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1672 cupsFilePuts(temp
, "Listen " CUPS_DEFAULT_DOMAINSOCKET
"\n");
1673 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1676 else if (!strcasecmp(line
, "Browsing") ||
1677 !strcasecmp(line
, "BrowseAddress") ||
1678 !strcasecmp(line
, "BrowseAllow") ||
1679 !strcasecmp(line
, "BrowseDeny") ||
1680 !strcasecmp(line
, "BrowseOrder"))
1682 if (!wrote_browsing
)
1686 if (remote_printers
|| share_printers
)
1688 if (remote_printers
&& share_printers
)
1689 cupsFilePuts(temp
, "# Enable printer sharing and shared printers.\n");
1690 else if (remote_printers
)
1691 cupsFilePuts(temp
, "# Show shared printers on the local network.\n");
1693 cupsFilePuts(temp
, "# Share local printers on the local network.\n");
1695 cupsFilePuts(temp
, "Browsing On\n");
1696 cupsFilePuts(temp
, "BrowseOrder allow,deny\n");
1698 if (remote_printers
)
1699 cupsFilePuts(temp
, "BrowseAllow @LOCAL\n");
1702 cupsFilePuts(temp
, "BrowseAddress @LOCAL\n");
1706 cupsFilePuts(temp
, "# Disable printer sharing and shared printers.\n");
1707 cupsFilePuts(temp
, "Browsing Off\n");
1711 else if (!strcasecmp(line
, "LogLevel"))
1717 cupsFilePuts(temp
, "# Show troubleshooting information in error_log.\n");
1718 cupsFilePuts(temp
, "LogLevel debug\n");
1722 cupsFilePuts(temp
, "# Show general information in error_log.\n");
1723 cupsFilePuts(temp
, "LogLevel info\n");
1726 else if (!strcasecmp(line
, "<Policy") && !strcasecmp(value
, "default"))
1730 cupsFilePrintf(temp
, "%s %s>\n", line
, value
);
1733 else if (!strcasecmp(line
, "</Policy>"))
1740 if (!user_cancel_any
)
1741 cupsFilePuts(temp
, " # Only the owner or an administrator can cancel a job...\n"
1742 " <Limit Cancel-Job>\n"
1743 " Order deny,allow\n"
1751 cupsFilePuts(temp
, "</Policy>\n");
1753 else if (!strcasecmp(line
, "<Location"))
1756 if (!strcmp(value
, "/admin"))
1757 in_admin_location
= 1;
1758 if (!strcmp(value
, "/admin/conf"))
1759 in_conf_location
= 1;
1760 else if (!strcmp(value
, "/"))
1761 in_root_location
= 1;
1763 cupsFilePrintf(temp
, "%s %s>\n", line
, value
);
1765 else if (!strcasecmp(line
, "</Location>"))
1768 if (in_admin_location
)
1770 wrote_admin_location
= 1;
1773 cupsFilePuts(temp
, " # Allow remote administration...\n");
1775 cupsFilePuts(temp
, " # Restrict access to the admin pages...\n");
1777 cupsFilePuts(temp
, " Order allow,deny\n");
1780 cupsFilePuts(temp
, " Allow @LOCAL\n");
1782 cupsFilePuts(temp
, " Allow localhost\n");
1784 else if (in_conf_location
)
1786 wrote_conf_location
= 1;
1789 cupsFilePuts(temp
, " # Allow remote access to the configuration files...\n");
1791 cupsFilePuts(temp
, " # Restrict access to the configuration files...\n");
1793 cupsFilePuts(temp
, " Order allow,deny\n");
1796 cupsFilePuts(temp
, " Allow @LOCAL\n");
1798 cupsFilePuts(temp
, " Allow localhost\n");
1800 else if (in_root_location
)
1802 wrote_root_location
= 1;
1804 if (remote_admin
&& share_printers
)
1805 cupsFilePuts(temp
, " # Allow shared printing and remote administration...\n");
1806 else if (remote_admin
)
1807 cupsFilePuts(temp
, " # Allow remote administration...\n");
1808 else if (share_printers
)
1809 cupsFilePuts(temp
, " # Allow shared printing...\n");
1811 cupsFilePuts(temp
, " # Restrict access to the server...\n");
1813 cupsFilePuts(temp
, " Order allow,deny\n");
1815 if (remote_admin
|| share_printers
)
1816 cupsFilePuts(temp
, " Allow @LOCAL\n");
1818 cupsFilePuts(temp
, " Allow localhost\n");
1821 in_admin_location
= 0;
1822 in_conf_location
= 0;
1823 in_root_location
= 0;
1825 cupsFilePuts(temp
, "</Location>\n");
1827 else if (!strcasecmp(line
, "<Limit") && in_policy
)
1830 * See if the policy limit is for the Cancel-Job operation...
1833 char *valptr
; /* Pointer into value */
1838 if (!strcasecmp(value
, "cancel-job"))
1841 * Don't write anything for this limit section...
1848 cupsFilePrintf(temp
, " %s", line
);
1852 for (valptr
= value
; !isspace(*valptr
& 255) && *valptr
; valptr
++);
1857 if (!strcasecmp(value
, "cancel-job"))
1860 * Write everything except for this definition...
1866 cupsFilePrintf(temp
, " %s", value
);
1868 for (value
= valptr
; isspace(*value
& 255); value
++);
1871 cupsFilePuts(temp
, ">\n");
1874 else if (!strcasecmp(line
, "</Limit>") && in_cancel_job
)
1878 if (in_cancel_job
== 1)
1879 cupsFilePuts(temp
, " </Limit>\n");
1883 if (!user_cancel_any
)
1884 cupsFilePuts(temp
, " # Only the owner or an administrator can cancel a job...\n"
1885 " <Limit Cancel-Job>\n"
1886 " Order deny,allow\n"
1887 " Require user @OWNER @SYSTEM\n"
1892 else if ((in_admin_location
|| in_conf_location
|| in_root_location
) &&
1893 (!strcasecmp(line
, "Allow") || !strcasecmp(line
, "Deny") ||
1894 !strcasecmp(line
, "Order")))
1896 else if (in_cancel_job
== 2)
1898 else if (!strcasecmp(line
, "<Limit") && value
)
1899 cupsFilePrintf(temp
, " %s %s>\n", line
, value
);
1900 else if (line
[0] == '<')
1904 cupsFilePrintf(temp
, "%*s%s %s>\n", indent
, "", line
, value
);
1912 cupsFilePrintf(temp
, "%*s%s\n", indent
, "", line
);
1916 cupsFilePrintf(temp
, "%*s%s %s\n", indent
, "", line
, value
);
1918 cupsFilePrintf(temp
, "%*s%s\n", indent
, "", line
);
1922 * Write any missing info...
1925 if (!wrote_browsing
)
1927 if (remote_printers
|| share_printers
)
1929 if (remote_printers
&& share_printers
)
1930 cupsFilePuts(temp
, "# Enable printer sharing and shared printers.\n");
1931 else if (remote_printers
)
1932 cupsFilePuts(temp
, "# Show shared printers on the local network.\n");
1934 cupsFilePuts(temp
, "# Share local printers on the local network.\n");
1936 cupsFilePuts(temp
, "Browsing On\n");
1937 cupsFilePuts(temp
, "BrowseOrder allow,deny\n");
1939 if (remote_printers
)
1940 cupsFilePuts(temp
, "BrowseAllow @LOCAL\n");
1943 cupsFilePuts(temp
, "BrowseAddress @LOCAL\n");
1947 cupsFilePuts(temp
, "# Disable printer sharing and shared printers.\n");
1948 cupsFilePuts(temp
, "Browsing Off\n");
1952 if (!wrote_loglevel
)
1956 cupsFilePuts(temp
, "# Show troubleshooting information in error_log.\n");
1957 cupsFilePuts(temp
, "LogLevel debug\n");
1961 cupsFilePuts(temp
, "# Show general information in error_log.\n");
1962 cupsFilePuts(temp
, "LogLevel info\n");
1966 if (!wrote_port_listen
)
1968 if (share_printers
|| remote_admin
)
1970 cupsFilePuts(temp
, "# Allow remote access\n");
1971 cupsFilePrintf(temp
, "Listen *:%d\n", ippPort());
1975 cupsFilePuts(temp
, "# Only listen for connections from the local machine.\n");
1976 cupsFilePrintf(temp
, "Listen localhost:%d\n", ippPort());
1979 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1980 cupsFilePuts(temp
, "Listen " CUPS_DEFAULT_DOMAINSOCKET
"\n");
1981 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1984 if (!wrote_root_location
)
1986 if (remote_admin
&& share_printers
)
1987 cupsFilePuts(temp
, "# Allow shared printing and remote administration...\n");
1988 else if (remote_admin
)
1989 cupsFilePuts(temp
, "# Allow remote administration...\n");
1990 else if (share_printers
)
1991 cupsFilePuts(temp
, "# Allow shared printing...\n");
1993 cupsFilePuts(temp
, "# Restrict access to the server...\n");
1995 cupsFilePuts(temp
, "<Location />\n"
1996 " Order allow,deny\n");
1998 if (remote_admin
|| share_printers
)
1999 cupsFilePuts(temp
, " Allow @LOCAL\n");
2001 cupsFilePuts(temp
, " Allow localhost\n");
2003 cupsFilePuts(temp
, "</Location>\n");
2006 if (!wrote_admin_location
)
2009 cupsFilePuts(temp
, "# Allow remote administration...\n");
2011 cupsFilePuts(temp
, "# Restrict access to the admin pages...\n");
2013 cupsFilePuts(temp
, "<Location /admin>\n"
2014 " Order allow,deny\n");
2017 cupsFilePuts(temp
, " Allow @LOCAL\n");
2019 cupsFilePuts(temp
, " Allow localhost\n");
2021 cupsFilePuts(temp
, "</Location>\n");
2024 if (!wrote_conf_location
)
2027 cupsFilePuts(temp
, "# Allow remote access to the configuration files...\n");
2029 cupsFilePuts(temp
, "# Restrict access to the configuration files...\n");
2031 cupsFilePuts(temp
, "<Location /admin/conf>\n"
2033 " Require user @SYSTEM\n"
2034 " Order allow,deny\n");
2037 cupsFilePuts(temp
, " Allow @LOCAL\n");
2039 cupsFilePuts(temp
, " Allow localhost\n");
2041 cupsFilePuts(temp
, "</Location>\n");
2046 cupsFilePuts(temp
, "<Policy default>\n"
2047 " # Job-related operations must be done by the owner or an adminstrator...\n"
2048 " <Limit Send-Document Send-URI Hold-Job Release-Job "
2049 "Restart-Job Purge-Jobs Set-Job-Attributes "
2050 "Create-Job-Subscription Renew-Subscription "
2051 "Cancel-Subscription Get-Notifications Reprocess-Job "
2052 "Cancel-Current-Job Suspend-Current-Job Resume-Job "
2054 " Require user @OWNER @SYSTEM\n"
2055 " Order deny,allow\n"
2057 " # All administration operations require an adminstrator to authenticate...\n"
2058 " <Limit Pause-Printer Resume-Printer "
2059 "Set-Printer-Attributes Enable-Printer "
2060 "Disable-Printer Pause-Printer-After-Current-Job "
2061 "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer "
2062 "Activate-Printer Restart-Printer Shutdown-Printer "
2063 "Startup-Printer Promote-Job Schedule-Job-After "
2064 "CUPS-Add-Printer CUPS-Delete-Printer "
2065 "CUPS-Add-Class CUPS-Delete-Class "
2066 "CUPS-Accept-Jobs CUPS-Reject-Jobs "
2067 "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n"
2069 " Require user @SYSTEM\n"
2070 " Order deny,allow\n"
2073 if (!user_cancel_any
)
2074 cupsFilePuts(temp
, " # Only the owner or an administrator can cancel a job...\n"
2075 " <Limit Cancel-Job>\n"
2076 " Require user @OWNER @SYSTEM\n"
2077 " Order deny,allow\n"
2080 cupsFilePuts(temp
, " <Limit All>\n"
2081 " Order deny,allow\n"
2086 cupsFileClose(cupsd
);
2087 cupsFileClose(temp
);
2090 * Upload the configuration file to the server...
2093 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
2095 if (status
!= HTTP_CREATED
)
2097 cgiSetVariable("MESSAGE", cgiText(_("Unable to upload cupsd.conf file:")));
2098 cgiSetVariable("ERROR", httpStatus(status
));
2099 cgiStartHTML(cgiText(_("Change Settings")));
2100 cgiCopyTemplateLang("error.tmpl");
2104 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
2106 cgiStartHTML(cgiText(_("Change Settings")));
2107 cgiCopyTemplateLang("restart.tmpl");
2114 else if (cgiIsPOST())
2117 * Save hand-edited config file...
2120 http_status_t status
; /* PUT status */
2121 char tempfile
[1024]; /* Temporary new cupsd.conf */
2122 int tempfd
; /* Temporary file descriptor */
2123 cups_file_t
*temp
; /* Temporary file */
2124 const char *start
, /* Start of line */
2125 *end
; /* End of line */
2129 * Create a temporary file for the new cupsd.conf file...
2132 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
2134 cgiStartHTML(cgiText(_("Edit Configuration File")));
2135 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
2136 cgiSetVariable("ERROR", strerror(errno
));
2137 cgiCopyTemplateLang("error.tmpl");
2144 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
2146 cgiStartHTML(cgiText(_("Edit Configuration File")));
2147 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
2148 cgiSetVariable("ERROR", strerror(errno
));
2149 cgiCopyTemplateLang("error.tmpl");
2159 * Copy the cupsd.conf text from the form variable...
2162 start
= cgiGetVariable("CUPSDCONF");
2165 if ((end
= strstr(start
, "\r\n")) == NULL
)
2166 if ((end
= strstr(start
, "\n")) == NULL
)
2167 end
= start
+ strlen(start
);
2169 cupsFileWrite(temp
, start
, end
- start
);
2170 cupsFilePutChar(temp
, '\n');
2174 else if (*end
== '\n')
2180 cupsFileClose(temp
);
2183 * Upload the configuration file to the server...
2186 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
2188 if (status
!= HTTP_CREATED
)
2190 cgiSetVariable("MESSAGE", cgiText(_("Unable to upload cupsd.conf file:")));
2191 cgiSetVariable("ERROR", httpStatus(status
));
2193 cgiStartHTML(cgiText(_("Edit Configuration File")));
2194 cgiCopyTemplateLang("error.tmpl");
2198 cgiSetVariable("refresh_page", "5;/admin/?OP=redirect");
2200 cgiStartHTML(cgiText(_("Edit Configuration File")));
2201 cgiCopyTemplateLang("restart.tmpl");
2210 struct stat info
; /* cupsd.conf information */
2211 cups_file_t
*cupsd
; /* cupsd.conf file */
2212 char *buffer
; /* Buffer for entire file */
2213 char filename
[1024]; /* Filename */
2214 const char *server_root
; /* Location of config files */
2218 * Locate the cupsd.conf file...
2221 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
2222 server_root
= CUPS_SERVERROOT
;
2224 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
2227 * Figure out the size...
2230 if (stat(filename
, &info
))
2232 cgiStartHTML(cgiText(_("Edit Configuration File")));
2233 cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:")));
2234 cgiSetVariable("ERROR", strerror(errno
));
2235 cgiCopyTemplateLang("error.tmpl");
2242 if (info
.st_size
> (1024 * 1024))
2244 cgiStartHTML(cgiText(_("Edit Configuration File")));
2245 cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:")));
2246 cgiSetVariable("ERROR",
2247 cgiText(_("Unable to edit cupsd.conf files larger than "
2249 cgiCopyTemplateLang("error.tmpl");
2252 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
2253 (long)info
.st_size
);
2258 * Open the cupsd.conf file...
2261 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
2264 * Unable to open - log an error...
2267 cgiStartHTML(cgiText(_("Edit Configuration File")));
2268 cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:")));
2269 cgiSetVariable("ERROR", strerror(errno
));
2270 cgiCopyTemplateLang("error.tmpl");
2278 * Allocate memory and load the file into a string buffer...
2281 buffer
= calloc(1, info
.st_size
+ 1);
2283 cupsFileRead(cupsd
, buffer
, info
.st_size
);
2284 cupsFileClose(cupsd
);
2286 cgiSetVariable("CUPSDCONF", buffer
);
2290 * Show the current config file...
2293 cgiStartHTML("Edit Configuration File");
2295 printf("<!-- \"%s\" -->\n", filename
);
2297 cgiCopyTemplateLang("edit-config.tmpl");
2305 * 'do_delete_class()' - Delete a class...
2309 do_delete_class(http_t
*http
) /* I - HTTP connection */
2311 ipp_t
*request
; /* IPP request */
2312 char uri
[HTTP_MAX_URI
]; /* Job URI */
2313 const char *pclass
; /* Printer class name */
2316 cgiStartHTML(cgiText(_("Delete Class")));
2318 if (cgiGetVariable("CONFIRM") == NULL
)
2320 cgiCopyTemplateLang("class-confirm.tmpl");
2325 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2326 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
2327 "/classes/%s", pclass
);
2330 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2331 cgiCopyTemplateLang("error.tmpl");
2337 * Build a CUPS_DELETE_CLASS request, which requires the following
2340 * attributes-charset
2341 * attributes-natural-language
2345 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2347 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2351 * Do the request and get back a response...
2354 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2356 if (cupsLastError() > IPP_OK_CONFLICT
)
2357 cgiShowIPPError(_("Unable to delete class:"));
2359 cgiCopyTemplateLang("class-deleted.tmpl");
2366 * 'do_delete_printer()' - Delete a printer...
2370 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2372 ipp_t
*request
; /* IPP request */
2373 char uri
[HTTP_MAX_URI
]; /* Job URI */
2374 const char *printer
; /* Printer printer name */
2377 cgiStartHTML(cgiText(_("Delete Printer")));
2379 if (cgiGetVariable("CONFIRM") == NULL
)
2381 cgiCopyTemplateLang("printer-confirm.tmpl");
2386 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2387 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
2388 "/printers/%s", printer
);
2391 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2392 cgiCopyTemplateLang("error.tmpl");
2398 * Build a CUPS_DELETE_PRINTER request, which requires the following
2401 * attributes-charset
2402 * attributes-natural-language
2406 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2408 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2412 * Do the request and get back a response...
2415 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2417 if (cupsLastError() > IPP_OK_CONFLICT
)
2418 cgiShowIPPError(_("Unable to delete printer:"));
2420 cgiCopyTemplateLang("printer-deleted.tmpl");
2427 * 'do_export()' - Export printers to Samba...
2431 do_export(http_t
*http
) /* I - HTTP connection */
2433 int i
, j
; /* Looping vars */
2434 ipp_t
*request
, /* IPP request */
2435 *response
; /* IPP response */
2436 const char *username
, /* Samba username */
2437 *password
, /* Samba password */
2438 *export_all
; /* Export all printers? */
2439 int export_count
, /* Number of printers to export */
2440 printer_count
; /* Number of available printers */
2447 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2453 username
= cgiGetVariable("USERNAME");
2454 password
= cgiGetVariable("PASSWORD");
2455 export_all
= cgiGetVariable("EXPORT_ALL");
2456 export_count
= cgiGetSize("EXPORT_NAME");
2458 if (username
&& *username
&& password
&& *password
&& export_count
<= 1000)
2464 char userpass
[1024], /* Username%password */
2465 *argv
[1005]; /* Arguments */
2466 int argc
; /* Number of arguments */
2467 int pid
; /* Process ID of child */
2468 int status
; /* Status of command */
2471 fputs("DEBUG: Export printers...\n", stderr
);
2474 * Create the command-line for cupsaddsmb...
2477 snprintf(userpass
, sizeof(userpass
), "%s%%%s", username
, password
);
2479 argv
[0] = "cupsaddsmb";
2486 argv
[argc
++] = "-a";
2489 for (i
= 0; i
< export_count
; i
++)
2490 argv
[argc
++] = (char *)cgiGetArray("EXPORT_NAME", i
);
2496 * Run the command...
2499 if ((pid
= fork()) == 0)
2502 * Child goes here...
2506 open("/dev/null", O_RDONLY
);
2510 execvp("cupsaddsmb", argv
);
2511 perror("ERROR: Unable to execute cupsaddsmb");
2515 cgiSetVariable("ERROR", cgiText(_("Unable to fork process!")));
2519 * Parent goes here, wait for child to finish...
2522 while (wait(&status
) < 0);
2526 char message
[1024]; /* Error message */
2529 if (WIFEXITED(status
))
2531 switch (WEXITSTATUS(status
))
2534 cgiSetVariable("ERROR", cgiText(_("Unable to connect to server!")));
2538 cgiSetVariable("ERROR", cgiText(_("Unable to get printer "
2543 cgiSetVariable("ERROR", cgiText(_("Unable to convert PPD file!")));
2547 cgiSetVariable("ERROR", cgiText(_("Unable to copy Windows 2000 "
2548 "printer driver files!")));
2552 cgiSetVariable("ERROR", cgiText(_("Unable to install Windows "
2553 "2000 printer driver files!")));
2557 cgiSetVariable("ERROR", cgiText(_("Unable to copy Windows 9x "
2558 "printer driver files!")));
2562 cgiSetVariable("ERROR", cgiText(_("Unable to install Windows "
2563 "9x printer driver files!")));
2567 cgiSetVariable("ERROR", cgiText(_("Unable to set Windows "
2568 "printer driver!")));
2572 cgiSetVariable("ERROR", cgiText(_("No printer drivers found!")));
2576 cgiSetVariable("ERROR", cgiText(_("Unable to execute "
2577 "cupsaddsmb command!")));
2581 snprintf(message
, sizeof(message
),
2582 cgiText(_("cupsaddsmb failed with status %d")),
2583 WEXITSTATUS(status
));
2585 cgiSetVariable("ERROR", message
);
2591 snprintf(message
, sizeof(message
),
2592 cgiText(_("cupsaddsmb crashed on signal %d")),
2595 cgiSetVariable("ERROR", message
);
2600 cgiCopyTemplateLang("samba-exported");
2606 else if (username
&& !*username
)
2607 cgiSetVariable("ERROR",
2608 cgiText(_("A Samba username is required to export "
2609 "printer drivers!")));
2610 else if (username
&& (!password
|| !*password
))
2611 cgiSetVariable("ERROR",
2612 cgiText(_("A Samba password is required to export "
2613 "printer drivers!")));
2616 * Get list of available printers...
2619 cgiSetSize("PRINTER_NAME", 0);
2620 cgiSetSize("PRINTER_EXPORT", 0);
2622 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2624 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2627 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2628 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2629 CUPS_PRINTER_IMPLICIT
);
2631 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2632 "requested-attributes", NULL
, "printer-name");
2634 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2636 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2637 ippDelete(response
);
2641 printer_count
= cgiGetSize("PRINTER_NAME");
2643 for (i
= 0; i
< printer_count
; i
++)
2645 for (j
= 0; j
< export_count
; j
++)
2646 if (!strcasecmp(cgiGetArray("PRINTER_NAME", i
),
2647 cgiGetArray("EXPORT_NAME", j
)))
2650 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2659 cgiCopyTemplateLang("samba-export.tmpl");
2665 * 'do_menu()' - Show the main menu...
2669 do_menu(http_t
*http
) /* I - HTTP connection */
2671 cups_file_t
*cupsd
; /* cupsd.conf file */
2672 char line
[1024], /* Line from cupsd.conf file */
2673 *value
; /* Value on line */
2674 const char *server_root
; /* Location of config files */
2675 const char *datadir
; /* Location of data files */
2676 ipp_t
*request
, /* IPP request */
2677 *response
; /* IPP response */
2678 ipp_attribute_t
*attr
; /* IPP attribute */
2682 * Locate the cupsd.conf file...
2685 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
2686 server_root
= CUPS_SERVERROOT
;
2688 snprintf(line
, sizeof(line
), "%s/cupsd.conf", server_root
);
2690 cgiStartHTML(cgiText(_("Administration")));
2692 printf("<!-- \"%s\" -->\n", line
);
2695 * Open the cupsd.conf file...
2698 if ((cupsd
= cupsFileOpen(line
, "r")) == NULL
)
2701 * Unable to open - log an error...
2704 cgiSetVariable("MESSAGE", cgiText(_("Unable to open cupsd.conf file:")));
2705 cgiSetVariable("ERROR", strerror(errno
));
2706 cgiCopyTemplateLang("error.tmpl");
2714 * Read the file, keeping track of what settings are enabled...
2717 int remote_access
= 0, /* Remote access allowed? */
2718 remote_admin
= 0, /* Remote administration allowed? */
2719 browsing
= 1, /* Browsing enabled? */
2720 browse_allow
= 1, /* Browse address set? */
2721 browse_address
= 0, /* Browse address set? */
2722 cancel_policy
= 1, /* Cancel-job policy set? */
2723 debug_logging
= 0; /* LogLevel debug set? */
2724 int linenum
= 0, /* Line number in file */
2725 in_policy
= 0, /* In a policy section? */
2726 in_cancel_job
= 0, /* In a cancel-job section? */
2727 in_admin_location
= 0; /* In the /admin location? */
2730 while (cupsFileGetConf(cupsd
, line
, sizeof(line
), &value
, &linenum
))
2732 if (!strcasecmp(line
, "Port"))
2736 else if (!strcasecmp(line
, "Listen"))
2738 char *port
; /* Pointer to port number, if any */
2741 if ((port
= strrchr(value
, ':')) != NULL
)
2744 if (strcasecmp(value
, "localhost") && strcmp(value
, "127.0.0.1"))
2747 else if (!strcasecmp(line
, "Browsing"))
2749 browsing
= !strcasecmp(value
, "yes") || !strcasecmp(value
, "on") ||
2750 !strcasecmp(value
, "true");
2752 else if (!strcasecmp(line
, "BrowseAddress"))
2756 else if (!strcasecmp(line
, "BrowseAllow"))
2760 else if (!strcasecmp(line
, "BrowseOrder"))
2762 browse_allow
= !strncasecmp(value
, "deny,", 5);
2764 else if (!strcasecmp(line
, "LogLevel"))
2766 debug_logging
= !strncasecmp(value
, "debug", 5);
2768 else if (!strcasecmp(line
, "<Policy") && !strcasecmp(value
, "default"))
2772 else if (!strcasecmp(line
, "</Policy>"))
2776 else if (!strcasecmp(line
, "<Limit") && in_policy
)
2779 * See if the policy limit is for the Cancel-Job operation...
2782 char *valptr
; /* Pointer into value */
2787 for (valptr
= value
; !isspace(*valptr
& 255) && *valptr
; valptr
++);
2792 if (!strcasecmp(value
, "cancel-job") || !strcasecmp(value
, "all"))
2798 for (value
= valptr
; isspace(*value
& 255); value
++);
2801 else if (!strcasecmp(line
, "</Limit>"))
2805 else if (!strcasecmp(line
, "Require") && in_cancel_job
)
2809 else if (!strcasecmp(line
, "<Location") && !strcasecmp(value
, "/admin"))
2811 in_admin_location
= 1;
2813 else if (!strcasecmp(line
, "</Location>"))
2815 in_admin_location
= 0;
2817 else if (!strcasecmp(line
, "Allow") && in_admin_location
&&
2818 strcasecmp(value
, "localhost") && strcasecmp(value
, "127.0.0.1"))
2824 cupsFileClose(cupsd
);
2826 if (browsing
&& browse_allow
)
2827 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2829 if (remote_access
&& browsing
&& browse_address
)
2830 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2832 if (remote_access
&& remote_admin
)
2833 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2836 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2839 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2843 * Get the list of printers and their devices...
2846 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2848 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2849 "requested-attributes", NULL
, "device-uri");
2851 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2852 CUPS_PRINTER_LOCAL
);
2853 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2854 CUPS_PRINTER_LOCAL
);
2856 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2859 * Got the printer list, now load the devices...
2862 int i
; /* Looping var */
2863 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2864 char *printer_device
; /* Current printer device */
2868 * Allocate an array and copy the device strings...
2871 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2873 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2875 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2877 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2881 * Free the printer list and get the device list...
2884 ippDelete(response
);
2886 request
= ippNewRequest(CUPS_GET_DEVICES
);
2888 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2891 * Got the device list, let's parse it...
2894 const char *device_uri
, /* device-uri attribute value */
2895 *device_make_and_model
, /* device-make-and-model value */
2896 *device_info
; /* device-info value */
2899 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2902 * Skip leading attributes until we hit a device...
2905 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2912 * Pull the needed attributes from this device...
2916 device_make_and_model
= NULL
;
2919 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2921 if (!strcmp(attr
->name
, "device-info") &&
2922 attr
->value_tag
== IPP_TAG_TEXT
)
2923 device_info
= attr
->values
[0].string
.text
;
2925 if (!strcmp(attr
->name
, "device-make-and-model") &&
2926 attr
->value_tag
== IPP_TAG_TEXT
)
2927 device_make_and_model
= attr
->values
[0].string
.text
;
2929 if (!strcmp(attr
->name
, "device-uri") &&
2930 attr
->value_tag
== IPP_TAG_URI
)
2931 device_uri
= attr
->values
[0].string
.text
;
2937 * See if we have everything needed...
2940 if (device_info
&& device_make_and_model
&& device_uri
&&
2941 strcasecmp(device_make_and_model
, "unknown") &&
2942 strchr(device_uri
, ':'))
2945 * Yes, now see if there is already a printer for this
2949 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2952 * Not found, so it must be a new printer...
2955 char options
[1024], /* Form variables for this device */
2956 *options_ptr
; /* Pointer into string */
2957 const char *ptr
; /* Pointer into device string */
2961 * Format the printer name variable for this device...
2963 * We use the device-info string first, then device-uri,
2964 * and finally device-make-and-model to come up with a
2968 strcpy(options
, "PRINTER_NAME=");
2969 options_ptr
= options
+ strlen(options
);
2971 if (strncasecmp(device_info
, "unknown", 7))
2973 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2976 ptr
= device_make_and_model
;
2979 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2981 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' || *ptr
== '.')
2982 *options_ptr
++ = *ptr
;
2983 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2984 *options_ptr
++ = '_';
2985 else if (*ptr
== '?' || *ptr
== '(')
2989 * Then add the make and model in the printer info, so
2990 * that MacOS clients see something reasonable...
2993 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2995 sizeof(options
) - (options_ptr
- options
));
2996 options_ptr
+= strlen(options_ptr
);
2998 cgiFormEncode(options_ptr
, device_make_and_model
,
2999 sizeof(options
) - (options_ptr
- options
));
3000 options_ptr
+= strlen(options_ptr
);
3003 * Then copy the device URI...
3006 strlcpy(options_ptr
, "&DEVICE_URI=",
3007 sizeof(options
) - (options_ptr
- options
));
3008 options_ptr
+= strlen(options_ptr
);
3010 cgiFormEncode(options_ptr
, device_uri
,
3011 sizeof(options
) - (options_ptr
- options
));
3012 options_ptr
+= strlen(options_ptr
);
3014 if (options_ptr
< (options
+ sizeof(options
) - 1))
3016 *options_ptr
++ = '|';
3017 cgiFormEncode(options_ptr
, device_make_and_model
,
3018 sizeof(options
) - (options_ptr
- options
));
3022 * Finally, set the form variables for this printer...
3025 cgiSetArray("device_info", i
, device_info
);
3026 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
3027 cgiSetArray("device_options", i
, options
);
3028 cgiSetArray("device_uri", i
, device_uri
);
3037 ippDelete(response
);
3040 * Free the device list...
3043 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
3045 printer_device
= (char *)cupsArrayNext(printer_devices
))
3046 free(printer_device
);
3048 cupsArrayDelete(printer_devices
);
3053 * See if Samba and the Windows drivers are installed...
3056 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
3057 datadir
= CUPS_DATADIR
;
3059 snprintf(line
, sizeof(line
), "%s/drivers/pscript5.dll", datadir
);
3060 if (!access(line
, 0))
3063 * Found Windows 2000 driver file, see if we have smbclient and
3067 if (cupsFileFind("smbclient", getenv("PATH"), line
, sizeof(line
)) &&
3068 cupsFileFind("rpcclient", getenv("PATH"), line
, sizeof(line
)))
3069 cgiSetVariable("HAVE_SAMBA", "Y");
3072 if (!cupsFileFind("smbclient", getenv("PATH"), line
, sizeof(line
)))
3073 fputs("ERROR: smbclient not found!\n", stderr
);
3075 if (!cupsFileFind("rpcclient", getenv("PATH"), line
, sizeof(line
)))
3076 fputs("ERROR: rpcclient not found!\n", stderr
);
3083 * Finally, show the main menu template...
3086 cgiCopyTemplateLang("admin.tmpl");
3093 * 'do_printer_op()' - Do a printer operation.
3097 do_printer_op(http_t
*http
, /* I - HTTP connection */
3098 ipp_op_t op
, /* I - Operation to perform */
3099 const char *title
) /* I - Title of page */
3101 ipp_t
*request
; /* IPP request */
3102 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3103 const char *printer
, /* Printer name (purge-jobs) */
3104 *is_class
; /* Is a class? */
3107 is_class
= cgiGetVariable("IS_CLASS");
3108 printer
= cgiGetVariable("PRINTER_NAME");
3112 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3113 cgiStartHTML(title
);
3114 cgiCopyTemplateLang("error.tmpl");
3120 * Build a printer request, which requires the following
3123 * attributes-charset
3124 * attributes-natural-language
3128 request
= ippNewRequest(op
);
3130 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
3131 is_class
? "/classes/%s" : "/printers/%s", printer
);
3132 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3136 * Do the request and get back a response...
3139 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3141 if (cupsLastError() > IPP_OK_CONFLICT
)
3143 cgiStartHTML(title
);
3144 cgiShowIPPError(_("Unable to change printer:"));
3149 * Redirect successful updates back to the printer page...
3152 char url
[1024], /* Printer/class URL */
3153 refresh
[1024]; /* Refresh URL */
3156 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3157 cgiFormEncode(uri
, url
, sizeof(uri
));
3158 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
3159 cgiSetVariable("refresh_page", refresh
);
3161 cgiStartHTML(title
);
3163 if (op
== IPP_PAUSE_PRINTER
)
3164 cgiCopyTemplateLang("printer-stop.tmpl");
3165 else if (op
== IPP_RESUME_PRINTER
)
3166 cgiCopyTemplateLang("printer-start.tmpl");
3167 else if (op
== CUPS_ACCEPT_JOBS
)
3168 cgiCopyTemplateLang("printer-accept.tmpl");
3169 else if (op
== CUPS_REJECT_JOBS
)
3170 cgiCopyTemplateLang("printer-reject.tmpl");
3171 else if (op
== IPP_PURGE_JOBS
)
3172 cgiCopyTemplateLang("printer-purge.tmpl");
3173 else if (op
== CUPS_SET_DEFAULT
)
3174 cgiCopyTemplateLang("printer-default.tmpl");
3182 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
3186 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
3188 int i
; /* Looping var */
3189 ipp_t
*request
, /* IPP request */
3190 *response
; /* IPP response */
3191 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3192 const char *printer
, /* Printer name (purge-jobs) */
3193 *is_class
, /* Is a class? */
3194 *users
, /* List of users or groups */
3195 *type
; /* Allow/deny type */
3196 int num_users
; /* Number of users */
3197 char *ptr
, /* Pointer into users string */
3198 *end
, /* Pointer to end of users string */
3199 quote
; /* Quote character */
3200 ipp_attribute_t
*attr
; /* Attribute */
3201 static const char * const attrs
[] = /* Requested attributes */
3203 "requesting-user-name-allowed",
3204 "requesting-user-name-denied"
3208 is_class
= cgiGetVariable("IS_CLASS");
3209 printer
= cgiGetVariable("PRINTER_NAME");
3213 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3214 cgiStartHTML(cgiText(_("Set Allowed Users")));
3215 cgiCopyTemplateLang("error.tmpl");
3220 users
= cgiGetVariable("users");
3221 type
= cgiGetVariable("type");
3223 if (!users
|| !type
||
3224 (strcmp(type
, "requesting-user-name-allowed") &&
3225 strcmp(type
, "requesting-user-name-denied")))
3228 * Build a Get-Printer-Attributes request, which requires the following
3231 * attributes-charset
3232 * attributes-natural-language
3234 * requested-attributes
3237 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
3239 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
3240 is_class
? "/classes/%s" : "/printers/%s", printer
);
3241 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3244 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
3245 "requested-attributes",
3246 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
3249 * Do the request and get back a response...
3252 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
3254 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3256 ippDelete(response
);
3259 cgiStartHTML(cgiText(_("Set Allowed Users")));
3261 if (cupsLastError() > IPP_OK_CONFLICT
)
3262 cgiShowIPPError(_("Unable to get printer attributes:"));
3264 cgiCopyTemplateLang("users.tmpl");
3271 * Save the changes...
3274 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
3277 * Skip whitespace and commas...
3280 while (*ptr
== ',' || isspace(*ptr
& 255))
3283 if (*ptr
== '\'' || *ptr
== '\"')
3286 * Scan quoted name...
3291 for (end
= ptr
; *end
; end
++)
3298 * Scan space or comma-delimited name...
3301 for (end
= ptr
; *end
; end
++)
3302 if (isspace(*end
& 255) || *end
== ',')
3307 * Advance to the next name...
3314 * Build a CUPS-Add-Printer/Class request, which requires the following
3317 * attributes-charset
3318 * attributes-natural-language
3320 * requesting-user-name-{allowed,denied}
3323 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3325 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
3326 is_class
? "/classes/%s" : "/printers/%s", printer
);
3327 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3331 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
3332 "requesting-user-name-allowed", NULL
, "all");
3335 attr
= ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
3336 type
, num_users
, NULL
, NULL
);
3338 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
3341 * Skip whitespace and commas...
3344 while (*ptr
== ',' || isspace(*ptr
& 255))
3347 if (*ptr
== '\'' || *ptr
== '\"')
3350 * Scan quoted name...
3355 for (end
= ptr
; *end
; end
++)
3362 * Scan space or comma-delimited name...
3365 for (end
= ptr
; *end
; end
++)
3366 if (isspace(*end
& 255) || *end
== ',')
3371 * Terminate the name...
3381 attr
->values
[i
].string
.text
= strdup(ptr
);
3384 * Advance to the next name...
3392 * Do the request and get back a response...
3395 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3397 if (cupsLastError() > IPP_OK_CONFLICT
)
3399 cgiStartHTML(cgiText(_("Set Allowed Users")));
3400 cgiShowIPPError(_("Unable to change printer:"));
3405 * Redirect successful updates back to the printer page...
3408 char url
[1024], /* Printer/class URL */
3409 refresh
[1024]; /* Refresh URL */
3412 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3413 cgiFormEncode(uri
, url
, sizeof(uri
));
3414 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
3415 cgiSetVariable("refresh_page", refresh
);
3417 cgiStartHTML(cgiText(_("Set Allowed Users")));
3419 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3420 "printer-modified.tmpl");
3429 * 'do_set_sharing()' - Set printer-is-shared value...
3433 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3435 ipp_t
*request
, /* IPP request */
3436 *response
; /* IPP response */
3437 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3438 const char *printer
, /* Printer name */
3439 *is_class
, /* Is a class? */
3440 *shared
; /* Sharing value */
3443 is_class
= cgiGetVariable("IS_CLASS");
3444 printer
= cgiGetVariable("PRINTER_NAME");
3445 shared
= cgiGetVariable("SHARED");
3447 if (!printer
|| !shared
)
3449 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3450 cgiStartHTML(cgiText(_("Set Publishing")));
3451 cgiCopyTemplateLang("error.tmpl");
3457 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3458 * following attributes:
3460 * attributes-charset
3461 * attributes-natural-language
3466 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3468 httpAssembleURIf(uri
, sizeof(uri
), "ipp", NULL
, "localhost", 0,
3469 is_class
? "/classes/%s" : "/printers/%s", printer
);
3470 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3473 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3476 * Do the request and get back a response...
3479 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3481 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3483 ippDelete(response
);
3486 if (cupsLastError() > IPP_OK_CONFLICT
)
3488 cgiStartHTML(cgiText(_("Set Publishing")));
3489 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3494 * Redirect successful updates back to the printer page...
3497 char url
[1024], /* Printer/class URL */
3498 refresh
[1024]; /* Refresh URL */
3501 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3502 cgiFormEncode(uri
, url
, sizeof(uri
));
3503 snprintf(refresh
, sizeof(refresh
), "5;/admin/?OP=redirect&URL=%s", uri
);
3504 cgiSetVariable("refresh_page", refresh
);
3506 cgiStartHTML(cgiText(_("Set Publishing")));
3507 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3508 "printer-modified.tmpl");
3516 * 'match_string()' - Return the number of matching characters.
3519 static int /* O - Number of matching characters */
3520 match_string(const char *a
, /* I - First string */
3521 const char *b
) /* I - Second string */
3523 int count
; /* Number of matching characters */
3527 * Loop through both strings until we hit the end of either or we find
3528 * a non-matching character. For the purposes of comparison, we ignore
3529 * whitespace and do a case-insensitive comparison so that we have a
3530 * better chance of finding a match...
3533 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
3536 * Skip leading whitespace characters...
3539 while (isspace(*a
& 255))
3542 while (isspace(*b
& 255))
3546 * Break out if we run out of characters...
3553 * Do a case-insensitive comparison of the next two chars...
3556 if (tolower(*a
& 255) != tolower(*b
& 255))
3565 * End of "$Id: admin.c 4943 2006-01-18 20:30:42Z mike $".