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