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