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