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