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