]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/admin.c
Import CUPS 1.4svn r7023 into easysw/current.
[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 #ifdef HAVE_GSSAPI
1392 default_auth_type = cgiGetVariable("KERBEROS") ? "Negotiate" : "Basic";
1393
1394 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1395 #endif /* HAVE_GSSAPI */
1396
1397 /*
1398 * Get the current server settings...
1399 */
1400
1401 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
1402 {
1403 cgiStartHTML(cgiText(_("Change Settings")));
1404 cgiSetVariable("MESSAGE",
1405 cgiText(_("Unable to change server settings:")));
1406 cgiSetVariable("ERROR", cupsLastErrorString());
1407 cgiCopyTemplateLang("error.tmpl");
1408 cgiEndHTML();
1409 return;
1410 }
1411
1412 /*
1413 * See if the settings have changed...
1414 */
1415
1416 if (strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1417 num_settings, settings)) ||
1418 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1419 num_settings, settings)) ||
1420 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1421 num_settings, settings)) ||
1422 strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
1423 num_settings, settings)) ||
1424 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1425 num_settings, settings)) ||
1426 #ifdef HAVE_GSSAPI
1427 !cupsGetOption("DefaultAuthType", num_settings, settings) ||
1428 strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1429 num_settings, settings)) ||
1430 #endif /* HAVE_GSSAPI */
1431 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1432 num_settings, settings)))
1433 {
1434 /*
1435 * Settings *have* changed, so save the changes...
1436 */
1437
1438 cupsFreeOptions(num_settings, settings);
1439
1440 num_settings = 0;
1441 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1442 debug_logging, num_settings, &settings);
1443 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1444 remote_admin, num_settings, &settings);
1445 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1446 remote_any, num_settings, &settings);
1447 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1448 remote_printers, num_settings, &settings);
1449 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1450 share_printers, num_settings, &settings);
1451 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1452 user_cancel_any, num_settings, &settings);
1453 #ifdef HAVE_GSSAPI
1454 num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
1455 num_settings, &settings);
1456 #endif /* HAVE_GSSAPI */
1457
1458 if (!cupsAdminSetServerSettings(http, num_settings, settings))
1459 {
1460 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1461 {
1462 puts("Status: 401\n");
1463 exit(0);
1464 }
1465
1466 cgiStartHTML(cgiText(_("Change Settings")));
1467 cgiSetVariable("MESSAGE",
1468 cgiText(_("Unable to change server settings:")));
1469 cgiSetVariable("ERROR", cupsLastErrorString());
1470 cgiCopyTemplateLang("error.tmpl");
1471 }
1472 else
1473 {
1474 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1475 cgiStartHTML(cgiText(_("Change Settings")));
1476 cgiCopyTemplateLang("restart.tmpl");
1477 }
1478 }
1479 else
1480 {
1481 /*
1482 * No changes...
1483 */
1484
1485 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1486 cgiStartHTML(cgiText(_("Change Settings")));
1487 cgiCopyTemplateLang("norestart.tmpl");
1488 }
1489
1490 cupsFreeOptions(num_settings, settings);
1491
1492 cgiEndHTML();
1493 }
1494 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1495 {
1496 /*
1497 * Save hand-edited config file...
1498 */
1499
1500 http_status_t status; /* PUT status */
1501 char tempfile[1024]; /* Temporary new cupsd.conf */
1502 int tempfd; /* Temporary file descriptor */
1503 cups_file_t *temp; /* Temporary file */
1504 const char *start, /* Start of line */
1505 *end; /* End of line */
1506
1507
1508 /*
1509 * Create a temporary file for the new cupsd.conf file...
1510 */
1511
1512 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1513 {
1514 cgiStartHTML(cgiText(_("Edit Configuration File")));
1515 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1516 cgiSetVariable("ERROR", strerror(errno));
1517 cgiCopyTemplateLang("error.tmpl");
1518 cgiEndHTML();
1519
1520 perror(tempfile);
1521 return;
1522 }
1523
1524 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
1525 {
1526 cgiStartHTML(cgiText(_("Edit Configuration File")));
1527 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1528 cgiSetVariable("ERROR", strerror(errno));
1529 cgiCopyTemplateLang("error.tmpl");
1530 cgiEndHTML();
1531
1532 perror(tempfile);
1533 close(tempfd);
1534 unlink(tempfile);
1535 return;
1536 }
1537
1538 /*
1539 * Copy the cupsd.conf text from the form variable...
1540 */
1541
1542 start = cgiGetVariable("CUPSDCONF");
1543 while (start)
1544 {
1545 if ((end = strstr(start, "\r\n")) == NULL)
1546 if ((end = strstr(start, "\n")) == NULL)
1547 end = start + strlen(start);
1548
1549 cupsFileWrite(temp, start, end - start);
1550 cupsFilePutChar(temp, '\n');
1551
1552 if (*end == '\r')
1553 start = end + 2;
1554 else if (*end == '\n')
1555 start = end + 1;
1556 else
1557 start = NULL;
1558 }
1559
1560 cupsFileClose(temp);
1561
1562 /*
1563 * Upload the configuration file to the server...
1564 */
1565
1566 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1567
1568 if (status == HTTP_UNAUTHORIZED)
1569 {
1570 puts("Status: 401\n");
1571 unlink(tempfile);
1572 exit(0);
1573 }
1574 else if (status != HTTP_CREATED)
1575 {
1576 cgiSetVariable("MESSAGE",
1577 cgiText(_("Unable to upload cupsd.conf file:")));
1578 cgiSetVariable("ERROR", httpStatus(status));
1579
1580 cgiStartHTML(cgiText(_("Edit Configuration File")));
1581 cgiCopyTemplateLang("error.tmpl");
1582 }
1583 else
1584 {
1585 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1586
1587 cgiStartHTML(cgiText(_("Edit Configuration File")));
1588 cgiCopyTemplateLang("restart.tmpl");
1589 }
1590
1591 cgiEndHTML();
1592
1593 unlink(tempfile);
1594 }
1595 else
1596 {
1597 struct stat info; /* cupsd.conf information */
1598 cups_file_t *cupsd; /* cupsd.conf file */
1599 char *buffer, /* Buffer for entire file */
1600 *bufptr, /* Pointer into buffer */
1601 *bufend; /* End of buffer */
1602 int ch; /* Character from file */
1603 char filename[1024]; /* Filename */
1604 const char *server_root; /* Location of config files */
1605
1606
1607 /*
1608 * Locate the cupsd.conf file...
1609 */
1610
1611 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1612 server_root = CUPS_SERVERROOT;
1613
1614 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
1615
1616 /*
1617 * Figure out the size...
1618 */
1619
1620 if (stat(filename, &info))
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 if (info.st_size > (1024 * 1024))
1634 {
1635 cgiStartHTML(cgiText(_("Edit Configuration File")));
1636 cgiSetVariable("MESSAGE",
1637 cgiText(_("Unable to access cupsd.conf file:")));
1638 cgiSetVariable("ERROR",
1639 cgiText(_("Unable to edit cupsd.conf files larger than "
1640 "1MB!")));
1641 cgiCopyTemplateLang("error.tmpl");
1642 cgiEndHTML();
1643
1644 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
1645 (long)info.st_size);
1646 return;
1647 }
1648
1649 /*
1650 * Open the cupsd.conf file...
1651 */
1652
1653 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
1654 {
1655 /*
1656 * Unable to open - log an error...
1657 */
1658
1659 cgiStartHTML(cgiText(_("Edit Configuration File")));
1660 cgiSetVariable("MESSAGE",
1661 cgiText(_("Unable to access cupsd.conf file:")));
1662 cgiSetVariable("ERROR", strerror(errno));
1663 cgiCopyTemplateLang("error.tmpl");
1664 cgiEndHTML();
1665
1666 perror(filename);
1667 return;
1668 }
1669
1670 /*
1671 * Allocate memory and load the file into a string buffer...
1672 */
1673
1674 buffer = calloc(1, info.st_size + 1);
1675
1676 cupsFileRead(cupsd, buffer, info.st_size);
1677 cupsFileClose(cupsd);
1678
1679 cgiSetVariable("CUPSDCONF", buffer);
1680 free(buffer);
1681
1682 /*
1683 * Then get the default cupsd.conf file and put that into a string as
1684 * well...
1685 */
1686
1687 strlcat(filename, ".default", sizeof(filename));
1688
1689 if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
1690 (cupsd = cupsFileOpen(filename, "r")) != NULL)
1691 {
1692 buffer = calloc(1, 2 * info.st_size + 1);
1693 bufend = buffer + 2 * info.st_size - 1;
1694
1695 for (bufptr = buffer;
1696 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
1697 {
1698 if (ch == '\\' || ch == '\"')
1699 {
1700 *bufptr++ = '\\';
1701 *bufptr++ = ch;
1702 }
1703 else if (ch == '\n')
1704 {
1705 *bufptr++ = '\\';
1706 *bufptr++ = 'n';
1707 }
1708 else if (ch == '\t')
1709 {
1710 *bufptr++ = '\\';
1711 *bufptr++ = 't';
1712 }
1713 else if (ch >= ' ')
1714 *bufptr++ = ch;
1715 }
1716
1717 *bufptr = '\0';
1718
1719 cupsFileClose(cupsd);
1720
1721 cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
1722 free(buffer);
1723 }
1724
1725 /*
1726 * Show the current config file...
1727 */
1728
1729 cgiStartHTML(cgiText(_("Edit Configuration File")));
1730
1731 cgiCopyTemplateLang("edit-config.tmpl");
1732
1733 cgiEndHTML();
1734 }
1735 }
1736
1737
1738 /*
1739 * 'do_delete_class()' - Delete a class...
1740 */
1741
1742 static void
1743 do_delete_class(http_t *http) /* I - HTTP connection */
1744 {
1745 ipp_t *request; /* IPP request */
1746 char uri[HTTP_MAX_URI]; /* Job URI */
1747 const char *pclass; /* Printer class name */
1748
1749
1750 /*
1751 * Get form variables...
1752 */
1753
1754 if (cgiGetVariable("CONFIRM") == NULL)
1755 {
1756 cgiStartHTML(cgiText(_("Delete Class")));
1757 cgiCopyTemplateLang("class-confirm.tmpl");
1758 cgiEndHTML();
1759 return;
1760 }
1761
1762 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
1763 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1764 "localhost", 0, "/classes/%s", pclass);
1765 else
1766 {
1767 cgiStartHTML(cgiText(_("Delete Class")));
1768 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1769 cgiCopyTemplateLang("error.tmpl");
1770 cgiEndHTML();
1771 return;
1772 }
1773
1774 /*
1775 * Build a CUPS_DELETE_CLASS request, which requires the following
1776 * attributes:
1777 *
1778 * attributes-charset
1779 * attributes-natural-language
1780 * printer-uri
1781 */
1782
1783 request = ippNewRequest(CUPS_DELETE_CLASS);
1784
1785 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1786 NULL, uri);
1787
1788 /*
1789 * Do the request and get back a response...
1790 */
1791
1792 ippDelete(cupsDoRequest(http, request, "/admin/"));
1793
1794 /*
1795 * Show the results...
1796 */
1797
1798 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1799 {
1800 puts("Status: 401\n");
1801 exit(0);
1802 }
1803 else if (cupsLastError() <= IPP_OK_CONFLICT)
1804 {
1805 /*
1806 * Redirect successful updates back to the classes page...
1807 */
1808
1809 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1810 }
1811
1812 cgiStartHTML(cgiText(_("Delete Class")));
1813
1814 if (cupsLastError() > IPP_OK_CONFLICT)
1815 cgiShowIPPError(_("Unable to delete class:"));
1816 else
1817 cgiCopyTemplateLang("class-deleted.tmpl");
1818
1819 cgiEndHTML();
1820 }
1821
1822
1823 /*
1824 * 'do_delete_printer()' - Delete a printer...
1825 */
1826
1827 static void
1828 do_delete_printer(http_t *http) /* I - HTTP connection */
1829 {
1830 ipp_t *request; /* IPP request */
1831 char uri[HTTP_MAX_URI]; /* Job URI */
1832 const char *printer; /* Printer printer name */
1833
1834
1835 /*
1836 * Get form variables...
1837 */
1838
1839 if (cgiGetVariable("CONFIRM") == NULL)
1840 {
1841 cgiStartHTML(cgiText(_("Delete Printer")));
1842 cgiCopyTemplateLang("printer-confirm.tmpl");
1843 cgiEndHTML();
1844 return;
1845 }
1846
1847 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
1848 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1849 "localhost", 0, "/printers/%s", printer);
1850 else
1851 {
1852 cgiStartHTML(cgiText(_("Delete Printer")));
1853 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1854 cgiCopyTemplateLang("error.tmpl");
1855 cgiEndHTML();
1856 return;
1857 }
1858
1859 /*
1860 * Build a CUPS_DELETE_PRINTER request, which requires the following
1861 * attributes:
1862 *
1863 * attributes-charset
1864 * attributes-natural-language
1865 * printer-uri
1866 */
1867
1868 request = ippNewRequest(CUPS_DELETE_PRINTER);
1869
1870 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1871 NULL, uri);
1872
1873 /*
1874 * Do the request and get back a response...
1875 */
1876
1877 ippDelete(cupsDoRequest(http, request, "/admin/"));
1878
1879 /*
1880 * Show the results...
1881 */
1882
1883 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1884 {
1885 puts("Status: 401\n");
1886 exit(0);
1887 }
1888 else if (cupsLastError() <= IPP_OK_CONFLICT)
1889 {
1890 /*
1891 * Redirect successful updates back to the printers page...
1892 */
1893
1894 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1895 }
1896
1897 cgiStartHTML(cgiText(_("Delete Printer")));
1898
1899 if (cupsLastError() > IPP_OK_CONFLICT)
1900 cgiShowIPPError(_("Unable to delete printer:"));
1901 else
1902 cgiCopyTemplateLang("printer-deleted.tmpl");
1903
1904 cgiEndHTML();
1905 }
1906
1907
1908 /*
1909 * 'do_export()' - Export printers to Samba...
1910 */
1911
1912 static void
1913 do_export(http_t *http) /* I - HTTP connection */
1914 {
1915 int i, j; /* Looping vars */
1916 ipp_t *request, /* IPP request */
1917 *response; /* IPP response */
1918 const char *username, /* Samba username */
1919 *password, /* Samba password */
1920 *export_all; /* Export all printers? */
1921 int export_count, /* Number of printers to export */
1922 printer_count; /* Number of available printers */
1923 const char *name, /* What name to pull */
1924 *dest; /* Current destination */
1925 char ppd[1024]; /* PPD file */
1926
1927
1928 /*
1929 * Get form data...
1930 */
1931
1932 username = cgiGetVariable("USERNAME");
1933 password = cgiGetVariable("PASSWORD");
1934 export_all = cgiGetVariable("EXPORT_ALL");
1935 export_count = cgiGetSize("EXPORT_NAME");
1936
1937 /*
1938 * Get list of available printers...
1939 */
1940
1941 cgiSetSize("PRINTER_NAME", 0);
1942 cgiSetSize("PRINTER_EXPORT", 0);
1943
1944 request = ippNewRequest(CUPS_GET_PRINTERS);
1945
1946 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1947 "printer-type", 0);
1948
1949 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1950 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
1951 CUPS_PRINTER_IMPLICIT);
1952
1953 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1954 "requested-attributes", NULL, "printer-name");
1955
1956 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1957 {
1958 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1959 ippDelete(response);
1960
1961 if (!export_all)
1962 {
1963 printer_count = cgiGetSize("PRINTER_NAME");
1964
1965 for (i = 0; i < printer_count; i ++)
1966 {
1967 dest = cgiGetArray("PRINTER_NAME", i);
1968
1969 for (j = 0; j < export_count; j ++)
1970 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
1971 break;
1972
1973 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
1974 }
1975 }
1976 }
1977
1978 /*
1979 * Export or get the printers to export...
1980 */
1981
1982 if (username && *username && password && *password &&
1983 (export_all || export_count > 0))
1984 {
1985 /*
1986 * Do export...
1987 */
1988
1989 fputs("DEBUG: Export printers...\n", stderr);
1990
1991 if (export_all)
1992 {
1993 name = "PRINTER_NAME";
1994 export_count = cgiGetSize("PRINTER_NAME");
1995 }
1996 else
1997 name = "EXPORT_NAME";
1998
1999 for (i = 0; i < export_count; i ++)
2000 {
2001 dest = cgiGetArray(name, i);
2002
2003 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2004 break;
2005
2006 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2007 stderr);
2008
2009 unlink(ppd);
2010
2011 if (!j)
2012 break;
2013 }
2014
2015 if (i < export_count)
2016 cgiSetVariable("ERROR", cupsLastErrorString());
2017 else
2018 {
2019 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2020 cgiCopyTemplateLang("samba-exported.tmpl");
2021 cgiEndHTML();
2022 return;
2023 }
2024 }
2025 else if (username && !*username)
2026 cgiSetVariable("ERROR",
2027 cgiText(_("A Samba username is required to export "
2028 "printer drivers!")));
2029 else if (username && (!password || !*password))
2030 cgiSetVariable("ERROR",
2031 cgiText(_("A Samba password is required to export "
2032 "printer drivers!")));
2033
2034 /*
2035 * Show form...
2036 */
2037
2038 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2039 cgiCopyTemplateLang("samba-export.tmpl");
2040 cgiEndHTML();
2041 }
2042
2043
2044 /*
2045 * 'do_list_printers()' - List available printers...
2046 */
2047
2048 static void
2049 do_list_printers(http_t *http) /* I - HTTP connection */
2050 {
2051 ipp_t *request, /* IPP request */
2052 *response; /* IPP response */
2053 ipp_attribute_t *attr; /* IPP attribute */
2054
2055
2056 cgiStartHTML(cgiText(_("List Available Printers")));
2057 fflush(stdout);
2058
2059 /*
2060 * Get the list of printers and their devices...
2061 */
2062
2063 request = ippNewRequest(CUPS_GET_PRINTERS);
2064
2065 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2066 "requested-attributes", NULL, "device-uri");
2067
2068 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2069 CUPS_PRINTER_LOCAL);
2070 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2071 CUPS_PRINTER_LOCAL);
2072
2073 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2074 {
2075 /*
2076 * Got the printer list, now load the devices...
2077 */
2078
2079 int i; /* Looping var */
2080 cups_array_t *printer_devices; /* Printer devices for local printers */
2081 char *printer_device; /* Current printer device */
2082
2083
2084 /*
2085 * Allocate an array and copy the device strings...
2086 */
2087
2088 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2089
2090 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2091 attr;
2092 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
2093 {
2094 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
2095 }
2096
2097 /*
2098 * Free the printer list and get the device list...
2099 */
2100
2101 ippDelete(response);
2102
2103 request = ippNewRequest(CUPS_GET_DEVICES);
2104
2105 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2106 {
2107 /*
2108 * Got the device list, let's parse it...
2109 */
2110
2111 const char *device_uri, /* device-uri attribute value */
2112 *device_make_and_model, /* device-make-and-model value */
2113 *device_info; /* device-info value */
2114
2115
2116 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2117 {
2118 /*
2119 * Skip leading attributes until we hit a device...
2120 */
2121
2122 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2123 attr = attr->next;
2124
2125 if (!attr)
2126 break;
2127
2128 /*
2129 * Pull the needed attributes from this device...
2130 */
2131
2132 device_info = NULL;
2133 device_make_and_model = NULL;
2134 device_uri = NULL;
2135
2136 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2137 {
2138 if (!strcmp(attr->name, "device-info") &&
2139 attr->value_tag == IPP_TAG_TEXT)
2140 device_info = attr->values[0].string.text;
2141
2142 if (!strcmp(attr->name, "device-make-and-model") &&
2143 attr->value_tag == IPP_TAG_TEXT)
2144 device_make_and_model = attr->values[0].string.text;
2145
2146 if (!strcmp(attr->name, "device-uri") &&
2147 attr->value_tag == IPP_TAG_URI)
2148 device_uri = attr->values[0].string.text;
2149
2150 attr = attr->next;
2151 }
2152
2153 /*
2154 * See if we have everything needed...
2155 */
2156
2157 if (device_info && device_make_and_model && device_uri &&
2158 strcasecmp(device_make_and_model, "unknown") &&
2159 strchr(device_uri, ':'))
2160 {
2161 /*
2162 * Yes, now see if there is already a printer for this
2163 * device...
2164 */
2165
2166 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2167 {
2168 /*
2169 * Not found, so it must be a new printer...
2170 */
2171
2172 char option[1024], /* Form variables for this device */
2173 *option_ptr; /* Pointer into string */
2174 const char *ptr; /* Pointer into device string */
2175
2176
2177 /*
2178 * Format the printer name variable for this device...
2179 *
2180 * We use the device-info string first, then device-uri,
2181 * and finally device-make-and-model to come up with a
2182 * suitable name.
2183 */
2184
2185 if (strncasecmp(device_info, "unknown", 7))
2186 ptr = device_info;
2187 else if ((ptr = strstr(device_uri, "://")) != NULL)
2188 ptr += 3;
2189 else
2190 ptr = device_make_and_model;
2191
2192 for (option_ptr = option;
2193 option_ptr < (option + sizeof(option) - 1) && *ptr;
2194 ptr ++)
2195 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2196 *ptr == '.')
2197 *option_ptr++ = *ptr;
2198 else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_')
2199 *option_ptr++ = '_';
2200 else if (*ptr == '?' || *ptr == '(')
2201 break;
2202
2203 *option_ptr = '\0';
2204
2205 cgiSetArray("TEMPLATE_NAME", i, option);
2206
2207 /*
2208 * Finally, set the form variables for this printer...
2209 */
2210
2211 cgiSetArray("device_info", i, device_info);
2212 cgiSetArray("device_make_and_model", i, device_make_and_model);
2213 cgiSetArray("device_uri", i, device_uri);
2214 i ++;
2215 }
2216 }
2217
2218 if (!attr)
2219 break;
2220 }
2221
2222 ippDelete(response);
2223
2224 /*
2225 * Free the device list...
2226 */
2227
2228 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2229 printer_device;
2230 printer_device = (char *)cupsArrayNext(printer_devices))
2231 free(printer_device);
2232
2233 cupsArrayDelete(printer_devices);
2234 }
2235 }
2236
2237 /*
2238 * Finally, show the printer list...
2239 */
2240
2241 cgiCopyTemplateLang("list-available-printers.tmpl");
2242
2243 cgiEndHTML();
2244 }
2245
2246
2247 /*
2248 * 'do_menu()' - Show the main menu...
2249 */
2250
2251 static void
2252 do_menu(http_t *http) /* I - HTTP connection */
2253 {
2254 int num_settings; /* Number of server settings */
2255 cups_option_t *settings; /* Server settings */
2256 const char *val; /* Setting value */
2257 char filename[1024]; /* Temporary filename */
2258 const char *datadir; /* Location of data files */
2259 ipp_t *request, /* IPP request */
2260 *response; /* IPP response */
2261
2262
2263 /*
2264 * Get the current server settings...
2265 */
2266
2267 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
2268 {
2269 cgiSetVariable("SETTINGS_MESSAGE",
2270 cgiText(_("Unable to open cupsd.conf file:")));
2271 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2272 }
2273
2274 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2275 settings)) != NULL && atoi(val))
2276 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2277
2278 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2279 settings)) != NULL && atoi(val))
2280 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2281
2282 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2283 settings)) != NULL && atoi(val))
2284 cgiSetVariable("REMOTE_ANY", "CHECKED");
2285
2286 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2287 settings)) != NULL && atoi(val))
2288 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2289
2290 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2291 settings)) != NULL && atoi(val))
2292 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2293
2294 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2295 settings)) != NULL && atoi(val))
2296 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2297
2298 #ifdef HAVE_GSSAPI
2299 cgiSetVariable("HAVE_GSSAPI", "1");
2300
2301 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2302 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2303 cgiSetVariable("KERBEROS", "CHECKED");
2304 #endif /* HAVE_GSSAPI */
2305
2306 cupsFreeOptions(num_settings, settings);
2307
2308 /*
2309 * See if Samba and the Windows drivers are installed...
2310 */
2311
2312 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2313 datadir = CUPS_DATADIR;
2314
2315 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2316 if (!access(filename, R_OK))
2317 {
2318 /*
2319 * Found Windows 2000 driver file, see if we have smbclient and
2320 * rpcclient...
2321 */
2322
2323 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2324 sizeof(filename)) &&
2325 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2326 sizeof(filename)))
2327 cgiSetVariable("HAVE_SAMBA", "Y");
2328 else
2329 {
2330 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2331 sizeof(filename)))
2332 fputs("ERROR: smbclient not found!\n", stderr);
2333
2334 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2335 sizeof(filename)))
2336 fputs("ERROR: rpcclient not found!\n", stderr);
2337 }
2338 }
2339 else
2340 perror(filename);
2341
2342 /*
2343 * Subscriptions...
2344 */
2345
2346 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2347
2348 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2349 NULL, "ipp://localhost/");
2350
2351 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2352 {
2353 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2354 ippDelete(response);
2355 }
2356
2357 /*
2358 * Finally, show the main menu template...
2359 */
2360
2361 cgiStartHTML(cgiText(_("Administration")));
2362
2363 cgiCopyTemplateLang("admin.tmpl");
2364
2365 cgiEndHTML();
2366 }
2367
2368
2369 /*
2370 * 'do_printer_op()' - Do a printer operation.
2371 */
2372
2373 static void
2374 do_printer_op(http_t *http, /* I - HTTP connection */
2375 ipp_op_t op, /* I - Operation to perform */
2376 const char *title) /* I - Title of page */
2377 {
2378 ipp_t *request; /* IPP request */
2379 char uri[HTTP_MAX_URI]; /* Printer URI */
2380 const char *printer, /* Printer name (purge-jobs) */
2381 *is_class; /* Is a class? */
2382
2383
2384 is_class = cgiGetVariable("IS_CLASS");
2385 printer = cgiGetVariable("PRINTER_NAME");
2386
2387 if (!printer)
2388 {
2389 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2390 cgiStartHTML(title);
2391 cgiCopyTemplateLang("error.tmpl");
2392 cgiEndHTML();
2393 return;
2394 }
2395
2396 /*
2397 * Build a printer request, which requires the following
2398 * attributes:
2399 *
2400 * attributes-charset
2401 * attributes-natural-language
2402 * printer-uri
2403 */
2404
2405 request = ippNewRequest(op);
2406
2407 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2408 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2409 printer);
2410 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2411 NULL, uri);
2412
2413 /*
2414 * Do the request and get back a response...
2415 */
2416
2417 ippDelete(cupsDoRequest(http, request, "/admin/"));
2418
2419 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2420 {
2421 puts("Status: 401\n");
2422 exit(0);
2423 }
2424 else if (cupsLastError() > IPP_OK_CONFLICT)
2425 {
2426 cgiStartHTML(title);
2427 cgiShowIPPError(_("Unable to change printer:"));
2428 }
2429 else
2430 {
2431 /*
2432 * Redirect successful updates back to the printer page...
2433 */
2434
2435 char url[1024], /* Printer/class URL */
2436 refresh[1024]; /* Refresh URL */
2437
2438
2439 cgiRewriteURL(uri, url, sizeof(url), NULL);
2440 cgiFormEncode(uri, url, sizeof(uri));
2441 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
2442 cgiSetVariable("refresh_page", refresh);
2443
2444 cgiStartHTML(title);
2445
2446 if (op == IPP_PAUSE_PRINTER)
2447 cgiCopyTemplateLang("printer-stop.tmpl");
2448 else if (op == IPP_RESUME_PRINTER)
2449 cgiCopyTemplateLang("printer-start.tmpl");
2450 else if (op == CUPS_ACCEPT_JOBS)
2451 cgiCopyTemplateLang("printer-accept.tmpl");
2452 else if (op == CUPS_REJECT_JOBS)
2453 cgiCopyTemplateLang("printer-reject.tmpl");
2454 else if (op == IPP_PURGE_JOBS)
2455 cgiCopyTemplateLang("printer-purge.tmpl");
2456 else if (op == CUPS_SET_DEFAULT)
2457 cgiCopyTemplateLang("printer-default.tmpl");
2458 }
2459
2460 cgiEndHTML();
2461 }
2462
2463
2464 /*
2465 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2466 */
2467
2468 static void
2469 do_set_allowed_users(http_t *http) /* I - HTTP connection */
2470 {
2471 int i; /* Looping var */
2472 ipp_t *request, /* IPP request */
2473 *response; /* IPP response */
2474 char uri[HTTP_MAX_URI]; /* Printer URI */
2475 const char *printer, /* Printer name (purge-jobs) */
2476 *is_class, /* Is a class? */
2477 *users, /* List of users or groups */
2478 *type; /* Allow/deny type */
2479 int num_users; /* Number of users */
2480 char *ptr, /* Pointer into users string */
2481 *end, /* Pointer to end of users string */
2482 quote; /* Quote character */
2483 ipp_attribute_t *attr; /* Attribute */
2484 static const char * const attrs[] = /* Requested attributes */
2485 {
2486 "requesting-user-name-allowed",
2487 "requesting-user-name-denied"
2488 };
2489
2490
2491 is_class = cgiGetVariable("IS_CLASS");
2492 printer = cgiGetVariable("PRINTER_NAME");
2493
2494 if (!printer)
2495 {
2496 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2497 cgiStartHTML(cgiText(_("Set Allowed Users")));
2498 cgiCopyTemplateLang("error.tmpl");
2499 cgiEndHTML();
2500 return;
2501 }
2502
2503 users = cgiGetVariable("users");
2504 type = cgiGetVariable("type");
2505
2506 if (!users || !type ||
2507 (strcmp(type, "requesting-user-name-allowed") &&
2508 strcmp(type, "requesting-user-name-denied")))
2509 {
2510 /*
2511 * Build a Get-Printer-Attributes request, which requires the following
2512 * attributes:
2513 *
2514 * attributes-charset
2515 * attributes-natural-language
2516 * printer-uri
2517 * requested-attributes
2518 */
2519
2520 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2521
2522 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2523 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2524 printer);
2525 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2526 NULL, uri);
2527
2528 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2529 "requested-attributes",
2530 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
2531
2532 /*
2533 * Do the request and get back a response...
2534 */
2535
2536 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2537 {
2538 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2539
2540 ippDelete(response);
2541 }
2542
2543 cgiStartHTML(cgiText(_("Set Allowed Users")));
2544
2545 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2546 {
2547 puts("Status: 401\n");
2548 exit(0);
2549 }
2550 else if (cupsLastError() > IPP_OK_CONFLICT)
2551 cgiShowIPPError(_("Unable to get printer attributes:"));
2552 else
2553 cgiCopyTemplateLang("users.tmpl");
2554
2555 cgiEndHTML();
2556 }
2557 else
2558 {
2559 /*
2560 * Save the changes...
2561 */
2562
2563 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
2564 {
2565 /*
2566 * Skip whitespace and commas...
2567 */
2568
2569 while (*ptr == ',' || isspace(*ptr & 255))
2570 ptr ++;
2571
2572 if (*ptr == '\'' || *ptr == '\"')
2573 {
2574 /*
2575 * Scan quoted name...
2576 */
2577
2578 quote = *ptr++;
2579
2580 for (end = ptr; *end; end ++)
2581 if (*end == quote)
2582 break;
2583 }
2584 else
2585 {
2586 /*
2587 * Scan space or comma-delimited name...
2588 */
2589
2590 for (end = ptr; *end; end ++)
2591 if (isspace(*end & 255) || *end == ',')
2592 break;
2593 }
2594
2595 /*
2596 * Advance to the next name...
2597 */
2598
2599 ptr = end;
2600 }
2601
2602 /*
2603 * Build a CUPS-Add-Printer/Class request, which requires the following
2604 * attributes:
2605 *
2606 * attributes-charset
2607 * attributes-natural-language
2608 * printer-uri
2609 * requesting-user-name-{allowed,denied}
2610 */
2611
2612 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
2613
2614 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2615 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2616 printer);
2617 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2618 NULL, uri);
2619
2620 if (num_users == 0)
2621 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2622 "requesting-user-name-allowed", NULL, "all");
2623 else
2624 {
2625 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2626 type, num_users, NULL, NULL);
2627
2628 for (i = 0, ptr = (char *)users; *ptr; i ++)
2629 {
2630 /*
2631 * Skip whitespace and commas...
2632 */
2633
2634 while (*ptr == ',' || isspace(*ptr & 255))
2635 ptr ++;
2636
2637 if (*ptr == '\'' || *ptr == '\"')
2638 {
2639 /*
2640 * Scan quoted name...
2641 */
2642
2643 quote = *ptr++;
2644
2645 for (end = ptr; *end; end ++)
2646 if (*end == quote)
2647 break;
2648 }
2649 else
2650 {
2651 /*
2652 * Scan space or comma-delimited name...
2653 */
2654
2655 for (end = ptr; *end; end ++)
2656 if (isspace(*end & 255) || *end == ',')
2657 break;
2658 }
2659
2660 /*
2661 * Terminate the name...
2662 */
2663
2664 if (*end)
2665 *end++ = '\0';
2666
2667 /*
2668 * Add the name...
2669 */
2670
2671 attr->values[i].string.text = strdup(ptr);
2672
2673 /*
2674 * Advance to the next name...
2675 */
2676
2677 ptr = end;
2678 }
2679 }
2680
2681 /*
2682 * Do the request and get back a response...
2683 */
2684
2685 ippDelete(cupsDoRequest(http, request, "/admin/"));
2686
2687 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2688 {
2689 puts("Status: 401\n");
2690 exit(0);
2691 }
2692 else if (cupsLastError() > IPP_OK_CONFLICT)
2693 {
2694 cgiStartHTML(cgiText(_("Set Allowed Users")));
2695 cgiShowIPPError(_("Unable to change printer:"));
2696 }
2697 else
2698 {
2699 /*
2700 * Redirect successful updates back to the printer page...
2701 */
2702
2703 char url[1024], /* Printer/class URL */
2704 refresh[1024]; /* Refresh URL */
2705
2706
2707 cgiRewriteURL(uri, url, sizeof(url), NULL);
2708 cgiFormEncode(uri, url, sizeof(uri));
2709 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
2710 uri);
2711 cgiSetVariable("refresh_page", refresh);
2712
2713 cgiStartHTML(cgiText(_("Set Allowed Users")));
2714
2715 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
2716 "printer-modified.tmpl");
2717 }
2718
2719 cgiEndHTML();
2720 }
2721 }
2722
2723
2724 /*
2725 * 'do_set_options()' - Configure the default options for a queue.
2726 */
2727
2728 static void
2729 do_set_options(http_t *http, /* I - HTTP connection */
2730 int is_class) /* I - Set options for class? */
2731 {
2732 int i, j, k, m; /* Looping vars */
2733 int have_options; /* Have options? */
2734 ipp_t *request, /* IPP request */
2735 *response; /* IPP response */
2736 ipp_attribute_t *attr; /* IPP attribute */
2737 char uri[HTTP_MAX_URI]; /* Job URI */
2738 const char *var; /* Variable value */
2739 const char *printer; /* Printer printer name */
2740 const char *filename; /* PPD filename */
2741 char tempfile[1024]; /* Temporary filename */
2742 cups_file_t *in, /* Input file */
2743 *out; /* Output file */
2744 char line[1024]; /* Line from PPD file */
2745 char keyword[1024], /* Keyword from Default line */
2746 *keyptr; /* Pointer into keyword... */
2747 ppd_file_t *ppd; /* PPD file */
2748 ppd_group_t *group; /* Option group */
2749 ppd_option_t *option; /* Option */
2750 ppd_attr_t *protocol; /* cupsProtocol attribute */
2751 const char *title; /* Page title */
2752
2753
2754 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
2755
2756 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
2757 is_class);
2758
2759 /*
2760 * Get the printer name...
2761 */
2762
2763 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2764 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2765 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2766 printer);
2767 else
2768 {
2769 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2770 cgiStartHTML(title);
2771 cgiCopyTemplateLang("error.tmpl");
2772 cgiEndHTML();
2773 return;
2774 }
2775
2776 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
2777
2778 /*
2779 * Get the PPD file...
2780 */
2781
2782 if (is_class)
2783 filename = NULL;
2784 else
2785 filename = cupsGetPPD2(http, printer);
2786
2787 if (filename)
2788 {
2789 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
2790
2791 if ((ppd = ppdOpenFile(filename)) == NULL)
2792 {
2793 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
2794 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2795 cgiStartHTML(title);
2796 cgiCopyTemplateLang("error.tmpl");
2797 cgiEndHTML();
2798 return;
2799 }
2800 }
2801 else
2802 {
2803 fputs("DEBUG: No PPD file\n", stderr);
2804 ppd = NULL;
2805 }
2806
2807 if (cgiGetVariable("job_sheets_start") != NULL ||
2808 cgiGetVariable("job_sheets_end") != NULL)
2809 have_options = 1;
2810 else
2811 have_options = 0;
2812
2813 if (ppd)
2814 {
2815 ppdMarkDefaults(ppd);
2816
2817 DEBUG_printf(("<P>ppd->num_groups = %d\n"
2818 "<UL>\n", ppd->num_groups));
2819
2820 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2821 {
2822 DEBUG_printf(("<LI>%s<UL>\n", group->text));
2823
2824 for (j = group->num_options, option = group->options;
2825 j > 0;
2826 j --, option ++)
2827 if ((var = cgiGetVariable(option->keyword)) != NULL)
2828 {
2829 DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
2830 have_options = 1;
2831 ppdMarkOption(ppd, option->keyword, var);
2832 }
2833 #ifdef DEBUG
2834 else
2835 printf("<LI>%s not defined!</LI>\n", option->keyword);
2836 #endif /* DEBUG */
2837
2838 DEBUG_puts("</UL></LI>");
2839 }
2840
2841 DEBUG_printf(("</UL>\n"
2842 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
2843 }
2844
2845 if (!have_options || ppdConflicts(ppd))
2846 {
2847 /*
2848 * Show the options to the user...
2849 */
2850
2851 fputs("DEBUG: Showing options...\n", stderr);
2852
2853 cgiStartHTML(cgiText(_("Set Printer Options")));
2854 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2855
2856 if (ppd)
2857 {
2858 ppdLocalize(ppd);
2859
2860 if (ppdConflicts(ppd))
2861 {
2862 for (i = ppd->num_groups, k = 0, group = ppd->groups;
2863 i > 0;
2864 i --, group ++)
2865 for (j = group->num_options, option = group->options;
2866 j > 0;
2867 j --, option ++)
2868 if (option->conflicted)
2869 {
2870 cgiSetArray("ckeyword", k, option->keyword);
2871 cgiSetArray("ckeytext", k, option->text);
2872 k ++;
2873 }
2874
2875 cgiCopyTemplateLang("option-conflict.tmpl");
2876 }
2877
2878 for (i = ppd->num_groups, group = ppd->groups;
2879 i > 0;
2880 i --, group ++)
2881 {
2882 if (!strcmp(group->name, "InstallableOptions"))
2883 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2884 else
2885 cgiSetVariable("GROUP", group->text);
2886
2887 cgiCopyTemplateLang("option-header.tmpl");
2888
2889 for (j = group->num_options, option = group->options;
2890 j > 0;
2891 j --, option ++)
2892 {
2893 if (!strcmp(option->keyword, "PageRegion"))
2894 continue;
2895
2896 cgiSetVariable("KEYWORD", option->keyword);
2897 cgiSetVariable("KEYTEXT", option->text);
2898
2899 if (option->conflicted)
2900 cgiSetVariable("CONFLICTED", "1");
2901 else
2902 cgiSetVariable("CONFLICTED", "0");
2903
2904 cgiSetSize("CHOICES", 0);
2905 cgiSetSize("TEXT", 0);
2906 for (k = 0, m = 0; k < option->num_choices; k ++)
2907 {
2908 /*
2909 * Hide custom option values...
2910 */
2911
2912 if (!strcmp(option->choices[k].choice, "Custom"))
2913 continue;
2914
2915 cgiSetArray("CHOICES", m, option->choices[k].choice);
2916 cgiSetArray("TEXT", m, option->choices[k].text);
2917
2918 m ++;
2919
2920 if (option->choices[k].marked)
2921 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
2922 }
2923
2924 switch (option->ui)
2925 {
2926 case PPD_UI_BOOLEAN :
2927 cgiCopyTemplateLang("option-boolean.tmpl");
2928 break;
2929 case PPD_UI_PICKONE :
2930 cgiCopyTemplateLang("option-pickone.tmpl");
2931 break;
2932 case PPD_UI_PICKMANY :
2933 cgiCopyTemplateLang("option-pickmany.tmpl");
2934 break;
2935 }
2936 }
2937
2938 cgiCopyTemplateLang("option-trailer.tmpl");
2939 }
2940 }
2941
2942 /*
2943 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
2944 * following attributes:
2945 *
2946 * attributes-charset
2947 * attributes-natural-language
2948 * printer-uri
2949 */
2950
2951 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2952
2953 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2954 "localhost", 0, "/printers/%s", printer);
2955 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2956 NULL, uri);
2957
2958 /*
2959 * Do the request and get back a response...
2960 */
2961
2962 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2963 {
2964 if ((attr = ippFindAttribute(response, "job-sheets-supported",
2965 IPP_TAG_ZERO)) != NULL)
2966 {
2967 /*
2968 * Add the job sheets options...
2969 */
2970
2971 cgiSetVariable("GROUP", cgiText(_("Banners")));
2972 cgiCopyTemplateLang("option-header.tmpl");
2973
2974 cgiSetSize("CHOICES", attr->num_values);
2975 cgiSetSize("TEXT", attr->num_values);
2976 for (k = 0; k < attr->num_values; k ++)
2977 {
2978 cgiSetArray("CHOICES", k, attr->values[k].string.text);
2979 cgiSetArray("TEXT", k, attr->values[k].string.text);
2980 }
2981
2982 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
2983
2984 cgiSetVariable("KEYWORD", "job_sheets_start");
2985 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
2986 cgiSetVariable("DEFCHOICE", attr == NULL ?
2987 "" : attr->values[0].string.text);
2988
2989 cgiCopyTemplateLang("option-pickone.tmpl");
2990
2991 cgiSetVariable("KEYWORD", "job_sheets_end");
2992 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
2993 cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ?
2994 "" : attr->values[1].string.text);
2995
2996 cgiCopyTemplateLang("option-pickone.tmpl");
2997
2998 cgiCopyTemplateLang("option-trailer.tmpl");
2999 }
3000
3001 if (ippFindAttribute(response, "printer-error-policy-supported",
3002 IPP_TAG_ZERO) ||
3003 ippFindAttribute(response, "printer-op-policy-supported",
3004 IPP_TAG_ZERO))
3005 {
3006 /*
3007 * Add the error and operation policy options...
3008 */
3009
3010 cgiSetVariable("GROUP", cgiText(_("Policies")));
3011 cgiCopyTemplateLang("option-header.tmpl");
3012
3013 /*
3014 * Error policy...
3015 */
3016
3017 attr = ippFindAttribute(response, "printer-error-policy-supported",
3018 IPP_TAG_ZERO);
3019
3020 if (attr)
3021 {
3022 cgiSetSize("CHOICES", attr->num_values);
3023 cgiSetSize("TEXT", attr->num_values);
3024 for (k = 0; k < attr->num_values; k ++)
3025 {
3026 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3027 cgiSetArray("TEXT", k, attr->values[k].string.text);
3028 }
3029
3030 attr = ippFindAttribute(response, "printer-error-policy",
3031 IPP_TAG_ZERO);
3032
3033 cgiSetVariable("KEYWORD", "printer_error_policy");
3034 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3035 cgiSetVariable("DEFCHOICE", attr == NULL ?
3036 "" : attr->values[0].string.text);
3037 }
3038
3039 cgiCopyTemplateLang("option-pickone.tmpl");
3040
3041 /*
3042 * Operation policy...
3043 */
3044
3045 attr = ippFindAttribute(response, "printer-op-policy-supported",
3046 IPP_TAG_ZERO);
3047
3048 if (attr)
3049 {
3050 cgiSetSize("CHOICES", attr->num_values);
3051 cgiSetSize("TEXT", attr->num_values);
3052 for (k = 0; k < attr->num_values; k ++)
3053 {
3054 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3055 cgiSetArray("TEXT", k, attr->values[k].string.text);
3056 }
3057
3058 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
3059
3060 cgiSetVariable("KEYWORD", "printer_op_policy");
3061 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3062 cgiSetVariable("DEFCHOICE", attr == NULL ?
3063 "" : attr->values[0].string.text);
3064
3065 cgiCopyTemplateLang("option-pickone.tmpl");
3066 }
3067
3068 cgiCopyTemplateLang("option-trailer.tmpl");
3069 }
3070
3071 ippDelete(response);
3072 }
3073
3074 /*
3075 * Binary protocol support...
3076 */
3077
3078 if (ppd->protocols && strstr(ppd->protocols, "BCP"))
3079 {
3080 protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
3081
3082 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
3083 cgiCopyTemplateLang("option-header.tmpl");
3084
3085 cgiSetSize("CHOICES", 2);
3086 cgiSetSize("TEXT", 2);
3087 cgiSetArray("CHOICES", 0, "None");
3088 cgiSetArray("TEXT", 0, cgiText(_("None")));
3089
3090 if (strstr(ppd->protocols, "TBCP"))
3091 {
3092 cgiSetArray("CHOICES", 1, "TBCP");
3093 cgiSetArray("TEXT", 1, "TBCP");
3094 }
3095 else
3096 {
3097 cgiSetArray("CHOICES", 1, "BCP");
3098 cgiSetArray("TEXT", 1, "BCP");
3099 }
3100
3101 cgiSetVariable("KEYWORD", "protocol");
3102 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
3103 cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
3104
3105 cgiCopyTemplateLang("option-pickone.tmpl");
3106
3107 cgiCopyTemplateLang("option-trailer.tmpl");
3108 }
3109
3110 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3111 cgiEndHTML();
3112 }
3113 else
3114 {
3115 /*
3116 * Set default options...
3117 */
3118
3119 fputs("DEBUG: Setting options...\n", stderr);
3120
3121 if (filename)
3122 {
3123 out = cupsTempFile2(tempfile, sizeof(tempfile));
3124 in = cupsFileOpen(filename, "r");
3125
3126 if (!in || !out)
3127 {
3128 cgiSetVariable("ERROR", strerror(errno));
3129 cgiStartHTML(cgiText(_("Set Printer Options")));
3130 cgiCopyTemplateLang("error.tmpl");
3131 cgiEndHTML();
3132
3133 if (in)
3134 cupsFileClose(in);
3135
3136 if (out)
3137 {
3138 cupsFileClose(out);
3139 unlink(tempfile);
3140 }
3141
3142 unlink(filename);
3143 return;
3144 }
3145
3146 while (cupsFileGets(in, line, sizeof(line)))
3147 {
3148 if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3149 continue;
3150 else if (strncmp(line, "*Default", 8))
3151 cupsFilePrintf(out, "%s\n", line);
3152 else
3153 {
3154 /*
3155 * Get default option name...
3156 */
3157
3158 strlcpy(keyword, line + 8, sizeof(keyword));
3159
3160 for (keyptr = keyword; *keyptr; keyptr ++)
3161 if (*keyptr == ':' || isspace(*keyptr & 255))
3162 break;
3163
3164 *keyptr = '\0';
3165
3166 if (!strcmp(keyword, "PageRegion") ||
3167 !strcmp(keyword, "PaperDimension") ||
3168 !strcmp(keyword, "ImageableArea"))
3169 var = cgiGetVariable("PageSize");
3170 else
3171 var = cgiGetVariable(keyword);
3172
3173 if (var != NULL)
3174 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
3175 else
3176 cupsFilePrintf(out, "%s\n", line);
3177 }
3178 }
3179
3180 if ((var = cgiGetVariable("protocol")) != NULL)
3181 cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol"));
3182
3183 cupsFileClose(in);
3184 cupsFileClose(out);
3185 }
3186 else
3187 {
3188 /*
3189 * Make sure temporary filename is cleared when there is no PPD...
3190 */
3191
3192 tempfile[0] = '\0';
3193 }
3194
3195 /*
3196 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3197 * following attributes:
3198 *
3199 * attributes-charset
3200 * attributes-natural-language
3201 * printer-uri
3202 * job-sheets-default
3203 * printer-error-policy
3204 * printer-op-policy
3205 * [ppd file]
3206 */
3207
3208 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3209 CUPS_ADD_MODIFY_PRINTER);
3210
3211 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3212 NULL, uri);
3213
3214 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3215 "job-sheets-default", 2, NULL, NULL);
3216 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3217 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3218
3219 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
3220 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3221 "printer-error-policy", NULL, var);
3222
3223 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
3224 attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3225 "printer-op-policy", NULL, var);
3226
3227 /*
3228 * Do the request and get back a response...
3229 */
3230
3231 if (filename)
3232 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3233 else
3234 ippDelete(cupsDoRequest(http, request, "/admin/"));
3235
3236 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3237 {
3238 puts("Status: 401\n");
3239 exit(0);
3240 }
3241 else if (cupsLastError() > IPP_OK_CONFLICT)
3242 {
3243 cgiStartHTML(title);
3244 cgiShowIPPError(_("Unable to set options:"));
3245 }
3246 else
3247 {
3248 /*
3249 * Redirect successful updates back to the printer page...
3250 */
3251
3252 char refresh[1024]; /* Refresh URL */
3253
3254
3255 cgiFormEncode(uri, printer, sizeof(uri));
3256 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3257 is_class ? "classes" : "printers", uri);
3258 cgiSetVariable("refresh_page", refresh);
3259
3260 cgiStartHTML(title);
3261
3262 cgiCopyTemplateLang("printer-configured.tmpl");
3263 }
3264
3265 cgiEndHTML();
3266
3267 if (filename)
3268 unlink(tempfile);
3269 }
3270
3271 if (filename)
3272 unlink(filename);
3273 }
3274
3275
3276 /*
3277 * 'do_set_sharing()' - Set printer-is-shared value...
3278 */
3279
3280 static void
3281 do_set_sharing(http_t *http) /* I - HTTP connection */
3282 {
3283 ipp_t *request, /* IPP request */
3284 *response; /* IPP response */
3285 char uri[HTTP_MAX_URI]; /* Printer URI */
3286 const char *printer, /* Printer name */
3287 *is_class, /* Is a class? */
3288 *shared; /* Sharing value */
3289
3290
3291 is_class = cgiGetVariable("IS_CLASS");
3292 printer = cgiGetVariable("PRINTER_NAME");
3293 shared = cgiGetVariable("SHARED");
3294
3295 if (!printer || !shared)
3296 {
3297 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3298 cgiStartHTML(cgiText(_("Set Publishing")));
3299 cgiCopyTemplateLang("error.tmpl");
3300 cgiEndHTML();
3301 return;
3302 }
3303
3304 /*
3305 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3306 * following attributes:
3307 *
3308 * attributes-charset
3309 * attributes-natural-language
3310 * printer-uri
3311 * printer-is-shared
3312 */
3313
3314 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
3315
3316 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3317 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3318 printer);
3319 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3320 NULL, uri);
3321
3322 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3323
3324 /*
3325 * Do the request and get back a response...
3326 */
3327
3328 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3329 {
3330 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3331
3332 ippDelete(response);
3333 }
3334
3335 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3336 {
3337 puts("Status: 401\n");
3338 exit(0);
3339 }
3340 else if (cupsLastError() > IPP_OK_CONFLICT)
3341 {
3342 cgiStartHTML(cgiText(_("Set Publishing")));
3343 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3344 }
3345 else
3346 {
3347 /*
3348 * Redirect successful updates back to the printer page...
3349 */
3350
3351 char url[1024], /* Printer/class URL */
3352 refresh[1024]; /* Refresh URL */
3353
3354
3355 cgiRewriteURL(uri, url, sizeof(url), NULL);
3356 cgiFormEncode(uri, url, sizeof(uri));
3357 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3358 cgiSetVariable("refresh_page", refresh);
3359
3360 cgiStartHTML(cgiText(_("Set Publishing")));
3361 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3362 "printer-modified.tmpl");
3363 }
3364
3365 cgiEndHTML();
3366 }
3367
3368
3369 /*
3370 * 'match_string()' - Return the number of matching characters.
3371 */
3372
3373 static int /* O - Number of matching characters */
3374 match_string(const char *a, /* I - First string */
3375 const char *b) /* I - Second string */
3376 {
3377 int count; /* Number of matching characters */
3378
3379
3380 /*
3381 * Loop through both strings until we hit the end of either or we find
3382 * a non-matching character. For the purposes of comparison, we ignore
3383 * whitespace and do a case-insensitive comparison so that we have a
3384 * better chance of finding a match...
3385 */
3386
3387 for (count = 0; *a && *b; a++, b++, count ++)
3388 {
3389 /*
3390 * Skip leading whitespace characters...
3391 */
3392
3393 while (isspace(*a & 255))
3394 a ++;
3395
3396 while (isspace(*b & 255))
3397 b ++;
3398
3399 /*
3400 * Break out if we run out of characters...
3401 */
3402
3403 if (!*a || !*b)
3404 break;
3405
3406 /*
3407 * Do a case-insensitive comparison of the next two chars...
3408 */
3409
3410 if (tolower(*a & 255) != tolower(*b & 255))
3411 break;
3412 }
3413
3414 return (count);
3415 }
3416
3417
3418 /*
3419 * End of "$Id: admin.c 7012 2007-10-10 21:22:45Z mike $".
3420 */