]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/admin.c
Load cups into easysw/current.
[thirdparty/cups.git] / cgi-bin / admin.c
CommitLineData
ef416fc2 1/*
f899b121 2 * "$Id: admin.c 6378 2007-03-21 07:18:18Z mike $"
ef416fc2 3 *
4 * Administration CGI for the Common UNIX Printing System (CUPS).
5 *
f7deaa1a 6 * Copyright 1997-2007 by Easy Software Products.
ef416fc2 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Main entry for CGI.
f7deaa1a 27 * do_add_rss_subscription() - Add a RSS subscription.
ef416fc2 28 * do_am_class() - Add or modify a class.
29 * do_am_printer() - Add or modify a printer.
f7deaa1a 30 * do_cancel_subscription() - Cancel a subscription.
ef416fc2 31 * do_config_printer() - Configure the default options for a printer.
32 * do_config_server() - Configure server settings.
33 * do_delete_class() - Delete a class...
34 * do_delete_printer() - Delete a printer...
fa73b229 35 * do_export() - Export printers to Samba...
ef416fc2 36 * do_menu() - Show the main menu...
37 * do_printer_op() - Do a printer operation.
38 * do_set_allowed_users() - Set the allowed/denied users for a queue.
39 * do_set_sharing() - Set printer-is-shared value...
40 * match_string() - Return the number of matching characters.
41 */
42
43/*
44 * Include necessary headers...
45 */
46
47#include "cgi-private.h"
757d2cad 48#include <cups/adminutil.h>
ef416fc2 49#include <cups/file.h>
50#include <errno.h>
fa73b229 51#include <unistd.h>
52#include <fcntl.h>
53#include <sys/wait.h>
ef416fc2 54
55
56/*
57 * Local functions...
58 */
59
f7deaa1a 60static void do_add_rss_subscription(http_t *http);
fa73b229 61static void do_am_class(http_t *http, int modify);
62static void do_am_printer(http_t *http, int modify);
f7deaa1a 63static void do_cancel_subscription(http_t *http);
fa73b229 64static void do_config_printer(http_t *http);
65static void do_config_server(http_t *http);
66static void do_delete_class(http_t *http);
67static void do_delete_printer(http_t *http);
68static void do_export(http_t *http);
69static void do_menu(http_t *http);
70static void do_printer_op(http_t *http,
ef416fc2 71 ipp_op_t op, const char *title);
fa73b229 72static void do_set_allowed_users(http_t *http);
73static void do_set_sharing(http_t *http);
ef416fc2 74static int match_string(const char *a, const char *b);
75
76
77/*
78 * 'main()' - Main entry for CGI.
79 */
80
81int /* O - Exit status */
82main(int argc, /* I - Number of command-line arguments */
83 char *argv[]) /* I - Command-line arguments */
84{
ef416fc2 85 http_t *http; /* Connection to the server */
86 const char *op; /* Operation name */
87
88
ef416fc2 89 /*
90 * Connect to the HTTP server...
91 */
92
bd7854cb 93 fputs("DEBUG: admin.cgi started...\n", stderr);
94
ef416fc2 95 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
96
a4d04587 97 if (!http)
98 {
99 perror("ERROR: Unable to connect to cupsd");
f301802f 100 fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n",
101 cupsServer() ? cupsServer() : "(null)");
a4d04587 102 fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort());
103 fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
104 exit(1);
105 }
106
bd7854cb 107 fprintf(stderr, "DEBUG: http=%p\n", http);
108
ef416fc2 109 /*
110 * Set the web interface section...
111 */
112
113 cgiSetVariable("SECTION", "admin");
114
115 /*
116 * See if we have form data...
117 */
118
119 if (!cgiInitialize())
120 {
121 /*
122 * Nope, send the administration menu...
123 */
124
bd7854cb 125 fputs("DEBUG: No form data, showing main menu...\n", stderr);
126
fa73b229 127 do_menu(http);
ef416fc2 128 }
129 else if ((op = cgiGetVariable("OP")) != NULL)
130 {
131 /*
132 * Do the operation...
133 */
134
bd7854cb 135 fprintf(stderr, "DEBUG: op=\"%s\"...\n", op);
136
ef416fc2 137 if (!strcmp(op, "redirect"))
138 {
139 const char *url; /* Redirection URL... */
d6ae789d 140 char prefix[1024]; /* URL prefix */
ef416fc2 141
142
d6ae789d 143 if (getenv("HTTPS"))
144 snprintf(prefix, sizeof(prefix), "https://%s:%s",
145 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
146 else
147 snprintf(prefix, sizeof(prefix), "http://%s:%s",
148 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
149
ef416fc2 150 if ((url = cgiGetVariable("URL")) != NULL)
d6ae789d 151 printf("Location: %s%s\n\n", prefix, url);
ef416fc2 152 else
d6ae789d 153 printf("Location: %s/admin\n\n", prefix);
ef416fc2 154 }
155 else if (!strcmp(op, "start-printer"))
fa73b229 156 do_printer_op(http, IPP_RESUME_PRINTER, cgiText(_("Start Printer")));
ef416fc2 157 else if (!strcmp(op, "stop-printer"))
fa73b229 158 do_printer_op(http, IPP_PAUSE_PRINTER, cgiText(_("Stop Printer")));
ef416fc2 159 else if (!strcmp(op, "start-class"))
fa73b229 160 do_printer_op(http, IPP_RESUME_PRINTER, cgiText(_("Start Class")));
ef416fc2 161 else if (!strcmp(op, "stop-class"))
fa73b229 162 do_printer_op(http, IPP_PAUSE_PRINTER, cgiText(_("Stop Class")));
ef416fc2 163 else if (!strcmp(op, "accept-jobs"))
fa73b229 164 do_printer_op(http, CUPS_ACCEPT_JOBS, cgiText(_("Accept Jobs")));
ef416fc2 165 else if (!strcmp(op, "reject-jobs"))
fa73b229 166 do_printer_op(http, CUPS_REJECT_JOBS, cgiText(_("Reject Jobs")));
ef416fc2 167 else if (!strcmp(op, "purge-jobs"))
fa73b229 168 do_printer_op(http, IPP_PURGE_JOBS, cgiText(_("Purge Jobs")));
ef416fc2 169 else if (!strcmp(op, "set-allowed-users"))
fa73b229 170 do_set_allowed_users(http);
ef416fc2 171 else if (!strcmp(op, "set-as-default"))
fa73b229 172 do_printer_op(http, CUPS_SET_DEFAULT, cgiText(_("Set As Default")));
ef416fc2 173 else if (!strcmp(op, "set-sharing"))
fa73b229 174 do_set_sharing(http);
ef416fc2 175 else if (!strcmp(op, "add-class"))
fa73b229 176 do_am_class(http, 0);
ef416fc2 177 else if (!strcmp(op, "add-printer"))
fa73b229 178 do_am_printer(http, 0);
ef416fc2 179 else if (!strcmp(op, "modify-class"))
fa73b229 180 do_am_class(http, 1);
ef416fc2 181 else if (!strcmp(op, "modify-printer"))
fa73b229 182 do_am_printer(http, 1);
ef416fc2 183 else if (!strcmp(op, "delete-class"))
fa73b229 184 do_delete_class(http);
ef416fc2 185 else if (!strcmp(op, "delete-printer"))
fa73b229 186 do_delete_printer(http);
ef416fc2 187 else if (!strcmp(op, "set-printer-options"))
fa73b229 188 do_config_printer(http);
ef416fc2 189 else if (!strcmp(op, "config-server"))
fa73b229 190 do_config_server(http);
191 else if (!strcmp(op, "export-samba"))
192 do_export(http);
f7deaa1a 193 else if (!strcmp(op, "add-rss-subscription"))
194 do_add_rss_subscription(http);
195 else if (!strcmp(op, "cancel-subscription"))
196 do_cancel_subscription(http);
ef416fc2 197 else
198 {
199 /*
200 * Bad operation code... Display an error...
201 */
202
fa73b229 203 cgiStartHTML(cgiText(_("Administration")));
204 cgiCopyTemplateLang("error-op.tmpl");
ef416fc2 205 cgiEndHTML();
206 }
ef416fc2 207 }
208 else
209 {
210 /*
211 * Form data but no operation code... Display an error...
212 */
213
fa73b229 214 cgiStartHTML(cgiText(_("Administration")));
215 cgiCopyTemplateLang("error-op.tmpl");
ef416fc2 216 cgiEndHTML();
217 }
218
219 /*
fa73b229 220 * Close the HTTP server connection...
ef416fc2 221 */
222
fa73b229 223 httpClose(http);
ef416fc2 224
225 /*
226 * Return with no errors...
227 */
228
229 return (0);
230}
231
232
f7deaa1a 233/*
234 * 'do_add_rss_subscription()' - Add a RSS subscription.
235 */
236
237static void
238do_add_rss_subscription(http_t *http) /* I - HTTP connection */
239{
240 ipp_t *request, /* IPP request data */
241 *response; /* IPP response data */
242 char rss_uri[1024]; /* RSS notify-recipient URI */
243 int num_events; /* Number of events */
244 const char *events[12], /* Subscribed events */
245 *subscription_name, /* Subscription name */
246 *printer_uri, /* Printer URI */
247 *ptr, /* Pointer into name */
248 *user; /* Username */
249 int max_events; /* Maximum number of events */
250
251
252 /*
253 * See if we have all of the required information...
254 */
255
256 subscription_name = cgiGetVariable("SUBSCRIPTION_NAME");
257 printer_uri = cgiGetVariable("PRINTER_URI");
258 num_events = 0;
259
260 if (cgiGetVariable("EVENT_JOB_CREATED"))
261 events[num_events ++] = "job-created";
262 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
263 events[num_events ++] = "job-completed";
264 if (cgiGetVariable("EVENT_JOB_STOPPED"))
265 events[num_events ++] = "job-stopped";
266 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
267 events[num_events ++] = "job-config-changed";
268 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
269 events[num_events ++] = "printer-stopped";
270 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
271 events[num_events ++] = "printer-added";
272 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
273 events[num_events ++] = "printer-modified";
274 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
275 events[num_events ++] = "printer-deleted";
276 if (cgiGetVariable("EVENT_SERVER_STARTED"))
277 events[num_events ++] = "server-started";
278 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
279 events[num_events ++] = "server-stopped";
280 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
281 events[num_events ++] = "server-restarted";
282 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
283 events[num_events ++] = "server-audit";
284
285 if ((ptr = cgiGetVariable("MAX_EVENTS")) != NULL)
286 max_events = atoi(ptr);
287 else
288 max_events = 0;
289
290 if (!subscription_name || !printer_uri || !num_events ||
291 max_events <= 0 || max_events > 9999)
292 {
293 /*
294 * Don't have everything we need, so get the available printers
295 * and classes and (re)show the add page...
296 */
297
298 request = ippNewRequest(CUPS_GET_PRINTERS);
299 response = cupsDoRequest(http, request, "/");
300
301 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
302
303 ippDelete(response);
304
305 cgiStartHTML(cgiText(_("Add RSS Subscription")));
306
307 cgiCopyTemplateLang("add-rss-subscription.tmpl");
308
309 cgiEndHTML();
310 return;
311 }
312
313 /*
314 * Validate the subscription name...
315 */
316
317 for (ptr = subscription_name; *ptr; ptr ++)
318 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
319 *ptr == '?' || *ptr == '#')
320 break;
321
322 if (*ptr)
323 {
324 cgiSetVariable("ERROR",
325 cgiText(_("The subscription name may not "
326 "contain spaces, slashes (/), question marks (?), "
327 "or the pound sign (#).")));
328 cgiStartHTML(_("Add RSS Subscription"));
329 cgiCopyTemplateLang("error.tmpl");
330 cgiEndHTML();
331 return;
332 }
333
334 /*
335 * Add the subscription...
336 */
337
338 ptr = subscription_name + strlen(subscription_name) - 4;
339 if (ptr < subscription_name || strcmp(ptr, ".rss"))
340 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
341 NULL, NULL, 0, "/%s.rss?max_events=%d", subscription_name,
342 max_events);
343 else
344 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
345 NULL, NULL, 0, "/%s?max_events=%d", subscription_name,
346 max_events);
347
348 request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
349
350 if (!strcasecmp(printer_uri, "#ALL#"))
351 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
352 NULL, "ipp://localhost/");
353 else
354 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
355 NULL, printer_uri);
356
357 if ((user = getenv("REMOTE_USER")) == NULL)
358 user = "guest";
359
360 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
361 NULL, user);
362
7594b224 363 ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
364 "notify-recipient-uri", NULL, rss_uri);
f7deaa1a 365 ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
366 num_events, NULL, events);
367 ippAddInteger(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
368 "notify-lease-duration", 0);
369
370 ippDelete(cupsDoRequest(http, request, "/"));
371
372 if (cupsLastError() > IPP_OK_CONFLICT)
373 {
374 cgiStartHTML(_("Add RSS Subscription"));
375 cgiShowIPPError(_("Unable to add RSS subscription:"));
376 }
377 else
378 {
379 /*
380 * Redirect successful updates back to the admin page...
381 */
382
383 cgiSetVariable("refresh_page", "5;URL=/admin");
384 cgiStartHTML(_("Add RSS Subscription"));
385 cgiCopyTemplateLang("subscription-added.tmpl");
386 }
387
388 cgiEndHTML();
389}
390
391
ef416fc2 392/*
393 * 'do_am_class()' - Add or modify a class.
394 */
395
396static void
fa73b229 397do_am_class(http_t *http, /* I - HTTP connection */
398 int modify) /* I - Modify the printer? */
ef416fc2 399{
400 int i, j; /* Looping vars */
401 int element; /* Element number */
402 int num_printers; /* Number of printers */
403 ipp_t *request, /* IPP request */
404 *response; /* IPP response */
405 ipp_attribute_t *attr; /* member-uris attribute */
ef416fc2 406 char uri[HTTP_MAX_URI]; /* Device or printer URI */
407 const char *name, /* Pointer to class name */
408 *ptr; /* Pointer to CGI variable */
409 const char *title; /* Title of page */
410 static const char * const pattrs[] = /* Requested printer attributes */
411 {
412 "member-names",
413 "printer-info",
414 "printer-location"
415 };
416
417
fa73b229 418 title = cgiText(modify ? _("Modify Class") : _("Add Class"));
ef416fc2 419 name = cgiGetVariable("PRINTER_NAME");
420
421 if (cgiGetVariable("PRINTER_LOCATION") == NULL)
422 {
423 /*
424 * Build a CUPS_GET_PRINTERS request, which requires the
425 * following attributes:
426 *
427 * attributes-charset
428 * attributes-natural-language
ef416fc2 429 */
430
fa73b229 431 request = ippNewRequest(CUPS_GET_PRINTERS);
ef416fc2 432
ef416fc2 433 /*
434 * Do the request and get back a response...
435 */
436
437 if ((response = cupsDoRequest(http, request, "/")) != NULL)
438 {
439 /*
440 * Create MEMBER_URIS and MEMBER_NAMES arrays...
441 */
442
443 for (element = 0, attr = response->attrs;
444 attr != NULL;
445 attr = attr->next)
446 if (attr->name && !strcmp(attr->name, "printer-uri-supported"))
447 {
448 if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
449 (!name || strcasecmp(name, ptr + 1)))
450 {
451 /*
452 * Don't show the current class...
453 */
454
455 cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
456 element ++;
457 }
458 }
459
460 for (element = 0, attr = response->attrs;
461 attr != NULL;
462 attr = attr->next)
463 if (attr->name && !strcmp(attr->name, "printer-name"))
464 {
465 if (!name || strcasecmp(name, attr->values[0].string.text))
466 {
467 /*
468 * Don't show the current class...
469 */
470
471 cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
472 element ++;
473 }
474 }
475
476 num_printers = cgiGetSize("MEMBER_URIS");
477
478 ippDelete(response);
479 }
480 else
481 num_printers = 0;
482
483 if (modify)
484 {
485 /*
486 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
487 * following attributes:
488 *
489 * attributes-charset
490 * attributes-natural-language
491 * printer-uri
492 */
493
fa73b229 494 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 495
a4d04587 496 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
497 "localhost", 0, "/classes/%s", name);
ef416fc2 498 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
499 NULL, uri);
500
501 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
502 "requested-attributes",
503 (int)(sizeof(pattrs) / sizeof(pattrs[0])),
504 NULL, pattrs);
505
506 /*
507 * Do the request and get back a response...
508 */
509
510 if ((response = cupsDoRequest(http, request, "/")) != NULL)
511 {
480ef0fe 512 if ((attr = ippFindAttribute(response, "member-names",
513 IPP_TAG_NAME)) != NULL)
ef416fc2 514 {
515 /*
516 * Mark any current members in the class...
517 */
518
519 for (j = 0; j < num_printers; j ++)
520 cgiSetArray("MEMBER_SELECTED", j, "");
521
522 for (i = 0; i < attr->num_values; i ++)
523 {
524 for (j = 0; j < num_printers; j ++)
525 {
526 if (!strcasecmp(attr->values[i].string.text,
527 cgiGetArray("MEMBER_NAMES", j)))
528 {
529 cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
530 break;
531 }
532 }
533 }
534 }
535
536 if ((attr = ippFindAttribute(response, "printer-info",
537 IPP_TAG_TEXT)) != NULL)
538 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
539
540 if ((attr = ippFindAttribute(response, "printer-location",
541 IPP_TAG_TEXT)) != NULL)
542 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
543
544 ippDelete(response);
545 }
546
547 /*
548 * Update the location and description of an existing printer...
549 */
550
551 cgiStartHTML(title);
552 cgiCopyTemplateLang("modify-class.tmpl");
553 }
554 else
555 {
556 /*
557 * Get the name, location, and description for a new printer...
558 */
559
560 cgiStartHTML(title);
561 cgiCopyTemplateLang("add-class.tmpl");
562 }
563
564 cgiEndHTML();
565
566 return;
567 }
568
569 for (ptr = name; *ptr; ptr ++)
570 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
571 break;
572
573 if (*ptr || ptr == name || strlen(name) > 127)
574 {
fa73b229 575 cgiSetVariable("ERROR",
576 cgiText(_("The class name may only contain up to "
577 "127 printable characters and may not "
578 "contain spaces, slashes (/), or the "
579 "pound sign (#).")));
ef416fc2 580 cgiStartHTML(title);
581 cgiCopyTemplateLang("error.tmpl");
582 cgiEndHTML();
583 return;
584 }
585
586 /*
587 * Build a CUPS_ADD_CLASS request, which requires the following
588 * attributes:
589 *
590 * attributes-charset
591 * attributes-natural-language
592 * printer-uri
593 * printer-location
594 * printer-info
595 * printer-is-accepting-jobs
596 * printer-state
597 * member-uris
598 */
599
fa73b229 600 request = ippNewRequest(CUPS_ADD_CLASS);
ef416fc2 601
a4d04587 602 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
603 "localhost", 0, "/classes/%s",
604 cgiGetVariable("PRINTER_NAME"));
ef416fc2 605 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
606 NULL, uri);
607
608 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
609 NULL, cgiGetVariable("PRINTER_LOCATION"));
610
611 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
612 NULL, cgiGetVariable("PRINTER_INFO"));
613
614 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
615
616 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
617 IPP_PRINTER_IDLE);
618
619 if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
620 {
621 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
622 num_printers, NULL, NULL);
623 for (i = 0; i < num_printers; i ++)
624 attr->values[i].string.text = strdup(cgiGetArray("MEMBER_URIS", i));
625 }
626
627 /*
628 * Do the request and get back a response...
629 */
630
fa73b229 631 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 632
fa73b229 633 if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 634 {
635 cgiStartHTML(title);
fa73b229 636 cgiShowIPPError(modify ? _("Unable to modify class:") :
637 _("Unable to add class:"));
ef416fc2 638 }
639 else
640 {
641 /*
642 * Redirect successful updates back to the class page...
643 */
644
645 char refresh[1024]; /* Refresh URL */
646
647 cgiFormEncode(uri, name, sizeof(uri));
f301802f 648 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
ef416fc2 649 uri);
650 cgiSetVariable("refresh_page", refresh);
651
652 cgiStartHTML(title);
653
654 if (modify)
655 cgiCopyTemplateLang("class-modified.tmpl");
656 else
657 cgiCopyTemplateLang("class-added.tmpl");
658 }
659
660 cgiEndHTML();
661}
662
663
664/*
665 * 'do_am_printer()' - Add or modify a printer.
666 */
667
668static void
fa73b229 669do_am_printer(http_t *http, /* I - HTTP connection */
670 int modify) /* I - Modify the printer? */
ef416fc2 671{
672 int i; /* Looping var */
89d46774 673 ipp_attribute_t *attr; /* Current attribute */
ef416fc2 674 ipp_t *request, /* IPP request */
675 *response, /* IPP response */
676 *oldinfo; /* Old printer information */
ef416fc2 677 const cgi_file_t *file; /* Uploaded file, if any */
678 const char *var; /* CGI variable */
679 char uri[HTTP_MAX_URI], /* Device or printer URI */
680 *uriptr; /* Pointer into URI */
681 int maxrate; /* Maximum baud rate */
682 char baudrate[255]; /* Baud rate string */
683 const char *name, /* Pointer to class name */
684 *ptr; /* Pointer to CGI variable */
685 const char *title; /* Title of page */
686 static int baudrates[] = /* Baud rates */
687 {
688 1200,
689 2400,
690 4800,
691 9600,
692 19200,
693 38400,
694 57600,
695 115200,
696 230400,
697 460800
698 };
699
700
f301802f 701 ptr = cgiGetVariable("DEVICE_URI");
fa73b229 702 fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
f301802f 703 ptr ? ptr : "(null)");
fa73b229 704
705 title = cgiText(modify ? _("Modify Printer") : _("Add Printer"));
ef416fc2 706
707 if (modify)
708 {
709 /*
710 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
711 * following attributes:
712 *
713 * attributes-charset
714 * attributes-natural-language
715 * printer-uri
716 */
717
fa73b229 718 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 719
a4d04587 720 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
721 "localhost", 0, "/printers/%s",
722 cgiGetVariable("PRINTER_NAME"));
ef416fc2 723 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
724 NULL, uri);
725
726 /*
727 * Do the request and get back a response...
728 */
729
730 oldinfo = cupsDoRequest(http, request, "/");
731 }
732 else
733 oldinfo = NULL;
734
735 if ((name = cgiGetVariable("PRINTER_NAME")) == NULL ||
736 cgiGetVariable("PRINTER_LOCATION") == NULL)
737 {
738 cgiStartHTML(title);
739
740 if (modify)
741 {
742 /*
743 * Update the location and description of an existing printer...
744 */
745
746 if (oldinfo)
747 cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0);
748
749 cgiCopyTemplateLang("modify-printer.tmpl");
750 }
751 else
752 {
753 /*
754 * Get the name, location, and description for a new printer...
755 */
756
757 cgiCopyTemplateLang("add-printer.tmpl");
758 }
759
760 cgiEndHTML();
761
762 if (oldinfo)
763 ippDelete(oldinfo);
764
765 return;
766 }
767
768 for (ptr = name; *ptr; ptr ++)
769 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
770 break;
771
772 if (*ptr || ptr == name || strlen(name) > 127)
773 {
fa73b229 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 (#).")));
ef416fc2 779 cgiStartHTML(title);
780 cgiCopyTemplateLang("error.tmpl");
781 cgiEndHTML();
782 return;
783 }
784
785 file = cgiGetFile();
786
787 if (file)
788 {
789 fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
790 fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
791 fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
792 fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
793 }
794
795 if ((var = cgiGetVariable("DEVICE_URI")) == NULL)
796 {
797 /*
798 * Build a CUPS_GET_DEVICES request, which requires the following
799 * attributes:
800 *
801 * attributes-charset
802 * attributes-natural-language
803 * printer-uri
804 */
805
a4d04587 806 fputs("DEBUG: Getting list of devices...\n", stderr);
807
fa73b229 808 request = ippNewRequest(CUPS_GET_DEVICES);
ef416fc2 809
810 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
811 NULL, "ipp://localhost/printers/");
812
813 /*
814 * Do the request and get back a response...
815 */
816
817 if ((response = cupsDoRequest(http, request, "/")) != NULL)
818 {
a4d04587 819 fputs("DEBUG: Got device list!\n", stderr);
820
ef416fc2 821 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
822 ippDelete(response);
823 }
a4d04587 824 else
825 fprintf(stderr,
826 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
827 cupsLastError(), cupsLastErrorString());
ef416fc2 828
829 /*
830 * Let the user choose...
831 */
832
833 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
834 {
835 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
836 if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
837 *uriptr = '\0';
838
839 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
840 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
841 }
842
843 cgiStartHTML(title);
844 cgiCopyTemplateLang("choose-device.tmpl");
845 cgiEndHTML();
846 }
847 else if (strchr(var, '/') == NULL)
848 {
849 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
850 {
851 /*
852 * Set the current device URI for the form to the old one...
853 */
854
855 if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
856 cgiSetVariable("DEVICE_URI", attr->values[0].string.text);
857 }
858
859 /*
860 * User needs to set the full URI...
861 */
862
863 cgiStartHTML(title);
864 cgiCopyTemplateLang("choose-uri.tmpl");
865 cgiEndHTML();
866 }
867 else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
868 {
869 /*
870 * Need baud rate, parity, etc.
871 */
872
873 if ((var = strchr(var, '?')) != NULL &&
874 strncmp(var, "?baud=", 6) == 0)
875 maxrate = atoi(var + 6);
876 else
877 maxrate = 19200;
878
879 for (i = 0; i < 10; i ++)
880 if (baudrates[i] > maxrate)
881 break;
882 else
883 {
884 sprintf(baudrate, "%d", baudrates[i]);
885 cgiSetArray("BAUDRATES", i, baudrate);
886 }
887
888 cgiStartHTML(title);
889 cgiCopyTemplateLang("choose-serial.tmpl");
890 cgiEndHTML();
891 }
892 else if (!file && (var = cgiGetVariable("PPD_NAME")) == NULL)
893 {
894 if (modify)
895 {
896 /*
897 * Get the PPD file...
898 */
899
900 int fd; /* PPD file */
901 char filename[1024]; /* PPD filename */
902 ppd_file_t *ppd; /* PPD information */
903 char buffer[1024]; /* Buffer */
904 int bytes; /* Number of bytes */
905 http_status_t get_status; /* Status of GET */
906
907
a4d04587 908 /* TODO: Use cupsGetFile() API... */
ef416fc2 909 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
910
911 if (httpGet(http, uri))
912 httpGet(http, uri);
913
914 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
915
916 if (get_status != HTTP_OK)
917 {
918 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
919 uri, get_status, httpStatus(get_status));
920 }
921 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
922 {
a4d04587 923 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
ef416fc2 924 write(fd, buffer, bytes);
925
926 close(fd);
927
928 if ((ppd = ppdOpenFile(filename)) != NULL)
929 {
930 if (ppd->manufacturer)
931 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
932
933 if (ppd->nickname)
934 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
935
936 ppdClose(ppd);
937 unlink(filename);
938 }
939 else
940 {
941 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
942 filename, ppdErrorString(ppdLastError(&bytes)));
943 }
944 }
945 else
946 {
947 httpFlush(http);
948
949 fprintf(stderr,
950 "ERROR: Unable to create temporary file for PPD file: %s\n",
951 strerror(errno));
952 }
953 }
954 else if ((uriptr = strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL)
955 {
956 /*
957 * Extract make and make/model from device URI string...
958 */
959
960 char make[1024], /* Make string */
961 *makeptr; /* Pointer into make */
962
963
964 *uriptr++ = '\0';
965
966 strlcpy(make, uriptr, sizeof(make));
967
968 if ((makeptr = strchr(make, ' ')) != NULL)
969 *makeptr = '\0';
970 else if ((makeptr = strchr(make, '-')) != NULL)
971 *makeptr = '\0';
972 else if (!strncasecmp(make, "laserjet", 8) ||
973 !strncasecmp(make, "deskjet", 7) ||
974 !strncasecmp(make, "designjet", 9))
975 strcpy(make, "HP");
976 else if (!strncasecmp(make, "phaser", 6))
977 strcpy(make, "Xerox");
978 else if (!strncasecmp(make, "stylus", 6))
979 strcpy(make, "Epson");
980 else
981 strcpy(make, "Generic");
982
983 cgiSetVariable("CURRENT_MAKE", make);
984 cgiSetVariable("PPD_MAKE", make);
985 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
986 }
987
988 /*
989 * Build a CUPS_GET_PPDS request, which requires the following
990 * attributes:
991 *
992 * attributes-charset
993 * attributes-natural-language
994 * printer-uri
995 */
996
fa73b229 997 request = ippNewRequest(CUPS_GET_PPDS);
ef416fc2 998
999 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1000 NULL, "ipp://localhost/printers/");
1001
ef416fc2 1002 if ((var = cgiGetVariable("PPD_MAKE")) != NULL)
1003 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1004 "ppd-make", NULL, var);
1005 else
1006 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1007 "requested-attributes", NULL, "ppd-make");
1008
1009 /*
1010 * Do the request and get back a response...
1011 */
1012
1013 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1014 {
1015 /*
1016 * Got the list of PPDs, see if the user has selected a make...
1017 */
1018
89d46774 1019 if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0)
ef416fc2 1020 {
1021 /*
89d46774 1022 * No PPD files with this make, try again with all makes...
ef416fc2 1023 */
1024
89d46774 1025 ippDelete(response);
1026
1027 request = ippNewRequest(CUPS_GET_PPDS);
1028
1029 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1030 NULL, "ipp://localhost/printers/");
1031
1032 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1033 "requested-attributes", NULL, "ppd-make");
ef416fc2 1034
89d46774 1035 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1036 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1037
1038 cgiStartHTML(title);
1039 cgiCopyTemplateLang("choose-make.tmpl");
1040 cgiEndHTML();
1041 }
1042 else if (!var)
1043 {
ef416fc2 1044 cgiStartHTML(title);
1045 cgiCopyTemplateLang("choose-make.tmpl");
1046 cgiEndHTML();
1047 }
1048 else
1049 {
1050 /*
1051 * Let the user choose a model...
1052 */
1053
1054 const char *make_model; /* Current make/model string */
1055
1056
1057 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
1058 {
1059 /*
1060 * Scan for "close" matches...
1061 */
1062
1063 int match, /* Current match */
1064 best_match, /* Best match so far */
1065 count; /* Number of drivers */
1066 const char *best, /* Best matching string */
1067 *current; /* Current string */
1068
1069
1070 count = cgiGetSize("PPD_MAKE_AND_MODEL");
1071
1072 for (i = 0, best_match = 0, best = NULL; i < count; i ++)
1073 {
1074 current = cgiGetArray("PPD_MAKE_AND_MODEL", i);
1075 match = match_string(make_model, current);
1076
1077 if (match > best_match)
1078 {
1079 best_match = match;
1080 best = current;
1081 }
1082 }
1083
1084 if (best_match > strlen(var))
1085 {
1086 /*
1087 * Found a match longer than the make...
1088 */
1089
1090 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best);
1091 }
1092 }
1093
1094 cgiStartHTML(title);
1095 cgiCopyTemplateLang("choose-model.tmpl");
1096 cgiEndHTML();
1097 }
1098
ef416fc2 1099 ippDelete(response);
1100 }
1101 else
1102 {
ef416fc2 1103 cgiStartHTML(title);
fa73b229 1104 cgiShowIPPError(_("Unable to get list of printer drivers:"));
ef416fc2 1105 cgiCopyTemplateLang("error.tmpl");
1106 cgiEndHTML();
1107 }
1108 }
1109 else
1110 {
1111 /*
1112 * Build a CUPS_ADD_PRINTER request, which requires the following
1113 * attributes:
1114 *
1115 * attributes-charset
1116 * attributes-natural-language
1117 * printer-uri
1118 * printer-location
1119 * printer-info
1120 * ppd-name
1121 * device-uri
1122 * printer-is-accepting-jobs
1123 * printer-state
1124 */
1125
fa73b229 1126 request = ippNewRequest(CUPS_ADD_PRINTER);
ef416fc2 1127
a4d04587 1128 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1129 "localhost", 0, "/printers/%s",
1130 cgiGetVariable("PRINTER_NAME"));
ef416fc2 1131 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1132 NULL, uri);
1133
1134 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1135 NULL, cgiGetVariable("PRINTER_LOCATION"));
1136
1137 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1138 NULL, cgiGetVariable("PRINTER_INFO"));
1139
1140 if (!file)
1141 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
1142 NULL, cgiGetVariable("PPD_NAME"));
1143
1144 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1145
1146 /*
1147 * Strip make and model from URI...
1148 */
1149
1150 if ((uriptr = strrchr(uri, '|')) != NULL)
1151 *uriptr = '\0';
1152
fa73b229 1153 if (!strncmp(uri, "serial:", 7))
ef416fc2 1154 {
1155 /*
1156 * Update serial port URI to include baud rate, etc.
1157 */
1158
1159 if ((uriptr = strchr(uri, '?')) == NULL)
1160 uriptr = uri + strlen(uri);
1161
1162 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
1163 "?baud=%s+bits=%s+parity=%s+flow=%s",
1164 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1165 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1166 }
1167
1168 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1169 NULL, uri);
1170
1171 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1172
1173 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1174 IPP_PRINTER_IDLE);
1175
1176 /*
1177 * Do the request and get back a response...
1178 */
1179
1180 if (file)
fa73b229 1181 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
ef416fc2 1182 else
fa73b229 1183 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 1184
fa73b229 1185 if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 1186 {
1187 cgiStartHTML(title);
fa73b229 1188 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1189 _("Unable to add printer:"));
ef416fc2 1190 }
1191 else
1192 {
1193 /*
1194 * Redirect successful updates back to the printer or set-options pages...
1195 */
1196
1197 char refresh[1024]; /* Refresh URL */
1198
1199
1200 cgiFormEncode(uri, name, sizeof(uri));
1201
1202 if (modify)
1203 snprintf(refresh, sizeof(refresh),
fa73b229 1204 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
ef416fc2 1205 else
1206 snprintf(refresh, sizeof(refresh),
f301802f 1207 "5;URL=/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri);
ef416fc2 1208
1209 cgiSetVariable("refresh_page", refresh);
1210
1211 cgiStartHTML(title);
1212
1213 if (modify)
1214 cgiCopyTemplateLang("printer-modified.tmpl");
1215 else
1216 cgiCopyTemplateLang("printer-added.tmpl");
1217 }
1218
1219 cgiEndHTML();
1220 }
1221
1222 if (oldinfo)
1223 ippDelete(oldinfo);
1224}
1225
1226
f7deaa1a 1227/*
1228 * 'do_cancel_subscription()' - Cancel a subscription.
1229 */
1230
1231static void
1232do_cancel_subscription(http_t *http)/* I - HTTP connection */
1233{
1234 ipp_t *request; /* IPP request data */
1235 const char *var, /* Form variable */
1236 *user; /* Username */
1237 int id; /* Subscription ID */
1238
1239
1240 /*
1241 * See if we have all of the required information...
1242 */
1243
1244 if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL)
1245 id = atoi(var);
1246 else
1247 id = 0;
1248
1249 if (id <= 0)
1250 {
1251 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1252 cgiStartHTML(_("Cancel RSS Subscription"));
1253 cgiCopyTemplateLang("error.tmpl");
1254 cgiEndHTML();
1255 return;
1256 }
1257
1258 /*
1259 * Cancel the subscription...
1260 */
1261
1262 request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
1263
1264 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1265 NULL, "ipp://localhost/");
1266 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
1267 "notify-subscription-id", id);
1268
1269 if ((user = getenv("REMOTE_USER")) == NULL)
1270 user = "guest";
1271
1272 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1273 NULL, user);
1274
1275 ippDelete(cupsDoRequest(http, request, "/"));
1276
1277 if (cupsLastError() > IPP_OK_CONFLICT)
1278 {
1279 cgiStartHTML(_("Cancel RSS Subscription"));
1280 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1281 }
1282 else
1283 {
1284 /*
1285 * Redirect successful updates back to the admin page...
1286 */
1287
1288 cgiSetVariable("refresh_page", "5;URL=/admin");
1289 cgiStartHTML(_("Cancel RSS Subscription"));
1290 cgiCopyTemplateLang("subscription-canceled.tmpl");
1291 }
1292
1293 cgiEndHTML();
1294}
1295
1296
ef416fc2 1297/*
1298 * 'do_config_printer()' - Configure the default options for a printer.
1299 */
1300
1301static void
fa73b229 1302do_config_printer(http_t *http) /* I - HTTP connection */
ef416fc2 1303{
1304 int i, j, k, m; /* Looping vars */
1305 int have_options; /* Have options? */
1306 ipp_t *request, /* IPP request */
1307 *response; /* IPP response */
1308 ipp_attribute_t *attr; /* IPP attribute */
1309 char uri[HTTP_MAX_URI]; /* Job URI */
1310 const char *var; /* Variable value */
1311 const char *printer; /* Printer printer name */
ef416fc2 1312 const char *filename; /* PPD filename */
1313 char tempfile[1024]; /* Temporary filename */
1314 cups_file_t *in, /* Input file */
1315 *out; /* Output file */
1316 char line[1024]; /* Line from PPD file */
1317 char keyword[1024], /* Keyword from Default line */
1318 *keyptr; /* Pointer into keyword... */
1319 ppd_file_t *ppd; /* PPD file */
1320 ppd_group_t *group; /* Option group */
1321 ppd_option_t *option; /* Option */
1322 ppd_attr_t *protocol; /* cupsProtocol attribute */
fa73b229 1323 const char *title; /* Page title */
ef416fc2 1324
1325
fa73b229 1326 title = cgiText(_("Set Printer Options"));
1327
bd7854cb 1328 fprintf(stderr, "DEBUG: do_config_printer(http=%p)\n", http);
1329
ef416fc2 1330 /*
1331 * Get the printer name...
1332 */
1333
1334 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
a4d04587 1335 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1336 "localhost", 0, "/printers/%s", printer);
ef416fc2 1337 else
1338 {
fa73b229 1339 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1340 cgiStartHTML(title);
ef416fc2 1341 cgiCopyTemplateLang("error.tmpl");
1342 cgiEndHTML();
1343 return;
1344 }
1345
bd7854cb 1346 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
1347
ef416fc2 1348 /*
1349 * Get the PPD file...
1350 */
1351
bd7854cb 1352 if ((filename = cupsGetPPD2(http, printer)) == NULL)
ef416fc2 1353 {
bd7854cb 1354 fputs("DEBUG: No PPD file!?!\n", stderr);
1355
fa73b229 1356 cgiStartHTML(title);
1357 cgiShowIPPError(_("Unable to get PPD file!"));
1358 cgiEndHTML();
ef416fc2 1359 return;
1360 }
1361
bd7854cb 1362 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
1363
ef416fc2 1364 if ((ppd = ppdOpenFile(filename)) == NULL)
1365 {
fa73b229 1366 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
1367 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
1368 cgiStartHTML(title);
ef416fc2 1369 cgiCopyTemplateLang("error.tmpl");
1370 cgiEndHTML();
1371 return;
1372 }
1373
1374 if (cgiGetVariable("job_sheets_start") != NULL ||
1375 cgiGetVariable("job_sheets_end") != NULL)
1376 have_options = 1;
1377 else
1378 have_options = 0;
1379
1380 ppdMarkDefaults(ppd);
1381
1382 DEBUG_printf(("<P>ppd->num_groups = %d\n"
1383 "<UL>\n", ppd->num_groups));
1384
1385 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
1386 {
1387 DEBUG_printf(("<LI>%s<UL>\n", group->text));
1388
480ef0fe 1389 for (j = group->num_options, option = group->options;
1390 j > 0;
1391 j --, option ++)
ef416fc2 1392 if ((var = cgiGetVariable(option->keyword)) != NULL)
1393 {
1394 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
1395 have_options = 1;
1396 ppdMarkOption(ppd, option->keyword, var);
1397 }
1398#ifdef DEBUG
1399 else
1400 printf("<LI>%s not defined!</LI>\n", option->keyword);
1401#endif /* DEBUG */
1402
1403 DEBUG_puts("</UL></LI>");
1404 }
1405
1406 DEBUG_printf(("</UL>\n"
1407 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
1408
1409 if (!have_options || ppdConflicts(ppd))
1410 {
1411 /*
1412 * Show the options to the user...
1413 */
1414
bd7854cb 1415 fputs("DEBUG: Showing options...\n", stderr);
1416
fa73b229 1417 ppdLocalize(ppd);
1418
89d46774 1419 cgiStartHTML(cgiText(_("Set Printer Options")));
ef416fc2 1420 cgiCopyTemplateLang("set-printer-options-header.tmpl");
1421
1422 if (ppdConflicts(ppd))
1423 {
480ef0fe 1424 for (i = ppd->num_groups, k = 0, group = ppd->groups;
1425 i > 0;
1426 i --, group ++)
1427 for (j = group->num_options, option = group->options;
1428 j > 0;
1429 j --, option ++)
ef416fc2 1430 if (option->conflicted)
1431 {
1432 cgiSetArray("ckeyword", k, option->keyword);
1433 cgiSetArray("ckeytext", k, option->text);
1434 k ++;
1435 }
1436
1437 cgiCopyTemplateLang("option-conflict.tmpl");
1438 }
1439
1440 for (i = ppd->num_groups, group = ppd->groups;
1441 i > 0;
1442 i --, group ++)
1443 {
1444 if (!strcmp(group->name, "InstallableOptions"))
fa73b229 1445 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
ef416fc2 1446 else
1447 cgiSetVariable("GROUP", group->text);
1448
1449 cgiCopyTemplateLang("option-header.tmpl");
1450
1451 for (j = group->num_options, option = group->options;
1452 j > 0;
1453 j --, option ++)
1454 {
1455 if (!strcmp(option->keyword, "PageRegion"))
1456 continue;
1457
1458 cgiSetVariable("KEYWORD", option->keyword);
1459 cgiSetVariable("KEYTEXT", option->text);
1460
1461 if (option->conflicted)
1462 cgiSetVariable("CONFLICTED", "1");
1463 else
1464 cgiSetVariable("CONFLICTED", "0");
1465
1466 cgiSetSize("CHOICES", 0);
1467 cgiSetSize("TEXT", 0);
1468 for (k = 0, m = 0; k < option->num_choices; k ++)
1469 {
1470 /*
1471 * Hide custom option values...
1472 */
1473
1474 if (!strcmp(option->choices[k].choice, "Custom"))
1475 continue;
1476
1477 cgiSetArray("CHOICES", m, option->choices[k].choice);
1478 cgiSetArray("TEXT", m, option->choices[k].text);
1479
1480 m ++;
1481
1482 if (option->choices[k].marked)
1483 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
1484 }
1485
1486 switch (option->ui)
1487 {
1488 case PPD_UI_BOOLEAN :
1489 cgiCopyTemplateLang("option-boolean.tmpl");
1490 break;
1491 case PPD_UI_PICKONE :
1492 cgiCopyTemplateLang("option-pickone.tmpl");
1493 break;
1494 case PPD_UI_PICKMANY :
1495 cgiCopyTemplateLang("option-pickmany.tmpl");
1496 break;
1497 }
1498 }
1499
1500 cgiCopyTemplateLang("option-trailer.tmpl");
1501 }
1502
1503 /*
1504 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1505 * following attributes:
1506 *
1507 * attributes-charset
1508 * attributes-natural-language
1509 * printer-uri
1510 */
1511
fa73b229 1512 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 1513
a4d04587 1514 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1515 "localhost", 0, "/printers/%s", printer);
ef416fc2 1516 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1517 NULL, uri);
1518
1519 /*
1520 * Do the request and get back a response...
1521 */
1522
1523 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1524 {
fa73b229 1525 if ((attr = ippFindAttribute(response, "job-sheets-supported",
1526 IPP_TAG_ZERO)) != NULL)
ef416fc2 1527 {
1528 /*
1529 * Add the job sheets options...
1530 */
1531
fa73b229 1532 cgiSetVariable("GROUP", cgiText(_("Banners")));
ef416fc2 1533 cgiCopyTemplateLang("option-header.tmpl");
1534
1535 cgiSetSize("CHOICES", attr->num_values);
1536 cgiSetSize("TEXT", attr->num_values);
1537 for (k = 0; k < attr->num_values; k ++)
1538 {
1539 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1540 cgiSetArray("TEXT", k, attr->values[k].string.text);
1541 }
1542
1543 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
1544
1545 cgiSetVariable("KEYWORD", "job_sheets_start");
fa73b229 1546 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
ef416fc2 1547 cgiSetVariable("DEFCHOICE", attr == NULL ?
1548 "" : attr->values[0].string.text);
1549
1550 cgiCopyTemplateLang("option-pickone.tmpl");
1551
1552 cgiSetVariable("KEYWORD", "job_sheets_end");
fa73b229 1553 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
ef416fc2 1554 cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ?
1555 "" : attr->values[1].string.text);
1556
1557 cgiCopyTemplateLang("option-pickone.tmpl");
1558
1559 cgiCopyTemplateLang("option-trailer.tmpl");
1560 }
1561
1562 if (ippFindAttribute(response, "printer-error-policy-supported",
1563 IPP_TAG_ZERO) ||
1564 ippFindAttribute(response, "printer-op-policy-supported",
1565 IPP_TAG_ZERO))
1566 {
1567 /*
1568 * Add the error and operation policy options...
1569 */
1570
fa73b229 1571 cgiSetVariable("GROUP", cgiText(_("Policies")));
ef416fc2 1572 cgiCopyTemplateLang("option-header.tmpl");
1573
1574 /*
1575 * Error policy...
1576 */
1577
1578 attr = ippFindAttribute(response, "printer-error-policy-supported",
1579 IPP_TAG_ZERO);
1580
1581 if (attr)
1582 {
1583 cgiSetSize("CHOICES", attr->num_values);
1584 cgiSetSize("TEXT", attr->num_values);
1585 for (k = 0; k < attr->num_values; k ++)
1586 {
1587 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1588 cgiSetArray("TEXT", k, attr->values[k].string.text);
1589 }
1590
1591 attr = ippFindAttribute(response, "printer-error-policy",
1592 IPP_TAG_ZERO);
1593
1594 cgiSetVariable("KEYWORD", "printer_error_policy");
fa73b229 1595 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
ef416fc2 1596 cgiSetVariable("DEFCHOICE", attr == NULL ?
1597 "" : attr->values[0].string.text);
1598 }
1599
1600 cgiCopyTemplateLang("option-pickone.tmpl");
1601
1602 /*
1603 * Operation policy...
1604 */
1605
1606 attr = ippFindAttribute(response, "printer-op-policy-supported",
1607 IPP_TAG_ZERO);
1608
1609 if (attr)
1610 {
1611 cgiSetSize("CHOICES", attr->num_values);
1612 cgiSetSize("TEXT", attr->num_values);
1613 for (k = 0; k < attr->num_values; k ++)
1614 {
1615 cgiSetArray("CHOICES", k, attr->values[k].string.text);
1616 cgiSetArray("TEXT", k, attr->values[k].string.text);
1617 }
1618
1619 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
1620
1621 cgiSetVariable("KEYWORD", "printer_op_policy");
fa73b229 1622 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
ef416fc2 1623 cgiSetVariable("DEFCHOICE", attr == NULL ?
1624 "" : attr->values[0].string.text);
1625
1626 cgiCopyTemplateLang("option-pickone.tmpl");
1627 }
1628
1629 cgiCopyTemplateLang("option-trailer.tmpl");
1630 }
1631
1632 ippDelete(response);
1633 }
1634
1635 /*
1636 * Binary protocol support...
1637 */
1638
1639 if (ppd->protocols && strstr(ppd->protocols, "BCP"))
1640 {
1641 protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
1642
fa73b229 1643 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
ef416fc2 1644 cgiCopyTemplateLang("option-header.tmpl");
1645
1646 cgiSetSize("CHOICES", 2);
1647 cgiSetSize("TEXT", 2);
1648 cgiSetArray("CHOICES", 0, "None");
fa73b229 1649 cgiSetArray("TEXT", 0, cgiText(_("None")));
ef416fc2 1650
1651 if (strstr(ppd->protocols, "TBCP"))
1652 {
1653 cgiSetArray("CHOICES", 1, "TBCP");
1654 cgiSetArray("TEXT", 1, "TBCP");
1655 }
1656 else
1657 {
1658 cgiSetArray("CHOICES", 1, "BCP");
1659 cgiSetArray("TEXT", 1, "BCP");
1660 }
1661
1662 cgiSetVariable("KEYWORD", "protocol");
fa73b229 1663 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
ef416fc2 1664 cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
1665
1666 cgiCopyTemplateLang("option-pickone.tmpl");
1667
1668 cgiCopyTemplateLang("option-trailer.tmpl");
1669 }
1670
1671 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
1672 cgiEndHTML();
1673 }
1674 else
1675 {
1676 /*
1677 * Set default options...
1678 */
1679
bd7854cb 1680 fputs("DEBUG: Setting options...\n", stderr);
1681
ef416fc2 1682 out = cupsTempFile2(tempfile, sizeof(tempfile));
1683 in = cupsFileOpen(filename, "r");
1684
1685 if (!in || !out)
1686 {
1687 cgiSetVariable("ERROR", strerror(errno));
89d46774 1688 cgiStartHTML(cgiText(_("Set Printer Options")));
ef416fc2 1689 cgiCopyTemplateLang("error.tmpl");
1690 cgiEndHTML();
1691
1692 if (in)
1693 cupsFileClose(in);
1694
1695 if (out)
1696 {
1697 cupsFileClose(out);
1698 unlink(tempfile);
1699 }
1700
1701 unlink(filename);
1702 return;
1703 }
1704
1705 while (cupsFileGets(in, line, sizeof(line)))
1706 {
1707 if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
1708 continue;
1709 else if (strncmp(line, "*Default", 8))
1710 cupsFilePrintf(out, "%s\n", line);
1711 else
1712 {
1713 /*
1714 * Get default option name...
1715 */
1716
1717 strlcpy(keyword, line + 8, sizeof(keyword));
1718
1719 for (keyptr = keyword; *keyptr; keyptr ++)
1720 if (*keyptr == ':' || isspace(*keyptr & 255))
1721 break;
1722
1723 *keyptr = '\0';
1724
f301802f 1725 if (!strcmp(keyword, "PageRegion") ||
1726 !strcmp(keyword, "PaperDimension") ||
1727 !strcmp(keyword, "ImageableArea"))
ef416fc2 1728 var = cgiGetVariable("PageSize");
1729 else
1730 var = cgiGetVariable(keyword);
1731
1732 if (var != NULL)
1733 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
1734 else
1735 cupsFilePrintf(out, "%s\n", line);
1736 }
1737 }
1738
1739 if ((var = cgiGetVariable("protocol")) != NULL)
1740 cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
1741
1742 cupsFileClose(in);
1743 cupsFileClose(out);
1744
1745 /*
1746 * Build a CUPS_ADD_PRINTER request, which requires the following
1747 * attributes:
1748 *
1749 * attributes-charset
1750 * attributes-natural-language
1751 * printer-uri
1752 * job-sheets-default
1753 * [ppd file]
1754 */
1755
fa73b229 1756 request = ippNewRequest(CUPS_ADD_PRINTER);
ef416fc2 1757
a4d04587 1758 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1759 "localhost", 0, "/printers/%s",
1760 cgiGetVariable("PRINTER_NAME"));
ef416fc2 1761 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1762 NULL, uri);
1763
1764 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1765 "job-sheets-default", 2, NULL, NULL);
1766 attr->values[0].string.text = strdup(cgiGetVariable("job_sheets_start"));
1767 attr->values[1].string.text = strdup(cgiGetVariable("job_sheets_end"));
1768
1769 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
1770 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1771 "printer-error-policy", NULL, var);
1772
1773 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
1774 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
1775 "printer-op-policy", NULL, var);
1776
1777 /*
1778 * Do the request and get back a response...
1779 */
1780
fa73b229 1781 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
ef416fc2 1782
fa73b229 1783 if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 1784 {
fa73b229 1785 cgiStartHTML(title);
1786 cgiShowIPPError(_("Unable to set options:"));
ef416fc2 1787 }
1788 else
1789 {
1790 /*
1791 * Redirect successful updates back to the printer page...
1792 */
1793
1794 char refresh[1024]; /* Refresh URL */
1795
fa73b229 1796
ef416fc2 1797 cgiFormEncode(uri, printer, sizeof(uri));
480ef0fe 1798 snprintf(refresh, sizeof(refresh),
f301802f 1799 "5;URL=/admin/?OP=redirect&URL=/printers/%s", uri);
ef416fc2 1800 cgiSetVariable("refresh_page", refresh);
1801
fa73b229 1802 cgiStartHTML(title);
ef416fc2 1803
1804 cgiCopyTemplateLang("printer-configured.tmpl");
1805 }
1806
1807 cgiEndHTML();
1808
1809 unlink(tempfile);
1810 }
1811
1812 unlink(filename);
1813}
1814
1815
1816/*
1817 * 'do_config_server()' - Configure server settings.
1818 */
1819
1820static void
fa73b229 1821do_config_server(http_t *http) /* I - HTTP connection */
ef416fc2 1822{
1823 if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF"))
1824 {
1825 /*
1826 * Save basic setting changes...
1827 */
1828
757d2cad 1829 int num_settings; /* Number of server settings */
1830 cups_option_t *settings; /* Server settings */
d09495fa 1831 const char *debug_logging, /* DEBUG_LOGGING value */
1832 *remote_admin, /* REMOTE_ADMIN value */
f7deaa1a 1833 *remote_any, /* REMOTE_ANY value */
d09495fa 1834 *remote_printers,
1835 /* REMOTE_PRINTERS value */
1836 *share_printers,/* SHARE_PRINTERS value */
7594b224 1837#ifdef HAVE_GSSAPI
1838 *default_auth_type,
1839 /* DefaultAuthType value */
1840#endif /* HAVE_GSSAPI */
d09495fa 1841 *user_cancel_any;
1842 /* USER_CANCEL_ANY value */
757d2cad 1843
1844
d09495fa 1845 /*
1846 * Get the checkbox values from the form...
1847 */
1848
7594b224 1849 debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1850 remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1851 remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1852 remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1853 share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1854 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1855#ifdef HAVE_GSSAPI
1856 default_auth_type = cgiGetVariable("KERBEROS") ? "Negotiate" : "Basic";
1857
1858 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1859#endif /* HAVE_GSSAPI */
d09495fa 1860
1861 /*
1862 * Get the current server settings...
1863 */
1864
f899b121 1865 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
ef416fc2 1866 {
fa73b229 1867 cgiStartHTML(cgiText(_("Change Settings")));
480ef0fe 1868 cgiSetVariable("MESSAGE",
1869 cgiText(_("Unable to change server settings:")));
757d2cad 1870 cgiSetVariable("ERROR", cupsLastErrorString());
ef416fc2 1871 cgiCopyTemplateLang("error.tmpl");
d09495fa 1872 cgiEndHTML();
1873 return;
1874 }
1875
1876 /*
1877 * See if the settings have changed...
1878 */
1879
1880 if (strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1881 num_settings, settings)) ||
1882 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1883 num_settings, settings)) ||
f7deaa1a 1884 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1885 num_settings, settings)) ||
d09495fa 1886 strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
1887 num_settings, settings)) ||
1888 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1889 num_settings, settings)) ||
7594b224 1890#ifdef HAVE_GSSAPI
1891 !cupsGetOption("DefaultAuthType", num_settings, settings) ||
1892 strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1893 num_settings, settings)) ||
1894#endif /* HAVE_GSSAPI */
d09495fa 1895 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1896 num_settings, settings)))
1897 {
1898 /*
1899 * Settings *have* changed, so save the changes...
1900 */
1901
1902 cupsFreeOptions(num_settings, settings);
1903
1904 num_settings = 0;
1905 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1906 debug_logging, num_settings, &settings);
1907 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1908 remote_admin, num_settings, &settings);
f7deaa1a 1909 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1910 remote_any, num_settings, &settings);
d09495fa 1911 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1912 remote_printers, num_settings, &settings);
1913 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1914 share_printers, num_settings, &settings);
1915 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1916 user_cancel_any, num_settings, &settings);
7594b224 1917#ifdef HAVE_GSSAPI
1918 num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
1919 num_settings, &settings);
1920#endif /* HAVE_GSSAPI */
d09495fa 1921
f899b121 1922 if (!cupsAdminSetServerSettings(http, num_settings, settings))
d09495fa 1923 {
1924 cgiStartHTML(cgiText(_("Change Settings")));
1925 cgiSetVariable("MESSAGE",
1926 cgiText(_("Unable to change server settings:")));
1927 cgiSetVariable("ERROR", cupsLastErrorString());
1928 cgiCopyTemplateLang("error.tmpl");
1929 }
1930 else
1931 {
1932 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1933 cgiStartHTML(cgiText(_("Change Settings")));
1934 cgiCopyTemplateLang("restart.tmpl");
1935 }
ef416fc2 1936 }
1937 else
1938 {
d09495fa 1939 /*
1940 * No changes...
1941 */
1942
f301802f 1943 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
fa73b229 1944 cgiStartHTML(cgiText(_("Change Settings")));
d09495fa 1945 cgiCopyTemplateLang("norestart.tmpl");
ef416fc2 1946 }
1947
757d2cad 1948 cupsFreeOptions(num_settings, settings);
ef416fc2 1949
757d2cad 1950 cgiEndHTML();
ef416fc2 1951 }
1952 else if (cgiIsPOST())
1953 {
1954 /*
1955 * Save hand-edited config file...
1956 */
1957
1958 http_status_t status; /* PUT status */
1959 char tempfile[1024]; /* Temporary new cupsd.conf */
1960 int tempfd; /* Temporary file descriptor */
1961 cups_file_t *temp; /* Temporary file */
1962 const char *start, /* Start of line */
1963 *end; /* End of line */
1964
1965
1966 /*
1967 * Create a temporary file for the new cupsd.conf file...
1968 */
1969
1970 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1971 {
fa73b229 1972 cgiStartHTML(cgiText(_("Edit Configuration File")));
1973 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
ef416fc2 1974 cgiSetVariable("ERROR", strerror(errno));
1975 cgiCopyTemplateLang("error.tmpl");
1976 cgiEndHTML();
1977
1978 perror(tempfile);
1979 return;
1980 }
1981
1982 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
1983 {
fa73b229 1984 cgiStartHTML(cgiText(_("Edit Configuration File")));
1985 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
ef416fc2 1986 cgiSetVariable("ERROR", strerror(errno));
1987 cgiCopyTemplateLang("error.tmpl");
1988 cgiEndHTML();
1989
1990 perror(tempfile);
1991 close(tempfd);
1992 unlink(tempfile);
1993 return;
1994 }
1995
1996 /*
1997 * Copy the cupsd.conf text from the form variable...
1998 */
1999
2000 start = cgiGetVariable("CUPSDCONF");
2001 while (start)
2002 {
2003 if ((end = strstr(start, "\r\n")) == NULL)
2004 if ((end = strstr(start, "\n")) == NULL)
2005 end = start + strlen(start);
2006
2007 cupsFileWrite(temp, start, end - start);
2008 cupsFilePutChar(temp, '\n');
2009
2010 if (*end == '\r')
2011 start = end + 2;
2012 else if (*end == '\n')
2013 start = end + 1;
2014 else
2015 start = NULL;
2016 }
2017
2018 cupsFileClose(temp);
2019
2020 /*
2021 * Upload the configuration file to the server...
2022 */
2023
2024 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
2025
2026 if (status != HTTP_CREATED)
2027 {
480ef0fe 2028 cgiSetVariable("MESSAGE",
2029 cgiText(_("Unable to upload cupsd.conf file:")));
ef416fc2 2030 cgiSetVariable("ERROR", httpStatus(status));
fa73b229 2031
2032 cgiStartHTML(cgiText(_("Edit Configuration File")));
ef416fc2 2033 cgiCopyTemplateLang("error.tmpl");
2034 }
2035 else
2036 {
f301802f 2037 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
ef416fc2 2038
fa73b229 2039 cgiStartHTML(cgiText(_("Edit Configuration File")));
ef416fc2 2040 cgiCopyTemplateLang("restart.tmpl");
2041 }
2042
2043 cgiEndHTML();
2044
2045 unlink(tempfile);
2046 }
2047 else
2048 {
2049 struct stat info; /* cupsd.conf information */
2050 cups_file_t *cupsd; /* cupsd.conf file */
2051 char *buffer; /* Buffer for entire file */
2052 char filename[1024]; /* Filename */
2053 const char *server_root; /* Location of config files */
2054
2055
2056 /*
2057 * Locate the cupsd.conf file...
2058 */
2059
2060 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
2061 server_root = CUPS_SERVERROOT;
2062
2063 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
2064
2065 /*
2066 * Figure out the size...
2067 */
2068
2069 if (stat(filename, &info))
2070 {
fa73b229 2071 cgiStartHTML(cgiText(_("Edit Configuration File")));
480ef0fe 2072 cgiSetVariable("MESSAGE",
2073 cgiText(_("Unable to access cupsd.conf file:")));
ef416fc2 2074 cgiSetVariable("ERROR", strerror(errno));
2075 cgiCopyTemplateLang("error.tmpl");
2076 cgiEndHTML();
2077
2078 perror(filename);
2079 return;
2080 }
2081
2082 if (info.st_size > (1024 * 1024))
2083 {
fa73b229 2084 cgiStartHTML(cgiText(_("Edit Configuration File")));
480ef0fe 2085 cgiSetVariable("MESSAGE",
2086 cgiText(_("Unable to access cupsd.conf file:")));
fa73b229 2087 cgiSetVariable("ERROR",
2088 cgiText(_("Unable to edit cupsd.conf files larger than "
2089 "1MB!")));
ef416fc2 2090 cgiCopyTemplateLang("error.tmpl");
2091 cgiEndHTML();
2092
2093 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
2094 (long)info.st_size);
2095 return;
2096 }
2097
2098 /*
2099 * Open the cupsd.conf file...
2100 */
2101
2102 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
2103 {
2104 /*
2105 * Unable to open - log an error...
2106 */
2107
fa73b229 2108 cgiStartHTML(cgiText(_("Edit Configuration File")));
480ef0fe 2109 cgiSetVariable("MESSAGE",
2110 cgiText(_("Unable to access cupsd.conf file:")));
ef416fc2 2111 cgiSetVariable("ERROR", strerror(errno));
2112 cgiCopyTemplateLang("error.tmpl");
2113 cgiEndHTML();
2114
2115 perror(filename);
2116 return;
2117 }
2118
2119 /*
2120 * Allocate memory and load the file into a string buffer...
2121 */
2122
2123 buffer = calloc(1, info.st_size + 1);
2124
2125 cupsFileRead(cupsd, buffer, info.st_size);
2126 cupsFileClose(cupsd);
2127
2128 cgiSetVariable("CUPSDCONF", buffer);
2129 free(buffer);
2130
2131 /*
2132 * Show the current config file...
2133 */
2134
89d46774 2135 cgiStartHTML(cgiText(_("Edit Configuration File")));
ef416fc2 2136
2137 printf("<!-- \"%s\" -->\n", filename);
2138
2139 cgiCopyTemplateLang("edit-config.tmpl");
2140
2141 cgiEndHTML();
2142 }
2143}
2144
2145
2146/*
2147 * 'do_delete_class()' - Delete a class...
2148 */
2149
2150static void
fa73b229 2151do_delete_class(http_t *http) /* I - HTTP connection */
ef416fc2 2152{
fa73b229 2153 ipp_t *request; /* IPP request */
ef416fc2 2154 char uri[HTTP_MAX_URI]; /* Job URI */
2155 const char *pclass; /* Printer class name */
ef416fc2 2156
2157
89d46774 2158 /*
2159 * Get form variables...
2160 */
fa73b229 2161
ef416fc2 2162 if (cgiGetVariable("CONFIRM") == NULL)
2163 {
89d46774 2164 cgiStartHTML(cgiText(_("Delete Class")));
ef416fc2 2165 cgiCopyTemplateLang("class-confirm.tmpl");
2166 cgiEndHTML();
2167 return;
2168 }
2169
2170 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
a4d04587 2171 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2172 "localhost", 0, "/classes/%s", pclass);
ef416fc2 2173 else
2174 {
89d46774 2175 cgiStartHTML(cgiText(_("Delete Class")));
fa73b229 2176 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
ef416fc2 2177 cgiCopyTemplateLang("error.tmpl");
2178 cgiEndHTML();
2179 return;
2180 }
2181
2182 /*
2183 * Build a CUPS_DELETE_CLASS request, which requires the following
2184 * attributes:
2185 *
2186 * attributes-charset
2187 * attributes-natural-language
2188 * printer-uri
2189 */
2190
fa73b229 2191 request = ippNewRequest(CUPS_DELETE_CLASS);
ef416fc2 2192
2193 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2194 NULL, uri);
2195
2196 /*
2197 * Do the request and get back a response...
2198 */
2199
fa73b229 2200 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 2201
89d46774 2202 /*
2203 * Show the results...
2204 */
2205
f7deaa1a 2206 if (cupsLastError() <= IPP_OK_CONFLICT)
2207 {
2208 /*
2209 * Redirect successful updates back to the classes page...
2210 */
2211
2212 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2213 }
2214
89d46774 2215 cgiStartHTML(cgiText(_("Delete Class")));
2216
fa73b229 2217 if (cupsLastError() > IPP_OK_CONFLICT)
2218 cgiShowIPPError(_("Unable to delete class:"));
ef416fc2 2219 else
2220 cgiCopyTemplateLang("class-deleted.tmpl");
2221
2222 cgiEndHTML();
2223}
2224
2225
2226/*
2227 * 'do_delete_printer()' - Delete a printer...
2228 */
2229
2230static void
fa73b229 2231do_delete_printer(http_t *http) /* I - HTTP connection */
ef416fc2 2232{
fa73b229 2233 ipp_t *request; /* IPP request */
ef416fc2 2234 char uri[HTTP_MAX_URI]; /* Job URI */
2235 const char *printer; /* Printer printer name */
ef416fc2 2236
2237
89d46774 2238 /*
2239 * Get form variables...
2240 */
fa73b229 2241
ef416fc2 2242 if (cgiGetVariable("CONFIRM") == NULL)
2243 {
89d46774 2244 cgiStartHTML(cgiText(_("Delete Printer")));
ef416fc2 2245 cgiCopyTemplateLang("printer-confirm.tmpl");
2246 cgiEndHTML();
2247 return;
2248 }
2249
2250 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
a4d04587 2251 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2252 "localhost", 0, "/printers/%s", printer);
ef416fc2 2253 else
2254 {
89d46774 2255 cgiStartHTML(cgiText(_("Delete Printer")));
fa73b229 2256 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
ef416fc2 2257 cgiCopyTemplateLang("error.tmpl");
2258 cgiEndHTML();
2259 return;
2260 }
2261
2262 /*
2263 * Build a CUPS_DELETE_PRINTER request, which requires the following
2264 * attributes:
2265 *
2266 * attributes-charset
2267 * attributes-natural-language
2268 * printer-uri
2269 */
2270
fa73b229 2271 request = ippNewRequest(CUPS_DELETE_PRINTER);
ef416fc2 2272
2273 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2274 NULL, uri);
2275
2276 /*
2277 * Do the request and get back a response...
2278 */
2279
fa73b229 2280 ippDelete(cupsDoRequest(http, request, "/admin/"));
2281
89d46774 2282 /*
2283 * Show the results...
2284 */
2285
f7deaa1a 2286 if (cupsLastError() <= IPP_OK_CONFLICT)
2287 {
2288 /*
2289 * Redirect successful updates back to the printers page...
2290 */
2291
2292 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2293 }
2294
89d46774 2295 cgiStartHTML(cgiText(_("Delete Printer")));
2296
fa73b229 2297 if (cupsLastError() > IPP_OK_CONFLICT)
2298 cgiShowIPPError(_("Unable to delete printer:"));
2299 else
2300 cgiCopyTemplateLang("printer-deleted.tmpl");
2301
2302 cgiEndHTML();
2303}
2304
2305
2306/*
2307 * 'do_export()' - Export printers to Samba...
2308 */
2309
2310static void
2311do_export(http_t *http) /* I - HTTP connection */
2312{
2313 int i, j; /* Looping vars */
2314 ipp_t *request, /* IPP request */
2315 *response; /* IPP response */
2316 const char *username, /* Samba username */
2317 *password, /* Samba password */
2318 *export_all; /* Export all printers? */
2319 int export_count, /* Number of printers to export */
2320 printer_count; /* Number of available printers */
757d2cad 2321 const char *name, /* What name to pull */
2322 *dest; /* Current destination */
2323 char ppd[1024]; /* PPD file */
fa73b229 2324
2325
fa73b229 2326 /*
2327 * Get form data...
2328 */
2329
2330 username = cgiGetVariable("USERNAME");
2331 password = cgiGetVariable("PASSWORD");
2332 export_all = cgiGetVariable("EXPORT_ALL");
2333 export_count = cgiGetSize("EXPORT_NAME");
2334
fa73b229 2335 /*
2336 * Get list of available printers...
2337 */
ef416fc2 2338
fa73b229 2339 cgiSetSize("PRINTER_NAME", 0);
2340 cgiSetSize("PRINTER_EXPORT", 0);
ef416fc2 2341
fa73b229 2342 request = ippNewRequest(CUPS_GET_PRINTERS);
2343
2344 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2345 "printer-type", 0);
2346
2347 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2348 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
2349 CUPS_PRINTER_IMPLICIT);
2350
2351 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2352 "requested-attributes", NULL, "printer-name");
2353
2354 if ((response = cupsDoRequest(http, request, "/")) != NULL)
ef416fc2 2355 {
fa73b229 2356 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2357 ippDelete(response);
2358
2359 if (!export_all)
2360 {
2361 printer_count = cgiGetSize("PRINTER_NAME");
2362
2363 for (i = 0; i < printer_count; i ++)
2364 {
757d2cad 2365 dest = cgiGetArray("PRINTER_NAME", i);
2366
fa73b229 2367 for (j = 0; j < export_count; j ++)
757d2cad 2368 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
fa73b229 2369 break;
2370
2371 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
2372 }
2373 }
ef416fc2 2374 }
ef416fc2 2375
757d2cad 2376 /*
2377 * Export or get the printers to export...
2378 */
2379
2380 if (username && *username && password && *password &&
2381 (export_all || export_count > 0))
2382 {
2383 /*
2384 * Do export...
2385 */
2386
2387 fputs("DEBUG: Export printers...\n", stderr);
2388
2389 if (export_all)
2390 {
2391 name = "PRINTER_NAME";
2392 export_count = cgiGetSize("PRINTER_NAME");
2393 }
2394 else
2395 name = "EXPORT_NAME";
2396
2397 for (i = 0; i < export_count; i ++)
2398 {
2399 dest = cgiGetArray(name, i);
2400
2401 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2402 break;
2403
2404 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2405 stderr);
2406
2407 unlink(ppd);
2408
2409 if (!j)
2410 break;
2411 }
2412
2413 if (i < export_count)
2414 cgiSetVariable("ERROR", cupsLastErrorString());
2415 else
2416 {
2417 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2418 cgiCopyTemplateLang("samba-exported.tmpl");
2419 cgiEndHTML();
2420 return;
2421 }
2422 }
2423 else if (username && !*username)
2424 cgiSetVariable("ERROR",
2425 cgiText(_("A Samba username is required to export "
2426 "printer drivers!")));
2427 else if (username && (!password || !*password))
2428 cgiSetVariable("ERROR",
2429 cgiText(_("A Samba password is required to export "
2430 "printer drivers!")));
2431
fa73b229 2432 /*
2433 * Show form...
2434 */
2435
757d2cad 2436 cgiStartHTML(cgiText(_("Export Printers to Samba")));
fa73b229 2437 cgiCopyTemplateLang("samba-export.tmpl");
ef416fc2 2438 cgiEndHTML();
2439}
2440
2441
2442/*
2443 * 'do_menu()' - Show the main menu...
2444 */
2445
2446static void
fa73b229 2447do_menu(http_t *http) /* I - HTTP connection */
ef416fc2 2448{
757d2cad 2449 int num_settings; /* Number of server settings */
2450 cups_option_t *settings; /* Server settings */
2451 const char *val; /* Setting value */
2452 char filename[1024]; /* Temporary filename */
fa73b229 2453 const char *datadir; /* Location of data files */
ef416fc2 2454 ipp_t *request, /* IPP request */
2455 *response; /* IPP response */
2456 ipp_attribute_t *attr; /* IPP attribute */
2457
2458
2459 /*
757d2cad 2460 * Get the current server settings...
ef416fc2 2461 */
2462
f899b121 2463 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
ef416fc2 2464 {
480ef0fe 2465 cgiSetVariable("SETTINGS_MESSAGE",
2466 cgiText(_("Unable to open cupsd.conf file:")));
2467 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
ef416fc2 2468 }
ef416fc2 2469
757d2cad 2470 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2471 settings)) != NULL && atoi(val))
2472 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
ef416fc2 2473
757d2cad 2474 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2475 settings)) != NULL && atoi(val))
2476 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
ef416fc2 2477
f7deaa1a 2478 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2479 settings)) != NULL && atoi(val))
2480 cgiSetVariable("REMOTE_ANY", "CHECKED");
2481
757d2cad 2482 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2483 settings)) != NULL && atoi(val))
2484 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
ef416fc2 2485
757d2cad 2486 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2487 settings)) != NULL && atoi(val))
2488 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
ef416fc2 2489
757d2cad 2490 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2491 settings)) != NULL && atoi(val))
2492 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
ef416fc2 2493
7594b224 2494#ifdef HAVE_GSSAPI
2495 cgiSetVariable("HAVE_GSSAPI", "1");
2496
2497 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2498 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2499 cgiSetVariable("KERBEROS", "CHECKED");
2500#endif /* HAVE_GSSAPI */
2501
480ef0fe 2502 cupsFreeOptions(num_settings, settings);
2503
ef416fc2 2504 /*
2505 * Get the list of printers and their devices...
2506 */
2507
fa73b229 2508 request = ippNewRequest(CUPS_GET_PRINTERS);
ef416fc2 2509
2510 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2511 "requested-attributes", NULL, "device-uri");
2512
2513 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2514 CUPS_PRINTER_LOCAL);
2515 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2516 CUPS_PRINTER_LOCAL);
2517
2518 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2519 {
2520 /*
2521 * Got the printer list, now load the devices...
2522 */
2523
2524 int i; /* Looping var */
fa73b229 2525 cups_array_t *printer_devices; /* Printer devices for local printers */
2526 char *printer_device; /* Current printer device */
ef416fc2 2527
2528
2529 /*
fa73b229 2530 * Allocate an array and copy the device strings...
ef416fc2 2531 */
2532
fa73b229 2533 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
ef416fc2 2534
fa73b229 2535 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2536 attr;
2537 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
ef416fc2 2538 {
fa73b229 2539 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
ef416fc2 2540 }
ef416fc2 2541
2542 /*
2543 * Free the printer list and get the device list...
2544 */
2545
2546 ippDelete(response);
2547
fa73b229 2548 request = ippNewRequest(CUPS_GET_DEVICES);
ef416fc2 2549
2550 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2551 {
2552 /*
2553 * Got the device list, let's parse it...
2554 */
2555
2556 const char *device_uri, /* device-uri attribute value */
2557 *device_make_and_model, /* device-make-and-model value */
2558 *device_info; /* device-info value */
2559
2560
2561 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2562 {
2563 /*
2564 * Skip leading attributes until we hit a device...
2565 */
2566
2567 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2568 attr = attr->next;
2569
2570 if (!attr)
2571 break;
2572
2573 /*
2574 * Pull the needed attributes from this device...
2575 */
2576
2577 device_info = NULL;
2578 device_make_and_model = NULL;
2579 device_uri = NULL;
2580
2581 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2582 {
fa73b229 2583 if (!strcmp(attr->name, "device-info") &&
ef416fc2 2584 attr->value_tag == IPP_TAG_TEXT)
2585 device_info = attr->values[0].string.text;
2586
fa73b229 2587 if (!strcmp(attr->name, "device-make-and-model") &&
ef416fc2 2588 attr->value_tag == IPP_TAG_TEXT)
2589 device_make_and_model = attr->values[0].string.text;
2590
fa73b229 2591 if (!strcmp(attr->name, "device-uri") &&
ef416fc2 2592 attr->value_tag == IPP_TAG_URI)
2593 device_uri = attr->values[0].string.text;
2594
2595 attr = attr->next;
2596 }
2597
2598 /*
2599 * See if we have everything needed...
2600 */
2601
2602 if (device_info && device_make_and_model && device_uri &&
2603 strcasecmp(device_make_and_model, "unknown") &&
2604 strchr(device_uri, ':'))
2605 {
2606 /*
2607 * Yes, now see if there is already a printer for this
2608 * device...
2609 */
2610
fa73b229 2611 if (!cupsArrayFind(printer_devices, (void *)device_uri))
ef416fc2 2612 {
2613 /*
2614 * Not found, so it must be a new printer...
2615 */
2616
2617 char options[1024], /* Form variables for this device */
2618 *options_ptr; /* Pointer into string */
2619 const char *ptr; /* Pointer into device string */
2620
2621
2622 /*
2623 * Format the printer name variable for this device...
2624 *
2625 * We use the device-info string first, then device-uri,
2626 * and finally device-make-and-model to come up with a
2627 * suitable name.
2628 */
2629
f7deaa1a 2630 strcpy(options, "TEMPLATE_NAME=");
ef416fc2 2631 options_ptr = options + strlen(options);
2632
2633 if (strncasecmp(device_info, "unknown", 7))
2634 ptr = device_info;
2635 else if ((ptr = strstr(device_uri, "://")) != NULL)
2636 ptr += 3;
2637 else
2638 ptr = device_make_and_model;
2639
2640 for (;
2641 options_ptr < (options + sizeof(options) - 1) && *ptr;
2642 ptr ++)
480ef0fe 2643 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2644 *ptr == '.')
ef416fc2 2645 *options_ptr++ = *ptr;
2646 else if ((*ptr == ' ' || *ptr == '/') && options_ptr[-1] != '_')
2647 *options_ptr++ = '_';
2648 else if (*ptr == '?' || *ptr == '(')
2649 break;
2650
2651 /*
2652 * Then add the make and model in the printer info, so
2653 * that MacOS clients see something reasonable...
2654 */
2655
2656 strlcpy(options_ptr, "&PRINTER_LOCATION=Local+Printer"
2657 "&PRINTER_INFO=",
2658 sizeof(options) - (options_ptr - options));
2659 options_ptr += strlen(options_ptr);
2660
2661 cgiFormEncode(options_ptr, device_make_and_model,
2662 sizeof(options) - (options_ptr - options));
2663 options_ptr += strlen(options_ptr);
2664
2665 /*
2666 * Then copy the device URI...
2667 */
2668
2669 strlcpy(options_ptr, "&DEVICE_URI=",
2670 sizeof(options) - (options_ptr - options));
2671 options_ptr += strlen(options_ptr);
2672
2673 cgiFormEncode(options_ptr, device_uri,
fa73b229 2674 sizeof(options) - (options_ptr - options));
ef416fc2 2675 options_ptr += strlen(options_ptr);
2676
2677 if (options_ptr < (options + sizeof(options) - 1))
2678 {
2679 *options_ptr++ = '|';
2680 cgiFormEncode(options_ptr, device_make_and_model,
2681 sizeof(options) - (options_ptr - options));
2682 }
2683
2684 /*
2685 * Finally, set the form variables for this printer...
2686 */
2687
2688 cgiSetArray("device_info", i, device_info);
2689 cgiSetArray("device_make_and_model", i, device_make_and_model);
2690 cgiSetArray("device_options", i, options);
2691 cgiSetArray("device_uri", i, device_uri);
2692 i ++;
2693 }
2694 }
2695
2696 if (!attr)
2697 break;
2698 }
2699
fa73b229 2700 ippDelete(response);
2701
ef416fc2 2702 /*
2703 * Free the device list...
2704 */
2705
fa73b229 2706 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2707 printer_device;
2708 printer_device = (char *)cupsArrayNext(printer_devices))
2709 free(printer_device);
ef416fc2 2710
fa73b229 2711 cupsArrayDelete(printer_devices);
ef416fc2 2712 }
2713 }
2714
fa73b229 2715 /*
2716 * See if Samba and the Windows drivers are installed...
2717 */
2718
2719 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2720 datadir = CUPS_DATADIR;
2721
757d2cad 2722 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2723 if (!access(filename, R_OK))
fa73b229 2724 {
2725 /*
2726 * Found Windows 2000 driver file, see if we have smbclient and
2727 * rpcclient...
2728 */
2729
757d2cad 2730 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2731 sizeof(filename)) &&
2732 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2733 sizeof(filename)))
fa73b229 2734 cgiSetVariable("HAVE_SAMBA", "Y");
2735 else
2736 {
757d2cad 2737 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2738 sizeof(filename)))
fa73b229 2739 fputs("ERROR: smbclient not found!\n", stderr);
2740
757d2cad 2741 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2742 sizeof(filename)))
fa73b229 2743 fputs("ERROR: rpcclient not found!\n", stderr);
2744 }
2745 }
2746 else
757d2cad 2747 perror(filename);
fa73b229 2748
f7deaa1a 2749 /*
2750 * Subscriptions...
2751 */
2752
2753 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2754
2755 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2756 NULL, "ipp://localhost/");
2757
2758 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2759 {
2760 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2761 ippDelete(response);
2762 }
2763
ef416fc2 2764 /*
2765 * Finally, show the main menu template...
2766 */
2767
757d2cad 2768 cgiStartHTML(cgiText(_("Administration")));
2769
ef416fc2 2770 cgiCopyTemplateLang("admin.tmpl");
2771
2772 cgiEndHTML();
2773}
2774
2775
2776/*
2777 * 'do_printer_op()' - Do a printer operation.
2778 */
2779
2780static void
2781do_printer_op(http_t *http, /* I - HTTP connection */
ef416fc2 2782 ipp_op_t op, /* I - Operation to perform */
2783 const char *title) /* I - Title of page */
2784{
fa73b229 2785 ipp_t *request; /* IPP request */
ef416fc2 2786 char uri[HTTP_MAX_URI]; /* Printer URI */
fa73b229 2787 const char *printer, /* Printer name (purge-jobs) */
2788 *is_class; /* Is a class? */
ef416fc2 2789
2790
fa73b229 2791 is_class = cgiGetVariable("IS_CLASS");
2792 printer = cgiGetVariable("PRINTER_NAME");
2793
2794 if (!printer)
ef416fc2 2795 {
fa73b229 2796 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
ef416fc2 2797 cgiStartHTML(title);
2798 cgiCopyTemplateLang("error.tmpl");
2799 cgiEndHTML();
2800 return;
2801 }
2802
2803 /*
2804 * Build a printer request, which requires the following
2805 * attributes:
2806 *
2807 * attributes-charset
2808 * attributes-natural-language
2809 * printer-uri
2810 */
2811
fa73b229 2812 request = ippNewRequest(op);
ef416fc2 2813
a4d04587 2814 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2815 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2816 printer);
ef416fc2 2817 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2818 NULL, uri);
2819
2820 /*
2821 * Do the request and get back a response...
2822 */
2823
fa73b229 2824 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 2825
fa73b229 2826 if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 2827 {
2828 cgiStartHTML(title);
fa73b229 2829 cgiShowIPPError(_("Unable to change printer:"));
ef416fc2 2830 }
2831 else
2832 {
2833 /*
2834 * Redirect successful updates back to the printer page...
2835 */
2836
fa73b229 2837 char url[1024], /* Printer/class URL */
2838 refresh[1024]; /* Refresh URL */
ef416fc2 2839
fa73b229 2840
2841 cgiRewriteURL(uri, url, sizeof(url), NULL);
2842 cgiFormEncode(uri, url, sizeof(uri));
f301802f 2843 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
ef416fc2 2844 cgiSetVariable("refresh_page", refresh);
2845
2846 cgiStartHTML(title);
2847
2848 if (op == IPP_PAUSE_PRINTER)
2849 cgiCopyTemplateLang("printer-stop.tmpl");
2850 else if (op == IPP_RESUME_PRINTER)
2851 cgiCopyTemplateLang("printer-start.tmpl");
2852 else if (op == CUPS_ACCEPT_JOBS)
2853 cgiCopyTemplateLang("printer-accept.tmpl");
2854 else if (op == CUPS_REJECT_JOBS)
2855 cgiCopyTemplateLang("printer-reject.tmpl");
2856 else if (op == IPP_PURGE_JOBS)
2857 cgiCopyTemplateLang("printer-purge.tmpl");
2858 else if (op == CUPS_SET_DEFAULT)
2859 cgiCopyTemplateLang("printer-default.tmpl");
2860 }
2861
2862 cgiEndHTML();
2863}
2864
2865
2866/*
2867 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2868 */
2869
2870static void
fa73b229 2871do_set_allowed_users(http_t *http) /* I - HTTP connection */
ef416fc2 2872{
2873 int i; /* Looping var */
2874 ipp_t *request, /* IPP request */
2875 *response; /* IPP response */
2876 char uri[HTTP_MAX_URI]; /* Printer URI */
2877 const char *printer, /* Printer name (purge-jobs) */
fa73b229 2878 *is_class, /* Is a class? */
ef416fc2 2879 *users, /* List of users or groups */
2880 *type; /* Allow/deny type */
2881 int num_users; /* Number of users */
2882 char *ptr, /* Pointer into users string */
2883 *end, /* Pointer to end of users string */
2884 quote; /* Quote character */
2885 ipp_attribute_t *attr; /* Attribute */
ef416fc2 2886 static const char * const attrs[] = /* Requested attributes */
2887 {
2888 "requesting-user-name-allowed",
2889 "requesting-user-name-denied"
2890 };
2891
2892
fa73b229 2893 is_class = cgiGetVariable("IS_CLASS");
2894 printer = cgiGetVariable("PRINTER_NAME");
2895
2896 if (!printer)
ef416fc2 2897 {
fa73b229 2898 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2899 cgiStartHTML(cgiText(_("Set Allowed Users")));
ef416fc2 2900 cgiCopyTemplateLang("error.tmpl");
2901 cgiEndHTML();
2902 return;
2903 }
2904
2905 users = cgiGetVariable("users");
2906 type = cgiGetVariable("type");
2907
2908 if (!users || !type ||
2909 (strcmp(type, "requesting-user-name-allowed") &&
2910 strcmp(type, "requesting-user-name-denied")))
2911 {
2912 /*
2913 * Build a Get-Printer-Attributes request, which requires the following
2914 * attributes:
2915 *
2916 * attributes-charset
2917 * attributes-natural-language
2918 * printer-uri
2919 * requested-attributes
2920 */
2921
fa73b229 2922 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
ef416fc2 2923
a4d04587 2924 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2925 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2926 printer);
ef416fc2 2927 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2928 NULL, uri);
2929
2930 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2931 "requested-attributes",
2932 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
2933
2934 /*
2935 * Do the request and get back a response...
2936 */
2937
fa73b229 2938 if ((response = cupsDoRequest(http, request, "/")) != NULL)
ef416fc2 2939 {
ef416fc2 2940 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2941
2942 ippDelete(response);
2943 }
ef416fc2 2944
fa73b229 2945 cgiStartHTML(cgiText(_("Set Allowed Users")));
ef416fc2 2946
fa73b229 2947 if (cupsLastError() > IPP_OK_CONFLICT)
2948 cgiShowIPPError(_("Unable to get printer attributes:"));
ef416fc2 2949 else
2950 cgiCopyTemplateLang("users.tmpl");
2951
2952 cgiEndHTML();
2953 }
2954 else
2955 {
2956 /*
2957 * Save the changes...
2958 */
2959
2960 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
2961 {
2962 /*
2963 * Skip whitespace and commas...
2964 */
2965
2966 while (*ptr == ',' || isspace(*ptr & 255))
2967 ptr ++;
2968
2969 if (*ptr == '\'' || *ptr == '\"')
2970 {
2971 /*
2972 * Scan quoted name...
2973 */
2974
2975 quote = *ptr++;
2976
2977 for (end = ptr; *end; end ++)
2978 if (*end == quote)
2979 break;
2980 }
2981 else
2982 {
2983 /*
2984 * Scan space or comma-delimited name...
2985 */
2986
2987 for (end = ptr; *end; end ++)
2988 if (isspace(*end & 255) || *end == ',')
2989 break;
2990 }
2991
2992 /*
2993 * Advance to the next name...
2994 */
2995
2996 ptr = end;
2997 }
2998
2999 /*
fa73b229 3000 * Build a CUPS-Add-Printer/Class request, which requires the following
ef416fc2 3001 * attributes:
3002 *
3003 * attributes-charset
3004 * attributes-natural-language
3005 * printer-uri
3006 * requesting-user-name-{allowed,denied}
3007 */
3008
fa73b229 3009 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 3010
a4d04587 3011 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3012 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3013 printer);
ef416fc2 3014 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3015 NULL, uri);
3016
3017 if (num_users == 0)
e1d6a774 3018 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
ef416fc2 3019 "requesting-user-name-allowed", NULL, "all");
3020 else
3021 {
e1d6a774 3022 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
ef416fc2 3023 type, num_users, NULL, NULL);
3024
3025 for (i = 0, ptr = (char *)users; *ptr; i ++)
3026 {
3027 /*
3028 * Skip whitespace and commas...
3029 */
3030
3031 while (*ptr == ',' || isspace(*ptr & 255))
3032 ptr ++;
3033
3034 if (*ptr == '\'' || *ptr == '\"')
3035 {
3036 /*
3037 * Scan quoted name...
3038 */
3039
3040 quote = *ptr++;
3041
3042 for (end = ptr; *end; end ++)
3043 if (*end == quote)
3044 break;
3045 }
3046 else
3047 {
3048 /*
3049 * Scan space or comma-delimited name...
3050 */
3051
3052 for (end = ptr; *end; end ++)
3053 if (isspace(*end & 255) || *end == ',')
3054 break;
3055 }
3056
3057 /*
3058 * Terminate the name...
3059 */
3060
3061 if (*end)
3062 *end++ = '\0';
3063
3064 /*
3065 * Add the name...
3066 */
3067
3068 attr->values[i].string.text = strdup(ptr);
3069
3070 /*
3071 * Advance to the next name...
3072 */
3073
3074 ptr = end;
3075 }
3076 }
3077
3078 /*
3079 * Do the request and get back a response...
3080 */
3081
fa73b229 3082 ippDelete(cupsDoRequest(http, request, "/admin/"));
ef416fc2 3083
fa73b229 3084 if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3085 {
fa73b229 3086 cgiStartHTML(cgiText(_("Set Allowed Users")));
3087 cgiShowIPPError(_("Unable to change printer:"));
ef416fc2 3088 }
3089 else
3090 {
3091 /*
3092 * Redirect successful updates back to the printer page...
3093 */
3094
fa73b229 3095 char url[1024], /* Printer/class URL */
3096 refresh[1024]; /* Refresh URL */
ef416fc2 3097
fa73b229 3098
3099 cgiRewriteURL(uri, url, sizeof(url), NULL);
3100 cgiFormEncode(uri, url, sizeof(uri));
f301802f 3101 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
3102 uri);
ef416fc2 3103 cgiSetVariable("refresh_page", refresh);
3104
fa73b229 3105 cgiStartHTML(cgiText(_("Set Allowed Users")));
ef416fc2 3106
fa73b229 3107 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3108 "printer-modified.tmpl");
ef416fc2 3109 }
3110
3111 cgiEndHTML();
3112 }
3113}
3114
3115
3116/*
3117 * 'do_set_sharing()' - Set printer-is-shared value...
3118 */
3119
3120static void
fa73b229 3121do_set_sharing(http_t *http) /* I - HTTP connection */
ef416fc2 3122{
3123 ipp_t *request, /* IPP request */
3124 *response; /* IPP response */
3125 char uri[HTTP_MAX_URI]; /* Printer URI */
3126 const char *printer, /* Printer name */
fa73b229 3127 *is_class, /* Is a class? */
ef416fc2 3128 *shared; /* Sharing value */
ef416fc2 3129
3130
fa73b229 3131 is_class = cgiGetVariable("IS_CLASS");
3132 printer = cgiGetVariable("PRINTER_NAME");
3133 shared = cgiGetVariable("SHARED");
ef416fc2 3134
fa73b229 3135 if (!printer || !shared)
ef416fc2 3136 {
fa73b229 3137 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3138 cgiStartHTML(cgiText(_("Set Publishing")));
ef416fc2 3139 cgiCopyTemplateLang("error.tmpl");
3140 cgiEndHTML();
3141 return;
3142 }
3143
3144 /*
fa73b229 3145 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3146 * following attributes:
ef416fc2 3147 *
3148 * attributes-charset
3149 * attributes-natural-language
3150 * printer-uri
3151 * printer-is-shared
3152 */
3153
fa73b229 3154 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
ef416fc2 3155
a4d04587 3156 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3157 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3158 printer);
ef416fc2 3159 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3160 NULL, uri);
3161
3162 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3163
3164 /*
3165 * Do the request and get back a response...
3166 */
3167
3168 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3169 {
ef416fc2 3170 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3171
3172 ippDelete(response);
3173 }
ef416fc2 3174
fa73b229 3175 if (cupsLastError() > IPP_OK_CONFLICT)
ef416fc2 3176 {
fa73b229 3177 cgiStartHTML(cgiText(_("Set Publishing")));
3178 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
ef416fc2 3179 }
3180 else
3181 {
3182 /*
3183 * Redirect successful updates back to the printer page...
3184 */
3185
fa73b229 3186 char url[1024], /* Printer/class URL */
3187 refresh[1024]; /* Refresh URL */
ef416fc2 3188
ef416fc2 3189
fa73b229 3190 cgiRewriteURL(uri, url, sizeof(url), NULL);
3191 cgiFormEncode(uri, url, sizeof(uri));
f301802f 3192 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
fa73b229 3193 cgiSetVariable("refresh_page", refresh);
ef416fc2 3194
fa73b229 3195 cgiStartHTML(cgiText(_("Set Publishing")));
3196 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3197 "printer-modified.tmpl");
ef416fc2 3198 }
3199
3200 cgiEndHTML();
3201}
3202
3203
3204/*
3205 * 'match_string()' - Return the number of matching characters.
3206 */
3207
3208static int /* O - Number of matching characters */
3209match_string(const char *a, /* I - First string */
3210 const char *b) /* I - Second string */
3211{
3212 int count; /* Number of matching characters */
3213
3214
3215 /*
3216 * Loop through both strings until we hit the end of either or we find
3217 * a non-matching character. For the purposes of comparison, we ignore
3218 * whitespace and do a case-insensitive comparison so that we have a
3219 * better chance of finding a match...
3220 */
3221
3222 for (count = 0; *a && *b; a++, b++, count ++)
3223 {
3224 /*
3225 * Skip leading whitespace characters...
3226 */
3227
3228 while (isspace(*a & 255))
3229 a ++;
3230
3231 while (isspace(*b & 255))
3232 b ++;
3233
3234 /*
3235 * Break out if we run out of characters...
3236 */
3237
3238 if (!*a || !*b)
3239 break;
3240
3241 /*
3242 * Do a case-insensitive comparison of the next two chars...
3243 */
3244
3245 if (tolower(*a & 255) != tolower(*b & 255))
3246 break;
3247 }
3248
3249 return (count);
3250}
3251
3252
3253/*
f899b121 3254 * End of "$Id: admin.c 6378 2007-03-21 07:18:18Z mike $".
ef416fc2 3255 */