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