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