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