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