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