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