]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/admin.c
9c3e67a8aabd78ab86a0f6c7de84ad8e4e5336a3
[thirdparty/cups.git] / cgi-bin / admin.c
1 /*
2 * "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $"
3 *
4 * Administration CGI for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 * main() - Main entry for CGI.
18 * choose_device_cb() - Add a device to the device selection page.
19 * do_add_rss_subscription() - Add a RSS subscription.
20 * do_am_class() - Add or modify a class.
21 * do_am_printer() - Add or modify a printer.
22 * do_cancel_subscription() - Cancel a subscription.
23 * do_config_server() - Configure server settings.
24 * do_delete_class() - Delete a class.
25 * do_delete_printer() - Delete a printer.
26 * do_export() - Export printers to Samba.
27 * do_list_printers() - List available printers.
28 * do_menu() - Show the main menu.
29 * do_set_allowed_users() - Set the allowed/denied users for a queue.
30 * do_set_default() - Set the server default printer/class.
31 * do_set_options() - Configure the default options for a queue.
32 * do_set_sharing() - Set printer-is-shared value.
33 * get_option_value() - Return the value of an option.
34 * get_points() - Get a value in points.
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include "cgi-private.h"
42 #include <cups/adminutil.h>
43 #include <cups/file.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <sys/wait.h>
48 #include <limits.h>
49
50
51 /*
52 * Local globals...
53 */
54
55 static int current_device; /* Current device for add/modify */
56 static time_t last_device_time; /* Last update time for device list */
57
58
59 /*
60 * Local functions...
61 */
62
63 static void choose_device_cb(const char *device_class,
64 const char *device_id, const char *device_info,
65 const char *device_make_and_model,
66 const char *device_uri,
67 const char *device_location,
68 const char *title);
69 static void do_add_rss_subscription(http_t *http);
70 static void do_am_class(http_t *http, int modify);
71 static void do_am_printer(http_t *http, int modify);
72 static void do_cancel_subscription(http_t *http);
73 static void do_config_server(http_t *http);
74 static void do_delete_class(http_t *http);
75 static void do_delete_printer(http_t *http);
76 static void do_export(http_t *http);
77 static void do_list_printers(http_t *http);
78 static void do_menu(http_t *http);
79 static void do_set_allowed_users(http_t *http);
80 static void do_set_default(http_t *http);
81 static void do_set_options(http_t *http, int is_class);
82 static void do_set_sharing(http_t *http);
83 static char *get_option_value(ppd_file_t *ppd, const char *name,
84 char *buffer, size_t bufsize);
85 static double get_points(double number, const char *uval);
86
87
88 /*
89 * 'main()' - Main entry for CGI.
90 */
91
92 int /* O - Exit status */
93 main(int argc, /* I - Number of command-line arguments */
94 char *argv[]) /* I - Command-line arguments */
95 {
96 http_t *http; /* Connection to the server */
97 const char *op; /* Operation name */
98
99
100 /*
101 * Connect to the HTTP server...
102 */
103
104 fputs("DEBUG: admin.cgi started...\n", stderr);
105
106 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
107
108 if (!http)
109 {
110 perror("ERROR: Unable to connect to cupsd");
111 fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n",
112 cupsServer() ? cupsServer() : "(null)");
113 fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort());
114 fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
115 exit(1);
116 }
117
118 fprintf(stderr, "DEBUG: http=%p\n", http);
119
120 /*
121 * Set the web interface section...
122 */
123
124 cgiSetVariable("SECTION", "admin");
125
126 /*
127 * See if we have form data...
128 */
129
130 if (!cgiInitialize() || !cgiGetVariable("OP"))
131 {
132 /*
133 * Nope, send the administration menu...
134 */
135
136 fputs("DEBUG: No form data, showing main menu...\n", stderr);
137
138 do_menu(http);
139 }
140 else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST())
141 {
142 /*
143 * Do the operation...
144 */
145
146 fprintf(stderr, "DEBUG: op=\"%s\"...\n", op);
147
148 if (!strcmp(op, "set-allowed-users"))
149 do_set_allowed_users(http);
150 else if (!strcmp(op, "set-as-default"))
151 do_set_default(http);
152 else if (!strcmp(op, "set-sharing"))
153 do_set_sharing(http);
154 else if (!strcmp(op, "find-new-printers") ||
155 !strcmp(op, "list-available-printers"))
156 do_list_printers(http);
157 else if (!strcmp(op, "add-class"))
158 do_am_class(http, 0);
159 else if (!strcmp(op, "add-printer"))
160 do_am_printer(http, 0);
161 else if (!strcmp(op, "modify-class"))
162 do_am_class(http, 1);
163 else if (!strcmp(op, "modify-printer"))
164 do_am_printer(http, 1);
165 else if (!strcmp(op, "delete-class"))
166 do_delete_class(http);
167 else if (!strcmp(op, "delete-printer"))
168 do_delete_printer(http);
169 else if (!strcmp(op, "set-class-options"))
170 do_set_options(http, 1);
171 else if (!strcmp(op, "set-printer-options"))
172 do_set_options(http, 0);
173 else if (!strcmp(op, "config-server"))
174 do_config_server(http);
175 else if (!strcmp(op, "export-samba"))
176 do_export(http);
177 else if (!strcmp(op, "add-rss-subscription"))
178 do_add_rss_subscription(http);
179 else if (!strcmp(op, "cancel-subscription"))
180 do_cancel_subscription(http);
181 else
182 {
183 /*
184 * Bad operation code - display an error...
185 */
186
187 cgiStartHTML(cgiText(_("Administration")));
188 cgiCopyTemplateLang("error-op.tmpl");
189 cgiEndHTML();
190 }
191 }
192 else if (op && !strcmp(op, "redirect"))
193 {
194 const char *url; /* Redirection URL... */
195 char prefix[1024]; /* URL prefix */
196
197
198 if (getenv("HTTPS"))
199 snprintf(prefix, sizeof(prefix), "https://%s:%s",
200 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
201 else
202 snprintf(prefix, sizeof(prefix), "http://%s:%s",
203 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
204
205 fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix);
206
207 if ((url = cgiGetVariable("URL")) != NULL)
208 printf("Location: %s%s\n\n", prefix, url);
209 else
210 printf("Location: %s/admin\n\n", prefix);
211 }
212 else
213 {
214 /*
215 * Form data but no operation code - display an error...
216 */
217
218 cgiStartHTML(cgiText(_("Administration")));
219 cgiCopyTemplateLang("error-op.tmpl");
220 cgiEndHTML();
221 }
222
223 /*
224 * Close the HTTP server connection...
225 */
226
227 httpClose(http);
228
229 /*
230 * Return with no errors...
231 */
232
233 return (0);
234 }
235
236
237 /*
238 * 'choose_device_cb()' - Add a device to the device selection page.
239 */
240
241 static void
242 choose_device_cb(
243 const char *device_class, /* I - Class */
244 const char *device_id, /* I - 1284 device ID */
245 const char *device_info, /* I - Description */
246 const char *device_make_and_model, /* I - Make and model */
247 const char *device_uri, /* I - Device URI */
248 const char *device_location, /* I - Location */
249 const char *title) /* I - Page title */
250 {
251 /*
252 * Add the device to the array...
253 */
254
255 cgiSetArray("device_class", current_device, device_class);
256 cgiSetArray("device_id", current_device, device_id);
257 cgiSetArray("device_info", current_device, device_info);
258 cgiSetArray("device_make_and_model", current_device, device_make_and_model);
259 cgiSetArray("device_uri", current_device, device_uri);
260 cgiSetArray("device_location", current_device, device_location);
261
262 current_device ++;
263
264 if (time(NULL) > last_device_time && cgiSupportsMultipart())
265 {
266 /*
267 * Update the page...
268 */
269
270 if (!last_device_time)
271 cgiStartMultipart();
272
273 cgiStartHTML(title);
274 cgiCopyTemplateLang("choose-device.tmpl");
275 cgiEndHTML();
276 fflush(stdout);
277
278 time(&last_device_time);
279 }
280 }
281
282
283 /*
284 * 'do_add_rss_subscription()' - Add a RSS subscription.
285 */
286
287 static void
288 do_add_rss_subscription(http_t *http) /* I - HTTP connection */
289 {
290 ipp_t *request, /* IPP request data */
291 *response; /* IPP response data */
292 char rss_uri[1024]; /* RSS notify-recipient URI */
293 int num_events; /* Number of events */
294 const char *events[12], /* Subscribed events */
295 *subscription_name, /* Subscription name */
296 *printer_uri, /* Printer URI */
297 *ptr, /* Pointer into name */
298 *user; /* Username */
299 int max_events; /* Maximum number of events */
300
301
302 /*
303 * See if we have all of the required information...
304 */
305
306 subscription_name = cgiGetVariable("SUBSCRIPTION_NAME");
307 printer_uri = cgiGetVariable("PRINTER_URI");
308 num_events = 0;
309
310 if (cgiGetVariable("EVENT_JOB_CREATED"))
311 events[num_events ++] = "job-created";
312 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
313 events[num_events ++] = "job-completed";
314 if (cgiGetVariable("EVENT_JOB_STOPPED"))
315 events[num_events ++] = "job-stopped";
316 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
317 events[num_events ++] = "job-config-changed";
318 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
319 events[num_events ++] = "printer-stopped";
320 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
321 events[num_events ++] = "printer-added";
322 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
323 events[num_events ++] = "printer-modified";
324 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
325 events[num_events ++] = "printer-deleted";
326 if (cgiGetVariable("EVENT_SERVER_STARTED"))
327 events[num_events ++] = "server-started";
328 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
329 events[num_events ++] = "server-stopped";
330 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
331 events[num_events ++] = "server-restarted";
332 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
333 events[num_events ++] = "server-audit";
334
335 if ((ptr = cgiGetVariable("MAX_EVENTS")) != NULL)
336 max_events = atoi(ptr);
337 else
338 max_events = 0;
339
340 if (!subscription_name || !printer_uri || !num_events ||
341 max_events <= 0 || max_events > 9999)
342 {
343 /*
344 * Don't have everything we need, so get the available printers
345 * and classes and (re)show the add page...
346 */
347
348 request = ippNewRequest(CUPS_GET_PRINTERS);
349 response = cupsDoRequest(http, request, "/");
350
351 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
352
353 ippDelete(response);
354
355 cgiStartHTML(cgiText(_("Add RSS Subscription")));
356
357 cgiCopyTemplateLang("add-rss-subscription.tmpl");
358
359 cgiEndHTML();
360 return;
361 }
362
363 /*
364 * Make sure we have a username...
365 */
366
367 if ((user = getenv("REMOTE_USER")) == NULL)
368 {
369 puts("Status: 401\n");
370 exit(0);
371 }
372
373 /*
374 * Validate the subscription name...
375 */
376
377 for (ptr = subscription_name; *ptr; ptr ++)
378 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
379 *ptr == '?' || *ptr == '#')
380 break;
381
382 if (*ptr)
383 {
384 cgiSetVariable("ERROR",
385 cgiText(_("The subscription name may not "
386 "contain spaces, slashes (/), question marks (?), "
387 "or the pound sign (#).")));
388 cgiStartHTML(_("Add RSS Subscription"));
389 cgiCopyTemplateLang("error.tmpl");
390 cgiEndHTML();
391 return;
392 }
393
394 /*
395 * Add the subscription...
396 */
397
398 ptr = subscription_name + strlen(subscription_name) - 4;
399 if (ptr < subscription_name || strcmp(ptr, ".rss"))
400 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
401 NULL, NULL, 0, "/%s.rss?max_events=%d", subscription_name,
402 max_events);
403 else
404 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
405 NULL, NULL, 0, "/%s?max_events=%d", subscription_name,
406 max_events);
407
408 request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
409
410 if (!strcasecmp(printer_uri, "#ALL#"))
411 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
412 NULL, "ipp://localhost/");
413 else
414 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
415 NULL, printer_uri);
416
417 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
418 NULL, user);
419
420 ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
421 "notify-recipient-uri", NULL, rss_uri);
422 ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
423 num_events, NULL, events);
424 ippAddInteger(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
425 "notify-lease-duration", 0);
426
427 ippDelete(cupsDoRequest(http, request, "/"));
428
429 if (cupsLastError() == IPP_NOT_AUTHORIZED)
430 {
431 puts("Status: 401\n");
432 exit(0);
433 }
434 else if (cupsLastError() > IPP_OK_CONFLICT)
435 {
436 cgiStartHTML(_("Add RSS Subscription"));
437 cgiShowIPPError(_("Unable to add RSS subscription:"));
438 }
439 else
440 {
441 /*
442 * Redirect successful updates back to the admin page...
443 */
444
445 cgiSetVariable("refresh_page", "5;URL=/admin");
446 cgiStartHTML(_("Add RSS Subscription"));
447 cgiCopyTemplateLang("subscription-added.tmpl");
448 }
449
450 cgiEndHTML();
451 }
452
453
454 /*
455 * 'do_am_class()' - Add or modify a class.
456 */
457
458 static void
459 do_am_class(http_t *http, /* I - HTTP connection */
460 int modify) /* I - Modify the printer? */
461 {
462 int i, j; /* Looping vars */
463 int element; /* Element number */
464 int num_printers; /* Number of printers */
465 ipp_t *request, /* IPP request */
466 *response; /* IPP response */
467 ipp_attribute_t *attr; /* member-uris attribute */
468 char uri[HTTP_MAX_URI]; /* Device or printer URI */
469 const char *name, /* Pointer to class name */
470 *ptr; /* Pointer to CGI variable */
471 const char *title; /* Title of page */
472 static const char * const pattrs[] = /* Requested printer attributes */
473 {
474 "member-names",
475 "printer-info",
476 "printer-location"
477 };
478
479
480 title = cgiText(modify ? _("Modify Class") : _("Add Class"));
481 name = cgiGetVariable("PRINTER_NAME");
482
483 if (cgiGetVariable("PRINTER_LOCATION") == NULL)
484 {
485 /*
486 * Build a CUPS_GET_PRINTERS request, which requires the
487 * following attributes:
488 *
489 * attributes-charset
490 * attributes-natural-language
491 */
492
493 request = ippNewRequest(CUPS_GET_PRINTERS);
494
495 /*
496 * Do the request and get back a response...
497 */
498
499 if ((response = cupsDoRequest(http, request, "/")) != NULL)
500 {
501 /*
502 * Create MEMBER_URIS and MEMBER_NAMES arrays...
503 */
504
505 for (element = 0, attr = response->attrs;
506 attr != NULL;
507 attr = attr->next)
508 if (attr->name && !strcmp(attr->name, "printer-uri-supported"))
509 {
510 if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
511 (!name || strcasecmp(name, ptr + 1)))
512 {
513 /*
514 * Don't show the current class...
515 */
516
517 cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
518 element ++;
519 }
520 }
521
522 for (element = 0, attr = response->attrs;
523 attr != NULL;
524 attr = attr->next)
525 if (attr->name && !strcmp(attr->name, "printer-name"))
526 {
527 if (!name || strcasecmp(name, attr->values[0].string.text))
528 {
529 /*
530 * Don't show the current class...
531 */
532
533 cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
534 element ++;
535 }
536 }
537
538 num_printers = cgiGetSize("MEMBER_URIS");
539
540 ippDelete(response);
541 }
542 else
543 num_printers = 0;
544
545 if (modify)
546 {
547 /*
548 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
549 * following attributes:
550 *
551 * attributes-charset
552 * attributes-natural-language
553 * printer-uri
554 */
555
556 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
557
558 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
559 "localhost", 0, "/classes/%s", name);
560 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
561 NULL, uri);
562
563 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
564 "requested-attributes",
565 (int)(sizeof(pattrs) / sizeof(pattrs[0])),
566 NULL, pattrs);
567
568 /*
569 * Do the request and get back a response...
570 */
571
572 if ((response = cupsDoRequest(http, request, "/")) != NULL)
573 {
574 if ((attr = ippFindAttribute(response, "member-names",
575 IPP_TAG_NAME)) != NULL)
576 {
577 /*
578 * Mark any current members in the class...
579 */
580
581 for (j = 0; j < num_printers; j ++)
582 cgiSetArray("MEMBER_SELECTED", j, "");
583
584 for (i = 0; i < attr->num_values; i ++)
585 {
586 for (j = 0; j < num_printers; j ++)
587 {
588 if (!strcasecmp(attr->values[i].string.text,
589 cgiGetArray("MEMBER_NAMES", j)))
590 {
591 cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
592 break;
593 }
594 }
595 }
596 }
597
598 if ((attr = ippFindAttribute(response, "printer-info",
599 IPP_TAG_TEXT)) != NULL)
600 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
601
602 if ((attr = ippFindAttribute(response, "printer-location",
603 IPP_TAG_TEXT)) != NULL)
604 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
605
606 ippDelete(response);
607 }
608
609 /*
610 * Update the location and description of an existing printer...
611 */
612
613 cgiStartHTML(title);
614 cgiCopyTemplateLang("modify-class.tmpl");
615 }
616 else
617 {
618 /*
619 * Get the name, location, and description for a new printer...
620 */
621
622 cgiStartHTML(title);
623 cgiCopyTemplateLang("add-class.tmpl");
624 }
625
626 cgiEndHTML();
627
628 return;
629 }
630
631 for (ptr = name; *ptr; ptr ++)
632 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
633 break;
634
635 if (*ptr || ptr == name || strlen(name) > 127)
636 {
637 cgiSetVariable("ERROR",
638 cgiText(_("The class name may only contain up to "
639 "127 printable characters and may not "
640 "contain spaces, slashes (/), or the "
641 "pound sign (#).")));
642 cgiStartHTML(title);
643 cgiCopyTemplateLang("error.tmpl");
644 cgiEndHTML();
645 return;
646 }
647
648 /*
649 * Build a CUPS_ADD_CLASS request, which requires the following
650 * attributes:
651 *
652 * attributes-charset
653 * attributes-natural-language
654 * printer-uri
655 * printer-location
656 * printer-info
657 * printer-is-accepting-jobs
658 * printer-state
659 * member-uris
660 */
661
662 request = ippNewRequest(CUPS_ADD_CLASS);
663
664 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
665 "localhost", 0, "/classes/%s",
666 cgiGetVariable("PRINTER_NAME"));
667 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
668 NULL, uri);
669
670 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
671 NULL, cgiGetVariable("PRINTER_LOCATION"));
672
673 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
674 NULL, cgiGetVariable("PRINTER_INFO"));
675
676 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
677
678 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
679 IPP_PRINTER_IDLE);
680
681 if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
682 {
683 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
684 num_printers, NULL, NULL);
685 for (i = 0; i < num_printers; i ++)
686 attr->values[i].string.text = strdup(cgiGetArray("MEMBER_URIS", i));
687 }
688
689 /*
690 * Do the request and get back a response...
691 */
692
693 ippDelete(cupsDoRequest(http, request, "/admin/"));
694
695 if (cupsLastError() == IPP_NOT_AUTHORIZED)
696 {
697 puts("Status: 401\n");
698 exit(0);
699 }
700 else if (cupsLastError() > IPP_OK_CONFLICT)
701 {
702 cgiStartHTML(title);
703 cgiShowIPPError(modify ? _("Unable to modify class:") :
704 _("Unable to add class:"));
705 }
706 else
707 {
708 /*
709 * Redirect successful updates back to the class page...
710 */
711
712 char refresh[1024]; /* Refresh URL */
713
714 cgiFormEncode(uri, name, sizeof(uri));
715 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
716 uri);
717 cgiSetVariable("refresh_page", refresh);
718
719 cgiStartHTML(title);
720
721 if (modify)
722 cgiCopyTemplateLang("class-modified.tmpl");
723 else
724 cgiCopyTemplateLang("class-added.tmpl");
725 }
726
727 cgiEndHTML();
728 }
729
730
731 /*
732 * 'do_am_printer()' - Add or modify a printer.
733 */
734
735 static void
736 do_am_printer(http_t *http, /* I - HTTP connection */
737 int modify) /* I - Modify the printer? */
738 {
739 int i; /* Looping var */
740 ipp_attribute_t *attr; /* Current attribute */
741 ipp_t *request, /* IPP request */
742 *response, /* IPP response */
743 *oldinfo; /* Old printer information */
744 const cgi_file_t *file; /* Uploaded file, if any */
745 const char *var; /* CGI variable */
746 char uri[HTTP_MAX_URI], /* Device or printer URI */
747 *uriptr; /* Pointer into URI */
748 int maxrate; /* Maximum baud rate */
749 char baudrate[255]; /* Baud rate string */
750 const char *name, /* Pointer to class name */
751 *ptr; /* Pointer to CGI variable */
752 const char *title; /* Title of page */
753 static int baudrates[] = /* Baud rates */
754 {
755 1200,
756 2400,
757 4800,
758 9600,
759 19200,
760 38400,
761 57600,
762 115200,
763 230400,
764 460800
765 };
766
767
768 ptr = cgiGetVariable("DEVICE_URI");
769 fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
770 ptr ? ptr : "(null)");
771
772 title = cgiText(modify ? _("Modify Printer") : _("Add Printer"));
773
774 if (modify)
775 {
776 /*
777 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
778 * following attributes:
779 *
780 * attributes-charset
781 * attributes-natural-language
782 * printer-uri
783 */
784
785 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
786
787 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
788 "localhost", 0, "/printers/%s",
789 cgiGetVariable("PRINTER_NAME"));
790 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
791 NULL, uri);
792
793 /*
794 * Do the request and get back a response...
795 */
796
797 oldinfo = cupsDoRequest(http, request, "/");
798 }
799 else
800 oldinfo = NULL;
801
802 file = cgiGetFile();
803
804 if (file)
805 {
806 fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
807 fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
808 fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
809 fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
810 }
811
812 if ((name = cgiGetVariable("PRINTER_NAME")) != NULL)
813 {
814 for (ptr = name; *ptr; ptr ++)
815 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
816 break;
817
818 if (*ptr || ptr == name || strlen(name) > 127)
819 {
820 cgiSetVariable("ERROR",
821 cgiText(_("The printer name may only contain up to "
822 "127 printable characters and may not "
823 "contain spaces, slashes (/), or the "
824 "pound sign (#).")));
825 cgiStartHTML(title);
826 cgiCopyTemplateLang("error.tmpl");
827 cgiEndHTML();
828 return;
829 }
830 }
831
832 if ((var = cgiGetVariable("DEVICE_URI")) != NULL)
833 {
834 if ((uriptr = strrchr(var, '|')) != NULL)
835 {
836 /*
837 * Extract make and make/model from device URI string...
838 */
839
840 char make[1024], /* Make string */
841 *makeptr; /* Pointer into make */
842
843
844 *uriptr++ = '\0';
845
846 strlcpy(make, uriptr, sizeof(make));
847
848 if ((makeptr = strchr(make, ' ')) != NULL)
849 *makeptr = '\0';
850 else if ((makeptr = strchr(make, '-')) != NULL)
851 *makeptr = '\0';
852 else if (!strncasecmp(make, "laserjet", 8) ||
853 !strncasecmp(make, "deskjet", 7) ||
854 !strncasecmp(make, "designjet", 9))
855 strcpy(make, "HP");
856 else if (!strncasecmp(make, "phaser", 6))
857 strcpy(make, "Xerox");
858 else if (!strncasecmp(make, "stylus", 6))
859 strcpy(make, "Epson");
860 else
861 strcpy(make, "Generic");
862
863 if (!cgiGetVariable("CURRENT_MAKE"))
864 cgiSetVariable("CURRENT_MAKE", make);
865
866 cgiSetVariable("PPD_MAKE", make);
867
868 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
869 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
870
871 if (!modify)
872 {
873 char template[128], /* Template name */
874 *tptr; /* Pointer into template name */
875
876 cgiSetVariable("PRINTER_INFO", uriptr);
877
878 for (tptr = template;
879 tptr < (template + sizeof(template) - 1) && *uriptr;
880 uriptr ++)
881 if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' ||
882 *uriptr == '.')
883 *tptr++ = *uriptr;
884 else if ((*uriptr == ' ' || *uriptr == '/') && tptr[-1] != '_')
885 *tptr++ = '_';
886 else if (*uriptr == '?' || *uriptr == '(')
887 break;
888
889 *tptr = '\0';
890
891 cgiSetVariable("TEMPLATE_NAME", template);
892 }
893 }
894 }
895
896 if (!var)
897 {
898 /*
899 * Look for devices so the user can pick something...
900 */
901
902 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
903 {
904 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
905 if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
906 *uriptr = '\0';
907
908 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
909 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
910 }
911
912 /*
913 * Scan for devices for up to 30 seconds, updating the page as we find
914 * them...
915 */
916
917 fputs("DEBUG: Getting list of devices...\n", stderr);
918
919 last_device_time = 0;
920 current_device = 0;
921 if (cupsGetDevices(http, 30, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
922 (cups_device_cb_t)choose_device_cb,
923 (void *)title) == IPP_OK)
924 {
925 fputs("DEBUG: Got device list!\n", stderr);
926
927 if (!cgiSupportsMultipart())
928 {
929 /*
930 * Non-modern browsers that don't support multi-part documents get
931 * everything at the end...
932 */
933
934 cgiStartHTML(title);
935 cgiCopyTemplateLang("choose-device.tmpl");
936 cgiEndHTML();
937 }
938 }
939 else
940 {
941 fprintf(stderr,
942 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
943 cupsLastError(), cupsLastErrorString());
944 if (cupsLastError() == IPP_NOT_AUTHORIZED)
945 {
946 puts("Status: 401\n");
947 exit(0);
948 }
949 else
950 {
951 cgiStartHTML(title);
952 cgiShowIPPError(modify ? _("Unable to modify printer:") :
953 _("Unable to add printer:"));
954 cgiEndHTML();
955 return;
956 }
957 }
958
959 /*
960 * Show the final selection page...
961 */
962
963 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
964 cgiStartHTML(title);
965 cgiCopyTemplateLang("choose-device.tmpl");
966 cgiEndHTML();
967 cgiEndMultipart();
968 }
969 else if (strchr(var, '/') == NULL)
970 {
971 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
972 {
973 /*
974 * Set the current device URI for the form to the old one...
975 */
976
977 if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
978 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
979 }
980
981 /*
982 * User needs to set the full URI...
983 */
984
985 cgiStartHTML(title);
986 cgiCopyTemplateLang("choose-uri.tmpl");
987 cgiEndHTML();
988 }
989 else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
990 {
991 /*
992 * Need baud rate, parity, etc.
993 */
994
995 if ((var = strchr(var, '?')) != NULL &&
996 strncmp(var, "?baud=", 6) == 0)
997 maxrate = atoi(var + 6);
998 else
999 maxrate = 19200;
1000
1001 for (i = 0; i < 10; i ++)
1002 if (baudrates[i] > maxrate)
1003 break;
1004 else
1005 {
1006 sprintf(baudrate, "%d", baudrates[i]);
1007 cgiSetArray("BAUDRATES", i, baudrate);
1008 }
1009
1010 cgiStartHTML(title);
1011 cgiCopyTemplateLang("choose-serial.tmpl");
1012 cgiEndHTML();
1013 }
1014 else if (!name || !cgiGetVariable("PRINTER_LOCATION"))
1015 {
1016 cgiStartHTML(title);
1017
1018 if (modify)
1019 {
1020 /*
1021 * Update the location and description of an existing printer...
1022 */
1023
1024 if (oldinfo)
1025 {
1026 if ((attr = ippFindAttribute(oldinfo, "printer-info",
1027 IPP_TAG_TEXT)) != NULL)
1028 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
1029
1030 if ((attr = ippFindAttribute(oldinfo, "printer-location",
1031 IPP_TAG_TEXT)) != NULL)
1032 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
1033 }
1034
1035 cgiCopyTemplateLang("modify-printer.tmpl");
1036 }
1037 else
1038 {
1039 /*
1040 * Get the name, location, and description for a new printer...
1041 */
1042
1043 #ifdef __APPLE__
1044 if (!strncmp(var, "usb:", 4))
1045 cgiSetVariable("printer_is_shared", "1");
1046 else
1047 #endif /* __APPLE__ */
1048 cgiSetVariable("printer_is_shared", "0");
1049
1050 cgiCopyTemplateLang("add-printer.tmpl");
1051 }
1052
1053 cgiEndHTML();
1054
1055 if (oldinfo)
1056 ippDelete(oldinfo);
1057
1058 return;
1059 }
1060 else if (!file &&
1061 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1062 {
1063 if (modify && !cgiGetVariable("SELECT_MAKE"))
1064 {
1065 /*
1066 * Get the PPD file...
1067 */
1068
1069 int fd; /* PPD file */
1070 char filename[1024]; /* PPD filename */
1071 ppd_file_t *ppd; /* PPD information */
1072 char buffer[1024]; /* Buffer */
1073 int bytes; /* Number of bytes */
1074 http_status_t get_status; /* Status of GET */
1075
1076
1077 /* TODO: Use cupsGetFile() API... */
1078 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
1079
1080 if (httpGet(http, uri))
1081 httpGet(http, uri);
1082
1083 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
1084
1085 if (get_status != HTTP_OK)
1086 {
1087 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
1088 uri, get_status, httpStatus(get_status));
1089 }
1090 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
1091 {
1092 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
1093 write(fd, buffer, bytes);
1094
1095 close(fd);
1096
1097 if ((ppd = ppdOpenFile(filename)) != NULL)
1098 {
1099 if (ppd->manufacturer)
1100 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
1101
1102 if (ppd->nickname)
1103 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
1104
1105 ppdClose(ppd);
1106 unlink(filename);
1107 }
1108 else
1109 {
1110 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
1111 filename, ppdErrorString(ppdLastError(&bytes)));
1112 }
1113 }
1114 else
1115 {
1116 httpFlush(http);
1117
1118 fprintf(stderr,
1119 "ERROR: Unable to create temporary file for PPD file: %s\n",
1120 strerror(errno));
1121 }
1122 }
1123
1124 /*
1125 * Build a CUPS_GET_PPDS request, which requires the following
1126 * attributes:
1127 *
1128 * attributes-charset
1129 * attributes-natural-language
1130 * printer-uri
1131 */
1132
1133 request = ippNewRequest(CUPS_GET_PPDS);
1134
1135 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1136 NULL, "ipp://localhost/printers/");
1137
1138 if ((var = cgiGetVariable("CURRENT_MAKE")) == NULL)
1139 var = cgiGetVariable("PPD_MAKE");
1140 if (var && !cgiGetVariable("SELECT_MAKE"))
1141 {
1142 const char *make_model; /* Make and model */
1143
1144
1145 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1146 "ppd-make", NULL, var);
1147
1148 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
1149 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1150 "ppd-make-and-model", NULL, make_model);
1151 }
1152 else
1153 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1154 "requested-attributes", NULL, "ppd-make");
1155
1156 /*
1157 * Do the request and get back a response...
1158 */
1159
1160 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1161 {
1162 /*
1163 * Got the list of PPDs, see if the user has selected a make...
1164 */
1165
1166 if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0)
1167 {
1168 /*
1169 * No PPD files with this make, try again with all makes...
1170 */
1171
1172 ippDelete(response);
1173
1174 request = ippNewRequest(CUPS_GET_PPDS);
1175
1176 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1177 NULL, "ipp://localhost/printers/");
1178
1179 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1180 "requested-attributes", NULL, "ppd-make");
1181
1182 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1183 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1184
1185 cgiStartHTML(title);
1186 cgiCopyTemplateLang("choose-make.tmpl");
1187 cgiEndHTML();
1188 }
1189 else if (!var || cgiGetVariable("SELECT_MAKE"))
1190 {
1191 cgiStartHTML(title);
1192 cgiCopyTemplateLang("choose-make.tmpl");
1193 cgiEndHTML();
1194 }
1195 else
1196 {
1197 /*
1198 * Let the user choose a model...
1199 */
1200
1201 cgiStartHTML(title);
1202 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1203 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1204 cgiCopyTemplateLang("choose-model.tmpl");
1205 cgiEndHTML();
1206 }
1207
1208 ippDelete(response);
1209 }
1210 else
1211 {
1212 cgiStartHTML(title);
1213 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1214 cgiCopyTemplateLang("error.tmpl");
1215 cgiEndHTML();
1216 }
1217 }
1218 else
1219 {
1220 /*
1221 * Build a CUPS_ADD_PRINTER request, which requires the following
1222 * attributes:
1223 *
1224 * attributes-charset
1225 * attributes-natural-language
1226 * printer-uri
1227 * printer-location
1228 * printer-info
1229 * ppd-name
1230 * device-uri
1231 * printer-is-accepting-jobs
1232 * printer-is-shared
1233 * printer-state
1234 */
1235
1236 request = ippNewRequest(CUPS_ADD_PRINTER);
1237
1238 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1239 "localhost", 0, "/printers/%s",
1240 cgiGetVariable("PRINTER_NAME"));
1241 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1242 NULL, uri);
1243
1244 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1245 NULL, cgiGetVariable("PRINTER_LOCATION"));
1246
1247 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1248 NULL, cgiGetVariable("PRINTER_INFO"));
1249
1250 if (!file)
1251 {
1252 var = cgiGetVariable("PPD_NAME");
1253 if (strcmp(var, "__no_change__"))
1254 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
1255 NULL, var);
1256 }
1257
1258 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1259
1260 /*
1261 * Strip make and model from URI...
1262 */
1263
1264 if ((uriptr = strrchr(uri, '|')) != NULL)
1265 *uriptr = '\0';
1266
1267 if (!strncmp(uri, "serial:", 7))
1268 {
1269 /*
1270 * Update serial port URI to include baud rate, etc.
1271 */
1272
1273 if ((uriptr = strchr(uri, '?')) == NULL)
1274 uriptr = uri + strlen(uri);
1275
1276 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
1277 "?baud=%s+bits=%s+parity=%s+flow=%s",
1278 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1279 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1280 }
1281
1282 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1283 NULL, uri);
1284
1285 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1286
1287 var = cgiGetVariable("printer_is_shared");
1288 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared",
1289 var && (!strcmp(var, "1") || !strcmp(var, "on")));
1290
1291 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1292 IPP_PRINTER_IDLE);
1293
1294 /*
1295 * Do the request and get back a response...
1296 */
1297
1298 if (file)
1299 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
1300 else
1301 ippDelete(cupsDoRequest(http, request, "/admin/"));
1302
1303 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1304 {
1305 puts("Status: 401\n");
1306 exit(0);
1307 }
1308 else if (cupsLastError() > IPP_OK_CONFLICT)
1309 {
1310 cgiStartHTML(title);
1311 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1312 _("Unable to add printer:"));
1313 }
1314 else if (modify)
1315 {
1316 /*
1317 * Redirect successful updates back to the printer page...
1318 */
1319
1320 char refresh[1024]; /* Refresh URL */
1321
1322
1323 cgiFormEncode(uri, name, sizeof(uri));
1324
1325 snprintf(refresh, sizeof(refresh),
1326 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
1327
1328 cgiSetVariable("refresh_page", refresh);
1329
1330 cgiStartHTML(title);
1331
1332 cgiCopyTemplateLang("printer-modified.tmpl");
1333 }
1334 else
1335 {
1336 /*
1337 * Set the printer options...
1338 */
1339
1340 cgiSetVariable("OP", "set-printer-options");
1341 do_set_options(http, 0);
1342 return;
1343 }
1344
1345 cgiEndHTML();
1346 }
1347
1348 if (oldinfo)
1349 ippDelete(oldinfo);
1350 }
1351
1352
1353 /*
1354 * 'do_cancel_subscription()' - Cancel a subscription.
1355 */
1356
1357 static void
1358 do_cancel_subscription(http_t *http)/* I - HTTP connection */
1359 {
1360 ipp_t *request; /* IPP request data */
1361 const char *var, /* Form variable */
1362 *user; /* Username */
1363 int id; /* Subscription ID */
1364
1365
1366 /*
1367 * See if we have all of the required information...
1368 */
1369
1370 if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL)
1371 id = atoi(var);
1372 else
1373 id = 0;
1374
1375 if (id <= 0)
1376 {
1377 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1378 cgiStartHTML(_("Cancel RSS Subscription"));
1379 cgiCopyTemplateLang("error.tmpl");
1380 cgiEndHTML();
1381 return;
1382 }
1383
1384 /*
1385 * Require a username...
1386 */
1387
1388 if ((user = getenv("REMOTE_USER")) == NULL)
1389 {
1390 puts("Status: 401\n");
1391 exit(0);
1392 }
1393
1394 /*
1395 * Cancel the subscription...
1396 */
1397
1398 request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
1399
1400 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1401 NULL, "ipp://localhost/");
1402 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
1403 "notify-subscription-id", id);
1404
1405 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1406 NULL, user);
1407
1408 ippDelete(cupsDoRequest(http, request, "/"));
1409
1410 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1411 {
1412 puts("Status: 401\n");
1413 exit(0);
1414 }
1415 else if (cupsLastError() > IPP_OK_CONFLICT)
1416 {
1417 cgiStartHTML(_("Cancel RSS Subscription"));
1418 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1419 }
1420 else
1421 {
1422 /*
1423 * Redirect successful updates back to the admin page...
1424 */
1425
1426 cgiSetVariable("refresh_page", "5;URL=/admin");
1427 cgiStartHTML(_("Cancel RSS Subscription"));
1428 cgiCopyTemplateLang("subscription-canceled.tmpl");
1429 }
1430
1431 cgiEndHTML();
1432 }
1433
1434
1435 /*
1436 * 'do_config_server()' - Configure server settings.
1437 */
1438
1439 static void
1440 do_config_server(http_t *http) /* I - HTTP connection */
1441 {
1442 if (cgiGetVariable("CHANGESETTINGS"))
1443 {
1444 /*
1445 * Save basic setting changes...
1446 */
1447
1448 int num_settings; /* Number of server settings */
1449 cups_option_t *settings; /* Server settings */
1450 int advanced, /* Advanced settings shown? */
1451 changed; /* Have settings changed? */
1452 const char *debug_logging, /* DEBUG_LOGGING value */
1453 *remote_admin, /* REMOTE_ADMIN value */
1454 *remote_any, /* REMOTE_ANY value */
1455 *remote_printers,
1456 /* REMOTE_PRINTERS value */
1457 *share_printers,/* SHARE_PRINTERS value */
1458 *user_cancel_any,
1459 /* USER_CANCEL_ANY value */
1460 *browse_web_if = NULL,
1461 /* BrowseWebIF value */
1462 *preserve_job_history = NULL,
1463 /* PreserveJobHistory value */
1464 *preserve_job_files = NULL,
1465 /* PreserveJobFiles value */
1466 *max_clients = NULL,
1467 /* MaxClients value */
1468 *max_jobs = NULL,
1469 /* MaxJobs value */
1470 *max_log_size = NULL;
1471 /* MaxLogSize value */
1472 char local_protocols[255],
1473 /* BrowseLocalProtocols */
1474 remote_protocols[255];
1475 /* BrowseRemoteProtocols */
1476 const char *current_browse_web_if,
1477 /* BrowseWebIF value */
1478 *current_preserve_job_history,
1479 /* PreserveJobHistory value */
1480 *current_preserve_job_files,
1481 /* PreserveJobFiles value */
1482 *current_max_clients,
1483 /* MaxClients value */
1484 *current_max_jobs,
1485 /* MaxJobs value */
1486 *current_max_log_size,
1487 /* MaxLogSize value */
1488 *current_local_protocols,
1489 /* BrowseLocalProtocols */
1490 *current_remote_protocols;
1491 /* BrowseRemoteProtocols */
1492 #ifdef HAVE_GSSAPI
1493 char default_auth_type[255];
1494 /* DefaultAuthType value */
1495 const char *val; /* Setting value */
1496 #endif /* HAVE_GSSAPI */
1497
1498
1499 /*
1500 * Get the checkbox values from the form...
1501 */
1502
1503 debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1504 remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1505 remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1506 remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1507 share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1508 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1509
1510 advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL;
1511 if (advanced)
1512 {
1513 /*
1514 * Get advanced settings...
1515 */
1516
1517 browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1518 preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1519 preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1520 max_clients = cgiGetVariable("MAX_CLIENTS");
1521 max_jobs = cgiGetVariable("MAX_JOBS");
1522 max_log_size = cgiGetVariable("MAX_LOG_SIZE");
1523
1524 if (!max_clients || atoi(max_clients) <= 0)
1525 max_clients = "100";
1526
1527 if (!max_jobs || atoi(max_jobs) <= 0)
1528 max_jobs = "500";
1529
1530 if (!max_log_size || atof(max_log_size) <= 0.0)
1531 max_log_size = "1m";
1532
1533 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1534 strcpy(local_protocols, "cups");
1535 else
1536 local_protocols[0] = '\0';
1537
1538 #ifdef HAVE_DNSSD
1539 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1540 {
1541 if (local_protocols[0])
1542 strcat(local_protocols, " dnssd");
1543 else
1544 strcat(local_protocols, "dnssd");
1545 }
1546 #endif /* HAVE_DNSSD */
1547
1548 #ifdef HAVE_LDAP
1549 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1550 {
1551 if (local_protocols[0])
1552 strcat(local_protocols, " ldap");
1553 else
1554 strcat(local_protocols, "ldap");
1555 }
1556 #endif /* HAVE_LDAP */
1557
1558 #ifdef HAVE_LIBSLP
1559 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1560 {
1561 if (local_protocols[0])
1562 strcat(local_protocols, " slp");
1563 else
1564 strcat(local_protocols, "slp");
1565 }
1566 #endif /* HAVE_SLP */
1567
1568 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1569 strcpy(remote_protocols, "cups");
1570 else
1571 remote_protocols[0] = '\0';
1572
1573 #ifdef HAVE_LDAP
1574 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1575 {
1576 if (remote_protocols[0])
1577 strcat(remote_protocols, " ldap");
1578 else
1579 strcat(remote_protocols, "ldap");
1580 }
1581 #endif /* HAVE_LDAP */
1582
1583 #ifdef HAVE_LIBSLP
1584 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1585 {
1586 if (remote_protocols[0])
1587 strcat(remote_protocols, " slp");
1588 else
1589 strcat(remote_protocols, "slp");
1590 }
1591 #endif /* HAVE_SLP */
1592 }
1593
1594 /*
1595 * Get the current server settings...
1596 */
1597
1598 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
1599 {
1600 cgiStartHTML(cgiText(_("Change Settings")));
1601 cgiSetVariable("MESSAGE",
1602 cgiText(_("Unable to change server settings:")));
1603 cgiSetVariable("ERROR", cupsLastErrorString());
1604 cgiCopyTemplateLang("error.tmpl");
1605 cgiEndHTML();
1606 return;
1607 }
1608
1609 #ifdef HAVE_GSSAPI
1610 /*
1611 * Get authentication settings...
1612 */
1613
1614 if (cgiGetVariable("KERBEROS"))
1615 strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
1616 else
1617 {
1618 val = cupsGetOption("DefaultAuthType", num_settings, settings);
1619
1620 if (!val || !strcasecmp(val, "Negotiate"))
1621 strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
1622 else
1623 strlcpy(default_auth_type, val, sizeof(default_auth_type));
1624 }
1625
1626 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1627 #endif /* HAVE_GSSAPI */
1628
1629 if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings,
1630 settings)) == NULL)
1631 current_browse_web_if = "No";
1632
1633 if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory",
1634 num_settings,
1635 settings)) == NULL)
1636 current_preserve_job_history = "Yes";
1637
1638 if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles",
1639 num_settings,
1640 settings)) == NULL)
1641 current_preserve_job_files = "No";
1642
1643 if ((current_max_clients = cupsGetOption("MaxClients", num_settings,
1644 settings)) == NULL)
1645 current_max_clients = "100";
1646
1647 if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings,
1648 settings)) == NULL)
1649 current_max_jobs = "500";
1650
1651 if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings,
1652 settings)) == NULL)
1653 current_max_log_size = "1m";
1654
1655 if ((current_local_protocols = cupsGetOption("BrowseLocalProtocols",
1656 num_settings,
1657 settings)) == NULL)
1658 current_local_protocols = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
1659
1660 if ((current_remote_protocols = cupsGetOption("BrowseRemoteProtocols",
1661 num_settings,
1662 settings)) == NULL)
1663 current_remote_protocols = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
1664
1665 /*
1666 * See if the settings have changed...
1667 */
1668
1669 changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1670 num_settings, settings)) ||
1671 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1672 num_settings, settings)) ||
1673 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1674 num_settings, settings)) ||
1675 strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
1676 num_settings, settings)) ||
1677 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1678 num_settings, settings)) ||
1679 #ifdef HAVE_GSSAPI
1680 !cupsGetOption("DefaultAuthType", num_settings, settings) ||
1681 strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1682 num_settings, settings)) ||
1683 #endif /* HAVE_GSSAPI */
1684 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1685 num_settings, settings));
1686
1687 if (advanced && !changed)
1688 changed = strcasecmp(local_protocols, current_local_protocols) ||
1689 strcasecmp(remote_protocols, current_remote_protocols) ||
1690 strcasecmp(browse_web_if, current_browse_web_if) ||
1691 strcasecmp(preserve_job_history, current_preserve_job_history) ||
1692 strcasecmp(preserve_job_files, current_preserve_job_files) ||
1693 strcasecmp(max_clients, current_max_clients) ||
1694 strcasecmp(max_jobs, current_max_jobs) ||
1695 strcasecmp(max_log_size, current_max_log_size);
1696
1697 if (changed)
1698 {
1699 /*
1700 * Settings *have* changed, so save the changes...
1701 */
1702
1703 cupsFreeOptions(num_settings, settings);
1704
1705 num_settings = 0;
1706 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1707 debug_logging, num_settings, &settings);
1708 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1709 remote_admin, num_settings, &settings);
1710 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1711 remote_any, num_settings, &settings);
1712 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1713 remote_printers, num_settings, &settings);
1714 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1715 share_printers, num_settings, &settings);
1716 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1717 user_cancel_any, num_settings, &settings);
1718 #ifdef HAVE_GSSAPI
1719 num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
1720 num_settings, &settings);
1721 #endif /* HAVE_GSSAPI */
1722
1723 if (advanced)
1724 {
1725 /*
1726 * Add advanced settings...
1727 */
1728
1729 if (strcasecmp(local_protocols, current_local_protocols))
1730 num_settings = cupsAddOption("BrowseLocalProtocols", local_protocols,
1731 num_settings, &settings);
1732 if (strcasecmp(remote_protocols, current_remote_protocols))
1733 num_settings = cupsAddOption("BrowseRemoteProtocols", remote_protocols,
1734 num_settings, &settings);
1735 if (strcasecmp(browse_web_if, current_browse_web_if))
1736 num_settings = cupsAddOption("BrowseWebIF", browse_web_if,
1737 num_settings, &settings);
1738 if (strcasecmp(preserve_job_history, current_preserve_job_history))
1739 num_settings = cupsAddOption("PreserveJobHistory",
1740 preserve_job_history, num_settings,
1741 &settings);
1742 if (strcasecmp(preserve_job_files, current_preserve_job_files))
1743 num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files,
1744 num_settings, &settings);
1745 if (strcasecmp(max_clients, current_max_clients))
1746 num_settings = cupsAddOption("MaxClients", max_clients, num_settings,
1747 &settings);
1748 if (strcasecmp(max_jobs, current_max_jobs))
1749 num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings,
1750 &settings);
1751 if (strcasecmp(max_log_size, current_max_log_size))
1752 num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings,
1753 &settings);
1754 }
1755
1756 if (!cupsAdminSetServerSettings(http, num_settings, settings))
1757 {
1758 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1759 {
1760 puts("Status: 401\n");
1761 exit(0);
1762 }
1763
1764 cgiStartHTML(cgiText(_("Change Settings")));
1765 cgiSetVariable("MESSAGE",
1766 cgiText(_("Unable to change server settings:")));
1767 cgiSetVariable("ERROR", cupsLastErrorString());
1768 cgiCopyTemplateLang("error.tmpl");
1769 }
1770 else
1771 {
1772 if (advanced)
1773 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1774 else
1775 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1776 cgiStartHTML(cgiText(_("Change Settings")));
1777 cgiCopyTemplateLang("restart.tmpl");
1778 }
1779 }
1780 else
1781 {
1782 /*
1783 * No changes...
1784 */
1785
1786 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1787 cgiStartHTML(cgiText(_("Change Settings")));
1788 cgiCopyTemplateLang("norestart.tmpl");
1789 }
1790
1791 cupsFreeOptions(num_settings, settings);
1792
1793 cgiEndHTML();
1794 }
1795 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1796 {
1797 /*
1798 * Save hand-edited config file...
1799 */
1800
1801 http_status_t status; /* PUT status */
1802 char tempfile[1024]; /* Temporary new cupsd.conf */
1803 int tempfd; /* Temporary file descriptor */
1804 cups_file_t *temp; /* Temporary file */
1805 const char *start, /* Start of line */
1806 *end; /* End of line */
1807
1808
1809 /*
1810 * Create a temporary file for the new cupsd.conf file...
1811 */
1812
1813 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1814 {
1815 cgiStartHTML(cgiText(_("Edit Configuration File")));
1816 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1817 cgiSetVariable("ERROR", strerror(errno));
1818 cgiCopyTemplateLang("error.tmpl");
1819 cgiEndHTML();
1820
1821 perror(tempfile);
1822 return;
1823 }
1824
1825 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
1826 {
1827 cgiStartHTML(cgiText(_("Edit Configuration File")));
1828 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1829 cgiSetVariable("ERROR", strerror(errno));
1830 cgiCopyTemplateLang("error.tmpl");
1831 cgiEndHTML();
1832
1833 perror(tempfile);
1834 close(tempfd);
1835 unlink(tempfile);
1836 return;
1837 }
1838
1839 /*
1840 * Copy the cupsd.conf text from the form variable...
1841 */
1842
1843 start = cgiGetVariable("CUPSDCONF");
1844 while (start)
1845 {
1846 if ((end = strstr(start, "\r\n")) == NULL)
1847 if ((end = strstr(start, "\n")) == NULL)
1848 end = start + strlen(start);
1849
1850 cupsFileWrite(temp, start, end - start);
1851 cupsFilePutChar(temp, '\n');
1852
1853 if (*end == '\r')
1854 start = end + 2;
1855 else if (*end == '\n')
1856 start = end + 1;
1857 else
1858 start = NULL;
1859 }
1860
1861 cupsFileClose(temp);
1862
1863 /*
1864 * Upload the configuration file to the server...
1865 */
1866
1867 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1868
1869 if (status == HTTP_UNAUTHORIZED)
1870 {
1871 puts("Status: 401\n");
1872 unlink(tempfile);
1873 exit(0);
1874 }
1875 else if (status != HTTP_CREATED)
1876 {
1877 cgiSetVariable("MESSAGE",
1878 cgiText(_("Unable to upload cupsd.conf file:")));
1879 cgiSetVariable("ERROR", httpStatus(status));
1880
1881 cgiStartHTML(cgiText(_("Edit Configuration File")));
1882 cgiCopyTemplateLang("error.tmpl");
1883 }
1884 else
1885 {
1886 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1887
1888 cgiStartHTML(cgiText(_("Edit Configuration File")));
1889 cgiCopyTemplateLang("restart.tmpl");
1890 }
1891
1892 cgiEndHTML();
1893
1894 unlink(tempfile);
1895 }
1896 else
1897 {
1898 struct stat info; /* cupsd.conf information */
1899 cups_file_t *cupsd; /* cupsd.conf file */
1900 char *buffer, /* Buffer for entire file */
1901 *bufptr, /* Pointer into buffer */
1902 *bufend; /* End of buffer */
1903 int ch; /* Character from file */
1904 char filename[1024]; /* Filename */
1905 const char *server_root; /* Location of config files */
1906
1907
1908 /*
1909 * Locate the cupsd.conf file...
1910 */
1911
1912 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1913 server_root = CUPS_SERVERROOT;
1914
1915 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
1916
1917 /*
1918 * Figure out the size...
1919 */
1920
1921 if (stat(filename, &info))
1922 {
1923 cgiStartHTML(cgiText(_("Edit Configuration File")));
1924 cgiSetVariable("MESSAGE",
1925 cgiText(_("Unable to access cupsd.conf file:")));
1926 cgiSetVariable("ERROR", strerror(errno));
1927 cgiCopyTemplateLang("error.tmpl");
1928 cgiEndHTML();
1929
1930 perror(filename);
1931 return;
1932 }
1933
1934 if (info.st_size > (1024 * 1024))
1935 {
1936 cgiStartHTML(cgiText(_("Edit Configuration File")));
1937 cgiSetVariable("MESSAGE",
1938 cgiText(_("Unable to access cupsd.conf file:")));
1939 cgiSetVariable("ERROR",
1940 cgiText(_("Unable to edit cupsd.conf files larger than "
1941 "1MB!")));
1942 cgiCopyTemplateLang("error.tmpl");
1943 cgiEndHTML();
1944
1945 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
1946 (long)info.st_size);
1947 return;
1948 }
1949
1950 /*
1951 * Open the cupsd.conf file...
1952 */
1953
1954 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
1955 {
1956 /*
1957 * Unable to open - log an error...
1958 */
1959
1960 cgiStartHTML(cgiText(_("Edit Configuration File")));
1961 cgiSetVariable("MESSAGE",
1962 cgiText(_("Unable to access cupsd.conf file:")));
1963 cgiSetVariable("ERROR", strerror(errno));
1964 cgiCopyTemplateLang("error.tmpl");
1965 cgiEndHTML();
1966
1967 perror(filename);
1968 return;
1969 }
1970
1971 /*
1972 * Allocate memory and load the file into a string buffer...
1973 */
1974
1975 if ((buffer = calloc(1, info.st_size + 1)) != NULL)
1976 {
1977 cupsFileRead(cupsd, buffer, info.st_size);
1978 cgiSetVariable("CUPSDCONF", buffer);
1979 free(buffer);
1980 }
1981
1982 cupsFileClose(cupsd);
1983
1984 /*
1985 * Then get the default cupsd.conf file and put that into a string as
1986 * well...
1987 */
1988
1989 strlcat(filename, ".default", sizeof(filename));
1990
1991 if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
1992 (cupsd = cupsFileOpen(filename, "r")) != NULL)
1993 {
1994 if ((buffer = calloc(1, 2 * info.st_size + 1)) != NULL)
1995 {
1996 bufend = buffer + 2 * info.st_size - 1;
1997
1998 for (bufptr = buffer;
1999 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
2000 {
2001 if (ch == '\\' || ch == '\"')
2002 {
2003 *bufptr++ = '\\';
2004 *bufptr++ = ch;
2005 }
2006 else if (ch == '\n')
2007 {
2008 *bufptr++ = '\\';
2009 *bufptr++ = 'n';
2010 }
2011 else if (ch == '\t')
2012 {
2013 *bufptr++ = '\\';
2014 *bufptr++ = 't';
2015 }
2016 else if (ch >= ' ')
2017 *bufptr++ = ch;
2018 }
2019
2020 *bufptr = '\0';
2021
2022 cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
2023 free(buffer);
2024 }
2025
2026 cupsFileClose(cupsd);
2027 }
2028
2029 /*
2030 * Show the current config file...
2031 */
2032
2033 cgiStartHTML(cgiText(_("Edit Configuration File")));
2034
2035 cgiCopyTemplateLang("edit-config.tmpl");
2036
2037 cgiEndHTML();
2038 }
2039 }
2040
2041
2042 /*
2043 * 'do_delete_class()' - Delete a class.
2044 */
2045
2046 static void
2047 do_delete_class(http_t *http) /* I - HTTP connection */
2048 {
2049 ipp_t *request; /* IPP request */
2050 char uri[HTTP_MAX_URI]; /* Job URI */
2051 const char *pclass; /* Printer class name */
2052
2053
2054 /*
2055 * Get form variables...
2056 */
2057
2058 if (cgiGetVariable("CONFIRM") == NULL)
2059 {
2060 cgiStartHTML(cgiText(_("Delete Class")));
2061 cgiCopyTemplateLang("class-confirm.tmpl");
2062 cgiEndHTML();
2063 return;
2064 }
2065
2066 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
2067 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2068 "localhost", 0, "/classes/%s", pclass);
2069 else
2070 {
2071 cgiStartHTML(cgiText(_("Delete Class")));
2072 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2073 cgiCopyTemplateLang("error.tmpl");
2074 cgiEndHTML();
2075 return;
2076 }
2077
2078 /*
2079 * Build a CUPS_DELETE_CLASS request, which requires the following
2080 * attributes:
2081 *
2082 * attributes-charset
2083 * attributes-natural-language
2084 * printer-uri
2085 */
2086
2087 request = ippNewRequest(CUPS_DELETE_CLASS);
2088
2089 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2090 NULL, uri);
2091
2092 /*
2093 * Do the request and get back a response...
2094 */
2095
2096 ippDelete(cupsDoRequest(http, request, "/admin/"));
2097
2098 /*
2099 * Show the results...
2100 */
2101
2102 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2103 {
2104 puts("Status: 401\n");
2105 exit(0);
2106 }
2107 else if (cupsLastError() <= IPP_OK_CONFLICT)
2108 {
2109 /*
2110 * Redirect successful updates back to the classes page...
2111 */
2112
2113 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2114 }
2115
2116 cgiStartHTML(cgiText(_("Delete Class")));
2117
2118 if (cupsLastError() > IPP_OK_CONFLICT)
2119 cgiShowIPPError(_("Unable to delete class:"));
2120 else
2121 cgiCopyTemplateLang("class-deleted.tmpl");
2122
2123 cgiEndHTML();
2124 }
2125
2126
2127 /*
2128 * 'do_delete_printer()' - Delete a printer.
2129 */
2130
2131 static void
2132 do_delete_printer(http_t *http) /* I - HTTP connection */
2133 {
2134 ipp_t *request; /* IPP request */
2135 char uri[HTTP_MAX_URI]; /* Job URI */
2136 const char *printer; /* Printer printer name */
2137
2138
2139 /*
2140 * Get form variables...
2141 */
2142
2143 if (cgiGetVariable("CONFIRM") == NULL)
2144 {
2145 cgiStartHTML(cgiText(_("Delete Printer")));
2146 cgiCopyTemplateLang("printer-confirm.tmpl");
2147 cgiEndHTML();
2148 return;
2149 }
2150
2151 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2152 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2153 "localhost", 0, "/printers/%s", printer);
2154 else
2155 {
2156 cgiStartHTML(cgiText(_("Delete Printer")));
2157 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2158 cgiCopyTemplateLang("error.tmpl");
2159 cgiEndHTML();
2160 return;
2161 }
2162
2163 /*
2164 * Build a CUPS_DELETE_PRINTER request, which requires the following
2165 * attributes:
2166 *
2167 * attributes-charset
2168 * attributes-natural-language
2169 * printer-uri
2170 */
2171
2172 request = ippNewRequest(CUPS_DELETE_PRINTER);
2173
2174 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2175 NULL, uri);
2176
2177 /*
2178 * Do the request and get back a response...
2179 */
2180
2181 ippDelete(cupsDoRequest(http, request, "/admin/"));
2182
2183 /*
2184 * Show the results...
2185 */
2186
2187 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2188 {
2189 puts("Status: 401\n");
2190 exit(0);
2191 }
2192 else if (cupsLastError() <= IPP_OK_CONFLICT)
2193 {
2194 /*
2195 * Redirect successful updates back to the printers page...
2196 */
2197
2198 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2199 }
2200
2201 cgiStartHTML(cgiText(_("Delete Printer")));
2202
2203 if (cupsLastError() > IPP_OK_CONFLICT)
2204 cgiShowIPPError(_("Unable to delete printer:"));
2205 else
2206 cgiCopyTemplateLang("printer-deleted.tmpl");
2207
2208 cgiEndHTML();
2209 }
2210
2211
2212 /*
2213 * 'do_export()' - Export printers to Samba.
2214 */
2215
2216 static void
2217 do_export(http_t *http) /* I - HTTP connection */
2218 {
2219 int i, j; /* Looping vars */
2220 ipp_t *request, /* IPP request */
2221 *response; /* IPP response */
2222 const char *username, /* Samba username */
2223 *password, /* Samba password */
2224 *export_all; /* Export all printers? */
2225 int export_count, /* Number of printers to export */
2226 printer_count; /* Number of available printers */
2227 const char *name, /* What name to pull */
2228 *dest; /* Current destination */
2229 char ppd[1024]; /* PPD file */
2230
2231
2232 /*
2233 * Get form data...
2234 */
2235
2236 username = cgiGetVariable("USERNAME");
2237 password = cgiGetVariable("PASSWORD");
2238 export_all = cgiGetVariable("EXPORT_ALL");
2239 export_count = cgiGetSize("EXPORT_NAME");
2240
2241 /*
2242 * Get list of available printers...
2243 */
2244
2245 cgiSetSize("PRINTER_NAME", 0);
2246 cgiSetSize("PRINTER_EXPORT", 0);
2247
2248 request = ippNewRequest(CUPS_GET_PRINTERS);
2249
2250 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2251 "printer-type", 0);
2252
2253 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2254 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
2255 CUPS_PRINTER_IMPLICIT);
2256
2257 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2258 "requested-attributes", NULL, "printer-name");
2259
2260 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2261 {
2262 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2263 ippDelete(response);
2264
2265 if (!export_all)
2266 {
2267 printer_count = cgiGetSize("PRINTER_NAME");
2268
2269 for (i = 0; i < printer_count; i ++)
2270 {
2271 dest = cgiGetArray("PRINTER_NAME", i);
2272
2273 for (j = 0; j < export_count; j ++)
2274 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
2275 break;
2276
2277 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
2278 }
2279 }
2280 }
2281
2282 /*
2283 * Export or get the printers to export...
2284 */
2285
2286 if (username && *username && password && *password &&
2287 (export_all || export_count > 0))
2288 {
2289 /*
2290 * Do export...
2291 */
2292
2293 fputs("DEBUG: Export printers...\n", stderr);
2294
2295 if (export_all)
2296 {
2297 name = "PRINTER_NAME";
2298 export_count = cgiGetSize("PRINTER_NAME");
2299 }
2300 else
2301 name = "EXPORT_NAME";
2302
2303 for (i = 0; i < export_count; i ++)
2304 {
2305 dest = cgiGetArray(name, i);
2306
2307 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2308 break;
2309
2310 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2311 stderr);
2312
2313 unlink(ppd);
2314
2315 if (!j)
2316 break;
2317 }
2318
2319 if (i < export_count)
2320 cgiSetVariable("ERROR", cupsLastErrorString());
2321 else
2322 {
2323 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2324 cgiCopyTemplateLang("samba-exported.tmpl");
2325 cgiEndHTML();
2326 return;
2327 }
2328 }
2329 else if (username && !*username)
2330 cgiSetVariable("ERROR",
2331 cgiText(_("A Samba username is required to export "
2332 "printer drivers!")));
2333 else if (username && (!password || !*password))
2334 cgiSetVariable("ERROR",
2335 cgiText(_("A Samba password is required to export "
2336 "printer drivers!")));
2337
2338 /*
2339 * Show form...
2340 */
2341
2342 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2343 cgiCopyTemplateLang("samba-export.tmpl");
2344 cgiEndHTML();
2345 }
2346
2347
2348 /*
2349 * 'do_list_printers()' - List available printers.
2350 */
2351
2352 static void
2353 do_list_printers(http_t *http) /* I - HTTP connection */
2354 {
2355 ipp_t *request, /* IPP request */
2356 *response; /* IPP response */
2357 ipp_attribute_t *attr; /* IPP attribute */
2358
2359
2360 cgiStartHTML(cgiText(_("List Available Printers")));
2361 fflush(stdout);
2362
2363 /*
2364 * Get the list of printers and their devices...
2365 */
2366
2367 request = ippNewRequest(CUPS_GET_PRINTERS);
2368
2369 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2370 "requested-attributes", NULL, "device-uri");
2371
2372 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2373 CUPS_PRINTER_LOCAL);
2374 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2375 CUPS_PRINTER_LOCAL);
2376
2377 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2378 {
2379 /*
2380 * Got the printer list, now load the devices...
2381 */
2382
2383 int i; /* Looping var */
2384 cups_array_t *printer_devices; /* Printer devices for local printers */
2385 char *printer_device; /* Current printer device */
2386
2387
2388 /*
2389 * Allocate an array and copy the device strings...
2390 */
2391
2392 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2393
2394 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2395 attr;
2396 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
2397 {
2398 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
2399 }
2400
2401 /*
2402 * Free the printer list and get the device list...
2403 */
2404
2405 ippDelete(response);
2406
2407 request = ippNewRequest(CUPS_GET_DEVICES);
2408
2409 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2410 {
2411 /*
2412 * Got the device list, let's parse it...
2413 */
2414
2415 const char *device_uri, /* device-uri attribute value */
2416 *device_make_and_model, /* device-make-and-model value */
2417 *device_info; /* device-info value */
2418
2419
2420 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2421 {
2422 /*
2423 * Skip leading attributes until we hit a device...
2424 */
2425
2426 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2427 attr = attr->next;
2428
2429 if (!attr)
2430 break;
2431
2432 /*
2433 * Pull the needed attributes from this device...
2434 */
2435
2436 device_info = NULL;
2437 device_make_and_model = NULL;
2438 device_uri = NULL;
2439
2440 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2441 {
2442 if (!strcmp(attr->name, "device-info") &&
2443 attr->value_tag == IPP_TAG_TEXT)
2444 device_info = attr->values[0].string.text;
2445
2446 if (!strcmp(attr->name, "device-make-and-model") &&
2447 attr->value_tag == IPP_TAG_TEXT)
2448 device_make_and_model = attr->values[0].string.text;
2449
2450 if (!strcmp(attr->name, "device-uri") &&
2451 attr->value_tag == IPP_TAG_URI)
2452 device_uri = attr->values[0].string.text;
2453
2454 attr = attr->next;
2455 }
2456
2457 /*
2458 * See if we have everything needed...
2459 */
2460
2461 if (device_info && device_make_and_model && device_uri &&
2462 strcasecmp(device_make_and_model, "unknown") &&
2463 strchr(device_uri, ':'))
2464 {
2465 /*
2466 * Yes, now see if there is already a printer for this
2467 * device...
2468 */
2469
2470 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2471 {
2472 /*
2473 * Not found, so it must be a new printer...
2474 */
2475
2476 char option[1024], /* Form variables for this device */
2477 *option_ptr; /* Pointer into string */
2478 const char *ptr; /* Pointer into device string */
2479
2480
2481 /*
2482 * Format the printer name variable for this device...
2483 *
2484 * We use the device-info string first, then device-uri,
2485 * and finally device-make-and-model to come up with a
2486 * suitable name.
2487 */
2488
2489 if (strncasecmp(device_info, "unknown", 7))
2490 ptr = device_info;
2491 else if ((ptr = strstr(device_uri, "://")) != NULL)
2492 ptr += 3;
2493 else
2494 ptr = device_make_and_model;
2495
2496 for (option_ptr = option;
2497 option_ptr < (option + sizeof(option) - 1) && *ptr;
2498 ptr ++)
2499 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2500 *ptr == '.')
2501 *option_ptr++ = *ptr;
2502 else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_')
2503 *option_ptr++ = '_';
2504 else if (*ptr == '?' || *ptr == '(')
2505 break;
2506
2507 *option_ptr = '\0';
2508
2509 cgiSetArray("TEMPLATE_NAME", i, option);
2510
2511 /*
2512 * Finally, set the form variables for this printer...
2513 */
2514
2515 cgiSetArray("device_info", i, device_info);
2516 cgiSetArray("device_make_and_model", i, device_make_and_model);
2517 cgiSetArray("device_uri", i, device_uri);
2518 i ++;
2519 }
2520 }
2521
2522 if (!attr)
2523 break;
2524 }
2525
2526 ippDelete(response);
2527
2528 /*
2529 * Free the device list...
2530 */
2531
2532 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2533 printer_device;
2534 printer_device = (char *)cupsArrayNext(printer_devices))
2535 free(printer_device);
2536
2537 cupsArrayDelete(printer_devices);
2538 }
2539 }
2540
2541 /*
2542 * Finally, show the printer list...
2543 */
2544
2545 cgiCopyTemplateLang("list-available-printers.tmpl");
2546
2547 cgiEndHTML();
2548 }
2549
2550
2551 /*
2552 * 'do_menu()' - Show the main menu.
2553 */
2554
2555 static void
2556 do_menu(http_t *http) /* I - HTTP connection */
2557 {
2558 int num_settings; /* Number of server settings */
2559 cups_option_t *settings; /* Server settings */
2560 const char *val; /* Setting value */
2561 char filename[1024]; /* Temporary filename */
2562 const char *datadir; /* Location of data files */
2563 ipp_t *request, /* IPP request */
2564 *response; /* IPP response */
2565
2566
2567 /*
2568 * Get the current server settings...
2569 */
2570
2571 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
2572 {
2573 cgiSetVariable("SETTINGS_MESSAGE",
2574 cgiText(_("Unable to open cupsd.conf file:")));
2575 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2576 }
2577
2578 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2579 settings)) != NULL && atoi(val))
2580 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2581
2582 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2583 settings)) != NULL && atoi(val))
2584 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2585
2586 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2587 settings)) != NULL && atoi(val))
2588 cgiSetVariable("REMOTE_ANY", "CHECKED");
2589
2590 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2591 settings)) != NULL && atoi(val))
2592 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2593
2594 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2595 settings)) != NULL && atoi(val))
2596 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2597
2598 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2599 settings)) != NULL && atoi(val))
2600 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2601
2602 #ifdef HAVE_GSSAPI
2603 cgiSetVariable("HAVE_GSSAPI", "1");
2604
2605 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2606 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2607 cgiSetVariable("KERBEROS", "CHECKED");
2608 #endif /* HAVE_GSSAPI */
2609
2610 #ifdef HAVE_DNSSD
2611 cgiSetVariable("HAVE_DNSSD", "1");
2612 #endif /* HAVE_DNSSD */
2613
2614 #ifdef HAVE_LDAP
2615 cgiSetVariable("HAVE_LDAP", "1");
2616 #endif /* HAVE_LDAP */
2617
2618 #ifdef HAVE_LIBSLP
2619 cgiSetVariable("HAVE_LIBSLP", "1");
2620 #endif /* HAVE_LIBSLP */
2621
2622 if ((val = cupsGetOption("BrowseRemoteProtocols", num_settings,
2623 settings)) == NULL)
2624 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2625 settings)) == NULL)
2626 val = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
2627
2628 if (strstr(val, "cups") || strstr(val, "CUPS"))
2629 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2630
2631 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2632 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2633
2634 if (strstr(val, "slp") || strstr(val, "SLP"))
2635 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2636
2637 if ((val = cupsGetOption("BrowseLocalProtocols", num_settings,
2638 settings)) == NULL)
2639 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2640 settings)) == NULL)
2641 val = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
2642
2643 if (strstr(val, "cups") || strstr(val, "CUPS"))
2644 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2645
2646 if (strstr(val, "dnssd") || strstr(val, "DNSSD") ||
2647 strstr(val, "dns-sd") || strstr(val, "DNS-SD") ||
2648 strstr(val, "bonjour") || strstr(val, "BONJOUR"))
2649 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2650
2651 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2652 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2653
2654 if (strstr(val, "slp") || strstr(val, "SLP"))
2655 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2656
2657 if ((val = cupsGetOption("BrowseWebIF", num_settings,
2658 settings)) == NULL)
2659 val = "No";
2660
2661 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2662 !strcasecmp(val, "true"))
2663 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2664
2665 if ((val = cupsGetOption("PreserveJobHistory", num_settings,
2666 settings)) == NULL)
2667 val = "Yes";
2668
2669 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2670 !strcasecmp(val, "true"))
2671 {
2672 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2673
2674 if ((val = cupsGetOption("PreserveJobFiles", num_settings,
2675 settings)) == NULL)
2676 val = "No";
2677
2678 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2679 !strcasecmp(val, "true"))
2680 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2681 }
2682
2683 if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
2684 val = "100";
2685
2686 cgiSetVariable("MAX_CLIENTS", val);
2687
2688 if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
2689 val = "500";
2690
2691 cgiSetVariable("MAX_JOBS", val);
2692
2693 if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
2694 val = "1m";
2695
2696 cgiSetVariable("MAX_LOG_SIZE", val);
2697
2698 cupsFreeOptions(num_settings, settings);
2699
2700 /*
2701 * See if Samba and the Windows drivers are installed...
2702 */
2703
2704 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2705 datadir = CUPS_DATADIR;
2706
2707 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2708 if (!access(filename, R_OK))
2709 {
2710 /*
2711 * Found Windows 2000 driver file, see if we have smbclient and
2712 * rpcclient...
2713 */
2714
2715 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2716 sizeof(filename)) &&
2717 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2718 sizeof(filename)))
2719 cgiSetVariable("HAVE_SAMBA", "Y");
2720 else
2721 {
2722 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2723 sizeof(filename)))
2724 fputs("ERROR: smbclient not found!\n", stderr);
2725
2726 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2727 sizeof(filename)))
2728 fputs("ERROR: rpcclient not found!\n", stderr);
2729 }
2730 }
2731 else
2732 perror(filename);
2733
2734 /*
2735 * Subscriptions...
2736 */
2737
2738 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2739
2740 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2741 NULL, "ipp://localhost/");
2742
2743 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2744 {
2745 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2746 ippDelete(response);
2747 }
2748
2749 /*
2750 * Finally, show the main menu template...
2751 */
2752
2753 cgiStartHTML(cgiText(_("Administration")));
2754
2755 cgiCopyTemplateLang("admin.tmpl");
2756
2757 cgiEndHTML();
2758 }
2759
2760
2761 /*
2762 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2763 */
2764
2765 static void
2766 do_set_allowed_users(http_t *http) /* I - HTTP connection */
2767 {
2768 int i; /* Looping var */
2769 ipp_t *request, /* IPP request */
2770 *response; /* IPP response */
2771 char uri[HTTP_MAX_URI]; /* Printer URI */
2772 const char *printer, /* Printer name (purge-jobs) */
2773 *is_class, /* Is a class? */
2774 *users, /* List of users or groups */
2775 *type; /* Allow/deny type */
2776 int num_users; /* Number of users */
2777 char *ptr, /* Pointer into users string */
2778 *end, /* Pointer to end of users string */
2779 quote; /* Quote character */
2780 ipp_attribute_t *attr; /* Attribute */
2781 static const char * const attrs[] = /* Requested attributes */
2782 {
2783 "requesting-user-name-allowed",
2784 "requesting-user-name-denied"
2785 };
2786
2787
2788 is_class = cgiGetVariable("IS_CLASS");
2789 printer = cgiGetVariable("PRINTER_NAME");
2790
2791 if (!printer)
2792 {
2793 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2794 cgiStartHTML(cgiText(_("Set Allowed Users")));
2795 cgiCopyTemplateLang("error.tmpl");
2796 cgiEndHTML();
2797 return;
2798 }
2799
2800 users = cgiGetVariable("users");
2801 type = cgiGetVariable("type");
2802
2803 if (!users || !type ||
2804 (strcmp(type, "requesting-user-name-allowed") &&
2805 strcmp(type, "requesting-user-name-denied")))
2806 {
2807 /*
2808 * Build a Get-Printer-Attributes request, which requires the following
2809 * attributes:
2810 *
2811 * attributes-charset
2812 * attributes-natural-language
2813 * printer-uri
2814 * requested-attributes
2815 */
2816
2817 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2818
2819 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2820 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2821 printer);
2822 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2823 NULL, uri);
2824
2825 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2826 "requested-attributes",
2827 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
2828
2829 /*
2830 * Do the request and get back a response...
2831 */
2832
2833 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2834 {
2835 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2836
2837 ippDelete(response);
2838 }
2839
2840 cgiStartHTML(cgiText(_("Set Allowed Users")));
2841
2842 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2843 {
2844 puts("Status: 401\n");
2845 exit(0);
2846 }
2847 else if (cupsLastError() > IPP_OK_CONFLICT)
2848 cgiShowIPPError(_("Unable to get printer attributes:"));
2849 else
2850 cgiCopyTemplateLang("users.tmpl");
2851
2852 cgiEndHTML();
2853 }
2854 else
2855 {
2856 /*
2857 * Save the changes...
2858 */
2859
2860 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
2861 {
2862 /*
2863 * Skip whitespace and commas...
2864 */
2865
2866 while (*ptr == ',' || isspace(*ptr & 255))
2867 ptr ++;
2868
2869 if (!*ptr)
2870 break;
2871
2872 if (*ptr == '\'' || *ptr == '\"')
2873 {
2874 /*
2875 * Scan quoted name...
2876 */
2877
2878 quote = *ptr++;
2879
2880 for (end = ptr; *end; end ++)
2881 if (*end == quote)
2882 break;
2883 }
2884 else
2885 {
2886 /*
2887 * Scan space or comma-delimited name...
2888 */
2889
2890 for (end = ptr; *end; end ++)
2891 if (isspace(*end & 255) || *end == ',')
2892 break;
2893 }
2894
2895 /*
2896 * Advance to the next name...
2897 */
2898
2899 ptr = end;
2900 }
2901
2902 /*
2903 * Build a CUPS-Add-Printer/Class request, which requires the following
2904 * attributes:
2905 *
2906 * attributes-charset
2907 * attributes-natural-language
2908 * printer-uri
2909 * requesting-user-name-{allowed,denied}
2910 */
2911
2912 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
2913
2914 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2915 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2916 printer);
2917 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2918 NULL, uri);
2919
2920 if (num_users == 0)
2921 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2922 "requesting-user-name-allowed", NULL, "all");
2923 else
2924 {
2925 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2926 type, num_users, NULL, NULL);
2927
2928 for (i = 0, ptr = (char *)users; *ptr; i ++)
2929 {
2930 /*
2931 * Skip whitespace and commas...
2932 */
2933
2934 while (*ptr == ',' || isspace(*ptr & 255))
2935 ptr ++;
2936
2937 if (!*ptr)
2938 break;
2939
2940 if (*ptr == '\'' || *ptr == '\"')
2941 {
2942 /*
2943 * Scan quoted name...
2944 */
2945
2946 quote = *ptr++;
2947
2948 for (end = ptr; *end; end ++)
2949 if (*end == quote)
2950 break;
2951 }
2952 else
2953 {
2954 /*
2955 * Scan space or comma-delimited name...
2956 */
2957
2958 for (end = ptr; *end; end ++)
2959 if (isspace(*end & 255) || *end == ',')
2960 break;
2961 }
2962
2963 /*
2964 * Terminate the name...
2965 */
2966
2967 if (*end)
2968 *end++ = '\0';
2969
2970 /*
2971 * Add the name...
2972 */
2973
2974 attr->values[i].string.text = strdup(ptr);
2975
2976 /*
2977 * Advance to the next name...
2978 */
2979
2980 ptr = end;
2981 }
2982 }
2983
2984 /*
2985 * Do the request and get back a response...
2986 */
2987
2988 ippDelete(cupsDoRequest(http, request, "/admin/"));
2989
2990 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2991 {
2992 puts("Status: 401\n");
2993 exit(0);
2994 }
2995 else if (cupsLastError() > IPP_OK_CONFLICT)
2996 {
2997 cgiStartHTML(cgiText(_("Set Allowed Users")));
2998 cgiShowIPPError(_("Unable to change printer:"));
2999 }
3000 else
3001 {
3002 /*
3003 * Redirect successful updates back to the printer page...
3004 */
3005
3006 char url[1024], /* Printer/class URL */
3007 refresh[1024]; /* Refresh URL */
3008
3009
3010 cgiRewriteURL(uri, url, sizeof(url), NULL);
3011 cgiFormEncode(uri, url, sizeof(uri));
3012 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
3013 uri);
3014 cgiSetVariable("refresh_page", refresh);
3015
3016 cgiStartHTML(cgiText(_("Set Allowed Users")));
3017
3018 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3019 "printer-modified.tmpl");
3020 }
3021
3022 cgiEndHTML();
3023 }
3024 }
3025
3026
3027 /*
3028 * 'do_set_default()' - Set the server default printer/class.
3029 */
3030
3031 static void
3032 do_set_default(http_t *http) /* I - HTTP connection */
3033 {
3034 const char *title; /* Page title */
3035 ipp_t *request; /* IPP request */
3036 char uri[HTTP_MAX_URI]; /* Printer URI */
3037 const char *printer, /* Printer name (purge-jobs) */
3038 *is_class; /* Is a class? */
3039
3040
3041 is_class = cgiGetVariable("IS_CLASS");
3042 printer = cgiGetVariable("PRINTER_NAME");
3043 title = cgiText(_("Set As Server Default"));
3044
3045 if (!printer)
3046 {
3047 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3048 cgiStartHTML(title);
3049 cgiCopyTemplateLang("error.tmpl");
3050 cgiEndHTML();
3051 return;
3052 }
3053
3054 /*
3055 * Build a printer request, which requires the following
3056 * attributes:
3057 *
3058 * attributes-charset
3059 * attributes-natural-language
3060 * printer-uri
3061 */
3062
3063 request = ippNewRequest(CUPS_SET_DEFAULT);
3064
3065 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3066 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3067 printer);
3068 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3069 NULL, uri);
3070
3071 /*
3072 * Do the request and get back a response...
3073 */
3074
3075 ippDelete(cupsDoRequest(http, request, "/admin/"));
3076
3077 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3078 {
3079 puts("Status: 401\n");
3080 exit(0);
3081 }
3082 else if (cupsLastError() > IPP_OK_CONFLICT)
3083 {
3084 cgiStartHTML(title);
3085 cgiShowIPPError(_("Unable to set server default:"));
3086 }
3087 else
3088 {
3089 /*
3090 * Redirect successful updates back to the printer page...
3091 */
3092
3093 char url[1024], /* Printer/class URL */
3094 refresh[1024]; /* Refresh URL */
3095
3096
3097 cgiRewriteURL(uri, url, sizeof(url), NULL);
3098 cgiFormEncode(uri, url, sizeof(uri));
3099 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3100 cgiSetVariable("refresh_page", refresh);
3101
3102 cgiStartHTML(title);
3103 cgiCopyTemplateLang("printer-default.tmpl");
3104 }
3105
3106 cgiEndHTML();
3107 }
3108
3109
3110 /*
3111 * 'do_set_options()' - Configure the default options for a queue.
3112 */
3113
3114 static void
3115 do_set_options(http_t *http, /* I - HTTP connection */
3116 int is_class) /* I - Set options for class? */
3117 {
3118 int i, j, k, m; /* Looping vars */
3119 int have_options; /* Have options? */
3120 ipp_t *request, /* IPP request */
3121 *response; /* IPP response */
3122 ipp_attribute_t *attr; /* IPP attribute */
3123 char uri[HTTP_MAX_URI]; /* Job URI */
3124 const char *var; /* Variable value */
3125 const char *printer; /* Printer printer name */
3126 const char *filename; /* PPD filename */
3127 char tempfile[1024]; /* Temporary filename */
3128 cups_file_t *in, /* Input file */
3129 *out; /* Output file */
3130 char line[1024], /* Line from PPD file */
3131 value[1024], /* Option value */
3132 keyword[1024], /* Keyword from Default line */
3133 *keyptr; /* Pointer into keyword... */
3134 ppd_file_t *ppd; /* PPD file */
3135 ppd_group_t *group; /* Option group */
3136 ppd_option_t *option; /* Option */
3137 ppd_coption_t *coption; /* Custom option */
3138 ppd_cparam_t *cparam; /* Custom parameter */
3139 ppd_attr_t *ppdattr; /* PPD attribute */
3140 const char *title; /* Page title */
3141
3142
3143 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
3144
3145 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
3146 is_class);
3147
3148 /*
3149 * Get the printer name...
3150 */
3151
3152 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
3153 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3154 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3155 printer);
3156 else
3157 {
3158 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3159 cgiStartHTML(title);
3160 cgiCopyTemplateLang("error.tmpl");
3161 cgiEndHTML();
3162 return;
3163 }
3164
3165 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
3166
3167 /*
3168 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3169 * command file to the printer...
3170 */
3171
3172 if (cgiGetVariable("AUTOCONFIGURE"))
3173 {
3174 cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
3175 return;
3176 }
3177
3178 /*
3179 * Get the PPD file...
3180 */
3181
3182 if (is_class)
3183 filename = NULL;
3184 else
3185 filename = cupsGetPPD2(http, printer);
3186
3187 if (filename)
3188 {
3189 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
3190
3191 if ((ppd = ppdOpenFile(filename)) == NULL)
3192 {
3193 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
3194 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3195 cgiStartHTML(title);
3196 cgiCopyTemplateLang("error.tmpl");
3197 cgiEndHTML();
3198 return;
3199 }
3200 }
3201 else
3202 {
3203 fputs("DEBUG: No PPD file\n", stderr);
3204 ppd = NULL;
3205 }
3206
3207 if (cgiGetVariable("job_sheets_start") != NULL ||
3208 cgiGetVariable("job_sheets_end") != NULL)
3209 have_options = 1;
3210 else
3211 have_options = 0;
3212
3213 if (ppd)
3214 {
3215 ppdMarkDefaults(ppd);
3216
3217 for (option = ppdFirstOption(ppd);
3218 option;
3219 option = ppdNextOption(ppd))
3220 if ((var = cgiGetVariable(option->keyword)) != NULL)
3221 {
3222 have_options = 1;
3223 ppdMarkOption(ppd, option->keyword, var);
3224 }
3225 }
3226
3227 if (!have_options || ppdConflicts(ppd))
3228 {
3229 /*
3230 * Show the options to the user...
3231 */
3232
3233 fputs("DEBUG: Showing options...\n", stderr);
3234
3235 /*
3236 * Show auto-configure button if supported...
3237 */
3238
3239 if (ppd)
3240 {
3241 if (ppd->num_filters == 0 ||
3242 ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
3243 ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
3244 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3245 else
3246 {
3247 for (i = 0; i < ppd->num_filters; i ++)
3248 if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
3249 {
3250 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3251 break;
3252 }
3253 }
3254 }
3255
3256 /*
3257 * Get the printer attributes...
3258 */
3259
3260 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
3261
3262 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3263 "localhost", 0, "/printers/%s", printer);
3264 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3265 NULL, uri);
3266
3267 response = cupsDoRequest(http, request, "/");
3268
3269 /*
3270 * List the groups used as "tabs"...
3271 */
3272
3273 i = 0;
3274
3275 if (ppd)
3276 {
3277 for (group = ppd->groups;
3278 i < ppd->num_groups;
3279 i ++, group ++)
3280 {
3281 cgiSetArray("GROUP_ID", i, group->name);
3282
3283 if (!strcmp(group->name, "InstallableOptions"))
3284 cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
3285 else
3286 cgiSetArray("GROUP", i, group->text);
3287 }
3288 }
3289
3290 if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
3291 {
3292 cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
3293 cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
3294 }
3295
3296 if (ippFindAttribute(response, "printer-error-policy-supported",
3297 IPP_TAG_ZERO) ||
3298 ippFindAttribute(response, "printer-op-policy-supported",
3299 IPP_TAG_ZERO))
3300 {
3301 cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
3302 cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
3303 }
3304
3305 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3306 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
3307 {
3308 cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
3309 cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
3310 }
3311
3312 cgiStartHTML(cgiText(_("Set Printer Options")));
3313 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3314
3315 if (ppd)
3316 {
3317 ppdLocalize(ppd);
3318
3319 if (ppdConflicts(ppd))
3320 {
3321 for (i = ppd->num_groups, k = 0, group = ppd->groups;
3322 i > 0;
3323 i --, group ++)
3324 for (j = group->num_options, option = group->options;
3325 j > 0;
3326 j --, option ++)
3327 if (option->conflicted)
3328 {
3329 cgiSetArray("ckeyword", k, option->keyword);
3330 cgiSetArray("ckeytext", k, option->text);
3331 k ++;
3332 }
3333
3334 cgiCopyTemplateLang("option-conflict.tmpl");
3335 }
3336
3337 for (i = ppd->num_groups, group = ppd->groups;
3338 i > 0;
3339 i --, group ++)
3340 {
3341 cgiSetVariable("GROUP_ID", group->name);
3342
3343 if (!strcmp(group->name, "InstallableOptions"))
3344 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3345 else
3346 cgiSetVariable("GROUP", group->text);
3347
3348 cgiCopyTemplateLang("option-header.tmpl");
3349
3350 for (j = group->num_options, option = group->options;
3351 j > 0;
3352 j --, option ++)
3353 {
3354 if (!strcmp(option->keyword, "PageRegion"))
3355 continue;
3356
3357 cgiSetVariable("KEYWORD", option->keyword);
3358 cgiSetVariable("KEYTEXT", option->text);
3359
3360 if (option->conflicted)
3361 cgiSetVariable("CONFLICTED", "1");
3362 else
3363 cgiSetVariable("CONFLICTED", "0");
3364
3365 cgiSetSize("CHOICES", 0);
3366 cgiSetSize("TEXT", 0);
3367 for (k = 0, m = 0; k < option->num_choices; k ++)
3368 {
3369 cgiSetArray("CHOICES", m, option->choices[k].choice);
3370 cgiSetArray("TEXT", m, option->choices[k].text);
3371
3372 m ++;
3373
3374 if (option->choices[k].marked)
3375 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
3376 }
3377
3378 cgiSetSize("PARAMS", 0);
3379 cgiSetSize("PARAMTEXT", 0);
3380 cgiSetSize("PARAMVALUE", 0);
3381 cgiSetSize("INPUTTYPE", 0);
3382
3383 if ((coption = ppdFindCustomOption(ppd, option->keyword)))
3384 {
3385 const char *units = NULL; /* Units value, if any */
3386
3387
3388 cgiSetVariable("ISCUSTOM", "1");
3389
3390 for (cparam = ppdFirstCustomParam(coption), m = 0;
3391 cparam;
3392 cparam = ppdNextCustomParam(coption), m ++)
3393 {
3394 if (!strcasecmp(option->keyword, "PageSize") &&
3395 strcasecmp(cparam->name, "Width") &&
3396 strcasecmp(cparam->name, "Height"))
3397 {
3398 m --;
3399 continue;
3400 }
3401
3402 cgiSetArray("PARAMS", m, cparam->name);
3403 cgiSetArray("PARAMTEXT", m, cparam->text);
3404 cgiSetArray("INPUTTYPE", m, "text");
3405
3406 switch (cparam->type)
3407 {
3408 case PPD_CUSTOM_POINTS :
3409 if (!strncasecmp(option->defchoice, "Custom.", 7))
3410 {
3411 units = option->defchoice + strlen(option->defchoice) - 2;
3412
3413 if (strcmp(units, "mm") && strcmp(units, "cm") &&
3414 strcmp(units, "in") && strcmp(units, "ft"))
3415 {
3416 if (units[1] == 'm')
3417 units ++;
3418 else
3419 units = "pt";
3420 }
3421 }
3422 else
3423 units = "pt";
3424
3425 if (!strcmp(units, "mm"))
3426 snprintf(value, sizeof(value), "%g",
3427 cparam->current.custom_points / 72.0 * 25.4);
3428 else if (!strcmp(units, "cm"))
3429 snprintf(value, sizeof(value), "%g",
3430 cparam->current.custom_points / 72.0 * 2.54);
3431 else if (!strcmp(units, "in"))
3432 snprintf(value, sizeof(value), "%g",
3433 cparam->current.custom_points / 72.0);
3434 else if (!strcmp(units, "ft"))
3435 snprintf(value, sizeof(value), "%g",
3436 cparam->current.custom_points / 72.0 / 12.0);
3437 else if (!strcmp(units, "m"))
3438 snprintf(value, sizeof(value), "%g",
3439 cparam->current.custom_points / 72.0 * 0.0254);
3440 else
3441 snprintf(value, sizeof(value), "%g",
3442 cparam->current.custom_points);
3443 cgiSetArray("PARAMVALUE", m, value);
3444 break;
3445
3446 case PPD_CUSTOM_CURVE :
3447 case PPD_CUSTOM_INVCURVE :
3448 case PPD_CUSTOM_REAL :
3449 snprintf(value, sizeof(value), "%g",
3450 cparam->current.custom_real);
3451 cgiSetArray("PARAMVALUE", m, value);
3452 break;
3453
3454 case PPD_CUSTOM_INT:
3455 snprintf(value, sizeof(value), "%d",
3456 cparam->current.custom_int);
3457 cgiSetArray("PARAMVALUE", m, value);
3458 break;
3459
3460 case PPD_CUSTOM_PASSCODE:
3461 case PPD_CUSTOM_PASSWORD:
3462 if (cparam->current.custom_password)
3463 cgiSetArray("PARAMVALUE", m,
3464 cparam->current.custom_password);
3465 else
3466 cgiSetArray("PARAMVALUE", m, "");
3467 cgiSetArray("INPUTTYPE", m, "password");
3468 break;
3469
3470 case PPD_CUSTOM_STRING:
3471 if (cparam->current.custom_string)
3472 cgiSetArray("PARAMVALUE", m,
3473 cparam->current.custom_string);
3474 else
3475 cgiSetArray("PARAMVALUE", m, "");
3476 break;
3477 }
3478 }
3479
3480 if (units)
3481 {
3482 cgiSetArray("PARAMS", m, "Units");
3483 cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
3484 cgiSetArray("PARAMVALUE", m, units);
3485 }
3486 }
3487 else
3488 cgiSetVariable("ISCUSTOM", "0");
3489
3490 switch (option->ui)
3491 {
3492 case PPD_UI_BOOLEAN :
3493 cgiCopyTemplateLang("option-boolean.tmpl");
3494 break;
3495 case PPD_UI_PICKONE :
3496 cgiCopyTemplateLang("option-pickone.tmpl");
3497 break;
3498 case PPD_UI_PICKMANY :
3499 cgiCopyTemplateLang("option-pickmany.tmpl");
3500 break;
3501 }
3502 }
3503
3504 cgiCopyTemplateLang("option-trailer.tmpl");
3505 }
3506 }
3507
3508 if ((attr = ippFindAttribute(response, "job-sheets-supported",
3509 IPP_TAG_ZERO)) != NULL)
3510 {
3511 /*
3512 * Add the job sheets options...
3513 */
3514
3515 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3516 cgiSetVariable("GROUP", cgiText(_("Banners")));
3517 cgiCopyTemplateLang("option-header.tmpl");
3518
3519 cgiSetSize("CHOICES", attr->num_values);
3520 cgiSetSize("TEXT", attr->num_values);
3521 for (k = 0; k < attr->num_values; k ++)
3522 {
3523 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3524 cgiSetArray("TEXT", k, attr->values[k].string.text);
3525 }
3526
3527 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
3528
3529 cgiSetVariable("KEYWORD", "job_sheets_start");
3530 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3531 cgiSetVariable("DEFCHOICE", attr != NULL ?
3532 attr->values[0].string.text : "");
3533
3534 cgiCopyTemplateLang("option-pickone.tmpl");
3535
3536 cgiSetVariable("KEYWORD", "job_sheets_end");
3537 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3538 cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
3539 attr->values[1].string.text : "");
3540
3541 cgiCopyTemplateLang("option-pickone.tmpl");
3542
3543 cgiCopyTemplateLang("option-trailer.tmpl");
3544 }
3545
3546 if (ippFindAttribute(response, "printer-error-policy-supported",
3547 IPP_TAG_ZERO) ||
3548 ippFindAttribute(response, "printer-op-policy-supported",
3549 IPP_TAG_ZERO))
3550 {
3551 /*
3552 * Add the error and operation policy options...
3553 */
3554
3555 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3556 cgiSetVariable("GROUP", cgiText(_("Policies")));
3557 cgiCopyTemplateLang("option-header.tmpl");
3558
3559 /*
3560 * Error policy...
3561 */
3562
3563 attr = ippFindAttribute(response, "printer-error-policy-supported",
3564 IPP_TAG_ZERO);
3565
3566 if (attr)
3567 {
3568 cgiSetSize("CHOICES", attr->num_values);
3569 cgiSetSize("TEXT", attr->num_values);
3570 for (k = 0; k < attr->num_values; k ++)
3571 {
3572 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3573 cgiSetArray("TEXT", k, attr->values[k].string.text);
3574 }
3575
3576 attr = ippFindAttribute(response, "printer-error-policy",
3577 IPP_TAG_ZERO);
3578
3579 cgiSetVariable("KEYWORD", "printer_error_policy");
3580 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3581 cgiSetVariable("DEFCHOICE", attr == NULL ?
3582 "" : attr->values[0].string.text);
3583 }
3584
3585 cgiCopyTemplateLang("option-pickone.tmpl");
3586
3587 /*
3588 * Operation policy...
3589 */
3590
3591 attr = ippFindAttribute(response, "printer-op-policy-supported",
3592 IPP_TAG_ZERO);
3593
3594 if (attr)
3595 {
3596 cgiSetSize("CHOICES", attr->num_values);
3597 cgiSetSize("TEXT", attr->num_values);
3598 for (k = 0; k < attr->num_values; k ++)
3599 {
3600 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3601 cgiSetArray("TEXT", k, attr->values[k].string.text);
3602 }
3603
3604 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
3605
3606 cgiSetVariable("KEYWORD", "printer_op_policy");
3607 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3608 cgiSetVariable("DEFCHOICE", attr == NULL ?
3609 "" : attr->values[0].string.text);
3610
3611 cgiCopyTemplateLang("option-pickone.tmpl");
3612 }
3613
3614 cgiCopyTemplateLang("option-trailer.tmpl");
3615 }
3616
3617 /*
3618 * Binary protocol support...
3619 */
3620
3621 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3622 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
3623 {
3624 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3625 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3626
3627 cgiSetSize("CHOICES", attr->num_values);
3628 cgiSetSize("TEXT", attr->num_values);
3629
3630 for (i = 0; i < attr->num_values; i ++)
3631 {
3632 cgiSetArray("CHOICES", i, attr->values[i].string.text);
3633 cgiSetArray("TEXT", i, attr->values[i].string.text);
3634 }
3635
3636 attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
3637 cgiSetVariable("KEYWORD", "port_monitor");
3638 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3639 cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
3640
3641 cgiCopyTemplateLang("option-header.tmpl");
3642 cgiCopyTemplateLang("option-pickone.tmpl");
3643 cgiCopyTemplateLang("option-trailer.tmpl");
3644 }
3645
3646 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3647 cgiEndHTML();
3648
3649 ippDelete(response);
3650 }
3651 else
3652 {
3653 /*
3654 * Set default options...
3655 */
3656
3657 fputs("DEBUG: Setting options...\n", stderr);
3658
3659 if (filename)
3660 {
3661 out = cupsTempFile2(tempfile, sizeof(tempfile));
3662 in = cupsFileOpen(filename, "r");
3663
3664 if (!in || !out)
3665 {
3666 cgiSetVariable("ERROR", strerror(errno));
3667 cgiStartHTML(cgiText(_("Set Printer Options")));
3668 cgiCopyTemplateLang("error.tmpl");
3669 cgiEndHTML();
3670
3671 if (in)
3672 cupsFileClose(in);
3673
3674 if (out)
3675 {
3676 cupsFileClose(out);
3677 unlink(tempfile);
3678 }
3679
3680 unlink(filename);
3681 return;
3682 }
3683
3684 while (cupsFileGets(in, line, sizeof(line)))
3685 {
3686 if (!strncmp(line, "*cupsProtocol:", 14))
3687 continue;
3688 else if (strncmp(line, "*Default", 8))
3689 cupsFilePrintf(out, "%s\n", line);
3690 else
3691 {
3692 /*
3693 * Get default option name...
3694 */
3695
3696 strlcpy(keyword, line + 8, sizeof(keyword));
3697
3698 for (keyptr = keyword; *keyptr; keyptr ++)
3699 if (*keyptr == ':' || isspace(*keyptr & 255))
3700 break;
3701
3702 *keyptr = '\0';
3703
3704 if (!strcmp(keyword, "PageRegion") ||
3705 !strcmp(keyword, "PaperDimension") ||
3706 !strcmp(keyword, "ImageableArea"))
3707 var = get_option_value(ppd, "PageSize", value, sizeof(value));
3708 else
3709 var = get_option_value(ppd, keyword, value, sizeof(value));
3710
3711 if (!var)
3712 cupsFilePrintf(out, "%s\n", line);
3713 else
3714 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
3715 }
3716 }
3717
3718 cupsFileClose(in);
3719 cupsFileClose(out);
3720 }
3721 else
3722 {
3723 /*
3724 * Make sure temporary filename is cleared when there is no PPD...
3725 */
3726
3727 tempfile[0] = '\0';
3728 }
3729
3730 /*
3731 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3732 * following attributes:
3733 *
3734 * attributes-charset
3735 * attributes-natural-language
3736 * printer-uri
3737 * job-sheets-default
3738 * printer-error-policy
3739 * printer-op-policy
3740 * [ppd file]
3741 */
3742
3743 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3744 CUPS_ADD_MODIFY_PRINTER);
3745
3746 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3747 NULL, uri);
3748
3749 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3750 "job-sheets-default", 2, NULL, NULL);
3751 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3752 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3753
3754 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
3755 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3756 "printer-error-policy", NULL, var);
3757
3758 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
3759 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3760 "printer-op-policy", NULL, var);
3761
3762 if ((var = cgiGetVariable("port_monitor")) != NULL)
3763 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3764 "port-monitor", NULL, var);
3765
3766 /*
3767 * Do the request and get back a response...
3768 */
3769
3770 if (filename)
3771 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3772 else
3773 ippDelete(cupsDoRequest(http, request, "/admin/"));
3774
3775 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3776 {
3777 puts("Status: 401\n");
3778 exit(0);
3779 }
3780 else if (cupsLastError() > IPP_OK_CONFLICT)
3781 {
3782 cgiStartHTML(title);
3783 cgiShowIPPError(_("Unable to set options:"));
3784 }
3785 else
3786 {
3787 /*
3788 * Redirect successful updates back to the printer page...
3789 */
3790
3791 char refresh[1024]; /* Refresh URL */
3792
3793
3794 cgiFormEncode(uri, printer, sizeof(uri));
3795 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3796 is_class ? "classes" : "printers", uri);
3797 cgiSetVariable("refresh_page", refresh);
3798
3799 cgiStartHTML(title);
3800
3801 cgiCopyTemplateLang("printer-configured.tmpl");
3802 }
3803
3804 cgiEndHTML();
3805
3806 if (filename)
3807 unlink(tempfile);
3808 }
3809
3810 if (filename)
3811 unlink(filename);
3812 }
3813
3814
3815 /*
3816 * 'do_set_sharing()' - Set printer-is-shared value.
3817 */
3818
3819 static void
3820 do_set_sharing(http_t *http) /* I - HTTP connection */
3821 {
3822 ipp_t *request, /* IPP request */
3823 *response; /* IPP response */
3824 char uri[HTTP_MAX_URI]; /* Printer URI */
3825 const char *printer, /* Printer name */
3826 *is_class, /* Is a class? */
3827 *shared; /* Sharing value */
3828
3829
3830 is_class = cgiGetVariable("IS_CLASS");
3831 printer = cgiGetVariable("PRINTER_NAME");
3832 shared = cgiGetVariable("SHARED");
3833
3834 if (!printer || !shared)
3835 {
3836 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3837 cgiStartHTML(cgiText(_("Set Publishing")));
3838 cgiCopyTemplateLang("error.tmpl");
3839 cgiEndHTML();
3840 return;
3841 }
3842
3843 /*
3844 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3845 * following attributes:
3846 *
3847 * attributes-charset
3848 * attributes-natural-language
3849 * printer-uri
3850 * printer-is-shared
3851 */
3852
3853 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
3854
3855 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3856 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3857 printer);
3858 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3859 NULL, uri);
3860
3861 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3862
3863 /*
3864 * Do the request and get back a response...
3865 */
3866
3867 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3868 {
3869 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3870
3871 ippDelete(response);
3872 }
3873
3874 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3875 {
3876 puts("Status: 401\n");
3877 exit(0);
3878 }
3879 else if (cupsLastError() > IPP_OK_CONFLICT)
3880 {
3881 cgiStartHTML(cgiText(_("Set Publishing")));
3882 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3883 }
3884 else
3885 {
3886 /*
3887 * Redirect successful updates back to the printer page...
3888 */
3889
3890 char url[1024], /* Printer/class URL */
3891 refresh[1024]; /* Refresh URL */
3892
3893
3894 cgiRewriteURL(uri, url, sizeof(url), NULL);
3895 cgiFormEncode(uri, url, sizeof(uri));
3896 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3897 cgiSetVariable("refresh_page", refresh);
3898
3899 cgiStartHTML(cgiText(_("Set Publishing")));
3900 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3901 "printer-modified.tmpl");
3902 }
3903
3904 cgiEndHTML();
3905 }
3906
3907
3908 /*
3909 * 'get_option_value()' - Return the value of an option.
3910 *
3911 * This function also handles generation of custom option values.
3912 */
3913
3914 static char * /* O - Value string or NULL on error */
3915 get_option_value(
3916 ppd_file_t *ppd, /* I - PPD file */
3917 const char *name, /* I - Option name */
3918 char *buffer, /* I - String buffer */
3919 size_t bufsize) /* I - Size of buffer */
3920 {
3921 char *bufptr, /* Pointer into buffer */
3922 *bufend; /* End of buffer */
3923 ppd_coption_t *coption; /* Custom option */
3924 ppd_cparam_t *cparam; /* Current custom parameter */
3925 char keyword[256]; /* Parameter name */
3926 const char *val, /* Parameter value */
3927 *uval; /* Units value */
3928 long integer; /* Integer value */
3929 double number, /* Number value */
3930 number_points; /* Number in points */
3931
3932
3933 /*
3934 * See if we have a custom option choice...
3935 */
3936
3937 if ((val = cgiGetVariable(name)) == NULL)
3938 {
3939 /*
3940 * Option not found!
3941 */
3942
3943 return (NULL);
3944 }
3945 else if (strcasecmp(val, "Custom") ||
3946 (coption = ppdFindCustomOption(ppd, name)) == NULL)
3947 {
3948 /*
3949 * Not a custom choice...
3950 */
3951
3952 strlcpy(buffer, val, bufsize);
3953 return (buffer);
3954 }
3955
3956 /*
3957 * OK, we have a custom option choice, format it...
3958 */
3959
3960 *buffer = '\0';
3961
3962 if (!strcmp(coption->keyword, "PageSize"))
3963 {
3964 const char *lval; /* Length string value */
3965 double width, /* Width value */
3966 width_points, /* Width in points */
3967 length, /* Length value */
3968 length_points; /* Length in points */
3969
3970
3971 val = cgiGetVariable("PageSize.Width");
3972 lval = cgiGetVariable("PageSize.Height");
3973 uval = cgiGetVariable("PageSize.Units");
3974
3975 if (!val || !lval || !uval ||
3976 (width = strtod(val, NULL)) == 0.0 ||
3977 (length = strtod(lval, NULL)) == 0.0 ||
3978 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3979 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3980 return (NULL);
3981
3982 width_points = get_points(width, uval);
3983 length_points = get_points(length, uval);
3984
3985 if (width_points < ppd->custom_min[0] ||
3986 width_points > ppd->custom_max[0] ||
3987 length_points < ppd->custom_min[1] ||
3988 length_points > ppd->custom_max[1])
3989 return (NULL);
3990
3991 snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
3992 }
3993 else if (cupsArrayCount(coption->params) == 1)
3994 {
3995 cparam = ppdFirstCustomParam(coption);
3996 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
3997
3998 if ((val = cgiGetVariable(keyword)) == NULL)
3999 return (NULL);
4000
4001 switch (cparam->type)
4002 {
4003 case PPD_CUSTOM_CURVE :
4004 case PPD_CUSTOM_INVCURVE :
4005 case PPD_CUSTOM_REAL :
4006 if ((number = strtod(val, NULL)) == 0.0 ||
4007 number < cparam->minimum.custom_real ||
4008 number > cparam->maximum.custom_real)
4009 return (NULL);
4010
4011 snprintf(buffer, bufsize, "Custom.%g", number);
4012 break;
4013
4014 case PPD_CUSTOM_INT :
4015 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4016 integer == LONG_MAX ||
4017 integer < cparam->minimum.custom_int ||
4018 integer > cparam->maximum.custom_int)
4019 return (NULL);
4020
4021 snprintf(buffer, bufsize, "Custom.%ld", integer);
4022 break;
4023
4024 case PPD_CUSTOM_POINTS :
4025 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4026
4027 if ((number = strtod(val, NULL)) == 0.0 ||
4028 (uval = cgiGetVariable(keyword)) == NULL ||
4029 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
4030 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
4031 return (NULL);
4032
4033 number_points = get_points(number, uval);
4034 if (number_points < cparam->minimum.custom_points ||
4035 number_points > cparam->maximum.custom_points)
4036 return (NULL);
4037
4038 snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
4039 break;
4040
4041 case PPD_CUSTOM_PASSCODE :
4042 for (uval = val; *uval; uval ++)
4043 if (!isdigit(*uval & 255))
4044 return (NULL);
4045
4046 case PPD_CUSTOM_PASSWORD :
4047 case PPD_CUSTOM_STRING :
4048 integer = (long)strlen(val);
4049 if (integer < cparam->minimum.custom_string ||
4050 integer > cparam->maximum.custom_string)
4051 return (NULL);
4052
4053 snprintf(buffer, bufsize, "Custom.%s", val);
4054 break;
4055 }
4056 }
4057 else
4058 {
4059 const char *prefix = "{"; /* Prefix string */
4060
4061
4062 bufptr = buffer;
4063 bufend = buffer + bufsize;
4064
4065 for (cparam = ppdFirstCustomParam(coption);
4066 cparam;
4067 cparam = ppdNextCustomParam(coption))
4068 {
4069 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
4070 cparam->name);
4071
4072 if ((val = cgiGetVariable(keyword)) == NULL)
4073 return (NULL);
4074
4075 snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
4076 bufptr += strlen(bufptr);
4077 prefix = " ";
4078
4079 switch (cparam->type)
4080 {
4081 case PPD_CUSTOM_CURVE :
4082 case PPD_CUSTOM_INVCURVE :
4083 case PPD_CUSTOM_REAL :
4084 if ((number = strtod(val, NULL)) == 0.0 ||
4085 number < cparam->minimum.custom_real ||
4086 number > cparam->maximum.custom_real)
4087 return (NULL);
4088
4089 snprintf(bufptr, bufend - bufptr, "%g", number);
4090 break;
4091
4092 case PPD_CUSTOM_INT :
4093 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4094 integer == LONG_MAX ||
4095 integer < cparam->minimum.custom_int ||
4096 integer > cparam->maximum.custom_int)
4097 return (NULL);
4098
4099 snprintf(bufptr, bufend - bufptr, "%ld", integer);
4100 break;
4101
4102 case PPD_CUSTOM_POINTS :
4103 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4104
4105 if ((number = strtod(val, NULL)) == 0.0 ||
4106 (uval = cgiGetVariable(keyword)) == NULL ||
4107 (strcmp(uval, "pt") && strcmp(uval, "in") &&
4108 strcmp(uval, "ft") && strcmp(uval, "cm") &&
4109 strcmp(uval, "mm") && strcmp(uval, "m")))
4110 return (NULL);
4111
4112 number_points = get_points(number, uval);
4113 if (number_points < cparam->minimum.custom_points ||
4114 number_points > cparam->maximum.custom_points)
4115 return (NULL);
4116
4117 snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
4118 break;
4119
4120 case PPD_CUSTOM_PASSCODE :
4121 for (uval = val; *uval; uval ++)
4122 if (!isdigit(*uval & 255))
4123 return (NULL);
4124
4125 case PPD_CUSTOM_PASSWORD :
4126 case PPD_CUSTOM_STRING :
4127 integer = (long)strlen(val);
4128 if (integer < cparam->minimum.custom_string ||
4129 integer > cparam->maximum.custom_string)
4130 return (NULL);
4131
4132 if ((bufptr + 2) > bufend)
4133 return (NULL);
4134
4135 bufend --;
4136 *bufptr++ = '\"';
4137
4138 while (*val && bufptr < bufend)
4139 {
4140 if (*val == '\\' || *val == '\"')
4141 {
4142 if ((bufptr + 1) >= bufend)
4143 return (NULL);
4144
4145 *bufptr++ = '\\';
4146 }
4147
4148 *bufptr++ = *val++;
4149 }
4150
4151 if (bufptr >= bufend)
4152 return (NULL);
4153
4154 *bufptr++ = '\"';
4155 *bufptr = '\0';
4156 bufend ++;
4157 break;
4158 }
4159
4160 bufptr += strlen(bufptr);
4161 }
4162
4163 if (bufptr == buffer || (bufend - bufptr) < 2)
4164 return (NULL);
4165
4166 strcpy(bufptr, "}");
4167 }
4168
4169 return (buffer);
4170 }
4171
4172
4173 /*
4174 * 'get_points()' - Get a value in points.
4175 */
4176
4177 static double /* O - Number in points */
4178 get_points(double number, /* I - Original number */
4179 const char *uval) /* I - Units */
4180 {
4181 if (!strcmp(uval, "mm")) /* Millimeters */
4182 return (number * 72.0 / 25.4);
4183 else if (!strcmp(uval, "cm")) /* Centimeters */
4184 return (number * 72.0 / 2.54);
4185 else if (!strcmp(uval, "in")) /* Inches */
4186 return (number * 72.0);
4187 else if (!strcmp(uval, "ft")) /* Feet */
4188 return (number * 72.0 * 12.0);
4189 else if (!strcmp(uval, "m")) /* Meters */
4190 return (number * 72.0 / 0.0254);
4191 else /* Points */
4192 return (number);
4193 }
4194
4195
4196 /*
4197 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".
4198 */