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