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