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