2 * "$Id: admin.c 6361 2007-03-19 16:01:28Z mike $"
4 * Administration CGI for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2007 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_add_rss_subscription() - Add a RSS subscription.
28 * do_am_class() - Add or modify a class.
29 * do_am_printer() - Add or modify a printer.
30 * do_cancel_subscription() - Cancel a subscription.
31 * do_config_printer() - Configure the default options for a printer.
32 * do_config_server() - Configure server settings.
33 * do_delete_class() - Delete a class...
34 * do_delete_printer() - Delete a printer...
35 * do_export() - Export printers to Samba...
36 * do_menu() - Show the main menu...
37 * do_printer_op() - Do a printer operation.
38 * do_set_allowed_users() - Set the allowed/denied users for a queue.
39 * do_set_sharing() - Set printer-is-shared value...
40 * match_string() - Return the number of matching characters.
44 * Include necessary headers...
47 #include "cgi-private.h"
48 #include <cups/adminutil.h>
49 #include <cups/file.h>
60 static void do_add_rss_subscription(http_t
*http
);
61 static void do_am_class(http_t
*http
, int modify
);
62 static void do_am_printer(http_t
*http
, int modify
);
63 static void do_cancel_subscription(http_t
*http
);
64 static void do_config_printer(http_t
*http
);
65 static void do_config_server(http_t
*http
);
66 static void do_delete_class(http_t
*http
);
67 static void do_delete_printer(http_t
*http
);
68 static void do_export(http_t
*http
);
69 static void do_menu(http_t
*http
);
70 static void do_printer_op(http_t
*http
,
71 ipp_op_t op
, const char *title
);
72 static void do_set_allowed_users(http_t
*http
);
73 static void do_set_sharing(http_t
*http
);
74 static int match_string(const char *a
, const char *b
);
78 * 'main()' - Main entry for CGI.
81 int /* O - Exit status */
82 main(int argc
, /* I - Number of command-line arguments */
83 char *argv
[]) /* I - Command-line arguments */
85 http_t
*http
; /* Connection to the server */
86 const char *op
; /* Operation name */
90 * Connect to the HTTP server...
93 fputs("DEBUG: admin.cgi started...\n", stderr
);
95 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
99 perror("ERROR: Unable to connect to cupsd");
100 fprintf(stderr
, "DEBUG: cupsServer()=\"%s\"\n",
101 cupsServer() ? cupsServer() : "(null)");
102 fprintf(stderr
, "DEBUG: ippPort()=%d\n", ippPort());
103 fprintf(stderr
, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
107 fprintf(stderr
, "DEBUG: http=%p\n", http
);
110 * Set the web interface section...
113 cgiSetVariable("SECTION", "admin");
116 * See if we have form data...
119 if (!cgiInitialize())
122 * Nope, send the administration menu...
125 fputs("DEBUG: No form data, showing main menu...\n", stderr
);
129 else if ((op
= cgiGetVariable("OP")) != NULL
)
132 * Do the operation...
135 fprintf(stderr
, "DEBUG: op=\"%s\"...\n", op
);
137 if (!strcmp(op
, "redirect"))
139 const char *url
; /* Redirection URL... */
140 char prefix
[1024]; /* URL prefix */
144 snprintf(prefix
, sizeof(prefix
), "https://%s:%s",
145 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
147 snprintf(prefix
, sizeof(prefix
), "http://%s:%s",
148 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
150 if ((url
= cgiGetVariable("URL")) != NULL
)
151 printf("Location: %s%s\n\n", prefix
, url
);
153 printf("Location: %s/admin\n\n", prefix
);
155 else if (!strcmp(op
, "start-printer"))
156 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Printer")));
157 else if (!strcmp(op
, "stop-printer"))
158 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Printer")));
159 else if (!strcmp(op
, "start-class"))
160 do_printer_op(http
, IPP_RESUME_PRINTER
, cgiText(_("Start Class")));
161 else if (!strcmp(op
, "stop-class"))
162 do_printer_op(http
, IPP_PAUSE_PRINTER
, cgiText(_("Stop Class")));
163 else if (!strcmp(op
, "accept-jobs"))
164 do_printer_op(http
, CUPS_ACCEPT_JOBS
, cgiText(_("Accept Jobs")));
165 else if (!strcmp(op
, "reject-jobs"))
166 do_printer_op(http
, CUPS_REJECT_JOBS
, cgiText(_("Reject Jobs")));
167 else if (!strcmp(op
, "purge-jobs"))
168 do_printer_op(http
, IPP_PURGE_JOBS
, cgiText(_("Purge Jobs")));
169 else if (!strcmp(op
, "set-allowed-users"))
170 do_set_allowed_users(http
);
171 else if (!strcmp(op
, "set-as-default"))
172 do_printer_op(http
, CUPS_SET_DEFAULT
, cgiText(_("Set As Default")));
173 else if (!strcmp(op
, "set-sharing"))
174 do_set_sharing(http
);
175 else if (!strcmp(op
, "add-class"))
176 do_am_class(http
, 0);
177 else if (!strcmp(op
, "add-printer"))
178 do_am_printer(http
, 0);
179 else if (!strcmp(op
, "modify-class"))
180 do_am_class(http
, 1);
181 else if (!strcmp(op
, "modify-printer"))
182 do_am_printer(http
, 1);
183 else if (!strcmp(op
, "delete-class"))
184 do_delete_class(http
);
185 else if (!strcmp(op
, "delete-printer"))
186 do_delete_printer(http
);
187 else if (!strcmp(op
, "set-printer-options"))
188 do_config_printer(http
);
189 else if (!strcmp(op
, "config-server"))
190 do_config_server(http
);
191 else if (!strcmp(op
, "export-samba"))
193 else if (!strcmp(op
, "add-rss-subscription"))
194 do_add_rss_subscription(http
);
195 else if (!strcmp(op
, "cancel-subscription"))
196 do_cancel_subscription(http
);
200 * Bad operation code... Display an error...
203 cgiStartHTML(cgiText(_("Administration")));
204 cgiCopyTemplateLang("error-op.tmpl");
211 * Form data but no operation code... Display an error...
214 cgiStartHTML(cgiText(_("Administration")));
215 cgiCopyTemplateLang("error-op.tmpl");
220 * Close the HTTP server connection...
226 * Return with no errors...
234 * 'do_add_rss_subscription()' - Add a RSS subscription.
238 do_add_rss_subscription(http_t
*http
) /* I - HTTP connection */
240 ipp_t
*request
, /* IPP request data */
241 *response
; /* IPP response data */
242 char rss_uri
[1024]; /* RSS notify-recipient URI */
243 int num_events
; /* Number of events */
244 const char *events
[12], /* Subscribed events */
245 *subscription_name
, /* Subscription name */
246 *printer_uri
, /* Printer URI */
247 *ptr
, /* Pointer into name */
248 *user
; /* Username */
249 int max_events
; /* Maximum number of events */
253 * See if we have all of the required information...
256 subscription_name
= cgiGetVariable("SUBSCRIPTION_NAME");
257 printer_uri
= cgiGetVariable("PRINTER_URI");
260 if (cgiGetVariable("EVENT_JOB_CREATED"))
261 events
[num_events
++] = "job-created";
262 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
263 events
[num_events
++] = "job-completed";
264 if (cgiGetVariable("EVENT_JOB_STOPPED"))
265 events
[num_events
++] = "job-stopped";
266 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
267 events
[num_events
++] = "job-config-changed";
268 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
269 events
[num_events
++] = "printer-stopped";
270 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
271 events
[num_events
++] = "printer-added";
272 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
273 events
[num_events
++] = "printer-modified";
274 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
275 events
[num_events
++] = "printer-deleted";
276 if (cgiGetVariable("EVENT_SERVER_STARTED"))
277 events
[num_events
++] = "server-started";
278 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
279 events
[num_events
++] = "server-stopped";
280 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
281 events
[num_events
++] = "server-restarted";
282 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
283 events
[num_events
++] = "server-audit";
285 if ((ptr
= cgiGetVariable("MAX_EVENTS")) != NULL
)
286 max_events
= atoi(ptr
);
290 if (!subscription_name
|| !printer_uri
|| !num_events
||
291 max_events
<= 0 || max_events
> 9999)
294 * Don't have everything we need, so get the available printers
295 * and classes and (re)show the add page...
298 request
= ippNewRequest(CUPS_GET_PRINTERS
);
299 response
= cupsDoRequest(http
, request
, "/");
301 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
305 cgiStartHTML(cgiText(_("Add RSS Subscription")));
307 cgiCopyTemplateLang("add-rss-subscription.tmpl");
314 * Validate the subscription name...
317 for (ptr
= subscription_name
; *ptr
; ptr
++)
318 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
319 *ptr
== '?' || *ptr
== '#')
324 cgiSetVariable("ERROR",
325 cgiText(_("The subscription name may not "
326 "contain spaces, slashes (/), question marks (?), "
327 "or the pound sign (#).")));
328 cgiStartHTML(_("Add RSS Subscription"));
329 cgiCopyTemplateLang("error.tmpl");
335 * Add the subscription...
338 ptr
= subscription_name
+ strlen(subscription_name
) - 4;
339 if (ptr
< subscription_name
|| strcmp(ptr
, ".rss"))
340 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
341 NULL
, NULL
, 0, "/%s.rss?max_events=%d", subscription_name
,
344 httpAssembleURIf(HTTP_URI_CODING_ALL
, rss_uri
, sizeof(rss_uri
), "rss",
345 NULL
, NULL
, 0, "/%s?max_events=%d", subscription_name
,
348 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
350 if (!strcasecmp(printer_uri
, "#ALL#"))
351 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
352 NULL
, "ipp://localhost/");
354 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
357 if ((user
= getenv("REMOTE_USER")) == NULL
)
360 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
363 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_URI
,
364 "notify-recipient-uri", NULL
, rss_uri
);
365 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
366 num_events
, NULL
, events
);
367 ippAddInteger(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_INTEGER
,
368 "notify-lease-duration", 0);
370 ippDelete(cupsDoRequest(http
, request
, "/"));
372 if (cupsLastError() > IPP_OK_CONFLICT
)
374 cgiStartHTML(_("Add RSS Subscription"));
375 cgiShowIPPError(_("Unable to add RSS subscription:"));
380 * Redirect successful updates back to the admin page...
383 cgiSetVariable("refresh_page", "5;URL=/admin");
384 cgiStartHTML(_("Add RSS Subscription"));
385 cgiCopyTemplateLang("subscription-added.tmpl");
393 * 'do_am_class()' - Add or modify a class.
397 do_am_class(http_t
*http
, /* I - HTTP connection */
398 int modify
) /* I - Modify the printer? */
400 int i
, j
; /* Looping vars */
401 int element
; /* Element number */
402 int num_printers
; /* Number of printers */
403 ipp_t
*request
, /* IPP request */
404 *response
; /* IPP response */
405 ipp_attribute_t
*attr
; /* member-uris attribute */
406 char uri
[HTTP_MAX_URI
]; /* Device or printer URI */
407 const char *name
, /* Pointer to class name */
408 *ptr
; /* Pointer to CGI variable */
409 const char *title
; /* Title of page */
410 static const char * const pattrs
[] = /* Requested printer attributes */
418 title
= cgiText(modify
? _("Modify Class") : _("Add Class"));
419 name
= cgiGetVariable("PRINTER_NAME");
421 if (cgiGetVariable("PRINTER_LOCATION") == NULL
)
424 * Build a CUPS_GET_PRINTERS request, which requires the
425 * following attributes:
428 * attributes-natural-language
431 request
= ippNewRequest(CUPS_GET_PRINTERS
);
434 * Do the request and get back a response...
437 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
440 * Create MEMBER_URIS and MEMBER_NAMES arrays...
443 for (element
= 0, attr
= response
->attrs
;
446 if (attr
->name
&& !strcmp(attr
->name
, "printer-uri-supported"))
448 if ((ptr
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
&&
449 (!name
|| strcasecmp(name
, ptr
+ 1)))
452 * Don't show the current class...
455 cgiSetArray("MEMBER_URIS", element
, attr
->values
[0].string
.text
);
460 for (element
= 0, attr
= response
->attrs
;
463 if (attr
->name
&& !strcmp(attr
->name
, "printer-name"))
465 if (!name
|| strcasecmp(name
, attr
->values
[0].string
.text
))
468 * Don't show the current class...
471 cgiSetArray("MEMBER_NAMES", element
, attr
->values
[0].string
.text
);
476 num_printers
= cgiGetSize("MEMBER_URIS");
486 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
487 * following attributes:
490 * attributes-natural-language
494 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
496 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
497 "localhost", 0, "/classes/%s", name
);
498 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
501 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
502 "requested-attributes",
503 (int)(sizeof(pattrs
) / sizeof(pattrs
[0])),
507 * Do the request and get back a response...
510 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
512 if ((attr
= ippFindAttribute(response
, "member-names",
513 IPP_TAG_NAME
)) != NULL
)
516 * Mark any current members in the class...
519 for (j
= 0; j
< num_printers
; j
++)
520 cgiSetArray("MEMBER_SELECTED", j
, "");
522 for (i
= 0; i
< attr
->num_values
; i
++)
524 for (j
= 0; j
< num_printers
; j
++)
526 if (!strcasecmp(attr
->values
[i
].string
.text
,
527 cgiGetArray("MEMBER_NAMES", j
)))
529 cgiSetArray("MEMBER_SELECTED", j
, "SELECTED");
536 if ((attr
= ippFindAttribute(response
, "printer-info",
537 IPP_TAG_TEXT
)) != NULL
)
538 cgiSetVariable("PRINTER_INFO", attr
->values
[0].string
.text
);
540 if ((attr
= ippFindAttribute(response
, "printer-location",
541 IPP_TAG_TEXT
)) != NULL
)
542 cgiSetVariable("PRINTER_LOCATION", attr
->values
[0].string
.text
);
548 * Update the location and description of an existing printer...
552 cgiCopyTemplateLang("modify-class.tmpl");
557 * Get the name, location, and description for a new printer...
561 cgiCopyTemplateLang("add-class.tmpl");
569 for (ptr
= name
; *ptr
; ptr
++)
570 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
573 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
575 cgiSetVariable("ERROR",
576 cgiText(_("The class name may only contain up to "
577 "127 printable characters and may not "
578 "contain spaces, slashes (/), or the "
579 "pound sign (#).")));
581 cgiCopyTemplateLang("error.tmpl");
587 * Build a CUPS_ADD_CLASS request, which requires the following
591 * attributes-natural-language
595 * printer-is-accepting-jobs
600 request
= ippNewRequest(CUPS_ADD_CLASS
);
602 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
603 "localhost", 0, "/classes/%s",
604 cgiGetVariable("PRINTER_NAME"));
605 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
608 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
609 NULL
, cgiGetVariable("PRINTER_LOCATION"));
611 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
612 NULL
, cgiGetVariable("PRINTER_INFO"));
614 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
616 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
619 if ((num_printers
= cgiGetSize("MEMBER_URIS")) > 0)
621 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris",
622 num_printers
, NULL
, NULL
);
623 for (i
= 0; i
< num_printers
; i
++)
624 attr
->values
[i
].string
.text
= strdup(cgiGetArray("MEMBER_URIS", i
));
628 * Do the request and get back a response...
631 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
633 if (cupsLastError() > IPP_OK_CONFLICT
)
636 cgiShowIPPError(modify
? _("Unable to modify class:") :
637 _("Unable to add class:"));
642 * Redirect successful updates back to the class page...
645 char refresh
[1024]; /* Refresh URL */
647 cgiFormEncode(uri
, name
, sizeof(uri
));
648 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
650 cgiSetVariable("refresh_page", refresh
);
655 cgiCopyTemplateLang("class-modified.tmpl");
657 cgiCopyTemplateLang("class-added.tmpl");
665 * 'do_am_printer()' - Add or modify a printer.
669 do_am_printer(http_t
*http
, /* I - HTTP connection */
670 int modify
) /* I - Modify the printer? */
672 int i
; /* Looping var */
673 ipp_attribute_t
*attr
; /* Current attribute */
674 ipp_t
*request
, /* IPP request */
675 *response
, /* IPP response */
676 *oldinfo
; /* Old printer information */
677 const cgi_file_t
*file
; /* Uploaded file, if any */
678 const char *var
; /* CGI variable */
679 char uri
[HTTP_MAX_URI
], /* Device or printer URI */
680 *uriptr
; /* Pointer into URI */
681 int maxrate
; /* Maximum baud rate */
682 char baudrate
[255]; /* Baud rate string */
683 const char *name
, /* Pointer to class name */
684 *ptr
; /* Pointer to CGI variable */
685 const char *title
; /* Title of page */
686 static int baudrates
[] = /* Baud rates */
701 ptr
= cgiGetVariable("DEVICE_URI");
702 fprintf(stderr
, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
703 ptr
? ptr
: "(null)");
705 title
= cgiText(modify
? _("Modify Printer") : _("Add Printer"));
710 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
711 * following attributes:
714 * attributes-natural-language
718 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
720 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
721 "localhost", 0, "/printers/%s",
722 cgiGetVariable("PRINTER_NAME"));
723 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
727 * Do the request and get back a response...
730 oldinfo
= cupsDoRequest(http
, request
, "/");
735 if ((name
= cgiGetVariable("PRINTER_NAME")) == NULL
||
736 cgiGetVariable("PRINTER_LOCATION") == NULL
)
743 * Update the location and description of an existing printer...
747 cgiSetIPPVars(oldinfo
, NULL
, NULL
, NULL
, 0);
749 cgiCopyTemplateLang("modify-printer.tmpl");
754 * Get the name, location, and description for a new printer...
757 cgiCopyTemplateLang("add-printer.tmpl");
768 for (ptr
= name
; *ptr
; ptr
++)
769 if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' || *ptr
== '#')
772 if (*ptr
|| ptr
== name
|| strlen(name
) > 127)
774 cgiSetVariable("ERROR",
775 cgiText(_("The printer name may only contain up to "
776 "127 printable characters and may not "
777 "contain spaces, slashes (/), or the "
778 "pound sign (#).")));
780 cgiCopyTemplateLang("error.tmpl");
789 fprintf(stderr
, "DEBUG: file->tempfile=%s\n", file
->tempfile
);
790 fprintf(stderr
, "DEBUG: file->name=%s\n", file
->name
);
791 fprintf(stderr
, "DEBUG: file->filename=%s\n", file
->filename
);
792 fprintf(stderr
, "DEBUG: file->mimetype=%s\n", file
->mimetype
);
795 if ((var
= cgiGetVariable("DEVICE_URI")) == NULL
)
798 * Build a CUPS_GET_DEVICES request, which requires the following
802 * attributes-natural-language
806 fputs("DEBUG: Getting list of devices...\n", stderr
);
808 request
= ippNewRequest(CUPS_GET_DEVICES
);
810 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
811 NULL
, "ipp://localhost/printers/");
814 * Do the request and get back a response...
817 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
819 fputs("DEBUG: Got device list!\n", stderr
);
821 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
826 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
827 cupsLastError(), cupsLastErrorString());
830 * Let the user choose...
833 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
835 strlcpy(uri
, attr
->values
[0].string
.text
, sizeof(uri
));
836 if ((uriptr
= strchr(uri
, ':')) != NULL
&& strncmp(uriptr
, "://", 3) == 0)
839 cgiSetVariable("CURRENT_DEVICE_URI", attr
->values
[0].string
.text
);
840 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri
);
844 cgiCopyTemplateLang("choose-device.tmpl");
847 else if (strchr(var
, '/') == NULL
)
849 if ((attr
= ippFindAttribute(oldinfo
, "device-uri", IPP_TAG_URI
)) != NULL
)
852 * Set the current device URI for the form to the old one...
855 if (strncmp(attr
->values
[0].string
.text
, var
, strlen(var
)) == 0)
856 cgiSetVariable("DEVICE_URI", attr
->values
[0].string
.text
);
860 * User needs to set the full URI...
864 cgiCopyTemplateLang("choose-uri.tmpl");
867 else if (!strncmp(var
, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
870 * Need baud rate, parity, etc.
873 if ((var
= strchr(var
, '?')) != NULL
&&
874 strncmp(var
, "?baud=", 6) == 0)
875 maxrate
= atoi(var
+ 6);
879 for (i
= 0; i
< 10; i
++)
880 if (baudrates
[i
] > maxrate
)
884 sprintf(baudrate
, "%d", baudrates
[i
]);
885 cgiSetArray("BAUDRATES", i
, baudrate
);
889 cgiCopyTemplateLang("choose-serial.tmpl");
892 else if (!file
&& (var
= cgiGetVariable("PPD_NAME")) == NULL
)
897 * Get the PPD file...
900 int fd
; /* PPD file */
901 char filename
[1024]; /* PPD filename */
902 ppd_file_t
*ppd
; /* PPD information */
903 char buffer
[1024]; /* Buffer */
904 int bytes
; /* Number of bytes */
905 http_status_t get_status
; /* Status of GET */
908 /* TODO: Use cupsGetFile() API... */
909 snprintf(uri
, sizeof(uri
), "/printers/%s.ppd", name
);
911 if (httpGet(http
, uri
))
914 while ((get_status
= httpUpdate(http
)) == HTTP_CONTINUE
);
916 if (get_status
!= HTTP_OK
)
918 fprintf(stderr
, "ERROR: Unable to get PPD file %s: %d - %s\n",
919 uri
, get_status
, httpStatus(get_status
));
921 else if ((fd
= cupsTempFd(filename
, sizeof(filename
))) >= 0)
923 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
924 write(fd
, buffer
, bytes
);
928 if ((ppd
= ppdOpenFile(filename
)) != NULL
)
930 if (ppd
->manufacturer
)
931 cgiSetVariable("CURRENT_MAKE", ppd
->manufacturer
);
934 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd
->nickname
);
941 fprintf(stderr
, "ERROR: Unable to open PPD file %s: %s\n",
942 filename
, ppdErrorString(ppdLastError(&bytes
)));
950 "ERROR: Unable to create temporary file for PPD file: %s\n",
954 else if ((uriptr
= strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL
)
957 * Extract make and make/model from device URI string...
960 char make
[1024], /* Make string */
961 *makeptr
; /* Pointer into make */
966 strlcpy(make
, uriptr
, sizeof(make
));
968 if ((makeptr
= strchr(make
, ' ')) != NULL
)
970 else if ((makeptr
= strchr(make
, '-')) != NULL
)
972 else if (!strncasecmp(make
, "laserjet", 8) ||
973 !strncasecmp(make
, "deskjet", 7) ||
974 !strncasecmp(make
, "designjet", 9))
976 else if (!strncasecmp(make
, "phaser", 6))
977 strcpy(make
, "Xerox");
978 else if (!strncasecmp(make
, "stylus", 6))
979 strcpy(make
, "Epson");
981 strcpy(make
, "Generic");
983 cgiSetVariable("CURRENT_MAKE", make
);
984 cgiSetVariable("PPD_MAKE", make
);
985 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr
);
989 * Build a CUPS_GET_PPDS request, which requires the following
993 * attributes-natural-language
997 request
= ippNewRequest(CUPS_GET_PPDS
);
999 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1000 NULL
, "ipp://localhost/printers/");
1002 if ((var
= cgiGetVariable("PPD_MAKE")) != NULL
)
1003 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_TEXT
,
1004 "ppd-make", NULL
, var
);
1006 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1007 "requested-attributes", NULL
, "ppd-make");
1010 * Do the request and get back a response...
1013 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1016 * Got the list of PPDs, see if the user has selected a make...
1019 if (cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0) == 0)
1022 * No PPD files with this make, try again with all makes...
1025 ippDelete(response
);
1027 request
= ippNewRequest(CUPS_GET_PPDS
);
1029 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1030 NULL
, "ipp://localhost/printers/");
1032 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1033 "requested-attributes", NULL
, "ppd-make");
1035 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1036 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
1038 cgiStartHTML(title
);
1039 cgiCopyTemplateLang("choose-make.tmpl");
1044 cgiStartHTML(title
);
1045 cgiCopyTemplateLang("choose-make.tmpl");
1051 * Let the user choose a model...
1054 const char *make_model
; /* Current make/model string */
1057 if ((make_model
= cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL
)
1060 * Scan for "close" matches...
1063 int match
, /* Current match */
1064 best_match
, /* Best match so far */
1065 count
; /* Number of drivers */
1066 const char *best
, /* Best matching string */
1067 *current
; /* Current string */
1070 count
= cgiGetSize("PPD_MAKE_AND_MODEL");
1072 for (i
= 0, best_match
= 0, best
= NULL
; i
< count
; i
++)
1074 current
= cgiGetArray("PPD_MAKE_AND_MODEL", i
);
1075 match
= match_string(make_model
, current
);
1077 if (match
> best_match
)
1084 if (best_match
> strlen(var
))
1087 * Found a match longer than the make...
1090 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best
);
1094 cgiStartHTML(title
);
1095 cgiCopyTemplateLang("choose-model.tmpl");
1099 ippDelete(response
);
1103 cgiStartHTML(title
);
1104 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1105 cgiCopyTemplateLang("error.tmpl");
1112 * Build a CUPS_ADD_PRINTER request, which requires the following
1115 * attributes-charset
1116 * attributes-natural-language
1122 * printer-is-accepting-jobs
1126 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1128 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1129 "localhost", 0, "/printers/%s",
1130 cgiGetVariable("PRINTER_NAME"));
1131 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1134 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-location",
1135 NULL
, cgiGetVariable("PRINTER_LOCATION"));
1137 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_TEXT
, "printer-info",
1138 NULL
, cgiGetVariable("PRINTER_INFO"));
1141 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "ppd-name",
1142 NULL
, cgiGetVariable("PPD_NAME"));
1144 strlcpy(uri
, cgiGetVariable("DEVICE_URI"), sizeof(uri
));
1147 * Strip make and model from URI...
1150 if ((uriptr
= strrchr(uri
, '|')) != NULL
)
1153 if (!strncmp(uri
, "serial:", 7))
1156 * Update serial port URI to include baud rate, etc.
1159 if ((uriptr
= strchr(uri
, '?')) == NULL
)
1160 uriptr
= uri
+ strlen(uri
);
1162 snprintf(uriptr
, sizeof(uri
) - (uriptr
- uri
),
1163 "?baud=%s+bits=%s+parity=%s+flow=%s",
1164 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1165 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1168 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "device-uri",
1171 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1173 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1177 * Do the request and get back a response...
1181 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", file
->tempfile
));
1183 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1185 if (cupsLastError() > IPP_OK_CONFLICT
)
1187 cgiStartHTML(title
);
1188 cgiShowIPPError(modify
? _("Unable to modify printer:") :
1189 _("Unable to add printer:"));
1194 * Redirect successful updates back to the printer or set-options pages...
1197 char refresh
[1024]; /* Refresh URL */
1200 cgiFormEncode(uri
, name
, sizeof(uri
));
1203 snprintf(refresh
, sizeof(refresh
),
1204 "5;/admin/?OP=redirect&URL=/printers/%s", uri
);
1206 snprintf(refresh
, sizeof(refresh
),
1207 "5;URL=/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri
);
1209 cgiSetVariable("refresh_page", refresh
);
1211 cgiStartHTML(title
);
1214 cgiCopyTemplateLang("printer-modified.tmpl");
1216 cgiCopyTemplateLang("printer-added.tmpl");
1228 * 'do_cancel_subscription()' - Cancel a subscription.
1232 do_cancel_subscription(http_t
*http
)/* I - HTTP connection */
1234 ipp_t
*request
; /* IPP request data */
1235 const char *var
, /* Form variable */
1236 *user
; /* Username */
1237 int id
; /* Subscription ID */
1241 * See if we have all of the required information...
1244 if ((var
= cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL
)
1251 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1252 cgiStartHTML(_("Cancel RSS Subscription"));
1253 cgiCopyTemplateLang("error.tmpl");
1259 * Cancel the subscription...
1262 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
1264 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1265 NULL
, "ipp://localhost/");
1266 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1267 "notify-subscription-id", id
);
1269 if ((user
= getenv("REMOTE_USER")) == NULL
)
1272 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1275 ippDelete(cupsDoRequest(http
, request
, "/"));
1277 if (cupsLastError() > IPP_OK_CONFLICT
)
1279 cgiStartHTML(_("Cancel RSS Subscription"));
1280 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1285 * Redirect successful updates back to the admin page...
1288 cgiSetVariable("refresh_page", "5;URL=/admin");
1289 cgiStartHTML(_("Cancel RSS Subscription"));
1290 cgiCopyTemplateLang("subscription-canceled.tmpl");
1298 * 'do_config_printer()' - Configure the default options for a printer.
1302 do_config_printer(http_t
*http
) /* I - HTTP connection */
1304 int i
, j
, k
, m
; /* Looping vars */
1305 int have_options
; /* Have options? */
1306 ipp_t
*request
, /* IPP request */
1307 *response
; /* IPP response */
1308 ipp_attribute_t
*attr
; /* IPP attribute */
1309 char uri
[HTTP_MAX_URI
]; /* Job URI */
1310 const char *var
; /* Variable value */
1311 const char *printer
; /* Printer printer name */
1312 const char *filename
; /* PPD filename */
1313 char tempfile
[1024]; /* Temporary filename */
1314 cups_file_t
*in
, /* Input file */
1315 *out
; /* Output file */
1316 char line
[1024]; /* Line from PPD file */
1317 char keyword
[1024], /* Keyword from Default line */
1318 *keyptr
; /* Pointer into keyword... */
1319 ppd_file_t
*ppd
; /* PPD file */
1320 ppd_group_t
*group
; /* Option group */
1321 ppd_option_t
*option
; /* Option */
1322 ppd_attr_t
*protocol
; /* cupsProtocol attribute */
1323 const char *title
; /* Page title */
1326 title
= cgiText(_("Set Printer Options"));
1328 fprintf(stderr
, "DEBUG: do_config_printer(http=%p)\n", http
);
1331 * Get the printer name...
1334 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
1335 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1336 "localhost", 0, "/printers/%s", printer
);
1339 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1340 cgiStartHTML(title
);
1341 cgiCopyTemplateLang("error.tmpl");
1346 fprintf(stderr
, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer
, uri
);
1349 * Get the PPD file...
1352 if ((filename
= cupsGetPPD2(http
, printer
)) == NULL
)
1354 fputs("DEBUG: No PPD file!?!\n", stderr
);
1356 cgiStartHTML(title
);
1357 cgiShowIPPError(_("Unable to get PPD file!"));
1362 fprintf(stderr
, "DEBUG: Got PPD file: \"%s\"\n", filename
);
1364 if ((ppd
= ppdOpenFile(filename
)) == NULL
)
1366 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i
)));
1367 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1368 cgiStartHTML(title
);
1369 cgiCopyTemplateLang("error.tmpl");
1374 if (cgiGetVariable("job_sheets_start") != NULL
||
1375 cgiGetVariable("job_sheets_end") != NULL
)
1380 ppdMarkDefaults(ppd
);
1382 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1383 "<UL>\n", ppd
->num_groups
));
1385 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
1387 DEBUG_printf(("<LI>%s<UL>\n", group
->text
));
1389 for (j
= group
->num_options
, option
= group
->options
;
1392 if ((var
= cgiGetVariable(option
->keyword
)) != NULL
)
1394 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option
->keyword
, var
));
1396 ppdMarkOption(ppd
, option
->keyword
, var
);
1400 printf("<LI>%s not defined!</LI>\n", option
->keyword
);
1403 DEBUG_puts("</UL></LI>");
1406 DEBUG_printf(("</UL>\n"
1407 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd
)));
1409 if (!have_options
|| ppdConflicts(ppd
))
1412 * Show the options to the user...
1415 fputs("DEBUG: Showing options...\n", stderr
);
1419 cgiStartHTML(cgiText(_("Set Printer Options")));
1420 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1422 if (ppdConflicts(ppd
))
1424 for (i
= ppd
->num_groups
, k
= 0, group
= ppd
->groups
;
1427 for (j
= group
->num_options
, option
= group
->options
;
1430 if (option
->conflicted
)
1432 cgiSetArray("ckeyword", k
, option
->keyword
);
1433 cgiSetArray("ckeytext", k
, option
->text
);
1437 cgiCopyTemplateLang("option-conflict.tmpl");
1440 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
1444 if (!strcmp(group
->name
, "InstallableOptions"))
1445 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
1447 cgiSetVariable("GROUP", group
->text
);
1449 cgiCopyTemplateLang("option-header.tmpl");
1451 for (j
= group
->num_options
, option
= group
->options
;
1455 if (!strcmp(option
->keyword
, "PageRegion"))
1458 cgiSetVariable("KEYWORD", option
->keyword
);
1459 cgiSetVariable("KEYTEXT", option
->text
);
1461 if (option
->conflicted
)
1462 cgiSetVariable("CONFLICTED", "1");
1464 cgiSetVariable("CONFLICTED", "0");
1466 cgiSetSize("CHOICES", 0);
1467 cgiSetSize("TEXT", 0);
1468 for (k
= 0, m
= 0; k
< option
->num_choices
; k
++)
1471 * Hide custom option values...
1474 if (!strcmp(option
->choices
[k
].choice
, "Custom"))
1477 cgiSetArray("CHOICES", m
, option
->choices
[k
].choice
);
1478 cgiSetArray("TEXT", m
, option
->choices
[k
].text
);
1482 if (option
->choices
[k
].marked
)
1483 cgiSetVariable("DEFCHOICE", option
->choices
[k
].choice
);
1488 case PPD_UI_BOOLEAN
:
1489 cgiCopyTemplateLang("option-boolean.tmpl");
1491 case PPD_UI_PICKONE
:
1492 cgiCopyTemplateLang("option-pickone.tmpl");
1494 case PPD_UI_PICKMANY
:
1495 cgiCopyTemplateLang("option-pickmany.tmpl");
1500 cgiCopyTemplateLang("option-trailer.tmpl");
1504 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1505 * following attributes:
1507 * attributes-charset
1508 * attributes-natural-language
1512 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
1514 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1515 "localhost", 0, "/printers/%s", printer
);
1516 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1520 * Do the request and get back a response...
1523 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1525 if ((attr
= ippFindAttribute(response
, "job-sheets-supported",
1526 IPP_TAG_ZERO
)) != NULL
)
1529 * Add the job sheets options...
1532 cgiSetVariable("GROUP", cgiText(_("Banners")));
1533 cgiCopyTemplateLang("option-header.tmpl");
1535 cgiSetSize("CHOICES", attr
->num_values
);
1536 cgiSetSize("TEXT", attr
->num_values
);
1537 for (k
= 0; k
< attr
->num_values
; k
++)
1539 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1540 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1543 attr
= ippFindAttribute(response
, "job-sheets-default", IPP_TAG_ZERO
);
1545 cgiSetVariable("KEYWORD", "job_sheets_start");
1546 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
1547 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1548 "" : attr
->values
[0].string
.text
);
1550 cgiCopyTemplateLang("option-pickone.tmpl");
1552 cgiSetVariable("KEYWORD", "job_sheets_end");
1553 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
1554 cgiSetVariable("DEFCHOICE", attr
== NULL
&& attr
->num_values
> 1 ?
1555 "" : attr
->values
[1].string
.text
);
1557 cgiCopyTemplateLang("option-pickone.tmpl");
1559 cgiCopyTemplateLang("option-trailer.tmpl");
1562 if (ippFindAttribute(response
, "printer-error-policy-supported",
1564 ippFindAttribute(response
, "printer-op-policy-supported",
1568 * Add the error and operation policy options...
1571 cgiSetVariable("GROUP", cgiText(_("Policies")));
1572 cgiCopyTemplateLang("option-header.tmpl");
1578 attr
= ippFindAttribute(response
, "printer-error-policy-supported",
1583 cgiSetSize("CHOICES", attr
->num_values
);
1584 cgiSetSize("TEXT", attr
->num_values
);
1585 for (k
= 0; k
< attr
->num_values
; k
++)
1587 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1588 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1591 attr
= ippFindAttribute(response
, "printer-error-policy",
1594 cgiSetVariable("KEYWORD", "printer_error_policy");
1595 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
1596 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1597 "" : attr
->values
[0].string
.text
);
1600 cgiCopyTemplateLang("option-pickone.tmpl");
1603 * Operation policy...
1606 attr
= ippFindAttribute(response
, "printer-op-policy-supported",
1611 cgiSetSize("CHOICES", attr
->num_values
);
1612 cgiSetSize("TEXT", attr
->num_values
);
1613 for (k
= 0; k
< attr
->num_values
; k
++)
1615 cgiSetArray("CHOICES", k
, attr
->values
[k
].string
.text
);
1616 cgiSetArray("TEXT", k
, attr
->values
[k
].string
.text
);
1619 attr
= ippFindAttribute(response
, "printer-op-policy", IPP_TAG_ZERO
);
1621 cgiSetVariable("KEYWORD", "printer_op_policy");
1622 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
1623 cgiSetVariable("DEFCHOICE", attr
== NULL
?
1624 "" : attr
->values
[0].string
.text
);
1626 cgiCopyTemplateLang("option-pickone.tmpl");
1629 cgiCopyTemplateLang("option-trailer.tmpl");
1632 ippDelete(response
);
1636 * Binary protocol support...
1639 if (ppd
->protocols
&& strstr(ppd
->protocols
, "BCP"))
1641 protocol
= ppdFindAttr(ppd
, "cupsProtocol", NULL
);
1643 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
1644 cgiCopyTemplateLang("option-header.tmpl");
1646 cgiSetSize("CHOICES", 2);
1647 cgiSetSize("TEXT", 2);
1648 cgiSetArray("CHOICES", 0, "None");
1649 cgiSetArray("TEXT", 0, cgiText(_("None")));
1651 if (strstr(ppd
->protocols
, "TBCP"))
1653 cgiSetArray("CHOICES", 1, "TBCP");
1654 cgiSetArray("TEXT", 1, "TBCP");
1658 cgiSetArray("CHOICES", 1, "BCP");
1659 cgiSetArray("TEXT", 1, "BCP");
1662 cgiSetVariable("KEYWORD", "protocol");
1663 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
1664 cgiSetVariable("DEFCHOICE", protocol
? protocol
->value
: "None");
1666 cgiCopyTemplateLang("option-pickone.tmpl");
1668 cgiCopyTemplateLang("option-trailer.tmpl");
1671 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1677 * Set default options...
1680 fputs("DEBUG: Setting options...\n", stderr
);
1682 out
= cupsTempFile2(tempfile
, sizeof(tempfile
));
1683 in
= cupsFileOpen(filename
, "r");
1687 cgiSetVariable("ERROR", strerror(errno
));
1688 cgiStartHTML(cgiText(_("Set Printer Options")));
1689 cgiCopyTemplateLang("error.tmpl");
1705 while (cupsFileGets(in
, line
, sizeof(line
)))
1707 if (!strncmp(line
, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1709 else if (strncmp(line
, "*Default", 8))
1710 cupsFilePrintf(out
, "%s\n", line
);
1714 * Get default option name...
1717 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
1719 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1720 if (*keyptr
== ':' || isspace(*keyptr
& 255))
1725 if (!strcmp(keyword
, "PageRegion") ||
1726 !strcmp(keyword
, "PaperDimension") ||
1727 !strcmp(keyword
, "ImageableArea"))
1728 var
= cgiGetVariable("PageSize");
1730 var
= cgiGetVariable(keyword
);
1733 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, var
);
1735 cupsFilePrintf(out
, "%s\n", line
);
1739 if ((var
= cgiGetVariable("protocol")) != NULL
)
1740 cupsFilePrintf(out
, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1746 * Build a CUPS_ADD_PRINTER request, which requires the following
1749 * attributes-charset
1750 * attributes-natural-language
1752 * job-sheets-default
1756 request
= ippNewRequest(CUPS_ADD_PRINTER
);
1758 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1759 "localhost", 0, "/printers/%s",
1760 cgiGetVariable("PRINTER_NAME"));
1761 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1764 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1765 "job-sheets-default", 2, NULL
, NULL
);
1766 attr
->values
[0].string
.text
= strdup(cgiGetVariable("job_sheets_start"));
1767 attr
->values
[1].string
.text
= strdup(cgiGetVariable("job_sheets_end"));
1769 if ((var
= cgiGetVariable("printer_error_policy")) != NULL
)
1770 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1771 "printer-error-policy", NULL
, var
);
1773 if ((var
= cgiGetVariable("printer_op_policy")) != NULL
)
1774 attr
= ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
1775 "printer-op-policy", NULL
, var
);
1778 * Do the request and get back a response...
1781 ippDelete(cupsDoFileRequest(http
, request
, "/admin/", tempfile
));
1783 if (cupsLastError() > IPP_OK_CONFLICT
)
1785 cgiStartHTML(title
);
1786 cgiShowIPPError(_("Unable to set options:"));
1791 * Redirect successful updates back to the printer page...
1794 char refresh
[1024]; /* Refresh URL */
1797 cgiFormEncode(uri
, printer
, sizeof(uri
));
1798 snprintf(refresh
, sizeof(refresh
),
1799 "5;URL=/admin/?OP=redirect&URL=/printers/%s", uri
);
1800 cgiSetVariable("refresh_page", refresh
);
1802 cgiStartHTML(title
);
1804 cgiCopyTemplateLang("printer-configured.tmpl");
1817 * 'do_config_server()' - Configure server settings.
1821 do_config_server(http_t
*http
) /* I - HTTP connection */
1823 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1826 * Save basic setting changes...
1829 int num_settings
; /* Number of server settings */
1830 cups_option_t
*settings
; /* Server settings */
1831 const char *debug_logging
, /* DEBUG_LOGGING value */
1832 *remote_admin
, /* REMOTE_ADMIN value */
1833 *remote_any
, /* REMOTE_ANY value */
1835 /* REMOTE_PRINTERS value */
1836 *share_printers
,/* SHARE_PRINTERS value */
1839 /* DefaultAuthType value */
1840 #endif /* HAVE_GSSAPI */
1842 /* USER_CANCEL_ANY value */
1846 * Get the checkbox values from the form...
1849 debug_logging
= cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1850 remote_admin
= cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1851 remote_any
= cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1852 remote_printers
= cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1853 share_printers
= cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1854 user_cancel_any
= cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1856 default_auth_type
= cgiGetVariable("KERBEROS") ? "Negotiate" : "Basic";
1858 fprintf(stderr
, "DEBUG: DefaultAuthType %s\n", default_auth_type
);
1859 #endif /* HAVE_GSSAPI */
1862 * Get the current server settings...
1865 if (!_cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
1867 cgiStartHTML(cgiText(_("Change Settings")));
1868 cgiSetVariable("MESSAGE",
1869 cgiText(_("Unable to change server settings:")));
1870 cgiSetVariable("ERROR", cupsLastErrorString());
1871 cgiCopyTemplateLang("error.tmpl");
1877 * See if the settings have changed...
1880 if (strcmp(debug_logging
, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
,
1881 num_settings
, settings
)) ||
1882 strcmp(remote_admin
, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
,
1883 num_settings
, settings
)) ||
1884 strcmp(remote_any
, cupsGetOption(CUPS_SERVER_REMOTE_ANY
,
1885 num_settings
, settings
)) ||
1886 strcmp(remote_printers
, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
,
1887 num_settings
, settings
)) ||
1888 strcmp(share_printers
, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
,
1889 num_settings
, settings
)) ||
1891 !cupsGetOption("DefaultAuthType", num_settings
, settings
) ||
1892 strcmp(default_auth_type
, cupsGetOption("DefaultAuthType",
1893 num_settings
, settings
)) ||
1894 #endif /* HAVE_GSSAPI */
1895 strcmp(user_cancel_any
, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
,
1896 num_settings
, settings
)))
1899 * Settings *have* changed, so save the changes...
1902 cupsFreeOptions(num_settings
, settings
);
1905 num_settings
= cupsAddOption(CUPS_SERVER_DEBUG_LOGGING
,
1906 debug_logging
, num_settings
, &settings
);
1907 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ADMIN
,
1908 remote_admin
, num_settings
, &settings
);
1909 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_ANY
,
1910 remote_any
, num_settings
, &settings
);
1911 num_settings
= cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS
,
1912 remote_printers
, num_settings
, &settings
);
1913 num_settings
= cupsAddOption(CUPS_SERVER_SHARE_PRINTERS
,
1914 share_printers
, num_settings
, &settings
);
1915 num_settings
= cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY
,
1916 user_cancel_any
, num_settings
, &settings
);
1918 num_settings
= cupsAddOption("DefaultAuthType", default_auth_type
,
1919 num_settings
, &settings
);
1920 #endif /* HAVE_GSSAPI */
1922 if (!_cupsAdminSetServerSettings(http
, num_settings
, settings
))
1924 cgiStartHTML(cgiText(_("Change Settings")));
1925 cgiSetVariable("MESSAGE",
1926 cgiText(_("Unable to change server settings:")));
1927 cgiSetVariable("ERROR", cupsLastErrorString());
1928 cgiCopyTemplateLang("error.tmpl");
1932 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1933 cgiStartHTML(cgiText(_("Change Settings")));
1934 cgiCopyTemplateLang("restart.tmpl");
1943 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1944 cgiStartHTML(cgiText(_("Change Settings")));
1945 cgiCopyTemplateLang("norestart.tmpl");
1948 cupsFreeOptions(num_settings
, settings
);
1952 else if (cgiIsPOST())
1955 * Save hand-edited config file...
1958 http_status_t status
; /* PUT status */
1959 char tempfile
[1024]; /* Temporary new cupsd.conf */
1960 int tempfd
; /* Temporary file descriptor */
1961 cups_file_t
*temp
; /* Temporary file */
1962 const char *start
, /* Start of line */
1963 *end
; /* End of line */
1967 * Create a temporary file for the new cupsd.conf file...
1970 if ((tempfd
= cupsTempFd(tempfile
, sizeof(tempfile
))) < 0)
1972 cgiStartHTML(cgiText(_("Edit Configuration File")));
1973 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1974 cgiSetVariable("ERROR", strerror(errno
));
1975 cgiCopyTemplateLang("error.tmpl");
1982 if ((temp
= cupsFileOpenFd(tempfd
, "w")) == NULL
)
1984 cgiStartHTML(cgiText(_("Edit Configuration File")));
1985 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1986 cgiSetVariable("ERROR", strerror(errno
));
1987 cgiCopyTemplateLang("error.tmpl");
1997 * Copy the cupsd.conf text from the form variable...
2000 start
= cgiGetVariable("CUPSDCONF");
2003 if ((end
= strstr(start
, "\r\n")) == NULL
)
2004 if ((end
= strstr(start
, "\n")) == NULL
)
2005 end
= start
+ strlen(start
);
2007 cupsFileWrite(temp
, start
, end
- start
);
2008 cupsFilePutChar(temp
, '\n');
2012 else if (*end
== '\n')
2018 cupsFileClose(temp
);
2021 * Upload the configuration file to the server...
2024 status
= cupsPutFile(http
, "/admin/conf/cupsd.conf", tempfile
);
2026 if (status
!= HTTP_CREATED
)
2028 cgiSetVariable("MESSAGE",
2029 cgiText(_("Unable to upload cupsd.conf file:")));
2030 cgiSetVariable("ERROR", httpStatus(status
));
2032 cgiStartHTML(cgiText(_("Edit Configuration File")));
2033 cgiCopyTemplateLang("error.tmpl");
2037 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
2039 cgiStartHTML(cgiText(_("Edit Configuration File")));
2040 cgiCopyTemplateLang("restart.tmpl");
2049 struct stat info
; /* cupsd.conf information */
2050 cups_file_t
*cupsd
; /* cupsd.conf file */
2051 char *buffer
; /* Buffer for entire file */
2052 char filename
[1024]; /* Filename */
2053 const char *server_root
; /* Location of config files */
2057 * Locate the cupsd.conf file...
2060 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
2061 server_root
= CUPS_SERVERROOT
;
2063 snprintf(filename
, sizeof(filename
), "%s/cupsd.conf", server_root
);
2066 * Figure out the size...
2069 if (stat(filename
, &info
))
2071 cgiStartHTML(cgiText(_("Edit Configuration File")));
2072 cgiSetVariable("MESSAGE",
2073 cgiText(_("Unable to access cupsd.conf file:")));
2074 cgiSetVariable("ERROR", strerror(errno
));
2075 cgiCopyTemplateLang("error.tmpl");
2082 if (info
.st_size
> (1024 * 1024))
2084 cgiStartHTML(cgiText(_("Edit Configuration File")));
2085 cgiSetVariable("MESSAGE",
2086 cgiText(_("Unable to access cupsd.conf file:")));
2087 cgiSetVariable("ERROR",
2088 cgiText(_("Unable to edit cupsd.conf files larger than "
2090 cgiCopyTemplateLang("error.tmpl");
2093 fprintf(stderr
, "ERROR: \"%s\" too large (%ld) to edit!\n", filename
,
2094 (long)info
.st_size
);
2099 * Open the cupsd.conf file...
2102 if ((cupsd
= cupsFileOpen(filename
, "r")) == NULL
)
2105 * Unable to open - log an error...
2108 cgiStartHTML(cgiText(_("Edit Configuration File")));
2109 cgiSetVariable("MESSAGE",
2110 cgiText(_("Unable to access cupsd.conf file:")));
2111 cgiSetVariable("ERROR", strerror(errno
));
2112 cgiCopyTemplateLang("error.tmpl");
2120 * Allocate memory and load the file into a string buffer...
2123 buffer
= calloc(1, info
.st_size
+ 1);
2125 cupsFileRead(cupsd
, buffer
, info
.st_size
);
2126 cupsFileClose(cupsd
);
2128 cgiSetVariable("CUPSDCONF", buffer
);
2132 * Show the current config file...
2135 cgiStartHTML(cgiText(_("Edit Configuration File")));
2137 printf("<!-- \"%s\" -->\n", filename
);
2139 cgiCopyTemplateLang("edit-config.tmpl");
2147 * 'do_delete_class()' - Delete a class...
2151 do_delete_class(http_t
*http
) /* I - HTTP connection */
2153 ipp_t
*request
; /* IPP request */
2154 char uri
[HTTP_MAX_URI
]; /* Job URI */
2155 const char *pclass
; /* Printer class name */
2159 * Get form variables...
2162 if (cgiGetVariable("CONFIRM") == NULL
)
2164 cgiStartHTML(cgiText(_("Delete Class")));
2165 cgiCopyTemplateLang("class-confirm.tmpl");
2170 if ((pclass
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2171 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2172 "localhost", 0, "/classes/%s", pclass
);
2175 cgiStartHTML(cgiText(_("Delete Class")));
2176 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2177 cgiCopyTemplateLang("error.tmpl");
2183 * Build a CUPS_DELETE_CLASS request, which requires the following
2186 * attributes-charset
2187 * attributes-natural-language
2191 request
= ippNewRequest(CUPS_DELETE_CLASS
);
2193 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2197 * Do the request and get back a response...
2200 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2203 * Show the results...
2206 if (cupsLastError() <= IPP_OK_CONFLICT
)
2209 * Redirect successful updates back to the classes page...
2212 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2215 cgiStartHTML(cgiText(_("Delete Class")));
2217 if (cupsLastError() > IPP_OK_CONFLICT
)
2218 cgiShowIPPError(_("Unable to delete class:"));
2220 cgiCopyTemplateLang("class-deleted.tmpl");
2227 * 'do_delete_printer()' - Delete a printer...
2231 do_delete_printer(http_t
*http
) /* I - HTTP connection */
2233 ipp_t
*request
; /* IPP request */
2234 char uri
[HTTP_MAX_URI
]; /* Job URI */
2235 const char *printer
; /* Printer printer name */
2239 * Get form variables...
2242 if (cgiGetVariable("CONFIRM") == NULL
)
2244 cgiStartHTML(cgiText(_("Delete Printer")));
2245 cgiCopyTemplateLang("printer-confirm.tmpl");
2250 if ((printer
= cgiGetVariable("PRINTER_NAME")) != NULL
)
2251 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2252 "localhost", 0, "/printers/%s", printer
);
2255 cgiStartHTML(cgiText(_("Delete Printer")));
2256 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2257 cgiCopyTemplateLang("error.tmpl");
2263 * Build a CUPS_DELETE_PRINTER request, which requires the following
2266 * attributes-charset
2267 * attributes-natural-language
2271 request
= ippNewRequest(CUPS_DELETE_PRINTER
);
2273 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2277 * Do the request and get back a response...
2280 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2283 * Show the results...
2286 if (cupsLastError() <= IPP_OK_CONFLICT
)
2289 * Redirect successful updates back to the printers page...
2292 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2295 cgiStartHTML(cgiText(_("Delete Printer")));
2297 if (cupsLastError() > IPP_OK_CONFLICT
)
2298 cgiShowIPPError(_("Unable to delete printer:"));
2300 cgiCopyTemplateLang("printer-deleted.tmpl");
2307 * 'do_export()' - Export printers to Samba...
2311 do_export(http_t
*http
) /* I - HTTP connection */
2313 int i
, j
; /* Looping vars */
2314 ipp_t
*request
, /* IPP request */
2315 *response
; /* IPP response */
2316 const char *username
, /* Samba username */
2317 *password
, /* Samba password */
2318 *export_all
; /* Export all printers? */
2319 int export_count
, /* Number of printers to export */
2320 printer_count
; /* Number of available printers */
2321 const char *name
, /* What name to pull */
2322 *dest
; /* Current destination */
2323 char ppd
[1024]; /* PPD file */
2330 username
= cgiGetVariable("USERNAME");
2331 password
= cgiGetVariable("PASSWORD");
2332 export_all
= cgiGetVariable("EXPORT_ALL");
2333 export_count
= cgiGetSize("EXPORT_NAME");
2336 * Get list of available printers...
2339 cgiSetSize("PRINTER_NAME", 0);
2340 cgiSetSize("PRINTER_EXPORT", 0);
2342 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2344 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2347 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
2348 "printer-type-mask", CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
|
2349 CUPS_PRINTER_IMPLICIT
);
2351 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2352 "requested-attributes", NULL
, "printer-name");
2354 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2356 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2357 ippDelete(response
);
2361 printer_count
= cgiGetSize("PRINTER_NAME");
2363 for (i
= 0; i
< printer_count
; i
++)
2365 dest
= cgiGetArray("PRINTER_NAME", i
);
2367 for (j
= 0; j
< export_count
; j
++)
2368 if (!strcasecmp(dest
, cgiGetArray("EXPORT_NAME", j
)))
2371 cgiSetArray("PRINTER_EXPORT", i
, j
< export_count
? "Y" : "");
2377 * Export or get the printers to export...
2380 if (username
&& *username
&& password
&& *password
&&
2381 (export_all
|| export_count
> 0))
2387 fputs("DEBUG: Export printers...\n", stderr
);
2391 name
= "PRINTER_NAME";
2392 export_count
= cgiGetSize("PRINTER_NAME");
2395 name
= "EXPORT_NAME";
2397 for (i
= 0; i
< export_count
; i
++)
2399 dest
= cgiGetArray(name
, i
);
2401 if (!cupsAdminCreateWindowsPPD(http
, dest
, ppd
, sizeof(ppd
)))
2404 j
= cupsAdminExportSamba(dest
, ppd
, "localhost", username
, password
,
2413 if (i
< export_count
)
2414 cgiSetVariable("ERROR", cupsLastErrorString());
2417 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2418 cgiCopyTemplateLang("samba-exported.tmpl");
2423 else if (username
&& !*username
)
2424 cgiSetVariable("ERROR",
2425 cgiText(_("A Samba username is required to export "
2426 "printer drivers!")));
2427 else if (username
&& (!password
|| !*password
))
2428 cgiSetVariable("ERROR",
2429 cgiText(_("A Samba password is required to export "
2430 "printer drivers!")));
2436 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2437 cgiCopyTemplateLang("samba-export.tmpl");
2443 * 'do_menu()' - Show the main menu...
2447 do_menu(http_t
*http
) /* I - HTTP connection */
2449 int num_settings
; /* Number of server settings */
2450 cups_option_t
*settings
; /* Server settings */
2451 const char *val
; /* Setting value */
2452 char filename
[1024]; /* Temporary filename */
2453 const char *datadir
; /* Location of data files */
2454 ipp_t
*request
, /* IPP request */
2455 *response
; /* IPP response */
2456 ipp_attribute_t
*attr
; /* IPP attribute */
2460 * Get the current server settings...
2463 if (!_cupsAdminGetServerSettings(http
, &num_settings
, &settings
))
2465 cgiSetVariable("SETTINGS_MESSAGE",
2466 cgiText(_("Unable to open cupsd.conf file:")));
2467 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2470 if ((val
= cupsGetOption(CUPS_SERVER_DEBUG_LOGGING
, num_settings
,
2471 settings
)) != NULL
&& atoi(val
))
2472 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2474 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ADMIN
, num_settings
,
2475 settings
)) != NULL
&& atoi(val
))
2476 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2478 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_ANY
, num_settings
,
2479 settings
)) != NULL
&& atoi(val
))
2480 cgiSetVariable("REMOTE_ANY", "CHECKED");
2482 if ((val
= cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS
, num_settings
,
2483 settings
)) != NULL
&& atoi(val
))
2484 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2486 if ((val
= cupsGetOption(CUPS_SERVER_SHARE_PRINTERS
, num_settings
,
2487 settings
)) != NULL
&& atoi(val
))
2488 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2490 if ((val
= cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY
, num_settings
,
2491 settings
)) != NULL
&& atoi(val
))
2492 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2495 cgiSetVariable("HAVE_GSSAPI", "1");
2497 if ((val
= cupsGetOption("DefaultAuthType", num_settings
,
2498 settings
)) != NULL
&& !strcasecmp(val
, "Negotiate"))
2499 cgiSetVariable("KERBEROS", "CHECKED");
2500 #endif /* HAVE_GSSAPI */
2502 cupsFreeOptions(num_settings
, settings
);
2505 * Get the list of printers and their devices...
2508 request
= ippNewRequest(CUPS_GET_PRINTERS
);
2510 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2511 "requested-attributes", NULL
, "device-uri");
2513 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type",
2514 CUPS_PRINTER_LOCAL
);
2515 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
, "printer-type-mask",
2516 CUPS_PRINTER_LOCAL
);
2518 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2521 * Got the printer list, now load the devices...
2524 int i
; /* Looping var */
2525 cups_array_t
*printer_devices
; /* Printer devices for local printers */
2526 char *printer_device
; /* Current printer device */
2530 * Allocate an array and copy the device strings...
2533 printer_devices
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2535 for (attr
= ippFindAttribute(response
, "device-uri", IPP_TAG_URI
);
2537 attr
= ippFindNextAttribute(response
, "device-uri", IPP_TAG_URI
))
2539 cupsArrayAdd(printer_devices
, strdup(attr
->values
[0].string
.text
));
2543 * Free the printer list and get the device list...
2546 ippDelete(response
);
2548 request
= ippNewRequest(CUPS_GET_DEVICES
);
2550 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2553 * Got the device list, let's parse it...
2556 const char *device_uri
, /* device-uri attribute value */
2557 *device_make_and_model
, /* device-make-and-model value */
2558 *device_info
; /* device-info value */
2561 for (i
= 0, attr
= response
->attrs
; attr
; attr
= attr
->next
)
2564 * Skip leading attributes until we hit a device...
2567 while (attr
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
2574 * Pull the needed attributes from this device...
2578 device_make_and_model
= NULL
;
2581 while (attr
&& attr
->group_tag
== IPP_TAG_PRINTER
)
2583 if (!strcmp(attr
->name
, "device-info") &&
2584 attr
->value_tag
== IPP_TAG_TEXT
)
2585 device_info
= attr
->values
[0].string
.text
;
2587 if (!strcmp(attr
->name
, "device-make-and-model") &&
2588 attr
->value_tag
== IPP_TAG_TEXT
)
2589 device_make_and_model
= attr
->values
[0].string
.text
;
2591 if (!strcmp(attr
->name
, "device-uri") &&
2592 attr
->value_tag
== IPP_TAG_URI
)
2593 device_uri
= attr
->values
[0].string
.text
;
2599 * See if we have everything needed...
2602 if (device_info
&& device_make_and_model
&& device_uri
&&
2603 strcasecmp(device_make_and_model
, "unknown") &&
2604 strchr(device_uri
, ':'))
2607 * Yes, now see if there is already a printer for this
2611 if (!cupsArrayFind(printer_devices
, (void *)device_uri
))
2614 * Not found, so it must be a new printer...
2617 char options
[1024], /* Form variables for this device */
2618 *options_ptr
; /* Pointer into string */
2619 const char *ptr
; /* Pointer into device string */
2623 * Format the printer name variable for this device...
2625 * We use the device-info string first, then device-uri,
2626 * and finally device-make-and-model to come up with a
2630 strcpy(options
, "TEMPLATE_NAME=");
2631 options_ptr
= options
+ strlen(options
);
2633 if (strncasecmp(device_info
, "unknown", 7))
2635 else if ((ptr
= strstr(device_uri
, "://")) != NULL
)
2638 ptr
= device_make_and_model
;
2641 options_ptr
< (options
+ sizeof(options
) - 1) && *ptr
;
2643 if (isalnum(*ptr
& 255) || *ptr
== '_' || *ptr
== '-' ||
2645 *options_ptr
++ = *ptr
;
2646 else if ((*ptr
== ' ' || *ptr
== '/') && options_ptr
[-1] != '_')
2647 *options_ptr
++ = '_';
2648 else if (*ptr
== '?' || *ptr
== '(')
2652 * Then add the make and model in the printer info, so
2653 * that MacOS clients see something reasonable...
2656 strlcpy(options_ptr
, "&PRINTER_LOCATION=Local+Printer"
2658 sizeof(options
) - (options_ptr
- options
));
2659 options_ptr
+= strlen(options_ptr
);
2661 cgiFormEncode(options_ptr
, device_make_and_model
,
2662 sizeof(options
) - (options_ptr
- options
));
2663 options_ptr
+= strlen(options_ptr
);
2666 * Then copy the device URI...
2669 strlcpy(options_ptr
, "&DEVICE_URI=",
2670 sizeof(options
) - (options_ptr
- options
));
2671 options_ptr
+= strlen(options_ptr
);
2673 cgiFormEncode(options_ptr
, device_uri
,
2674 sizeof(options
) - (options_ptr
- options
));
2675 options_ptr
+= strlen(options_ptr
);
2677 if (options_ptr
< (options
+ sizeof(options
) - 1))
2679 *options_ptr
++ = '|';
2680 cgiFormEncode(options_ptr
, device_make_and_model
,
2681 sizeof(options
) - (options_ptr
- options
));
2685 * Finally, set the form variables for this printer...
2688 cgiSetArray("device_info", i
, device_info
);
2689 cgiSetArray("device_make_and_model", i
, device_make_and_model
);
2690 cgiSetArray("device_options", i
, options
);
2691 cgiSetArray("device_uri", i
, device_uri
);
2700 ippDelete(response
);
2703 * Free the device list...
2706 for (printer_device
= (char *)cupsArrayFirst(printer_devices
);
2708 printer_device
= (char *)cupsArrayNext(printer_devices
))
2709 free(printer_device
);
2711 cupsArrayDelete(printer_devices
);
2716 * See if Samba and the Windows drivers are installed...
2719 if ((datadir
= getenv("CUPS_DATADIR")) == NULL
)
2720 datadir
= CUPS_DATADIR
;
2722 snprintf(filename
, sizeof(filename
), "%s/drivers/pscript5.dll", datadir
);
2723 if (!access(filename
, R_OK
))
2726 * Found Windows 2000 driver file, see if we have smbclient and
2730 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2731 sizeof(filename
)) &&
2732 cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2734 cgiSetVariable("HAVE_SAMBA", "Y");
2737 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename
,
2739 fputs("ERROR: smbclient not found!\n", stderr
);
2741 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename
,
2743 fputs("ERROR: rpcclient not found!\n", stderr
);
2753 request
= ippNewRequest(IPP_GET_SUBSCRIPTIONS
);
2755 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2756 NULL
, "ipp://localhost/");
2758 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2760 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2761 ippDelete(response
);
2765 * Finally, show the main menu template...
2768 cgiStartHTML(cgiText(_("Administration")));
2770 cgiCopyTemplateLang("admin.tmpl");
2777 * 'do_printer_op()' - Do a printer operation.
2781 do_printer_op(http_t
*http
, /* I - HTTP connection */
2782 ipp_op_t op
, /* I - Operation to perform */
2783 const char *title
) /* I - Title of page */
2785 ipp_t
*request
; /* IPP request */
2786 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2787 const char *printer
, /* Printer name (purge-jobs) */
2788 *is_class
; /* Is a class? */
2791 is_class
= cgiGetVariable("IS_CLASS");
2792 printer
= cgiGetVariable("PRINTER_NAME");
2796 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2797 cgiStartHTML(title
);
2798 cgiCopyTemplateLang("error.tmpl");
2804 * Build a printer request, which requires the following
2807 * attributes-charset
2808 * attributes-natural-language
2812 request
= ippNewRequest(op
);
2814 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2815 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2817 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2821 * Do the request and get back a response...
2824 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
2826 if (cupsLastError() > IPP_OK_CONFLICT
)
2828 cgiStartHTML(title
);
2829 cgiShowIPPError(_("Unable to change printer:"));
2834 * Redirect successful updates back to the printer page...
2837 char url
[1024], /* Printer/class URL */
2838 refresh
[1024]; /* Refresh URL */
2841 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
2842 cgiFormEncode(uri
, url
, sizeof(uri
));
2843 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
2844 cgiSetVariable("refresh_page", refresh
);
2846 cgiStartHTML(title
);
2848 if (op
== IPP_PAUSE_PRINTER
)
2849 cgiCopyTemplateLang("printer-stop.tmpl");
2850 else if (op
== IPP_RESUME_PRINTER
)
2851 cgiCopyTemplateLang("printer-start.tmpl");
2852 else if (op
== CUPS_ACCEPT_JOBS
)
2853 cgiCopyTemplateLang("printer-accept.tmpl");
2854 else if (op
== CUPS_REJECT_JOBS
)
2855 cgiCopyTemplateLang("printer-reject.tmpl");
2856 else if (op
== IPP_PURGE_JOBS
)
2857 cgiCopyTemplateLang("printer-purge.tmpl");
2858 else if (op
== CUPS_SET_DEFAULT
)
2859 cgiCopyTemplateLang("printer-default.tmpl");
2867 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2871 do_set_allowed_users(http_t
*http
) /* I - HTTP connection */
2873 int i
; /* Looping var */
2874 ipp_t
*request
, /* IPP request */
2875 *response
; /* IPP response */
2876 char uri
[HTTP_MAX_URI
]; /* Printer URI */
2877 const char *printer
, /* Printer name (purge-jobs) */
2878 *is_class
, /* Is a class? */
2879 *users
, /* List of users or groups */
2880 *type
; /* Allow/deny type */
2881 int num_users
; /* Number of users */
2882 char *ptr
, /* Pointer into users string */
2883 *end
, /* Pointer to end of users string */
2884 quote
; /* Quote character */
2885 ipp_attribute_t
*attr
; /* Attribute */
2886 static const char * const attrs
[] = /* Requested attributes */
2888 "requesting-user-name-allowed",
2889 "requesting-user-name-denied"
2893 is_class
= cgiGetVariable("IS_CLASS");
2894 printer
= cgiGetVariable("PRINTER_NAME");
2898 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2899 cgiStartHTML(cgiText(_("Set Allowed Users")));
2900 cgiCopyTemplateLang("error.tmpl");
2905 users
= cgiGetVariable("users");
2906 type
= cgiGetVariable("type");
2908 if (!users
|| !type
||
2909 (strcmp(type
, "requesting-user-name-allowed") &&
2910 strcmp(type
, "requesting-user-name-denied")))
2913 * Build a Get-Printer-Attributes request, which requires the following
2916 * attributes-charset
2917 * attributes-natural-language
2919 * requested-attributes
2922 request
= ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES
);
2924 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
2925 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
2927 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
2930 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
2931 "requested-attributes",
2932 (int)(sizeof(attrs
) / sizeof(attrs
[0])), NULL
, attrs
);
2935 * Do the request and get back a response...
2938 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
2940 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
2942 ippDelete(response
);
2945 cgiStartHTML(cgiText(_("Set Allowed Users")));
2947 if (cupsLastError() > IPP_OK_CONFLICT
)
2948 cgiShowIPPError(_("Unable to get printer attributes:"));
2950 cgiCopyTemplateLang("users.tmpl");
2957 * Save the changes...
2960 for (num_users
= 0, ptr
= (char *)users
; *ptr
; num_users
++)
2963 * Skip whitespace and commas...
2966 while (*ptr
== ',' || isspace(*ptr
& 255))
2969 if (*ptr
== '\'' || *ptr
== '\"')
2972 * Scan quoted name...
2977 for (end
= ptr
; *end
; end
++)
2984 * Scan space or comma-delimited name...
2987 for (end
= ptr
; *end
; end
++)
2988 if (isspace(*end
& 255) || *end
== ',')
2993 * Advance to the next name...
3000 * Build a CUPS-Add-Printer/Class request, which requires the following
3003 * attributes-charset
3004 * attributes-natural-language
3006 * requesting-user-name-{allowed,denied}
3009 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3011 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3012 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3014 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3018 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3019 "requesting-user-name-allowed", NULL
, "all");
3022 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
,
3023 type
, num_users
, NULL
, NULL
);
3025 for (i
= 0, ptr
= (char *)users
; *ptr
; i
++)
3028 * Skip whitespace and commas...
3031 while (*ptr
== ',' || isspace(*ptr
& 255))
3034 if (*ptr
== '\'' || *ptr
== '\"')
3037 * Scan quoted name...
3042 for (end
= ptr
; *end
; end
++)
3049 * Scan space or comma-delimited name...
3052 for (end
= ptr
; *end
; end
++)
3053 if (isspace(*end
& 255) || *end
== ',')
3058 * Terminate the name...
3068 attr
->values
[i
].string
.text
= strdup(ptr
);
3071 * Advance to the next name...
3079 * Do the request and get back a response...
3082 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
3084 if (cupsLastError() > IPP_OK_CONFLICT
)
3086 cgiStartHTML(cgiText(_("Set Allowed Users")));
3087 cgiShowIPPError(_("Unable to change printer:"));
3092 * Redirect successful updates back to the printer page...
3095 char url
[1024], /* Printer/class URL */
3096 refresh
[1024]; /* Refresh URL */
3099 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3100 cgiFormEncode(uri
, url
, sizeof(uri
));
3101 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s",
3103 cgiSetVariable("refresh_page", refresh
);
3105 cgiStartHTML(cgiText(_("Set Allowed Users")));
3107 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3108 "printer-modified.tmpl");
3117 * 'do_set_sharing()' - Set printer-is-shared value...
3121 do_set_sharing(http_t
*http
) /* I - HTTP connection */
3123 ipp_t
*request
, /* IPP request */
3124 *response
; /* IPP response */
3125 char uri
[HTTP_MAX_URI
]; /* Printer URI */
3126 const char *printer
, /* Printer name */
3127 *is_class
, /* Is a class? */
3128 *shared
; /* Sharing value */
3131 is_class
= cgiGetVariable("IS_CLASS");
3132 printer
= cgiGetVariable("PRINTER_NAME");
3133 shared
= cgiGetVariable("SHARED");
3135 if (!printer
|| !shared
)
3137 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3138 cgiStartHTML(cgiText(_("Set Publishing")));
3139 cgiCopyTemplateLang("error.tmpl");
3145 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3146 * following attributes:
3148 * attributes-charset
3149 * attributes-natural-language
3154 request
= ippNewRequest(is_class
? CUPS_ADD_CLASS
: CUPS_ADD_PRINTER
);
3156 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3157 "localhost", 0, is_class
? "/classes/%s" : "/printers/%s",
3159 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
3162 ippAddBoolean(request
, IPP_TAG_OPERATION
, "printer-is-shared", atoi(shared
));
3165 * Do the request and get back a response...
3168 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
)
3170 cgiSetIPPVars(response
, NULL
, NULL
, NULL
, 0);
3172 ippDelete(response
);
3175 if (cupsLastError() > IPP_OK_CONFLICT
)
3177 cgiStartHTML(cgiText(_("Set Publishing")));
3178 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3183 * Redirect successful updates back to the printer page...
3186 char url
[1024], /* Printer/class URL */
3187 refresh
[1024]; /* Refresh URL */
3190 cgiRewriteURL(uri
, url
, sizeof(url
), NULL
);
3191 cgiFormEncode(uri
, url
, sizeof(uri
));
3192 snprintf(refresh
, sizeof(refresh
), "5;URL=/admin/?OP=redirect&URL=%s", uri
);
3193 cgiSetVariable("refresh_page", refresh
);
3195 cgiStartHTML(cgiText(_("Set Publishing")));
3196 cgiCopyTemplateLang(is_class
? "class-modified.tmpl" :
3197 "printer-modified.tmpl");
3205 * 'match_string()' - Return the number of matching characters.
3208 static int /* O - Number of matching characters */
3209 match_string(const char *a
, /* I - First string */
3210 const char *b
) /* I - Second string */
3212 int count
; /* Number of matching characters */
3216 * Loop through both strings until we hit the end of either or we find
3217 * a non-matching character. For the purposes of comparison, we ignore
3218 * whitespace and do a case-insensitive comparison so that we have a
3219 * better chance of finding a match...
3222 for (count
= 0; *a
&& *b
; a
++, b
++, count
++)
3225 * Skip leading whitespace characters...
3228 while (isspace(*a
& 255))
3231 while (isspace(*b
& 255))
3235 * Break out if we run out of characters...
3242 * Do a case-insensitive comparison of the next two chars...
3245 if (tolower(*a
& 255) != tolower(*b
& 255))
3254 * End of "$Id: admin.c 6361 2007-03-19 16:01:28Z mike $".