]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/admin.c
Merge changes from CUPS 1.5svn-r9198.
[thirdparty/cups.git] / cgi-bin / admin.c
1 /*
2 * "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $"
3 *
4 * Administration CGI for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2010 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 * choose_device_cb() - Add a device to the device selection page.
19 * do_add_rss_subscription() - Add a RSS subscription.
20 * do_am_class() - Add or modify a class.
21 * do_am_printer() - Add or modify a printer.
22 * do_cancel_subscription() - Cancel a subscription.
23 * do_config_server() - Configure server settings.
24 * do_delete_class() - Delete a class.
25 * do_delete_printer() - Delete a printer.
26 * do_export() - Export printers to Samba.
27 * do_list_printers() - List available printers.
28 * do_menu() - Show the main menu.
29 * do_set_allowed_users() - Set the allowed/denied users for a queue.
30 * do_set_default() - Set the server default printer/class.
31 * do_set_options() - Configure the default options for a queue.
32 * do_set_sharing() - Set printer-is-shared value.
33 * get_option_value() - Return the value of an option.
34 * get_points() - Get a value in points.
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include "cgi-private.h"
42 #include <cups/adminutil.h>
43 #include <cups/ppd.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <sys/wait.h>
48 #include <limits.h>
49
50
51 /*
52 * Local globals...
53 */
54
55 static int current_device = 0; /* Current device shown */
56
57
58 /*
59 * Local functions...
60 */
61
62 static void choose_device_cb(const char *device_class,
63 const char *device_id, const char *device_info,
64 const char *device_make_and_model,
65 const char *device_uri,
66 const char *device_location,
67 const char *title);
68 static void do_add_rss_subscription(http_t *http);
69 static void do_am_class(http_t *http, int modify);
70 static void do_am_printer(http_t *http, int modify);
71 static void do_cancel_subscription(http_t *http);
72 static void do_config_server(http_t *http);
73 static void do_delete_class(http_t *http);
74 static void do_delete_printer(http_t *http);
75 static void do_export(http_t *http);
76 static void do_list_printers(http_t *http);
77 static void do_menu(http_t *http);
78 static void do_set_allowed_users(http_t *http);
79 static void do_set_default(http_t *http);
80 static void do_set_options(http_t *http, int is_class);
81 static void do_set_sharing(http_t *http);
82 static char *get_option_value(ppd_file_t *ppd, const char *name,
83 char *buffer, size_t bufsize);
84 static double get_points(double number, const char *uval);
85
86
87 /*
88 * 'main()' - Main entry for CGI.
89 */
90
91 int /* O - Exit status */
92 main(int argc, /* I - Number of command-line arguments */
93 char *argv[]) /* I - Command-line arguments */
94 {
95 http_t *http; /* Connection to the server */
96 const char *op; /* Operation name */
97
98
99 /*
100 * Connect to the HTTP server...
101 */
102
103 fputs("DEBUG: admin.cgi started...\n", stderr);
104
105 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
106
107 if (!http)
108 {
109 perror("ERROR: Unable to connect to cupsd");
110 fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n",
111 cupsServer() ? cupsServer() : "(null)");
112 fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort());
113 fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
114 exit(1);
115 }
116
117 fprintf(stderr, "DEBUG: http=%p\n", http);
118
119 /*
120 * Set the web interface section...
121 */
122
123 cgiSetVariable("SECTION", "admin");
124 cgiSetVariable("REFRESH_PAGE", "");
125
126 /*
127 * See if we have form data...
128 */
129
130 if (!cgiInitialize() || !cgiGetVariable("OP"))
131 {
132 /*
133 * Nope, send the administration menu...
134 */
135
136 fputs("DEBUG: No form data, showing main menu...\n", stderr);
137
138 do_menu(http);
139 }
140 else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST())
141 {
142 /*
143 * Do the operation...
144 */
145
146 fprintf(stderr, "DEBUG: op=\"%s\"...\n", op);
147
148 if (!strcmp(op, "set-allowed-users"))
149 do_set_allowed_users(http);
150 else if (!strcmp(op, "set-as-default"))
151 do_set_default(http);
152 else if (!strcmp(op, "set-sharing"))
153 do_set_sharing(http);
154 else if (!strcmp(op, "find-new-printers") ||
155 !strcmp(op, "list-available-printers"))
156 do_list_printers(http);
157 else if (!strcmp(op, "add-class"))
158 do_am_class(http, 0);
159 else if (!strcmp(op, "add-printer"))
160 do_am_printer(http, 0);
161 else if (!strcmp(op, "modify-class"))
162 do_am_class(http, 1);
163 else if (!strcmp(op, "modify-printer"))
164 do_am_printer(http, 1);
165 else if (!strcmp(op, "delete-class"))
166 do_delete_class(http);
167 else if (!strcmp(op, "delete-printer"))
168 do_delete_printer(http);
169 else if (!strcmp(op, "set-class-options"))
170 do_set_options(http, 1);
171 else if (!strcmp(op, "set-printer-options"))
172 do_set_options(http, 0);
173 else if (!strcmp(op, "config-server"))
174 do_config_server(http);
175 else if (!strcmp(op, "export-samba"))
176 do_export(http);
177 else if (!strcmp(op, "add-rss-subscription"))
178 do_add_rss_subscription(http);
179 else if (!strcmp(op, "cancel-subscription"))
180 do_cancel_subscription(http);
181 else
182 {
183 /*
184 * Bad operation code - display an error...
185 */
186
187 cgiStartHTML(cgiText(_("Administration")));
188 cgiCopyTemplateLang("error-op.tmpl");
189 cgiEndHTML();
190 }
191 }
192 else if (op && !strcmp(op, "redirect"))
193 {
194 const char *url; /* Redirection URL... */
195 char prefix[1024]; /* URL prefix */
196
197
198 if (getenv("HTTPS"))
199 snprintf(prefix, sizeof(prefix), "https://%s:%s",
200 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
201 else
202 snprintf(prefix, sizeof(prefix), "http://%s:%s",
203 getenv("SERVER_NAME"), getenv("SERVER_PORT"));
204
205 fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix);
206
207 if ((url = cgiGetVariable("URL")) != NULL)
208 {
209 char encoded[1024], /* Encoded URL string */
210 *ptr; /* Pointer into encoded string */
211
212
213 ptr = encoded;
214 if (*url != '/')
215 *ptr++ = '/';
216
217 for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++)
218 {
219 if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128)
220 {
221 /*
222 * Percent-encode this character; safe because we have at least 4
223 * bytes left in the array...
224 */
225
226 sprintf(ptr, "%%%02X", *url & 255);
227 ptr += 3;
228 }
229 else
230 *ptr++ = *url;
231 }
232
233 *ptr = '\0';
234
235 if (*url)
236 {
237 /*
238 * URL was too long, just redirect to the admin page...
239 */
240
241 printf("Location: %s/admin\n\n", prefix);
242 }
243 else
244 {
245 /*
246 * URL is OK, redirect there...
247 */
248
249 printf("Location: %s%s\n\n", prefix, encoded);
250 }
251 }
252 else
253 printf("Location: %s/admin\n\n", prefix);
254 }
255 else
256 {
257 /*
258 * Form data but no operation code - display an error...
259 */
260
261 cgiStartHTML(cgiText(_("Administration")));
262 cgiCopyTemplateLang("error-op.tmpl");
263 cgiEndHTML();
264 }
265
266 /*
267 * Close the HTTP server connection...
268 */
269
270 httpClose(http);
271
272 /*
273 * Return with no errors...
274 */
275
276 return (0);
277 }
278
279
280 /*
281 * 'choose_device_cb()' - Add a device to the device selection page.
282 */
283
284 static void
285 choose_device_cb(
286 const char *device_class, /* I - Class */
287 const char *device_id, /* I - 1284 device ID */
288 const char *device_info, /* I - Description */
289 const char *device_make_and_model, /* I - Make and model */
290 const char *device_uri, /* I - Device URI */
291 const char *device_location, /* I - Location */
292 const char *title) /* I - Page title */
293 {
294 /*
295 * For modern browsers, start a multi-part page so we can show that something
296 * is happening. Non-modern browsers just get everything at the end...
297 */
298
299 if (current_device == 0 && cgiSupportsMultipart())
300 {
301 cgiStartMultipart();
302 cgiStartHTML(title);
303 cgiCopyTemplateLang("choose-device.tmpl");
304 cgiEndHTML();
305 fflush(stdout);
306 }
307
308
309 /*
310 * Add the device to the array...
311 */
312
313 cgiSetArray("device_class", current_device, device_class);
314 cgiSetArray("device_id", current_device, device_id);
315 cgiSetArray("device_info", current_device, device_info);
316 cgiSetArray("device_make_and_model", current_device, device_make_and_model);
317 cgiSetArray("device_uri", current_device, device_uri);
318 cgiSetArray("device_location", current_device, device_location);
319
320 current_device ++;
321 }
322
323
324 /*
325 * 'do_add_rss_subscription()' - Add a RSS subscription.
326 */
327
328 static void
329 do_add_rss_subscription(http_t *http) /* I - HTTP connection */
330 {
331 ipp_t *request, /* IPP request data */
332 *response; /* IPP response data */
333 char rss_uri[1024]; /* RSS notify-recipient URI */
334 int num_events; /* Number of events */
335 const char *events[12], /* Subscribed events */
336 *subscription_name, /* Subscription name */
337 *printer_uri, /* Printer URI */
338 *ptr, /* Pointer into name */
339 *user; /* Username */
340 int max_events; /* Maximum number of events */
341
342
343 /*
344 * See if we have all of the required information...
345 */
346
347 subscription_name = cgiGetVariable("SUBSCRIPTION_NAME");
348 printer_uri = cgiGetVariable("PRINTER_URI");
349 num_events = 0;
350
351 if (cgiGetVariable("EVENT_JOB_CREATED"))
352 events[num_events ++] = "job-created";
353 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
354 events[num_events ++] = "job-completed";
355 if (cgiGetVariable("EVENT_JOB_STOPPED"))
356 events[num_events ++] = "job-stopped";
357 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
358 events[num_events ++] = "job-config-changed";
359 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
360 events[num_events ++] = "printer-stopped";
361 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
362 events[num_events ++] = "printer-added";
363 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
364 events[num_events ++] = "printer-modified";
365 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
366 events[num_events ++] = "printer-deleted";
367 if (cgiGetVariable("EVENT_SERVER_STARTED"))
368 events[num_events ++] = "server-started";
369 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
370 events[num_events ++] = "server-stopped";
371 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
372 events[num_events ++] = "server-restarted";
373 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
374 events[num_events ++] = "server-audit";
375
376 if ((ptr = cgiGetVariable("MAX_EVENTS")) != NULL)
377 max_events = atoi(ptr);
378 else
379 max_events = 0;
380
381 if (!subscription_name || !printer_uri || !num_events ||
382 max_events <= 0 || max_events > 9999)
383 {
384 /*
385 * Don't have everything we need, so get the available printers
386 * and classes and (re)show the add page...
387 */
388
389 if (cgiGetVariable("EVENT_JOB_CREATED"))
390 cgiSetVariable("EVENT_JOB_CREATED", "CHECKED");
391 if (cgiGetVariable("EVENT_JOB_COMPLETED"))
392 cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED");
393 if (cgiGetVariable("EVENT_JOB_STOPPED"))
394 cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED");
395 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
396 cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED");
397 if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
398 cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED");
399 if (cgiGetVariable("EVENT_PRINTER_ADDED"))
400 cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED");
401 if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
402 cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED");
403 if (cgiGetVariable("EVENT_PRINTER_DELETED"))
404 cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED");
405 if (cgiGetVariable("EVENT_SERVER_STARTED"))
406 cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED");
407 if (cgiGetVariable("EVENT_SERVER_STOPPED"))
408 cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED");
409 if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
410 cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED");
411 if (cgiGetVariable("EVENT_SERVER_AUDIT"))
412 cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED");
413
414 request = ippNewRequest(CUPS_GET_PRINTERS);
415 response = cupsDoRequest(http, request, "/");
416
417 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
418
419 ippDelete(response);
420
421 cgiStartHTML(cgiText(_("Add RSS Subscription")));
422
423 cgiCopyTemplateLang("add-rss-subscription.tmpl");
424
425 cgiEndHTML();
426 return;
427 }
428
429 /*
430 * Make sure we have a username...
431 */
432
433 if ((user = getenv("REMOTE_USER")) == NULL)
434 {
435 puts("Status: 401\n");
436 exit(0);
437 }
438
439 /*
440 * Validate the subscription name...
441 */
442
443 for (ptr = subscription_name; *ptr; ptr ++)
444 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
445 *ptr == '?' || *ptr == '#')
446 break;
447
448 if (*ptr)
449 {
450 cgiSetVariable("ERROR",
451 cgiText(_("The subscription name may not "
452 "contain spaces, slashes (/), question marks (?), "
453 "or the pound sign (#).")));
454 cgiStartHTML(_("Add RSS Subscription"));
455 cgiCopyTemplateLang("error.tmpl");
456 cgiEndHTML();
457 return;
458 }
459
460 /*
461 * Add the subscription...
462 */
463
464 ptr = subscription_name + strlen(subscription_name) - 4;
465 if (ptr < subscription_name || strcmp(ptr, ".rss"))
466 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
467 NULL, NULL, 0, "/%s.rss?max_events=%d", subscription_name,
468 max_events);
469 else
470 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
471 NULL, NULL, 0, "/%s?max_events=%d", subscription_name,
472 max_events);
473
474 request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
475
476 if (!strcasecmp(printer_uri, "#ALL#"))
477 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
478 NULL, "ipp://localhost/");
479 else
480 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
481 NULL, printer_uri);
482
483 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
484 NULL, user);
485
486 ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
487 "notify-recipient-uri", NULL, rss_uri);
488 ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
489 num_events, NULL, events);
490 ippAddInteger(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
491 "notify-lease-duration", 0);
492
493 ippDelete(cupsDoRequest(http, request, "/"));
494
495 if (cupsLastError() == IPP_NOT_AUTHORIZED)
496 {
497 puts("Status: 401\n");
498 exit(0);
499 }
500 else if (cupsLastError() > IPP_OK_CONFLICT)
501 {
502 cgiStartHTML(_("Add RSS Subscription"));
503 cgiShowIPPError(_("Unable to add RSS subscription:"));
504 }
505 else
506 {
507 /*
508 * Redirect successful updates back to the admin page...
509 */
510
511 cgiSetVariable("refresh_page", "5;URL=/admin");
512 cgiStartHTML(_("Add RSS Subscription"));
513 cgiCopyTemplateLang("subscription-added.tmpl");
514 }
515
516 cgiEndHTML();
517 }
518
519
520 /*
521 * 'do_am_class()' - Add or modify a class.
522 */
523
524 static void
525 do_am_class(http_t *http, /* I - HTTP connection */
526 int modify) /* I - Modify the printer? */
527 {
528 int i, j; /* Looping vars */
529 int element; /* Element number */
530 int num_printers; /* Number of printers */
531 ipp_t *request, /* IPP request */
532 *response; /* IPP response */
533 ipp_attribute_t *attr; /* member-uris attribute */
534 char uri[HTTP_MAX_URI]; /* Device or printer URI */
535 const char *name, /* Pointer to class name */
536 *op, /* Operation name */
537 *ptr; /* Pointer to CGI variable */
538 const char *title; /* Title of page */
539 static const char * const pattrs[] = /* Requested printer attributes */
540 {
541 "member-names",
542 "printer-info",
543 "printer-location"
544 };
545
546
547 title = cgiText(modify ? _("Modify Class") : _("Add Class"));
548 op = cgiGetVariable("OP");
549 name = cgiGetVariable("PRINTER_NAME");
550
551 if (cgiGetVariable("PRINTER_LOCATION") == NULL)
552 {
553 /*
554 * Build a CUPS_GET_PRINTERS request, which requires the
555 * following attributes:
556 *
557 * attributes-charset
558 * attributes-natural-language
559 */
560
561 request = ippNewRequest(CUPS_GET_PRINTERS);
562
563 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
564 CUPS_PRINTER_LOCAL);
565 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
566 CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
567 CUPS_PRINTER_IMPLICIT);
568
569 /*
570 * Do the request and get back a response...
571 */
572
573 cgiClearVariables();
574 if (op)
575 cgiSetVariable("OP", op);
576 if (name)
577 cgiSetVariable("PRINTER_NAME", name);
578
579 if ((response = cupsDoRequest(http, request, "/")) != NULL)
580 {
581 /*
582 * Create MEMBER_URIS and MEMBER_NAMES arrays...
583 */
584
585 for (element = 0, attr = response->attrs;
586 attr != NULL;
587 attr = attr->next)
588 if (attr->name && !strcmp(attr->name, "printer-uri-supported"))
589 {
590 if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
591 (!name || strcasecmp(name, ptr + 1)))
592 {
593 /*
594 * Don't show the current class...
595 */
596
597 cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
598 element ++;
599 }
600 }
601
602 for (element = 0, attr = response->attrs;
603 attr != NULL;
604 attr = attr->next)
605 if (attr->name && !strcmp(attr->name, "printer-name"))
606 {
607 if (!name || strcasecmp(name, attr->values[0].string.text))
608 {
609 /*
610 * Don't show the current class...
611 */
612
613 cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
614 element ++;
615 }
616 }
617
618 num_printers = cgiGetSize("MEMBER_URIS");
619
620 ippDelete(response);
621 }
622 else
623 num_printers = 0;
624
625 if (modify)
626 {
627 /*
628 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
629 * following attributes:
630 *
631 * attributes-charset
632 * attributes-natural-language
633 * printer-uri
634 */
635
636 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
637
638 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
639 "localhost", 0, "/classes/%s", name);
640 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
641 NULL, uri);
642
643 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
644 "requested-attributes",
645 (int)(sizeof(pattrs) / sizeof(pattrs[0])),
646 NULL, pattrs);
647
648 /*
649 * Do the request and get back a response...
650 */
651
652 if ((response = cupsDoRequest(http, request, "/")) != NULL)
653 {
654 if ((attr = ippFindAttribute(response, "member-names",
655 IPP_TAG_NAME)) != NULL)
656 {
657 /*
658 * Mark any current members in the class...
659 */
660
661 for (j = 0; j < num_printers; j ++)
662 cgiSetArray("MEMBER_SELECTED", j, "");
663
664 for (i = 0; i < attr->num_values; i ++)
665 {
666 for (j = 0; j < num_printers; j ++)
667 {
668 if (!strcasecmp(attr->values[i].string.text,
669 cgiGetArray("MEMBER_NAMES", j)))
670 {
671 cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
672 break;
673 }
674 }
675 }
676 }
677
678 if ((attr = ippFindAttribute(response, "printer-info",
679 IPP_TAG_TEXT)) != NULL)
680 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
681
682 if ((attr = ippFindAttribute(response, "printer-location",
683 IPP_TAG_TEXT)) != NULL)
684 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
685
686 ippDelete(response);
687 }
688
689 /*
690 * Update the location and description of an existing printer...
691 */
692
693 cgiStartHTML(title);
694 cgiCopyTemplateLang("modify-class.tmpl");
695 }
696 else
697 {
698 /*
699 * Get the name, location, and description for a new printer...
700 */
701
702 cgiStartHTML(title);
703 cgiCopyTemplateLang("add-class.tmpl");
704 }
705
706 cgiEndHTML();
707
708 return;
709 }
710
711 if (!name)
712 {
713 cgiStartHTML(title);
714 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
715 cgiCopyTemplateLang("error.tmpl");
716 cgiEndHTML();
717 return;
718 }
719
720 for (ptr = name; *ptr; ptr ++)
721 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
722 break;
723
724 if (*ptr || ptr == name || strlen(name) > 127)
725 {
726 cgiSetVariable("ERROR",
727 cgiText(_("The class name may only contain up to "
728 "127 printable characters and may not "
729 "contain spaces, slashes (/), or the "
730 "pound sign (#).")));
731 cgiStartHTML(title);
732 cgiCopyTemplateLang("error.tmpl");
733 cgiEndHTML();
734 return;
735 }
736
737 /*
738 * Build a CUPS_ADD_CLASS request, which requires the following
739 * attributes:
740 *
741 * attributes-charset
742 * attributes-natural-language
743 * printer-uri
744 * printer-location
745 * printer-info
746 * printer-is-accepting-jobs
747 * printer-state
748 * member-uris
749 */
750
751 request = ippNewRequest(CUPS_ADD_CLASS);
752
753 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
754 "localhost", 0, "/classes/%s", name);
755 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
756 NULL, uri);
757
758 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
759 NULL, cgiGetVariable("PRINTER_LOCATION"));
760
761 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
762 NULL, cgiGetVariable("PRINTER_INFO"));
763
764 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
765
766 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
767 IPP_PRINTER_IDLE);
768
769 if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
770 {
771 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
772 num_printers, NULL, NULL);
773 for (i = 0; i < num_printers; i ++)
774 attr->values[i].string.text = _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i));
775 }
776
777 /*
778 * Do the request and get back a response...
779 */
780
781 ippDelete(cupsDoRequest(http, request, "/admin/"));
782
783 if (cupsLastError() == IPP_NOT_AUTHORIZED)
784 {
785 puts("Status: 401\n");
786 exit(0);
787 }
788 else if (cupsLastError() > IPP_OK_CONFLICT)
789 {
790 cgiStartHTML(title);
791 cgiShowIPPError(modify ? _("Unable to modify class:") :
792 _("Unable to add class:"));
793 }
794 else
795 {
796 /*
797 * Redirect successful updates back to the class page...
798 */
799
800 char refresh[1024]; /* Refresh URL */
801
802 cgiFormEncode(uri, name, sizeof(uri));
803 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
804 uri);
805 cgiSetVariable("refresh_page", refresh);
806
807 cgiStartHTML(title);
808
809 if (modify)
810 cgiCopyTemplateLang("class-modified.tmpl");
811 else
812 cgiCopyTemplateLang("class-added.tmpl");
813 }
814
815 cgiEndHTML();
816 }
817
818
819 /*
820 * 'do_am_printer()' - Add or modify a printer.
821 */
822
823 static void
824 do_am_printer(http_t *http, /* I - HTTP connection */
825 int modify) /* I - Modify the printer? */
826 {
827 int i; /* Looping var */
828 ipp_attribute_t *attr; /* Current attribute */
829 ipp_t *request, /* IPP request */
830 *response, /* IPP response */
831 *oldinfo; /* Old printer information */
832 const cgi_file_t *file; /* Uploaded file, if any */
833 const char *var; /* CGI variable */
834 char uri[HTTP_MAX_URI], /* Device or printer URI */
835 *uriptr; /* Pointer into URI */
836 int maxrate; /* Maximum baud rate */
837 char baudrate[255]; /* Baud rate string */
838 const char *name, /* Pointer to class name */
839 *ptr; /* Pointer to CGI variable */
840 const char *title; /* Title of page */
841 static int baudrates[] = /* Baud rates */
842 {
843 1200,
844 2400,
845 4800,
846 9600,
847 19200,
848 38400,
849 57600,
850 115200,
851 230400,
852 460800
853 };
854
855
856 ptr = cgiGetVariable("DEVICE_URI");
857 fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
858 ptr ? ptr : "(null)");
859
860 title = cgiText(modify ? _("Modify Printer") : _("Add Printer"));
861
862 if (modify)
863 {
864 /*
865 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
866 * following attributes:
867 *
868 * attributes-charset
869 * attributes-natural-language
870 * printer-uri
871 */
872
873 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
874
875 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
876 "localhost", 0, "/printers/%s",
877 cgiGetVariable("PRINTER_NAME"));
878 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
879 NULL, uri);
880
881 /*
882 * Do the request and get back a response...
883 */
884
885 oldinfo = cupsDoRequest(http, request, "/");
886 }
887 else
888 oldinfo = NULL;
889
890 file = cgiGetFile();
891
892 if (file)
893 {
894 fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
895 fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
896 fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
897 fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
898 }
899
900 if ((name = cgiGetVariable("PRINTER_NAME")) != NULL)
901 {
902 for (ptr = name; *ptr; ptr ++)
903 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
904 break;
905
906 if (*ptr || ptr == name || strlen(name) > 127)
907 {
908 cgiSetVariable("ERROR",
909 cgiText(_("The printer name may only contain up to "
910 "127 printable characters and may not "
911 "contain spaces, slashes (/), or the "
912 "pound sign (#).")));
913 cgiStartHTML(title);
914 cgiCopyTemplateLang("error.tmpl");
915 cgiEndHTML();
916 return;
917 }
918 }
919
920 if ((var = cgiGetVariable("DEVICE_URI")) != NULL)
921 {
922 if ((uriptr = strrchr(var, '|')) != NULL)
923 {
924 /*
925 * Extract make and make/model from device URI string...
926 */
927
928 char make[1024], /* Make string */
929 *makeptr; /* Pointer into make */
930
931
932 *uriptr++ = '\0';
933
934 strlcpy(make, uriptr, sizeof(make));
935
936 if ((makeptr = strchr(make, ' ')) != NULL)
937 *makeptr = '\0';
938 else if ((makeptr = strchr(make, '-')) != NULL)
939 *makeptr = '\0';
940 else if (!strncasecmp(make, "laserjet", 8) ||
941 !strncasecmp(make, "deskjet", 7) ||
942 !strncasecmp(make, "designjet", 9))
943 strcpy(make, "HP");
944 else if (!strncasecmp(make, "phaser", 6))
945 strcpy(make, "Xerox");
946 else if (!strncasecmp(make, "stylus", 6))
947 strcpy(make, "Epson");
948 else
949 strcpy(make, "Generic");
950
951 if (!cgiGetVariable("CURRENT_MAKE"))
952 cgiSetVariable("CURRENT_MAKE", make);
953
954 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
955 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
956
957 if (!modify)
958 {
959 char template[128], /* Template name */
960 *tptr; /* Pointer into template name */
961
962 cgiSetVariable("PRINTER_INFO", uriptr);
963
964 for (tptr = template;
965 tptr < (template + sizeof(template) - 1) && *uriptr;
966 uriptr ++)
967 if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' ||
968 *uriptr == '.')
969 *tptr++ = *uriptr;
970 else if ((*uriptr == ' ' || *uriptr == '/') && tptr > template &&
971 tptr[-1] != '_')
972 *tptr++ = '_';
973 else if (*uriptr == '?' || *uriptr == '(')
974 break;
975
976 *tptr = '\0';
977
978 cgiSetVariable("TEMPLATE_NAME", template);
979 }
980 }
981 }
982
983 if (!var)
984 {
985 /*
986 * Look for devices so the user can pick something...
987 */
988
989 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
990 {
991 strlcpy(uri, attr->values[0].string.text, sizeof(uri));
992 if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
993 *uriptr = '\0';
994
995 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
996 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
997 }
998
999 /*
1000 * Scan for devices for up to 30 seconds...
1001 */
1002
1003 fputs("DEBUG: Getting list of devices...\n", stderr);
1004
1005 current_device = 0;
1006 if (cupsGetDevices(http, 30, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
1007 (cups_device_cb_t)choose_device_cb,
1008 (void *)title) == IPP_OK)
1009 {
1010 fputs("DEBUG: Got device list!\n", stderr);
1011
1012 if (cgiSupportsMultipart())
1013 cgiStartMultipart();
1014
1015 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
1016 cgiStartHTML(title);
1017 cgiCopyTemplateLang("choose-device.tmpl");
1018 cgiEndHTML();
1019
1020 if (cgiSupportsMultipart())
1021 cgiEndMultipart();
1022 }
1023 else
1024 {
1025 fprintf(stderr,
1026 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
1027 cupsLastError(), cupsLastErrorString());
1028 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1029 {
1030 puts("Status: 401\n");
1031 exit(0);
1032 }
1033 else
1034 {
1035 cgiStartHTML(title);
1036 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1037 _("Unable to add printer:"));
1038 cgiEndHTML();
1039 return;
1040 }
1041 }
1042 }
1043 else if (strchr(var, '/') == NULL)
1044 {
1045 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
1046 {
1047 /*
1048 * Set the current device URI for the form to the old one...
1049 */
1050
1051 if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
1052 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
1053 }
1054
1055 /*
1056 * User needs to set the full URI...
1057 */
1058
1059 cgiStartHTML(title);
1060 cgiCopyTemplateLang("choose-uri.tmpl");
1061 cgiEndHTML();
1062 }
1063 else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
1064 {
1065 /*
1066 * Need baud rate, parity, etc.
1067 */
1068
1069 if ((var = strchr(var, '?')) != NULL &&
1070 strncmp(var, "?baud=", 6) == 0)
1071 maxrate = atoi(var + 6);
1072 else
1073 maxrate = 19200;
1074
1075 for (i = 0; i < 10; i ++)
1076 if (baudrates[i] > maxrate)
1077 break;
1078 else
1079 {
1080 sprintf(baudrate, "%d", baudrates[i]);
1081 cgiSetArray("BAUDRATES", i, baudrate);
1082 }
1083
1084 cgiStartHTML(title);
1085 cgiCopyTemplateLang("choose-serial.tmpl");
1086 cgiEndHTML();
1087 }
1088 else if (!name || !cgiGetVariable("PRINTER_LOCATION"))
1089 {
1090 cgiStartHTML(title);
1091
1092 if (modify)
1093 {
1094 /*
1095 * Update the location and description of an existing printer...
1096 */
1097
1098 if (oldinfo)
1099 {
1100 if ((attr = ippFindAttribute(oldinfo, "printer-info",
1101 IPP_TAG_TEXT)) != NULL)
1102 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
1103
1104 if ((attr = ippFindAttribute(oldinfo, "printer-location",
1105 IPP_TAG_TEXT)) != NULL)
1106 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
1107
1108 if ((attr = ippFindAttribute(oldinfo, "printer-is-shared",
1109 IPP_TAG_BOOLEAN)) != NULL)
1110 cgiSetVariable("PRINTER_IS_SHARED",
1111 attr->values[0].boolean ? "1" : "0");
1112 }
1113
1114 cgiCopyTemplateLang("modify-printer.tmpl");
1115 }
1116 else
1117 {
1118 /*
1119 * Get the name, location, and description for a new printer...
1120 */
1121
1122 #ifdef __APPLE__
1123 if (!strncmp(var, "usb:", 4))
1124 cgiSetVariable("printer_is_shared", "1");
1125 else
1126 #endif /* __APPLE__ */
1127 cgiSetVariable("printer_is_shared", "0");
1128
1129 cgiCopyTemplateLang("add-printer.tmpl");
1130 }
1131
1132 cgiEndHTML();
1133
1134 if (oldinfo)
1135 ippDelete(oldinfo);
1136
1137 return;
1138 }
1139 else if (!file &&
1140 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
1141 {
1142 if (modify && !cgiGetVariable("SELECT_MAKE"))
1143 {
1144 /*
1145 * Get the PPD file...
1146 */
1147
1148 int fd; /* PPD file */
1149 char filename[1024]; /* PPD filename */
1150 ppd_file_t *ppd; /* PPD information */
1151 char buffer[1024]; /* Buffer */
1152 int bytes; /* Number of bytes */
1153 http_status_t get_status; /* Status of GET */
1154
1155
1156 /* TODO: Use cupsGetFile() API... */
1157 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
1158
1159 if (httpGet(http, uri))
1160 httpGet(http, uri);
1161
1162 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
1163
1164 if (get_status != HTTP_OK)
1165 {
1166 httpFlush(http);
1167
1168 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
1169 uri, get_status, httpStatus(get_status));
1170 }
1171 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
1172 {
1173 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
1174 write(fd, buffer, bytes);
1175
1176 close(fd);
1177
1178 if ((ppd = ppdOpenFile(filename)) != NULL)
1179 {
1180 if (ppd->manufacturer)
1181 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
1182
1183 if (ppd->nickname)
1184 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
1185
1186 ppdClose(ppd);
1187 unlink(filename);
1188 }
1189 else
1190 {
1191 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
1192 filename, ppdErrorString(ppdLastError(&bytes)));
1193 }
1194 }
1195 else
1196 {
1197 httpFlush(http);
1198
1199 fprintf(stderr,
1200 "ERROR: Unable to create temporary file for PPD file: %s\n",
1201 strerror(errno));
1202 }
1203 }
1204
1205 /*
1206 * Build a CUPS_GET_PPDS request, which requires the following
1207 * attributes:
1208 *
1209 * attributes-charset
1210 * attributes-natural-language
1211 * printer-uri
1212 */
1213
1214 request = ippNewRequest(CUPS_GET_PPDS);
1215
1216 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1217 NULL, "ipp://localhost/printers/");
1218
1219 if ((var = cgiGetVariable("PPD_MAKE")) == NULL)
1220 var = cgiGetVariable("CURRENT_MAKE");
1221 if (var && !cgiGetVariable("SELECT_MAKE"))
1222 {
1223 const char *make_model; /* Make and model */
1224
1225
1226 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1227 "ppd-make", NULL, var);
1228
1229 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
1230 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1231 "ppd-make-and-model", NULL, make_model);
1232 }
1233 else
1234 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1235 "requested-attributes", NULL, "ppd-make");
1236
1237 /*
1238 * Do the request and get back a response...
1239 */
1240
1241 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1242 {
1243 /*
1244 * Got the list of PPDs, see if the user has selected a make...
1245 */
1246
1247 if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify)
1248 {
1249 /*
1250 * No PPD files with this make, try again with all makes...
1251 */
1252
1253 ippDelete(response);
1254
1255 request = ippNewRequest(CUPS_GET_PPDS);
1256
1257 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1258 NULL, "ipp://localhost/printers/");
1259
1260 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1261 "requested-attributes", NULL, "ppd-make");
1262
1263 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1264 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1265
1266 cgiStartHTML(title);
1267 cgiCopyTemplateLang("choose-make.tmpl");
1268 cgiEndHTML();
1269 }
1270 else if (!var || cgiGetVariable("SELECT_MAKE"))
1271 {
1272 cgiStartHTML(title);
1273 cgiCopyTemplateLang("choose-make.tmpl");
1274 cgiEndHTML();
1275 }
1276 else
1277 {
1278 /*
1279 * Let the user choose a model...
1280 */
1281
1282 cgiStartHTML(title);
1283 if (!cgiGetVariable("PPD_MAKE"))
1284 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
1285 if (!modify)
1286 cgiSetVariable("CURRENT_MAKE_AND_MODEL",
1287 cgiGetArray("PPD_MAKE_AND_MODEL", 0));
1288 cgiCopyTemplateLang("choose-model.tmpl");
1289 cgiEndHTML();
1290 }
1291
1292 ippDelete(response);
1293 }
1294 else
1295 {
1296 cgiStartHTML(title);
1297 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1298 cgiCopyTemplateLang("error.tmpl");
1299 cgiEndHTML();
1300 }
1301 }
1302 else
1303 {
1304 /*
1305 * Build a CUPS_ADD_PRINTER request, which requires the following
1306 * attributes:
1307 *
1308 * attributes-charset
1309 * attributes-natural-language
1310 * printer-uri
1311 * printer-location
1312 * printer-info
1313 * ppd-name
1314 * device-uri
1315 * printer-is-accepting-jobs
1316 * printer-is-shared
1317 * printer-state
1318 */
1319
1320 request = ippNewRequest(CUPS_ADD_PRINTER);
1321
1322 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1323 "localhost", 0, "/printers/%s",
1324 cgiGetVariable("PRINTER_NAME"));
1325 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1326 NULL, uri);
1327
1328 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1329 NULL, cgiGetVariable("PRINTER_LOCATION"));
1330
1331 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1332 NULL, cgiGetVariable("PRINTER_INFO"));
1333
1334 if (!file)
1335 {
1336 var = cgiGetVariable("PPD_NAME");
1337 if (strcmp(var, "__no_change__"))
1338 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
1339 NULL, var);
1340 }
1341
1342 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1343
1344 /*
1345 * Strip make and model from URI...
1346 */
1347
1348 if ((uriptr = strrchr(uri, '|')) != NULL)
1349 *uriptr = '\0';
1350
1351 if (!strncmp(uri, "serial:", 7))
1352 {
1353 /*
1354 * Update serial port URI to include baud rate, etc.
1355 */
1356
1357 if ((uriptr = strchr(uri, '?')) == NULL)
1358 uriptr = uri + strlen(uri);
1359
1360 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
1361 "?baud=%s+bits=%s+parity=%s+flow=%s",
1362 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1363 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1364 }
1365
1366 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1367 NULL, uri);
1368
1369 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1370
1371 var = cgiGetVariable("printer_is_shared");
1372 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared",
1373 var && (!strcmp(var, "1") || !strcmp(var, "on")));
1374
1375 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1376 IPP_PRINTER_IDLE);
1377
1378 /*
1379 * Do the request and get back a response...
1380 */
1381
1382 if (file)
1383 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
1384 else
1385 ippDelete(cupsDoRequest(http, request, "/admin/"));
1386
1387 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1388 {
1389 puts("Status: 401\n");
1390 exit(0);
1391 }
1392 else if (cupsLastError() > IPP_OK_CONFLICT)
1393 {
1394 cgiStartHTML(title);
1395 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1396 _("Unable to add printer:"));
1397 }
1398 else if (modify)
1399 {
1400 /*
1401 * Redirect successful updates back to the printer page...
1402 */
1403
1404 char refresh[1024]; /* Refresh URL */
1405
1406
1407 cgiFormEncode(uri, name, sizeof(uri));
1408
1409 snprintf(refresh, sizeof(refresh),
1410 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
1411
1412 cgiSetVariable("refresh_page", refresh);
1413
1414 cgiStartHTML(title);
1415
1416 cgiCopyTemplateLang("printer-modified.tmpl");
1417 }
1418 else
1419 {
1420 /*
1421 * Set the printer options...
1422 */
1423
1424 cgiSetVariable("OP", "set-printer-options");
1425 do_set_options(http, 0);
1426 return;
1427 }
1428
1429 cgiEndHTML();
1430 }
1431
1432 if (oldinfo)
1433 ippDelete(oldinfo);
1434 }
1435
1436
1437 /*
1438 * 'do_cancel_subscription()' - Cancel a subscription.
1439 */
1440
1441 static void
1442 do_cancel_subscription(http_t *http)/* I - HTTP connection */
1443 {
1444 ipp_t *request; /* IPP request data */
1445 const char *var, /* Form variable */
1446 *user; /* Username */
1447 int id; /* Subscription ID */
1448
1449
1450 /*
1451 * See if we have all of the required information...
1452 */
1453
1454 if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL)
1455 id = atoi(var);
1456 else
1457 id = 0;
1458
1459 if (id <= 0)
1460 {
1461 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
1462 cgiStartHTML(_("Cancel RSS Subscription"));
1463 cgiCopyTemplateLang("error.tmpl");
1464 cgiEndHTML();
1465 return;
1466 }
1467
1468 /*
1469 * Require a username...
1470 */
1471
1472 if ((user = getenv("REMOTE_USER")) == NULL)
1473 {
1474 puts("Status: 401\n");
1475 exit(0);
1476 }
1477
1478 /*
1479 * Cancel the subscription...
1480 */
1481
1482 request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
1483
1484 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1485 NULL, "ipp://localhost/");
1486 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
1487 "notify-subscription-id", id);
1488
1489 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1490 NULL, user);
1491
1492 ippDelete(cupsDoRequest(http, request, "/"));
1493
1494 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1495 {
1496 puts("Status: 401\n");
1497 exit(0);
1498 }
1499 else if (cupsLastError() > IPP_OK_CONFLICT)
1500 {
1501 cgiStartHTML(_("Cancel RSS Subscription"));
1502 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1503 }
1504 else
1505 {
1506 /*
1507 * Redirect successful updates back to the admin page...
1508 */
1509
1510 cgiSetVariable("refresh_page", "5;URL=/admin");
1511 cgiStartHTML(_("Cancel RSS Subscription"));
1512 cgiCopyTemplateLang("subscription-canceled.tmpl");
1513 }
1514
1515 cgiEndHTML();
1516 }
1517
1518
1519 /*
1520 * 'do_config_server()' - Configure server settings.
1521 */
1522
1523 static void
1524 do_config_server(http_t *http) /* I - HTTP connection */
1525 {
1526 if (cgiGetVariable("CHANGESETTINGS"))
1527 {
1528 /*
1529 * Save basic setting changes...
1530 */
1531
1532 int num_settings; /* Number of server settings */
1533 cups_option_t *settings; /* Server settings */
1534 int advanced, /* Advanced settings shown? */
1535 changed; /* Have settings changed? */
1536 const char *debug_logging, /* DEBUG_LOGGING value */
1537 *remote_admin, /* REMOTE_ADMIN value */
1538 *remote_any, /* REMOTE_ANY value */
1539 *remote_printers,
1540 /* REMOTE_PRINTERS value */
1541 *share_printers,/* SHARE_PRINTERS value */
1542 *user_cancel_any,
1543 /* USER_CANCEL_ANY value */
1544 *browse_web_if = NULL,
1545 /* BrowseWebIF value */
1546 *preserve_job_history = NULL,
1547 /* PreserveJobHistory value */
1548 *preserve_job_files = NULL,
1549 /* PreserveJobFiles value */
1550 *max_clients = NULL,
1551 /* MaxClients value */
1552 *max_jobs = NULL,
1553 /* MaxJobs value */
1554 *max_log_size = NULL;
1555 /* MaxLogSize value */
1556 char local_protocols[255],
1557 /* BrowseLocalProtocols */
1558 remote_protocols[255];
1559 /* BrowseRemoteProtocols */
1560 const char *current_browse_web_if,
1561 /* BrowseWebIF value */
1562 *current_preserve_job_history,
1563 /* PreserveJobHistory value */
1564 *current_preserve_job_files,
1565 /* PreserveJobFiles value */
1566 *current_max_clients,
1567 /* MaxClients value */
1568 *current_max_jobs,
1569 /* MaxJobs value */
1570 *current_max_log_size,
1571 /* MaxLogSize value */
1572 *current_local_protocols,
1573 /* BrowseLocalProtocols */
1574 *current_remote_protocols;
1575 /* BrowseRemoteProtocols */
1576 #ifdef HAVE_GSSAPI
1577 char default_auth_type[255];
1578 /* DefaultAuthType value */
1579 const char *val; /* Setting value */
1580 #endif /* HAVE_GSSAPI */
1581
1582
1583 /*
1584 * Get the checkbox values from the form...
1585 */
1586
1587 debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1588 remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1589 remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1590 remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1591 share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1592 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1593
1594 advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL;
1595 if (advanced)
1596 {
1597 /*
1598 * Get advanced settings...
1599 */
1600
1601 browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
1602 preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
1603 preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
1604 max_clients = cgiGetVariable("MAX_CLIENTS");
1605 max_jobs = cgiGetVariable("MAX_JOBS");
1606 max_log_size = cgiGetVariable("MAX_LOG_SIZE");
1607
1608 if (!max_clients || atoi(max_clients) <= 0)
1609 max_clients = "100";
1610
1611 if (!max_jobs || atoi(max_jobs) <= 0)
1612 max_jobs = "500";
1613
1614 if (!max_log_size || atof(max_log_size) <= 0.0)
1615 max_log_size = "1m";
1616
1617 if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
1618 strcpy(local_protocols, "cups");
1619 else
1620 local_protocols[0] = '\0';
1621
1622 #ifdef HAVE_DNSSD
1623 if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
1624 {
1625 if (local_protocols[0])
1626 strcat(local_protocols, " dnssd");
1627 else
1628 strcat(local_protocols, "dnssd");
1629 }
1630 #endif /* HAVE_DNSSD */
1631
1632 #ifdef HAVE_LDAP
1633 if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
1634 {
1635 if (local_protocols[0])
1636 strcat(local_protocols, " ldap");
1637 else
1638 strcat(local_protocols, "ldap");
1639 }
1640 #endif /* HAVE_LDAP */
1641
1642 #ifdef HAVE_LIBSLP
1643 if (cgiGetVariable("BROWSE_LOCAL_SLP"))
1644 {
1645 if (local_protocols[0])
1646 strcat(local_protocols, " slp");
1647 else
1648 strcat(local_protocols, "slp");
1649 }
1650 #endif /* HAVE_SLP */
1651
1652 if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
1653 strcpy(remote_protocols, "cups");
1654 else
1655 remote_protocols[0] = '\0';
1656
1657 #ifdef HAVE_LDAP
1658 if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
1659 {
1660 if (remote_protocols[0])
1661 strcat(remote_protocols, " ldap");
1662 else
1663 strcat(remote_protocols, "ldap");
1664 }
1665 #endif /* HAVE_LDAP */
1666
1667 #ifdef HAVE_LIBSLP
1668 if (cgiGetVariable("BROWSE_REMOTE_SLP"))
1669 {
1670 if (remote_protocols[0])
1671 strcat(remote_protocols, " slp");
1672 else
1673 strcat(remote_protocols, "slp");
1674 }
1675 #endif /* HAVE_SLP */
1676 }
1677
1678 /*
1679 * Get the current server settings...
1680 */
1681
1682 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
1683 {
1684 cgiStartHTML(cgiText(_("Change Settings")));
1685 cgiSetVariable("MESSAGE",
1686 cgiText(_("Unable to change server settings:")));
1687 cgiSetVariable("ERROR", cupsLastErrorString());
1688 cgiCopyTemplateLang("error.tmpl");
1689 cgiEndHTML();
1690 return;
1691 }
1692
1693 #ifdef HAVE_GSSAPI
1694 /*
1695 * Get authentication settings...
1696 */
1697
1698 if (cgiGetVariable("KERBEROS"))
1699 strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
1700 else
1701 {
1702 val = cupsGetOption("DefaultAuthType", num_settings, settings);
1703
1704 if (!val || !strcasecmp(val, "Negotiate"))
1705 strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
1706 else
1707 strlcpy(default_auth_type, val, sizeof(default_auth_type));
1708 }
1709
1710 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1711 #endif /* HAVE_GSSAPI */
1712
1713 if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings,
1714 settings)) == NULL)
1715 current_browse_web_if = "No";
1716
1717 if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory",
1718 num_settings,
1719 settings)) == NULL)
1720 current_preserve_job_history = "Yes";
1721
1722 if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles",
1723 num_settings,
1724 settings)) == NULL)
1725 current_preserve_job_files = "No";
1726
1727 if ((current_max_clients = cupsGetOption("MaxClients", num_settings,
1728 settings)) == NULL)
1729 current_max_clients = "100";
1730
1731 if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings,
1732 settings)) == NULL)
1733 current_max_jobs = "500";
1734
1735 if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings,
1736 settings)) == NULL)
1737 current_max_log_size = "1m";
1738
1739 if ((current_local_protocols = cupsGetOption("BrowseLocalProtocols",
1740 num_settings,
1741 settings)) == NULL)
1742 current_local_protocols = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
1743
1744 if ((current_remote_protocols = cupsGetOption("BrowseRemoteProtocols",
1745 num_settings,
1746 settings)) == NULL)
1747 current_remote_protocols = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
1748
1749 /*
1750 * See if the settings have changed...
1751 */
1752
1753 changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1754 num_settings, settings)) ||
1755 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1756 num_settings, settings)) ||
1757 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1758 num_settings, settings)) ||
1759 strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
1760 num_settings, settings)) ||
1761 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1762 num_settings, settings)) ||
1763 #ifdef HAVE_GSSAPI
1764 !cupsGetOption("DefaultAuthType", num_settings, settings) ||
1765 strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1766 num_settings, settings)) ||
1767 #endif /* HAVE_GSSAPI */
1768 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1769 num_settings, settings));
1770
1771 if (advanced && !changed)
1772 changed = strcasecmp(local_protocols, current_local_protocols) ||
1773 strcasecmp(remote_protocols, current_remote_protocols) ||
1774 strcasecmp(browse_web_if, current_browse_web_if) ||
1775 strcasecmp(preserve_job_history, current_preserve_job_history) ||
1776 strcasecmp(preserve_job_files, current_preserve_job_files) ||
1777 strcasecmp(max_clients, current_max_clients) ||
1778 strcasecmp(max_jobs, current_max_jobs) ||
1779 strcasecmp(max_log_size, current_max_log_size);
1780
1781 if (changed)
1782 {
1783 /*
1784 * Settings *have* changed, so save the changes...
1785 */
1786
1787 cupsFreeOptions(num_settings, settings);
1788
1789 num_settings = 0;
1790 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1791 debug_logging, num_settings, &settings);
1792 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1793 remote_admin, num_settings, &settings);
1794 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1795 remote_any, num_settings, &settings);
1796 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1797 remote_printers, num_settings, &settings);
1798 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1799 share_printers, num_settings, &settings);
1800 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1801 user_cancel_any, num_settings, &settings);
1802 #ifdef HAVE_GSSAPI
1803 num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
1804 num_settings, &settings);
1805 #endif /* HAVE_GSSAPI */
1806
1807 if (advanced)
1808 {
1809 /*
1810 * Add advanced settings...
1811 */
1812
1813 if (strcasecmp(local_protocols, current_local_protocols))
1814 num_settings = cupsAddOption("BrowseLocalProtocols", local_protocols,
1815 num_settings, &settings);
1816 if (strcasecmp(remote_protocols, current_remote_protocols))
1817 num_settings = cupsAddOption("BrowseRemoteProtocols", remote_protocols,
1818 num_settings, &settings);
1819 if (strcasecmp(browse_web_if, current_browse_web_if))
1820 num_settings = cupsAddOption("BrowseWebIF", browse_web_if,
1821 num_settings, &settings);
1822 if (strcasecmp(preserve_job_history, current_preserve_job_history))
1823 num_settings = cupsAddOption("PreserveJobHistory",
1824 preserve_job_history, num_settings,
1825 &settings);
1826 if (strcasecmp(preserve_job_files, current_preserve_job_files))
1827 num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files,
1828 num_settings, &settings);
1829 if (strcasecmp(max_clients, current_max_clients))
1830 num_settings = cupsAddOption("MaxClients", max_clients, num_settings,
1831 &settings);
1832 if (strcasecmp(max_jobs, current_max_jobs))
1833 num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings,
1834 &settings);
1835 if (strcasecmp(max_log_size, current_max_log_size))
1836 num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings,
1837 &settings);
1838 }
1839
1840 if (!cupsAdminSetServerSettings(http, num_settings, settings))
1841 {
1842 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1843 {
1844 puts("Status: 401\n");
1845 exit(0);
1846 }
1847
1848 cgiStartHTML(cgiText(_("Change Settings")));
1849 cgiSetVariable("MESSAGE",
1850 cgiText(_("Unable to change server settings:")));
1851 cgiSetVariable("ERROR", cupsLastErrorString());
1852 cgiCopyTemplateLang("error.tmpl");
1853 }
1854 else
1855 {
1856 if (advanced)
1857 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
1858 else
1859 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1860 cgiStartHTML(cgiText(_("Change Settings")));
1861 cgiCopyTemplateLang("restart.tmpl");
1862 }
1863 }
1864 else
1865 {
1866 /*
1867 * No changes...
1868 */
1869
1870 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1871 cgiStartHTML(cgiText(_("Change Settings")));
1872 cgiCopyTemplateLang("norestart.tmpl");
1873 }
1874
1875 cupsFreeOptions(num_settings, settings);
1876
1877 cgiEndHTML();
1878 }
1879 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1880 {
1881 /*
1882 * Save hand-edited config file...
1883 */
1884
1885 http_status_t status; /* PUT status */
1886 char tempfile[1024]; /* Temporary new cupsd.conf */
1887 int tempfd; /* Temporary file descriptor */
1888 cups_file_t *temp; /* Temporary file */
1889 const char *start, /* Start of line */
1890 *end; /* End of line */
1891
1892
1893 /*
1894 * Create a temporary file for the new cupsd.conf file...
1895 */
1896
1897 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1898 {
1899 cgiStartHTML(cgiText(_("Edit Configuration File")));
1900 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1901 cgiSetVariable("ERROR", strerror(errno));
1902 cgiCopyTemplateLang("error.tmpl");
1903 cgiEndHTML();
1904
1905 perror(tempfile);
1906 return;
1907 }
1908
1909 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
1910 {
1911 cgiStartHTML(cgiText(_("Edit Configuration File")));
1912 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1913 cgiSetVariable("ERROR", strerror(errno));
1914 cgiCopyTemplateLang("error.tmpl");
1915 cgiEndHTML();
1916
1917 perror(tempfile);
1918 close(tempfd);
1919 unlink(tempfile);
1920 return;
1921 }
1922
1923 /*
1924 * Copy the cupsd.conf text from the form variable...
1925 */
1926
1927 start = cgiGetVariable("CUPSDCONF");
1928 while (start)
1929 {
1930 if ((end = strstr(start, "\r\n")) == NULL)
1931 if ((end = strstr(start, "\n")) == NULL)
1932 end = start + strlen(start);
1933
1934 cupsFileWrite(temp, start, end - start);
1935 cupsFilePutChar(temp, '\n');
1936
1937 if (*end == '\r')
1938 start = end + 2;
1939 else if (*end == '\n')
1940 start = end + 1;
1941 else
1942 start = NULL;
1943 }
1944
1945 cupsFileClose(temp);
1946
1947 /*
1948 * Upload the configuration file to the server...
1949 */
1950
1951 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1952
1953 if (status == HTTP_UNAUTHORIZED)
1954 {
1955 puts("Status: 401\n");
1956 unlink(tempfile);
1957 exit(0);
1958 }
1959 else if (status != HTTP_CREATED)
1960 {
1961 cgiSetVariable("MESSAGE",
1962 cgiText(_("Unable to upload cupsd.conf file:")));
1963 cgiSetVariable("ERROR", httpStatus(status));
1964
1965 cgiStartHTML(cgiText(_("Edit Configuration File")));
1966 cgiCopyTemplateLang("error.tmpl");
1967 }
1968 else
1969 {
1970 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1971
1972 cgiStartHTML(cgiText(_("Edit Configuration File")));
1973 cgiCopyTemplateLang("restart.tmpl");
1974 }
1975
1976 cgiEndHTML();
1977
1978 unlink(tempfile);
1979 }
1980 else
1981 {
1982 struct stat info; /* cupsd.conf information */
1983 cups_file_t *cupsd; /* cupsd.conf file */
1984 char *buffer, /* Buffer for entire file */
1985 *bufptr, /* Pointer into buffer */
1986 *bufend; /* End of buffer */
1987 int ch; /* Character from file */
1988 char filename[1024]; /* Filename */
1989 const char *server_root; /* Location of config files */
1990
1991
1992 /*
1993 * Locate the cupsd.conf file...
1994 */
1995
1996 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1997 server_root = CUPS_SERVERROOT;
1998
1999 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
2000
2001 /*
2002 * Figure out the size...
2003 */
2004
2005 if (stat(filename, &info))
2006 {
2007 cgiStartHTML(cgiText(_("Edit Configuration File")));
2008 cgiSetVariable("MESSAGE",
2009 cgiText(_("Unable to access cupsd.conf file:")));
2010 cgiSetVariable("ERROR", strerror(errno));
2011 cgiCopyTemplateLang("error.tmpl");
2012 cgiEndHTML();
2013
2014 perror(filename);
2015 return;
2016 }
2017
2018 if (info.st_size > (1024 * 1024))
2019 {
2020 cgiStartHTML(cgiText(_("Edit Configuration File")));
2021 cgiSetVariable("MESSAGE",
2022 cgiText(_("Unable to access cupsd.conf file:")));
2023 cgiSetVariable("ERROR",
2024 cgiText(_("Unable to edit cupsd.conf files larger than "
2025 "1MB")));
2026 cgiCopyTemplateLang("error.tmpl");
2027 cgiEndHTML();
2028
2029 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
2030 (long)info.st_size);
2031 return;
2032 }
2033
2034 /*
2035 * Open the cupsd.conf file...
2036 */
2037
2038 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
2039 {
2040 /*
2041 * Unable to open - log an error...
2042 */
2043
2044 cgiStartHTML(cgiText(_("Edit Configuration File")));
2045 cgiSetVariable("MESSAGE",
2046 cgiText(_("Unable to access cupsd.conf file:")));
2047 cgiSetVariable("ERROR", strerror(errno));
2048 cgiCopyTemplateLang("error.tmpl");
2049 cgiEndHTML();
2050
2051 perror(filename);
2052 return;
2053 }
2054
2055 /*
2056 * Allocate memory and load the file into a string buffer...
2057 */
2058
2059 if ((buffer = calloc(1, info.st_size + 1)) != NULL)
2060 {
2061 cupsFileRead(cupsd, buffer, info.st_size);
2062 cgiSetVariable("CUPSDCONF", buffer);
2063 free(buffer);
2064 }
2065
2066 cupsFileClose(cupsd);
2067
2068 /*
2069 * Then get the default cupsd.conf file and put that into a string as
2070 * well...
2071 */
2072
2073 strlcat(filename, ".default", sizeof(filename));
2074
2075 if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
2076 (cupsd = cupsFileOpen(filename, "r")) != NULL)
2077 {
2078 if ((buffer = calloc(1, 2 * info.st_size + 1)) != NULL)
2079 {
2080 bufend = buffer + 2 * info.st_size - 1;
2081
2082 for (bufptr = buffer;
2083 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
2084 {
2085 if (ch == '\\' || ch == '\"')
2086 {
2087 *bufptr++ = '\\';
2088 *bufptr++ = ch;
2089 }
2090 else if (ch == '\n')
2091 {
2092 *bufptr++ = '\\';
2093 *bufptr++ = 'n';
2094 }
2095 else if (ch == '\t')
2096 {
2097 *bufptr++ = '\\';
2098 *bufptr++ = 't';
2099 }
2100 else if (ch >= ' ')
2101 *bufptr++ = ch;
2102 }
2103
2104 *bufptr = '\0';
2105
2106 cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
2107 free(buffer);
2108 }
2109
2110 cupsFileClose(cupsd);
2111 }
2112
2113 /*
2114 * Show the current config file...
2115 */
2116
2117 cgiStartHTML(cgiText(_("Edit Configuration File")));
2118
2119 cgiCopyTemplateLang("edit-config.tmpl");
2120
2121 cgiEndHTML();
2122 }
2123 }
2124
2125
2126 /*
2127 * 'do_delete_class()' - Delete a class.
2128 */
2129
2130 static void
2131 do_delete_class(http_t *http) /* I - HTTP connection */
2132 {
2133 ipp_t *request; /* IPP request */
2134 char uri[HTTP_MAX_URI]; /* Job URI */
2135 const char *pclass; /* Printer class name */
2136
2137
2138 /*
2139 * Get form variables...
2140 */
2141
2142 if (cgiGetVariable("CONFIRM") == NULL)
2143 {
2144 cgiStartHTML(cgiText(_("Delete Class")));
2145 cgiCopyTemplateLang("class-confirm.tmpl");
2146 cgiEndHTML();
2147 return;
2148 }
2149
2150 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
2151 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2152 "localhost", 0, "/classes/%s", pclass);
2153 else
2154 {
2155 cgiStartHTML(cgiText(_("Delete Class")));
2156 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2157 cgiCopyTemplateLang("error.tmpl");
2158 cgiEndHTML();
2159 return;
2160 }
2161
2162 /*
2163 * Build a CUPS_DELETE_CLASS request, which requires the following
2164 * attributes:
2165 *
2166 * attributes-charset
2167 * attributes-natural-language
2168 * printer-uri
2169 */
2170
2171 request = ippNewRequest(CUPS_DELETE_CLASS);
2172
2173 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2174 NULL, uri);
2175
2176 /*
2177 * Do the request and get back a response...
2178 */
2179
2180 ippDelete(cupsDoRequest(http, request, "/admin/"));
2181
2182 /*
2183 * Show the results...
2184 */
2185
2186 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2187 {
2188 puts("Status: 401\n");
2189 exit(0);
2190 }
2191 else if (cupsLastError() <= IPP_OK_CONFLICT)
2192 {
2193 /*
2194 * Redirect successful updates back to the classes page...
2195 */
2196
2197 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
2198 }
2199
2200 cgiStartHTML(cgiText(_("Delete Class")));
2201
2202 if (cupsLastError() > IPP_OK_CONFLICT)
2203 cgiShowIPPError(_("Unable to delete class:"));
2204 else
2205 cgiCopyTemplateLang("class-deleted.tmpl");
2206
2207 cgiEndHTML();
2208 }
2209
2210
2211 /*
2212 * 'do_delete_printer()' - Delete a printer.
2213 */
2214
2215 static void
2216 do_delete_printer(http_t *http) /* I - HTTP connection */
2217 {
2218 ipp_t *request; /* IPP request */
2219 char uri[HTTP_MAX_URI]; /* Job URI */
2220 const char *printer; /* Printer printer name */
2221
2222
2223 /*
2224 * Get form variables...
2225 */
2226
2227 if (cgiGetVariable("CONFIRM") == NULL)
2228 {
2229 cgiStartHTML(cgiText(_("Delete Printer")));
2230 cgiCopyTemplateLang("printer-confirm.tmpl");
2231 cgiEndHTML();
2232 return;
2233 }
2234
2235 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2236 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2237 "localhost", 0, "/printers/%s", printer);
2238 else
2239 {
2240 cgiStartHTML(cgiText(_("Delete Printer")));
2241 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2242 cgiCopyTemplateLang("error.tmpl");
2243 cgiEndHTML();
2244 return;
2245 }
2246
2247 /*
2248 * Build a CUPS_DELETE_PRINTER request, which requires the following
2249 * attributes:
2250 *
2251 * attributes-charset
2252 * attributes-natural-language
2253 * printer-uri
2254 */
2255
2256 request = ippNewRequest(CUPS_DELETE_PRINTER);
2257
2258 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2259 NULL, uri);
2260
2261 /*
2262 * Do the request and get back a response...
2263 */
2264
2265 ippDelete(cupsDoRequest(http, request, "/admin/"));
2266
2267 /*
2268 * Show the results...
2269 */
2270
2271 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2272 {
2273 puts("Status: 401\n");
2274 exit(0);
2275 }
2276 else if (cupsLastError() <= IPP_OK_CONFLICT)
2277 {
2278 /*
2279 * Redirect successful updates back to the printers page...
2280 */
2281
2282 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
2283 }
2284
2285 cgiStartHTML(cgiText(_("Delete Printer")));
2286
2287 if (cupsLastError() > IPP_OK_CONFLICT)
2288 cgiShowIPPError(_("Unable to delete printer:"));
2289 else
2290 cgiCopyTemplateLang("printer-deleted.tmpl");
2291
2292 cgiEndHTML();
2293 }
2294
2295
2296 /*
2297 * 'do_export()' - Export printers to Samba.
2298 */
2299
2300 static void
2301 do_export(http_t *http) /* I - HTTP connection */
2302 {
2303 int i, j; /* Looping vars */
2304 ipp_t *request, /* IPP request */
2305 *response; /* IPP response */
2306 const char *username, /* Samba username */
2307 *password, /* Samba password */
2308 *export_all; /* Export all printers? */
2309 int export_count, /* Number of printers to export */
2310 printer_count; /* Number of available printers */
2311 const char *name, /* What name to pull */
2312 *dest; /* Current destination */
2313 char ppd[1024]; /* PPD file */
2314
2315
2316 /*
2317 * Get form data...
2318 */
2319
2320 username = cgiGetVariable("USERNAME");
2321 password = cgiGetVariable("PASSWORD");
2322 export_all = cgiGetVariable("EXPORT_ALL");
2323 export_count = cgiGetSize("EXPORT_NAME");
2324
2325 /*
2326 * Get list of available printers...
2327 */
2328
2329 cgiSetSize("PRINTER_NAME", 0);
2330 cgiSetSize("PRINTER_EXPORT", 0);
2331
2332 request = ippNewRequest(CUPS_GET_PRINTERS);
2333
2334 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2335 "printer-type", 0);
2336
2337 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
2338 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
2339 CUPS_PRINTER_IMPLICIT);
2340
2341 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2342 "requested-attributes", NULL, "printer-name");
2343
2344 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2345 {
2346 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2347 ippDelete(response);
2348
2349 if (!export_all)
2350 {
2351 printer_count = cgiGetSize("PRINTER_NAME");
2352
2353 for (i = 0; i < printer_count; i ++)
2354 {
2355 dest = cgiGetArray("PRINTER_NAME", i);
2356
2357 for (j = 0; j < export_count; j ++)
2358 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
2359 break;
2360
2361 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
2362 }
2363 }
2364 }
2365
2366 /*
2367 * Export or get the printers to export...
2368 */
2369
2370 if (username && *username && password && *password &&
2371 (export_all || export_count > 0))
2372 {
2373 /*
2374 * Do export...
2375 */
2376
2377 fputs("DEBUG: Export printers...\n", stderr);
2378
2379 if (export_all)
2380 {
2381 name = "PRINTER_NAME";
2382 export_count = cgiGetSize("PRINTER_NAME");
2383 }
2384 else
2385 name = "EXPORT_NAME";
2386
2387 for (i = 0; i < export_count; i ++)
2388 {
2389 dest = cgiGetArray(name, i);
2390
2391 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2392 break;
2393
2394 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2395 stderr);
2396
2397 unlink(ppd);
2398
2399 if (!j)
2400 break;
2401 }
2402
2403 if (i < export_count)
2404 cgiSetVariable("ERROR", cupsLastErrorString());
2405 else
2406 {
2407 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2408 cgiCopyTemplateLang("samba-exported.tmpl");
2409 cgiEndHTML();
2410 return;
2411 }
2412 }
2413 else if (username && !*username)
2414 cgiSetVariable("ERROR",
2415 cgiText(_("A Samba username is required to export "
2416 "printer drivers")));
2417 else if (username && (!password || !*password))
2418 cgiSetVariable("ERROR",
2419 cgiText(_("A Samba password is required to export "
2420 "printer drivers")));
2421
2422 /*
2423 * Show form...
2424 */
2425
2426 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2427 cgiCopyTemplateLang("samba-export.tmpl");
2428 cgiEndHTML();
2429 }
2430
2431
2432 /*
2433 * 'do_list_printers()' - List available printers.
2434 */
2435
2436 static void
2437 do_list_printers(http_t *http) /* I - HTTP connection */
2438 {
2439 ipp_t *request, /* IPP request */
2440 *response; /* IPP response */
2441 ipp_attribute_t *attr; /* IPP attribute */
2442
2443
2444 cgiStartHTML(cgiText(_("List Available Printers")));
2445 fflush(stdout);
2446
2447 /*
2448 * Get the list of printers and their devices...
2449 */
2450
2451 request = ippNewRequest(CUPS_GET_PRINTERS);
2452
2453 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2454 "requested-attributes", NULL, "device-uri");
2455
2456 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2457 CUPS_PRINTER_LOCAL);
2458 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2459 CUPS_PRINTER_LOCAL);
2460
2461 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2462 {
2463 /*
2464 * Got the printer list, now load the devices...
2465 */
2466
2467 int i; /* Looping var */
2468 cups_array_t *printer_devices; /* Printer devices for local printers */
2469 char *printer_device; /* Current printer device */
2470
2471
2472 /*
2473 * Allocate an array and copy the device strings...
2474 */
2475
2476 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2477
2478 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2479 attr;
2480 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
2481 {
2482 cupsArrayAdd(printer_devices, _cupsStrAlloc(attr->values[0].string.text));
2483 }
2484
2485 /*
2486 * Free the printer list and get the device list...
2487 */
2488
2489 ippDelete(response);
2490
2491 request = ippNewRequest(CUPS_GET_DEVICES);
2492
2493 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2494 {
2495 /*
2496 * Got the device list, let's parse it...
2497 */
2498
2499 const char *device_uri, /* device-uri attribute value */
2500 *device_make_and_model, /* device-make-and-model value */
2501 *device_info; /* device-info value */
2502
2503
2504 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2505 {
2506 /*
2507 * Skip leading attributes until we hit a device...
2508 */
2509
2510 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2511 attr = attr->next;
2512
2513 if (!attr)
2514 break;
2515
2516 /*
2517 * Pull the needed attributes from this device...
2518 */
2519
2520 device_info = NULL;
2521 device_make_and_model = NULL;
2522 device_uri = NULL;
2523
2524 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2525 {
2526 if (!strcmp(attr->name, "device-info") &&
2527 attr->value_tag == IPP_TAG_TEXT)
2528 device_info = attr->values[0].string.text;
2529
2530 if (!strcmp(attr->name, "device-make-and-model") &&
2531 attr->value_tag == IPP_TAG_TEXT)
2532 device_make_and_model = attr->values[0].string.text;
2533
2534 if (!strcmp(attr->name, "device-uri") &&
2535 attr->value_tag == IPP_TAG_URI)
2536 device_uri = attr->values[0].string.text;
2537
2538 attr = attr->next;
2539 }
2540
2541 /*
2542 * See if we have everything needed...
2543 */
2544
2545 if (device_info && device_make_and_model && device_uri &&
2546 strcasecmp(device_make_and_model, "unknown") &&
2547 strchr(device_uri, ':'))
2548 {
2549 /*
2550 * Yes, now see if there is already a printer for this
2551 * device...
2552 */
2553
2554 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2555 {
2556 /*
2557 * Not found, so it must be a new printer...
2558 */
2559
2560 char option[1024], /* Form variables for this device */
2561 *option_ptr; /* Pointer into string */
2562 const char *ptr; /* Pointer into device string */
2563
2564
2565 /*
2566 * Format the printer name variable for this device...
2567 *
2568 * We use the device-info string first, then device-uri,
2569 * and finally device-make-and-model to come up with a
2570 * suitable name.
2571 */
2572
2573 if (strncasecmp(device_info, "unknown", 7))
2574 ptr = device_info;
2575 else if ((ptr = strstr(device_uri, "://")) != NULL)
2576 ptr += 3;
2577 else
2578 ptr = device_make_and_model;
2579
2580 for (option_ptr = option;
2581 option_ptr < (option + sizeof(option) - 1) && *ptr;
2582 ptr ++)
2583 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2584 *ptr == '.')
2585 *option_ptr++ = *ptr;
2586 else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_')
2587 *option_ptr++ = '_';
2588 else if (*ptr == '?' || *ptr == '(')
2589 break;
2590
2591 *option_ptr = '\0';
2592
2593 cgiSetArray("TEMPLATE_NAME", i, option);
2594
2595 /*
2596 * Finally, set the form variables for this printer...
2597 */
2598
2599 cgiSetArray("device_info", i, device_info);
2600 cgiSetArray("device_make_and_model", i, device_make_and_model);
2601 cgiSetArray("device_uri", i, device_uri);
2602 i ++;
2603 }
2604 }
2605
2606 if (!attr)
2607 break;
2608 }
2609
2610 ippDelete(response);
2611
2612 /*
2613 * Free the device list...
2614 */
2615
2616 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2617 printer_device;
2618 printer_device = (char *)cupsArrayNext(printer_devices))
2619 _cupsStrFree(printer_device);
2620
2621 cupsArrayDelete(printer_devices);
2622 }
2623 }
2624
2625 /*
2626 * Finally, show the printer list...
2627 */
2628
2629 cgiCopyTemplateLang("list-available-printers.tmpl");
2630
2631 cgiEndHTML();
2632 }
2633
2634
2635 /*
2636 * 'do_menu()' - Show the main menu.
2637 */
2638
2639 static void
2640 do_menu(http_t *http) /* I - HTTP connection */
2641 {
2642 int num_settings; /* Number of server settings */
2643 cups_option_t *settings; /* Server settings */
2644 const char *val; /* Setting value */
2645 char filename[1024]; /* Temporary filename */
2646 const char *datadir; /* Location of data files */
2647 ipp_t *request, /* IPP request */
2648 *response; /* IPP response */
2649
2650
2651 /*
2652 * Get the current server settings...
2653 */
2654
2655 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
2656 {
2657 cgiSetVariable("SETTINGS_MESSAGE",
2658 cgiText(_("Unable to open cupsd.conf file:")));
2659 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2660 }
2661
2662 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2663 settings)) != NULL && atoi(val))
2664 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2665
2666 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2667 settings)) != NULL && atoi(val))
2668 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2669
2670 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2671 settings)) != NULL && atoi(val))
2672 cgiSetVariable("REMOTE_ANY", "CHECKED");
2673
2674 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2675 settings)) != NULL && atoi(val))
2676 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2677
2678 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2679 settings)) != NULL && atoi(val))
2680 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2681
2682 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2683 settings)) != NULL && atoi(val))
2684 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2685
2686 #ifdef HAVE_GSSAPI
2687 cgiSetVariable("HAVE_GSSAPI", "1");
2688
2689 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2690 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2691 cgiSetVariable("KERBEROS", "CHECKED");
2692 else
2693 #endif /* HAVE_GSSAPI */
2694 cgiSetVariable("KERBEROS", "");
2695
2696 #ifdef HAVE_DNSSD
2697 cgiSetVariable("HAVE_DNSSD", "1");
2698 #endif /* HAVE_DNSSD */
2699
2700 #ifdef HAVE_LDAP
2701 cgiSetVariable("HAVE_LDAP", "1");
2702 #endif /* HAVE_LDAP */
2703
2704 #ifdef HAVE_LIBSLP
2705 cgiSetVariable("HAVE_LIBSLP", "1");
2706 #endif /* HAVE_LIBSLP */
2707
2708 if ((val = cupsGetOption("BrowseRemoteProtocols", num_settings,
2709 settings)) == NULL)
2710 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2711 settings)) == NULL)
2712 val = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
2713
2714 if (strstr(val, "cups") || strstr(val, "CUPS"))
2715 cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
2716
2717 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2718 cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
2719
2720 if (strstr(val, "slp") || strstr(val, "SLP"))
2721 cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
2722
2723 if ((val = cupsGetOption("BrowseLocalProtocols", num_settings,
2724 settings)) == NULL)
2725 if ((val = cupsGetOption("BrowseProtocols", num_settings,
2726 settings)) == NULL)
2727 val = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
2728
2729 if (strstr(val, "cups") || strstr(val, "CUPS"))
2730 cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
2731
2732 if (strstr(val, "dnssd") || strstr(val, "DNSSD") ||
2733 strstr(val, "dns-sd") || strstr(val, "DNS-SD") ||
2734 strstr(val, "bonjour") || strstr(val, "BONJOUR"))
2735 cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
2736
2737 if (strstr(val, "ldap") || strstr(val, "LDAP"))
2738 cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
2739
2740 if (strstr(val, "slp") || strstr(val, "SLP"))
2741 cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
2742
2743 if ((val = cupsGetOption("BrowseWebIF", num_settings,
2744 settings)) == NULL)
2745 val = "No";
2746
2747 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2748 !strcasecmp(val, "true"))
2749 cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
2750
2751 if ((val = cupsGetOption("PreserveJobHistory", num_settings,
2752 settings)) == NULL)
2753 val = "Yes";
2754
2755 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2756 !strcasecmp(val, "true"))
2757 {
2758 cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
2759
2760 if ((val = cupsGetOption("PreserveJobFiles", num_settings,
2761 settings)) == NULL)
2762 val = "No";
2763
2764 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
2765 !strcasecmp(val, "true"))
2766 cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
2767 }
2768
2769 if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
2770 val = "100";
2771
2772 cgiSetVariable("MAX_CLIENTS", val);
2773
2774 if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
2775 val = "500";
2776
2777 cgiSetVariable("MAX_JOBS", val);
2778
2779 if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
2780 val = "1m";
2781
2782 cgiSetVariable("MAX_LOG_SIZE", val);
2783
2784 cupsFreeOptions(num_settings, settings);
2785
2786 /*
2787 * See if Samba and the Windows drivers are installed...
2788 */
2789
2790 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2791 datadir = CUPS_DATADIR;
2792
2793 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2794 if (!access(filename, R_OK))
2795 {
2796 /*
2797 * Found Windows 2000 driver file, see if we have smbclient and
2798 * rpcclient...
2799 */
2800
2801 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2802 sizeof(filename)) &&
2803 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2804 sizeof(filename)))
2805 cgiSetVariable("HAVE_SAMBA", "Y");
2806 else
2807 {
2808 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2809 sizeof(filename)))
2810 fputs("ERROR: smbclient not found!\n", stderr);
2811
2812 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2813 sizeof(filename)))
2814 fputs("ERROR: rpcclient not found!\n", stderr);
2815 }
2816 }
2817 else
2818 perror(filename);
2819
2820 /*
2821 * Subscriptions...
2822 */
2823
2824 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2825
2826 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2827 NULL, "ipp://localhost/");
2828
2829 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2830 {
2831 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2832 ippDelete(response);
2833 }
2834
2835 /*
2836 * Finally, show the main menu template...
2837 */
2838
2839 cgiStartHTML(cgiText(_("Administration")));
2840
2841 cgiCopyTemplateLang("admin.tmpl");
2842
2843 cgiEndHTML();
2844 }
2845
2846
2847 /*
2848 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2849 */
2850
2851 static void
2852 do_set_allowed_users(http_t *http) /* I - HTTP connection */
2853 {
2854 int i; /* Looping var */
2855 ipp_t *request, /* IPP request */
2856 *response; /* IPP response */
2857 char uri[HTTP_MAX_URI]; /* Printer URI */
2858 const char *printer, /* Printer name (purge-jobs) */
2859 *is_class, /* Is a class? */
2860 *users, /* List of users or groups */
2861 *type; /* Allow/deny type */
2862 int num_users; /* Number of users */
2863 char *ptr, /* Pointer into users string */
2864 *end, /* Pointer to end of users string */
2865 quote; /* Quote character */
2866 ipp_attribute_t *attr; /* Attribute */
2867 static const char * const attrs[] = /* Requested attributes */
2868 {
2869 "requesting-user-name-allowed",
2870 "requesting-user-name-denied"
2871 };
2872
2873
2874 is_class = cgiGetVariable("IS_CLASS");
2875 printer = cgiGetVariable("PRINTER_NAME");
2876
2877 if (!printer)
2878 {
2879 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
2880 cgiStartHTML(cgiText(_("Set Allowed Users")));
2881 cgiCopyTemplateLang("error.tmpl");
2882 cgiEndHTML();
2883 return;
2884 }
2885
2886 users = cgiGetVariable("users");
2887 type = cgiGetVariable("type");
2888
2889 if (!users || !type ||
2890 (strcmp(type, "requesting-user-name-allowed") &&
2891 strcmp(type, "requesting-user-name-denied")))
2892 {
2893 /*
2894 * Build a Get-Printer-Attributes request, which requires the following
2895 * attributes:
2896 *
2897 * attributes-charset
2898 * attributes-natural-language
2899 * printer-uri
2900 * requested-attributes
2901 */
2902
2903 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2904
2905 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2906 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2907 printer);
2908 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2909 NULL, uri);
2910
2911 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2912 "requested-attributes",
2913 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
2914
2915 /*
2916 * Do the request and get back a response...
2917 */
2918
2919 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2920 {
2921 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2922
2923 ippDelete(response);
2924 }
2925
2926 cgiStartHTML(cgiText(_("Set Allowed Users")));
2927
2928 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2929 {
2930 puts("Status: 401\n");
2931 exit(0);
2932 }
2933 else if (cupsLastError() > IPP_OK_CONFLICT)
2934 cgiShowIPPError(_("Unable to get printer attributes:"));
2935 else
2936 cgiCopyTemplateLang("users.tmpl");
2937
2938 cgiEndHTML();
2939 }
2940 else
2941 {
2942 /*
2943 * Save the changes...
2944 */
2945
2946 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
2947 {
2948 /*
2949 * Skip whitespace and commas...
2950 */
2951
2952 while (*ptr == ',' || isspace(*ptr & 255))
2953 ptr ++;
2954
2955 if (!*ptr)
2956 break;
2957
2958 if (*ptr == '\'' || *ptr == '\"')
2959 {
2960 /*
2961 * Scan quoted name...
2962 */
2963
2964 quote = *ptr++;
2965
2966 for (end = ptr; *end; end ++)
2967 if (*end == quote)
2968 break;
2969 }
2970 else
2971 {
2972 /*
2973 * Scan space or comma-delimited name...
2974 */
2975
2976 for (end = ptr; *end; end ++)
2977 if (isspace(*end & 255) || *end == ',')
2978 break;
2979 }
2980
2981 /*
2982 * Advance to the next name...
2983 */
2984
2985 ptr = end;
2986 }
2987
2988 /*
2989 * Build a CUPS-Add-Printer/Class request, which requires the following
2990 * attributes:
2991 *
2992 * attributes-charset
2993 * attributes-natural-language
2994 * printer-uri
2995 * requesting-user-name-{allowed,denied}
2996 */
2997
2998 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
2999
3000 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3001 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3002 printer);
3003 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3004 NULL, uri);
3005
3006 if (num_users == 0)
3007 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3008 "requesting-user-name-allowed", NULL, "all");
3009 else
3010 {
3011 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3012 type, num_users, NULL, NULL);
3013
3014 for (i = 0, ptr = (char *)users; *ptr; i ++)
3015 {
3016 /*
3017 * Skip whitespace and commas...
3018 */
3019
3020 while (*ptr == ',' || isspace(*ptr & 255))
3021 ptr ++;
3022
3023 if (!*ptr)
3024 break;
3025
3026 if (*ptr == '\'' || *ptr == '\"')
3027 {
3028 /*
3029 * Scan quoted name...
3030 */
3031
3032 quote = *ptr++;
3033
3034 for (end = ptr; *end; end ++)
3035 if (*end == quote)
3036 break;
3037 }
3038 else
3039 {
3040 /*
3041 * Scan space or comma-delimited name...
3042 */
3043
3044 for (end = ptr; *end; end ++)
3045 if (isspace(*end & 255) || *end == ',')
3046 break;
3047 }
3048
3049 /*
3050 * Terminate the name...
3051 */
3052
3053 if (*end)
3054 *end++ = '\0';
3055
3056 /*
3057 * Add the name...
3058 */
3059
3060 attr->values[i].string.text = _cupsStrAlloc(ptr);
3061
3062 /*
3063 * Advance to the next name...
3064 */
3065
3066 ptr = end;
3067 }
3068 }
3069
3070 /*
3071 * Do the request and get back a response...
3072 */
3073
3074 ippDelete(cupsDoRequest(http, request, "/admin/"));
3075
3076 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3077 {
3078 puts("Status: 401\n");
3079 exit(0);
3080 }
3081 else if (cupsLastError() > IPP_OK_CONFLICT)
3082 {
3083 cgiStartHTML(cgiText(_("Set Allowed Users")));
3084 cgiShowIPPError(_("Unable to change printer:"));
3085 }
3086 else
3087 {
3088 /*
3089 * Redirect successful updates back to the printer page...
3090 */
3091
3092 char url[1024], /* Printer/class URL */
3093 refresh[1024]; /* Refresh URL */
3094
3095
3096 cgiRewriteURL(uri, url, sizeof(url), NULL);
3097 cgiFormEncode(uri, url, sizeof(uri));
3098 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
3099 uri);
3100 cgiSetVariable("refresh_page", refresh);
3101
3102 cgiStartHTML(cgiText(_("Set Allowed Users")));
3103
3104 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3105 "printer-modified.tmpl");
3106 }
3107
3108 cgiEndHTML();
3109 }
3110 }
3111
3112
3113 /*
3114 * 'do_set_default()' - Set the server default printer/class.
3115 */
3116
3117 static void
3118 do_set_default(http_t *http) /* I - HTTP connection */
3119 {
3120 const char *title; /* Page title */
3121 ipp_t *request; /* IPP request */
3122 char uri[HTTP_MAX_URI]; /* Printer URI */
3123 const char *printer, /* Printer name (purge-jobs) */
3124 *is_class; /* Is a class? */
3125
3126
3127 is_class = cgiGetVariable("IS_CLASS");
3128 printer = cgiGetVariable("PRINTER_NAME");
3129 title = cgiText(_("Set As Server Default"));
3130
3131 if (!printer)
3132 {
3133 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3134 cgiStartHTML(title);
3135 cgiCopyTemplateLang("error.tmpl");
3136 cgiEndHTML();
3137 return;
3138 }
3139
3140 /*
3141 * Build a printer request, which requires the following
3142 * attributes:
3143 *
3144 * attributes-charset
3145 * attributes-natural-language
3146 * printer-uri
3147 */
3148
3149 request = ippNewRequest(CUPS_SET_DEFAULT);
3150
3151 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3152 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3153 printer);
3154 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3155 NULL, uri);
3156
3157 /*
3158 * Do the request and get back a response...
3159 */
3160
3161 ippDelete(cupsDoRequest(http, request, "/admin/"));
3162
3163 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3164 {
3165 puts("Status: 401\n");
3166 exit(0);
3167 }
3168 else if (cupsLastError() > IPP_OK_CONFLICT)
3169 {
3170 cgiStartHTML(title);
3171 cgiShowIPPError(_("Unable to set server default:"));
3172 }
3173 else
3174 {
3175 /*
3176 * Redirect successful updates back to the printer page...
3177 */
3178
3179 char url[1024], /* Printer/class URL */
3180 refresh[1024]; /* Refresh URL */
3181
3182
3183 cgiRewriteURL(uri, url, sizeof(url), NULL);
3184 cgiFormEncode(uri, url, sizeof(uri));
3185 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3186 cgiSetVariable("refresh_page", refresh);
3187
3188 cgiStartHTML(title);
3189 cgiCopyTemplateLang("printer-default.tmpl");
3190 }
3191
3192 cgiEndHTML();
3193 }
3194
3195
3196 /*
3197 * 'do_set_options()' - Configure the default options for a queue.
3198 */
3199
3200 static void
3201 do_set_options(http_t *http, /* I - HTTP connection */
3202 int is_class) /* I - Set options for class? */
3203 {
3204 int i, j, k, m; /* Looping vars */
3205 int have_options; /* Have options? */
3206 ipp_t *request, /* IPP request */
3207 *response; /* IPP response */
3208 ipp_attribute_t *attr; /* IPP attribute */
3209 char uri[HTTP_MAX_URI]; /* Job URI */
3210 const char *var; /* Variable value */
3211 const char *printer; /* Printer printer name */
3212 const char *filename; /* PPD filename */
3213 char tempfile[1024]; /* Temporary filename */
3214 cups_file_t *in, /* Input file */
3215 *out; /* Output file */
3216 char line[1024], /* Line from PPD file */
3217 value[1024], /* Option value */
3218 keyword[1024], /* Keyword from Default line */
3219 *keyptr; /* Pointer into keyword... */
3220 ppd_file_t *ppd; /* PPD file */
3221 ppd_group_t *group; /* Option group */
3222 ppd_option_t *option; /* Option */
3223 ppd_coption_t *coption; /* Custom option */
3224 ppd_cparam_t *cparam; /* Custom parameter */
3225 ppd_attr_t *ppdattr; /* PPD attribute */
3226 const char *title; /* Page title */
3227
3228
3229 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
3230
3231 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
3232 is_class);
3233
3234 /*
3235 * Get the printer name...
3236 */
3237
3238 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
3239 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3240 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3241 printer);
3242 else
3243 {
3244 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3245 cgiStartHTML(title);
3246 cgiCopyTemplateLang("error.tmpl");
3247 cgiEndHTML();
3248 return;
3249 }
3250
3251 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
3252
3253 /*
3254 * If the user clicks on the Auto-Configure button, send an AutoConfigure
3255 * command file to the printer...
3256 */
3257
3258 if (cgiGetVariable("AUTOCONFIGURE"))
3259 {
3260 cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
3261 return;
3262 }
3263
3264 /*
3265 * Get the PPD file...
3266 */
3267
3268 if (is_class)
3269 filename = NULL;
3270 else
3271 filename = cupsGetPPD2(http, printer);
3272
3273 if (filename)
3274 {
3275 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
3276
3277 if ((ppd = ppdOpenFile(filename)) == NULL)
3278 {
3279 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
3280 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
3281 cgiStartHTML(title);
3282 cgiCopyTemplateLang("error.tmpl");
3283 cgiEndHTML();
3284 return;
3285 }
3286 }
3287 else
3288 {
3289 fputs("DEBUG: No PPD file\n", stderr);
3290 ppd = NULL;
3291 }
3292
3293 if (cgiGetVariable("job_sheets_start") != NULL ||
3294 cgiGetVariable("job_sheets_end") != NULL)
3295 have_options = 1;
3296 else
3297 have_options = 0;
3298
3299 if (ppd)
3300 {
3301 ppdMarkDefaults(ppd);
3302
3303 for (option = ppdFirstOption(ppd);
3304 option;
3305 option = ppdNextOption(ppd))
3306 {
3307 if ((var = cgiGetVariable(option->keyword)) != NULL)
3308 {
3309 have_options = 1;
3310 ppdMarkOption(ppd, option->keyword, var);
3311 fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var);
3312 }
3313 else
3314 fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword);
3315 }
3316 }
3317
3318 if (!have_options || ppdConflicts(ppd))
3319 {
3320 /*
3321 * Show the options to the user...
3322 */
3323
3324 fputs("DEBUG: Showing options...\n", stderr);
3325
3326 /*
3327 * Show auto-configure button if supported...
3328 */
3329
3330 if (ppd)
3331 {
3332 if (ppd->num_filters == 0 ||
3333 ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
3334 ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
3335 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3336 else
3337 {
3338 for (i = 0; i < ppd->num_filters; i ++)
3339 if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
3340 {
3341 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
3342 break;
3343 }
3344 }
3345 }
3346
3347 /*
3348 * Get the printer attributes...
3349 */
3350
3351 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
3352
3353 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3354 "localhost", 0, "/printers/%s", printer);
3355 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3356 NULL, uri);
3357
3358 response = cupsDoRequest(http, request, "/");
3359
3360 /*
3361 * List the groups used as "tabs"...
3362 */
3363
3364 i = 0;
3365
3366 if (ppd)
3367 {
3368 for (group = ppd->groups;
3369 i < ppd->num_groups;
3370 i ++, group ++)
3371 {
3372 cgiSetArray("GROUP_ID", i, group->name);
3373
3374 if (!strcmp(group->name, "InstallableOptions"))
3375 cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
3376 else
3377 cgiSetArray("GROUP", i, group->text);
3378 }
3379 }
3380
3381 if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
3382 {
3383 cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
3384 cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
3385 }
3386
3387 if (ippFindAttribute(response, "printer-error-policy-supported",
3388 IPP_TAG_ZERO) ||
3389 ippFindAttribute(response, "printer-op-policy-supported",
3390 IPP_TAG_ZERO))
3391 {
3392 cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
3393 cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
3394 }
3395
3396 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3397 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
3398 {
3399 cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
3400 cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
3401 }
3402
3403 cgiStartHTML(cgiText(_("Set Printer Options")));
3404 cgiCopyTemplateLang("set-printer-options-header.tmpl");
3405
3406 if (ppd)
3407 {
3408 ppdLocalize(ppd);
3409
3410 if (ppdConflicts(ppd))
3411 {
3412 for (i = ppd->num_groups, k = 0, group = ppd->groups;
3413 i > 0;
3414 i --, group ++)
3415 for (j = group->num_options, option = group->options;
3416 j > 0;
3417 j --, option ++)
3418 if (option->conflicted)
3419 {
3420 cgiSetArray("ckeyword", k, option->keyword);
3421 cgiSetArray("ckeytext", k, option->text);
3422
3423 for (m = 0; m < option->num_choices; m ++)
3424 {
3425 if (option->choices[m].marked)
3426 {
3427 cgiSetArray("cchoice", k, option->choices[m].text);
3428 break;
3429 }
3430 }
3431
3432 k ++;
3433 }
3434
3435 cgiCopyTemplateLang("option-conflict.tmpl");
3436 }
3437
3438 for (i = ppd->num_groups, group = ppd->groups;
3439 i > 0;
3440 i --, group ++)
3441 {
3442 cgiSetVariable("GROUP_ID", group->name);
3443
3444 if (!strcmp(group->name, "InstallableOptions"))
3445 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
3446 else
3447 cgiSetVariable("GROUP", group->text);
3448
3449 cgiCopyTemplateLang("option-header.tmpl");
3450
3451 for (j = group->num_options, option = group->options;
3452 j > 0;
3453 j --, option ++)
3454 {
3455 if (!strcmp(option->keyword, "PageRegion"))
3456 continue;
3457
3458 cgiSetVariable("KEYWORD", option->keyword);
3459 cgiSetVariable("KEYTEXT", option->text);
3460
3461 if (option->conflicted)
3462 cgiSetVariable("CONFLICTED", "1");
3463 else
3464 cgiSetVariable("CONFLICTED", "0");
3465
3466 cgiSetSize("CHOICES", 0);
3467 cgiSetSize("TEXT", 0);
3468 for (k = 0, m = 0; k < option->num_choices; k ++)
3469 {
3470 cgiSetArray("CHOICES", m, option->choices[k].choice);
3471 cgiSetArray("TEXT", m, option->choices[k].text);
3472
3473 m ++;
3474
3475 if (option->choices[k].marked)
3476 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
3477 }
3478
3479 cgiSetSize("PARAMS", 0);
3480 cgiSetSize("PARAMTEXT", 0);
3481 cgiSetSize("PARAMVALUE", 0);
3482 cgiSetSize("INPUTTYPE", 0);
3483
3484 if ((coption = ppdFindCustomOption(ppd, option->keyword)))
3485 {
3486 const char *units = NULL; /* Units value, if any */
3487
3488
3489 cgiSetVariable("ISCUSTOM", "1");
3490
3491 for (cparam = ppdFirstCustomParam(coption), m = 0;
3492 cparam;
3493 cparam = ppdNextCustomParam(coption), m ++)
3494 {
3495 if (!strcasecmp(option->keyword, "PageSize") &&
3496 strcasecmp(cparam->name, "Width") &&
3497 strcasecmp(cparam->name, "Height"))
3498 {
3499 m --;
3500 continue;
3501 }
3502
3503 cgiSetArray("PARAMS", m, cparam->name);
3504 cgiSetArray("PARAMTEXT", m, cparam->text);
3505 cgiSetArray("INPUTTYPE", m, "text");
3506
3507 switch (cparam->type)
3508 {
3509 case PPD_CUSTOM_POINTS :
3510 if (!strncasecmp(option->defchoice, "Custom.", 7))
3511 {
3512 units = option->defchoice + strlen(option->defchoice) - 2;
3513
3514 if (strcmp(units, "mm") && strcmp(units, "cm") &&
3515 strcmp(units, "in") && strcmp(units, "ft"))
3516 {
3517 if (units[1] == 'm')
3518 units ++;
3519 else
3520 units = "pt";
3521 }
3522 }
3523 else
3524 units = "pt";
3525
3526 if (!strcmp(units, "mm"))
3527 snprintf(value, sizeof(value), "%g",
3528 cparam->current.custom_points / 72.0 * 25.4);
3529 else if (!strcmp(units, "cm"))
3530 snprintf(value, sizeof(value), "%g",
3531 cparam->current.custom_points / 72.0 * 2.54);
3532 else if (!strcmp(units, "in"))
3533 snprintf(value, sizeof(value), "%g",
3534 cparam->current.custom_points / 72.0);
3535 else if (!strcmp(units, "ft"))
3536 snprintf(value, sizeof(value), "%g",
3537 cparam->current.custom_points / 72.0 / 12.0);
3538 else if (!strcmp(units, "m"))
3539 snprintf(value, sizeof(value), "%g",
3540 cparam->current.custom_points / 72.0 * 0.0254);
3541 else
3542 snprintf(value, sizeof(value), "%g",
3543 cparam->current.custom_points);
3544 cgiSetArray("PARAMVALUE", m, value);
3545 break;
3546
3547 case PPD_CUSTOM_CURVE :
3548 case PPD_CUSTOM_INVCURVE :
3549 case PPD_CUSTOM_REAL :
3550 snprintf(value, sizeof(value), "%g",
3551 cparam->current.custom_real);
3552 cgiSetArray("PARAMVALUE", m, value);
3553 break;
3554
3555 case PPD_CUSTOM_INT:
3556 snprintf(value, sizeof(value), "%d",
3557 cparam->current.custom_int);
3558 cgiSetArray("PARAMVALUE", m, value);
3559 break;
3560
3561 case PPD_CUSTOM_PASSCODE:
3562 case PPD_CUSTOM_PASSWORD:
3563 if (cparam->current.custom_password)
3564 cgiSetArray("PARAMVALUE", m,
3565 cparam->current.custom_password);
3566 else
3567 cgiSetArray("PARAMVALUE", m, "");
3568 cgiSetArray("INPUTTYPE", m, "password");
3569 break;
3570
3571 case PPD_CUSTOM_STRING:
3572 if (cparam->current.custom_string)
3573 cgiSetArray("PARAMVALUE", m,
3574 cparam->current.custom_string);
3575 else
3576 cgiSetArray("PARAMVALUE", m, "");
3577 break;
3578 }
3579 }
3580
3581 if (units)
3582 {
3583 cgiSetArray("PARAMS", m, "Units");
3584 cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
3585 cgiSetArray("PARAMVALUE", m, units);
3586 }
3587 }
3588 else
3589 cgiSetVariable("ISCUSTOM", "0");
3590
3591 switch (option->ui)
3592 {
3593 case PPD_UI_BOOLEAN :
3594 cgiCopyTemplateLang("option-boolean.tmpl");
3595 break;
3596 case PPD_UI_PICKONE :
3597 cgiCopyTemplateLang("option-pickone.tmpl");
3598 break;
3599 case PPD_UI_PICKMANY :
3600 cgiCopyTemplateLang("option-pickmany.tmpl");
3601 break;
3602 }
3603 }
3604
3605 cgiCopyTemplateLang("option-trailer.tmpl");
3606 }
3607 }
3608
3609 if ((attr = ippFindAttribute(response, "job-sheets-supported",
3610 IPP_TAG_ZERO)) != NULL)
3611 {
3612 /*
3613 * Add the job sheets options...
3614 */
3615
3616 cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
3617 cgiSetVariable("GROUP", cgiText(_("Banners")));
3618 cgiCopyTemplateLang("option-header.tmpl");
3619
3620 cgiSetSize("CHOICES", attr->num_values);
3621 cgiSetSize("TEXT", attr->num_values);
3622 for (k = 0; k < attr->num_values; k ++)
3623 {
3624 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3625 cgiSetArray("TEXT", k, attr->values[k].string.text);
3626 }
3627
3628 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
3629
3630 cgiSetVariable("KEYWORD", "job_sheets_start");
3631 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3632 cgiSetVariable("DEFCHOICE", attr != NULL ?
3633 attr->values[0].string.text : "");
3634
3635 cgiCopyTemplateLang("option-pickone.tmpl");
3636
3637 cgiSetVariable("KEYWORD", "job_sheets_end");
3638 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3639 cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
3640 attr->values[1].string.text : "");
3641
3642 cgiCopyTemplateLang("option-pickone.tmpl");
3643
3644 cgiCopyTemplateLang("option-trailer.tmpl");
3645 }
3646
3647 if (ippFindAttribute(response, "printer-error-policy-supported",
3648 IPP_TAG_ZERO) ||
3649 ippFindAttribute(response, "printer-op-policy-supported",
3650 IPP_TAG_ZERO))
3651 {
3652 /*
3653 * Add the error and operation policy options...
3654 */
3655
3656 cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
3657 cgiSetVariable("GROUP", cgiText(_("Policies")));
3658 cgiCopyTemplateLang("option-header.tmpl");
3659
3660 /*
3661 * Error policy...
3662 */
3663
3664 attr = ippFindAttribute(response, "printer-error-policy-supported",
3665 IPP_TAG_ZERO);
3666
3667 if (attr)
3668 {
3669 cgiSetSize("CHOICES", attr->num_values);
3670 cgiSetSize("TEXT", attr->num_values);
3671 for (k = 0; k < attr->num_values; k ++)
3672 {
3673 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3674 cgiSetArray("TEXT", k, attr->values[k].string.text);
3675 }
3676
3677 attr = ippFindAttribute(response, "printer-error-policy",
3678 IPP_TAG_ZERO);
3679
3680 cgiSetVariable("KEYWORD", "printer_error_policy");
3681 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3682 cgiSetVariable("DEFCHOICE", attr == NULL ?
3683 "" : attr->values[0].string.text);
3684 }
3685
3686 cgiCopyTemplateLang("option-pickone.tmpl");
3687
3688 /*
3689 * Operation policy...
3690 */
3691
3692 attr = ippFindAttribute(response, "printer-op-policy-supported",
3693 IPP_TAG_ZERO);
3694
3695 if (attr)
3696 {
3697 cgiSetSize("CHOICES", attr->num_values);
3698 cgiSetSize("TEXT", attr->num_values);
3699 for (k = 0; k < attr->num_values; k ++)
3700 {
3701 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3702 cgiSetArray("TEXT", k, attr->values[k].string.text);
3703 }
3704
3705 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
3706
3707 cgiSetVariable("KEYWORD", "printer_op_policy");
3708 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3709 cgiSetVariable("DEFCHOICE", attr == NULL ?
3710 "" : attr->values[0].string.text);
3711
3712 cgiCopyTemplateLang("option-pickone.tmpl");
3713 }
3714
3715 cgiCopyTemplateLang("option-trailer.tmpl");
3716 }
3717
3718 /*
3719 * Binary protocol support...
3720 */
3721
3722 if ((attr = ippFindAttribute(response, "port-monitor-supported",
3723 IPP_TAG_NAME)) != NULL && attr->num_values > 1)
3724 {
3725 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
3726 cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
3727
3728 cgiSetSize("CHOICES", attr->num_values);
3729 cgiSetSize("TEXT", attr->num_values);
3730
3731 for (i = 0; i < attr->num_values; i ++)
3732 {
3733 cgiSetArray("CHOICES", i, attr->values[i].string.text);
3734 cgiSetArray("TEXT", i, attr->values[i].string.text);
3735 }
3736
3737 attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
3738 cgiSetVariable("KEYWORD", "port_monitor");
3739 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
3740 cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
3741
3742 cgiCopyTemplateLang("option-header.tmpl");
3743 cgiCopyTemplateLang("option-pickone.tmpl");
3744 cgiCopyTemplateLang("option-trailer.tmpl");
3745 }
3746
3747 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3748 cgiEndHTML();
3749
3750 ippDelete(response);
3751 }
3752 else
3753 {
3754 /*
3755 * Set default options...
3756 */
3757
3758 fputs("DEBUG: Setting options...\n", stderr);
3759
3760 if (filename)
3761 {
3762 out = cupsTempFile2(tempfile, sizeof(tempfile));
3763 in = cupsFileOpen(filename, "r");
3764
3765 if (!in || !out)
3766 {
3767 cgiSetVariable("ERROR", strerror(errno));
3768 cgiStartHTML(cgiText(_("Set Printer Options")));
3769 cgiCopyTemplateLang("error.tmpl");
3770 cgiEndHTML();
3771
3772 if (in)
3773 cupsFileClose(in);
3774
3775 if (out)
3776 {
3777 cupsFileClose(out);
3778 unlink(tempfile);
3779 }
3780
3781 unlink(filename);
3782 return;
3783 }
3784
3785 while (cupsFileGets(in, line, sizeof(line)))
3786 {
3787 if (!strncmp(line, "*cupsProtocol:", 14))
3788 continue;
3789 else if (strncmp(line, "*Default", 8))
3790 cupsFilePrintf(out, "%s\n", line);
3791 else
3792 {
3793 /*
3794 * Get default option name...
3795 */
3796
3797 strlcpy(keyword, line + 8, sizeof(keyword));
3798
3799 for (keyptr = keyword; *keyptr; keyptr ++)
3800 if (*keyptr == ':' || isspace(*keyptr & 255))
3801 break;
3802
3803 *keyptr = '\0';
3804
3805 if (!strcmp(keyword, "PageRegion") ||
3806 !strcmp(keyword, "PaperDimension") ||
3807 !strcmp(keyword, "ImageableArea"))
3808 var = get_option_value(ppd, "PageSize", value, sizeof(value));
3809 else
3810 var = get_option_value(ppd, keyword, value, sizeof(value));
3811
3812 if (!var)
3813 cupsFilePrintf(out, "%s\n", line);
3814 else
3815 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
3816 }
3817 }
3818
3819 cupsFileClose(in);
3820 cupsFileClose(out);
3821 }
3822 else
3823 {
3824 /*
3825 * Make sure temporary filename is cleared when there is no PPD...
3826 */
3827
3828 tempfile[0] = '\0';
3829 }
3830
3831 /*
3832 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3833 * following attributes:
3834 *
3835 * attributes-charset
3836 * attributes-natural-language
3837 * printer-uri
3838 * job-sheets-default
3839 * printer-error-policy
3840 * printer-op-policy
3841 * [ppd file]
3842 */
3843
3844 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3845 CUPS_ADD_MODIFY_PRINTER);
3846
3847 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3848 NULL, uri);
3849
3850 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3851 "job-sheets-default", 2, NULL, NULL);
3852 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3853 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3854
3855 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
3856 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3857 "printer-error-policy", NULL, var);
3858
3859 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
3860 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3861 "printer-op-policy", NULL, var);
3862
3863 if ((var = cgiGetVariable("port_monitor")) != NULL)
3864 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3865 "port-monitor", NULL, var);
3866
3867 /*
3868 * Do the request and get back a response...
3869 */
3870
3871 if (filename)
3872 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3873 else
3874 ippDelete(cupsDoRequest(http, request, "/admin/"));
3875
3876 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3877 {
3878 puts("Status: 401\n");
3879 exit(0);
3880 }
3881 else if (cupsLastError() > IPP_OK_CONFLICT)
3882 {
3883 cgiStartHTML(title);
3884 cgiShowIPPError(_("Unable to set options:"));
3885 }
3886 else
3887 {
3888 /*
3889 * Redirect successful updates back to the printer page...
3890 */
3891
3892 char refresh[1024]; /* Refresh URL */
3893
3894
3895 cgiFormEncode(uri, printer, sizeof(uri));
3896 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3897 is_class ? "classes" : "printers", uri);
3898 cgiSetVariable("refresh_page", refresh);
3899
3900 cgiStartHTML(title);
3901
3902 cgiCopyTemplateLang("printer-configured.tmpl");
3903 }
3904
3905 cgiEndHTML();
3906
3907 if (filename)
3908 unlink(tempfile);
3909 }
3910
3911 if (filename)
3912 unlink(filename);
3913 }
3914
3915
3916 /*
3917 * 'do_set_sharing()' - Set printer-is-shared value.
3918 */
3919
3920 static void
3921 do_set_sharing(http_t *http) /* I - HTTP connection */
3922 {
3923 ipp_t *request, /* IPP request */
3924 *response; /* IPP response */
3925 char uri[HTTP_MAX_URI]; /* Printer URI */
3926 const char *printer, /* Printer name */
3927 *is_class, /* Is a class? */
3928 *shared; /* Sharing value */
3929
3930
3931 is_class = cgiGetVariable("IS_CLASS");
3932 printer = cgiGetVariable("PRINTER_NAME");
3933 shared = cgiGetVariable("SHARED");
3934
3935 if (!printer || !shared)
3936 {
3937 cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
3938 cgiStartHTML(cgiText(_("Set Publishing")));
3939 cgiCopyTemplateLang("error.tmpl");
3940 cgiEndHTML();
3941 return;
3942 }
3943
3944 /*
3945 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3946 * following attributes:
3947 *
3948 * attributes-charset
3949 * attributes-natural-language
3950 * printer-uri
3951 * printer-is-shared
3952 */
3953
3954 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
3955
3956 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3957 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3958 printer);
3959 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3960 NULL, uri);
3961
3962 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3963
3964 /*
3965 * Do the request and get back a response...
3966 */
3967
3968 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3969 {
3970 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3971
3972 ippDelete(response);
3973 }
3974
3975 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3976 {
3977 puts("Status: 401\n");
3978 exit(0);
3979 }
3980 else if (cupsLastError() > IPP_OK_CONFLICT)
3981 {
3982 cgiStartHTML(cgiText(_("Set Publishing")));
3983 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3984 }
3985 else
3986 {
3987 /*
3988 * Redirect successful updates back to the printer page...
3989 */
3990
3991 char url[1024], /* Printer/class URL */
3992 refresh[1024]; /* Refresh URL */
3993
3994
3995 cgiRewriteURL(uri, url, sizeof(url), NULL);
3996 cgiFormEncode(uri, url, sizeof(uri));
3997 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3998 cgiSetVariable("refresh_page", refresh);
3999
4000 cgiStartHTML(cgiText(_("Set Publishing")));
4001 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
4002 "printer-modified.tmpl");
4003 }
4004
4005 cgiEndHTML();
4006 }
4007
4008
4009 /*
4010 * 'get_option_value()' - Return the value of an option.
4011 *
4012 * This function also handles generation of custom option values.
4013 */
4014
4015 static char * /* O - Value string or NULL on error */
4016 get_option_value(
4017 ppd_file_t *ppd, /* I - PPD file */
4018 const char *name, /* I - Option name */
4019 char *buffer, /* I - String buffer */
4020 size_t bufsize) /* I - Size of buffer */
4021 {
4022 char *bufptr, /* Pointer into buffer */
4023 *bufend; /* End of buffer */
4024 ppd_coption_t *coption; /* Custom option */
4025 ppd_cparam_t *cparam; /* Current custom parameter */
4026 char keyword[256]; /* Parameter name */
4027 const char *val, /* Parameter value */
4028 *uval; /* Units value */
4029 long integer; /* Integer value */
4030 double number, /* Number value */
4031 number_points; /* Number in points */
4032
4033
4034 /*
4035 * See if we have a custom option choice...
4036 */
4037
4038 if ((val = cgiGetVariable(name)) == NULL)
4039 {
4040 /*
4041 * Option not found!
4042 */
4043
4044 return (NULL);
4045 }
4046 else if (strcasecmp(val, "Custom") ||
4047 (coption = ppdFindCustomOption(ppd, name)) == NULL)
4048 {
4049 /*
4050 * Not a custom choice...
4051 */
4052
4053 strlcpy(buffer, val, bufsize);
4054 return (buffer);
4055 }
4056
4057 /*
4058 * OK, we have a custom option choice, format it...
4059 */
4060
4061 *buffer = '\0';
4062
4063 if (!strcmp(coption->keyword, "PageSize"))
4064 {
4065 const char *lval; /* Length string value */
4066 double width, /* Width value */
4067 width_points, /* Width in points */
4068 length, /* Length value */
4069 length_points; /* Length in points */
4070
4071
4072 val = cgiGetVariable("PageSize.Width");
4073 lval = cgiGetVariable("PageSize.Height");
4074 uval = cgiGetVariable("PageSize.Units");
4075
4076 if (!val || !lval || !uval ||
4077 (width = strtod(val, NULL)) == 0.0 ||
4078 (length = strtod(lval, NULL)) == 0.0 ||
4079 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
4080 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
4081 return (NULL);
4082
4083 width_points = get_points(width, uval);
4084 length_points = get_points(length, uval);
4085
4086 if (width_points < ppd->custom_min[0] ||
4087 width_points > ppd->custom_max[0] ||
4088 length_points < ppd->custom_min[1] ||
4089 length_points > ppd->custom_max[1])
4090 return (NULL);
4091
4092 snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
4093 }
4094 else if (cupsArrayCount(coption->params) == 1)
4095 {
4096 cparam = ppdFirstCustomParam(coption);
4097 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
4098
4099 if ((val = cgiGetVariable(keyword)) == NULL)
4100 return (NULL);
4101
4102 switch (cparam->type)
4103 {
4104 case PPD_CUSTOM_CURVE :
4105 case PPD_CUSTOM_INVCURVE :
4106 case PPD_CUSTOM_REAL :
4107 if ((number = strtod(val, NULL)) == 0.0 ||
4108 number < cparam->minimum.custom_real ||
4109 number > cparam->maximum.custom_real)
4110 return (NULL);
4111
4112 snprintf(buffer, bufsize, "Custom.%g", number);
4113 break;
4114
4115 case PPD_CUSTOM_INT :
4116 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4117 integer == LONG_MAX ||
4118 integer < cparam->minimum.custom_int ||
4119 integer > cparam->maximum.custom_int)
4120 return (NULL);
4121
4122 snprintf(buffer, bufsize, "Custom.%ld", integer);
4123 break;
4124
4125 case PPD_CUSTOM_POINTS :
4126 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4127
4128 if ((number = strtod(val, NULL)) == 0.0 ||
4129 (uval = cgiGetVariable(keyword)) == NULL ||
4130 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
4131 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
4132 return (NULL);
4133
4134 number_points = get_points(number, uval);
4135 if (number_points < cparam->minimum.custom_points ||
4136 number_points > cparam->maximum.custom_points)
4137 return (NULL);
4138
4139 snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
4140 break;
4141
4142 case PPD_CUSTOM_PASSCODE :
4143 for (uval = val; *uval; uval ++)
4144 if (!isdigit(*uval & 255))
4145 return (NULL);
4146
4147 case PPD_CUSTOM_PASSWORD :
4148 case PPD_CUSTOM_STRING :
4149 integer = (long)strlen(val);
4150 if (integer < cparam->minimum.custom_string ||
4151 integer > cparam->maximum.custom_string)
4152 return (NULL);
4153
4154 snprintf(buffer, bufsize, "Custom.%s", val);
4155 break;
4156 }
4157 }
4158 else
4159 {
4160 const char *prefix = "{"; /* Prefix string */
4161
4162
4163 bufptr = buffer;
4164 bufend = buffer + bufsize;
4165
4166 for (cparam = ppdFirstCustomParam(coption);
4167 cparam;
4168 cparam = ppdNextCustomParam(coption))
4169 {
4170 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
4171 cparam->name);
4172
4173 if ((val = cgiGetVariable(keyword)) == NULL)
4174 return (NULL);
4175
4176 snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
4177 bufptr += strlen(bufptr);
4178 prefix = " ";
4179
4180 switch (cparam->type)
4181 {
4182 case PPD_CUSTOM_CURVE :
4183 case PPD_CUSTOM_INVCURVE :
4184 case PPD_CUSTOM_REAL :
4185 if ((number = strtod(val, NULL)) == 0.0 ||
4186 number < cparam->minimum.custom_real ||
4187 number > cparam->maximum.custom_real)
4188 return (NULL);
4189
4190 snprintf(bufptr, bufend - bufptr, "%g", number);
4191 break;
4192
4193 case PPD_CUSTOM_INT :
4194 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
4195 integer == LONG_MAX ||
4196 integer < cparam->minimum.custom_int ||
4197 integer > cparam->maximum.custom_int)
4198 return (NULL);
4199
4200 snprintf(bufptr, bufend - bufptr, "%ld", integer);
4201 break;
4202
4203 case PPD_CUSTOM_POINTS :
4204 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
4205
4206 if ((number = strtod(val, NULL)) == 0.0 ||
4207 (uval = cgiGetVariable(keyword)) == NULL ||
4208 (strcmp(uval, "pt") && strcmp(uval, "in") &&
4209 strcmp(uval, "ft") && strcmp(uval, "cm") &&
4210 strcmp(uval, "mm") && strcmp(uval, "m")))
4211 return (NULL);
4212
4213 number_points = get_points(number, uval);
4214 if (number_points < cparam->minimum.custom_points ||
4215 number_points > cparam->maximum.custom_points)
4216 return (NULL);
4217
4218 snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
4219 break;
4220
4221 case PPD_CUSTOM_PASSCODE :
4222 for (uval = val; *uval; uval ++)
4223 if (!isdigit(*uval & 255))
4224 return (NULL);
4225
4226 case PPD_CUSTOM_PASSWORD :
4227 case PPD_CUSTOM_STRING :
4228 integer = (long)strlen(val);
4229 if (integer < cparam->minimum.custom_string ||
4230 integer > cparam->maximum.custom_string)
4231 return (NULL);
4232
4233 if ((bufptr + 2) > bufend)
4234 return (NULL);
4235
4236 bufend --;
4237 *bufptr++ = '\"';
4238
4239 while (*val && bufptr < bufend)
4240 {
4241 if (*val == '\\' || *val == '\"')
4242 {
4243 if ((bufptr + 1) >= bufend)
4244 return (NULL);
4245
4246 *bufptr++ = '\\';
4247 }
4248
4249 *bufptr++ = *val++;
4250 }
4251
4252 if (bufptr >= bufend)
4253 return (NULL);
4254
4255 *bufptr++ = '\"';
4256 *bufptr = '\0';
4257 bufend ++;
4258 break;
4259 }
4260
4261 bufptr += strlen(bufptr);
4262 }
4263
4264 if (bufptr == buffer || (bufend - bufptr) < 2)
4265 return (NULL);
4266
4267 strcpy(bufptr, "}");
4268 }
4269
4270 return (buffer);
4271 }
4272
4273
4274 /*
4275 * 'get_points()' - Get a value in points.
4276 */
4277
4278 static double /* O - Number in points */
4279 get_points(double number, /* I - Original number */
4280 const char *uval) /* I - Units */
4281 {
4282 if (!strcmp(uval, "mm")) /* Millimeters */
4283 return (number * 72.0 / 25.4);
4284 else if (!strcmp(uval, "cm")) /* Centimeters */
4285 return (number * 72.0 / 2.54);
4286 else if (!strcmp(uval, "in")) /* Inches */
4287 return (number * 72.0);
4288 else if (!strcmp(uval, "ft")) /* Feet */
4289 return (number * 72.0 * 12.0);
4290 else if (!strcmp(uval, "m")) /* Meters */
4291 return (number * 72.0 / 0.0254);
4292 else /* Points */
4293 return (number);
4294 }
4295
4296
4297 /*
4298 * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $".
4299 */