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