]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/admin.c
Merge changes from CUPS 1.4svn-r8329.
[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 }
1f0275e3 1060 else if (!file && !cgiGetVariable("PPD_NAME"))
ef416fc2 1061 {
1062 if (modify)
1063 {
1064 /*
1065 * Get the PPD file...
1066 */
1067
1068 int fd; /* PPD file */
1069 char filename[1024]; /* PPD filename */
1070 ppd_file_t *ppd; /* PPD information */
1071 char buffer[1024]; /* Buffer */
1072 int bytes; /* Number of bytes */
1073 http_status_t get_status; /* Status of GET */
1074
1075
a4d04587 1076 /* TODO: Use cupsGetFile() API... */
ef416fc2 1077 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
1078
1079 if (httpGet(http, uri))
1080 httpGet(http, uri);
1081
1082 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
1083
1084 if (get_status != HTTP_OK)
1085 {
1086 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
1087 uri, get_status, httpStatus(get_status));
1088 }
1089 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
1090 {
a4d04587 1091 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
ef416fc2 1092 write(fd, buffer, bytes);
1093
1094 close(fd);
1095
1096 if ((ppd = ppdOpenFile(filename)) != NULL)
1097 {
1098 if (ppd->manufacturer)
1099 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
1100
1101 if (ppd->nickname)
1102 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
1103
1104 ppdClose(ppd);
1105 unlink(filename);
1106 }
1107 else
1108 {
1109 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
1110 filename, ppdErrorString(ppdLastError(&bytes)));
1111 }
1112 }
1113 else
1114 {
1115 httpFlush(http);
1116
1117 fprintf(stderr,
1118 "ERROR: Unable to create temporary file for PPD file: %s\n",
1119 strerror(errno));
1120 }
1121 }
ef416fc2 1122
1123 /*
1124 * Build a CUPS_GET_PPDS request, which requires the following
1125 * attributes:
1126 *
1127 * attributes-charset
1128 * attributes-natural-language
1129 * printer-uri
1130 */
1131
fa73b229 1132 request = ippNewRequest(CUPS_GET_PPDS);
ef416fc2 1133
1134 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1135 NULL, "ipp://localhost/printers/");
1136
2e4ff8af
MS
1137 if ((var = cgiGetVariable("CURRENT_MAKE")) == NULL)
1138 var = cgiGetVariable("PPD_MAKE");
1139 if (var)
58dc1933 1140 {
e4572d57
MS
1141 const char *make_model; /* Make and model */
1142
1143
ef416fc2 1144 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1145 "ppd-make", NULL, var);
58dc1933 1146
e4572d57
MS
1147 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL &&
1148 !cgiGetVariable("SELECT_MAKE"))
58dc1933 1149 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
e4572d57 1150 "ppd-make-and-model", NULL, make_model);
58dc1933 1151 }
ef416fc2 1152 else
1153 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1154 "requested-attributes", NULL, "ppd-make");
1155
1156 /*
1157 * Do the request and get back a response...
1158 */
1159
1160 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1161 {
1162 /*
1163 * Got the list of PPDs, see if the user has selected a make...
1164 */
1165
89d46774 1166 if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0)
ef416fc2 1167 {
1168 /*
89d46774 1169 * No PPD files with this make, try again with all makes...
ef416fc2 1170 */
1171
89d46774 1172 ippDelete(response);
1173
1174 request = ippNewRequest(CUPS_GET_PPDS);
1175
1176 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1177 NULL, "ipp://localhost/printers/");
1178
1179 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1180 "requested-attributes", NULL, "ppd-make");
ef416fc2 1181
89d46774 1182 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1183 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1184
1185 cgiStartHTML(title);
1186 cgiCopyTemplateLang("choose-make.tmpl");
1187 cgiEndHTML();
1188 }
2e4ff8af 1189 else if (!var || cgiGetVariable("SELECT_MAKE"))
89d46774 1190 {
ef416fc2 1191 cgiStartHTML(title);
1192 cgiCopyTemplateLang("choose-make.tmpl");
1193 cgiEndHTML();
1194 }
1195 else
1196 {
1197 /*
1198 * Let the user choose a model...
1199 */
1200
ef416fc2 1201 cgiStartHTML(title);
58dc1933
MS
1202 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1203 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
ef416fc2 1204 cgiCopyTemplateLang("choose-model.tmpl");
1205 cgiEndHTML();
1206 }
1207
ef416fc2 1208 ippDelete(response);
1209 }
1210 else
1211 {
ef416fc2 1212 cgiStartHTML(title);
fa73b229 1213 cgiShowIPPError(_("Unable to get list of printer drivers:"));
ef416fc2 1214 cgiCopyTemplateLang("error.tmpl");
1215 cgiEndHTML();
1216 }
1217 }
1218 else
1219 {
1220 /*
1221 * Build a CUPS_ADD_PRINTER request, which requires the following
1222 * attributes:
1223 *
1224 * attributes-charset
1225 * attributes-natural-language
1226 * printer-uri
1227 * printer-location
1228 * printer-info
1229 * ppd-name
1230 * device-uri
1231 * printer-is-accepting-jobs
c5571a1d 1232 * printer-is-shared
ef416fc2 1233 * printer-state
1234 */
1235
fa73b229 1236 request = ippNewRequest(CUPS_ADD_PRINTER);
ef416fc2 1237
a4d04587 1238 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1239 "localhost", 0, "/printers/%s",
1240 cgiGetVariable("PRINTER_NAME"));
ef416fc2 1241 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1242 NULL, uri);
1243
1244 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1245 NULL, cgiGetVariable("PRINTER_LOCATION"));
1246
1247 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1248 NULL, cgiGetVariable("PRINTER_INFO"));
1249
1250 if (!file)
0af14961
MS
1251 {
1252 var = cgiGetVariable("PPD_NAME");
1253 if (strcmp(var, "__no_change__"))
1254 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
1255 NULL, var);
1256 }
ef416fc2 1257
1258 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1259
1260 /*
1261 * Strip make and model from URI...
1262 */
1263
1264 if ((uriptr = strrchr(uri, '|')) != NULL)
1265 *uriptr = '\0';
1266
fa73b229 1267 if (!strncmp(uri, "serial:", 7))
ef416fc2 1268 {
1269 /*
1270 * Update serial port URI to include baud rate, etc.
1271 */
1272
1273 if ((uriptr = strchr(uri, '?')) == NULL)
1274 uriptr = uri + strlen(uri);
1275
1276 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
1277 "?baud=%s+bits=%s+parity=%s+flow=%s",
1278 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1279 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1280 }
1281
1282 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1283 NULL, uri);
1284
1285 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1286
c5571a1d
MS
1287 var = cgiGetVariable("printer_is_shared");
1288 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared",
1289 var && (!strcmp(var, "1") || !strcmp(var, "on")));
1290
ef416fc2 1291 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1292 IPP_PRINTER_IDLE);
1293
1294 /*
1295 * Do the request and get back a response...
1296 */
1297
1298 if (file)
fa73b229 1299 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
ef416fc2 1300 else
fa73b229 1301 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 1302
355e94dc
MS
1303 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1304 {
1305 puts("Status: 401\n");
1306 exit(0);
1307 }
1308 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 1309 {
1310 cgiStartHTML(title);
fa73b229 1311 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1312 _("Unable to add printer:"));
ef416fc2 1313 }
2e4ff8af 1314 else if (modify)
ef416fc2 1315 {
1316 /*
2e4ff8af 1317 * Redirect successful updates back to the printer page...
ef416fc2 1318 */
1319
1320 char refresh[1024]; /* Refresh URL */
1321
1322
1323 cgiFormEncode(uri, name, sizeof(uri));
1324
2e4ff8af
MS
1325 snprintf(refresh, sizeof(refresh),
1326 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
ef416fc2 1327
1328 cgiSetVariable("refresh_page", refresh);
1329
1330 cgiStartHTML(title);
1331
2e4ff8af
MS
1332 cgiCopyTemplateLang("printer-modified.tmpl");
1333 }
1334 else
1335 {
1336 /*
1337 * Set the printer options...
1338 */
1339
1340 cgiSetVariable("OP", "set-printer-options");
1341 do_set_options(http, 0);
1342 return;
ef416fc2 1343 }
1344
1345 cgiEndHTML();
1346 }
1347
1348 if (oldinfo)
1349 ippDelete(oldinfo);
1350}
1351
1352
f7deaa1a 1353/*
1354 * 'do_cancel_subscription()' - Cancel a subscription.
1355 */
1356
1357static void
1358do_cancel_subscription(http_t *http)/* I - HTTP connection */
1359{
1360 ipp_t *request; /* IPP request data */
1361 const char *var, /* Form variable */
1362 *user; /* Username */
1363 int id; /* Subscription ID */
1364
1365
1366 /*
1367 * See if we have all of the required information...
1368 */
1369
1370 if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL)
1371 id = atoi(var);
1372 else
1373 id = 0;
1374
1375 if (id <= 0)
1376 {
1377 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1378 cgiStartHTML(_("Cancel RSS Subscription"));
1379 cgiCopyTemplateLang("error.tmpl");
1380 cgiEndHTML();
1381 return;
1382 }
1383
839a51c8
MS
1384 /*
1385 * Require a username...
1386 */
1387
1388 if ((user = getenv("REMOTE_USER")) == NULL)
1389 {
1390 puts("Status: 401\n");
1391 exit(0);
1392 }
1393
f7deaa1a 1394 /*
1395 * Cancel the subscription...
1396 */
1397
1398 request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
1399
1400 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1401 NULL, "ipp://localhost/");
1402 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
1403 "notify-subscription-id", id);
1404
f7deaa1a 1405 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1406 NULL, user);
1407
1408 ippDelete(cupsDoRequest(http, request, "/"));
1409
355e94dc
MS
1410 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1411 {
1412 puts("Status: 401\n");
1413 exit(0);
1414 }
1415 else if (cupsLastError() > IPP_OK_CONFLICT)
f7deaa1a 1416 {
1417 cgiStartHTML(_("Cancel RSS Subscription"));
1418 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1419 }
1420 else
1421 {
1422 /*
1423 * Redirect successful updates back to the admin page...
1424 */
1425
1426 cgiSetVariable("refresh_page", "5;URL=/admin");
1427 cgiStartHTML(_("Cancel RSS Subscription"));
1428 cgiCopyTemplateLang("subscription-canceled.tmpl");
1429 }
1430
1431 cgiEndHTML();
1432}
1433
1434
ef416fc2 1435/*
323c5de1 1436 * 'do_config_server()' - Configure server settings.
ef416fc2 1437 */
1438
1439static void
323c5de1 1440do_config_server(http_t *http) /* I - HTTP connection */
ef416fc2 1441{
2e4ff8af 1442 if (cgiGetVariable("CHANGESETTINGS"))
ef416fc2 1443 {
323c5de1 1444 /*
1445 * Save basic setting changes...
1446 */
ef416fc2 1447
323c5de1 1448 int num_settings; /* Number of server settings */
1449 cups_option_t *settings; /* Server settings */
0af14961
MS
1450 int advanced, /* Advanced settings shown? */
1451 changed; /* Have settings changed? */
323c5de1 1452 const char *debug_logging, /* DEBUG_LOGGING value */
1453 *remote_admin, /* REMOTE_ADMIN value */
1454 *remote_any, /* REMOTE_ANY value */
1455 *remote_printers,
1456 /* REMOTE_PRINTERS value */
1457 *share_printers,/* SHARE_PRINTERS value */
0af14961 1458 *user_cancel_any,
ac884b6a 1459 /* USER_CANCEL_ANY value */
0af14961
MS
1460 *browse_web_if, /* BrowseWebIF value */
1461 *preserve_job_history,
1462 /* PreserveJobHistory value */
1463 *preserve_job_files,
1464 /* PreserveJobFiles value */
1f6f3dbc 1465 *max_clients, /* MaxClients value */
0af14961 1466 *max_jobs, /* MaxJobs value */
1f6f3dbc 1467 *max_log_size; /* MaxLogSize value */
0af14961
MS
1468 char local_protocols[255],
1469 /* BrowseLocalProtocols */
1470 remote_protocols[255];
1471 /* BrowseRemoteProtocols */
58dc1933
MS
1472 const char *current_browse_web_if,
1473 /* BrowseWebIF value */
1474 *current_preserve_job_history,
1475 /* PreserveJobHistory value */
1476 *current_preserve_job_files,
1477 /* PreserveJobFiles value */
1478 *current_max_clients,
1479 /* MaxClients value */
1480 *current_max_jobs,
1481 /* MaxJobs value */
1482 *current_max_log_size,
1483 /* MaxLogSize value */
1484 *current_local_protocols,
1485 /* BrowseLocalProtocols */
1486 *current_remote_protocols;
1487 /* BrowseRemoteProtocols */
323c5de1 1488#ifdef HAVE_GSSAPI
ac884b6a 1489 char default_auth_type[255];
323c5de1 1490 /* DefaultAuthType value */
1f6f3dbc 1491 const char *val; /* Setting value */
323c5de1 1492#endif /* HAVE_GSSAPI */
bd7854cb 1493
ef416fc2 1494
323c5de1 1495 /*
1496 * Get the checkbox values from the form...
1497 */
bd7854cb 1498
0af14961
MS
1499 debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1500 remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1501 remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1502 remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1503 share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1504 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1505
1506 advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL;
1507 if (advanced)
1508 {
1509 /*
1510 * Get advanced settings...
1511 */
1512
1513 browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1514 preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1515 preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1f6f3dbc 1516 max_clients = cgiGetVariable("MAX_CLIENTS");
0af14961
MS
1517 max_jobs = cgiGetVariable("MAX_JOBS");
1518 max_log_size = cgiGetVariable("MAX_LOG_SIZE");
1519
1f6f3dbc
MS
1520 if (!max_clients || atoi(max_clients) <= 0)
1521 max_clients = "100";
1522
0af14961
MS
1523 if (!max_jobs || atoi(max_jobs) <= 0)
1524 max_jobs = "500";
1525
1526 if (!max_log_size || atof(max_log_size) <= 0.0)
1527 max_log_size = "1m";
1528
1529 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1530 strcpy(local_protocols, "cups");
1531 else
1532 local_protocols[0] = '\0';
1533
1534#ifdef HAVE_DNSSD
1535 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1536 {
1537 if (local_protocols[0])
1538 strcat(local_protocols, " dnssd");
1539 else
1540 strcat(local_protocols, "dnssd");
1541 }
1542#endif /* HAVE_DNSSD */
1543
1544#ifdef HAVE_LDAP
1545 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1546 {
1547 if (local_protocols[0])
1548 strcat(local_protocols, " ldap");
1549 else
1550 strcat(local_protocols, "ldap");
1551 }
1552#endif /* HAVE_LDAP */
1553
1554#ifdef HAVE_LIBSLP
1555 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1556 {
1557 if (local_protocols[0])
1558 strcat(local_protocols, " slp");
1559 else
1560 strcat(local_protocols, "slp");
1561 }
1562#endif /* HAVE_SLP */
1563
1564 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1565 strcpy(remote_protocols, "cups");
1566 else
1567 remote_protocols[0] = '\0';
1568
1569#ifdef HAVE_LDAP
1570 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1571 {
1572 if (remote_protocols[0])
1573 strcat(remote_protocols, " ldap");
1574 else
1575 strcat(remote_protocols, "ldap");
1576 }
1577#endif /* HAVE_LDAP */
1578
1579#ifdef HAVE_LIBSLP
1580 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1581 {
1582 if (remote_protocols[0])
1583 strcat(remote_protocols, " slp");
1584 else
1585 strcat(remote_protocols, "slp");
1586 }
1587#endif /* HAVE_SLP */
1588 }
bd7854cb 1589
323c5de1 1590 /*
1591 * Get the current server settings...
1592 */
ef416fc2 1593
323c5de1 1594 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
1595 {
1596 cgiStartHTML(cgiText(_("Change Settings")));
1597 cgiSetVariable("MESSAGE",
1598 cgiText(_("Unable to change server settings:")));
1599 cgiSetVariable("ERROR", cupsLastErrorString());
1600 cgiCopyTemplateLang("error.tmpl");
1601 cgiEndHTML();
1602 return;
1603 }
ef416fc2 1604
0a682745
MS
1605#ifdef HAVE_GSSAPI
1606 /*
1607 * Get authentication settings...
1608 */
1609
1610 if (cgiGetVariable("KERBEROS"))
ac884b6a 1611 strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
0a682745
MS
1612 else
1613 {
0af14961 1614 val = cupsGetOption("DefaultAuthType", num_settings, settings);
ac884b6a 1615
1f6f3dbc 1616 if (!val || !strcasecmp(val, "Negotiate"))
ac884b6a
MS
1617 strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
1618 else
1619 strlcpy(default_auth_type, val, sizeof(default_auth_type));
0a682745
MS
1620 }
1621
1622 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1623#endif /* HAVE_GSSAPI */
1624
58dc1933
MS
1625 if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings,
1626 settings)) == NULL)
1627 current_browse_web_if = "No";
1628
1629 if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory",
1630 num_settings,
1631 settings)) == NULL)
1632 current_preserve_job_history = "Yes";
1633
1634 if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles",
1635 num_settings,
1636 settings)) == NULL)
1637 current_preserve_job_files = "No";
1638
1639 if ((current_max_clients = cupsGetOption("MaxClients", num_settings,
1640 settings)) == NULL)
1641 current_max_clients = "100";
1642
1643 if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings,
1644 settings)) == NULL)
1645 current_max_jobs = "500";
1646
1647 if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings,
1648 settings)) == NULL)
1649 current_max_log_size = "1m";
1650
1651 if ((current_local_protocols = cupsGetOption("BrowseLocalProtocols",
1652 num_settings,
1653 settings)) == NULL)
1654 current_local_protocols = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
1655
1656 if ((current_remote_protocols = cupsGetOption("BrowseRemoteProtocols",
1657 num_settings,
1658 settings)) == NULL)
1659 current_remote_protocols = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
1660
323c5de1 1661 /*
1662 * See if the settings have changed...
1663 */
1664
0af14961
MS
1665 changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1666 num_settings, settings)) ||
1667 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1668 num_settings, settings)) ||
1669 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1670 num_settings, settings)) ||
1671 strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
1672 num_settings, settings)) ||
1673 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1674 num_settings, settings)) ||
323c5de1 1675#ifdef HAVE_GSSAPI
0af14961
MS
1676 !cupsGetOption("DefaultAuthType", num_settings, settings) ||
1677 strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1678 num_settings, settings)) ||
323c5de1 1679#endif /* HAVE_GSSAPI */
0af14961
MS
1680 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1681 num_settings, settings));
1682
1683 if (advanced && !changed)
58dc1933
MS
1684 changed = strcasecmp(local_protocols, current_local_protocols) ||
1685 strcasecmp(remote_protocols, current_remote_protocols) ||
1686 strcasecmp(browse_web_if, current_browse_web_if) ||
1687 strcasecmp(preserve_job_history, current_preserve_job_history) ||
1688 strcasecmp(preserve_job_files, current_preserve_job_files) ||
1689 strcasecmp(max_clients, current_max_clients) ||
1690 strcasecmp(max_jobs, current_max_jobs) ||
1691 strcasecmp(max_log_size, current_max_log_size);
0af14961
MS
1692
1693 if (changed)
323c5de1 1694 {
1695 /*
1696 * Settings *have* changed, so save the changes...
1697 */
ef416fc2 1698
323c5de1 1699 cupsFreeOptions(num_settings, settings);
ef416fc2 1700
323c5de1 1701 num_settings = 0;
1702 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1703 debug_logging, num_settings, &settings);
1704 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1705 remote_admin, num_settings, &settings);
1706 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1707 remote_any, num_settings, &settings);
1708 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1709 remote_printers, num_settings, &settings);
1710 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1711 share_printers, num_settings, &settings);
1712 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1713 user_cancel_any, num_settings, &settings);
1714#ifdef HAVE_GSSAPI
1715 num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
1716 num_settings, &settings);
1717#endif /* HAVE_GSSAPI */
ef416fc2 1718
0af14961
MS
1719 if (advanced)
1720 {
1721 /*
1722 * Add advanced settings...
1723 */
1724
58dc1933 1725 if (strcasecmp(local_protocols, current_local_protocols))
0af14961
MS
1726 num_settings = cupsAddOption("BrowseLocalProtocols", local_protocols,
1727 num_settings, &settings);
58dc1933 1728 if (strcasecmp(remote_protocols, current_remote_protocols))
0af14961
MS
1729 num_settings = cupsAddOption("BrowseRemoteProtocols", remote_protocols,
1730 num_settings, &settings);
58dc1933 1731 if (strcasecmp(browse_web_if, current_browse_web_if))
0af14961
MS
1732 num_settings = cupsAddOption("BrowseWebIF", browse_web_if,
1733 num_settings, &settings);
58dc1933 1734 if (strcasecmp(preserve_job_history, current_preserve_job_history))
0af14961
MS
1735 num_settings = cupsAddOption("PreserveJobHistory",
1736 preserve_job_history, num_settings,
1737 &settings);
58dc1933 1738 if (strcasecmp(preserve_job_files, current_preserve_job_files))
0af14961
MS
1739 num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files,
1740 num_settings, &settings);
58dc1933 1741 if (strcasecmp(max_clients, current_max_clients))
1f6f3dbc
MS
1742 num_settings = cupsAddOption("MaxClients", max_clients, num_settings,
1743 &settings);
58dc1933 1744 if (strcasecmp(max_jobs, current_max_jobs))
0af14961
MS
1745 num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings,
1746 &settings);
58dc1933 1747 if (strcasecmp(max_log_size, current_max_log_size))
0af14961
MS
1748 num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings,
1749 &settings);
1750 }
1751
323c5de1 1752 if (!cupsAdminSetServerSettings(http, num_settings, settings))
ef416fc2 1753 {
355e94dc
MS
1754 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1755 {
1756 puts("Status: 401\n");
1757 exit(0);
1758 }
1759
323c5de1 1760 cgiStartHTML(cgiText(_("Change Settings")));
1761 cgiSetVariable("MESSAGE",
1762 cgiText(_("Unable to change server settings:")));
1763 cgiSetVariable("ERROR", cupsLastErrorString());
1764 cgiCopyTemplateLang("error.tmpl");
ef416fc2 1765 }
ef416fc2 1766 else
323c5de1 1767 {
58dc1933
MS
1768 if (advanced)
1769 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1770 else
1771 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
323c5de1 1772 cgiStartHTML(cgiText(_("Change Settings")));
1773 cgiCopyTemplateLang("restart.tmpl");
1774 }
1775 }
1776 else
1777 {
1778 /*
1779 * No changes...
1780 */
ef416fc2 1781
323c5de1 1782 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1783 cgiStartHTML(cgiText(_("Change Settings")));
1784 cgiCopyTemplateLang("norestart.tmpl");
1785 }
ef416fc2 1786
323c5de1 1787 cupsFreeOptions(num_settings, settings);
ef416fc2 1788
323c5de1 1789 cgiEndHTML();
1790 }
2e4ff8af 1791 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
ef416fc2 1792 {
1793 /*
323c5de1 1794 * Save hand-edited config file...
ef416fc2 1795 */
1796
323c5de1 1797 http_status_t status; /* PUT status */
1798 char tempfile[1024]; /* Temporary new cupsd.conf */
1799 int tempfd; /* Temporary file descriptor */
1800 cups_file_t *temp; /* Temporary file */
1801 const char *start, /* Start of line */
1802 *end; /* End of line */
bd7854cb 1803
fa73b229 1804
323c5de1 1805 /*
1806 * Create a temporary file for the new cupsd.conf file...
1807 */
ef416fc2 1808
323c5de1 1809 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
ef416fc2 1810 {
323c5de1 1811 cgiStartHTML(cgiText(_("Edit Configuration File")));
1812 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1813 cgiSetVariable("ERROR", strerror(errno));
1814 cgiCopyTemplateLang("error.tmpl");
1815 cgiEndHTML();
1816
1817 perror(tempfile);
1818 return;
ef416fc2 1819 }
1820
323c5de1 1821 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
ef416fc2 1822 {
323c5de1 1823 cgiStartHTML(cgiText(_("Edit Configuration File")));
1824 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1825 cgiSetVariable("ERROR", strerror(errno));
1826 cgiCopyTemplateLang("error.tmpl");
1827 cgiEndHTML();
ef416fc2 1828
323c5de1 1829 perror(tempfile);
1830 close(tempfd);
1831 unlink(tempfile);
1832 return;
1833 }
ef416fc2 1834
323c5de1 1835 /*
1836 * Copy the cupsd.conf text from the form variable...
1837 */
ef416fc2 1838
323c5de1 1839 start = cgiGetVariable("CUPSDCONF");
1840 while (start)
1841 {
1842 if ((end = strstr(start, "\r\n")) == NULL)
1843 if ((end = strstr(start, "\n")) == NULL)
1844 end = start + strlen(start);
ef416fc2 1845
323c5de1 1846 cupsFileWrite(temp, start, end - start);
1847 cupsFilePutChar(temp, '\n');
ef416fc2 1848
323c5de1 1849 if (*end == '\r')
1850 start = end + 2;
1851 else if (*end == '\n')
1852 start = end + 1;
1853 else
1854 start = NULL;
1855 }
ef416fc2 1856
323c5de1 1857 cupsFileClose(temp);
ef416fc2 1858
323c5de1 1859 /*
1860 * Upload the configuration file to the server...
1861 */
ef416fc2 1862
323c5de1 1863 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
ef416fc2 1864
355e94dc
MS
1865 if (status == HTTP_UNAUTHORIZED)
1866 {
1867 puts("Status: 401\n");
1868 unlink(tempfile);
1869 exit(0);
1870 }
1871 else if (status != HTTP_CREATED)
323c5de1 1872 {
1873 cgiSetVariable("MESSAGE",
1874 cgiText(_("Unable to upload cupsd.conf file:")));
1875 cgiSetVariable("ERROR", httpStatus(status));
1876
1877 cgiStartHTML(cgiText(_("Edit Configuration File")));
1878 cgiCopyTemplateLang("error.tmpl");
1879 }
1880 else
1881 {
1882 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1883
1884 cgiStartHTML(cgiText(_("Edit Configuration File")));
1885 cgiCopyTemplateLang("restart.tmpl");
ef416fc2 1886 }
1887
323c5de1 1888 cgiEndHTML();
1889
1890 unlink(tempfile);
1891 }
1892 else
1893 {
1894 struct stat info; /* cupsd.conf information */
1895 cups_file_t *cupsd; /* cupsd.conf file */
355e94dc
MS
1896 char *buffer, /* Buffer for entire file */
1897 *bufptr, /* Pointer into buffer */
1898 *bufend; /* End of buffer */
1899 int ch; /* Character from file */
323c5de1 1900 char filename[1024]; /* Filename */
1901 const char *server_root; /* Location of config files */
1902
1903
ef416fc2 1904 /*
323c5de1 1905 * Locate the cupsd.conf file...
ef416fc2 1906 */
1907
323c5de1 1908 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1909 server_root = CUPS_SERVERROOT;
ef416fc2 1910
323c5de1 1911 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
ef416fc2 1912
1913 /*
323c5de1 1914 * Figure out the size...
ef416fc2 1915 */
1916
323c5de1 1917 if (stat(filename, &info))
ef416fc2 1918 {
323c5de1 1919 cgiStartHTML(cgiText(_("Edit Configuration File")));
1920 cgiSetVariable("MESSAGE",
1921 cgiText(_("Unable to access cupsd.conf file:")));
1922 cgiSetVariable("ERROR", strerror(errno));
1923 cgiCopyTemplateLang("error.tmpl");
1924 cgiEndHTML();
ef416fc2 1925
323c5de1 1926 perror(filename);
1927 return;
1928 }
ef416fc2 1929
323c5de1 1930 if (info.st_size > (1024 * 1024))
1931 {
1932 cgiStartHTML(cgiText(_("Edit Configuration File")));
1933 cgiSetVariable("MESSAGE",
1934 cgiText(_("Unable to access cupsd.conf file:")));
1935 cgiSetVariable("ERROR",
1936 cgiText(_("Unable to edit cupsd.conf files larger than "
1937 "1MB!")));
1938 cgiCopyTemplateLang("error.tmpl");
1939 cgiEndHTML();
ef416fc2 1940
323c5de1 1941 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
1942 (long)info.st_size);
1943 return;
1944 }
ef416fc2 1945
323c5de1 1946 /*
1947 * Open the cupsd.conf file...
1948 */
ef416fc2 1949
323c5de1 1950 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
1951 {
1952 /*
1953 * Unable to open - log an error...
1954 */
ef416fc2 1955
323c5de1 1956 cgiStartHTML(cgiText(_("Edit Configuration File")));
1957 cgiSetVariable("MESSAGE",
1958 cgiText(_("Unable to access cupsd.conf file:")));
1959 cgiSetVariable("ERROR", strerror(errno));
1960 cgiCopyTemplateLang("error.tmpl");
1961 cgiEndHTML();
ef416fc2 1962
323c5de1 1963 perror(filename);
1964 return;
1965 }
ef416fc2 1966
323c5de1 1967 /*
1968 * Allocate memory and load the file into a string buffer...
1969 */
ef416fc2 1970
91c84a35
MS
1971 if ((buffer = calloc(1, info.st_size + 1)) != NULL)
1972 {
1973 cupsFileRead(cupsd, buffer, info.st_size);
1974 cgiSetVariable("CUPSDCONF", buffer);
1975 free(buffer);
1976 }
ef416fc2 1977
323c5de1 1978 cupsFileClose(cupsd);
ef416fc2 1979
355e94dc
MS
1980 /*
1981 * Then get the default cupsd.conf file and put that into a string as
1982 * well...
1983 */
1984
1985 strlcat(filename, ".default", sizeof(filename));
1986
1987 if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
1988 (cupsd = cupsFileOpen(filename, "r")) != NULL)
1989 {
91c84a35 1990 if ((buffer = calloc(1, 2 * info.st_size + 1)) != NULL)
355e94dc 1991 {
91c84a35
MS
1992 bufend = buffer + 2 * info.st_size - 1;
1993
1994 for (bufptr = buffer;
1995 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
355e94dc 1996 {
91c84a35
MS
1997 if (ch == '\\' || ch == '\"')
1998 {
1999 *bufptr++ = '\\';
2000 *bufptr++ = ch;
2001 }
2002 else if (ch == '\n')
2003 {
2004 *bufptr++ = '\\';
2005 *bufptr++ = 'n';
2006 }
2007 else if (ch == '\t')
2008 {
2009 *bufptr++ = '\\';
2010 *bufptr++ = 't';
2011 }
2012 else if (ch >= ' ')
2013 *bufptr++ = ch;
355e94dc 2014 }
355e94dc 2015
91c84a35 2016 *bufptr = '\0';
355e94dc 2017
91c84a35
MS
2018 cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
2019 free(buffer);
2020 }
355e94dc 2021
91c84a35 2022 cupsFileClose(cupsd);
355e94dc
MS
2023 }
2024
323c5de1 2025 /*
2026 * Show the current config file...
2027 */
ef416fc2 2028
323c5de1 2029 cgiStartHTML(cgiText(_("Edit Configuration File")));
ef416fc2 2030
323c5de1 2031 cgiCopyTemplateLang("edit-config.tmpl");
ef416fc2 2032
323c5de1 2033 cgiEndHTML();
2034 }
2035}
ef416fc2 2036
ef416fc2 2037
323c5de1 2038/*
749b1e90 2039 * 'do_delete_class()' - Delete a class.
323c5de1 2040 */
ef416fc2 2041
323c5de1 2042static void
2043do_delete_class(http_t *http) /* I - HTTP connection */
2044{
2045 ipp_t *request; /* IPP request */
2046 char uri[HTTP_MAX_URI]; /* Job URI */
2047 const char *pclass; /* Printer class name */
ef416fc2 2048
ef416fc2 2049
323c5de1 2050 /*
2051 * Get form variables...
2052 */
ef416fc2 2053
323c5de1 2054 if (cgiGetVariable("CONFIRM") == NULL)
2055 {
2056 cgiStartHTML(cgiText(_("Delete Class")));
2057 cgiCopyTemplateLang("class-confirm.tmpl");
2058 cgiEndHTML();
2059 return;
2060 }
ef416fc2 2061
323c5de1 2062 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
2063 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2064 "localhost", 0, "/classes/%s", pclass);
2065 else
2066 {
2067 cgiStartHTML(cgiText(_("Delete Class")));
2068 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2069 cgiCopyTemplateLang("error.tmpl");
2070 cgiEndHTML();
2071 return;
2072 }
ef416fc2 2073
323c5de1 2074 /*
2075 * Build a CUPS_DELETE_CLASS request, which requires the following
2076 * attributes:
2077 *
2078 * attributes-charset
2079 * attributes-natural-language
2080 * printer-uri
2081 */
2082
2083 request = ippNewRequest(CUPS_DELETE_CLASS);
2084
2085 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2086 NULL, uri);
2087
2088 /*
2089 * Do the request and get back a response...
2090 */
2091
2092 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 2093
323c5de1 2094 /*
2095 * Show the results...
2096 */
2097
355e94dc
MS
2098 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2099 {
2100 puts("Status: 401\n");
2101 exit(0);
2102 }
2103 else if (cupsLastError() <= IPP_OK_CONFLICT)
323c5de1 2104 {
ef416fc2 2105 /*
323c5de1 2106 * Redirect successful updates back to the classes page...
ef416fc2 2107 */
2108
323c5de1 2109 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2110 }
ef416fc2 2111
323c5de1 2112 cgiStartHTML(cgiText(_("Delete Class")));
ef416fc2 2113
323c5de1 2114 if (cupsLastError() > IPP_OK_CONFLICT)
2115 cgiShowIPPError(_("Unable to delete class:"));
2116 else
2117 cgiCopyTemplateLang("class-deleted.tmpl");
ef416fc2 2118
323c5de1 2119 cgiEndHTML();
2120}
ef416fc2 2121
ef416fc2 2122
323c5de1 2123/*
749b1e90 2124 * 'do_delete_printer()' - Delete a printer.
323c5de1 2125 */
ef416fc2 2126
323c5de1 2127static void
2128do_delete_printer(http_t *http) /* I - HTTP connection */
2129{
2130 ipp_t *request; /* IPP request */
2131 char uri[HTTP_MAX_URI]; /* Job URI */
2132 const char *printer; /* Printer printer name */
ef416fc2 2133
323c5de1 2134
2135 /*
2136 * Get form variables...
2137 */
2138
2139 if (cgiGetVariable("CONFIRM") == NULL)
2140 {
2141 cgiStartHTML(cgiText(_("Delete Printer")));
2142 cgiCopyTemplateLang("printer-confirm.tmpl");
ef416fc2 2143 cgiEndHTML();
323c5de1 2144 return;
ef416fc2 2145 }
323c5de1 2146
2147 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2148 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2149 "localhost", 0, "/printers/%s", printer);
ef416fc2 2150 else
323c5de1 2151 {
2152 cgiStartHTML(cgiText(_("Delete Printer")));
2153 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2154 cgiCopyTemplateLang("error.tmpl");
2155 cgiEndHTML();
2156 return;
2157 }
2158
2159 /*
2160 * Build a CUPS_DELETE_PRINTER request, which requires the following
2161 * attributes:
2162 *
2163 * attributes-charset
2164 * attributes-natural-language
2165 * printer-uri
2166 */
2167
2168 request = ippNewRequest(CUPS_DELETE_PRINTER);
2169
2170 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2171 NULL, uri);
2172
2173 /*
2174 * Do the request and get back a response...
2175 */
2176
2177 ippDelete(cupsDoRequest(http, request, "/admin/"));
2178
2179 /*
2180 * Show the results...
2181 */
2182
355e94dc
MS
2183 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2184 {
2185 puts("Status: 401\n");
2186 exit(0);
2187 }
2188 else if (cupsLastError() <= IPP_OK_CONFLICT)
ef416fc2 2189 {
2190 /*
323c5de1 2191 * Redirect successful updates back to the printers page...
ef416fc2 2192 */
2193
323c5de1 2194 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2195 }
bd7854cb 2196
323c5de1 2197 cgiStartHTML(cgiText(_("Delete Printer")));
ef416fc2 2198
323c5de1 2199 if (cupsLastError() > IPP_OK_CONFLICT)
2200 cgiShowIPPError(_("Unable to delete printer:"));
2201 else
2202 cgiCopyTemplateLang("printer-deleted.tmpl");
ef416fc2 2203
323c5de1 2204 cgiEndHTML();
2205}
ef416fc2 2206
ef416fc2 2207
323c5de1 2208/*
749b1e90 2209 * 'do_export()' - Export printers to Samba.
323c5de1 2210 */
ef416fc2 2211
323c5de1 2212static void
2213do_export(http_t *http) /* I - HTTP connection */
2214{
2215 int i, j; /* Looping vars */
2216 ipp_t *request, /* IPP request */
2217 *response; /* IPP response */
2218 const char *username, /* Samba username */
2219 *password, /* Samba password */
2220 *export_all; /* Export all printers? */
2221 int export_count, /* Number of printers to export */
2222 printer_count; /* Number of available printers */
2223 const char *name, /* What name to pull */
2224 *dest; /* Current destination */
2225 char ppd[1024]; /* PPD file */
ef416fc2 2226
ef416fc2 2227
323c5de1 2228 /*
2229 * Get form data...
2230 */
ef416fc2 2231
323c5de1 2232 username = cgiGetVariable("USERNAME");
2233 password = cgiGetVariable("PASSWORD");
2234 export_all = cgiGetVariable("EXPORT_ALL");
2235 export_count = cgiGetSize("EXPORT_NAME");
ef416fc2 2236
323c5de1 2237 /*
2238 * Get list of available printers...
2239 */
ef416fc2 2240
323c5de1 2241 cgiSetSize("PRINTER_NAME", 0);
2242 cgiSetSize("PRINTER_EXPORT", 0);
ef416fc2 2243
323c5de1 2244 request = ippNewRequest(CUPS_GET_PRINTERS);
ef416fc2 2245
323c5de1 2246 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2247 "printer-type", 0);
ef416fc2 2248
323c5de1 2249 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2250 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
2251 CUPS_PRINTER_IMPLICIT);
ef416fc2 2252
323c5de1 2253 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2254 "requested-attributes", NULL, "printer-name");
ef416fc2 2255
323c5de1 2256 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2257 {
2258 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2259 ippDelete(response);
ef416fc2 2260
323c5de1 2261 if (!export_all)
2262 {
2263 printer_count = cgiGetSize("PRINTER_NAME");
ef416fc2 2264
323c5de1 2265 for (i = 0; i < printer_count; i ++)
2266 {
2267 dest = cgiGetArray("PRINTER_NAME", i);
ef416fc2 2268
323c5de1 2269 for (j = 0; j < export_count; j ++)
2270 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
2271 break;
2272
2273 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
2274 }
2275 }
2276 }
2277
2278 /*
2279 * Export or get the printers to export...
2280 */
ef416fc2 2281
323c5de1 2282 if (username && *username && password && *password &&
2283 (export_all || export_count > 0))
2284 {
ef416fc2 2285 /*
323c5de1 2286 * Do export...
ef416fc2 2287 */
2288
323c5de1 2289 fputs("DEBUG: Export printers...\n", stderr);
ef416fc2 2290
323c5de1 2291 if (export_all)
ef416fc2 2292 {
323c5de1 2293 name = "PRINTER_NAME";
2294 export_count = cgiGetSize("PRINTER_NAME");
ef416fc2 2295 }
2296 else
323c5de1 2297 name = "EXPORT_NAME";
ef416fc2 2298
323c5de1 2299 for (i = 0; i < export_count; i ++)
2300 {
2301 dest = cgiGetArray(name, i);
ef416fc2 2302
323c5de1 2303 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2304 break;
fa73b229 2305
323c5de1 2306 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2307 stderr);
ef416fc2 2308
323c5de1 2309 unlink(ppd);
ef416fc2 2310
323c5de1 2311 if (!j)
2312 break;
ef416fc2 2313 }
2314
323c5de1 2315 if (i < export_count)
2316 cgiSetVariable("ERROR", cupsLastErrorString());
2317 else
2318 {
2319 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2320 cgiCopyTemplateLang("samba-exported.tmpl");
2321 cgiEndHTML();
2322 return;
2323 }
ef416fc2 2324 }
323c5de1 2325 else if (username && !*username)
2326 cgiSetVariable("ERROR",
2327 cgiText(_("A Samba username is required to export "
2328 "printer drivers!")));
2329 else if (username && (!password || !*password))
2330 cgiSetVariable("ERROR",
2331 cgiText(_("A Samba password is required to export "
2332 "printer drivers!")));
2333
2334 /*
2335 * Show form...
2336 */
ef416fc2 2337
323c5de1 2338 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2339 cgiCopyTemplateLang("samba-export.tmpl");
2340 cgiEndHTML();
ef416fc2 2341}
2342
2343
2344/*
749b1e90 2345 * 'do_list_printers()' - List available printers.
ef416fc2 2346 */
2347
2348static void
323c5de1 2349do_list_printers(http_t *http) /* I - HTTP connection */
ef416fc2 2350{
323c5de1 2351 ipp_t *request, /* IPP request */
2352 *response; /* IPP response */
2353 ipp_attribute_t *attr; /* IPP attribute */
ef416fc2 2354
757d2cad 2355
323c5de1 2356 cgiStartHTML(cgiText(_("List Available Printers")));
2357 fflush(stdout);
2358
2359 /*
2360 * Get the list of printers and their devices...
2361 */
2362
2363 request = ippNewRequest(CUPS_GET_PRINTERS);
2364
2365 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2366 "requested-attributes", NULL, "device-uri");
2367
2368 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2369 CUPS_PRINTER_LOCAL);
2370 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2371 CUPS_PRINTER_LOCAL);
757d2cad 2372
323c5de1 2373 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2374 {
d09495fa 2375 /*
323c5de1 2376 * Got the printer list, now load the devices...
d09495fa 2377 */
2378
323c5de1 2379 int i; /* Looping var */
2380 cups_array_t *printer_devices; /* Printer devices for local printers */
2381 char *printer_device; /* Current printer device */
7594b224 2382
d09495fa 2383
2384 /*
323c5de1 2385 * Allocate an array and copy the device strings...
d09495fa 2386 */
2387
323c5de1 2388 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2389
2390 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2391 attr;
2392 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
ef416fc2 2393 {
323c5de1 2394 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
d09495fa 2395 }
2396
2397 /*
323c5de1 2398 * Free the printer list and get the device list...
d09495fa 2399 */
2400
323c5de1 2401 ippDelete(response);
d09495fa 2402
323c5de1 2403 request = ippNewRequest(CUPS_GET_DEVICES);
d09495fa 2404
323c5de1 2405 if ((response = cupsDoRequest(http, request, "/")) != NULL)
ef416fc2 2406 {
d09495fa 2407 /*
323c5de1 2408 * Got the device list, let's parse it...
d09495fa 2409 */
2410
323c5de1 2411 const char *device_uri, /* device-uri attribute value */
2412 *device_make_and_model, /* device-make-and-model value */
2413 *device_info; /* device-info value */
ef416fc2 2414
ef416fc2 2415
323c5de1 2416 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2417 {
2418 /*
2419 * Skip leading attributes until we hit a device...
2420 */
ef416fc2 2421
323c5de1 2422 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2423 attr = attr->next;
ef416fc2 2424
323c5de1 2425 if (!attr)
2426 break;
ef416fc2 2427
323c5de1 2428 /*
2429 * Pull the needed attributes from this device...
2430 */
ef416fc2 2431
323c5de1 2432 device_info = NULL;
2433 device_make_and_model = NULL;
2434 device_uri = NULL;
ef416fc2 2435
323c5de1 2436 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2437 {
2438 if (!strcmp(attr->name, "device-info") &&
2439 attr->value_tag == IPP_TAG_TEXT)
2440 device_info = attr->values[0].string.text;
ef416fc2 2441
323c5de1 2442 if (!strcmp(attr->name, "device-make-and-model") &&
2443 attr->value_tag == IPP_TAG_TEXT)
2444 device_make_and_model = attr->values[0].string.text;
ef416fc2 2445
323c5de1 2446 if (!strcmp(attr->name, "device-uri") &&
2447 attr->value_tag == IPP_TAG_URI)
2448 device_uri = attr->values[0].string.text;
ef416fc2 2449
323c5de1 2450 attr = attr->next;
2451 }
ef416fc2 2452
323c5de1 2453 /*
2454 * See if we have everything needed...
2455 */
ef416fc2 2456
323c5de1 2457 if (device_info && device_make_and_model && device_uri &&
2458 strcasecmp(device_make_and_model, "unknown") &&
2459 strchr(device_uri, ':'))
2460 {
2461 /*
2462 * Yes, now see if there is already a printer for this
2463 * device...
2464 */
ef416fc2 2465
323c5de1 2466 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2467 {
2468 /*
2469 * Not found, so it must be a new printer...
2470 */
ef416fc2 2471
2e4ff8af
MS
2472 char option[1024], /* Form variables for this device */
2473 *option_ptr; /* Pointer into string */
323c5de1 2474 const char *ptr; /* Pointer into device string */
ef416fc2 2475
fa73b229 2476
323c5de1 2477 /*
2478 * Format the printer name variable for this device...
2479 *
2480 * We use the device-info string first, then device-uri,
2481 * and finally device-make-and-model to come up with a
2482 * suitable name.
2483 */
ef416fc2 2484
323c5de1 2485 if (strncasecmp(device_info, "unknown", 7))
2486 ptr = device_info;
2487 else if ((ptr = strstr(device_uri, "://")) != NULL)
2488 ptr += 3;
2489 else
2490 ptr = device_make_and_model;
ef416fc2 2491
2e4ff8af
MS
2492 for (option_ptr = option;
2493 option_ptr < (option + sizeof(option) - 1) && *ptr;
323c5de1 2494 ptr ++)
2495 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2496 *ptr == '.')
2e4ff8af
MS
2497 *option_ptr++ = *ptr;
2498 else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_')
2499 *option_ptr++ = '_';
323c5de1 2500 else if (*ptr == '?' || *ptr == '(')
2501 break;
ef416fc2 2502
2e4ff8af 2503 *option_ptr = '\0';
ef416fc2 2504
2e4ff8af 2505 cgiSetArray("TEMPLATE_NAME", i, option);
ef416fc2 2506
323c5de1 2507 /*
2508 * Finally, set the form variables for this printer...
2509 */
ef416fc2 2510
323c5de1 2511 cgiSetArray("device_info", i, device_info);
2512 cgiSetArray("device_make_and_model", i, device_make_and_model);
323c5de1 2513 cgiSetArray("device_uri", i, device_uri);
2514 i ++;
2515 }
2516 }
ef416fc2 2517
323c5de1 2518 if (!attr)
2519 break;
2520 }
2521
2522 ippDelete(response);
ef416fc2 2523
ef416fc2 2524 /*
323c5de1 2525 * Free the device list...
ef416fc2 2526 */
2527
323c5de1 2528 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2529 printer_device;
2530 printer_device = (char *)cupsArrayNext(printer_devices))
2531 free(printer_device);
ef416fc2 2532
323c5de1 2533 cupsArrayDelete(printer_devices);
ef416fc2 2534 }
323c5de1 2535 }
ef416fc2 2536
323c5de1 2537 /*
2538 * Finally, show the printer list...
2539 */
ef416fc2 2540
323c5de1 2541 cgiCopyTemplateLang("list-available-printers.tmpl");
ef416fc2 2542
323c5de1 2543 cgiEndHTML();
ef416fc2 2544}
2545
2546
2547/*
749b1e90 2548 * 'do_menu()' - Show the main menu.
ef416fc2 2549 */
2550
2551static void
323c5de1 2552do_menu(http_t *http) /* I - HTTP connection */
ef416fc2 2553{
323c5de1 2554 int num_settings; /* Number of server settings */
2555 cups_option_t *settings; /* Server settings */
2556 const char *val; /* Setting value */
2557 char filename[1024]; /* Temporary filename */
2558 const char *datadir; /* Location of data files */
2559 ipp_t *request, /* IPP request */
2560 *response; /* IPP response */
ef416fc2 2561
2562
89d46774 2563 /*
323c5de1 2564 * Get the current server settings...
89d46774 2565 */
fa73b229 2566
323c5de1 2567 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
ef416fc2 2568 {
323c5de1 2569 cgiSetVariable("SETTINGS_MESSAGE",
2570 cgiText(_("Unable to open cupsd.conf file:")));
2571 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
ef416fc2 2572 }
2573
323c5de1 2574 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2575 settings)) != NULL && atoi(val))
2576 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
ef416fc2 2577
323c5de1 2578 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2579 settings)) != NULL && atoi(val))
2580 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
ef416fc2 2581
323c5de1 2582 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2583 settings)) != NULL && atoi(val))
2584 cgiSetVariable("REMOTE_ANY", "CHECKED");
ef416fc2 2585
323c5de1 2586 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2587 settings)) != NULL && atoi(val))
2588 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
ef416fc2 2589
323c5de1 2590 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2591 settings)) != NULL && atoi(val))
2592 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
ef416fc2 2593
323c5de1 2594 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2595 settings)) != NULL && atoi(val))
2596 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2597
2598#ifdef HAVE_GSSAPI
2599 cgiSetVariable("HAVE_GSSAPI", "1");
2600
2601 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2602 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2603 cgiSetVariable("KERBEROS", "CHECKED");
2604#endif /* HAVE_GSSAPI */
2605
0af14961
MS
2606#ifdef HAVE_DNSSD
2607 cgiSetVariable("HAVE_DNSSD", "1");
2608#endif /* HAVE_DNSSD */
2609
2610#ifdef HAVE_LDAP
2611 cgiSetVariable("HAVE_LDAP", "1");
2612#endif /* HAVE_LDAP */
2613
2614#ifdef HAVE_LIBSLP
2615 cgiSetVariable("HAVE_LIBSLP", "1");
2616#endif /* HAVE_LIBSLP */
2617
2618 if ((val = cupsGetOption("BrowseRemoteProtocols", num_settings,
2619 settings)) == NULL)
2620 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2621 settings)) == NULL)
2622 val = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
2623
2624 if (strstr(val, "cups") || strstr(val, "CUPS"))
2625 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2626
2627 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2628 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2629
2630 if (strstr(val, "slp") || strstr(val, "SLP"))
2631 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2632
2633 if ((val = cupsGetOption("BrowseLocalProtocols", num_settings,
2634 settings)) == NULL)
2635 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2636 settings)) == NULL)
2637 val = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
2638
2639 if (strstr(val, "cups") || strstr(val, "CUPS"))
2640 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2641
2642 if (strstr(val, "dnssd") || strstr(val, "DNSSD") ||
2643 strstr(val, "dns-sd") || strstr(val, "DNS-SD") ||
2644 strstr(val, "bonjour") || strstr(val, "BONJOUR"))
2645 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2646
2647 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2648 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2649
2650 if (strstr(val, "slp") || strstr(val, "SLP"))
2651 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2652
2653 if ((val = cupsGetOption("BrowseWebIF", num_settings,
2654 settings)) == NULL)
2655 val = "No";
2656
2657 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2658 !strcasecmp(val, "true"))
2659 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2660
2661 if ((val = cupsGetOption("PreserveJobHistory", num_settings,
2662 settings)) == NULL)
2663 val = "Yes";
2664
2665 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2666 !strcasecmp(val, "true"))
2667 {
2668 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2669
2670 if ((val = cupsGetOption("PreserveJobFiles", num_settings,
2671 settings)) == NULL)
2672 val = "No";
2673
2674 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2675 !strcasecmp(val, "true"))
2676 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2677 }
2678
1f6f3dbc
MS
2679 if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
2680 val = "100";
2681
2682 cgiSetVariable("MAX_CLIENTS", val);
2683
0af14961
MS
2684 if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
2685 val = "500";
2686
2687 cgiSetVariable("MAX_JOBS", val);
2688
2689 if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
2690 val = "1m";
2691
2692 cgiSetVariable("MAX_LOG_SIZE", val);
2693
323c5de1 2694 cupsFreeOptions(num_settings, settings);
ef416fc2 2695
89d46774 2696 /*
323c5de1 2697 * See if Samba and the Windows drivers are installed...
89d46774 2698 */
2699
323c5de1 2700 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2701 datadir = CUPS_DATADIR;
2702
2703 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2704 if (!access(filename, R_OK))
f7deaa1a 2705 {
2706 /*
323c5de1 2707 * Found Windows 2000 driver file, see if we have smbclient and
2708 * rpcclient...
f7deaa1a 2709 */
2710
323c5de1 2711 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2712 sizeof(filename)) &&
2713 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2714 sizeof(filename)))
2715 cgiSetVariable("HAVE_SAMBA", "Y");
2716 else
2717 {
2718 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2719 sizeof(filename)))
2720 fputs("ERROR: smbclient not found!\n", stderr);
2721
2722 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2723 sizeof(filename)))
2724 fputs("ERROR: rpcclient not found!\n", stderr);
2725 }
f7deaa1a 2726 }
323c5de1 2727 else
2728 perror(filename);
f7deaa1a 2729
323c5de1 2730 /*
2731 * Subscriptions...
2732 */
89d46774 2733
323c5de1 2734 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2735
2736 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2737 NULL, "ipp://localhost/");
2738
2739 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2740 {
2741 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2742 ippDelete(response);
2743 }
2744
2745 /*
2746 * Finally, show the main menu template...
2747 */
2748
2749 cgiStartHTML(cgiText(_("Administration")));
2750
2751 cgiCopyTemplateLang("admin.tmpl");
ef416fc2 2752
2753 cgiEndHTML();
2754}
2755
2756
fa73b229 2757/*
323c5de1 2758 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
fa73b229 2759 */
2760
2761static void
323c5de1 2762do_set_allowed_users(http_t *http) /* I - HTTP connection */
fa73b229 2763{
323c5de1 2764 int i; /* Looping var */
fa73b229 2765 ipp_t *request, /* IPP request */
2766 *response; /* IPP response */
323c5de1 2767 char uri[HTTP_MAX_URI]; /* Printer URI */
2768 const char *printer, /* Printer name (purge-jobs) */
2769 *is_class, /* Is a class? */
2770 *users, /* List of users or groups */
2771 *type; /* Allow/deny type */
2772 int num_users; /* Number of users */
2773 char *ptr, /* Pointer into users string */
2774 *end, /* Pointer to end of users string */
2775 quote; /* Quote character */
2776 ipp_attribute_t *attr; /* Attribute */
2777 static const char * const attrs[] = /* Requested attributes */
2778 {
2779 "requesting-user-name-allowed",
2780 "requesting-user-name-denied"
2781 };
fa73b229 2782
fa73b229 2783
323c5de1 2784 is_class = cgiGetVariable("IS_CLASS");
2785 printer = cgiGetVariable("PRINTER_NAME");
fa73b229 2786
323c5de1 2787 if (!printer)
2788 {
2789 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2790 cgiStartHTML(cgiText(_("Set Allowed Users")));
2791 cgiCopyTemplateLang("error.tmpl");
2792 cgiEndHTML();
2793 return;
2794 }
ef416fc2 2795
323c5de1 2796 users = cgiGetVariable("users");
2797 type = cgiGetVariable("type");
ef416fc2 2798
323c5de1 2799 if (!users || !type ||
2800 (strcmp(type, "requesting-user-name-allowed") &&
2801 strcmp(type, "requesting-user-name-denied")))
2802 {
2803 /*
2804 * Build a Get-Printer-Attributes request, which requires the following
2805 * attributes:
2806 *
2807 * attributes-charset
2808 * attributes-natural-language
2809 * printer-uri
2810 * requested-attributes
2811 */
fa73b229 2812
323c5de1 2813 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
fa73b229 2814
323c5de1 2815 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2816 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2817 printer);
2818 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2819 NULL, uri);
fa73b229 2820
323c5de1 2821 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2822 "requested-attributes",
2823 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
fa73b229 2824
323c5de1 2825 /*
2826 * Do the request and get back a response...
2827 */
fa73b229 2828
323c5de1 2829 if ((response = cupsDoRequest(http, request, "/")) != NULL)
fa73b229 2830 {
323c5de1 2831 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
fa73b229 2832
323c5de1 2833 ippDelete(response);
fa73b229 2834 }
ef416fc2 2835
323c5de1 2836 cgiStartHTML(cgiText(_("Set Allowed Users")));
757d2cad 2837
355e94dc
MS
2838 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2839 {
2840 puts("Status: 401\n");
2841 exit(0);
2842 }
2843 else if (cupsLastError() > IPP_OK_CONFLICT)
323c5de1 2844 cgiShowIPPError(_("Unable to get printer attributes:"));
2845 else
2846 cgiCopyTemplateLang("users.tmpl");
2847
2848 cgiEndHTML();
2849 }
2850 else
757d2cad 2851 {
2852 /*
323c5de1 2853 * Save the changes...
757d2cad 2854 */
2855
323c5de1 2856 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
757d2cad 2857 {
323c5de1 2858 /*
2859 * Skip whitespace and commas...
2860 */
fa73b229 2861
323c5de1 2862 while (*ptr == ',' || isspace(*ptr & 255))
2863 ptr ++;
ef416fc2 2864
1f6f3dbc
MS
2865 if (!*ptr)
2866 break;
2867
323c5de1 2868 if (*ptr == '\'' || *ptr == '\"')
2869 {
2870 /*
2871 * Scan quoted name...
2872 */
ef416fc2 2873
323c5de1 2874 quote = *ptr++;
ef416fc2 2875
323c5de1 2876 for (end = ptr; *end; end ++)
2877 if (*end == quote)
2878 break;
2879 }
2880 else
2881 {
2882 /*
2883 * Scan space or comma-delimited name...
2884 */
ef416fc2 2885
323c5de1 2886 for (end = ptr; *end; end ++)
2887 if (isspace(*end & 255) || *end == ',')
2888 break;
2889 }
ef416fc2 2890
323c5de1 2891 /*
2892 * Advance to the next name...
2893 */
ef416fc2 2894
323c5de1 2895 ptr = end;
2896 }
ef416fc2 2897
323c5de1 2898 /*
2899 * Build a CUPS-Add-Printer/Class request, which requires the following
2900 * attributes:
2901 *
2902 * attributes-charset
2903 * attributes-natural-language
2904 * printer-uri
2905 * requesting-user-name-{allowed,denied}
2906 */
ef416fc2 2907
323c5de1 2908 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 2909
323c5de1 2910 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2911 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2912 printer);
2913 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2914 NULL, uri);
f7deaa1a 2915
323c5de1 2916 if (num_users == 0)
2917 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2918 "requesting-user-name-allowed", NULL, "all");
2919 else
2920 {
2921 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2922 type, num_users, NULL, NULL);
ef416fc2 2923
323c5de1 2924 for (i = 0, ptr = (char *)users; *ptr; i ++)
2925 {
2926 /*
2927 * Skip whitespace and commas...
2928 */
ef416fc2 2929
323c5de1 2930 while (*ptr == ',' || isspace(*ptr & 255))
2931 ptr ++;
ef416fc2 2932
1f6f3dbc
MS
2933 if (!*ptr)
2934 break;
2935
323c5de1 2936 if (*ptr == '\'' || *ptr == '\"')
2937 {
2938 /*
2939 * Scan quoted name...
2940 */
7594b224 2941
323c5de1 2942 quote = *ptr++;
7594b224 2943
323c5de1 2944 for (end = ptr; *end; end ++)
2945 if (*end == quote)
2946 break;
2947 }
2948 else
2949 {
2950 /*
2951 * Scan space or comma-delimited name...
2952 */
480ef0fe 2953
323c5de1 2954 for (end = ptr; *end; end ++)
2955 if (isspace(*end & 255) || *end == ',')
2956 break;
2957 }
ef416fc2 2958
323c5de1 2959 /*
2960 * Terminate the name...
2961 */
ef416fc2 2962
323c5de1 2963 if (*end)
2964 *end++ = '\0';
ef416fc2 2965
323c5de1 2966 /*
2967 * Add the name...
2968 */
ef416fc2 2969
323c5de1 2970 attr->values[i].string.text = strdup(ptr);
ef416fc2 2971
323c5de1 2972 /*
2973 * Advance to the next name...
2974 */
ef416fc2 2975
323c5de1 2976 ptr = end;
2977 }
2978 }
ef416fc2 2979
2980 /*
323c5de1 2981 * Do the request and get back a response...
ef416fc2 2982 */
2983
323c5de1 2984 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 2985
355e94dc
MS
2986 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2987 {
2988 puts("Status: 401\n");
2989 exit(0);
2990 }
2991 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 2992 {
323c5de1 2993 cgiStartHTML(cgiText(_("Set Allowed Users")));
2994 cgiShowIPPError(_("Unable to change printer:"));
ef416fc2 2995 }
323c5de1 2996 else
ef416fc2 2997 {
2998 /*
323c5de1 2999 * Redirect successful updates back to the printer page...
ef416fc2 3000 */
3001
323c5de1 3002 char url[1024], /* Printer/class URL */
3003 refresh[1024]; /* Refresh URL */
ef416fc2 3004
3005
323c5de1 3006 cgiRewriteURL(uri, url, sizeof(url), NULL);
3007 cgiFormEncode(uri, url, sizeof(uri));
3008 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
3009 uri);
3010 cgiSetVariable("refresh_page", refresh);
ef416fc2 3011
323c5de1 3012 cgiStartHTML(cgiText(_("Set Allowed Users")));
ef416fc2 3013
323c5de1 3014 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3015 "printer-modified.tmpl");
3016 }
ef416fc2 3017
323c5de1 3018 cgiEndHTML();
3019 }
3020}
ef416fc2 3021
ef416fc2 3022
58dc1933
MS
3023/*
3024 * 'do_set_default()' - Set the server default printer/class.
3025 */
3026
3027static void
3028do_set_default(http_t *http) /* I - HTTP connection */
3029{
3030 const char *title; /* Page title */
3031 ipp_t *request; /* IPP request */
3032 char uri[HTTP_MAX_URI]; /* Printer URI */
3033 const char *printer, /* Printer name (purge-jobs) */
3034 *is_class; /* Is a class? */
3035
3036
3037 is_class = cgiGetVariable("IS_CLASS");
3038 printer = cgiGetVariable("PRINTER_NAME");
3039 title = cgiText(_("Set As Server Default"));
3040
3041 if (!printer)
3042 {
3043 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3044 cgiStartHTML(title);
3045 cgiCopyTemplateLang("error.tmpl");
3046 cgiEndHTML();
3047 return;
3048 }
3049
3050 /*
3051 * Build a printer request, which requires the following
3052 * attributes:
3053 *
3054 * attributes-charset
3055 * attributes-natural-language
3056 * printer-uri
3057 */
3058
3059 request = ippNewRequest(CUPS_SET_DEFAULT);
3060
3061 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3062 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3063 printer);
3064 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3065 NULL, uri);
3066
3067 /*
3068 * Do the request and get back a response...
3069 */
3070
3071 ippDelete(cupsDoRequest(http, request, "/admin/"));
3072
3073 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3074 {
3075 puts("Status: 401\n");
3076 exit(0);
3077 }
3078 else if (cupsLastError() > IPP_OK_CONFLICT)
3079 {
3080 cgiStartHTML(title);
3081 cgiShowIPPError(_("Unable to set server default:"));
3082 }
3083 else
3084 {
3085 /*
3086 * Redirect successful updates back to the printer page...
3087 */
3088
3089 char url[1024], /* Printer/class URL */
3090 refresh[1024]; /* Refresh URL */
3091
3092
3093 cgiRewriteURL(uri, url, sizeof(url), NULL);
3094 cgiFormEncode(uri, url, sizeof(uri));
3095 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3096 cgiSetVariable("refresh_page", refresh);
3097
3098 cgiStartHTML(title);
3099 cgiCopyTemplateLang("printer-default.tmpl");
3100 }
3101
3102 cgiEndHTML();
3103}
3104
3105
323c5de1 3106/*
3107 * 'do_set_options()' - Configure the default options for a queue.
3108 */
ef416fc2 3109
323c5de1 3110static void
3111do_set_options(http_t *http, /* I - HTTP connection */
3112 int is_class) /* I - Set options for class? */
3113{
3114 int i, j, k, m; /* Looping vars */
3115 int have_options; /* Have options? */
3116 ipp_t *request, /* IPP request */
3117 *response; /* IPP response */
3118 ipp_attribute_t *attr; /* IPP attribute */
3119 char uri[HTTP_MAX_URI]; /* Job URI */
3120 const char *var; /* Variable value */
3121 const char *printer; /* Printer printer name */
3122 const char *filename; /* PPD filename */
3123 char tempfile[1024]; /* Temporary filename */
3124 cups_file_t *in, /* Input file */
3125 *out; /* Output file */
749b1e90
MS
3126 char line[1024], /* Line from PPD file */
3127 value[1024], /* Option value */
3128 keyword[1024], /* Keyword from Default line */
323c5de1 3129 *keyptr; /* Pointer into keyword... */
3130 ppd_file_t *ppd; /* PPD file */
3131 ppd_group_t *group; /* Option group */
3132 ppd_option_t *option; /* Option */
749b1e90
MS
3133 ppd_coption_t *coption; /* Custom option */
3134 ppd_cparam_t *cparam; /* Custom parameter */
1f6f3dbc 3135 ppd_attr_t *ppdattr; /* PPD attribute */
323c5de1 3136 const char *title; /* Page title */
ef416fc2 3137
ef416fc2 3138
323c5de1 3139 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
ef416fc2 3140
323c5de1 3141 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
3142 is_class);
ef416fc2 3143
323c5de1 3144 /*
3145 * Get the printer name...
3146 */
ef416fc2 3147
323c5de1 3148 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
3149 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3150 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3151 printer);
3152 else
3153 {
3154 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3155 cgiStartHTML(title);
3156 cgiCopyTemplateLang("error.tmpl");
3157 cgiEndHTML();
3158 return;
3159 }
ef416fc2 3160
323c5de1 3161 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
ef416fc2 3162
1f6f3dbc
MS
3163 /*
3164 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3165 * command file to the printer...
3166 */
3167
3168 if (cgiGetVariable("AUTOCONFIGURE"))
3169 {
58dc1933 3170 cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
1f6f3dbc
MS
3171 return;
3172 }
3173
323c5de1 3174 /*
3175 * Get the PPD file...
3176 */
ef416fc2 3177
323c5de1 3178 if (is_class)
3179 filename = NULL;
3180 else
3181 filename = cupsGetPPD2(http, printer);
ef416fc2 3182
323c5de1 3183 if (filename)
3184 {
3185 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
ef416fc2 3186
323c5de1 3187 if ((ppd = ppdOpenFile(filename)) == NULL)
3188 {
3189 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
3190 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3191 cgiStartHTML(title);
3192 cgiCopyTemplateLang("error.tmpl");
3193 cgiEndHTML();
3194 return;
3195 }
3196 }
3197 else
3198 {
3199 fputs("DEBUG: No PPD file\n", stderr);
3200 ppd = NULL;
3201 }
ef416fc2 3202
323c5de1 3203 if (cgiGetVariable("job_sheets_start") != NULL ||
3204 cgiGetVariable("job_sheets_end") != NULL)
3205 have_options = 1;
3206 else
3207 have_options = 0;
ef416fc2 3208
323c5de1 3209 if (ppd)
3210 {
3211 ppdMarkDefaults(ppd);
ef416fc2 3212
749b1e90
MS
3213 for (option = ppdFirstOption(ppd);
3214 option;
3215 option = ppdNextOption(ppd))
3216 if ((var = cgiGetVariable(option->keyword)) != NULL)
3217 {
3218 have_options = 1;
3219 ppdMarkOption(ppd, option->keyword, var);
3220 }
323c5de1 3221 }
fa73b229 3222
323c5de1 3223 if (!have_options || ppdConflicts(ppd))
fa73b229 3224 {
3225 /*
323c5de1 3226 * Show the options to the user...
fa73b229 3227 */
3228
323c5de1 3229 fputs("DEBUG: Showing options...\n", stderr);
fa73b229 3230
58dc1933
MS
3231 /*
3232 * Show auto-configure button if supported...
3233 */
3234
1f6f3dbc
MS
3235 if (ppd)
3236 {
3237 if (ppd->num_filters == 0 ||
3238 ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
3239 ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
3240 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3241 else
3242 {
3243 for (i = 0; i < ppd->num_filters; i ++)
3244 if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
3245 {
3246 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3247 break;
3248 }
3249 }
3250 }
3251
58dc1933
MS
3252 /*
3253 * Get the printer attributes...
3254 */
3255
3256 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
3257
3258 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3259 "localhost", 0, "/printers/%s", printer);
3260 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3261 NULL, uri);
3262
3263 response = cupsDoRequest(http, request, "/");
3264
3265 /*
3266 * List the groups used as "tabs"...
3267 */
3268
3269 i = 0;
3270
3271 if (ppd)
3272 {
3273 for (group = ppd->groups;
3274 i < ppd->num_groups;
3275 i ++, group ++)
3276 {
3277 cgiSetArray("GROUP_ID", i, group->name);
3278
3279 if (!strcmp(group->name, "InstallableOptions"))
3280 cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
3281 else
3282 cgiSetArray("GROUP", i, group->text);
3283 }
3284 }
3285
3286 if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
3287 {
3288 cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
3289 cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
3290 }
3291
3292 if (ippFindAttribute(response, "printer-error-policy-supported",
3293 IPP_TAG_ZERO) ||
3294 ippFindAttribute(response, "printer-op-policy-supported",
3295 IPP_TAG_ZERO))
3296 {
3297 cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
3298 cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
3299 }
3300
3301 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3302 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
3303 {
3304 cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
3305 cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
3306 }
3307
323c5de1 3308 cgiStartHTML(cgiText(_("Set Printer Options")));
3309 cgiCopyTemplateLang("set-printer-options-header.tmpl");
fa73b229 3310
323c5de1 3311 if (ppd)
3312 {
3313 ppdLocalize(ppd);
f7deaa1a 3314
323c5de1 3315 if (ppdConflicts(ppd))
3316 {
3317 for (i = ppd->num_groups, k = 0, group = ppd->groups;
3318 i > 0;
3319 i --, group ++)
3320 for (j = group->num_options, option = group->options;
3321 j > 0;
3322 j --, option ++)
3323 if (option->conflicted)
3324 {
3325 cgiSetArray("ckeyword", k, option->keyword);
3326 cgiSetArray("ckeytext", k, option->text);
3327 k ++;
3328 }
f7deaa1a 3329
323c5de1 3330 cgiCopyTemplateLang("option-conflict.tmpl");
3331 }
f7deaa1a 3332
323c5de1 3333 for (i = ppd->num_groups, group = ppd->groups;
3334 i > 0;
3335 i --, group ++)
3336 {
58dc1933
MS
3337 cgiSetVariable("GROUP_ID", group->name);
3338
323c5de1 3339 if (!strcmp(group->name, "InstallableOptions"))
3340 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3341 else
3342 cgiSetVariable("GROUP", group->text);
f7deaa1a 3343
323c5de1 3344 cgiCopyTemplateLang("option-header.tmpl");
3345
3346 for (j = group->num_options, option = group->options;
3347 j > 0;
3348 j --, option ++)
3349 {
3350 if (!strcmp(option->keyword, "PageRegion"))
3351 continue;
ef416fc2 3352
323c5de1 3353 cgiSetVariable("KEYWORD", option->keyword);
3354 cgiSetVariable("KEYTEXT", option->text);
749b1e90 3355
323c5de1 3356 if (option->conflicted)
3357 cgiSetVariable("CONFLICTED", "1");
3358 else
3359 cgiSetVariable("CONFLICTED", "0");
3360
3361 cgiSetSize("CHOICES", 0);
3362 cgiSetSize("TEXT", 0);
3363 for (k = 0, m = 0; k < option->num_choices; k ++)
3364 {
323c5de1 3365 cgiSetArray("CHOICES", m, option->choices[k].choice);
3366 cgiSetArray("TEXT", m, option->choices[k].text);
ef416fc2 3367
323c5de1 3368 m ++;
ef416fc2 3369
323c5de1 3370 if (option->choices[k].marked)
3371 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
3372 }
ef416fc2 3373
749b1e90
MS
3374 cgiSetSize("PARAMS", 0);
3375 cgiSetSize("PARAMTEXT", 0);
3376 cgiSetSize("PARAMVALUE", 0);
3377 cgiSetSize("INPUTTYPE", 0);
3378
3379 if ((coption = ppdFindCustomOption(ppd, option->keyword)))
3380 {
3381 const char *units = NULL; /* Units value, if any */
3382
3383
3384 cgiSetVariable("ISCUSTOM", "1");
3385
3386 for (cparam = ppdFirstCustomParam(coption), m = 0;
3387 cparam;
3388 cparam = ppdNextCustomParam(coption), m ++)
3389 {
3390 if (!strcasecmp(option->keyword, "PageSize") &&
3391 strcasecmp(cparam->name, "Width") &&
3392 strcasecmp(cparam->name, "Height"))
3393 {
3394 m --;
3395 continue;
3396 }
3397
3398 cgiSetArray("PARAMS", m, cparam->name);
3399 cgiSetArray("PARAMTEXT", m, cparam->text);
3400 cgiSetArray("INPUTTYPE", m, "text");
3401
3402 switch (cparam->type)
3403 {
3404 case PPD_CUSTOM_POINTS :
3405 if (!strncasecmp(option->defchoice, "Custom.", 7))
3406 {
3407 units = option->defchoice + strlen(option->defchoice) - 2;
3408
3409 if (strcmp(units, "mm") && strcmp(units, "cm") &&
3410 strcmp(units, "in") && strcmp(units, "ft"))
3411 {
3412 if (units[1] == 'm')
3413 units ++;
3414 else
3415 units = "pt";
3416 }
3417 }
3418 else
3419 units = "pt";
3420
3421 if (!strcmp(units, "mm"))
3422 snprintf(value, sizeof(value), "%g",
3423 cparam->current.custom_points / 72.0 * 25.4);
3424 else if (!strcmp(units, "cm"))
3425 snprintf(value, sizeof(value), "%g",
3426 cparam->current.custom_points / 72.0 * 2.54);
3427 else if (!strcmp(units, "in"))
3428 snprintf(value, sizeof(value), "%g",
3429 cparam->current.custom_points / 72.0);
3430 else if (!strcmp(units, "ft"))
3431 snprintf(value, sizeof(value), "%g",
3432 cparam->current.custom_points / 72.0 / 12.0);
3433 else if (!strcmp(units, "m"))
3434 snprintf(value, sizeof(value), "%g",
3435 cparam->current.custom_points / 72.0 * 0.0254);
3436 else
3437 snprintf(value, sizeof(value), "%g",
3438 cparam->current.custom_points);
3439 cgiSetArray("PARAMVALUE", m, value);
3440 break;
3441
3442 case PPD_CUSTOM_CURVE :
3443 case PPD_CUSTOM_INVCURVE :
3444 case PPD_CUSTOM_REAL :
3445 snprintf(value, sizeof(value), "%g",
3446 cparam->current.custom_real);
3447 cgiSetArray("PARAMVALUE", m, value);
3448 break;
3449
3450 case PPD_CUSTOM_INT:
3451 snprintf(value, sizeof(value), "%d",
3452 cparam->current.custom_int);
3453 cgiSetArray("PARAMVALUE", m, value);
3454 break;
3455
3456 case PPD_CUSTOM_PASSCODE:
3457 case PPD_CUSTOM_PASSWORD:
3458 if (cparam->current.custom_password)
3459 cgiSetArray("PARAMVALUE", m,
3460 cparam->current.custom_password);
3461 else
3462 cgiSetArray("PARAMVALUE", m, "");
3463 cgiSetArray("INPUTTYPE", m, "password");
3464 break;
3465
3466 case PPD_CUSTOM_STRING:
3467 if (cparam->current.custom_string)
3468 cgiSetArray("PARAMVALUE", m,
3469 cparam->current.custom_string);
3470 else
3471 cgiSetArray("PARAMVALUE", m, "");
3472 break;
3473 }
3474 }
3475
3476 if (units)
3477 {
3478 cgiSetArray("PARAMS", m, "Units");
3479 cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
3480 cgiSetArray("PARAMVALUE", m, units);
3481 }
3482 }
3483 else
3484 cgiSetVariable("ISCUSTOM", "0");
3485
323c5de1 3486 switch (option->ui)
3487 {
3488 case PPD_UI_BOOLEAN :
3489 cgiCopyTemplateLang("option-boolean.tmpl");
3490 break;
3491 case PPD_UI_PICKONE :
3492 cgiCopyTemplateLang("option-pickone.tmpl");
3493 break;
3494 case PPD_UI_PICKMANY :
3495 cgiCopyTemplateLang("option-pickmany.tmpl");
3496 break;
3497 }
3498 }
ef416fc2 3499
323c5de1 3500 cgiCopyTemplateLang("option-trailer.tmpl");
3501 }
3502 }
ef416fc2 3503
58dc1933
MS
3504 if ((attr = ippFindAttribute(response, "job-sheets-supported",
3505 IPP_TAG_ZERO)) != NULL)
3506 {
3507 /*
3508 * Add the job sheets options...
3509 */
fa73b229 3510
58dc1933
MS
3511 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3512 cgiSetVariable("GROUP", cgiText(_("Banners")));
3513 cgiCopyTemplateLang("option-header.tmpl");
ef416fc2 3514
58dc1933
MS
3515 cgiSetSize("CHOICES", attr->num_values);
3516 cgiSetSize("TEXT", attr->num_values);
3517 for (k = 0; k < attr->num_values; k ++)
3518 {
3519 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3520 cgiSetArray("TEXT", k, attr->values[k].string.text);
3521 }
ef416fc2 3522
58dc1933 3523 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
ef416fc2 3524
58dc1933
MS
3525 cgiSetVariable("KEYWORD", "job_sheets_start");
3526 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3527 cgiSetVariable("DEFCHOICE", attr != NULL ?
3528 attr->values[0].string.text : "");
3529
3530 cgiCopyTemplateLang("option-pickone.tmpl");
3531
3532 cgiSetVariable("KEYWORD", "job_sheets_end");
3533 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3534 cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
3535 attr->values[1].string.text : "");
3536
3537 cgiCopyTemplateLang("option-pickone.tmpl");
3538
3539 cgiCopyTemplateLang("option-trailer.tmpl");
3540 }
3541
3542 if (ippFindAttribute(response, "printer-error-policy-supported",
3543 IPP_TAG_ZERO) ||
3544 ippFindAttribute(response, "printer-op-policy-supported",
3545 IPP_TAG_ZERO))
323c5de1 3546 {
58dc1933
MS
3547 /*
3548 * Add the error and operation policy options...
3549 */
ef416fc2 3550
58dc1933
MS
3551 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3552 cgiSetVariable("GROUP", cgiText(_("Policies")));
3553 cgiCopyTemplateLang("option-header.tmpl");
3554
3555 /*
3556 * Error policy...
3557 */
ef416fc2 3558
58dc1933
MS
3559 attr = ippFindAttribute(response, "printer-error-policy-supported",
3560 IPP_TAG_ZERO);
3561
3562 if (attr)
3563 {
323c5de1 3564 cgiSetSize("CHOICES", attr->num_values);
3565 cgiSetSize("TEXT", attr->num_values);
3566 for (k = 0; k < attr->num_values; k ++)
3567 {
3568 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3569 cgiSetArray("TEXT", k, attr->values[k].string.text);
3570 }
ef416fc2 3571
58dc1933
MS
3572 attr = ippFindAttribute(response, "printer-error-policy",
3573 IPP_TAG_ZERO);
ef416fc2 3574
58dc1933
MS
3575 cgiSetVariable("KEYWORD", "printer_error_policy");
3576 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3577 cgiSetVariable("DEFCHOICE", attr == NULL ?
3578 "" : attr->values[0].string.text);
323c5de1 3579 }
ef416fc2 3580
58dc1933 3581 cgiCopyTemplateLang("option-pickone.tmpl");
ef416fc2 3582
58dc1933
MS
3583 /*
3584 * Operation policy...
3585 */
ef416fc2 3586
58dc1933
MS
3587 attr = ippFindAttribute(response, "printer-op-policy-supported",
3588 IPP_TAG_ZERO);
323c5de1 3589
58dc1933
MS
3590 if (attr)
3591 {
3592 cgiSetSize("CHOICES", attr->num_values);
3593 cgiSetSize("TEXT", attr->num_values);
3594 for (k = 0; k < attr->num_values; k ++)
323c5de1 3595 {
58dc1933
MS
3596 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3597 cgiSetArray("TEXT", k, attr->values[k].string.text);
3598 }
ef416fc2 3599
58dc1933 3600 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
ef416fc2 3601
58dc1933
MS
3602 cgiSetVariable("KEYWORD", "printer_op_policy");
3603 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3604 cgiSetVariable("DEFCHOICE", attr == NULL ?
3605 "" : attr->values[0].string.text);
fa73b229 3606
323c5de1 3607 cgiCopyTemplateLang("option-pickone.tmpl");
323c5de1 3608 }
ef416fc2 3609
58dc1933 3610 cgiCopyTemplateLang("option-trailer.tmpl");
ef416fc2 3611 }
ef416fc2 3612
ef416fc2 3613 /*
323c5de1 3614 * Binary protocol support...
ef416fc2 3615 */
3616
58dc1933
MS
3617 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3618 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
ef416fc2 3619 {
58dc1933
MS
3620 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3621 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
ef416fc2 3622
58dc1933
MS
3623 cgiSetSize("CHOICES", attr->num_values);
3624 cgiSetSize("TEXT", attr->num_values);
ef416fc2 3625
58dc1933 3626 for (i = 0; i < attr->num_values; i ++)
ef416fc2 3627 {
58dc1933
MS
3628 cgiSetArray("CHOICES", i, attr->values[i].string.text);
3629 cgiSetArray("TEXT", i, attr->values[i].string.text);
ef416fc2 3630 }
3631
58dc1933
MS
3632 attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
3633 cgiSetVariable("KEYWORD", "port_monitor");
3634 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3635 cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
ef416fc2 3636
58dc1933 3637 cgiCopyTemplateLang("option-header.tmpl");
323c5de1 3638 cgiCopyTemplateLang("option-pickone.tmpl");
323c5de1 3639 cgiCopyTemplateLang("option-trailer.tmpl");
ef416fc2 3640 }
3641
323c5de1 3642 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3643 cgiEndHTML();
58dc1933
MS
3644
3645 ippDelete(response);
323c5de1 3646 }
3647 else
3648 {
ef416fc2 3649 /*
323c5de1 3650 * Set default options...
ef416fc2 3651 */
3652
323c5de1 3653 fputs("DEBUG: Setting options...\n", stderr);
ef416fc2 3654
323c5de1 3655 if (filename)
ef416fc2 3656 {
323c5de1 3657 out = cupsTempFile2(tempfile, sizeof(tempfile));
3658 in = cupsFileOpen(filename, "r");
ef416fc2 3659
323c5de1 3660 if (!in || !out)
ef416fc2 3661 {
323c5de1 3662 cgiSetVariable("ERROR", strerror(errno));
3663 cgiStartHTML(cgiText(_("Set Printer Options")));
3664 cgiCopyTemplateLang("error.tmpl");
3665 cgiEndHTML();
ef416fc2 3666
323c5de1 3667 if (in)
3668 cupsFileClose(in);
ef416fc2 3669
323c5de1 3670 if (out)
ef416fc2 3671 {
323c5de1 3672 cupsFileClose(out);
3673 unlink(tempfile);
3674 }
ef416fc2 3675
323c5de1 3676 unlink(filename);
3677 return;
3678 }
ef416fc2 3679
323c5de1 3680 while (cupsFileGets(in, line, sizeof(line)))
3681 {
58dc1933 3682 if (!strncmp(line, "*cupsProtocol:", 14))
323c5de1 3683 continue;
3684 else if (strncmp(line, "*Default", 8))
3685 cupsFilePrintf(out, "%s\n", line);
ef416fc2 3686 else
3687 {
3688 /*
323c5de1 3689 * Get default option name...
ef416fc2 3690 */
3691
323c5de1 3692 strlcpy(keyword, line + 8, sizeof(keyword));
3693
3694 for (keyptr = keyword; *keyptr; keyptr ++)
3695 if (*keyptr == ':' || isspace(*keyptr & 255))
ef416fc2 3696 break;
ef416fc2 3697
323c5de1 3698 *keyptr = '\0';
ef416fc2 3699
323c5de1 3700 if (!strcmp(keyword, "PageRegion") ||
3701 !strcmp(keyword, "PaperDimension") ||
3702 !strcmp(keyword, "ImageableArea"))
749b1e90 3703 var = get_option_value(ppd, "PageSize", value, sizeof(value));
323c5de1 3704 else
749b1e90 3705 var = get_option_value(ppd, keyword, value, sizeof(value));
ef416fc2 3706
749b1e90 3707 if (!var)
323c5de1 3708 cupsFilePrintf(out, "%s\n", line);
749b1e90
MS
3709 else
3710 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
323c5de1 3711 }
3712 }
ef416fc2 3713
323c5de1 3714 cupsFileClose(in);
3715 cupsFileClose(out);
3716 }
3717 else
3718 {
3719 /*
3720 * Make sure temporary filename is cleared when there is no PPD...
3721 */
ef416fc2 3722
323c5de1 3723 tempfile[0] = '\0';
ef416fc2 3724 }
3725
323c5de1 3726 /*
3727 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3728 * following attributes:
3729 *
3730 * attributes-charset
3731 * attributes-natural-language
3732 * printer-uri
3733 * job-sheets-default
3734 * printer-error-policy
3735 * printer-op-policy
3736 * [ppd file]
3737 */
3738
3739 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3740 CUPS_ADD_MODIFY_PRINTER);
3741
3742 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3743 NULL, uri);
3744
3745 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3746 "job-sheets-default", 2, NULL, NULL);
3747 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3748 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3749
3750 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
1f0275e3
MS
3751 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3752 "printer-error-policy", NULL, var);
323c5de1 3753
3754 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
1f0275e3
MS
3755 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3756 "printer-op-policy", NULL, var);
323c5de1 3757
58dc1933
MS
3758 if ((var = cgiGetVariable("port_monitor")) != NULL)
3759 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3760 "port-monitor", NULL, var);
3761
ef416fc2 3762 /*
3763 * Do the request and get back a response...
3764 */
3765
323c5de1 3766 if (filename)
3767 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3768 else
3769 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 3770
355e94dc
MS
3771 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3772 {
3773 puts("Status: 401\n");
3774 exit(0);
3775 }
3776 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3777 {
323c5de1 3778 cgiStartHTML(title);
3779 cgiShowIPPError(_("Unable to set options:"));
ef416fc2 3780 }
3781 else
3782 {
3783 /*
3784 * Redirect successful updates back to the printer page...
3785 */
3786
323c5de1 3787 char refresh[1024]; /* Refresh URL */
ef416fc2 3788
fa73b229 3789
323c5de1 3790 cgiFormEncode(uri, printer, sizeof(uri));
3791 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3792 is_class ? "classes" : "printers", uri);
ef416fc2 3793 cgiSetVariable("refresh_page", refresh);
3794
323c5de1 3795 cgiStartHTML(title);
ef416fc2 3796
323c5de1 3797 cgiCopyTemplateLang("printer-configured.tmpl");
ef416fc2 3798 }
3799
3800 cgiEndHTML();
323c5de1 3801
3802 if (filename)
3803 unlink(tempfile);
ef416fc2 3804 }
323c5de1 3805
3806 if (filename)
3807 unlink(filename);
ef416fc2 3808}
3809
3810
3811/*
749b1e90 3812 * 'do_set_sharing()' - Set printer-is-shared value.
ef416fc2 3813 */
3814
3815static void
fa73b229 3816do_set_sharing(http_t *http) /* I - HTTP connection */
ef416fc2 3817{
3818 ipp_t *request, /* IPP request */
3819 *response; /* IPP response */
3820 char uri[HTTP_MAX_URI]; /* Printer URI */
3821 const char *printer, /* Printer name */
fa73b229 3822 *is_class, /* Is a class? */
ef416fc2 3823 *shared; /* Sharing value */
ef416fc2 3824
3825
fa73b229 3826 is_class = cgiGetVariable("IS_CLASS");
3827 printer = cgiGetVariable("PRINTER_NAME");
3828 shared = cgiGetVariable("SHARED");
ef416fc2 3829
fa73b229 3830 if (!printer || !shared)
ef416fc2 3831 {
fa73b229 3832 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3833 cgiStartHTML(cgiText(_("Set Publishing")));
ef416fc2 3834 cgiCopyTemplateLang("error.tmpl");
3835 cgiEndHTML();
3836 return;
3837 }
3838
3839 /*
fa73b229 3840 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3841 * following attributes:
ef416fc2 3842 *
3843 * attributes-charset
3844 * attributes-natural-language
3845 * printer-uri
3846 * printer-is-shared
3847 */
3848
fa73b229 3849 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 3850
a4d04587 3851 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3852 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3853 printer);
ef416fc2 3854 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3855 NULL, uri);
3856
3857 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3858
3859 /*
3860 * Do the request and get back a response...
3861 */
3862
3863 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3864 {
ef416fc2 3865 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3866
3867 ippDelete(response);
3868 }
ef416fc2 3869
355e94dc
MS
3870 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3871 {
3872 puts("Status: 401\n");
3873 exit(0);
3874 }
3875 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3876 {
fa73b229 3877 cgiStartHTML(cgiText(_("Set Publishing")));
3878 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
ef416fc2 3879 }
3880 else
3881 {
3882 /*
3883 * Redirect successful updates back to the printer page...
3884 */
3885
fa73b229 3886 char url[1024], /* Printer/class URL */
3887 refresh[1024]; /* Refresh URL */
ef416fc2 3888
ef416fc2 3889
fa73b229 3890 cgiRewriteURL(uri, url, sizeof(url), NULL);
3891 cgiFormEncode(uri, url, sizeof(uri));
f301802f 3892 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
fa73b229 3893 cgiSetVariable("refresh_page", refresh);
ef416fc2 3894
fa73b229 3895 cgiStartHTML(cgiText(_("Set Publishing")));
3896 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3897 "printer-modified.tmpl");
ef416fc2 3898 }
3899
3900 cgiEndHTML();
3901}
3902
3903
749b1e90
MS
3904/*
3905 * 'get_option_value()' - Return the value of an option.
3906 *
3907 * This function also handles generation of custom option values.
3908 */
3909
3910static char * /* O - Value string or NULL on error */
3911get_option_value(
3912 ppd_file_t *ppd, /* I - PPD file */
3913 const char *name, /* I - Option name */
3914 char *buffer, /* I - String buffer */
3915 size_t bufsize) /* I - Size of buffer */
3916{
3917 char *bufptr, /* Pointer into buffer */
3918 *bufend; /* End of buffer */
3919 ppd_coption_t *coption; /* Custom option */
3920 ppd_cparam_t *cparam; /* Current custom parameter */
3921 char keyword[256]; /* Parameter name */
3922 const char *val, /* Parameter value */
3923 *uval; /* Units value */
3924 long integer; /* Integer value */
3925 double number, /* Number value */
3926 number_points; /* Number in points */
3927
3928
3929 /*
3930 * See if we have a custom option choice...
3931 */
3932
3933 if ((val = cgiGetVariable(name)) == NULL)
3934 {
3935 /*
3936 * Option not found!
3937 */
3938
3939 return (NULL);
3940 }
3941 else if (strcasecmp(val, "Custom") ||
3942 (coption = ppdFindCustomOption(ppd, name)) == NULL)
3943 {
3944 /*
3945 * Not a custom choice...
3946 */
3947
3948 strlcpy(buffer, val, bufsize);
3949 return (buffer);
3950 }
3951
3952 /*
3953 * OK, we have a custom option choice, format it...
3954 */
3955
3956 *buffer = '\0';
3957
3958 if (!strcmp(coption->keyword, "PageSize"))
3959 {
3960 const char *lval; /* Length string value */
3961 double width, /* Width value */
3962 width_points, /* Width in points */
3963 length, /* Length value */
3964 length_points; /* Length in points */
3965
3966
3967 val = cgiGetVariable("PageSize.Width");
3968 lval = cgiGetVariable("PageSize.Height");
3969 uval = cgiGetVariable("PageSize.Units");
3970
3971 if (!val || !lval || !uval ||
3972 (width = strtod(val, NULL)) == 0.0 ||
3973 (length = strtod(lval, NULL)) == 0.0 ||
3974 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3975 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3976 return (NULL);
3977
3978 width_points = get_points(width, uval);
3979 length_points = get_points(length, uval);
3980
3981 if (width_points < ppd->custom_min[0] ||
3982 width_points > ppd->custom_max[0] ||
3983 length_points < ppd->custom_min[1] ||
3984 length_points > ppd->custom_max[1])
3985 return (NULL);
3986
3987 snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
3988 }
3989 else if (cupsArrayCount(coption->params) == 1)
3990 {
3991 cparam = ppdFirstCustomParam(coption);
3992 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
3993
3994 if ((val = cgiGetVariable(keyword)) == NULL)
3995 return (NULL);
3996
3997 switch (cparam->type)
3998 {
3999 case PPD_CUSTOM_CURVE :
4000 case PPD_CUSTOM_INVCURVE :
4001 case PPD_CUSTOM_REAL :
4002 if ((number = strtod(val, NULL)) == 0.0 ||
4003 number < cparam->minimum.custom_real ||
4004 number > cparam->maximum.custom_real)
4005 return (NULL);
4006
4007 snprintf(buffer, bufsize, "Custom.%g", number);
4008 break;
4009
4010 case PPD_CUSTOM_INT :
4011 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4012 integer == LONG_MAX ||
4013 integer < cparam->minimum.custom_int ||
4014 integer > cparam->maximum.custom_int)
4015 return (NULL);
4016
4017 snprintf(buffer, bufsize, "Custom.%ld", integer);
4018 break;
4019
4020 case PPD_CUSTOM_POINTS :
4021 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4022
4023 if ((number = strtod(val, NULL)) == 0.0 ||
4024 (uval = cgiGetVariable(keyword)) == NULL ||
4025 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
4026 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
4027 return (NULL);
4028
4029 number_points = get_points(number, uval);
4030 if (number_points < cparam->minimum.custom_points ||
4031 number_points > cparam->maximum.custom_points)
4032 return (NULL);
4033
4034 snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
4035 break;
4036
4037 case PPD_CUSTOM_PASSCODE :
4038 for (uval = val; *uval; uval ++)
4039 if (!isdigit(*uval & 255))
4040 return (NULL);
4041
4042 case PPD_CUSTOM_PASSWORD :
4043 case PPD_CUSTOM_STRING :
4044 integer = (long)strlen(val);
4045 if (integer < cparam->minimum.custom_string ||
4046 integer > cparam->maximum.custom_string)
4047 return (NULL);
4048
4049 snprintf(buffer, bufsize, "Custom.%s", val);
4050 break;
4051 }
4052 }
4053 else
4054 {
4055 const char *prefix = "{"; /* Prefix string */
4056
4057
4058 bufptr = buffer;
4059 bufend = buffer + bufsize;
4060
4061 for (cparam = ppdFirstCustomParam(coption);
4062 cparam;
4063 cparam = ppdNextCustomParam(coption))
4064 {
4065 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
4066 cparam->name);
4067
4068 if ((val = cgiGetVariable(keyword)) == NULL)
4069 return (NULL);
4070
4071 snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
4072 bufptr += strlen(bufptr);
4073 prefix = " ";
4074
4075 switch (cparam->type)
4076 {
4077 case PPD_CUSTOM_CURVE :
4078 case PPD_CUSTOM_INVCURVE :
4079 case PPD_CUSTOM_REAL :
4080 if ((number = strtod(val, NULL)) == 0.0 ||
4081 number < cparam->minimum.custom_real ||
4082 number > cparam->maximum.custom_real)
4083 return (NULL);
4084
4085 snprintf(bufptr, bufend - bufptr, "%g", number);
4086 break;
4087
4088 case PPD_CUSTOM_INT :
4089 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4090 integer == LONG_MAX ||
4091 integer < cparam->minimum.custom_int ||
4092 integer > cparam->maximum.custom_int)
4093 return (NULL);
4094
4095 snprintf(bufptr, bufend - bufptr, "%ld", integer);
4096 break;
4097
4098 case PPD_CUSTOM_POINTS :
4099 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4100
4101 if ((number = strtod(val, NULL)) == 0.0 ||
4102 (uval = cgiGetVariable(keyword)) == NULL ||
4103 (strcmp(uval, "pt") && strcmp(uval, "in") &&
4104 strcmp(uval, "ft") && strcmp(uval, "cm") &&
4105 strcmp(uval, "mm") && strcmp(uval, "m")))
4106 return (NULL);
4107
4108 number_points = get_points(number, uval);
4109 if (number_points < cparam->minimum.custom_points ||
4110 number_points > cparam->maximum.custom_points)
4111 return (NULL);
4112
4113 snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
4114 break;
4115
4116 case PPD_CUSTOM_PASSCODE :
4117 for (uval = val; *uval; uval ++)
4118 if (!isdigit(*uval & 255))
4119 return (NULL);
4120
4121 case PPD_CUSTOM_PASSWORD :
4122 case PPD_CUSTOM_STRING :
4123 integer = (long)strlen(val);
4124 if (integer < cparam->minimum.custom_string ||
4125 integer > cparam->maximum.custom_string)
4126 return (NULL);
4127
4128 if ((bufptr + 2) > bufend)
4129 return (NULL);
4130
4131 bufend --;
4132 *bufptr++ = '\"';
4133
4134 while (*val && bufptr < bufend)
4135 {
4136 if (*val == '\\' || *val == '\"')
4137 {
4138 if ((bufptr + 1) >= bufend)
4139 return (NULL);
4140
4141 *bufptr++ = '\\';
4142 }
4143
4144 *bufptr++ = *val++;
4145 }
4146
4147 if (bufptr >= bufend)
4148 return (NULL);
4149
4150 *bufptr++ = '\"';
4151 *bufptr = '\0';
4152 bufend ++;
4153 break;
4154 }
4155
4156 bufptr += strlen(bufptr);
4157 }
4158
4159 if (bufptr == buffer || (bufend - bufptr) < 2)
4160 return (NULL);
4161
4162 strcpy(bufptr, "}");
4163 }
4164
4165 return (buffer);
4166}
4167
4168
4169/*
4170 * 'get_points()' - Get a value in points.
4171 */
4172
4173static double /* O - Number in points */
4174get_points(double number, /* I - Original number */
4175 const char *uval) /* I - Units */
4176{
4177 if (!strcmp(uval, "mm")) /* Millimeters */
4178 return (number * 72.0 / 25.4);
4179 else if (!strcmp(uval, "cm")) /* Centimeters */
4180 return (number * 72.0 / 2.54);
4181 else if (!strcmp(uval, "in")) /* Inches */
4182 return (number * 72.0);
4183 else if (!strcmp(uval, "ft")) /* Feet */
4184 return (number * 72.0 * 12.0);
4185 else if (!strcmp(uval, "m")) /* Meters */
4186 return (number * 72.0 / 0.0254);
4187 else /* Points */
4188 return (number);
4189}
4190
4191
ef416fc2 4192/*
58dc1933 4193 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".
ef416fc2 4194 */