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