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