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