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