]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/admin.c
Merge changes from CUPS 1.5svn-r8933.
[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;
951 else if ((*uriptr == ' ' || *uriptr == '/') && tptr[-1] != '_')
952 *tptr++ = '_';
953 else if (*uriptr == '?' || *uriptr == '(')
954 break;
955
956 *tptr = '\0';
957
958 cgiSetVariable("TEMPLATE_NAME", template);
959 }
960 }
ef416fc2 961 }
962
2e4ff8af 963 if (!var)
ef416fc2 964 {
965 /*
58dc1933 966 * Look for devices so the user can pick something...
ef416fc2 967 */
968
58dc1933
MS
969 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
970 {
971 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
972 if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
973 *uriptr = '\0';
a4d04587 974
58dc1933
MS
975 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
976 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
977 }
ef416fc2 978
ef416fc2 979 /*
ef55b745
MS
980 * For modern browsers, start a multi-part page so we can show that something
981 * is happening. Non-modern browsers just get everything at the end...
982 */
983
984 if (cgiSupportsMultipart())
985 {
986 cgiStartMultipart();
987 cgiStartHTML(title);
988 cgiCopyTemplateLang("choose-device.tmpl");
989 cgiEndHTML();
990 fflush(stdout);
991 }
992
993 /*
994 * Scan for devices for up to 30 seconds...
ef416fc2 995 */
996
58dc1933 997 fputs("DEBUG: Getting list of devices...\n", stderr);
a4d04587 998
ef55b745 999 current_device = 0;
ed6e7faf
MS
1000 if (cupsGetDevices(http, 30, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
1001 (cups_device_cb_t)choose_device_cb,
ef55b745 1002 &current_device) == IPP_OK)
d2354e63 1003 {
58dc1933 1004 fputs("DEBUG: Got device list!\n", stderr);
d2354e63 1005
ef55b745
MS
1006 if (cgiSupportsMultipart())
1007 cgiStartMultipart();
d2354e63 1008
ef55b745
MS
1009 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1010 cgiStartHTML(title);
1011 cgiCopyTemplateLang("choose-device.tmpl");
1012 cgiEndHTML();
1013
1014 if (cgiSupportsMultipart())
1015 cgiEndMultipart();
d2354e63 1016 }
a4d04587 1017 else
e4572d57 1018 {
a4d04587 1019 fprintf(stderr,
1020 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1021 cupsLastError(), cupsLastErrorString());
e4572d57
MS
1022 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1023 {
1024 puts("Status: 401\n");
1025 exit(0);
1026 }
1027 else
1028 {
1029 cgiStartHTML(title);
1030 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1031 _("Unable to add printer:"));
1032 cgiEndHTML();
1033 return;
1034 }
1035 }
ef416fc2 1036 }
1037 else if (strchr(var, '/') == NULL)
1038 {
1039 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
1040 {
1041 /*
1042 * Set the current device URI for the form to the old one...
1043 */
1044
1045 if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
1f6f3dbc 1046 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
ef416fc2 1047 }
1048
1049 /*
1050 * User needs to set the full URI...
1051 */
1052
1053 cgiStartHTML(title);
1054 cgiCopyTemplateLang("choose-uri.tmpl");
1055 cgiEndHTML();
1056 }
1057 else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1058 {
1059 /*
1060 * Need baud rate, parity, etc.
1061 */
1062
1063 if ((var = strchr(var, '?')) != NULL &&
1064 strncmp(var, "?baud=", 6) == 0)
1065 maxrate = atoi(var + 6);
1066 else
1067 maxrate = 19200;
1068
1069 for (i = 0; i < 10; i ++)
1070 if (baudrates[i] > maxrate)
1071 break;
1072 else
1073 {
1074 sprintf(baudrate, "%d", baudrates[i]);
1075 cgiSetArray("BAUDRATES", i, baudrate);
1076 }
1077
1078 cgiStartHTML(title);
1079 cgiCopyTemplateLang("choose-serial.tmpl");
1080 cgiEndHTML();
1081 }
2e4ff8af
MS
1082 else if (!name || !cgiGetVariable("PRINTER_LOCATION"))
1083 {
1084 cgiStartHTML(title);
1085
1086 if (modify)
1087 {
1088 /*
1089 * Update the location and description of an existing printer...
1090 */
1091
1092 if (oldinfo)
1f6f3dbc
MS
1093 {
1094 if ((attr = ippFindAttribute(oldinfo, "printer-info",
1095 IPP_TAG_TEXT)) != NULL)
1096 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
1097
1098 if ((attr = ippFindAttribute(oldinfo, "printer-location",
1099 IPP_TAG_TEXT)) != NULL)
1100 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
ef55b745
MS
1101
1102 if ((attr = ippFindAttribute(oldinfo, "printer-is-shared",
1103 IPP_TAG_BOOLEAN)) != NULL)
1104 cgiSetVariable("PRINTER_IS_SHARED",
1105 attr->values[0].boolean ? "1" : "0");
1f6f3dbc 1106 }
2e4ff8af
MS
1107
1108 cgiCopyTemplateLang("modify-printer.tmpl");
1109 }
1110 else
1111 {
1112 /*
1113 * Get the name, location, and description for a new printer...
1114 */
1115
c5571a1d
MS
1116#ifdef __APPLE__
1117 if (!strncmp(var, "usb:", 4))
1118 cgiSetVariable("printer_is_shared", "1");
1119 else
1120#endif /* __APPLE__ */
1121 cgiSetVariable("printer_is_shared", "0");
1122
2e4ff8af
MS
1123 cgiCopyTemplateLang("add-printer.tmpl");
1124 }
1125
1126 cgiEndHTML();
1127
1128 if (oldinfo)
1129 ippDelete(oldinfo);
1130
1131 return;
1132 }
bf3816c7
MS
1133 else if (!file &&
1134 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
ef416fc2 1135 {
bf3816c7 1136 if (modify && !cgiGetVariable("SELECT_MAKE"))
ef416fc2 1137 {
1138 /*
1139 * Get the PPD file...
1140 */
1141
1142 int fd; /* PPD file */
1143 char filename[1024]; /* PPD filename */
1144 ppd_file_t *ppd; /* PPD information */
1145 char buffer[1024]; /* Buffer */
1146 int bytes; /* Number of bytes */
1147 http_status_t get_status; /* Status of GET */
1148
1149
a4d04587 1150 /* TODO: Use cupsGetFile() API... */
ef416fc2 1151 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
1152
1153 if (httpGet(http, uri))
1154 httpGet(http, uri);
1155
1156 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
1157
1158 if (get_status != HTTP_OK)
1159 {
178cb736
MS
1160 httpFlush(http);
1161
ef416fc2 1162 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
1163 uri, get_status, httpStatus(get_status));
1164 }
1165 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
1166 {
a4d04587 1167 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
ef416fc2 1168 write(fd, buffer, bytes);
1169
1170 close(fd);
1171
1172 if ((ppd = ppdOpenFile(filename)) != NULL)
1173 {
1174 if (ppd->manufacturer)
1175 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
1176
1177 if (ppd->nickname)
1178 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
1179
1180 ppdClose(ppd);
1181 unlink(filename);
1182 }
1183 else
1184 {
1185 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
1186 filename, ppdErrorString(ppdLastError(&bytes)));
1187 }
1188 }
1189 else
1190 {
1191 httpFlush(http);
1192
1193 fprintf(stderr,
1194 "ERROR: Unable to create temporary file for PPD file: %s\n",
1195 strerror(errno));
1196 }
1197 }
ef416fc2 1198
1199 /*
1200 * Build a CUPS_GET_PPDS request, which requires the following
1201 * attributes:
1202 *
1203 * attributes-charset
1204 * attributes-natural-language
1205 * printer-uri
1206 */
1207
fa73b229 1208 request = ippNewRequest(CUPS_GET_PPDS);
ef416fc2 1209
1210 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1211 NULL, "ipp://localhost/printers/");
1212
2e4ff8af
MS
1213 if ((var = cgiGetVariable("CURRENT_MAKE")) == NULL)
1214 var = cgiGetVariable("PPD_MAKE");
bf3816c7 1215 if (var && !cgiGetVariable("SELECT_MAKE"))
58dc1933 1216 {
e4572d57
MS
1217 const char *make_model; /* Make and model */
1218
1219
ef416fc2 1220 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1221 "ppd-make", NULL, var);
58dc1933 1222
bf3816c7 1223 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
58dc1933 1224 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
e4572d57 1225 "ppd-make-and-model", NULL, make_model);
58dc1933 1226 }
ef416fc2 1227 else
1228 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1229 "requested-attributes", NULL, "ppd-make");
1230
1231 /*
1232 * Do the request and get back a response...
1233 */
1234
1235 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1236 {
1237 /*
1238 * Got the list of PPDs, see if the user has selected a make...
1239 */
1240
ef55b745 1241 if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify)
ef416fc2 1242 {
1243 /*
89d46774 1244 * No PPD files with this make, try again with all makes...
ef416fc2 1245 */
1246
89d46774 1247 ippDelete(response);
1248
1249 request = ippNewRequest(CUPS_GET_PPDS);
1250
1251 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1252 NULL, "ipp://localhost/printers/");
1253
1254 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1255 "requested-attributes", NULL, "ppd-make");
ef416fc2 1256
89d46774 1257 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1258 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1259
1260 cgiStartHTML(title);
1261 cgiCopyTemplateLang("choose-make.tmpl");
1262 cgiEndHTML();
1263 }
2e4ff8af 1264 else if (!var || cgiGetVariable("SELECT_MAKE"))
89d46774 1265 {
ef416fc2 1266 cgiStartHTML(title);
1267 cgiCopyTemplateLang("choose-make.tmpl");
1268 cgiEndHTML();
1269 }
1270 else
1271 {
1272 /*
1273 * Let the user choose a model...
1274 */
1275
ef416fc2 1276 cgiStartHTML(title);
ef55b745
MS
1277 if (!cgiGetVariable("PPD_MAKE"))
1278 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1279 if (!modify)
1280 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1281 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
ef416fc2 1282 cgiCopyTemplateLang("choose-model.tmpl");
1283 cgiEndHTML();
1284 }
1285
ef416fc2 1286 ippDelete(response);
1287 }
1288 else
1289 {
ef416fc2 1290 cgiStartHTML(title);
fa73b229 1291 cgiShowIPPError(_("Unable to get list of printer drivers:"));
ef416fc2 1292 cgiCopyTemplateLang("error.tmpl");
1293 cgiEndHTML();
1294 }
1295 }
1296 else
1297 {
1298 /*
1299 * Build a CUPS_ADD_PRINTER request, which requires the following
1300 * attributes:
1301 *
1302 * attributes-charset
1303 * attributes-natural-language
1304 * printer-uri
1305 * printer-location
1306 * printer-info
1307 * ppd-name
1308 * device-uri
1309 * printer-is-accepting-jobs
c5571a1d 1310 * printer-is-shared
ef416fc2 1311 * printer-state
1312 */
1313
fa73b229 1314 request = ippNewRequest(CUPS_ADD_PRINTER);
ef416fc2 1315
a4d04587 1316 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1317 "localhost", 0, "/printers/%s",
1318 cgiGetVariable("PRINTER_NAME"));
ef416fc2 1319 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1320 NULL, uri);
1321
1322 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1323 NULL, cgiGetVariable("PRINTER_LOCATION"));
1324
1325 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1326 NULL, cgiGetVariable("PRINTER_INFO"));
1327
1328 if (!file)
0af14961
MS
1329 {
1330 var = cgiGetVariable("PPD_NAME");
1331 if (strcmp(var, "__no_change__"))
1332 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
1333 NULL, var);
1334 }
ef416fc2 1335
1336 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1337
1338 /*
1339 * Strip make and model from URI...
1340 */
1341
1342 if ((uriptr = strrchr(uri, '|')) != NULL)
1343 *uriptr = '\0';
1344
fa73b229 1345 if (!strncmp(uri, "serial:", 7))
ef416fc2 1346 {
1347 /*
1348 * Update serial port URI to include baud rate, etc.
1349 */
1350
1351 if ((uriptr = strchr(uri, '?')) == NULL)
1352 uriptr = uri + strlen(uri);
1353
1354 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
1355 "?baud=%s+bits=%s+parity=%s+flow=%s",
1356 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1357 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1358 }
1359
1360 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1361 NULL, uri);
1362
1363 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1364
c5571a1d
MS
1365 var = cgiGetVariable("printer_is_shared");
1366 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared",
1367 var && (!strcmp(var, "1") || !strcmp(var, "on")));
1368
ef416fc2 1369 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1370 IPP_PRINTER_IDLE);
1371
1372 /*
1373 * Do the request and get back a response...
1374 */
1375
1376 if (file)
fa73b229 1377 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
ef416fc2 1378 else
fa73b229 1379 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 1380
355e94dc
MS
1381 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1382 {
1383 puts("Status: 401\n");
1384 exit(0);
1385 }
1386 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 1387 {
1388 cgiStartHTML(title);
fa73b229 1389 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1390 _("Unable to add printer:"));
ef416fc2 1391 }
2e4ff8af 1392 else if (modify)
ef416fc2 1393 {
1394 /*
2e4ff8af 1395 * Redirect successful updates back to the printer page...
ef416fc2 1396 */
1397
1398 char refresh[1024]; /* Refresh URL */
1399
1400
1401 cgiFormEncode(uri, name, sizeof(uri));
1402
2e4ff8af
MS
1403 snprintf(refresh, sizeof(refresh),
1404 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
ef416fc2 1405
1406 cgiSetVariable("refresh_page", refresh);
1407
1408 cgiStartHTML(title);
1409
2e4ff8af
MS
1410 cgiCopyTemplateLang("printer-modified.tmpl");
1411 }
1412 else
1413 {
1414 /*
1415 * Set the printer options...
1416 */
1417
1418 cgiSetVariable("OP", "set-printer-options");
1419 do_set_options(http, 0);
1420 return;
ef416fc2 1421 }
1422
1423 cgiEndHTML();
1424 }
1425
1426 if (oldinfo)
1427 ippDelete(oldinfo);
1428}
1429
1430
f7deaa1a 1431/*
1432 * 'do_cancel_subscription()' - Cancel a subscription.
1433 */
1434
1435static void
1436do_cancel_subscription(http_t *http)/* I - HTTP connection */
1437{
1438 ipp_t *request; /* IPP request data */
1439 const char *var, /* Form variable */
1440 *user; /* Username */
1441 int id; /* Subscription ID */
1442
1443
1444 /*
1445 * See if we have all of the required information...
1446 */
1447
1448 if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL)
1449 id = atoi(var);
1450 else
1451 id = 0;
1452
1453 if (id <= 0)
1454 {
4d301e69 1455 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
f7deaa1a 1456 cgiStartHTML(_("Cancel RSS Subscription"));
1457 cgiCopyTemplateLang("error.tmpl");
1458 cgiEndHTML();
1459 return;
1460 }
1461
839a51c8
MS
1462 /*
1463 * Require a username...
1464 */
1465
1466 if ((user = getenv("REMOTE_USER")) == NULL)
1467 {
1468 puts("Status: 401\n");
1469 exit(0);
1470 }
1471
f7deaa1a 1472 /*
1473 * Cancel the subscription...
1474 */
1475
1476 request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
1477
1478 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1479 NULL, "ipp://localhost/");
1480 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
1481 "notify-subscription-id", id);
1482
f7deaa1a 1483 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1484 NULL, user);
1485
1486 ippDelete(cupsDoRequest(http, request, "/"));
1487
355e94dc
MS
1488 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1489 {
1490 puts("Status: 401\n");
1491 exit(0);
1492 }
1493 else if (cupsLastError() > IPP_OK_CONFLICT)
f7deaa1a 1494 {
1495 cgiStartHTML(_("Cancel RSS Subscription"));
1496 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1497 }
1498 else
1499 {
1500 /*
1501 * Redirect successful updates back to the admin page...
1502 */
1503
1504 cgiSetVariable("refresh_page", "5;URL=/admin");
1505 cgiStartHTML(_("Cancel RSS Subscription"));
1506 cgiCopyTemplateLang("subscription-canceled.tmpl");
1507 }
1508
1509 cgiEndHTML();
1510}
1511
1512
ef416fc2 1513/*
323c5de1 1514 * 'do_config_server()' - Configure server settings.
ef416fc2 1515 */
1516
1517static void
323c5de1 1518do_config_server(http_t *http) /* I - HTTP connection */
ef416fc2 1519{
2e4ff8af 1520 if (cgiGetVariable("CHANGESETTINGS"))
ef416fc2 1521 {
323c5de1 1522 /*
1523 * Save basic setting changes...
1524 */
ef416fc2 1525
323c5de1 1526 int num_settings; /* Number of server settings */
1527 cups_option_t *settings; /* Server settings */
0af14961
MS
1528 int advanced, /* Advanced settings shown? */
1529 changed; /* Have settings changed? */
323c5de1 1530 const char *debug_logging, /* DEBUG_LOGGING value */
1531 *remote_admin, /* REMOTE_ADMIN value */
1532 *remote_any, /* REMOTE_ANY value */
1533 *remote_printers,
1534 /* REMOTE_PRINTERS value */
1535 *share_printers,/* SHARE_PRINTERS value */
0af14961 1536 *user_cancel_any,
ac884b6a 1537 /* USER_CANCEL_ANY value */
bf3816c7
MS
1538 *browse_web_if = NULL,
1539 /* BrowseWebIF value */
1540 *preserve_job_history = NULL,
0af14961 1541 /* PreserveJobHistory value */
bf3816c7 1542 *preserve_job_files = NULL,
0af14961 1543 /* PreserveJobFiles value */
bf3816c7
MS
1544 *max_clients = NULL,
1545 /* MaxClients value */
1546 *max_jobs = NULL,
1547 /* MaxJobs value */
1548 *max_log_size = NULL;
1549 /* MaxLogSize value */
0af14961
MS
1550 char local_protocols[255],
1551 /* BrowseLocalProtocols */
1552 remote_protocols[255];
1553 /* BrowseRemoteProtocols */
58dc1933
MS
1554 const char *current_browse_web_if,
1555 /* BrowseWebIF value */
1556 *current_preserve_job_history,
1557 /* PreserveJobHistory value */
1558 *current_preserve_job_files,
1559 /* PreserveJobFiles value */
1560 *current_max_clients,
1561 /* MaxClients value */
1562 *current_max_jobs,
1563 /* MaxJobs value */
1564 *current_max_log_size,
1565 /* MaxLogSize value */
1566 *current_local_protocols,
1567 /* BrowseLocalProtocols */
1568 *current_remote_protocols;
1569 /* BrowseRemoteProtocols */
323c5de1 1570#ifdef HAVE_GSSAPI
ac884b6a 1571 char default_auth_type[255];
323c5de1 1572 /* DefaultAuthType value */
ef55b745 1573 const char *val; /* Setting value */
323c5de1 1574#endif /* HAVE_GSSAPI */
bd7854cb 1575
ef416fc2 1576
323c5de1 1577 /*
1578 * Get the checkbox values from the form...
1579 */
bd7854cb 1580
0af14961
MS
1581 debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1582 remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1583 remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1584 remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1585 share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1586 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1587
1588 advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL;
1589 if (advanced)
1590 {
1591 /*
1592 * Get advanced settings...
1593 */
1594
1595 browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1596 preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1597 preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1f6f3dbc 1598 max_clients = cgiGetVariable("MAX_CLIENTS");
0af14961
MS
1599 max_jobs = cgiGetVariable("MAX_JOBS");
1600 max_log_size = cgiGetVariable("MAX_LOG_SIZE");
1601
1f6f3dbc
MS
1602 if (!max_clients || atoi(max_clients) <= 0)
1603 max_clients = "100";
1604
0af14961
MS
1605 if (!max_jobs || atoi(max_jobs) <= 0)
1606 max_jobs = "500";
1607
1608 if (!max_log_size || atof(max_log_size) <= 0.0)
1609 max_log_size = "1m";
1610
1611 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1612 strcpy(local_protocols, "cups");
1613 else
1614 local_protocols[0] = '\0';
1615
1616#ifdef HAVE_DNSSD
1617 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1618 {
1619 if (local_protocols[0])
1620 strcat(local_protocols, " dnssd");
1621 else
1622 strcat(local_protocols, "dnssd");
1623 }
1624#endif /* HAVE_DNSSD */
1625
1626#ifdef HAVE_LDAP
1627 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1628 {
1629 if (local_protocols[0])
1630 strcat(local_protocols, " ldap");
1631 else
1632 strcat(local_protocols, "ldap");
1633 }
1634#endif /* HAVE_LDAP */
1635
1636#ifdef HAVE_LIBSLP
1637 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1638 {
1639 if (local_protocols[0])
1640 strcat(local_protocols, " slp");
1641 else
1642 strcat(local_protocols, "slp");
1643 }
1644#endif /* HAVE_SLP */
ef55b745 1645
0af14961
MS
1646 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1647 strcpy(remote_protocols, "cups");
1648 else
1649 remote_protocols[0] = '\0';
1650
1651#ifdef HAVE_LDAP
1652 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1653 {
1654 if (remote_protocols[0])
1655 strcat(remote_protocols, " ldap");
1656 else
1657 strcat(remote_protocols, "ldap");
1658 }
1659#endif /* HAVE_LDAP */
1660
1661#ifdef HAVE_LIBSLP
1662 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1663 {
1664 if (remote_protocols[0])
1665 strcat(remote_protocols, " slp");
1666 else
1667 strcat(remote_protocols, "slp");
1668 }
1669#endif /* HAVE_SLP */
1670 }
bd7854cb 1671
323c5de1 1672 /*
1673 * Get the current server settings...
1674 */
ef416fc2 1675
323c5de1 1676 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
1677 {
1678 cgiStartHTML(cgiText(_("Change Settings")));
1679 cgiSetVariable("MESSAGE",
1680 cgiText(_("Unable to change server settings:")));
1681 cgiSetVariable("ERROR", cupsLastErrorString());
1682 cgiCopyTemplateLang("error.tmpl");
1683 cgiEndHTML();
1684 return;
1685 }
ef416fc2 1686
0a682745
MS
1687#ifdef HAVE_GSSAPI
1688 /*
1689 * Get authentication settings...
1690 */
1691
1692 if (cgiGetVariable("KERBEROS"))
ac884b6a 1693 strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
0a682745
MS
1694 else
1695 {
0af14961 1696 val = cupsGetOption("DefaultAuthType", num_settings, settings);
ac884b6a 1697
1f6f3dbc 1698 if (!val || !strcasecmp(val, "Negotiate"))
ac884b6a
MS
1699 strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
1700 else
1701 strlcpy(default_auth_type, val, sizeof(default_auth_type));
0a682745
MS
1702 }
1703
1704 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1705#endif /* HAVE_GSSAPI */
1706
58dc1933
MS
1707 if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings,
1708 settings)) == NULL)
1709 current_browse_web_if = "No";
1710
1711 if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory",
1712 num_settings,
1713 settings)) == NULL)
1714 current_preserve_job_history = "Yes";
1715
1716 if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles",
1717 num_settings,
1718 settings)) == NULL)
1719 current_preserve_job_files = "No";
1720
1721 if ((current_max_clients = cupsGetOption("MaxClients", num_settings,
1722 settings)) == NULL)
1723 current_max_clients = "100";
1724
1725 if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings,
1726 settings)) == NULL)
1727 current_max_jobs = "500";
1728
1729 if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings,
1730 settings)) == NULL)
1731 current_max_log_size = "1m";
1732
1733 if ((current_local_protocols = cupsGetOption("BrowseLocalProtocols",
1734 num_settings,
1735 settings)) == NULL)
1736 current_local_protocols = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
1737
1738 if ((current_remote_protocols = cupsGetOption("BrowseRemoteProtocols",
1739 num_settings,
1740 settings)) == NULL)
1741 current_remote_protocols = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
1742
323c5de1 1743 /*
1744 * See if the settings have changed...
1745 */
1746
0af14961
MS
1747 changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1748 num_settings, settings)) ||
1749 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1750 num_settings, settings)) ||
1751 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1752 num_settings, settings)) ||
1753 strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
1754 num_settings, settings)) ||
1755 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1756 num_settings, settings)) ||
323c5de1 1757#ifdef HAVE_GSSAPI
0af14961
MS
1758 !cupsGetOption("DefaultAuthType", num_settings, settings) ||
1759 strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1760 num_settings, settings)) ||
323c5de1 1761#endif /* HAVE_GSSAPI */
0af14961
MS
1762 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1763 num_settings, settings));
1764
1765 if (advanced && !changed)
58dc1933
MS
1766 changed = strcasecmp(local_protocols, current_local_protocols) ||
1767 strcasecmp(remote_protocols, current_remote_protocols) ||
1768 strcasecmp(browse_web_if, current_browse_web_if) ||
1769 strcasecmp(preserve_job_history, current_preserve_job_history) ||
1770 strcasecmp(preserve_job_files, current_preserve_job_files) ||
1771 strcasecmp(max_clients, current_max_clients) ||
1772 strcasecmp(max_jobs, current_max_jobs) ||
1773 strcasecmp(max_log_size, current_max_log_size);
0af14961
MS
1774
1775 if (changed)
323c5de1 1776 {
1777 /*
1778 * Settings *have* changed, so save the changes...
1779 */
ef416fc2 1780
323c5de1 1781 cupsFreeOptions(num_settings, settings);
ef416fc2 1782
323c5de1 1783 num_settings = 0;
1784 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1785 debug_logging, num_settings, &settings);
1786 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1787 remote_admin, num_settings, &settings);
1788 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1789 remote_any, num_settings, &settings);
1790 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1791 remote_printers, num_settings, &settings);
1792 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1793 share_printers, num_settings, &settings);
1794 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1795 user_cancel_any, num_settings, &settings);
1796#ifdef HAVE_GSSAPI
1797 num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
1798 num_settings, &settings);
1799#endif /* HAVE_GSSAPI */
ef416fc2 1800
0af14961
MS
1801 if (advanced)
1802 {
1803 /*
1804 * Add advanced settings...
1805 */
1806
58dc1933 1807 if (strcasecmp(local_protocols, current_local_protocols))
0af14961
MS
1808 num_settings = cupsAddOption("BrowseLocalProtocols", local_protocols,
1809 num_settings, &settings);
58dc1933 1810 if (strcasecmp(remote_protocols, current_remote_protocols))
0af14961
MS
1811 num_settings = cupsAddOption("BrowseRemoteProtocols", remote_protocols,
1812 num_settings, &settings);
58dc1933 1813 if (strcasecmp(browse_web_if, current_browse_web_if))
0af14961
MS
1814 num_settings = cupsAddOption("BrowseWebIF", browse_web_if,
1815 num_settings, &settings);
58dc1933 1816 if (strcasecmp(preserve_job_history, current_preserve_job_history))
0af14961
MS
1817 num_settings = cupsAddOption("PreserveJobHistory",
1818 preserve_job_history, num_settings,
1819 &settings);
58dc1933 1820 if (strcasecmp(preserve_job_files, current_preserve_job_files))
0af14961
MS
1821 num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files,
1822 num_settings, &settings);
58dc1933 1823 if (strcasecmp(max_clients, current_max_clients))
1f6f3dbc
MS
1824 num_settings = cupsAddOption("MaxClients", max_clients, num_settings,
1825 &settings);
58dc1933 1826 if (strcasecmp(max_jobs, current_max_jobs))
0af14961
MS
1827 num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings,
1828 &settings);
58dc1933 1829 if (strcasecmp(max_log_size, current_max_log_size))
0af14961
MS
1830 num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings,
1831 &settings);
1832 }
1833
323c5de1 1834 if (!cupsAdminSetServerSettings(http, num_settings, settings))
ef416fc2 1835 {
355e94dc
MS
1836 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1837 {
1838 puts("Status: 401\n");
1839 exit(0);
1840 }
1841
323c5de1 1842 cgiStartHTML(cgiText(_("Change Settings")));
1843 cgiSetVariable("MESSAGE",
1844 cgiText(_("Unable to change server settings:")));
1845 cgiSetVariable("ERROR", cupsLastErrorString());
1846 cgiCopyTemplateLang("error.tmpl");
ef416fc2 1847 }
ef416fc2 1848 else
323c5de1 1849 {
58dc1933
MS
1850 if (advanced)
1851 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1852 else
1853 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
323c5de1 1854 cgiStartHTML(cgiText(_("Change Settings")));
1855 cgiCopyTemplateLang("restart.tmpl");
1856 }
1857 }
1858 else
1859 {
1860 /*
1861 * No changes...
1862 */
ef416fc2 1863
323c5de1 1864 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1865 cgiStartHTML(cgiText(_("Change Settings")));
1866 cgiCopyTemplateLang("norestart.tmpl");
1867 }
ef416fc2 1868
323c5de1 1869 cupsFreeOptions(num_settings, settings);
ef416fc2 1870
323c5de1 1871 cgiEndHTML();
1872 }
2e4ff8af 1873 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
ef416fc2 1874 {
1875 /*
323c5de1 1876 * Save hand-edited config file...
ef416fc2 1877 */
1878
323c5de1 1879 http_status_t status; /* PUT status */
1880 char tempfile[1024]; /* Temporary new cupsd.conf */
1881 int tempfd; /* Temporary file descriptor */
1882 cups_file_t *temp; /* Temporary file */
1883 const char *start, /* Start of line */
1884 *end; /* End of line */
bd7854cb 1885
fa73b229 1886
323c5de1 1887 /*
1888 * Create a temporary file for the new cupsd.conf file...
1889 */
ef416fc2 1890
323c5de1 1891 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
ef416fc2 1892 {
323c5de1 1893 cgiStartHTML(cgiText(_("Edit Configuration File")));
1894 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1895 cgiSetVariable("ERROR", strerror(errno));
1896 cgiCopyTemplateLang("error.tmpl");
1897 cgiEndHTML();
ef55b745 1898
323c5de1 1899 perror(tempfile);
1900 return;
ef416fc2 1901 }
1902
323c5de1 1903 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
ef416fc2 1904 {
323c5de1 1905 cgiStartHTML(cgiText(_("Edit Configuration File")));
1906 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1907 cgiSetVariable("ERROR", strerror(errno));
1908 cgiCopyTemplateLang("error.tmpl");
1909 cgiEndHTML();
ef55b745 1910
323c5de1 1911 perror(tempfile);
1912 close(tempfd);
1913 unlink(tempfile);
1914 return;
1915 }
ef416fc2 1916
323c5de1 1917 /*
1918 * Copy the cupsd.conf text from the form variable...
1919 */
ef416fc2 1920
323c5de1 1921 start = cgiGetVariable("CUPSDCONF");
1922 while (start)
1923 {
1924 if ((end = strstr(start, "\r\n")) == NULL)
1925 if ((end = strstr(start, "\n")) == NULL)
1926 end = start + strlen(start);
ef416fc2 1927
323c5de1 1928 cupsFileWrite(temp, start, end - start);
1929 cupsFilePutChar(temp, '\n');
ef416fc2 1930
323c5de1 1931 if (*end == '\r')
1932 start = end + 2;
1933 else if (*end == '\n')
1934 start = end + 1;
1935 else
1936 start = NULL;
1937 }
ef416fc2 1938
323c5de1 1939 cupsFileClose(temp);
ef416fc2 1940
323c5de1 1941 /*
1942 * Upload the configuration file to the server...
1943 */
ef416fc2 1944
323c5de1 1945 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
ef416fc2 1946
355e94dc
MS
1947 if (status == HTTP_UNAUTHORIZED)
1948 {
1949 puts("Status: 401\n");
1950 unlink(tempfile);
1951 exit(0);
1952 }
1953 else if (status != HTTP_CREATED)
323c5de1 1954 {
1955 cgiSetVariable("MESSAGE",
1956 cgiText(_("Unable to upload cupsd.conf file:")));
1957 cgiSetVariable("ERROR", httpStatus(status));
1958
1959 cgiStartHTML(cgiText(_("Edit Configuration File")));
1960 cgiCopyTemplateLang("error.tmpl");
1961 }
1962 else
1963 {
1964 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1965
1966 cgiStartHTML(cgiText(_("Edit Configuration File")));
1967 cgiCopyTemplateLang("restart.tmpl");
ef416fc2 1968 }
1969
323c5de1 1970 cgiEndHTML();
1971
1972 unlink(tempfile);
1973 }
1974 else
1975 {
1976 struct stat info; /* cupsd.conf information */
1977 cups_file_t *cupsd; /* cupsd.conf file */
355e94dc
MS
1978 char *buffer, /* Buffer for entire file */
1979 *bufptr, /* Pointer into buffer */
1980 *bufend; /* End of buffer */
1981 int ch; /* Character from file */
323c5de1 1982 char filename[1024]; /* Filename */
1983 const char *server_root; /* Location of config files */
1984
1985
ef416fc2 1986 /*
323c5de1 1987 * Locate the cupsd.conf file...
ef416fc2 1988 */
1989
323c5de1 1990 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1991 server_root = CUPS_SERVERROOT;
ef416fc2 1992
323c5de1 1993 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
ef416fc2 1994
1995 /*
323c5de1 1996 * Figure out the size...
ef416fc2 1997 */
1998
323c5de1 1999 if (stat(filename, &info))
ef416fc2 2000 {
323c5de1 2001 cgiStartHTML(cgiText(_("Edit Configuration File")));
2002 cgiSetVariable("MESSAGE",
2003 cgiText(_("Unable to access cupsd.conf file:")));
2004 cgiSetVariable("ERROR", strerror(errno));
2005 cgiCopyTemplateLang("error.tmpl");
2006 cgiEndHTML();
ef416fc2 2007
323c5de1 2008 perror(filename);
2009 return;
2010 }
ef416fc2 2011
323c5de1 2012 if (info.st_size > (1024 * 1024))
2013 {
2014 cgiStartHTML(cgiText(_("Edit Configuration File")));
2015 cgiSetVariable("MESSAGE",
2016 cgiText(_("Unable to access cupsd.conf file:")));
2017 cgiSetVariable("ERROR",
2018 cgiText(_("Unable to edit cupsd.conf files larger than "
4d301e69 2019 "1MB")));
323c5de1 2020 cgiCopyTemplateLang("error.tmpl");
2021 cgiEndHTML();
ef416fc2 2022
323c5de1 2023 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
2024 (long)info.st_size);
2025 return;
2026 }
ef416fc2 2027
323c5de1 2028 /*
2029 * Open the cupsd.conf file...
2030 */
ef416fc2 2031
323c5de1 2032 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
2033 {
2034 /*
2035 * Unable to open - log an error...
2036 */
ef416fc2 2037
323c5de1 2038 cgiStartHTML(cgiText(_("Edit Configuration File")));
2039 cgiSetVariable("MESSAGE",
2040 cgiText(_("Unable to access cupsd.conf file:")));
2041 cgiSetVariable("ERROR", strerror(errno));
2042 cgiCopyTemplateLang("error.tmpl");
2043 cgiEndHTML();
ef416fc2 2044
323c5de1 2045 perror(filename);
2046 return;
2047 }
ef416fc2 2048
323c5de1 2049 /*
2050 * Allocate memory and load the file into a string buffer...
2051 */
ef416fc2 2052
91c84a35
MS
2053 if ((buffer = calloc(1, info.st_size + 1)) != NULL)
2054 {
2055 cupsFileRead(cupsd, buffer, info.st_size);
2056 cgiSetVariable("CUPSDCONF", buffer);
2057 free(buffer);
2058 }
ef416fc2 2059
323c5de1 2060 cupsFileClose(cupsd);
ef416fc2 2061
355e94dc
MS
2062 /*
2063 * Then get the default cupsd.conf file and put that into a string as
2064 * well...
2065 */
2066
2067 strlcat(filename, ".default", sizeof(filename));
2068
2069 if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
2070 (cupsd = cupsFileOpen(filename, "r")) != NULL)
2071 {
91c84a35 2072 if ((buffer = calloc(1, 2 * info.st_size + 1)) != NULL)
355e94dc 2073 {
91c84a35
MS
2074 bufend = buffer + 2 * info.st_size - 1;
2075
2076 for (bufptr = buffer;
2077 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
355e94dc 2078 {
91c84a35
MS
2079 if (ch == '\\' || ch == '\"')
2080 {
2081 *bufptr++ = '\\';
2082 *bufptr++ = ch;
2083 }
2084 else if (ch == '\n')
2085 {
2086 *bufptr++ = '\\';
2087 *bufptr++ = 'n';
2088 }
2089 else if (ch == '\t')
2090 {
2091 *bufptr++ = '\\';
2092 *bufptr++ = 't';
2093 }
2094 else if (ch >= ' ')
2095 *bufptr++ = ch;
355e94dc 2096 }
355e94dc 2097
91c84a35 2098 *bufptr = '\0';
355e94dc 2099
91c84a35
MS
2100 cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
2101 free(buffer);
2102 }
355e94dc 2103
91c84a35 2104 cupsFileClose(cupsd);
355e94dc
MS
2105 }
2106
323c5de1 2107 /*
2108 * Show the current config file...
2109 */
ef416fc2 2110
323c5de1 2111 cgiStartHTML(cgiText(_("Edit Configuration File")));
ef416fc2 2112
323c5de1 2113 cgiCopyTemplateLang("edit-config.tmpl");
ef416fc2 2114
323c5de1 2115 cgiEndHTML();
2116 }
2117}
ef416fc2 2118
ef416fc2 2119
323c5de1 2120/*
749b1e90 2121 * 'do_delete_class()' - Delete a class.
323c5de1 2122 */
ef416fc2 2123
323c5de1 2124static void
2125do_delete_class(http_t *http) /* I - HTTP connection */
2126{
2127 ipp_t *request; /* IPP request */
2128 char uri[HTTP_MAX_URI]; /* Job URI */
2129 const char *pclass; /* Printer class name */
ef416fc2 2130
ef416fc2 2131
323c5de1 2132 /*
2133 * Get form variables...
2134 */
ef416fc2 2135
323c5de1 2136 if (cgiGetVariable("CONFIRM") == NULL)
2137 {
2138 cgiStartHTML(cgiText(_("Delete Class")));
2139 cgiCopyTemplateLang("class-confirm.tmpl");
2140 cgiEndHTML();
2141 return;
2142 }
ef416fc2 2143
323c5de1 2144 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
2145 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2146 "localhost", 0, "/classes/%s", pclass);
2147 else
2148 {
2149 cgiStartHTML(cgiText(_("Delete Class")));
4d301e69 2150 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
323c5de1 2151 cgiCopyTemplateLang("error.tmpl");
2152 cgiEndHTML();
2153 return;
2154 }
ef416fc2 2155
323c5de1 2156 /*
2157 * Build a CUPS_DELETE_CLASS request, which requires the following
2158 * attributes:
2159 *
2160 * attributes-charset
2161 * attributes-natural-language
2162 * printer-uri
2163 */
2164
2165 request = ippNewRequest(CUPS_DELETE_CLASS);
2166
2167 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2168 NULL, uri);
2169
2170 /*
2171 * Do the request and get back a response...
2172 */
2173
2174 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 2175
323c5de1 2176 /*
2177 * Show the results...
2178 */
2179
355e94dc
MS
2180 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2181 {
2182 puts("Status: 401\n");
2183 exit(0);
2184 }
2185 else if (cupsLastError() <= IPP_OK_CONFLICT)
323c5de1 2186 {
ef416fc2 2187 /*
323c5de1 2188 * Redirect successful updates back to the classes page...
ef416fc2 2189 */
2190
323c5de1 2191 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2192 }
ef416fc2 2193
323c5de1 2194 cgiStartHTML(cgiText(_("Delete Class")));
ef416fc2 2195
323c5de1 2196 if (cupsLastError() > IPP_OK_CONFLICT)
2197 cgiShowIPPError(_("Unable to delete class:"));
2198 else
2199 cgiCopyTemplateLang("class-deleted.tmpl");
ef416fc2 2200
323c5de1 2201 cgiEndHTML();
2202}
ef416fc2 2203
ef416fc2 2204
323c5de1 2205/*
749b1e90 2206 * 'do_delete_printer()' - Delete a printer.
323c5de1 2207 */
ef416fc2 2208
323c5de1 2209static void
2210do_delete_printer(http_t *http) /* I - HTTP connection */
2211{
2212 ipp_t *request; /* IPP request */
2213 char uri[HTTP_MAX_URI]; /* Job URI */
2214 const char *printer; /* Printer printer name */
ef416fc2 2215
323c5de1 2216
2217 /*
2218 * Get form variables...
2219 */
2220
2221 if (cgiGetVariable("CONFIRM") == NULL)
2222 {
2223 cgiStartHTML(cgiText(_("Delete Printer")));
2224 cgiCopyTemplateLang("printer-confirm.tmpl");
ef416fc2 2225 cgiEndHTML();
323c5de1 2226 return;
ef416fc2 2227 }
323c5de1 2228
2229 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2230 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2231 "localhost", 0, "/printers/%s", printer);
ef416fc2 2232 else
323c5de1 2233 {
2234 cgiStartHTML(cgiText(_("Delete Printer")));
4d301e69 2235 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
323c5de1 2236 cgiCopyTemplateLang("error.tmpl");
2237 cgiEndHTML();
2238 return;
2239 }
2240
2241 /*
2242 * Build a CUPS_DELETE_PRINTER request, which requires the following
2243 * attributes:
2244 *
2245 * attributes-charset
2246 * attributes-natural-language
2247 * printer-uri
2248 */
2249
2250 request = ippNewRequest(CUPS_DELETE_PRINTER);
2251
2252 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2253 NULL, uri);
2254
2255 /*
2256 * Do the request and get back a response...
2257 */
2258
2259 ippDelete(cupsDoRequest(http, request, "/admin/"));
2260
2261 /*
2262 * Show the results...
2263 */
2264
355e94dc
MS
2265 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2266 {
2267 puts("Status: 401\n");
2268 exit(0);
2269 }
2270 else if (cupsLastError() <= IPP_OK_CONFLICT)
ef416fc2 2271 {
2272 /*
323c5de1 2273 * Redirect successful updates back to the printers page...
ef416fc2 2274 */
2275
323c5de1 2276 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2277 }
bd7854cb 2278
323c5de1 2279 cgiStartHTML(cgiText(_("Delete Printer")));
ef416fc2 2280
323c5de1 2281 if (cupsLastError() > IPP_OK_CONFLICT)
2282 cgiShowIPPError(_("Unable to delete printer:"));
2283 else
2284 cgiCopyTemplateLang("printer-deleted.tmpl");
ef416fc2 2285
323c5de1 2286 cgiEndHTML();
2287}
ef416fc2 2288
ef416fc2 2289
323c5de1 2290/*
749b1e90 2291 * 'do_export()' - Export printers to Samba.
323c5de1 2292 */
ef416fc2 2293
323c5de1 2294static void
2295do_export(http_t *http) /* I - HTTP connection */
2296{
2297 int i, j; /* Looping vars */
2298 ipp_t *request, /* IPP request */
2299 *response; /* IPP response */
2300 const char *username, /* Samba username */
2301 *password, /* Samba password */
2302 *export_all; /* Export all printers? */
2303 int export_count, /* Number of printers to export */
2304 printer_count; /* Number of available printers */
2305 const char *name, /* What name to pull */
2306 *dest; /* Current destination */
2307 char ppd[1024]; /* PPD file */
ef416fc2 2308
ef416fc2 2309
323c5de1 2310 /*
2311 * Get form data...
2312 */
ef416fc2 2313
323c5de1 2314 username = cgiGetVariable("USERNAME");
2315 password = cgiGetVariable("PASSWORD");
2316 export_all = cgiGetVariable("EXPORT_ALL");
2317 export_count = cgiGetSize("EXPORT_NAME");
ef416fc2 2318
323c5de1 2319 /*
2320 * Get list of available printers...
2321 */
ef416fc2 2322
323c5de1 2323 cgiSetSize("PRINTER_NAME", 0);
2324 cgiSetSize("PRINTER_EXPORT", 0);
ef416fc2 2325
323c5de1 2326 request = ippNewRequest(CUPS_GET_PRINTERS);
ef416fc2 2327
323c5de1 2328 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2329 "printer-type", 0);
ef416fc2 2330
323c5de1 2331 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2332 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
2333 CUPS_PRINTER_IMPLICIT);
ef416fc2 2334
323c5de1 2335 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2336 "requested-attributes", NULL, "printer-name");
ef416fc2 2337
323c5de1 2338 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2339 {
2340 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2341 ippDelete(response);
ef416fc2 2342
323c5de1 2343 if (!export_all)
2344 {
2345 printer_count = cgiGetSize("PRINTER_NAME");
ef416fc2 2346
323c5de1 2347 for (i = 0; i < printer_count; i ++)
2348 {
2349 dest = cgiGetArray("PRINTER_NAME", i);
ef416fc2 2350
323c5de1 2351 for (j = 0; j < export_count; j ++)
2352 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
2353 break;
2354
2355 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
2356 }
2357 }
2358 }
2359
2360 /*
2361 * Export or get the printers to export...
2362 */
ef416fc2 2363
323c5de1 2364 if (username && *username && password && *password &&
2365 (export_all || export_count > 0))
2366 {
ef416fc2 2367 /*
323c5de1 2368 * Do export...
ef416fc2 2369 */
2370
323c5de1 2371 fputs("DEBUG: Export printers...\n", stderr);
ef416fc2 2372
323c5de1 2373 if (export_all)
ef416fc2 2374 {
323c5de1 2375 name = "PRINTER_NAME";
2376 export_count = cgiGetSize("PRINTER_NAME");
ef416fc2 2377 }
2378 else
323c5de1 2379 name = "EXPORT_NAME";
ef416fc2 2380
323c5de1 2381 for (i = 0; i < export_count; i ++)
2382 {
2383 dest = cgiGetArray(name, i);
ef416fc2 2384
323c5de1 2385 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2386 break;
fa73b229 2387
323c5de1 2388 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2389 stderr);
ef416fc2 2390
323c5de1 2391 unlink(ppd);
ef416fc2 2392
323c5de1 2393 if (!j)
2394 break;
ef416fc2 2395 }
2396
323c5de1 2397 if (i < export_count)
2398 cgiSetVariable("ERROR", cupsLastErrorString());
2399 else
2400 {
2401 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2402 cgiCopyTemplateLang("samba-exported.tmpl");
2403 cgiEndHTML();
2404 return;
2405 }
ef416fc2 2406 }
323c5de1 2407 else if (username && !*username)
2408 cgiSetVariable("ERROR",
2409 cgiText(_("A Samba username is required to export "
4d301e69 2410 "printer drivers")));
323c5de1 2411 else if (username && (!password || !*password))
2412 cgiSetVariable("ERROR",
2413 cgiText(_("A Samba password is required to export "
4d301e69 2414 "printer drivers")));
323c5de1 2415
2416 /*
2417 * Show form...
2418 */
ef416fc2 2419
323c5de1 2420 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2421 cgiCopyTemplateLang("samba-export.tmpl");
2422 cgiEndHTML();
ef416fc2 2423}
2424
2425
2426/*
749b1e90 2427 * 'do_list_printers()' - List available printers.
ef416fc2 2428 */
2429
2430static void
323c5de1 2431do_list_printers(http_t *http) /* I - HTTP connection */
ef416fc2 2432{
323c5de1 2433 ipp_t *request, /* IPP request */
2434 *response; /* IPP response */
2435 ipp_attribute_t *attr; /* IPP attribute */
ef416fc2 2436
757d2cad 2437
323c5de1 2438 cgiStartHTML(cgiText(_("List Available Printers")));
2439 fflush(stdout);
2440
2441 /*
2442 * Get the list of printers and their devices...
2443 */
2444
2445 request = ippNewRequest(CUPS_GET_PRINTERS);
2446
2447 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2448 "requested-attributes", NULL, "device-uri");
2449
2450 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2451 CUPS_PRINTER_LOCAL);
2452 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2453 CUPS_PRINTER_LOCAL);
757d2cad 2454
323c5de1 2455 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2456 {
d09495fa 2457 /*
323c5de1 2458 * Got the printer list, now load the devices...
d09495fa 2459 */
2460
323c5de1 2461 int i; /* Looping var */
2462 cups_array_t *printer_devices; /* Printer devices for local printers */
2463 char *printer_device; /* Current printer device */
7594b224 2464
d09495fa 2465
2466 /*
323c5de1 2467 * Allocate an array and copy the device strings...
d09495fa 2468 */
2469
323c5de1 2470 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2471
2472 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2473 attr;
2474 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
ef416fc2 2475 {
323c5de1 2476 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
d09495fa 2477 }
2478
2479 /*
323c5de1 2480 * Free the printer list and get the device list...
d09495fa 2481 */
2482
323c5de1 2483 ippDelete(response);
d09495fa 2484
323c5de1 2485 request = ippNewRequest(CUPS_GET_DEVICES);
d09495fa 2486
323c5de1 2487 if ((response = cupsDoRequest(http, request, "/")) != NULL)
ef416fc2 2488 {
d09495fa 2489 /*
323c5de1 2490 * Got the device list, let's parse it...
d09495fa 2491 */
2492
323c5de1 2493 const char *device_uri, /* device-uri attribute value */
2494 *device_make_and_model, /* device-make-and-model value */
2495 *device_info; /* device-info value */
ef416fc2 2496
ef416fc2 2497
323c5de1 2498 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2499 {
2500 /*
2501 * Skip leading attributes until we hit a device...
2502 */
ef416fc2 2503
323c5de1 2504 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2505 attr = attr->next;
ef416fc2 2506
323c5de1 2507 if (!attr)
2508 break;
ef416fc2 2509
323c5de1 2510 /*
2511 * Pull the needed attributes from this device...
2512 */
ef416fc2 2513
323c5de1 2514 device_info = NULL;
2515 device_make_and_model = NULL;
2516 device_uri = NULL;
ef416fc2 2517
323c5de1 2518 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2519 {
2520 if (!strcmp(attr->name, "device-info") &&
2521 attr->value_tag == IPP_TAG_TEXT)
2522 device_info = attr->values[0].string.text;
ef416fc2 2523
323c5de1 2524 if (!strcmp(attr->name, "device-make-and-model") &&
2525 attr->value_tag == IPP_TAG_TEXT)
2526 device_make_and_model = attr->values[0].string.text;
ef416fc2 2527
323c5de1 2528 if (!strcmp(attr->name, "device-uri") &&
2529 attr->value_tag == IPP_TAG_URI)
2530 device_uri = attr->values[0].string.text;
ef416fc2 2531
323c5de1 2532 attr = attr->next;
2533 }
ef416fc2 2534
323c5de1 2535 /*
2536 * See if we have everything needed...
2537 */
ef416fc2 2538
323c5de1 2539 if (device_info && device_make_and_model && device_uri &&
2540 strcasecmp(device_make_and_model, "unknown") &&
2541 strchr(device_uri, ':'))
2542 {
2543 /*
2544 * Yes, now see if there is already a printer for this
2545 * device...
2546 */
ef416fc2 2547
323c5de1 2548 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2549 {
2550 /*
2551 * Not found, so it must be a new printer...
2552 */
ef416fc2 2553
2e4ff8af
MS
2554 char option[1024], /* Form variables for this device */
2555 *option_ptr; /* Pointer into string */
323c5de1 2556 const char *ptr; /* Pointer into device string */
ef416fc2 2557
fa73b229 2558
323c5de1 2559 /*
2560 * Format the printer name variable for this device...
2561 *
2562 * We use the device-info string first, then device-uri,
2563 * and finally device-make-and-model to come up with a
2564 * suitable name.
2565 */
ef416fc2 2566
323c5de1 2567 if (strncasecmp(device_info, "unknown", 7))
2568 ptr = device_info;
2569 else if ((ptr = strstr(device_uri, "://")) != NULL)
2570 ptr += 3;
2571 else
2572 ptr = device_make_and_model;
ef416fc2 2573
2e4ff8af
MS
2574 for (option_ptr = option;
2575 option_ptr < (option + sizeof(option) - 1) && *ptr;
323c5de1 2576 ptr ++)
2577 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2578 *ptr == '.')
2e4ff8af
MS
2579 *option_ptr++ = *ptr;
2580 else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_')
2581 *option_ptr++ = '_';
323c5de1 2582 else if (*ptr == '?' || *ptr == '(')
2583 break;
ef416fc2 2584
2e4ff8af 2585 *option_ptr = '\0';
ef416fc2 2586
2e4ff8af 2587 cgiSetArray("TEMPLATE_NAME", i, option);
ef416fc2 2588
323c5de1 2589 /*
2590 * Finally, set the form variables for this printer...
2591 */
ef416fc2 2592
323c5de1 2593 cgiSetArray("device_info", i, device_info);
2594 cgiSetArray("device_make_and_model", i, device_make_and_model);
323c5de1 2595 cgiSetArray("device_uri", i, device_uri);
2596 i ++;
2597 }
2598 }
ef416fc2 2599
323c5de1 2600 if (!attr)
2601 break;
2602 }
2603
2604 ippDelete(response);
ef416fc2 2605
ef416fc2 2606 /*
323c5de1 2607 * Free the device list...
ef416fc2 2608 */
2609
323c5de1 2610 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2611 printer_device;
2612 printer_device = (char *)cupsArrayNext(printer_devices))
2613 free(printer_device);
ef416fc2 2614
323c5de1 2615 cupsArrayDelete(printer_devices);
ef416fc2 2616 }
323c5de1 2617 }
ef416fc2 2618
323c5de1 2619 /*
2620 * Finally, show the printer list...
2621 */
ef416fc2 2622
323c5de1 2623 cgiCopyTemplateLang("list-available-printers.tmpl");
ef416fc2 2624
323c5de1 2625 cgiEndHTML();
ef416fc2 2626}
2627
2628
2629/*
749b1e90 2630 * 'do_menu()' - Show the main menu.
ef416fc2 2631 */
2632
2633static void
323c5de1 2634do_menu(http_t *http) /* I - HTTP connection */
ef416fc2 2635{
323c5de1 2636 int num_settings; /* Number of server settings */
2637 cups_option_t *settings; /* Server settings */
2638 const char *val; /* Setting value */
2639 char filename[1024]; /* Temporary filename */
2640 const char *datadir; /* Location of data files */
2641 ipp_t *request, /* IPP request */
2642 *response; /* IPP response */
ef416fc2 2643
2644
89d46774 2645 /*
323c5de1 2646 * Get the current server settings...
89d46774 2647 */
fa73b229 2648
323c5de1 2649 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
ef416fc2 2650 {
323c5de1 2651 cgiSetVariable("SETTINGS_MESSAGE",
2652 cgiText(_("Unable to open cupsd.conf file:")));
2653 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
ef416fc2 2654 }
2655
323c5de1 2656 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2657 settings)) != NULL && atoi(val))
2658 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
ef416fc2 2659
323c5de1 2660 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2661 settings)) != NULL && atoi(val))
2662 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
ef416fc2 2663
323c5de1 2664 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2665 settings)) != NULL && atoi(val))
2666 cgiSetVariable("REMOTE_ANY", "CHECKED");
ef416fc2 2667
323c5de1 2668 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2669 settings)) != NULL && atoi(val))
2670 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
ef416fc2 2671
323c5de1 2672 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2673 settings)) != NULL && atoi(val))
2674 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
ef416fc2 2675
323c5de1 2676 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2677 settings)) != NULL && atoi(val))
2678 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2679
2680#ifdef HAVE_GSSAPI
2681 cgiSetVariable("HAVE_GSSAPI", "1");
2682
2683 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2684 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2685 cgiSetVariable("KERBEROS", "CHECKED");
ef55b745 2686 else
323c5de1 2687#endif /* HAVE_GSSAPI */
ef55b745 2688 cgiSetVariable("KERBEROS", "");
323c5de1 2689
0af14961
MS
2690#ifdef HAVE_DNSSD
2691 cgiSetVariable("HAVE_DNSSD", "1");
2692#endif /* HAVE_DNSSD */
2693
2694#ifdef HAVE_LDAP
2695 cgiSetVariable("HAVE_LDAP", "1");
2696#endif /* HAVE_LDAP */
2697
2698#ifdef HAVE_LIBSLP
2699 cgiSetVariable("HAVE_LIBSLP", "1");
2700#endif /* HAVE_LIBSLP */
2701
2702 if ((val = cupsGetOption("BrowseRemoteProtocols", num_settings,
2703 settings)) == NULL)
2704 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2705 settings)) == NULL)
2706 val = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
2707
2708 if (strstr(val, "cups") || strstr(val, "CUPS"))
2709 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2710
2711 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2712 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2713
2714 if (strstr(val, "slp") || strstr(val, "SLP"))
2715 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2716
2717 if ((val = cupsGetOption("BrowseLocalProtocols", num_settings,
2718 settings)) == NULL)
2719 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2720 settings)) == NULL)
2721 val = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
2722
2723 if (strstr(val, "cups") || strstr(val, "CUPS"))
2724 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2725
2726 if (strstr(val, "dnssd") || strstr(val, "DNSSD") ||
2727 strstr(val, "dns-sd") || strstr(val, "DNS-SD") ||
2728 strstr(val, "bonjour") || strstr(val, "BONJOUR"))
2729 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2730
2731 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2732 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2733
2734 if (strstr(val, "slp") || strstr(val, "SLP"))
2735 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2736
2737 if ((val = cupsGetOption("BrowseWebIF", num_settings,
2738 settings)) == NULL)
2739 val = "No";
2740
2741 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2742 !strcasecmp(val, "true"))
2743 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2744
2745 if ((val = cupsGetOption("PreserveJobHistory", num_settings,
2746 settings)) == NULL)
2747 val = "Yes";
2748
2749 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2750 !strcasecmp(val, "true"))
2751 {
2752 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2753
2754 if ((val = cupsGetOption("PreserveJobFiles", num_settings,
2755 settings)) == NULL)
2756 val = "No";
2757
2758 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2759 !strcasecmp(val, "true"))
2760 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2761 }
2762
1f6f3dbc
MS
2763 if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
2764 val = "100";
2765
2766 cgiSetVariable("MAX_CLIENTS", val);
2767
0af14961
MS
2768 if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
2769 val = "500";
2770
2771 cgiSetVariable("MAX_JOBS", val);
2772
2773 if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
2774 val = "1m";
2775
2776 cgiSetVariable("MAX_LOG_SIZE", val);
2777
323c5de1 2778 cupsFreeOptions(num_settings, settings);
ef416fc2 2779
89d46774 2780 /*
323c5de1 2781 * See if Samba and the Windows drivers are installed...
89d46774 2782 */
2783
323c5de1 2784 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2785 datadir = CUPS_DATADIR;
2786
2787 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2788 if (!access(filename, R_OK))
f7deaa1a 2789 {
2790 /*
323c5de1 2791 * Found Windows 2000 driver file, see if we have smbclient and
2792 * rpcclient...
f7deaa1a 2793 */
2794
323c5de1 2795 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2796 sizeof(filename)) &&
2797 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2798 sizeof(filename)))
2799 cgiSetVariable("HAVE_SAMBA", "Y");
2800 else
2801 {
2802 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2803 sizeof(filename)))
2804 fputs("ERROR: smbclient not found!\n", stderr);
2805
2806 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2807 sizeof(filename)))
2808 fputs("ERROR: rpcclient not found!\n", stderr);
2809 }
f7deaa1a 2810 }
323c5de1 2811 else
2812 perror(filename);
f7deaa1a 2813
323c5de1 2814 /*
2815 * Subscriptions...
2816 */
89d46774 2817
323c5de1 2818 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2819
2820 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2821 NULL, "ipp://localhost/");
2822
2823 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2824 {
2825 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2826 ippDelete(response);
2827 }
2828
2829 /*
2830 * Finally, show the main menu template...
2831 */
2832
2833 cgiStartHTML(cgiText(_("Administration")));
2834
2835 cgiCopyTemplateLang("admin.tmpl");
ef416fc2 2836
2837 cgiEndHTML();
2838}
2839
2840
fa73b229 2841/*
323c5de1 2842 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
fa73b229 2843 */
2844
2845static void
323c5de1 2846do_set_allowed_users(http_t *http) /* I - HTTP connection */
fa73b229 2847{
323c5de1 2848 int i; /* Looping var */
fa73b229 2849 ipp_t *request, /* IPP request */
2850 *response; /* IPP response */
323c5de1 2851 char uri[HTTP_MAX_URI]; /* Printer URI */
2852 const char *printer, /* Printer name (purge-jobs) */
2853 *is_class, /* Is a class? */
2854 *users, /* List of users or groups */
2855 *type; /* Allow/deny type */
2856 int num_users; /* Number of users */
2857 char *ptr, /* Pointer into users string */
2858 *end, /* Pointer to end of users string */
2859 quote; /* Quote character */
2860 ipp_attribute_t *attr; /* Attribute */
2861 static const char * const attrs[] = /* Requested attributes */
2862 {
2863 "requesting-user-name-allowed",
2864 "requesting-user-name-denied"
2865 };
fa73b229 2866
fa73b229 2867
323c5de1 2868 is_class = cgiGetVariable("IS_CLASS");
2869 printer = cgiGetVariable("PRINTER_NAME");
fa73b229 2870
323c5de1 2871 if (!printer)
2872 {
4d301e69 2873 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
323c5de1 2874 cgiStartHTML(cgiText(_("Set Allowed Users")));
2875 cgiCopyTemplateLang("error.tmpl");
2876 cgiEndHTML();
2877 return;
2878 }
ef416fc2 2879
323c5de1 2880 users = cgiGetVariable("users");
2881 type = cgiGetVariable("type");
ef416fc2 2882
323c5de1 2883 if (!users || !type ||
2884 (strcmp(type, "requesting-user-name-allowed") &&
2885 strcmp(type, "requesting-user-name-denied")))
2886 {
2887 /*
2888 * Build a Get-Printer-Attributes request, which requires the following
2889 * attributes:
2890 *
2891 * attributes-charset
2892 * attributes-natural-language
2893 * printer-uri
2894 * requested-attributes
2895 */
fa73b229 2896
323c5de1 2897 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
fa73b229 2898
323c5de1 2899 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2900 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2901 printer);
2902 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2903 NULL, uri);
fa73b229 2904
323c5de1 2905 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2906 "requested-attributes",
2907 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
fa73b229 2908
323c5de1 2909 /*
2910 * Do the request and get back a response...
2911 */
fa73b229 2912
323c5de1 2913 if ((response = cupsDoRequest(http, request, "/")) != NULL)
fa73b229 2914 {
323c5de1 2915 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
fa73b229 2916
323c5de1 2917 ippDelete(response);
fa73b229 2918 }
ef416fc2 2919
323c5de1 2920 cgiStartHTML(cgiText(_("Set Allowed Users")));
757d2cad 2921
355e94dc
MS
2922 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2923 {
2924 puts("Status: 401\n");
2925 exit(0);
2926 }
2927 else if (cupsLastError() > IPP_OK_CONFLICT)
323c5de1 2928 cgiShowIPPError(_("Unable to get printer attributes:"));
2929 else
2930 cgiCopyTemplateLang("users.tmpl");
2931
2932 cgiEndHTML();
2933 }
2934 else
757d2cad 2935 {
2936 /*
323c5de1 2937 * Save the changes...
757d2cad 2938 */
2939
323c5de1 2940 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
757d2cad 2941 {
323c5de1 2942 /*
2943 * Skip whitespace and commas...
2944 */
fa73b229 2945
323c5de1 2946 while (*ptr == ',' || isspace(*ptr & 255))
2947 ptr ++;
ef416fc2 2948
1f6f3dbc
MS
2949 if (!*ptr)
2950 break;
2951
323c5de1 2952 if (*ptr == '\'' || *ptr == '\"')
2953 {
2954 /*
2955 * Scan quoted name...
2956 */
ef416fc2 2957
323c5de1 2958 quote = *ptr++;
ef416fc2 2959
323c5de1 2960 for (end = ptr; *end; end ++)
2961 if (*end == quote)
2962 break;
2963 }
2964 else
2965 {
2966 /*
2967 * Scan space or comma-delimited name...
2968 */
ef416fc2 2969
323c5de1 2970 for (end = ptr; *end; end ++)
2971 if (isspace(*end & 255) || *end == ',')
2972 break;
2973 }
ef416fc2 2974
323c5de1 2975 /*
2976 * Advance to the next name...
2977 */
ef416fc2 2978
323c5de1 2979 ptr = end;
2980 }
ef416fc2 2981
323c5de1 2982 /*
2983 * Build a CUPS-Add-Printer/Class request, which requires the following
2984 * attributes:
2985 *
2986 * attributes-charset
2987 * attributes-natural-language
2988 * printer-uri
2989 * requesting-user-name-{allowed,denied}
2990 */
ef416fc2 2991
323c5de1 2992 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 2993
323c5de1 2994 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2995 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2996 printer);
2997 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2998 NULL, uri);
f7deaa1a 2999
323c5de1 3000 if (num_users == 0)
3001 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3002 "requesting-user-name-allowed", NULL, "all");
3003 else
3004 {
3005 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3006 type, num_users, NULL, NULL);
ef416fc2 3007
323c5de1 3008 for (i = 0, ptr = (char *)users; *ptr; i ++)
3009 {
3010 /*
3011 * Skip whitespace and commas...
3012 */
ef416fc2 3013
323c5de1 3014 while (*ptr == ',' || isspace(*ptr & 255))
3015 ptr ++;
ef416fc2 3016
1f6f3dbc
MS
3017 if (!*ptr)
3018 break;
3019
323c5de1 3020 if (*ptr == '\'' || *ptr == '\"')
3021 {
3022 /*
3023 * Scan quoted name...
3024 */
7594b224 3025
323c5de1 3026 quote = *ptr++;
7594b224 3027
323c5de1 3028 for (end = ptr; *end; end ++)
3029 if (*end == quote)
3030 break;
3031 }
3032 else
3033 {
3034 /*
3035 * Scan space or comma-delimited name...
3036 */
480ef0fe 3037
323c5de1 3038 for (end = ptr; *end; end ++)
3039 if (isspace(*end & 255) || *end == ',')
3040 break;
3041 }
ef416fc2 3042
323c5de1 3043 /*
3044 * Terminate the name...
3045 */
ef416fc2 3046
323c5de1 3047 if (*end)
3048 *end++ = '\0';
ef416fc2 3049
323c5de1 3050 /*
3051 * Add the name...
3052 */
ef416fc2 3053
323c5de1 3054 attr->values[i].string.text = strdup(ptr);
ef416fc2 3055
323c5de1 3056 /*
3057 * Advance to the next name...
3058 */
ef416fc2 3059
323c5de1 3060 ptr = end;
3061 }
3062 }
ef416fc2 3063
3064 /*
323c5de1 3065 * Do the request and get back a response...
ef416fc2 3066 */
3067
323c5de1 3068 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 3069
355e94dc
MS
3070 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3071 {
3072 puts("Status: 401\n");
3073 exit(0);
3074 }
3075 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3076 {
323c5de1 3077 cgiStartHTML(cgiText(_("Set Allowed Users")));
3078 cgiShowIPPError(_("Unable to change printer:"));
ef416fc2 3079 }
323c5de1 3080 else
ef416fc2 3081 {
3082 /*
323c5de1 3083 * Redirect successful updates back to the printer page...
ef416fc2 3084 */
3085
323c5de1 3086 char url[1024], /* Printer/class URL */
3087 refresh[1024]; /* Refresh URL */
ef416fc2 3088
3089
323c5de1 3090 cgiRewriteURL(uri, url, sizeof(url), NULL);
3091 cgiFormEncode(uri, url, sizeof(uri));
3092 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
3093 uri);
3094 cgiSetVariable("refresh_page", refresh);
ef416fc2 3095
323c5de1 3096 cgiStartHTML(cgiText(_("Set Allowed Users")));
ef416fc2 3097
323c5de1 3098 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3099 "printer-modified.tmpl");
3100 }
ef416fc2 3101
323c5de1 3102 cgiEndHTML();
3103 }
3104}
ef416fc2 3105
ef416fc2 3106
58dc1933
MS
3107/*
3108 * 'do_set_default()' - Set the server default printer/class.
3109 */
3110
3111static void
3112do_set_default(http_t *http) /* I - HTTP connection */
3113{
3114 const char *title; /* Page title */
3115 ipp_t *request; /* IPP request */
3116 char uri[HTTP_MAX_URI]; /* Printer URI */
3117 const char *printer, /* Printer name (purge-jobs) */
3118 *is_class; /* Is a class? */
3119
3120
3121 is_class = cgiGetVariable("IS_CLASS");
3122 printer = cgiGetVariable("PRINTER_NAME");
3123 title = cgiText(_("Set As Server Default"));
3124
3125 if (!printer)
3126 {
4d301e69 3127 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
58dc1933
MS
3128 cgiStartHTML(title);
3129 cgiCopyTemplateLang("error.tmpl");
3130 cgiEndHTML();
3131 return;
3132 }
3133
3134 /*
3135 * Build a printer request, which requires the following
3136 * attributes:
3137 *
3138 * attributes-charset
3139 * attributes-natural-language
3140 * printer-uri
3141 */
3142
3143 request = ippNewRequest(CUPS_SET_DEFAULT);
3144
3145 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3146 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3147 printer);
3148 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3149 NULL, uri);
3150
3151 /*
3152 * Do the request and get back a response...
3153 */
3154
3155 ippDelete(cupsDoRequest(http, request, "/admin/"));
3156
3157 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3158 {
3159 puts("Status: 401\n");
3160 exit(0);
3161 }
3162 else if (cupsLastError() > IPP_OK_CONFLICT)
3163 {
3164 cgiStartHTML(title);
3165 cgiShowIPPError(_("Unable to set server default:"));
3166 }
3167 else
3168 {
3169 /*
3170 * Redirect successful updates back to the printer page...
3171 */
3172
3173 char url[1024], /* Printer/class URL */
3174 refresh[1024]; /* Refresh URL */
3175
3176
3177 cgiRewriteURL(uri, url, sizeof(url), NULL);
3178 cgiFormEncode(uri, url, sizeof(uri));
3179 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3180 cgiSetVariable("refresh_page", refresh);
3181
3182 cgiStartHTML(title);
3183 cgiCopyTemplateLang("printer-default.tmpl");
3184 }
3185
3186 cgiEndHTML();
3187}
3188
3189
323c5de1 3190/*
3191 * 'do_set_options()' - Configure the default options for a queue.
3192 */
ef416fc2 3193
323c5de1 3194static void
3195do_set_options(http_t *http, /* I - HTTP connection */
3196 int is_class) /* I - Set options for class? */
3197{
3198 int i, j, k, m; /* Looping vars */
3199 int have_options; /* Have options? */
3200 ipp_t *request, /* IPP request */
3201 *response; /* IPP response */
3202 ipp_attribute_t *attr; /* IPP attribute */
3203 char uri[HTTP_MAX_URI]; /* Job URI */
3204 const char *var; /* Variable value */
3205 const char *printer; /* Printer printer name */
3206 const char *filename; /* PPD filename */
3207 char tempfile[1024]; /* Temporary filename */
3208 cups_file_t *in, /* Input file */
3209 *out; /* Output file */
749b1e90
MS
3210 char line[1024], /* Line from PPD file */
3211 value[1024], /* Option value */
3212 keyword[1024], /* Keyword from Default line */
323c5de1 3213 *keyptr; /* Pointer into keyword... */
3214 ppd_file_t *ppd; /* PPD file */
3215 ppd_group_t *group; /* Option group */
3216 ppd_option_t *option; /* Option */
749b1e90
MS
3217 ppd_coption_t *coption; /* Custom option */
3218 ppd_cparam_t *cparam; /* Custom parameter */
1f6f3dbc 3219 ppd_attr_t *ppdattr; /* PPD attribute */
323c5de1 3220 const char *title; /* Page title */
ef416fc2 3221
ef416fc2 3222
323c5de1 3223 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
ef416fc2 3224
323c5de1 3225 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
3226 is_class);
ef416fc2 3227
323c5de1 3228 /*
3229 * Get the printer name...
3230 */
ef416fc2 3231
323c5de1 3232 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
3233 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3234 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3235 printer);
3236 else
3237 {
4d301e69 3238 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
323c5de1 3239 cgiStartHTML(title);
3240 cgiCopyTemplateLang("error.tmpl");
3241 cgiEndHTML();
3242 return;
3243 }
ef416fc2 3244
323c5de1 3245 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
ef416fc2 3246
1f6f3dbc
MS
3247 /*
3248 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3249 * command file to the printer...
3250 */
3251
3252 if (cgiGetVariable("AUTOCONFIGURE"))
3253 {
58dc1933 3254 cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
1f6f3dbc
MS
3255 return;
3256 }
3257
323c5de1 3258 /*
3259 * Get the PPD file...
3260 */
ef416fc2 3261
323c5de1 3262 if (is_class)
3263 filename = NULL;
3264 else
3265 filename = cupsGetPPD2(http, printer);
ef416fc2 3266
323c5de1 3267 if (filename)
3268 {
3269 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
ef416fc2 3270
323c5de1 3271 if ((ppd = ppdOpenFile(filename)) == NULL)
3272 {
3273 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
3274 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3275 cgiStartHTML(title);
3276 cgiCopyTemplateLang("error.tmpl");
3277 cgiEndHTML();
3278 return;
3279 }
3280 }
3281 else
3282 {
3283 fputs("DEBUG: No PPD file\n", stderr);
3284 ppd = NULL;
3285 }
ef416fc2 3286
323c5de1 3287 if (cgiGetVariable("job_sheets_start") != NULL ||
3288 cgiGetVariable("job_sheets_end") != NULL)
3289 have_options = 1;
3290 else
3291 have_options = 0;
ef416fc2 3292
323c5de1 3293 if (ppd)
3294 {
3295 ppdMarkDefaults(ppd);
ef416fc2 3296
749b1e90
MS
3297 for (option = ppdFirstOption(ppd);
3298 option;
3299 option = ppdNextOption(ppd))
ef55b745 3300 {
749b1e90
MS
3301 if ((var = cgiGetVariable(option->keyword)) != NULL)
3302 {
3303 have_options = 1;
3304 ppdMarkOption(ppd, option->keyword, var);
ef55b745 3305 fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var);
749b1e90 3306 }
ef55b745
MS
3307 else
3308 fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword);
3309 }
323c5de1 3310 }
fa73b229 3311
323c5de1 3312 if (!have_options || ppdConflicts(ppd))
fa73b229 3313 {
3314 /*
323c5de1 3315 * Show the options to the user...
fa73b229 3316 */
3317
323c5de1 3318 fputs("DEBUG: Showing options...\n", stderr);
fa73b229 3319
58dc1933
MS
3320 /*
3321 * Show auto-configure button if supported...
3322 */
3323
1f6f3dbc
MS
3324 if (ppd)
3325 {
3326 if (ppd->num_filters == 0 ||
3327 ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
3328 ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
3329 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
ef55b745 3330 else
1f6f3dbc
MS
3331 {
3332 for (i = 0; i < ppd->num_filters; i ++)
3333 if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
3334 {
3335 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3336 break;
3337 }
3338 }
3339 }
3340
58dc1933
MS
3341 /*
3342 * Get the printer attributes...
3343 */
3344
3345 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
3346
3347 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3348 "localhost", 0, "/printers/%s", printer);
3349 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3350 NULL, uri);
3351
3352 response = cupsDoRequest(http, request, "/");
3353
3354 /*
3355 * List the groups used as "tabs"...
3356 */
3357
3358 i = 0;
3359
3360 if (ppd)
3361 {
3362 for (group = ppd->groups;
3363 i < ppd->num_groups;
3364 i ++, group ++)
3365 {
3366 cgiSetArray("GROUP_ID", i, group->name);
3367
3368 if (!strcmp(group->name, "InstallableOptions"))
3369 cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
3370 else
3371 cgiSetArray("GROUP", i, group->text);
3372 }
3373 }
3374
3375 if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
3376 {
3377 cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
3378 cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
3379 }
3380
3381 if (ippFindAttribute(response, "printer-error-policy-supported",
3382 IPP_TAG_ZERO) ||
3383 ippFindAttribute(response, "printer-op-policy-supported",
3384 IPP_TAG_ZERO))
3385 {
3386 cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
3387 cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
3388 }
3389
3390 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3391 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
3392 {
3393 cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
3394 cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
3395 }
3396
323c5de1 3397 cgiStartHTML(cgiText(_("Set Printer Options")));
3398 cgiCopyTemplateLang("set-printer-options-header.tmpl");
fa73b229 3399
323c5de1 3400 if (ppd)
3401 {
3402 ppdLocalize(ppd);
f7deaa1a 3403
323c5de1 3404 if (ppdConflicts(ppd))
3405 {
3406 for (i = ppd->num_groups, k = 0, group = ppd->groups;
3407 i > 0;
3408 i --, group ++)
3409 for (j = group->num_options, option = group->options;
3410 j > 0;
3411 j --, option ++)
3412 if (option->conflicted)
3413 {
3414 cgiSetArray("ckeyword", k, option->keyword);
3415 cgiSetArray("ckeytext", k, option->text);
ef55b745
MS
3416
3417 for (m = 0; m < option->num_choices; m ++)
3418 {
3419 if (option->choices[m].marked)
3420 {
3421 cgiSetArray("cchoice", k, option->choices[m].text);
3422 break;
3423 }
3424 }
3425
323c5de1 3426 k ++;
3427 }
f7deaa1a 3428
323c5de1 3429 cgiCopyTemplateLang("option-conflict.tmpl");
3430 }
f7deaa1a 3431
323c5de1 3432 for (i = ppd->num_groups, group = ppd->groups;
3433 i > 0;
3434 i --, group ++)
3435 {
58dc1933
MS
3436 cgiSetVariable("GROUP_ID", group->name);
3437
323c5de1 3438 if (!strcmp(group->name, "InstallableOptions"))
3439 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3440 else
3441 cgiSetVariable("GROUP", group->text);
f7deaa1a 3442
323c5de1 3443 cgiCopyTemplateLang("option-header.tmpl");
ef55b745 3444
323c5de1 3445 for (j = group->num_options, option = group->options;
3446 j > 0;
3447 j --, option ++)
3448 {
3449 if (!strcmp(option->keyword, "PageRegion"))
3450 continue;
ef416fc2 3451
323c5de1 3452 cgiSetVariable("KEYWORD", option->keyword);
3453 cgiSetVariable("KEYTEXT", option->text);
749b1e90 3454
323c5de1 3455 if (option->conflicted)
3456 cgiSetVariable("CONFLICTED", "1");
3457 else
3458 cgiSetVariable("CONFLICTED", "0");
3459
3460 cgiSetSize("CHOICES", 0);
3461 cgiSetSize("TEXT", 0);
3462 for (k = 0, m = 0; k < option->num_choices; k ++)
3463 {
323c5de1 3464 cgiSetArray("CHOICES", m, option->choices[k].choice);
3465 cgiSetArray("TEXT", m, option->choices[k].text);
ef416fc2 3466
323c5de1 3467 m ++;
ef416fc2 3468
323c5de1 3469 if (option->choices[k].marked)
3470 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
3471 }
ef416fc2 3472
749b1e90
MS
3473 cgiSetSize("PARAMS", 0);
3474 cgiSetSize("PARAMTEXT", 0);
3475 cgiSetSize("PARAMVALUE", 0);
3476 cgiSetSize("INPUTTYPE", 0);
3477
3478 if ((coption = ppdFindCustomOption(ppd, option->keyword)))
3479 {
3480 const char *units = NULL; /* Units value, if any */
3481
3482
3483 cgiSetVariable("ISCUSTOM", "1");
3484
3485 for (cparam = ppdFirstCustomParam(coption), m = 0;
3486 cparam;
3487 cparam = ppdNextCustomParam(coption), m ++)
3488 {
3489 if (!strcasecmp(option->keyword, "PageSize") &&
3490 strcasecmp(cparam->name, "Width") &&
3491 strcasecmp(cparam->name, "Height"))
3492 {
3493 m --;
3494 continue;
3495 }
3496
3497 cgiSetArray("PARAMS", m, cparam->name);
3498 cgiSetArray("PARAMTEXT", m, cparam->text);
3499 cgiSetArray("INPUTTYPE", m, "text");
3500
3501 switch (cparam->type)
3502 {
3503 case PPD_CUSTOM_POINTS :
3504 if (!strncasecmp(option->defchoice, "Custom.", 7))
3505 {
3506 units = option->defchoice + strlen(option->defchoice) - 2;
3507
3508 if (strcmp(units, "mm") && strcmp(units, "cm") &&
3509 strcmp(units, "in") && strcmp(units, "ft"))
3510 {
3511 if (units[1] == 'm')
3512 units ++;
3513 else
3514 units = "pt";
3515 }
3516 }
3517 else
3518 units = "pt";
3519
3520 if (!strcmp(units, "mm"))
3521 snprintf(value, sizeof(value), "%g",
3522 cparam->current.custom_points / 72.0 * 25.4);
3523 else if (!strcmp(units, "cm"))
3524 snprintf(value, sizeof(value), "%g",
3525 cparam->current.custom_points / 72.0 * 2.54);
3526 else if (!strcmp(units, "in"))
3527 snprintf(value, sizeof(value), "%g",
3528 cparam->current.custom_points / 72.0);
3529 else if (!strcmp(units, "ft"))
3530 snprintf(value, sizeof(value), "%g",
3531 cparam->current.custom_points / 72.0 / 12.0);
3532 else if (!strcmp(units, "m"))
3533 snprintf(value, sizeof(value), "%g",
3534 cparam->current.custom_points / 72.0 * 0.0254);
3535 else
3536 snprintf(value, sizeof(value), "%g",
3537 cparam->current.custom_points);
3538 cgiSetArray("PARAMVALUE", m, value);
3539 break;
3540
3541 case PPD_CUSTOM_CURVE :
3542 case PPD_CUSTOM_INVCURVE :
3543 case PPD_CUSTOM_REAL :
3544 snprintf(value, sizeof(value), "%g",
3545 cparam->current.custom_real);
3546 cgiSetArray("PARAMVALUE", m, value);
3547 break;
3548
3549 case PPD_CUSTOM_INT:
3550 snprintf(value, sizeof(value), "%d",
3551 cparam->current.custom_int);
3552 cgiSetArray("PARAMVALUE", m, value);
3553 break;
3554
3555 case PPD_CUSTOM_PASSCODE:
3556 case PPD_CUSTOM_PASSWORD:
3557 if (cparam->current.custom_password)
3558 cgiSetArray("PARAMVALUE", m,
3559 cparam->current.custom_password);
3560 else
3561 cgiSetArray("PARAMVALUE", m, "");
3562 cgiSetArray("INPUTTYPE", m, "password");
3563 break;
3564
3565 case PPD_CUSTOM_STRING:
3566 if (cparam->current.custom_string)
3567 cgiSetArray("PARAMVALUE", m,
3568 cparam->current.custom_string);
3569 else
3570 cgiSetArray("PARAMVALUE", m, "");
3571 break;
3572 }
3573 }
3574
3575 if (units)
3576 {
3577 cgiSetArray("PARAMS", m, "Units");
3578 cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
3579 cgiSetArray("PARAMVALUE", m, units);
3580 }
3581 }
3582 else
3583 cgiSetVariable("ISCUSTOM", "0");
3584
323c5de1 3585 switch (option->ui)
3586 {
3587 case PPD_UI_BOOLEAN :
3588 cgiCopyTemplateLang("option-boolean.tmpl");
3589 break;
3590 case PPD_UI_PICKONE :
3591 cgiCopyTemplateLang("option-pickone.tmpl");
3592 break;
3593 case PPD_UI_PICKMANY :
3594 cgiCopyTemplateLang("option-pickmany.tmpl");
3595 break;
3596 }
3597 }
ef416fc2 3598
323c5de1 3599 cgiCopyTemplateLang("option-trailer.tmpl");
3600 }
3601 }
ef416fc2 3602
58dc1933
MS
3603 if ((attr = ippFindAttribute(response, "job-sheets-supported",
3604 IPP_TAG_ZERO)) != NULL)
3605 {
3606 /*
3607 * Add the job sheets options...
3608 */
fa73b229 3609
58dc1933
MS
3610 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3611 cgiSetVariable("GROUP", cgiText(_("Banners")));
3612 cgiCopyTemplateLang("option-header.tmpl");
ef416fc2 3613
58dc1933
MS
3614 cgiSetSize("CHOICES", attr->num_values);
3615 cgiSetSize("TEXT", attr->num_values);
3616 for (k = 0; k < attr->num_values; k ++)
3617 {
3618 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3619 cgiSetArray("TEXT", k, attr->values[k].string.text);
3620 }
ef416fc2 3621
58dc1933 3622 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
ef416fc2 3623
58dc1933
MS
3624 cgiSetVariable("KEYWORD", "job_sheets_start");
3625 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3626 cgiSetVariable("DEFCHOICE", attr != NULL ?
3627 attr->values[0].string.text : "");
3628
3629 cgiCopyTemplateLang("option-pickone.tmpl");
3630
3631 cgiSetVariable("KEYWORD", "job_sheets_end");
3632 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3633 cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
3634 attr->values[1].string.text : "");
3635
3636 cgiCopyTemplateLang("option-pickone.tmpl");
3637
3638 cgiCopyTemplateLang("option-trailer.tmpl");
3639 }
3640
3641 if (ippFindAttribute(response, "printer-error-policy-supported",
3642 IPP_TAG_ZERO) ||
3643 ippFindAttribute(response, "printer-op-policy-supported",
3644 IPP_TAG_ZERO))
323c5de1 3645 {
58dc1933
MS
3646 /*
3647 * Add the error and operation policy options...
3648 */
ef416fc2 3649
58dc1933
MS
3650 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3651 cgiSetVariable("GROUP", cgiText(_("Policies")));
3652 cgiCopyTemplateLang("option-header.tmpl");
3653
3654 /*
3655 * Error policy...
3656 */
ef416fc2 3657
58dc1933
MS
3658 attr = ippFindAttribute(response, "printer-error-policy-supported",
3659 IPP_TAG_ZERO);
3660
3661 if (attr)
3662 {
323c5de1 3663 cgiSetSize("CHOICES", attr->num_values);
3664 cgiSetSize("TEXT", attr->num_values);
3665 for (k = 0; k < attr->num_values; k ++)
3666 {
3667 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3668 cgiSetArray("TEXT", k, attr->values[k].string.text);
3669 }
ef416fc2 3670
58dc1933
MS
3671 attr = ippFindAttribute(response, "printer-error-policy",
3672 IPP_TAG_ZERO);
ef416fc2 3673
58dc1933
MS
3674 cgiSetVariable("KEYWORD", "printer_error_policy");
3675 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3676 cgiSetVariable("DEFCHOICE", attr == NULL ?
3677 "" : attr->values[0].string.text);
323c5de1 3678 }
ef416fc2 3679
58dc1933 3680 cgiCopyTemplateLang("option-pickone.tmpl");
ef416fc2 3681
58dc1933
MS
3682 /*
3683 * Operation policy...
3684 */
ef416fc2 3685
58dc1933
MS
3686 attr = ippFindAttribute(response, "printer-op-policy-supported",
3687 IPP_TAG_ZERO);
323c5de1 3688
58dc1933
MS
3689 if (attr)
3690 {
3691 cgiSetSize("CHOICES", attr->num_values);
3692 cgiSetSize("TEXT", attr->num_values);
3693 for (k = 0; k < attr->num_values; k ++)
323c5de1 3694 {
58dc1933
MS
3695 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3696 cgiSetArray("TEXT", k, attr->values[k].string.text);
3697 }
ef416fc2 3698
58dc1933 3699 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
ef416fc2 3700
58dc1933
MS
3701 cgiSetVariable("KEYWORD", "printer_op_policy");
3702 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3703 cgiSetVariable("DEFCHOICE", attr == NULL ?
3704 "" : attr->values[0].string.text);
fa73b229 3705
323c5de1 3706 cgiCopyTemplateLang("option-pickone.tmpl");
323c5de1 3707 }
ef416fc2 3708
58dc1933 3709 cgiCopyTemplateLang("option-trailer.tmpl");
ef416fc2 3710 }
ef416fc2 3711
ef416fc2 3712 /*
323c5de1 3713 * Binary protocol support...
ef416fc2 3714 */
3715
58dc1933
MS
3716 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3717 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
ef416fc2 3718 {
58dc1933
MS
3719 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3720 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
ef416fc2 3721
58dc1933
MS
3722 cgiSetSize("CHOICES", attr->num_values);
3723 cgiSetSize("TEXT", attr->num_values);
ef416fc2 3724
58dc1933 3725 for (i = 0; i < attr->num_values; i ++)
ef416fc2 3726 {
58dc1933
MS
3727 cgiSetArray("CHOICES", i, attr->values[i].string.text);
3728 cgiSetArray("TEXT", i, attr->values[i].string.text);
ef416fc2 3729 }
3730
58dc1933
MS
3731 attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
3732 cgiSetVariable("KEYWORD", "port_monitor");
3733 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3734 cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
ef416fc2 3735
58dc1933 3736 cgiCopyTemplateLang("option-header.tmpl");
323c5de1 3737 cgiCopyTemplateLang("option-pickone.tmpl");
323c5de1 3738 cgiCopyTemplateLang("option-trailer.tmpl");
ef416fc2 3739 }
3740
323c5de1 3741 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3742 cgiEndHTML();
58dc1933
MS
3743
3744 ippDelete(response);
323c5de1 3745 }
3746 else
3747 {
ef416fc2 3748 /*
323c5de1 3749 * Set default options...
ef416fc2 3750 */
3751
323c5de1 3752 fputs("DEBUG: Setting options...\n", stderr);
ef416fc2 3753
323c5de1 3754 if (filename)
ef416fc2 3755 {
323c5de1 3756 out = cupsTempFile2(tempfile, sizeof(tempfile));
3757 in = cupsFileOpen(filename, "r");
ef416fc2 3758
323c5de1 3759 if (!in || !out)
ef416fc2 3760 {
323c5de1 3761 cgiSetVariable("ERROR", strerror(errno));
3762 cgiStartHTML(cgiText(_("Set Printer Options")));
3763 cgiCopyTemplateLang("error.tmpl");
3764 cgiEndHTML();
ef416fc2 3765
323c5de1 3766 if (in)
3767 cupsFileClose(in);
ef416fc2 3768
323c5de1 3769 if (out)
ef416fc2 3770 {
323c5de1 3771 cupsFileClose(out);
3772 unlink(tempfile);
3773 }
ef416fc2 3774
323c5de1 3775 unlink(filename);
3776 return;
3777 }
ef416fc2 3778
323c5de1 3779 while (cupsFileGets(in, line, sizeof(line)))
3780 {
58dc1933 3781 if (!strncmp(line, "*cupsProtocol:", 14))
323c5de1 3782 continue;
3783 else if (strncmp(line, "*Default", 8))
3784 cupsFilePrintf(out, "%s\n", line);
ef416fc2 3785 else
3786 {
3787 /*
323c5de1 3788 * Get default option name...
ef416fc2 3789 */
3790
323c5de1 3791 strlcpy(keyword, line + 8, sizeof(keyword));
3792
3793 for (keyptr = keyword; *keyptr; keyptr ++)
3794 if (*keyptr == ':' || isspace(*keyptr & 255))
ef416fc2 3795 break;
ef416fc2 3796
323c5de1 3797 *keyptr = '\0';
ef416fc2 3798
323c5de1 3799 if (!strcmp(keyword, "PageRegion") ||
3800 !strcmp(keyword, "PaperDimension") ||
3801 !strcmp(keyword, "ImageableArea"))
749b1e90 3802 var = get_option_value(ppd, "PageSize", value, sizeof(value));
323c5de1 3803 else
749b1e90 3804 var = get_option_value(ppd, keyword, value, sizeof(value));
ef416fc2 3805
749b1e90 3806 if (!var)
323c5de1 3807 cupsFilePrintf(out, "%s\n", line);
749b1e90
MS
3808 else
3809 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
323c5de1 3810 }
3811 }
ef416fc2 3812
323c5de1 3813 cupsFileClose(in);
3814 cupsFileClose(out);
3815 }
3816 else
3817 {
3818 /*
3819 * Make sure temporary filename is cleared when there is no PPD...
3820 */
ef416fc2 3821
323c5de1 3822 tempfile[0] = '\0';
ef416fc2 3823 }
3824
323c5de1 3825 /*
3826 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3827 * following attributes:
3828 *
3829 * attributes-charset
3830 * attributes-natural-language
3831 * printer-uri
3832 * job-sheets-default
3833 * printer-error-policy
3834 * printer-op-policy
3835 * [ppd file]
3836 */
3837
3838 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3839 CUPS_ADD_MODIFY_PRINTER);
3840
3841 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3842 NULL, uri);
3843
3844 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3845 "job-sheets-default", 2, NULL, NULL);
3846 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3847 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3848
3849 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
1f0275e3
MS
3850 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3851 "printer-error-policy", NULL, var);
323c5de1 3852
3853 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
1f0275e3
MS
3854 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3855 "printer-op-policy", NULL, var);
323c5de1 3856
58dc1933
MS
3857 if ((var = cgiGetVariable("port_monitor")) != NULL)
3858 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3859 "port-monitor", NULL, var);
3860
ef416fc2 3861 /*
3862 * Do the request and get back a response...
3863 */
3864
323c5de1 3865 if (filename)
3866 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3867 else
3868 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 3869
355e94dc
MS
3870 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3871 {
3872 puts("Status: 401\n");
3873 exit(0);
3874 }
3875 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3876 {
323c5de1 3877 cgiStartHTML(title);
3878 cgiShowIPPError(_("Unable to set options:"));
ef416fc2 3879 }
3880 else
3881 {
3882 /*
3883 * Redirect successful updates back to the printer page...
3884 */
3885
323c5de1 3886 char refresh[1024]; /* Refresh URL */
ef416fc2 3887
fa73b229 3888
323c5de1 3889 cgiFormEncode(uri, printer, sizeof(uri));
3890 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3891 is_class ? "classes" : "printers", uri);
ef416fc2 3892 cgiSetVariable("refresh_page", refresh);
3893
323c5de1 3894 cgiStartHTML(title);
ef416fc2 3895
323c5de1 3896 cgiCopyTemplateLang("printer-configured.tmpl");
ef416fc2 3897 }
3898
3899 cgiEndHTML();
323c5de1 3900
3901 if (filename)
3902 unlink(tempfile);
ef416fc2 3903 }
323c5de1 3904
3905 if (filename)
3906 unlink(filename);
ef416fc2 3907}
3908
3909
3910/*
749b1e90 3911 * 'do_set_sharing()' - Set printer-is-shared value.
ef416fc2 3912 */
3913
3914static void
fa73b229 3915do_set_sharing(http_t *http) /* I - HTTP connection */
ef416fc2 3916{
3917 ipp_t *request, /* IPP request */
3918 *response; /* IPP response */
3919 char uri[HTTP_MAX_URI]; /* Printer URI */
3920 const char *printer, /* Printer name */
fa73b229 3921 *is_class, /* Is a class? */
ef416fc2 3922 *shared; /* Sharing value */
ef416fc2 3923
3924
fa73b229 3925 is_class = cgiGetVariable("IS_CLASS");
3926 printer = cgiGetVariable("PRINTER_NAME");
3927 shared = cgiGetVariable("SHARED");
ef416fc2 3928
fa73b229 3929 if (!printer || !shared)
ef416fc2 3930 {
4d301e69 3931 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
fa73b229 3932 cgiStartHTML(cgiText(_("Set Publishing")));
ef416fc2 3933 cgiCopyTemplateLang("error.tmpl");
3934 cgiEndHTML();
3935 return;
3936 }
3937
3938 /*
fa73b229 3939 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3940 * following attributes:
ef416fc2 3941 *
3942 * attributes-charset
3943 * attributes-natural-language
3944 * printer-uri
3945 * printer-is-shared
3946 */
3947
fa73b229 3948 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 3949
a4d04587 3950 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3951 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3952 printer);
ef416fc2 3953 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3954 NULL, uri);
3955
3956 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3957
3958 /*
3959 * Do the request and get back a response...
3960 */
3961
3962 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3963 {
ef416fc2 3964 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3965
3966 ippDelete(response);
3967 }
ef416fc2 3968
355e94dc
MS
3969 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3970 {
3971 puts("Status: 401\n");
3972 exit(0);
3973 }
3974 else if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3975 {
fa73b229 3976 cgiStartHTML(cgiText(_("Set Publishing")));
3977 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
ef416fc2 3978 }
3979 else
3980 {
3981 /*
3982 * Redirect successful updates back to the printer page...
3983 */
3984
fa73b229 3985 char url[1024], /* Printer/class URL */
3986 refresh[1024]; /* Refresh URL */
ef416fc2 3987
ef416fc2 3988
fa73b229 3989 cgiRewriteURL(uri, url, sizeof(url), NULL);
3990 cgiFormEncode(uri, url, sizeof(uri));
f301802f 3991 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
fa73b229 3992 cgiSetVariable("refresh_page", refresh);
ef416fc2 3993
fa73b229 3994 cgiStartHTML(cgiText(_("Set Publishing")));
3995 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3996 "printer-modified.tmpl");
ef416fc2 3997 }
3998
3999 cgiEndHTML();
4000}
4001
4002
749b1e90
MS
4003/*
4004 * 'get_option_value()' - Return the value of an option.
4005 *
4006 * This function also handles generation of custom option values.
4007 */
4008
4009static char * /* O - Value string or NULL on error */
4010get_option_value(
4011 ppd_file_t *ppd, /* I - PPD file */
4012 const char *name, /* I - Option name */
4013 char *buffer, /* I - String buffer */
4014 size_t bufsize) /* I - Size of buffer */
4015{
4016 char *bufptr, /* Pointer into buffer */
4017 *bufend; /* End of buffer */
4018 ppd_coption_t *coption; /* Custom option */
4019 ppd_cparam_t *cparam; /* Current custom parameter */
4020 char keyword[256]; /* Parameter name */
4021 const char *val, /* Parameter value */
4022 *uval; /* Units value */
4023 long integer; /* Integer value */
4024 double number, /* Number value */
4025 number_points; /* Number in points */
4026
4027
4028 /*
4029 * See if we have a custom option choice...
4030 */
4031
4032 if ((val = cgiGetVariable(name)) == NULL)
4033 {
4034 /*
4035 * Option not found!
4036 */
4037
4038 return (NULL);
4039 }
4040 else if (strcasecmp(val, "Custom") ||
4041 (coption = ppdFindCustomOption(ppd, name)) == NULL)
4042 {
4043 /*
4044 * Not a custom choice...
4045 */
4046
4047 strlcpy(buffer, val, bufsize);
4048 return (buffer);
4049 }
4050
4051 /*
4052 * OK, we have a custom option choice, format it...
4053 */
4054
4055 *buffer = '\0';
4056
4057 if (!strcmp(coption->keyword, "PageSize"))
4058 {
4059 const char *lval; /* Length string value */
4060 double width, /* Width value */
4061 width_points, /* Width in points */
4062 length, /* Length value */
4063 length_points; /* Length in points */
4064
4065
4066 val = cgiGetVariable("PageSize.Width");
4067 lval = cgiGetVariable("PageSize.Height");
4068 uval = cgiGetVariable("PageSize.Units");
4069
4070 if (!val || !lval || !uval ||
4071 (width = strtod(val, NULL)) == 0.0 ||
4072 (length = strtod(lval, NULL)) == 0.0 ||
4073 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
4074 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
4075 return (NULL);
4076
4077 width_points = get_points(width, uval);
4078 length_points = get_points(length, uval);
4079
4080 if (width_points < ppd->custom_min[0] ||
4081 width_points > ppd->custom_max[0] ||
4082 length_points < ppd->custom_min[1] ||
4083 length_points > ppd->custom_max[1])
4084 return (NULL);
4085
4086 snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
4087 }
ef55b745 4088 else if (cupsArrayCount(coption->params) == 1)
749b1e90
MS
4089 {
4090 cparam = ppdFirstCustomParam(coption);
4091 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
4092
4093 if ((val = cgiGetVariable(keyword)) == NULL)
4094 return (NULL);
4095
4096 switch (cparam->type)
4097 {
4098 case PPD_CUSTOM_CURVE :
4099 case PPD_CUSTOM_INVCURVE :
4100 case PPD_CUSTOM_REAL :
4101 if ((number = strtod(val, NULL)) == 0.0 ||
4102 number < cparam->minimum.custom_real ||
4103 number > cparam->maximum.custom_real)
4104 return (NULL);
4105
4106 snprintf(buffer, bufsize, "Custom.%g", number);
4107 break;
4108
4109 case PPD_CUSTOM_INT :
4110 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4111 integer == LONG_MAX ||
4112 integer < cparam->minimum.custom_int ||
4113 integer > cparam->maximum.custom_int)
4114 return (NULL);
4115
4116 snprintf(buffer, bufsize, "Custom.%ld", integer);
4117 break;
4118
4119 case PPD_CUSTOM_POINTS :
4120 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4121
4122 if ((number = strtod(val, NULL)) == 0.0 ||
4123 (uval = cgiGetVariable(keyword)) == NULL ||
4124 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
4125 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
4126 return (NULL);
4127
4128 number_points = get_points(number, uval);
4129 if (number_points < cparam->minimum.custom_points ||
4130 number_points > cparam->maximum.custom_points)
4131 return (NULL);
4132
4133 snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
4134 break;
4135
4136 case PPD_CUSTOM_PASSCODE :
4137 for (uval = val; *uval; uval ++)
4138 if (!isdigit(*uval & 255))
4139 return (NULL);
4140
4141 case PPD_CUSTOM_PASSWORD :
4142 case PPD_CUSTOM_STRING :
4143 integer = (long)strlen(val);
4144 if (integer < cparam->minimum.custom_string ||
4145 integer > cparam->maximum.custom_string)
4146 return (NULL);
4147
4148 snprintf(buffer, bufsize, "Custom.%s", val);
4149 break;
4150 }
4151 }
4152 else
4153 {
4154 const char *prefix = "{"; /* Prefix string */
4155
4156
4157 bufptr = buffer;
4158 bufend = buffer + bufsize;
4159
4160 for (cparam = ppdFirstCustomParam(coption);
4161 cparam;
4162 cparam = ppdNextCustomParam(coption))
4163 {
4164 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
4165 cparam->name);
4166
4167 if ((val = cgiGetVariable(keyword)) == NULL)
4168 return (NULL);
4169
4170 snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
4171 bufptr += strlen(bufptr);
4172 prefix = " ";
4173
4174 switch (cparam->type)
4175 {
4176 case PPD_CUSTOM_CURVE :
4177 case PPD_CUSTOM_INVCURVE :
4178 case PPD_CUSTOM_REAL :
4179 if ((number = strtod(val, NULL)) == 0.0 ||
4180 number < cparam->minimum.custom_real ||
4181 number > cparam->maximum.custom_real)
4182 return (NULL);
4183
4184 snprintf(bufptr, bufend - bufptr, "%g", number);
4185 break;
4186
4187 case PPD_CUSTOM_INT :
4188 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4189 integer == LONG_MAX ||
4190 integer < cparam->minimum.custom_int ||
4191 integer > cparam->maximum.custom_int)
4192 return (NULL);
4193
4194 snprintf(bufptr, bufend - bufptr, "%ld", integer);
4195 break;
4196
4197 case PPD_CUSTOM_POINTS :
4198 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4199
4200 if ((number = strtod(val, NULL)) == 0.0 ||
4201 (uval = cgiGetVariable(keyword)) == NULL ||
4202 (strcmp(uval, "pt") && strcmp(uval, "in") &&
4203 strcmp(uval, "ft") && strcmp(uval, "cm") &&
4204 strcmp(uval, "mm") && strcmp(uval, "m")))
4205 return (NULL);
4206
4207 number_points = get_points(number, uval);
4208 if (number_points < cparam->minimum.custom_points ||
4209 number_points > cparam->maximum.custom_points)
4210 return (NULL);
4211
4212 snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
4213 break;
4214
4215 case PPD_CUSTOM_PASSCODE :
4216 for (uval = val; *uval; uval ++)
4217 if (!isdigit(*uval & 255))
4218 return (NULL);
4219
4220 case PPD_CUSTOM_PASSWORD :
4221 case PPD_CUSTOM_STRING :
4222 integer = (long)strlen(val);
4223 if (integer < cparam->minimum.custom_string ||
4224 integer > cparam->maximum.custom_string)
4225 return (NULL);
4226
4227 if ((bufptr + 2) > bufend)
4228 return (NULL);
4229
4230 bufend --;
4231 *bufptr++ = '\"';
4232
4233 while (*val && bufptr < bufend)
4234 {
4235 if (*val == '\\' || *val == '\"')
4236 {
4237 if ((bufptr + 1) >= bufend)
4238 return (NULL);
4239
4240 *bufptr++ = '\\';
4241 }
4242
4243 *bufptr++ = *val++;
4244 }
4245
4246 if (bufptr >= bufend)
4247 return (NULL);
4248
4249 *bufptr++ = '\"';
4250 *bufptr = '\0';
4251 bufend ++;
4252 break;
4253 }
4254
4255 bufptr += strlen(bufptr);
4256 }
4257
4258 if (bufptr == buffer || (bufend - bufptr) < 2)
4259 return (NULL);
4260
4261 strcpy(bufptr, "}");
4262 }
4263
4264 return (buffer);
4265}
4266
4267
4268/*
4269 * 'get_points()' - Get a value in points.
4270 */
4271
4272static double /* O - Number in points */
4273get_points(double number, /* I - Original number */
4274 const char *uval) /* I - Units */
4275{
4276 if (!strcmp(uval, "mm")) /* Millimeters */
4277 return (number * 72.0 / 25.4);
4278 else if (!strcmp(uval, "cm")) /* Centimeters */
4279 return (number * 72.0 / 2.54);
4280 else if (!strcmp(uval, "in")) /* Inches */
4281 return (number * 72.0);
4282 else if (!strcmp(uval, "ft")) /* Feet */
4283 return (number * 72.0 * 12.0);
4284 else if (!strcmp(uval, "m")) /* Meters */
4285 return (number * 72.0 / 0.0254);
4286 else /* Points */
4287 return (number);
4288}
4289
4290
ef416fc2 4291/*
58dc1933 4292 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".
ef416fc2 4293 */