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