]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/admin.c
Remove remaining references to subscriptions and samba.
[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 */
2152 char filename[1024]; /* Temporary filename */
2153 const char *datadir; /* Location of data files */
2154 ipp_t *request, /* IPP request */
2155 *response; /* IPP response */
ef416fc2 2156
2157
89d46774 2158 /*
323c5de1 2159 * Get the current server settings...
89d46774 2160 */
fa73b229 2161
323c5de1 2162 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
ef416fc2 2163 {
323c5de1 2164 cgiSetVariable("SETTINGS_MESSAGE",
2165 cgiText(_("Unable to open cupsd.conf file:")));
2166 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
ef416fc2 2167 }
2168
323c5de1 2169 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2170 settings)) != NULL && atoi(val))
2171 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
ef416fc2 2172
323c5de1 2173 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2174 settings)) != NULL && atoi(val))
2175 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
ef416fc2 2176
323c5de1 2177 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2178 settings)) != NULL && atoi(val))
2179 cgiSetVariable("REMOTE_ANY", "CHECKED");
ef416fc2 2180
323c5de1 2181 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2182 settings)) != NULL && atoi(val))
2183 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
ef416fc2 2184
323c5de1 2185 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2186 settings)) != NULL && atoi(val))
2187 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2188
2189#ifdef HAVE_GSSAPI
2190 cgiSetVariable("HAVE_GSSAPI", "1");
2191
2192 if ((val = cupsGetOption("DefaultAuthType", num_settings,
88f9aafc 2193 settings)) != NULL && !_cups_strcasecmp(val, "Negotiate"))
323c5de1 2194 cgiSetVariable("KERBEROS", "CHECKED");
ef55b745 2195 else
323c5de1 2196#endif /* HAVE_GSSAPI */
ef55b745 2197 cgiSetVariable("KERBEROS", "");
323c5de1 2198
0af14961
MS
2199 if ((val = cupsGetOption("BrowseWebIF", num_settings,
2200 settings)) == NULL)
2201 val = "No";
2202
88f9aafc
MS
2203 if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") ||
2204 !_cups_strcasecmp(val, "true"))
0af14961
MS
2205 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2206
2207 if ((val = cupsGetOption("PreserveJobHistory", num_settings,
2208 settings)) == NULL)
2209 val = "Yes";
2210
82cc1f9a
MS
2211 if (val &&
2212 (!_cups_strcasecmp(val, "0") || !_cups_strcasecmp(val, "no") ||
2213 !_cups_strcasecmp(val, "off") || !_cups_strcasecmp(val, "false") ||
2214 !_cups_strcasecmp(val, "disabled")))
0af14961 2215 {
82cc1f9a
MS
2216 cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
2217 cgiSetVariable("PRESERVE_JOB_FILES", "0");
2218 }
2219 else
2220 {
2221 cgiSetVariable("PRESERVE_JOBS", "CHECKED");
2222 cgiSetVariable("PRESERVE_JOB_HISTORY", val);
0af14961
MS
2223
2224 if ((val = cupsGetOption("PreserveJobFiles", num_settings,
2225 settings)) == NULL)
82cc1f9a
MS
2226 val = "1d";
2227
2228 cgiSetVariable("PRESERVE_JOB_FILES", val);
0af14961 2229
0af14961
MS
2230 }
2231
1f6f3dbc
MS
2232 if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
2233 val = "100";
2234
2235 cgiSetVariable("MAX_CLIENTS", val);
2236
0af14961
MS
2237 if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
2238 val = "500";
2239
2240 cgiSetVariable("MAX_JOBS", val);
2241
2242 if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
2243 val = "1m";
2244
2245 cgiSetVariable("MAX_LOG_SIZE", val);
2246
323c5de1 2247 cupsFreeOptions(num_settings, settings);
ef416fc2 2248
323c5de1 2249 /*
2250 * Finally, show the main menu template...
2251 */
2252
2253 cgiStartHTML(cgiText(_("Administration")));
2254
2255 cgiCopyTemplateLang("admin.tmpl");
ef416fc2 2256
2257 cgiEndHTML();
2258}
2259
2260
fa73b229 2261/*
323c5de1 2262 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
fa73b229 2263 */
2264
2265static void
323c5de1 2266do_set_allowed_users(http_t *http) /* I - HTTP connection */
fa73b229 2267{
323c5de1 2268 int i; /* Looping var */
fa73b229 2269 ipp_t *request, /* IPP request */
2270 *response; /* IPP response */
323c5de1 2271 char uri[HTTP_MAX_URI]; /* Printer URI */
2272 const char *printer, /* Printer name (purge-jobs) */
2273 *is_class, /* Is a class? */
2274 *users, /* List of users or groups */
2275 *type; /* Allow/deny type */
2276 int num_users; /* Number of users */
2277 char *ptr, /* Pointer into users string */
2278 *end, /* Pointer to end of users string */
2279 quote; /* Quote character */
2280 ipp_attribute_t *attr; /* Attribute */
2281 static const char * const attrs[] = /* Requested attributes */
2282 {
2283 "requesting-user-name-allowed",
2284 "requesting-user-name-denied"
2285 };
fa73b229 2286
fa73b229 2287
323c5de1 2288 is_class = cgiGetVariable("IS_CLASS");
2289 printer = cgiGetVariable("PRINTER_NAME");
fa73b229 2290
323c5de1 2291 if (!printer)
2292 {
4d301e69 2293 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
323c5de1 2294 cgiStartHTML(cgiText(_("Set Allowed Users")));
2295 cgiCopyTemplateLang("error.tmpl");
2296 cgiEndHTML();
2297 return;
2298 }
ef416fc2 2299
323c5de1 2300 users = cgiGetVariable("users");
2301 type = cgiGetVariable("type");
ef416fc2 2302
323c5de1 2303 if (!users || !type ||
2304 (strcmp(type, "requesting-user-name-allowed") &&
2305 strcmp(type, "requesting-user-name-denied")))
2306 {
2307 /*
2308 * Build a Get-Printer-Attributes request, which requires the following
2309 * attributes:
2310 *
2311 * attributes-charset
2312 * attributes-natural-language
2313 * printer-uri
2314 * requested-attributes
2315 */
fa73b229 2316
323c5de1 2317 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
fa73b229 2318
323c5de1 2319 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2320 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2321 printer);
2322 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2323 NULL, uri);
fa73b229 2324
323c5de1 2325 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2326 "requested-attributes",
2327 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
fa73b229 2328
323c5de1 2329 /*
2330 * Do the request and get back a response...
2331 */
fa73b229 2332
323c5de1 2333 if ((response = cupsDoRequest(http, request, "/")) != NULL)
fa73b229 2334 {
323c5de1 2335 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
fa73b229 2336
323c5de1 2337 ippDelete(response);
fa73b229 2338 }
ef416fc2 2339
323c5de1 2340 cgiStartHTML(cgiText(_("Set Allowed Users")));
757d2cad 2341
355e94dc
MS
2342 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2343 {
2344 puts("Status: 401\n");
2345 exit(0);
2346 }
2347 else if (cupsLastError() > IPP_OK_CONFLICT)
f3c17241 2348 cgiShowIPPError(_("Unable to get printer attributes"));
323c5de1 2349 else
2350 cgiCopyTemplateLang("users.tmpl");
2351
2352 cgiEndHTML();
2353 }
2354 else
757d2cad 2355 {
2356 /*
323c5de1 2357 * Save the changes...
757d2cad 2358 */
2359
323c5de1 2360 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
757d2cad 2361 {
323c5de1 2362 /*
2363 * Skip whitespace and commas...
2364 */
fa73b229 2365
323c5de1 2366 while (*ptr == ',' || isspace(*ptr & 255))
2367 ptr ++;
ef416fc2 2368
1f6f3dbc
MS
2369 if (!*ptr)
2370 break;
2371
323c5de1 2372 if (*ptr == '\'' || *ptr == '\"')
2373 {
2374 /*
2375 * Scan quoted name...
2376 */
ef416fc2 2377
323c5de1 2378 quote = *ptr++;
ef416fc2 2379
323c5de1 2380 for (end = ptr; *end; end ++)
2381 if (*end == quote)
2382 break;
2383 }
2384 else
2385 {
2386 /*
2387 * Scan space or comma-delimited name...
2388 */
ef416fc2 2389
323c5de1 2390 for (end = ptr; *end; end ++)
2391 if (isspace(*end & 255) || *end == ',')
2392 break;
2393 }
ef416fc2 2394
323c5de1 2395 /*
2396 * Advance to the next name...
2397 */
ef416fc2 2398
323c5de1 2399 ptr = end;
2400 }
ef416fc2 2401
323c5de1 2402 /*
2403 * Build a CUPS-Add-Printer/Class request, which requires the following
2404 * attributes:
2405 *
2406 * attributes-charset
2407 * attributes-natural-language
2408 * printer-uri
2409 * requesting-user-name-{allowed,denied}
2410 */
ef416fc2 2411
323c5de1 2412 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 2413
323c5de1 2414 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2415 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2416 printer);
2417 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2418 NULL, uri);
f7deaa1a 2419
323c5de1 2420 if (num_users == 0)
2421 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2422 "requesting-user-name-allowed", NULL, "all");
2423 else
2424 {
2425 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2426 type, num_users, NULL, NULL);
ef416fc2 2427
323c5de1 2428 for (i = 0, ptr = (char *)users; *ptr; i ++)
2429 {
2430 /*
2431 * Skip whitespace and commas...
2432 */
ef416fc2 2433
323c5de1 2434 while (*ptr == ',' || isspace(*ptr & 255))
2435 ptr ++;
ef416fc2 2436
1f6f3dbc
MS
2437 if (!*ptr)
2438 break;
2439
323c5de1 2440 if (*ptr == '\'' || *ptr == '\"')
2441 {
2442 /*
2443 * Scan quoted name...
2444 */
7594b224 2445
323c5de1 2446 quote = *ptr++;
7594b224 2447
323c5de1 2448 for (end = ptr; *end; end ++)
2449 if (*end == quote)
2450 break;
2451 }
2452 else
2453 {
2454 /*
2455 * Scan space or comma-delimited name...
2456 */
480ef0fe 2457
323c5de1 2458 for (end = ptr; *end; end ++)
2459 if (isspace(*end & 255) || *end == ',')
2460 break;
2461 }
ef416fc2 2462
323c5de1 2463 /*
2464 * Terminate the name...
2465 */
ef416fc2 2466
323c5de1 2467 if (*end)
2468 *end++ = '\0';
ef416fc2 2469
323c5de1 2470 /*
2471 * Add the name...
2472 */
ef416fc2 2473
86c184ff 2474 ippSetString(request, &attr, i, ptr);
ef416fc2 2475
323c5de1 2476 /*
2477 * Advance to the next name...
2478 */
ef416fc2 2479
323c5de1 2480 ptr = end;
2481 }
2482 }
ef416fc2 2483
2484 /*
323c5de1 2485 * Do the request and get back a response...
ef416fc2 2486 */
2487
323c5de1 2488 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 2489
355e94dc
MS
2490 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2491 {
2492 puts("Status: 401\n");
2493 exit(0);
2494 }
2495 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 2496 {
323c5de1 2497 cgiStartHTML(cgiText(_("Set Allowed Users")));
f3c17241 2498 cgiShowIPPError(_("Unable to change printer"));
ef416fc2 2499 }
323c5de1 2500 else
ef416fc2 2501 {
2502 /*
323c5de1 2503 * Redirect successful updates back to the printer page...
ef416fc2 2504 */
2505
323c5de1 2506 char url[1024], /* Printer/class URL */
2507 refresh[1024]; /* Refresh URL */
ef416fc2 2508
2509
323c5de1 2510 cgiRewriteURL(uri, url, sizeof(url), NULL);
2511 cgiFormEncode(uri, url, sizeof(uri));
2512 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
2513 uri);
2514 cgiSetVariable("refresh_page", refresh);
ef416fc2 2515
323c5de1 2516 cgiStartHTML(cgiText(_("Set Allowed Users")));
ef416fc2 2517
323c5de1 2518 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
2519 "printer-modified.tmpl");
2520 }
ef416fc2 2521
323c5de1 2522 cgiEndHTML();
2523 }
2524}
ef416fc2 2525
ef416fc2 2526
58dc1933
MS
2527/*
2528 * 'do_set_default()' - Set the server default printer/class.
2529 */
2530
2531static void
2532do_set_default(http_t *http) /* I - HTTP connection */
2533{
2534 const char *title; /* Page title */
2535 ipp_t *request; /* IPP request */
2536 char uri[HTTP_MAX_URI]; /* Printer URI */
2537 const char *printer, /* Printer name (purge-jobs) */
2538 *is_class; /* Is a class? */
2539
2540
2541 is_class = cgiGetVariable("IS_CLASS");
2542 printer = cgiGetVariable("PRINTER_NAME");
2543 title = cgiText(_("Set As Server Default"));
2544
2545 if (!printer)
2546 {
4d301e69 2547 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
58dc1933
MS
2548 cgiStartHTML(title);
2549 cgiCopyTemplateLang("error.tmpl");
2550 cgiEndHTML();
2551 return;
2552 }
2553
2554 /*
2555 * Build a printer request, which requires the following
2556 * attributes:
2557 *
2558 * attributes-charset
2559 * attributes-natural-language
2560 * printer-uri
2561 */
2562
2563 request = ippNewRequest(CUPS_SET_DEFAULT);
2564
2565 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2566 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2567 printer);
2568 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2569 NULL, uri);
2570
2571 /*
2572 * Do the request and get back a response...
2573 */
2574
2575 ippDelete(cupsDoRequest(http, request, "/admin/"));
2576
2577 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2578 {
2579 puts("Status: 401\n");
2580 exit(0);
2581 }
2582 else if (cupsLastError() > IPP_OK_CONFLICT)
2583 {
2584 cgiStartHTML(title);
f3c17241 2585 cgiShowIPPError(_("Unable to set server default"));
58dc1933
MS
2586 }
2587 else
2588 {
2589 /*
2590 * Redirect successful updates back to the printer page...
2591 */
2592
2593 char url[1024], /* Printer/class URL */
2594 refresh[1024]; /* Refresh URL */
2595
2596
2597 cgiRewriteURL(uri, url, sizeof(url), NULL);
2598 cgiFormEncode(uri, url, sizeof(uri));
2599 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
2600 cgiSetVariable("refresh_page", refresh);
2601
2602 cgiStartHTML(title);
2603 cgiCopyTemplateLang("printer-default.tmpl");
2604 }
2605
2606 cgiEndHTML();
2607}
2608
2609
323c5de1 2610/*
2611 * 'do_set_options()' - Configure the default options for a queue.
2612 */
ef416fc2 2613
323c5de1 2614static void
2615do_set_options(http_t *http, /* I - HTTP connection */
2616 int is_class) /* I - Set options for class? */
2617{
2618 int i, j, k, m; /* Looping vars */
2619 int have_options; /* Have options? */
2620 ipp_t *request, /* IPP request */
2621 *response; /* IPP response */
2622 ipp_attribute_t *attr; /* IPP attribute */
2623 char uri[HTTP_MAX_URI]; /* Job URI */
2624 const char *var; /* Variable value */
2625 const char *printer; /* Printer printer name */
2626 const char *filename; /* PPD filename */
2627 char tempfile[1024]; /* Temporary filename */
2628 cups_file_t *in, /* Input file */
2629 *out; /* Output file */
749b1e90
MS
2630 char line[1024], /* Line from PPD file */
2631 value[1024], /* Option value */
2632 keyword[1024], /* Keyword from Default line */
323c5de1 2633 *keyptr; /* Pointer into keyword... */
2634 ppd_file_t *ppd; /* PPD file */
2635 ppd_group_t *group; /* Option group */
2636 ppd_option_t *option; /* Option */
749b1e90
MS
2637 ppd_coption_t *coption; /* Custom option */
2638 ppd_cparam_t *cparam; /* Custom parameter */
1f6f3dbc 2639 ppd_attr_t *ppdattr; /* PPD attribute */
323c5de1 2640 const char *title; /* Page title */
ef416fc2 2641
ef416fc2 2642
323c5de1 2643 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
ef416fc2 2644
323c5de1 2645 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
2646 is_class);
ef416fc2 2647
323c5de1 2648 /*
2649 * Get the printer name...
2650 */
ef416fc2 2651
323c5de1 2652 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2653 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2654 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2655 printer);
2656 else
2657 {
4d301e69 2658 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
323c5de1 2659 cgiStartHTML(title);
2660 cgiCopyTemplateLang("error.tmpl");
2661 cgiEndHTML();
2662 return;
2663 }
ef416fc2 2664
323c5de1 2665 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
ef416fc2 2666
1f6f3dbc
MS
2667 /*
2668 * If the user clicks on the Auto-Configure button, send an AutoConfigure
2669 * command file to the printer...
2670 */
2671
2672 if (cgiGetVariable("AUTOCONFIGURE"))
2673 {
58dc1933 2674 cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
1f6f3dbc
MS
2675 return;
2676 }
2677
323c5de1 2678 /*
2679 * Get the PPD file...
2680 */
ef416fc2 2681
323c5de1 2682 if (is_class)
2683 filename = NULL;
2684 else
2685 filename = cupsGetPPD2(http, printer);
ef416fc2 2686
323c5de1 2687 if (filename)
2688 {
2689 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
ef416fc2 2690
323c5de1 2691 if ((ppd = ppdOpenFile(filename)) == NULL)
2692 {
2693 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
f3c17241 2694 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
323c5de1 2695 cgiStartHTML(title);
2696 cgiCopyTemplateLang("error.tmpl");
2697 cgiEndHTML();
2698 return;
2699 }
2700 }
2701 else
2702 {
2703 fputs("DEBUG: No PPD file\n", stderr);
2704 ppd = NULL;
2705 }
ef416fc2 2706
323c5de1 2707 if (cgiGetVariable("job_sheets_start") != NULL ||
2708 cgiGetVariable("job_sheets_end") != NULL)
2709 have_options = 1;
2710 else
2711 have_options = 0;
ef416fc2 2712
323c5de1 2713 if (ppd)
2714 {
2715 ppdMarkDefaults(ppd);
ef416fc2 2716
749b1e90
MS
2717 for (option = ppdFirstOption(ppd);
2718 option;
2719 option = ppdNextOption(ppd))
ef55b745 2720 {
749b1e90
MS
2721 if ((var = cgiGetVariable(option->keyword)) != NULL)
2722 {
2723 have_options = 1;
2724 ppdMarkOption(ppd, option->keyword, var);
ef55b745 2725 fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var);
749b1e90 2726 }
ef55b745
MS
2727 else
2728 fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword);
2729 }
323c5de1 2730 }
fa73b229 2731
323c5de1 2732 if (!have_options || ppdConflicts(ppd))
fa73b229 2733 {
2734 /*
323c5de1 2735 * Show the options to the user...
fa73b229 2736 */
2737
323c5de1 2738 fputs("DEBUG: Showing options...\n", stderr);
fa73b229 2739
58dc1933
MS
2740 /*
2741 * Show auto-configure button if supported...
2742 */
2743
1f6f3dbc
MS
2744 if (ppd)
2745 {
2746 if (ppd->num_filters == 0 ||
2747 ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
2748 ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
2749 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
ef55b745 2750 else
1f6f3dbc
MS
2751 {
2752 for (i = 0; i < ppd->num_filters; i ++)
2753 if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
2754 {
2755 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
2756 break;
2757 }
2758 }
2759 }
2760
58dc1933
MS
2761 /*
2762 * Get the printer attributes...
2763 */
2764
2765 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2766
2767 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2768 "localhost", 0, "/printers/%s", printer);
2769 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2770 NULL, uri);
2771
2772 response = cupsDoRequest(http, request, "/");
2773
2774 /*
2775 * List the groups used as "tabs"...
2776 */
2777
2778 i = 0;
2779
2780 if (ppd)
2781 {
2782 for (group = ppd->groups;
2783 i < ppd->num_groups;
2784 i ++, group ++)
2785 {
2786 cgiSetArray("GROUP_ID", i, group->name);
2787
2788 if (!strcmp(group->name, "InstallableOptions"))
2789 cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
2790 else
2791 cgiSetArray("GROUP", i, group->text);
2792 }
2793 }
2794
2795 if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
2796 {
2797 cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
2798 cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
2799 }
2800
2801 if (ippFindAttribute(response, "printer-error-policy-supported",
2802 IPP_TAG_ZERO) ||
2803 ippFindAttribute(response, "printer-op-policy-supported",
2804 IPP_TAG_ZERO))
2805 {
2806 cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
2807 cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
2808 }
2809
2810 if ((attr = ippFindAttribute(response, "port-monitor-supported",
2811 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
2812 {
2813 cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
2814 cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
2815 }
2816
323c5de1 2817 cgiStartHTML(cgiText(_("Set Printer Options")));
2818 cgiCopyTemplateLang("set-printer-options-header.tmpl");
fa73b229 2819
323c5de1 2820 if (ppd)
2821 {
2822 ppdLocalize(ppd);
f7deaa1a 2823
323c5de1 2824 if (ppdConflicts(ppd))
2825 {
2826 for (i = ppd->num_groups, k = 0, group = ppd->groups;
2827 i > 0;
2828 i --, group ++)
2829 for (j = group->num_options, option = group->options;
2830 j > 0;
2831 j --, option ++)
2832 if (option->conflicted)
2833 {
2834 cgiSetArray("ckeyword", k, option->keyword);
2835 cgiSetArray("ckeytext", k, option->text);
ef55b745
MS
2836
2837 for (m = 0; m < option->num_choices; m ++)
2838 {
2839 if (option->choices[m].marked)
2840 {
2841 cgiSetArray("cchoice", k, option->choices[m].text);
2842 break;
2843 }
2844 }
2845
323c5de1 2846 k ++;
2847 }
f7deaa1a 2848
323c5de1 2849 cgiCopyTemplateLang("option-conflict.tmpl");
2850 }
f7deaa1a 2851
323c5de1 2852 for (i = ppd->num_groups, group = ppd->groups;
2853 i > 0;
2854 i --, group ++)
2855 {
7cf5915e
MS
2856 for (j = group->num_options, option = group->options;
2857 j > 0;
2858 j --, option ++)
2859 {
2860 if (!strcmp(option->keyword, "PageRegion"))
2861 continue;
2862
2863 if (option->num_choices > 1)
2864 break;
2865 }
2866
2867 if (j == 0)
2868 continue;
2869
58dc1933
MS
2870 cgiSetVariable("GROUP_ID", group->name);
2871
323c5de1 2872 if (!strcmp(group->name, "InstallableOptions"))
2873 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2874 else
2875 cgiSetVariable("GROUP", group->text);
f7deaa1a 2876
323c5de1 2877 cgiCopyTemplateLang("option-header.tmpl");
ef55b745 2878
323c5de1 2879 for (j = group->num_options, option = group->options;
2880 j > 0;
2881 j --, option ++)
2882 {
7cf5915e 2883 if (!strcmp(option->keyword, "PageRegion") || option->num_choices < 2)
323c5de1 2884 continue;
ef416fc2 2885
323c5de1 2886 cgiSetVariable("KEYWORD", option->keyword);
2887 cgiSetVariable("KEYTEXT", option->text);
749b1e90 2888
323c5de1 2889 if (option->conflicted)
2890 cgiSetVariable("CONFLICTED", "1");
2891 else
2892 cgiSetVariable("CONFLICTED", "0");
2893
2894 cgiSetSize("CHOICES", 0);
2895 cgiSetSize("TEXT", 0);
2896 for (k = 0, m = 0; k < option->num_choices; k ++)
2897 {
323c5de1 2898 cgiSetArray("CHOICES", m, option->choices[k].choice);
2899 cgiSetArray("TEXT", m, option->choices[k].text);
ef416fc2 2900
323c5de1 2901 m ++;
ef416fc2 2902
323c5de1 2903 if (option->choices[k].marked)
2904 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
2905 }
ef416fc2 2906
749b1e90
MS
2907 cgiSetSize("PARAMS", 0);
2908 cgiSetSize("PARAMTEXT", 0);
2909 cgiSetSize("PARAMVALUE", 0);
2910 cgiSetSize("INPUTTYPE", 0);
2911
2912 if ((coption = ppdFindCustomOption(ppd, option->keyword)))
2913 {
2914 const char *units = NULL; /* Units value, if any */
2915
749b1e90
MS
2916 cgiSetVariable("ISCUSTOM", "1");
2917
2918 for (cparam = ppdFirstCustomParam(coption), m = 0;
2919 cparam;
2920 cparam = ppdNextCustomParam(coption), m ++)
2921 {
88f9aafc
MS
2922 if (!_cups_strcasecmp(option->keyword, "PageSize") &&
2923 _cups_strcasecmp(cparam->name, "Width") &&
2924 _cups_strcasecmp(cparam->name, "Height"))
749b1e90
MS
2925 {
2926 m --;
2927 continue;
2928 }
2929
2930 cgiSetArray("PARAMS", m, cparam->name);
2931 cgiSetArray("PARAMTEXT", m, cparam->text);
2932 cgiSetArray("INPUTTYPE", m, "text");
2933
2934 switch (cparam->type)
2935 {
2936 case PPD_CUSTOM_POINTS :
88f9aafc 2937 if (!_cups_strncasecmp(option->defchoice, "Custom.", 7))
749b1e90
MS
2938 {
2939 units = option->defchoice + strlen(option->defchoice) - 2;
2940
2941 if (strcmp(units, "mm") && strcmp(units, "cm") &&
2942 strcmp(units, "in") && strcmp(units, "ft"))
2943 {
2944 if (units[1] == 'm')
2945 units ++;
2946 else
2947 units = "pt";
2948 }
2949 }
2950 else
2951 units = "pt";
2952
2953 if (!strcmp(units, "mm"))
2954 snprintf(value, sizeof(value), "%g",
2955 cparam->current.custom_points / 72.0 * 25.4);
2956 else if (!strcmp(units, "cm"))
2957 snprintf(value, sizeof(value), "%g",
2958 cparam->current.custom_points / 72.0 * 2.54);
2959 else if (!strcmp(units, "in"))
2960 snprintf(value, sizeof(value), "%g",
2961 cparam->current.custom_points / 72.0);
2962 else if (!strcmp(units, "ft"))
2963 snprintf(value, sizeof(value), "%g",
2964 cparam->current.custom_points / 72.0 / 12.0);
2965 else if (!strcmp(units, "m"))
2966 snprintf(value, sizeof(value), "%g",
2967 cparam->current.custom_points / 72.0 * 0.0254);
2968 else
2969 snprintf(value, sizeof(value), "%g",
2970 cparam->current.custom_points);
2971 cgiSetArray("PARAMVALUE", m, value);
2972 break;
2973
2974 case PPD_CUSTOM_CURVE :
2975 case PPD_CUSTOM_INVCURVE :
2976 case PPD_CUSTOM_REAL :
2977 snprintf(value, sizeof(value), "%g",
2978 cparam->current.custom_real);
2979 cgiSetArray("PARAMVALUE", m, value);
2980 break;
2981
2982 case PPD_CUSTOM_INT:
2983 snprintf(value, sizeof(value), "%d",
2984 cparam->current.custom_int);
2985 cgiSetArray("PARAMVALUE", m, value);
2986 break;
2987
2988 case PPD_CUSTOM_PASSCODE:
2989 case PPD_CUSTOM_PASSWORD:
2990 if (cparam->current.custom_password)
2991 cgiSetArray("PARAMVALUE", m,
2992 cparam->current.custom_password);
2993 else
2994 cgiSetArray("PARAMVALUE", m, "");
2995 cgiSetArray("INPUTTYPE", m, "password");
2996 break;
2997
2998 case PPD_CUSTOM_STRING:
2999 if (cparam->current.custom_string)
3000 cgiSetArray("PARAMVALUE", m,
3001 cparam->current.custom_string);
3002 else
3003 cgiSetArray("PARAMVALUE", m, "");
3004 break;
3005 }
3006 }
3007
3008 if (units)
3009 {
3010 cgiSetArray("PARAMS", m, "Units");
3011 cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
3012 cgiSetArray("PARAMVALUE", m, units);
3013 }
3014 }
3015 else
3016 cgiSetVariable("ISCUSTOM", "0");
3017
323c5de1 3018 switch (option->ui)
3019 {
3020 case PPD_UI_BOOLEAN :
3021 cgiCopyTemplateLang("option-boolean.tmpl");
3022 break;
3023 case PPD_UI_PICKONE :
3024 cgiCopyTemplateLang("option-pickone.tmpl");
3025 break;
3026 case PPD_UI_PICKMANY :
3027 cgiCopyTemplateLang("option-pickmany.tmpl");
3028 break;
3029 }
3030 }
ef416fc2 3031
323c5de1 3032 cgiCopyTemplateLang("option-trailer.tmpl");
3033 }
3034 }
ef416fc2 3035
58dc1933
MS
3036 if ((attr = ippFindAttribute(response, "job-sheets-supported",
3037 IPP_TAG_ZERO)) != NULL)
3038 {
3039 /*
3040 * Add the job sheets options...
3041 */
fa73b229 3042
58dc1933
MS
3043 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3044 cgiSetVariable("GROUP", cgiText(_("Banners")));
3045 cgiCopyTemplateLang("option-header.tmpl");
ef416fc2 3046
58dc1933
MS
3047 cgiSetSize("CHOICES", attr->num_values);
3048 cgiSetSize("TEXT", attr->num_values);
3049 for (k = 0; k < attr->num_values; k ++)
3050 {
3051 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3052 cgiSetArray("TEXT", k, attr->values[k].string.text);
3053 }
ef416fc2 3054
58dc1933 3055 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
ef416fc2 3056
58dc1933 3057 cgiSetVariable("KEYWORD", "job_sheets_start");
eac3a0a0
MS
3058 cgiSetVariable("KEYTEXT",
3059 /* TRANSLATORS: Banner/cover sheet before the print job. */
3060 cgiText(_("Starting Banner")));
58dc1933
MS
3061 cgiSetVariable("DEFCHOICE", attr != NULL ?
3062 attr->values[0].string.text : "");
3063
3064 cgiCopyTemplateLang("option-pickone.tmpl");
3065
3066 cgiSetVariable("KEYWORD", "job_sheets_end");
eac3a0a0
MS
3067 cgiSetVariable("KEYTEXT",
3068 /* TRANSLATORS: Banner/cover sheet after the print job. */
3069 cgiText(_("Ending Banner")));
58dc1933
MS
3070 cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
3071 attr->values[1].string.text : "");
3072
3073 cgiCopyTemplateLang("option-pickone.tmpl");
3074
3075 cgiCopyTemplateLang("option-trailer.tmpl");
3076 }
3077
3078 if (ippFindAttribute(response, "printer-error-policy-supported",
3079 IPP_TAG_ZERO) ||
3080 ippFindAttribute(response, "printer-op-policy-supported",
3081 IPP_TAG_ZERO))
323c5de1 3082 {
58dc1933
MS
3083 /*
3084 * Add the error and operation policy options...
3085 */
ef416fc2 3086
58dc1933
MS
3087 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3088 cgiSetVariable("GROUP", cgiText(_("Policies")));
3089 cgiCopyTemplateLang("option-header.tmpl");
3090
3091 /*
3092 * Error policy...
3093 */
ef416fc2 3094
58dc1933
MS
3095 attr = ippFindAttribute(response, "printer-error-policy-supported",
3096 IPP_TAG_ZERO);
3097
3098 if (attr)
3099 {
323c5de1 3100 cgiSetSize("CHOICES", attr->num_values);
3101 cgiSetSize("TEXT", attr->num_values);
3102 for (k = 0; k < attr->num_values; k ++)
3103 {
3104 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3105 cgiSetArray("TEXT", k, attr->values[k].string.text);
3106 }
ef416fc2 3107
58dc1933
MS
3108 attr = ippFindAttribute(response, "printer-error-policy",
3109 IPP_TAG_ZERO);
ef416fc2 3110
58dc1933
MS
3111 cgiSetVariable("KEYWORD", "printer_error_policy");
3112 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3113 cgiSetVariable("DEFCHOICE", attr == NULL ?
3114 "" : attr->values[0].string.text);
323c5de1 3115 }
ef416fc2 3116
58dc1933 3117 cgiCopyTemplateLang("option-pickone.tmpl");
ef416fc2 3118
58dc1933
MS
3119 /*
3120 * Operation policy...
3121 */
ef416fc2 3122
58dc1933
MS
3123 attr = ippFindAttribute(response, "printer-op-policy-supported",
3124 IPP_TAG_ZERO);
323c5de1 3125
58dc1933
MS
3126 if (attr)
3127 {
3128 cgiSetSize("CHOICES", attr->num_values);
3129 cgiSetSize("TEXT", attr->num_values);
3130 for (k = 0; k < attr->num_values; k ++)
323c5de1 3131 {
58dc1933
MS
3132 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3133 cgiSetArray("TEXT", k, attr->values[k].string.text);
3134 }
ef416fc2 3135
58dc1933 3136 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
ef416fc2 3137
58dc1933
MS
3138 cgiSetVariable("KEYWORD", "printer_op_policy");
3139 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3140 cgiSetVariable("DEFCHOICE", attr == NULL ?
3141 "" : attr->values[0].string.text);
fa73b229 3142
323c5de1 3143 cgiCopyTemplateLang("option-pickone.tmpl");
323c5de1 3144 }
ef416fc2 3145
58dc1933 3146 cgiCopyTemplateLang("option-trailer.tmpl");
ef416fc2 3147 }
ef416fc2 3148
ef416fc2 3149 /*
323c5de1 3150 * Binary protocol support...
ef416fc2 3151 */
3152
58dc1933
MS
3153 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3154 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
ef416fc2 3155 {
58dc1933
MS
3156 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3157 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
ef416fc2 3158
58dc1933
MS
3159 cgiSetSize("CHOICES", attr->num_values);
3160 cgiSetSize("TEXT", attr->num_values);
ef416fc2 3161
58dc1933 3162 for (i = 0; i < attr->num_values; i ++)
ef416fc2 3163 {
58dc1933
MS
3164 cgiSetArray("CHOICES", i, attr->values[i].string.text);
3165 cgiSetArray("TEXT", i, attr->values[i].string.text);
ef416fc2 3166 }
3167
58dc1933
MS
3168 attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
3169 cgiSetVariable("KEYWORD", "port_monitor");
3170 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3171 cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
ef416fc2 3172
58dc1933 3173 cgiCopyTemplateLang("option-header.tmpl");
323c5de1 3174 cgiCopyTemplateLang("option-pickone.tmpl");
323c5de1 3175 cgiCopyTemplateLang("option-trailer.tmpl");
ef416fc2 3176 }
3177
323c5de1 3178 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3179 cgiEndHTML();
58dc1933
MS
3180
3181 ippDelete(response);
323c5de1 3182 }
3183 else
3184 {
ef416fc2 3185 /*
323c5de1 3186 * Set default options...
ef416fc2 3187 */
3188
323c5de1 3189 fputs("DEBUG: Setting options...\n", stderr);
ef416fc2 3190
323c5de1 3191 if (filename)
ef416fc2 3192 {
323c5de1 3193 out = cupsTempFile2(tempfile, sizeof(tempfile));
3194 in = cupsFileOpen(filename, "r");
ef416fc2 3195
323c5de1 3196 if (!in || !out)
ef416fc2 3197 {
323c5de1 3198 cgiSetVariable("ERROR", strerror(errno));
3199 cgiStartHTML(cgiText(_("Set Printer Options")));
3200 cgiCopyTemplateLang("error.tmpl");
3201 cgiEndHTML();
ef416fc2 3202
323c5de1 3203 if (in)
3204 cupsFileClose(in);
ef416fc2 3205
323c5de1 3206 if (out)
ef416fc2 3207 {
323c5de1 3208 cupsFileClose(out);
3209 unlink(tempfile);
3210 }
ef416fc2 3211
323c5de1 3212 unlink(filename);
3213 return;
3214 }
ef416fc2 3215
323c5de1 3216 while (cupsFileGets(in, line, sizeof(line)))
3217 {
58dc1933 3218 if (!strncmp(line, "*cupsProtocol:", 14))
323c5de1 3219 continue;
3220 else if (strncmp(line, "*Default", 8))
3221 cupsFilePrintf(out, "%s\n", line);
ef416fc2 3222 else
3223 {
3224 /*
323c5de1 3225 * Get default option name...
ef416fc2 3226 */
3227
323c5de1 3228 strlcpy(keyword, line + 8, sizeof(keyword));
3229
3230 for (keyptr = keyword; *keyptr; keyptr ++)
3231 if (*keyptr == ':' || isspace(*keyptr & 255))
ef416fc2 3232 break;
ef416fc2 3233
323c5de1 3234 *keyptr = '\0';
ef416fc2 3235
323c5de1 3236 if (!strcmp(keyword, "PageRegion") ||
3237 !strcmp(keyword, "PaperDimension") ||
3238 !strcmp(keyword, "ImageableArea"))
749b1e90 3239 var = get_option_value(ppd, "PageSize", value, sizeof(value));
323c5de1 3240 else
749b1e90 3241 var = get_option_value(ppd, keyword, value, sizeof(value));
ef416fc2 3242
749b1e90 3243 if (!var)
323c5de1 3244 cupsFilePrintf(out, "%s\n", line);
749b1e90
MS
3245 else
3246 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
323c5de1 3247 }
3248 }
ef416fc2 3249
323c5de1 3250 cupsFileClose(in);
3251 cupsFileClose(out);
3252 }
3253 else
3254 {
3255 /*
3256 * Make sure temporary filename is cleared when there is no PPD...
3257 */
ef416fc2 3258
323c5de1 3259 tempfile[0] = '\0';
ef416fc2 3260 }
3261
323c5de1 3262 /*
3263 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3264 * following attributes:
3265 *
3266 * attributes-charset
3267 * attributes-natural-language
3268 * printer-uri
3269 * job-sheets-default
3270 * printer-error-policy
3271 * printer-op-policy
3272 * [ppd file]
3273 */
3274
3275 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3276 CUPS_ADD_MODIFY_PRINTER);
3277
3278 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3279 NULL, uri);
3280
3281 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3282 "job-sheets-default", 2, NULL, NULL);
86c184ff
MS
3283 ippSetString(request, &attr, 0, cgiGetVariable("job_sheets_start"));
3284 ippSetString(request, &attr, 1, cgiGetVariable("job_sheets_end"));
323c5de1 3285
3286 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
1f0275e3
MS
3287 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3288 "printer-error-policy", NULL, var);
323c5de1 3289
3290 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
1f0275e3
MS
3291 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3292 "printer-op-policy", NULL, var);
323c5de1 3293
58dc1933
MS
3294 if ((var = cgiGetVariable("port_monitor")) != NULL)
3295 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3296 "port-monitor", NULL, var);
3297
ef416fc2 3298 /*
3299 * Do the request and get back a response...
3300 */
3301
323c5de1 3302 if (filename)
3303 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3304 else
3305 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 3306
355e94dc
MS
3307 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3308 {
3309 puts("Status: 401\n");
3310 exit(0);
3311 }
3312 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3313 {
323c5de1 3314 cgiStartHTML(title);
f3c17241 3315 cgiShowIPPError(_("Unable to set options"));
ef416fc2 3316 }
3317 else
3318 {
3319 /*
3320 * Redirect successful updates back to the printer page...
3321 */
3322
323c5de1 3323 char refresh[1024]; /* Refresh URL */
ef416fc2 3324
fa73b229 3325
323c5de1 3326 cgiFormEncode(uri, printer, sizeof(uri));
3327 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3328 is_class ? "classes" : "printers", uri);
ef416fc2 3329 cgiSetVariable("refresh_page", refresh);
3330
323c5de1 3331 cgiStartHTML(title);
ef416fc2 3332
323c5de1 3333 cgiCopyTemplateLang("printer-configured.tmpl");
ef416fc2 3334 }
3335
3336 cgiEndHTML();
323c5de1 3337
3338 if (filename)
3339 unlink(tempfile);
ef416fc2 3340 }
323c5de1 3341
3342 if (filename)
3343 unlink(filename);
ef416fc2 3344}
3345
3346
3347/*
749b1e90 3348 * 'do_set_sharing()' - Set printer-is-shared value.
ef416fc2 3349 */
3350
3351static void
fa73b229 3352do_set_sharing(http_t *http) /* I - HTTP connection */
ef416fc2 3353{
3354 ipp_t *request, /* IPP request */
3355 *response; /* IPP response */
3356 char uri[HTTP_MAX_URI]; /* Printer URI */
3357 const char *printer, /* Printer name */
fa73b229 3358 *is_class, /* Is a class? */
ef416fc2 3359 *shared; /* Sharing value */
ef416fc2 3360
3361
fa73b229 3362 is_class = cgiGetVariable("IS_CLASS");
3363 printer = cgiGetVariable("PRINTER_NAME");
3364 shared = cgiGetVariable("SHARED");
ef416fc2 3365
fa73b229 3366 if (!printer || !shared)
ef416fc2 3367 {
4d301e69 3368 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
fa73b229 3369 cgiStartHTML(cgiText(_("Set Publishing")));
ef416fc2 3370 cgiCopyTemplateLang("error.tmpl");
3371 cgiEndHTML();
3372 return;
3373 }
3374
3375 /*
fa73b229 3376 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3377 * following attributes:
ef416fc2 3378 *
3379 * attributes-charset
3380 * attributes-natural-language
3381 * printer-uri
3382 * printer-is-shared
3383 */
3384
fa73b229 3385 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 3386
a4d04587 3387 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3388 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3389 printer);
ef416fc2 3390 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3391 NULL, uri);
3392
7e86f2f6 3393 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", (char)atoi(shared));
ef416fc2 3394
3395 /*
3396 * Do the request and get back a response...
3397 */
3398
3399 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3400 {
ef416fc2 3401 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3402
3403 ippDelete(response);
3404 }
ef416fc2 3405
355e94dc
MS
3406 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3407 {
3408 puts("Status: 401\n");
3409 exit(0);
3410 }
3411 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3412 {
fa73b229 3413 cgiStartHTML(cgiText(_("Set Publishing")));
f3c17241 3414 cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
ef416fc2 3415 }
3416 else
3417 {
3418 /*
3419 * Redirect successful updates back to the printer page...
3420 */
3421
fa73b229 3422 char url[1024], /* Printer/class URL */
3423 refresh[1024]; /* Refresh URL */
ef416fc2 3424
ef416fc2 3425
fa73b229 3426 cgiRewriteURL(uri, url, sizeof(url), NULL);
3427 cgiFormEncode(uri, url, sizeof(uri));
f301802f 3428 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
fa73b229 3429 cgiSetVariable("refresh_page", refresh);
ef416fc2 3430
fa73b229 3431 cgiStartHTML(cgiText(_("Set Publishing")));
3432 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3433 "printer-modified.tmpl");
ef416fc2 3434 }
3435
3436 cgiEndHTML();
3437}
3438
3439
749b1e90
MS
3440/*
3441 * 'get_option_value()' - Return the value of an option.
3442 *
3443 * This function also handles generation of custom option values.
3444 */
3445
3446static char * /* O - Value string or NULL on error */
3447get_option_value(
3448 ppd_file_t *ppd, /* I - PPD file */
3449 const char *name, /* I - Option name */
3450 char *buffer, /* I - String buffer */
3451 size_t bufsize) /* I - Size of buffer */
3452{
3453 char *bufptr, /* Pointer into buffer */
3454 *bufend; /* End of buffer */
3455 ppd_coption_t *coption; /* Custom option */
3456 ppd_cparam_t *cparam; /* Current custom parameter */
3457 char keyword[256]; /* Parameter name */
3458 const char *val, /* Parameter value */
3459 *uval; /* Units value */
3460 long integer; /* Integer value */
3461 double number, /* Number value */
3462 number_points; /* Number in points */
3463
3464
3465 /*
3466 * See if we have a custom option choice...
3467 */
3468
3469 if ((val = cgiGetVariable(name)) == NULL)
3470 {
3471 /*
3472 * Option not found!
3473 */
3474
3475 return (NULL);
3476 }
88f9aafc 3477 else if (_cups_strcasecmp(val, "Custom") ||
749b1e90
MS
3478 (coption = ppdFindCustomOption(ppd, name)) == NULL)
3479 {
3480 /*
3481 * Not a custom choice...
3482 */
3483
3484 strlcpy(buffer, val, bufsize);
3485 return (buffer);
3486 }
3487
3488 /*
3489 * OK, we have a custom option choice, format it...
3490 */
3491
3492 *buffer = '\0';
3493
3494 if (!strcmp(coption->keyword, "PageSize"))
3495 {
3496 const char *lval; /* Length string value */
3497 double width, /* Width value */
3498 width_points, /* Width in points */
3499 length, /* Length value */
3500 length_points; /* Length in points */
3501
3502
3503 val = cgiGetVariable("PageSize.Width");
3504 lval = cgiGetVariable("PageSize.Height");
3505 uval = cgiGetVariable("PageSize.Units");
3506
3507 if (!val || !lval || !uval ||
3508 (width = strtod(val, NULL)) == 0.0 ||
3509 (length = strtod(lval, NULL)) == 0.0 ||
3510 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3511 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3512 return (NULL);
3513
3514 width_points = get_points(width, uval);
3515 length_points = get_points(length, uval);
3516
3517 if (width_points < ppd->custom_min[0] ||
3518 width_points > ppd->custom_max[0] ||
3519 length_points < ppd->custom_min[1] ||
3520 length_points > ppd->custom_max[1])
3521 return (NULL);
3522
3523 snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
3524 }
ef55b745 3525 else if (cupsArrayCount(coption->params) == 1)
749b1e90
MS
3526 {
3527 cparam = ppdFirstCustomParam(coption);
3528 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
3529
3530 if ((val = cgiGetVariable(keyword)) == NULL)
3531 return (NULL);
3532
3533 switch (cparam->type)
3534 {
3535 case PPD_CUSTOM_CURVE :
3536 case PPD_CUSTOM_INVCURVE :
3537 case PPD_CUSTOM_REAL :
3538 if ((number = strtod(val, NULL)) == 0.0 ||
3539 number < cparam->minimum.custom_real ||
3540 number > cparam->maximum.custom_real)
3541 return (NULL);
3542
3543 snprintf(buffer, bufsize, "Custom.%g", number);
3544 break;
3545
3546 case PPD_CUSTOM_INT :
3547 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
3548 integer == LONG_MAX ||
3549 integer < cparam->minimum.custom_int ||
3550 integer > cparam->maximum.custom_int)
3551 return (NULL);
3552
3553 snprintf(buffer, bufsize, "Custom.%ld", integer);
3554 break;
3555
3556 case PPD_CUSTOM_POINTS :
3557 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
3558
3559 if ((number = strtod(val, NULL)) == 0.0 ||
3560 (uval = cgiGetVariable(keyword)) == NULL ||
3561 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3562 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3563 return (NULL);
3564
3565 number_points = get_points(number, uval);
3566 if (number_points < cparam->minimum.custom_points ||
3567 number_points > cparam->maximum.custom_points)
3568 return (NULL);
3569
3570 snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
3571 break;
3572
3573 case PPD_CUSTOM_PASSCODE :
3574 for (uval = val; *uval; uval ++)
3575 if (!isdigit(*uval & 255))
3576 return (NULL);
3577
3578 case PPD_CUSTOM_PASSWORD :
3579 case PPD_CUSTOM_STRING :
3580 integer = (long)strlen(val);
3581 if (integer < cparam->minimum.custom_string ||
3582 integer > cparam->maximum.custom_string)
3583 return (NULL);
3584
3585 snprintf(buffer, bufsize, "Custom.%s", val);
3586 break;
3587 }
3588 }
3589 else
3590 {
3591 const char *prefix = "{"; /* Prefix string */
3592
3593
3594 bufptr = buffer;
3595 bufend = buffer + bufsize;
3596
3597 for (cparam = ppdFirstCustomParam(coption);
3598 cparam;
3599 cparam = ppdNextCustomParam(coption))
3600 {
3601 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
3602 cparam->name);
3603
3604 if ((val = cgiGetVariable(keyword)) == NULL)
3605 return (NULL);
3606
07623986 3607 snprintf(bufptr, (size_t)(bufend - bufptr), "%s%s=", prefix, cparam->name);
749b1e90
MS
3608 bufptr += strlen(bufptr);
3609 prefix = " ";
3610
3611 switch (cparam->type)
3612 {
3613 case PPD_CUSTOM_CURVE :
3614 case PPD_CUSTOM_INVCURVE :
3615 case PPD_CUSTOM_REAL :
3616 if ((number = strtod(val, NULL)) == 0.0 ||
3617 number < cparam->minimum.custom_real ||
3618 number > cparam->maximum.custom_real)
3619 return (NULL);
3620
07623986 3621 snprintf(bufptr, (size_t)(bufend - bufptr), "%g", number);
749b1e90
MS
3622 break;
3623
3624 case PPD_CUSTOM_INT :
3625 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
3626 integer == LONG_MAX ||
3627 integer < cparam->minimum.custom_int ||
3628 integer > cparam->maximum.custom_int)
3629 return (NULL);
3630
07623986 3631 snprintf(bufptr, (size_t)(bufend - bufptr), "%ld", integer);
749b1e90
MS
3632 break;
3633
3634 case PPD_CUSTOM_POINTS :
3635 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
3636
3637 if ((number = strtod(val, NULL)) == 0.0 ||
3638 (uval = cgiGetVariable(keyword)) == NULL ||
3639 (strcmp(uval, "pt") && strcmp(uval, "in") &&
3640 strcmp(uval, "ft") && strcmp(uval, "cm") &&
3641 strcmp(uval, "mm") && strcmp(uval, "m")))
3642 return (NULL);
3643
3644 number_points = get_points(number, uval);
3645 if (number_points < cparam->minimum.custom_points ||
3646 number_points > cparam->maximum.custom_points)
3647 return (NULL);
3648
07623986 3649 snprintf(bufptr, (size_t)(bufend - bufptr), "%g%s", number, uval);
749b1e90
MS
3650 break;
3651
3652 case PPD_CUSTOM_PASSCODE :
3653 for (uval = val; *uval; uval ++)
3654 if (!isdigit(*uval & 255))
3655 return (NULL);
3656
3657 case PPD_CUSTOM_PASSWORD :
3658 case PPD_CUSTOM_STRING :
3659 integer = (long)strlen(val);
3660 if (integer < cparam->minimum.custom_string ||
3661 integer > cparam->maximum.custom_string)
3662 return (NULL);
3663
3664 if ((bufptr + 2) > bufend)
3665 return (NULL);
3666
3667 bufend --;
3668 *bufptr++ = '\"';
3669
3670 while (*val && bufptr < bufend)
3671 {
3672 if (*val == '\\' || *val == '\"')
3673 {
3674 if ((bufptr + 1) >= bufend)
3675 return (NULL);
3676
3677 *bufptr++ = '\\';
3678 }
3679
3680 *bufptr++ = *val++;
3681 }
3682
3683 if (bufptr >= bufend)
3684 return (NULL);
3685
3686 *bufptr++ = '\"';
3687 *bufptr = '\0';
3688 bufend ++;
3689 break;
3690 }
3691
3692 bufptr += strlen(bufptr);
3693 }
3694
3695 if (bufptr == buffer || (bufend - bufptr) < 2)
3696 return (NULL);
3697
5a9febac 3698 memcpy(bufptr, "}", 2);
749b1e90
MS
3699 }
3700
3701 return (buffer);
3702}
3703
3704
3705/*
3706 * 'get_points()' - Get a value in points.
3707 */
3708
3709static double /* O - Number in points */
3710get_points(double number, /* I - Original number */
3711 const char *uval) /* I - Units */
3712{
3713 if (!strcmp(uval, "mm")) /* Millimeters */
3714 return (number * 72.0 / 25.4);
3715 else if (!strcmp(uval, "cm")) /* Centimeters */
3716 return (number * 72.0 / 2.54);
3717 else if (!strcmp(uval, "in")) /* Inches */
3718 return (number * 72.0);
3719 else if (!strcmp(uval, "ft")) /* Feet */
3720 return (number * 72.0 * 12.0);
3721 else if (!strcmp(uval, "m")) /* Meters */
3722 return (number * 72.0 / 0.0254);
3723 else /* Points */
3724 return (number);
3725}
3726
3727
fb2d5470
MS
3728/*
3729 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
3730 */
3731
3732static char * /* O - Filename or NULL */
3733get_printer_ppd(const char *uri, /* I - Printer URI */
3734 char *buffer, /* I - Filename buffer */
3735 size_t bufsize) /* I - Size of filename buffer */
3736{
3737 http_t *http; /* Connection to printer */
3738 ipp_t *request, /* Get-Printer-Attributes request */
3739 *response; /* Get-Printer-Attributes response */
3740 char resolved[1024], /* Resolved URI */
3741 scheme[32], /* URI scheme */
3742 userpass[256], /* Username:password */
3743 host[256], /* Hostname */
3744 resource[256]; /* Resource path */
3745 int port; /* Port number */
622207ef
MS
3746 static const char * const pattrs[] = /* Printer attributes we need */
3747 {
644dca18 3748 "all",
622207ef
MS
3749 "media-col-database"
3750 };
fb2d5470
MS
3751
3752
3753 /*
3754 * Connect to the printer...
3755 */
3756
3757 if (strstr(uri, "._tcp"))
3758 {
3759 /*
3760 * Resolve URI...
3761 */
3762
3763 if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
3764 {
3765 fprintf(stderr, "ERROR: Unable to resolve \"%s\".\n", uri);
3766 return (NULL);
3767 }
3768
3769 uri = resolved;
3770 }
3771
3772 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
3773 {
3774 fprintf(stderr, "ERROR: Bad printer URI \"%s\".\n", uri);
3775 return (NULL);
3776 }
3777
3778 http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
3779 if (!http)
3780 {
3781 fprintf(stderr, "ERROR: Unable to connect to \"%s:%d\": %s\n", host, port, cupsLastErrorString());
3782 return (NULL);
3783 }
3784
3785 /*
3786 * Send a Get-Printer-Attributes request...
3787 */
3788
3789 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
3790 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
622207ef 3791 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
fb2d5470
MS
3792 response = cupsDoRequest(http, request, resource);
3793
3794 if (!_ppdCreateFromIPP(buffer, bufsize, response))
3795 fprintf(stderr, "ERROR: Unable to create PPD file: %s\n", strerror(errno));
3796
3797 ippDelete(response);
3798 httpClose(http);
3799
3800 if (buffer[0])
3801 return (buffer);
3802 else
3803 return (NULL);
3804}