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