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