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