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