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