]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/admin.c
Merge changes from CUPS 1.4svn-r7874.
[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 cgiCopyTemplateLang("add-printer.tmpl");
969 }
970
971 cgiEndHTML();
972
973 if (oldinfo)
974 ippDelete(oldinfo);
975
976 return;
977 }
978 else if (!file && !cgiGetVariable("PPD_NAME"))
979 {
980 if (modify)
981 {
982 /*
983 * Get the PPD file...
984 */
985
986 int fd; /* PPD file */
987 char filename[1024]; /* PPD filename */
988 ppd_file_t *ppd; /* PPD information */
989 char buffer[1024]; /* Buffer */
990 int bytes; /* Number of bytes */
991 http_status_t get_status; /* Status of GET */
992
993
994 /* TODO: Use cupsGetFile() API... */
995 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
996
997 if (httpGet(http, uri))
998 httpGet(http, uri);
999
1000 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
1001
1002 if (get_status != HTTP_OK)
1003 {
1004 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
1005 uri, get_status, httpStatus(get_status));
1006 }
1007 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
1008 {
1009 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
1010 write(fd, buffer, bytes);
1011
1012 close(fd);
1013
1014 if ((ppd = ppdOpenFile(filename)) != NULL)
1015 {
1016 if (ppd->manufacturer)
1017 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
1018
1019 if (ppd->nickname)
1020 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
1021
1022 ppdClose(ppd);
1023 unlink(filename);
1024 }
1025 else
1026 {
1027 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
1028 filename, ppdErrorString(ppdLastError(&bytes)));
1029 }
1030 }
1031 else
1032 {
1033 httpFlush(http);
1034
1035 fprintf(stderr,
1036 "ERROR: Unable to create temporary file for PPD file: %s\n",
1037 strerror(errno));
1038 }
1039 }
1040
1041 /*
1042 * Build a CUPS_GET_PPDS request, which requires the following
1043 * attributes:
1044 *
1045 * attributes-charset
1046 * attributes-natural-language
1047 * printer-uri
1048 */
1049
1050 request = ippNewRequest(CUPS_GET_PPDS);
1051
1052 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1053 NULL, "ipp://localhost/printers/");
1054
1055 if ((var = cgiGetVariable("CURRENT_MAKE")) == NULL)
1056 var = cgiGetVariable("PPD_MAKE");
1057 if (var)
1058 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
1059 "ppd-make", NULL, var);
1060 else
1061 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1062 "requested-attributes", NULL, "ppd-make");
1063
1064 /*
1065 * Do the request and get back a response...
1066 */
1067
1068 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1069 {
1070 /*
1071 * Got the list of PPDs, see if the user has selected a make...
1072 */
1073
1074 if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0)
1075 {
1076 /*
1077 * No PPD files with this make, try again with all makes...
1078 */
1079
1080 ippDelete(response);
1081
1082 request = ippNewRequest(CUPS_GET_PPDS);
1083
1084 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1085 NULL, "ipp://localhost/printers/");
1086
1087 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1088 "requested-attributes", NULL, "ppd-make");
1089
1090 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1091 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1092
1093 cgiStartHTML(title);
1094 cgiCopyTemplateLang("choose-make.tmpl");
1095 cgiEndHTML();
1096 }
1097 else if (!var || cgiGetVariable("SELECT_MAKE"))
1098 {
1099 cgiStartHTML(title);
1100 cgiCopyTemplateLang("choose-make.tmpl");
1101 cgiEndHTML();
1102 }
1103 else
1104 {
1105 /*
1106 * Let the user choose a model...
1107 */
1108
1109 const char *make_model; /* Current make/model string */
1110
1111
1112 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
1113 {
1114 /*
1115 * Scan for "close" matches...
1116 */
1117
1118 int match, /* Current match */
1119 best_match, /* Best match so far */
1120 count; /* Number of drivers */
1121 const char *best, /* Best matching string */
1122 *current; /* Current string */
1123
1124
1125 count = cgiGetSize("PPD_MAKE_AND_MODEL");
1126
1127 for (i = 0, best_match = 0, best = NULL; i < count; i ++)
1128 {
1129 current = cgiGetArray("PPD_MAKE_AND_MODEL", i);
1130 match = match_string(make_model, current);
1131
1132 if (match > best_match)
1133 {
1134 best_match = match;
1135 best = current;
1136 }
1137 }
1138
1139 if (best_match > strlen(var))
1140 {
1141 /*
1142 * Found a match longer than the make...
1143 */
1144
1145 cgiSetVariable("CURRENT_MAKE_AND_MODEL", best);
1146 }
1147 }
1148
1149 cgiStartHTML(title);
1150 cgiCopyTemplateLang("choose-model.tmpl");
1151 cgiEndHTML();
1152 }
1153
1154 ippDelete(response);
1155 }
1156 else
1157 {
1158 cgiStartHTML(title);
1159 cgiShowIPPError(_("Unable to get list of printer drivers:"));
1160 cgiCopyTemplateLang("error.tmpl");
1161 cgiEndHTML();
1162 }
1163 }
1164 else
1165 {
1166 /*
1167 * Build a CUPS_ADD_PRINTER request, which requires the following
1168 * attributes:
1169 *
1170 * attributes-charset
1171 * attributes-natural-language
1172 * printer-uri
1173 * printer-location
1174 * printer-info
1175 * ppd-name
1176 * device-uri
1177 * printer-is-accepting-jobs
1178 * printer-state
1179 */
1180
1181 request = ippNewRequest(CUPS_ADD_PRINTER);
1182
1183 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1184 "localhost", 0, "/printers/%s",
1185 cgiGetVariable("PRINTER_NAME"));
1186 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1187 NULL, uri);
1188
1189 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1190 NULL, cgiGetVariable("PRINTER_LOCATION"));
1191
1192 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1193 NULL, cgiGetVariable("PRINTER_INFO"));
1194
1195 if (!file)
1196 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
1197 NULL, cgiGetVariable("PPD_NAME"));
1198
1199 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
1200
1201 /*
1202 * Strip make and model from URI...
1203 */
1204
1205 if ((uriptr = strrchr(uri, '|')) != NULL)
1206 *uriptr = '\0';
1207
1208 if (!strncmp(uri, "serial:", 7))
1209 {
1210 /*
1211 * Update serial port URI to include baud rate, etc.
1212 */
1213
1214 if ((uriptr = strchr(uri, '?')) == NULL)
1215 uriptr = uri + strlen(uri);
1216
1217 snprintf(uriptr, sizeof(uri) - (uriptr - uri),
1218 "?baud=%s+bits=%s+parity=%s+flow=%s",
1219 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
1220 cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
1221 }
1222
1223 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
1224 NULL, uri);
1225
1226 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1227
1228 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1229 IPP_PRINTER_IDLE);
1230
1231 /*
1232 * Do the request and get back a response...
1233 */
1234
1235 if (file)
1236 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
1237 else
1238 ippDelete(cupsDoRequest(http, request, "/admin/"));
1239
1240 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1241 {
1242 puts("Status: 401\n");
1243 exit(0);
1244 }
1245 else if (cupsLastError() > IPP_OK_CONFLICT)
1246 {
1247 cgiStartHTML(title);
1248 cgiShowIPPError(modify ? _("Unable to modify printer:") :
1249 _("Unable to add printer:"));
1250 }
1251 else if (modify)
1252 {
1253 /*
1254 * Redirect successful updates back to the printer page...
1255 */
1256
1257 char refresh[1024]; /* Refresh URL */
1258
1259
1260 cgiFormEncode(uri, name, sizeof(uri));
1261
1262 snprintf(refresh, sizeof(refresh),
1263 "5;/admin/?OP=redirect&URL=/printers/%s", uri);
1264
1265 cgiSetVariable("refresh_page", refresh);
1266
1267 cgiStartHTML(title);
1268
1269 cgiCopyTemplateLang("printer-modified.tmpl");
1270 }
1271 else
1272 {
1273 /*
1274 * Set the printer options...
1275 */
1276
1277 cgiSetVariable("OP", "set-printer-options");
1278 do_set_options(http, 0);
1279 return;
1280 }
1281
1282 cgiEndHTML();
1283 }
1284
1285 if (oldinfo)
1286 ippDelete(oldinfo);
1287 }
1288
1289
1290 /*
1291 * 'do_cancel_subscription()' - Cancel a subscription.
1292 */
1293
1294 static void
1295 do_cancel_subscription(http_t *http)/* I - HTTP connection */
1296 {
1297 ipp_t *request; /* IPP request data */
1298 const char *var, /* Form variable */
1299 *user; /* Username */
1300 int id; /* Subscription ID */
1301
1302
1303 /*
1304 * See if we have all of the required information...
1305 */
1306
1307 if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL)
1308 id = atoi(var);
1309 else
1310 id = 0;
1311
1312 if (id <= 0)
1313 {
1314 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!")));
1315 cgiStartHTML(_("Cancel RSS Subscription"));
1316 cgiCopyTemplateLang("error.tmpl");
1317 cgiEndHTML();
1318 return;
1319 }
1320
1321 /*
1322 * Require a username...
1323 */
1324
1325 if ((user = getenv("REMOTE_USER")) == NULL)
1326 {
1327 puts("Status: 401\n");
1328 exit(0);
1329 }
1330
1331 /*
1332 * Cancel the subscription...
1333 */
1334
1335 request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
1336
1337 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1338 NULL, "ipp://localhost/");
1339 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
1340 "notify-subscription-id", id);
1341
1342 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1343 NULL, user);
1344
1345 ippDelete(cupsDoRequest(http, request, "/"));
1346
1347 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1348 {
1349 puts("Status: 401\n");
1350 exit(0);
1351 }
1352 else if (cupsLastError() > IPP_OK_CONFLICT)
1353 {
1354 cgiStartHTML(_("Cancel RSS Subscription"));
1355 cgiShowIPPError(_("Unable to cancel RSS subscription:"));
1356 }
1357 else
1358 {
1359 /*
1360 * Redirect successful updates back to the admin page...
1361 */
1362
1363 cgiSetVariable("refresh_page", "5;URL=/admin");
1364 cgiStartHTML(_("Cancel RSS Subscription"));
1365 cgiCopyTemplateLang("subscription-canceled.tmpl");
1366 }
1367
1368 cgiEndHTML();
1369 }
1370
1371
1372 /*
1373 * 'do_config_server()' - Configure server settings.
1374 */
1375
1376 static void
1377 do_config_server(http_t *http) /* I - HTTP connection */
1378 {
1379 if (cgiGetVariable("CHANGESETTINGS"))
1380 {
1381 /*
1382 * Save basic setting changes...
1383 */
1384
1385 int num_settings; /* Number of server settings */
1386 cups_option_t *settings; /* Server settings */
1387 const char *debug_logging, /* DEBUG_LOGGING value */
1388 *remote_admin, /* REMOTE_ADMIN value */
1389 *remote_any, /* REMOTE_ANY value */
1390 *remote_printers,
1391 /* REMOTE_PRINTERS value */
1392 *share_printers,/* SHARE_PRINTERS value */
1393 *user_cancel_any;
1394 /* USER_CANCEL_ANY value */
1395 #ifdef HAVE_GSSAPI
1396 char default_auth_type[255];
1397 /* DefaultAuthType value */
1398 #endif /* HAVE_GSSAPI */
1399
1400
1401 /*
1402 * Get the checkbox values from the form...
1403 */
1404
1405 debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
1406 remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
1407 remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
1408 remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
1409 share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
1410 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
1411
1412 /*
1413 * Get the current server settings...
1414 */
1415
1416 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
1417 {
1418 cgiStartHTML(cgiText(_("Change Settings")));
1419 cgiSetVariable("MESSAGE",
1420 cgiText(_("Unable to change server settings:")));
1421 cgiSetVariable("ERROR", cupsLastErrorString());
1422 cgiCopyTemplateLang("error.tmpl");
1423 cgiEndHTML();
1424 return;
1425 }
1426
1427 #ifdef HAVE_GSSAPI
1428 /*
1429 * Get authentication settings...
1430 */
1431
1432 if (cgiGetVariable("KERBEROS"))
1433 strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
1434 else
1435 {
1436 const char *val = cupsGetOption("DefaultAuthType", num_settings,
1437 settings);
1438
1439 if (val && !strcasecmp(val, "Negotiate"))
1440 strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
1441 else
1442 strlcpy(default_auth_type, val, sizeof(default_auth_type));
1443 }
1444
1445 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
1446 #endif /* HAVE_GSSAPI */
1447
1448 /*
1449 * See if the settings have changed...
1450 */
1451
1452 if (strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
1453 num_settings, settings)) ||
1454 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
1455 num_settings, settings)) ||
1456 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
1457 num_settings, settings)) ||
1458 strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
1459 num_settings, settings)) ||
1460 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
1461 num_settings, settings)) ||
1462 #ifdef HAVE_GSSAPI
1463 !cupsGetOption("DefaultAuthType", num_settings, settings) ||
1464 strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
1465 num_settings, settings)) ||
1466 #endif /* HAVE_GSSAPI */
1467 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
1468 num_settings, settings)))
1469 {
1470 /*
1471 * Settings *have* changed, so save the changes...
1472 */
1473
1474 cupsFreeOptions(num_settings, settings);
1475
1476 num_settings = 0;
1477 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1478 debug_logging, num_settings, &settings);
1479 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1480 remote_admin, num_settings, &settings);
1481 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1482 remote_any, num_settings, &settings);
1483 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
1484 remote_printers, num_settings, &settings);
1485 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1486 share_printers, num_settings, &settings);
1487 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1488 user_cancel_any, num_settings, &settings);
1489 #ifdef HAVE_GSSAPI
1490 num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
1491 num_settings, &settings);
1492 #endif /* HAVE_GSSAPI */
1493
1494 if (!cupsAdminSetServerSettings(http, num_settings, settings))
1495 {
1496 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1497 {
1498 puts("Status: 401\n");
1499 exit(0);
1500 }
1501
1502 cgiStartHTML(cgiText(_("Change Settings")));
1503 cgiSetVariable("MESSAGE",
1504 cgiText(_("Unable to change server settings:")));
1505 cgiSetVariable("ERROR", cupsLastErrorString());
1506 cgiCopyTemplateLang("error.tmpl");
1507 }
1508 else
1509 {
1510 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1511 cgiStartHTML(cgiText(_("Change Settings")));
1512 cgiCopyTemplateLang("restart.tmpl");
1513 }
1514 }
1515 else
1516 {
1517 /*
1518 * No changes...
1519 */
1520
1521 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1522 cgiStartHTML(cgiText(_("Change Settings")));
1523 cgiCopyTemplateLang("norestart.tmpl");
1524 }
1525
1526 cupsFreeOptions(num_settings, settings);
1527
1528 cgiEndHTML();
1529 }
1530 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
1531 {
1532 /*
1533 * Save hand-edited config file...
1534 */
1535
1536 http_status_t status; /* PUT status */
1537 char tempfile[1024]; /* Temporary new cupsd.conf */
1538 int tempfd; /* Temporary file descriptor */
1539 cups_file_t *temp; /* Temporary file */
1540 const char *start, /* Start of line */
1541 *end; /* End of line */
1542
1543
1544 /*
1545 * Create a temporary file for the new cupsd.conf file...
1546 */
1547
1548 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
1549 {
1550 cgiStartHTML(cgiText(_("Edit Configuration File")));
1551 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
1552 cgiSetVariable("ERROR", strerror(errno));
1553 cgiCopyTemplateLang("error.tmpl");
1554 cgiEndHTML();
1555
1556 perror(tempfile);
1557 return;
1558 }
1559
1560 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
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 close(tempfd);
1570 unlink(tempfile);
1571 return;
1572 }
1573
1574 /*
1575 * Copy the cupsd.conf text from the form variable...
1576 */
1577
1578 start = cgiGetVariable("CUPSDCONF");
1579 while (start)
1580 {
1581 if ((end = strstr(start, "\r\n")) == NULL)
1582 if ((end = strstr(start, "\n")) == NULL)
1583 end = start + strlen(start);
1584
1585 cupsFileWrite(temp, start, end - start);
1586 cupsFilePutChar(temp, '\n');
1587
1588 if (*end == '\r')
1589 start = end + 2;
1590 else if (*end == '\n')
1591 start = end + 1;
1592 else
1593 start = NULL;
1594 }
1595
1596 cupsFileClose(temp);
1597
1598 /*
1599 * Upload the configuration file to the server...
1600 */
1601
1602 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1603
1604 if (status == HTTP_UNAUTHORIZED)
1605 {
1606 puts("Status: 401\n");
1607 unlink(tempfile);
1608 exit(0);
1609 }
1610 else if (status != HTTP_CREATED)
1611 {
1612 cgiSetVariable("MESSAGE",
1613 cgiText(_("Unable to upload cupsd.conf file:")));
1614 cgiSetVariable("ERROR", httpStatus(status));
1615
1616 cgiStartHTML(cgiText(_("Edit Configuration File")));
1617 cgiCopyTemplateLang("error.tmpl");
1618 }
1619 else
1620 {
1621 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
1622
1623 cgiStartHTML(cgiText(_("Edit Configuration File")));
1624 cgiCopyTemplateLang("restart.tmpl");
1625 }
1626
1627 cgiEndHTML();
1628
1629 unlink(tempfile);
1630 }
1631 else
1632 {
1633 struct stat info; /* cupsd.conf information */
1634 cups_file_t *cupsd; /* cupsd.conf file */
1635 char *buffer, /* Buffer for entire file */
1636 *bufptr, /* Pointer into buffer */
1637 *bufend; /* End of buffer */
1638 int ch; /* Character from file */
1639 char filename[1024]; /* Filename */
1640 const char *server_root; /* Location of config files */
1641
1642
1643 /*
1644 * Locate the cupsd.conf file...
1645 */
1646
1647 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
1648 server_root = CUPS_SERVERROOT;
1649
1650 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
1651
1652 /*
1653 * Figure out the size...
1654 */
1655
1656 if (stat(filename, &info))
1657 {
1658 cgiStartHTML(cgiText(_("Edit Configuration File")));
1659 cgiSetVariable("MESSAGE",
1660 cgiText(_("Unable to access cupsd.conf file:")));
1661 cgiSetVariable("ERROR", strerror(errno));
1662 cgiCopyTemplateLang("error.tmpl");
1663 cgiEndHTML();
1664
1665 perror(filename);
1666 return;
1667 }
1668
1669 if (info.st_size > (1024 * 1024))
1670 {
1671 cgiStartHTML(cgiText(_("Edit Configuration File")));
1672 cgiSetVariable("MESSAGE",
1673 cgiText(_("Unable to access cupsd.conf file:")));
1674 cgiSetVariable("ERROR",
1675 cgiText(_("Unable to edit cupsd.conf files larger than "
1676 "1MB!")));
1677 cgiCopyTemplateLang("error.tmpl");
1678 cgiEndHTML();
1679
1680 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
1681 (long)info.st_size);
1682 return;
1683 }
1684
1685 /*
1686 * Open the cupsd.conf file...
1687 */
1688
1689 if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
1690 {
1691 /*
1692 * Unable to open - log an error...
1693 */
1694
1695 cgiStartHTML(cgiText(_("Edit Configuration File")));
1696 cgiSetVariable("MESSAGE",
1697 cgiText(_("Unable to access cupsd.conf file:")));
1698 cgiSetVariable("ERROR", strerror(errno));
1699 cgiCopyTemplateLang("error.tmpl");
1700 cgiEndHTML();
1701
1702 perror(filename);
1703 return;
1704 }
1705
1706 /*
1707 * Allocate memory and load the file into a string buffer...
1708 */
1709
1710 if ((buffer = calloc(1, info.st_size + 1)) != NULL)
1711 {
1712 cupsFileRead(cupsd, buffer, info.st_size);
1713 cgiSetVariable("CUPSDCONF", buffer);
1714 free(buffer);
1715 }
1716
1717 cupsFileClose(cupsd);
1718
1719 /*
1720 * Then get the default cupsd.conf file and put that into a string as
1721 * well...
1722 */
1723
1724 strlcat(filename, ".default", sizeof(filename));
1725
1726 if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
1727 (cupsd = cupsFileOpen(filename, "r")) != NULL)
1728 {
1729 if ((buffer = calloc(1, 2 * info.st_size + 1)) != NULL)
1730 {
1731 bufend = buffer + 2 * info.st_size - 1;
1732
1733 for (bufptr = buffer;
1734 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
1735 {
1736 if (ch == '\\' || ch == '\"')
1737 {
1738 *bufptr++ = '\\';
1739 *bufptr++ = ch;
1740 }
1741 else if (ch == '\n')
1742 {
1743 *bufptr++ = '\\';
1744 *bufptr++ = 'n';
1745 }
1746 else if (ch == '\t')
1747 {
1748 *bufptr++ = '\\';
1749 *bufptr++ = 't';
1750 }
1751 else if (ch >= ' ')
1752 *bufptr++ = ch;
1753 }
1754
1755 *bufptr = '\0';
1756
1757 cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
1758 free(buffer);
1759 }
1760
1761 cupsFileClose(cupsd);
1762 }
1763
1764 /*
1765 * Show the current config file...
1766 */
1767
1768 cgiStartHTML(cgiText(_("Edit Configuration File")));
1769
1770 cgiCopyTemplateLang("edit-config.tmpl");
1771
1772 cgiEndHTML();
1773 }
1774 }
1775
1776
1777 /*
1778 * 'do_delete_class()' - Delete a class.
1779 */
1780
1781 static void
1782 do_delete_class(http_t *http) /* I - HTTP connection */
1783 {
1784 ipp_t *request; /* IPP request */
1785 char uri[HTTP_MAX_URI]; /* Job URI */
1786 const char *pclass; /* Printer class name */
1787
1788
1789 /*
1790 * Get form variables...
1791 */
1792
1793 if (cgiGetVariable("CONFIRM") == NULL)
1794 {
1795 cgiStartHTML(cgiText(_("Delete Class")));
1796 cgiCopyTemplateLang("class-confirm.tmpl");
1797 cgiEndHTML();
1798 return;
1799 }
1800
1801 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
1802 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1803 "localhost", 0, "/classes/%s", pclass);
1804 else
1805 {
1806 cgiStartHTML(cgiText(_("Delete Class")));
1807 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1808 cgiCopyTemplateLang("error.tmpl");
1809 cgiEndHTML();
1810 return;
1811 }
1812
1813 /*
1814 * Build a CUPS_DELETE_CLASS request, which requires the following
1815 * attributes:
1816 *
1817 * attributes-charset
1818 * attributes-natural-language
1819 * printer-uri
1820 */
1821
1822 request = ippNewRequest(CUPS_DELETE_CLASS);
1823
1824 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1825 NULL, uri);
1826
1827 /*
1828 * Do the request and get back a response...
1829 */
1830
1831 ippDelete(cupsDoRequest(http, request, "/admin/"));
1832
1833 /*
1834 * Show the results...
1835 */
1836
1837 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1838 {
1839 puts("Status: 401\n");
1840 exit(0);
1841 }
1842 else if (cupsLastError() <= IPP_OK_CONFLICT)
1843 {
1844 /*
1845 * Redirect successful updates back to the classes page...
1846 */
1847
1848 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
1849 }
1850
1851 cgiStartHTML(cgiText(_("Delete Class")));
1852
1853 if (cupsLastError() > IPP_OK_CONFLICT)
1854 cgiShowIPPError(_("Unable to delete class:"));
1855 else
1856 cgiCopyTemplateLang("class-deleted.tmpl");
1857
1858 cgiEndHTML();
1859 }
1860
1861
1862 /*
1863 * 'do_delete_printer()' - Delete a printer.
1864 */
1865
1866 static void
1867 do_delete_printer(http_t *http) /* I - HTTP connection */
1868 {
1869 ipp_t *request; /* IPP request */
1870 char uri[HTTP_MAX_URI]; /* Job URI */
1871 const char *printer; /* Printer printer name */
1872
1873
1874 /*
1875 * Get form variables...
1876 */
1877
1878 if (cgiGetVariable("CONFIRM") == NULL)
1879 {
1880 cgiStartHTML(cgiText(_("Delete Printer")));
1881 cgiCopyTemplateLang("printer-confirm.tmpl");
1882 cgiEndHTML();
1883 return;
1884 }
1885
1886 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
1887 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1888 "localhost", 0, "/printers/%s", printer);
1889 else
1890 {
1891 cgiStartHTML(cgiText(_("Delete Printer")));
1892 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
1893 cgiCopyTemplateLang("error.tmpl");
1894 cgiEndHTML();
1895 return;
1896 }
1897
1898 /*
1899 * Build a CUPS_DELETE_PRINTER request, which requires the following
1900 * attributes:
1901 *
1902 * attributes-charset
1903 * attributes-natural-language
1904 * printer-uri
1905 */
1906
1907 request = ippNewRequest(CUPS_DELETE_PRINTER);
1908
1909 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1910 NULL, uri);
1911
1912 /*
1913 * Do the request and get back a response...
1914 */
1915
1916 ippDelete(cupsDoRequest(http, request, "/admin/"));
1917
1918 /*
1919 * Show the results...
1920 */
1921
1922 if (cupsLastError() == IPP_NOT_AUTHORIZED)
1923 {
1924 puts("Status: 401\n");
1925 exit(0);
1926 }
1927 else if (cupsLastError() <= IPP_OK_CONFLICT)
1928 {
1929 /*
1930 * Redirect successful updates back to the printers page...
1931 */
1932
1933 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
1934 }
1935
1936 cgiStartHTML(cgiText(_("Delete Printer")));
1937
1938 if (cupsLastError() > IPP_OK_CONFLICT)
1939 cgiShowIPPError(_("Unable to delete printer:"));
1940 else
1941 cgiCopyTemplateLang("printer-deleted.tmpl");
1942
1943 cgiEndHTML();
1944 }
1945
1946
1947 /*
1948 * 'do_export()' - Export printers to Samba.
1949 */
1950
1951 static void
1952 do_export(http_t *http) /* I - HTTP connection */
1953 {
1954 int i, j; /* Looping vars */
1955 ipp_t *request, /* IPP request */
1956 *response; /* IPP response */
1957 const char *username, /* Samba username */
1958 *password, /* Samba password */
1959 *export_all; /* Export all printers? */
1960 int export_count, /* Number of printers to export */
1961 printer_count; /* Number of available printers */
1962 const char *name, /* What name to pull */
1963 *dest; /* Current destination */
1964 char ppd[1024]; /* PPD file */
1965
1966
1967 /*
1968 * Get form data...
1969 */
1970
1971 username = cgiGetVariable("USERNAME");
1972 password = cgiGetVariable("PASSWORD");
1973 export_all = cgiGetVariable("EXPORT_ALL");
1974 export_count = cgiGetSize("EXPORT_NAME");
1975
1976 /*
1977 * Get list of available printers...
1978 */
1979
1980 cgiSetSize("PRINTER_NAME", 0);
1981 cgiSetSize("PRINTER_EXPORT", 0);
1982
1983 request = ippNewRequest(CUPS_GET_PRINTERS);
1984
1985 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1986 "printer-type", 0);
1987
1988 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1989 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
1990 CUPS_PRINTER_IMPLICIT);
1991
1992 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1993 "requested-attributes", NULL, "printer-name");
1994
1995 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1996 {
1997 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
1998 ippDelete(response);
1999
2000 if (!export_all)
2001 {
2002 printer_count = cgiGetSize("PRINTER_NAME");
2003
2004 for (i = 0; i < printer_count; i ++)
2005 {
2006 dest = cgiGetArray("PRINTER_NAME", i);
2007
2008 for (j = 0; j < export_count; j ++)
2009 if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
2010 break;
2011
2012 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
2013 }
2014 }
2015 }
2016
2017 /*
2018 * Export or get the printers to export...
2019 */
2020
2021 if (username && *username && password && *password &&
2022 (export_all || export_count > 0))
2023 {
2024 /*
2025 * Do export...
2026 */
2027
2028 fputs("DEBUG: Export printers...\n", stderr);
2029
2030 if (export_all)
2031 {
2032 name = "PRINTER_NAME";
2033 export_count = cgiGetSize("PRINTER_NAME");
2034 }
2035 else
2036 name = "EXPORT_NAME";
2037
2038 for (i = 0; i < export_count; i ++)
2039 {
2040 dest = cgiGetArray(name, i);
2041
2042 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
2043 break;
2044
2045 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
2046 stderr);
2047
2048 unlink(ppd);
2049
2050 if (!j)
2051 break;
2052 }
2053
2054 if (i < export_count)
2055 cgiSetVariable("ERROR", cupsLastErrorString());
2056 else
2057 {
2058 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2059 cgiCopyTemplateLang("samba-exported.tmpl");
2060 cgiEndHTML();
2061 return;
2062 }
2063 }
2064 else if (username && !*username)
2065 cgiSetVariable("ERROR",
2066 cgiText(_("A Samba username is required to export "
2067 "printer drivers!")));
2068 else if (username && (!password || !*password))
2069 cgiSetVariable("ERROR",
2070 cgiText(_("A Samba password is required to export "
2071 "printer drivers!")));
2072
2073 /*
2074 * Show form...
2075 */
2076
2077 cgiStartHTML(cgiText(_("Export Printers to Samba")));
2078 cgiCopyTemplateLang("samba-export.tmpl");
2079 cgiEndHTML();
2080 }
2081
2082
2083 /*
2084 * 'do_list_printers()' - List available printers.
2085 */
2086
2087 static void
2088 do_list_printers(http_t *http) /* I - HTTP connection */
2089 {
2090 ipp_t *request, /* IPP request */
2091 *response; /* IPP response */
2092 ipp_attribute_t *attr; /* IPP attribute */
2093
2094
2095 cgiStartHTML(cgiText(_("List Available Printers")));
2096 fflush(stdout);
2097
2098 /*
2099 * Get the list of printers and their devices...
2100 */
2101
2102 request = ippNewRequest(CUPS_GET_PRINTERS);
2103
2104 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2105 "requested-attributes", NULL, "device-uri");
2106
2107 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
2108 CUPS_PRINTER_LOCAL);
2109 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
2110 CUPS_PRINTER_LOCAL);
2111
2112 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2113 {
2114 /*
2115 * Got the printer list, now load the devices...
2116 */
2117
2118 int i; /* Looping var */
2119 cups_array_t *printer_devices; /* Printer devices for local printers */
2120 char *printer_device; /* Current printer device */
2121
2122
2123 /*
2124 * Allocate an array and copy the device strings...
2125 */
2126
2127 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2128
2129 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
2130 attr;
2131 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
2132 {
2133 cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
2134 }
2135
2136 /*
2137 * Free the printer list and get the device list...
2138 */
2139
2140 ippDelete(response);
2141
2142 request = ippNewRequest(CUPS_GET_DEVICES);
2143
2144 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2145 {
2146 /*
2147 * Got the device list, let's parse it...
2148 */
2149
2150 const char *device_uri, /* device-uri attribute value */
2151 *device_make_and_model, /* device-make-and-model value */
2152 *device_info; /* device-info value */
2153
2154
2155 for (i = 0, attr = response->attrs; attr; attr = attr->next)
2156 {
2157 /*
2158 * Skip leading attributes until we hit a device...
2159 */
2160
2161 while (attr && attr->group_tag != IPP_TAG_PRINTER)
2162 attr = attr->next;
2163
2164 if (!attr)
2165 break;
2166
2167 /*
2168 * Pull the needed attributes from this device...
2169 */
2170
2171 device_info = NULL;
2172 device_make_and_model = NULL;
2173 device_uri = NULL;
2174
2175 while (attr && attr->group_tag == IPP_TAG_PRINTER)
2176 {
2177 if (!strcmp(attr->name, "device-info") &&
2178 attr->value_tag == IPP_TAG_TEXT)
2179 device_info = attr->values[0].string.text;
2180
2181 if (!strcmp(attr->name, "device-make-and-model") &&
2182 attr->value_tag == IPP_TAG_TEXT)
2183 device_make_and_model = attr->values[0].string.text;
2184
2185 if (!strcmp(attr->name, "device-uri") &&
2186 attr->value_tag == IPP_TAG_URI)
2187 device_uri = attr->values[0].string.text;
2188
2189 attr = attr->next;
2190 }
2191
2192 /*
2193 * See if we have everything needed...
2194 */
2195
2196 if (device_info && device_make_and_model && device_uri &&
2197 strcasecmp(device_make_and_model, "unknown") &&
2198 strchr(device_uri, ':'))
2199 {
2200 /*
2201 * Yes, now see if there is already a printer for this
2202 * device...
2203 */
2204
2205 if (!cupsArrayFind(printer_devices, (void *)device_uri))
2206 {
2207 /*
2208 * Not found, so it must be a new printer...
2209 */
2210
2211 char option[1024], /* Form variables for this device */
2212 *option_ptr; /* Pointer into string */
2213 const char *ptr; /* Pointer into device string */
2214
2215
2216 /*
2217 * Format the printer name variable for this device...
2218 *
2219 * We use the device-info string first, then device-uri,
2220 * and finally device-make-and-model to come up with a
2221 * suitable name.
2222 */
2223
2224 if (strncasecmp(device_info, "unknown", 7))
2225 ptr = device_info;
2226 else if ((ptr = strstr(device_uri, "://")) != NULL)
2227 ptr += 3;
2228 else
2229 ptr = device_make_and_model;
2230
2231 for (option_ptr = option;
2232 option_ptr < (option + sizeof(option) - 1) && *ptr;
2233 ptr ++)
2234 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
2235 *ptr == '.')
2236 *option_ptr++ = *ptr;
2237 else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_')
2238 *option_ptr++ = '_';
2239 else if (*ptr == '?' || *ptr == '(')
2240 break;
2241
2242 *option_ptr = '\0';
2243
2244 cgiSetArray("TEMPLATE_NAME", i, option);
2245
2246 /*
2247 * Finally, set the form variables for this printer...
2248 */
2249
2250 cgiSetArray("device_info", i, device_info);
2251 cgiSetArray("device_make_and_model", i, device_make_and_model);
2252 cgiSetArray("device_uri", i, device_uri);
2253 i ++;
2254 }
2255 }
2256
2257 if (!attr)
2258 break;
2259 }
2260
2261 ippDelete(response);
2262
2263 /*
2264 * Free the device list...
2265 */
2266
2267 for (printer_device = (char *)cupsArrayFirst(printer_devices);
2268 printer_device;
2269 printer_device = (char *)cupsArrayNext(printer_devices))
2270 free(printer_device);
2271
2272 cupsArrayDelete(printer_devices);
2273 }
2274 }
2275
2276 /*
2277 * Finally, show the printer list...
2278 */
2279
2280 cgiCopyTemplateLang("list-available-printers.tmpl");
2281
2282 cgiEndHTML();
2283 }
2284
2285
2286 /*
2287 * 'do_menu()' - Show the main menu.
2288 */
2289
2290 static void
2291 do_menu(http_t *http) /* I - HTTP connection */
2292 {
2293 int num_settings; /* Number of server settings */
2294 cups_option_t *settings; /* Server settings */
2295 const char *val; /* Setting value */
2296 char filename[1024]; /* Temporary filename */
2297 const char *datadir; /* Location of data files */
2298 ipp_t *request, /* IPP request */
2299 *response; /* IPP response */
2300
2301
2302 /*
2303 * Get the current server settings...
2304 */
2305
2306 if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
2307 {
2308 cgiSetVariable("SETTINGS_MESSAGE",
2309 cgiText(_("Unable to open cupsd.conf file:")));
2310 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
2311 }
2312
2313 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
2314 settings)) != NULL && atoi(val))
2315 cgiSetVariable("DEBUG_LOGGING", "CHECKED");
2316
2317 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
2318 settings)) != NULL && atoi(val))
2319 cgiSetVariable("REMOTE_ADMIN", "CHECKED");
2320
2321 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
2322 settings)) != NULL && atoi(val))
2323 cgiSetVariable("REMOTE_ANY", "CHECKED");
2324
2325 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
2326 settings)) != NULL && atoi(val))
2327 cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
2328
2329 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
2330 settings)) != NULL && atoi(val))
2331 cgiSetVariable("SHARE_PRINTERS", "CHECKED");
2332
2333 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
2334 settings)) != NULL && atoi(val))
2335 cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
2336
2337 #ifdef HAVE_GSSAPI
2338 cgiSetVariable("HAVE_GSSAPI", "1");
2339
2340 if ((val = cupsGetOption("DefaultAuthType", num_settings,
2341 settings)) != NULL && !strcasecmp(val, "Negotiate"))
2342 cgiSetVariable("KERBEROS", "CHECKED");
2343 #endif /* HAVE_GSSAPI */
2344
2345 cupsFreeOptions(num_settings, settings);
2346
2347 /*
2348 * See if Samba and the Windows drivers are installed...
2349 */
2350
2351 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
2352 datadir = CUPS_DATADIR;
2353
2354 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
2355 if (!access(filename, R_OK))
2356 {
2357 /*
2358 * Found Windows 2000 driver file, see if we have smbclient and
2359 * rpcclient...
2360 */
2361
2362 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2363 sizeof(filename)) &&
2364 cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2365 sizeof(filename)))
2366 cgiSetVariable("HAVE_SAMBA", "Y");
2367 else
2368 {
2369 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
2370 sizeof(filename)))
2371 fputs("ERROR: smbclient not found!\n", stderr);
2372
2373 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
2374 sizeof(filename)))
2375 fputs("ERROR: rpcclient not found!\n", stderr);
2376 }
2377 }
2378 else
2379 perror(filename);
2380
2381 /*
2382 * Subscriptions...
2383 */
2384
2385 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
2386
2387 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2388 NULL, "ipp://localhost/");
2389
2390 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2391 {
2392 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2393 ippDelete(response);
2394 }
2395
2396 /*
2397 * Finally, show the main menu template...
2398 */
2399
2400 cgiStartHTML(cgiText(_("Administration")));
2401
2402 cgiCopyTemplateLang("admin.tmpl");
2403
2404 cgiEndHTML();
2405 }
2406
2407
2408 /*
2409 * 'do_printer_op()' - Do a printer operation.
2410 */
2411
2412 static void
2413 do_printer_op(http_t *http, /* I - HTTP connection */
2414 ipp_op_t op, /* I - Operation to perform */
2415 const char *title) /* I - Title of page */
2416 {
2417 ipp_t *request; /* IPP request */
2418 char uri[HTTP_MAX_URI]; /* Printer URI */
2419 const char *printer, /* Printer name (purge-jobs) */
2420 *is_class; /* Is a class? */
2421
2422
2423 is_class = cgiGetVariable("IS_CLASS");
2424 printer = cgiGetVariable("PRINTER_NAME");
2425
2426 if (!printer)
2427 {
2428 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2429 cgiStartHTML(title);
2430 cgiCopyTemplateLang("error.tmpl");
2431 cgiEndHTML();
2432 return;
2433 }
2434
2435 /*
2436 * Build a printer request, which requires the following
2437 * attributes:
2438 *
2439 * attributes-charset
2440 * attributes-natural-language
2441 * printer-uri
2442 */
2443
2444 request = ippNewRequest(op);
2445
2446 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2447 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2448 printer);
2449 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2450 NULL, uri);
2451
2452 /*
2453 * Do the request and get back a response...
2454 */
2455
2456 ippDelete(cupsDoRequest(http, request, "/admin/"));
2457
2458 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2459 {
2460 puts("Status: 401\n");
2461 exit(0);
2462 }
2463 else if (cupsLastError() > IPP_OK_CONFLICT)
2464 {
2465 cgiStartHTML(title);
2466 cgiShowIPPError(_("Unable to change printer:"));
2467 }
2468 else
2469 {
2470 /*
2471 * Redirect successful updates back to the printer page...
2472 */
2473
2474 char url[1024], /* Printer/class URL */
2475 refresh[1024]; /* Refresh URL */
2476
2477
2478 cgiRewriteURL(uri, url, sizeof(url), NULL);
2479 cgiFormEncode(uri, url, sizeof(uri));
2480 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
2481 cgiSetVariable("refresh_page", refresh);
2482
2483 cgiStartHTML(title);
2484
2485 if (op == IPP_PAUSE_PRINTER)
2486 cgiCopyTemplateLang("printer-stop.tmpl");
2487 else if (op == IPP_RESUME_PRINTER)
2488 cgiCopyTemplateLang("printer-start.tmpl");
2489 else if (op == CUPS_ACCEPT_JOBS)
2490 cgiCopyTemplateLang("printer-accept.tmpl");
2491 else if (op == CUPS_REJECT_JOBS)
2492 cgiCopyTemplateLang("printer-reject.tmpl");
2493 else if (op == IPP_PURGE_JOBS)
2494 cgiCopyTemplateLang("printer-purge.tmpl");
2495 else if (op == CUPS_SET_DEFAULT)
2496 cgiCopyTemplateLang("printer-default.tmpl");
2497 }
2498
2499 cgiEndHTML();
2500 }
2501
2502
2503 /*
2504 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
2505 */
2506
2507 static void
2508 do_set_allowed_users(http_t *http) /* I - HTTP connection */
2509 {
2510 int i; /* Looping var */
2511 ipp_t *request, /* IPP request */
2512 *response; /* IPP response */
2513 char uri[HTTP_MAX_URI]; /* Printer URI */
2514 const char *printer, /* Printer name (purge-jobs) */
2515 *is_class, /* Is a class? */
2516 *users, /* List of users or groups */
2517 *type; /* Allow/deny type */
2518 int num_users; /* Number of users */
2519 char *ptr, /* Pointer into users string */
2520 *end, /* Pointer to end of users string */
2521 quote; /* Quote character */
2522 ipp_attribute_t *attr; /* Attribute */
2523 static const char * const attrs[] = /* Requested attributes */
2524 {
2525 "requesting-user-name-allowed",
2526 "requesting-user-name-denied"
2527 };
2528
2529
2530 is_class = cgiGetVariable("IS_CLASS");
2531 printer = cgiGetVariable("PRINTER_NAME");
2532
2533 if (!printer)
2534 {
2535 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2536 cgiStartHTML(cgiText(_("Set Allowed Users")));
2537 cgiCopyTemplateLang("error.tmpl");
2538 cgiEndHTML();
2539 return;
2540 }
2541
2542 users = cgiGetVariable("users");
2543 type = cgiGetVariable("type");
2544
2545 if (!users || !type ||
2546 (strcmp(type, "requesting-user-name-allowed") &&
2547 strcmp(type, "requesting-user-name-denied")))
2548 {
2549 /*
2550 * Build a Get-Printer-Attributes request, which requires the following
2551 * attributes:
2552 *
2553 * attributes-charset
2554 * attributes-natural-language
2555 * printer-uri
2556 * requested-attributes
2557 */
2558
2559 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
2560
2561 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2562 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2563 printer);
2564 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2565 NULL, uri);
2566
2567 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
2568 "requested-attributes",
2569 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
2570
2571 /*
2572 * Do the request and get back a response...
2573 */
2574
2575 if ((response = cupsDoRequest(http, request, "/")) != NULL)
2576 {
2577 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
2578
2579 ippDelete(response);
2580 }
2581
2582 cgiStartHTML(cgiText(_("Set Allowed Users")));
2583
2584 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2585 {
2586 puts("Status: 401\n");
2587 exit(0);
2588 }
2589 else if (cupsLastError() > IPP_OK_CONFLICT)
2590 cgiShowIPPError(_("Unable to get printer attributes:"));
2591 else
2592 cgiCopyTemplateLang("users.tmpl");
2593
2594 cgiEndHTML();
2595 }
2596 else
2597 {
2598 /*
2599 * Save the changes...
2600 */
2601
2602 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
2603 {
2604 /*
2605 * Skip whitespace and commas...
2606 */
2607
2608 while (*ptr == ',' || isspace(*ptr & 255))
2609 ptr ++;
2610
2611 if (*ptr == '\'' || *ptr == '\"')
2612 {
2613 /*
2614 * Scan quoted name...
2615 */
2616
2617 quote = *ptr++;
2618
2619 for (end = ptr; *end; end ++)
2620 if (*end == quote)
2621 break;
2622 }
2623 else
2624 {
2625 /*
2626 * Scan space or comma-delimited name...
2627 */
2628
2629 for (end = ptr; *end; end ++)
2630 if (isspace(*end & 255) || *end == ',')
2631 break;
2632 }
2633
2634 /*
2635 * Advance to the next name...
2636 */
2637
2638 ptr = end;
2639 }
2640
2641 /*
2642 * Build a CUPS-Add-Printer/Class request, which requires the following
2643 * attributes:
2644 *
2645 * attributes-charset
2646 * attributes-natural-language
2647 * printer-uri
2648 * requesting-user-name-{allowed,denied}
2649 */
2650
2651 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
2652
2653 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2654 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2655 printer);
2656 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
2657 NULL, uri);
2658
2659 if (num_users == 0)
2660 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2661 "requesting-user-name-allowed", NULL, "all");
2662 else
2663 {
2664 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
2665 type, num_users, NULL, NULL);
2666
2667 for (i = 0, ptr = (char *)users; *ptr; i ++)
2668 {
2669 /*
2670 * Skip whitespace and commas...
2671 */
2672
2673 while (*ptr == ',' || isspace(*ptr & 255))
2674 ptr ++;
2675
2676 if (*ptr == '\'' || *ptr == '\"')
2677 {
2678 /*
2679 * Scan quoted name...
2680 */
2681
2682 quote = *ptr++;
2683
2684 for (end = ptr; *end; end ++)
2685 if (*end == quote)
2686 break;
2687 }
2688 else
2689 {
2690 /*
2691 * Scan space or comma-delimited name...
2692 */
2693
2694 for (end = ptr; *end; end ++)
2695 if (isspace(*end & 255) || *end == ',')
2696 break;
2697 }
2698
2699 /*
2700 * Terminate the name...
2701 */
2702
2703 if (*end)
2704 *end++ = '\0';
2705
2706 /*
2707 * Add the name...
2708 */
2709
2710 attr->values[i].string.text = strdup(ptr);
2711
2712 /*
2713 * Advance to the next name...
2714 */
2715
2716 ptr = end;
2717 }
2718 }
2719
2720 /*
2721 * Do the request and get back a response...
2722 */
2723
2724 ippDelete(cupsDoRequest(http, request, "/admin/"));
2725
2726 if (cupsLastError() == IPP_NOT_AUTHORIZED)
2727 {
2728 puts("Status: 401\n");
2729 exit(0);
2730 }
2731 else if (cupsLastError() > IPP_OK_CONFLICT)
2732 {
2733 cgiStartHTML(cgiText(_("Set Allowed Users")));
2734 cgiShowIPPError(_("Unable to change printer:"));
2735 }
2736 else
2737 {
2738 /*
2739 * Redirect successful updates back to the printer page...
2740 */
2741
2742 char url[1024], /* Printer/class URL */
2743 refresh[1024]; /* Refresh URL */
2744
2745
2746 cgiRewriteURL(uri, url, sizeof(url), NULL);
2747 cgiFormEncode(uri, url, sizeof(uri));
2748 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
2749 uri);
2750 cgiSetVariable("refresh_page", refresh);
2751
2752 cgiStartHTML(cgiText(_("Set Allowed Users")));
2753
2754 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
2755 "printer-modified.tmpl");
2756 }
2757
2758 cgiEndHTML();
2759 }
2760 }
2761
2762
2763 /*
2764 * 'do_set_options()' - Configure the default options for a queue.
2765 */
2766
2767 static void
2768 do_set_options(http_t *http, /* I - HTTP connection */
2769 int is_class) /* I - Set options for class? */
2770 {
2771 int i, j, k, m; /* Looping vars */
2772 int have_options; /* Have options? */
2773 ipp_t *request, /* IPP request */
2774 *response; /* IPP response */
2775 ipp_attribute_t *attr; /* IPP attribute */
2776 char uri[HTTP_MAX_URI]; /* Job URI */
2777 const char *var; /* Variable value */
2778 const char *printer; /* Printer printer name */
2779 const char *filename; /* PPD filename */
2780 char tempfile[1024]; /* Temporary filename */
2781 cups_file_t *in, /* Input file */
2782 *out; /* Output file */
2783 char line[1024], /* Line from PPD file */
2784 value[1024], /* Option value */
2785 keyword[1024], /* Keyword from Default line */
2786 *keyptr; /* Pointer into keyword... */
2787 ppd_file_t *ppd; /* PPD file */
2788 ppd_group_t *group; /* Option group */
2789 ppd_option_t *option; /* Option */
2790 ppd_coption_t *coption; /* Custom option */
2791 ppd_cparam_t *cparam; /* Custom parameter */
2792 ppd_attr_t *protocol; /* cupsProtocol attribute */
2793 const char *title; /* Page title */
2794
2795
2796 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
2797
2798 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
2799 is_class);
2800
2801 /*
2802 * Get the printer name...
2803 */
2804
2805 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
2806 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2807 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
2808 printer);
2809 else
2810 {
2811 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
2812 cgiStartHTML(title);
2813 cgiCopyTemplateLang("error.tmpl");
2814 cgiEndHTML();
2815 return;
2816 }
2817
2818 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
2819
2820 /*
2821 * Get the PPD file...
2822 */
2823
2824 if (is_class)
2825 filename = NULL;
2826 else
2827 filename = cupsGetPPD2(http, printer);
2828
2829 if (filename)
2830 {
2831 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
2832
2833 if ((ppd = ppdOpenFile(filename)) == NULL)
2834 {
2835 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
2836 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
2837 cgiStartHTML(title);
2838 cgiCopyTemplateLang("error.tmpl");
2839 cgiEndHTML();
2840 return;
2841 }
2842 }
2843 else
2844 {
2845 fputs("DEBUG: No PPD file\n", stderr);
2846 ppd = NULL;
2847 }
2848
2849 if (cgiGetVariable("job_sheets_start") != NULL ||
2850 cgiGetVariable("job_sheets_end") != NULL)
2851 have_options = 1;
2852 else
2853 have_options = 0;
2854
2855 if (ppd)
2856 {
2857 ppdMarkDefaults(ppd);
2858
2859 for (option = ppdFirstOption(ppd);
2860 option;
2861 option = ppdNextOption(ppd))
2862 if ((var = cgiGetVariable(option->keyword)) != NULL)
2863 {
2864 have_options = 1;
2865 ppdMarkOption(ppd, option->keyword, var);
2866 }
2867 }
2868
2869 if (!have_options || ppdConflicts(ppd))
2870 {
2871 /*
2872 * Show the options to the user...
2873 */
2874
2875 fputs("DEBUG: Showing options...\n", stderr);
2876
2877 cgiStartHTML(cgiText(_("Set Printer Options")));
2878 cgiCopyTemplateLang("set-printer-options-header.tmpl");
2879
2880 if (ppd)
2881 {
2882 ppdLocalize(ppd);
2883
2884 if (ppdConflicts(ppd))
2885 {
2886 for (i = ppd->num_groups, k = 0, group = ppd->groups;
2887 i > 0;
2888 i --, group ++)
2889 for (j = group->num_options, option = group->options;
2890 j > 0;
2891 j --, option ++)
2892 if (option->conflicted)
2893 {
2894 cgiSetArray("ckeyword", k, option->keyword);
2895 cgiSetArray("ckeytext", k, option->text);
2896 k ++;
2897 }
2898
2899 cgiCopyTemplateLang("option-conflict.tmpl");
2900 }
2901
2902 for (i = ppd->num_groups, group = ppd->groups;
2903 i > 0;
2904 i --, group ++)
2905 {
2906 if (!strcmp(group->name, "InstallableOptions"))
2907 cgiSetVariable("GROUP", cgiText(_("Options Installed")));
2908 else
2909 cgiSetVariable("GROUP", group->text);
2910
2911 cgiCopyTemplateLang("option-header.tmpl");
2912
2913 for (j = group->num_options, option = group->options;
2914 j > 0;
2915 j --, option ++)
2916 {
2917 if (!strcmp(option->keyword, "PageRegion"))
2918 continue;
2919
2920 cgiSetVariable("KEYWORD", option->keyword);
2921 cgiSetVariable("KEYTEXT", option->text);
2922
2923 if (option->conflicted)
2924 cgiSetVariable("CONFLICTED", "1");
2925 else
2926 cgiSetVariable("CONFLICTED", "0");
2927
2928 cgiSetSize("CHOICES", 0);
2929 cgiSetSize("TEXT", 0);
2930 for (k = 0, m = 0; k < option->num_choices; k ++)
2931 {
2932 cgiSetArray("CHOICES", m, option->choices[k].choice);
2933 cgiSetArray("TEXT", m, option->choices[k].text);
2934
2935 m ++;
2936
2937 if (option->choices[k].marked)
2938 cgiSetVariable("DEFCHOICE", option->choices[k].choice);
2939 }
2940
2941 cgiSetSize("PARAMS", 0);
2942 cgiSetSize("PARAMTEXT", 0);
2943 cgiSetSize("PARAMVALUE", 0);
2944 cgiSetSize("INPUTTYPE", 0);
2945
2946 if ((coption = ppdFindCustomOption(ppd, option->keyword)))
2947 {
2948 const char *units = NULL; /* Units value, if any */
2949
2950
2951 cgiSetVariable("ISCUSTOM", "1");
2952
2953 for (cparam = ppdFirstCustomParam(coption), m = 0;
2954 cparam;
2955 cparam = ppdNextCustomParam(coption), m ++)
2956 {
2957 if (!strcasecmp(option->keyword, "PageSize") &&
2958 strcasecmp(cparam->name, "Width") &&
2959 strcasecmp(cparam->name, "Height"))
2960 {
2961 m --;
2962 continue;
2963 }
2964
2965 cgiSetArray("PARAMS", m, cparam->name);
2966 cgiSetArray("PARAMTEXT", m, cparam->text);
2967 cgiSetArray("INPUTTYPE", m, "text");
2968
2969 switch (cparam->type)
2970 {
2971 case PPD_CUSTOM_POINTS :
2972 if (!strncasecmp(option->defchoice, "Custom.", 7))
2973 {
2974 units = option->defchoice + strlen(option->defchoice) - 2;
2975
2976 if (strcmp(units, "mm") && strcmp(units, "cm") &&
2977 strcmp(units, "in") && strcmp(units, "ft"))
2978 {
2979 if (units[1] == 'm')
2980 units ++;
2981 else
2982 units = "pt";
2983 }
2984 }
2985 else
2986 units = "pt";
2987
2988 if (!strcmp(units, "mm"))
2989 snprintf(value, sizeof(value), "%g",
2990 cparam->current.custom_points / 72.0 * 25.4);
2991 else if (!strcmp(units, "cm"))
2992 snprintf(value, sizeof(value), "%g",
2993 cparam->current.custom_points / 72.0 * 2.54);
2994 else if (!strcmp(units, "in"))
2995 snprintf(value, sizeof(value), "%g",
2996 cparam->current.custom_points / 72.0);
2997 else if (!strcmp(units, "ft"))
2998 snprintf(value, sizeof(value), "%g",
2999 cparam->current.custom_points / 72.0 / 12.0);
3000 else if (!strcmp(units, "m"))
3001 snprintf(value, sizeof(value), "%g",
3002 cparam->current.custom_points / 72.0 * 0.0254);
3003 else
3004 snprintf(value, sizeof(value), "%g",
3005 cparam->current.custom_points);
3006 cgiSetArray("PARAMVALUE", m, value);
3007 break;
3008
3009 case PPD_CUSTOM_CURVE :
3010 case PPD_CUSTOM_INVCURVE :
3011 case PPD_CUSTOM_REAL :
3012 snprintf(value, sizeof(value), "%g",
3013 cparam->current.custom_real);
3014 cgiSetArray("PARAMVALUE", m, value);
3015 break;
3016
3017 case PPD_CUSTOM_INT:
3018 snprintf(value, sizeof(value), "%d",
3019 cparam->current.custom_int);
3020 cgiSetArray("PARAMVALUE", m, value);
3021 break;
3022
3023 case PPD_CUSTOM_PASSCODE:
3024 case PPD_CUSTOM_PASSWORD:
3025 if (cparam->current.custom_password)
3026 cgiSetArray("PARAMVALUE", m,
3027 cparam->current.custom_password);
3028 else
3029 cgiSetArray("PARAMVALUE", m, "");
3030 cgiSetArray("INPUTTYPE", m, "password");
3031 break;
3032
3033 case PPD_CUSTOM_STRING:
3034 if (cparam->current.custom_string)
3035 cgiSetArray("PARAMVALUE", m,
3036 cparam->current.custom_string);
3037 else
3038 cgiSetArray("PARAMVALUE", m, "");
3039 break;
3040 }
3041 }
3042
3043 if (units)
3044 {
3045 cgiSetArray("PARAMS", m, "Units");
3046 cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
3047 cgiSetArray("PARAMVALUE", m, units);
3048 }
3049 }
3050 else
3051 cgiSetVariable("ISCUSTOM", "0");
3052
3053 switch (option->ui)
3054 {
3055 case PPD_UI_BOOLEAN :
3056 cgiCopyTemplateLang("option-boolean.tmpl");
3057 break;
3058 case PPD_UI_PICKONE :
3059 cgiCopyTemplateLang("option-pickone.tmpl");
3060 break;
3061 case PPD_UI_PICKMANY :
3062 cgiCopyTemplateLang("option-pickmany.tmpl");
3063 break;
3064 }
3065 }
3066
3067 cgiCopyTemplateLang("option-trailer.tmpl");
3068 }
3069 }
3070
3071 /*
3072 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
3073 * following attributes:
3074 *
3075 * attributes-charset
3076 * attributes-natural-language
3077 * printer-uri
3078 */
3079
3080 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
3081
3082 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3083 "localhost", 0, "/printers/%s", printer);
3084 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3085 NULL, uri);
3086
3087 /*
3088 * Do the request and get back a response...
3089 */
3090
3091 if ((response = cupsDoRequest(http, request, "/")) != NULL)
3092 {
3093 if ((attr = ippFindAttribute(response, "job-sheets-supported",
3094 IPP_TAG_ZERO)) != NULL)
3095 {
3096 /*
3097 * Add the job sheets options...
3098 */
3099
3100 cgiSetVariable("GROUP", cgiText(_("Banners")));
3101 cgiCopyTemplateLang("option-header.tmpl");
3102
3103 cgiSetSize("CHOICES", attr->num_values);
3104 cgiSetSize("TEXT", attr->num_values);
3105 for (k = 0; k < attr->num_values; k ++)
3106 {
3107 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3108 cgiSetArray("TEXT", k, attr->values[k].string.text);
3109 }
3110
3111 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
3112
3113 cgiSetVariable("KEYWORD", "job_sheets_start");
3114 cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner")));
3115 cgiSetVariable("DEFCHOICE", attr != NULL ?
3116 attr->values[0].string.text : "");
3117
3118 cgiCopyTemplateLang("option-pickone.tmpl");
3119
3120 cgiSetVariable("KEYWORD", "job_sheets_end");
3121 cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner")));
3122 cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
3123 attr->values[1].string.text : "");
3124
3125 cgiCopyTemplateLang("option-pickone.tmpl");
3126
3127 cgiCopyTemplateLang("option-trailer.tmpl");
3128 }
3129
3130 if (ippFindAttribute(response, "printer-error-policy-supported",
3131 IPP_TAG_ZERO) ||
3132 ippFindAttribute(response, "printer-op-policy-supported",
3133 IPP_TAG_ZERO))
3134 {
3135 /*
3136 * Add the error and operation policy options...
3137 */
3138
3139 cgiSetVariable("GROUP", cgiText(_("Policies")));
3140 cgiCopyTemplateLang("option-header.tmpl");
3141
3142 /*
3143 * Error policy...
3144 */
3145
3146 attr = ippFindAttribute(response, "printer-error-policy-supported",
3147 IPP_TAG_ZERO);
3148
3149 if (attr)
3150 {
3151 cgiSetSize("CHOICES", attr->num_values);
3152 cgiSetSize("TEXT", attr->num_values);
3153 for (k = 0; k < attr->num_values; k ++)
3154 {
3155 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3156 cgiSetArray("TEXT", k, attr->values[k].string.text);
3157 }
3158
3159 attr = ippFindAttribute(response, "printer-error-policy",
3160 IPP_TAG_ZERO);
3161
3162 cgiSetVariable("KEYWORD", "printer_error_policy");
3163 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
3164 cgiSetVariable("DEFCHOICE", attr == NULL ?
3165 "" : attr->values[0].string.text);
3166 }
3167
3168 cgiCopyTemplateLang("option-pickone.tmpl");
3169
3170 /*
3171 * Operation policy...
3172 */
3173
3174 attr = ippFindAttribute(response, "printer-op-policy-supported",
3175 IPP_TAG_ZERO);
3176
3177 if (attr)
3178 {
3179 cgiSetSize("CHOICES", attr->num_values);
3180 cgiSetSize("TEXT", attr->num_values);
3181 for (k = 0; k < attr->num_values; k ++)
3182 {
3183 cgiSetArray("CHOICES", k, attr->values[k].string.text);
3184 cgiSetArray("TEXT", k, attr->values[k].string.text);
3185 }
3186
3187 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
3188
3189 cgiSetVariable("KEYWORD", "printer_op_policy");
3190 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
3191 cgiSetVariable("DEFCHOICE", attr == NULL ?
3192 "" : attr->values[0].string.text);
3193
3194 cgiCopyTemplateLang("option-pickone.tmpl");
3195 }
3196
3197 cgiCopyTemplateLang("option-trailer.tmpl");
3198 }
3199
3200 ippDelete(response);
3201 }
3202
3203 /*
3204 * Binary protocol support...
3205 */
3206
3207 if (ppd && ppd->protocols && strstr(ppd->protocols, "BCP"))
3208 {
3209 protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
3210
3211 cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
3212 cgiCopyTemplateLang("option-header.tmpl");
3213
3214 cgiSetSize("CHOICES", 2);
3215 cgiSetSize("TEXT", 2);
3216 cgiSetArray("CHOICES", 0, "None");
3217 cgiSetArray("TEXT", 0, cgiText(_("None")));
3218
3219 if (strstr(ppd->protocols, "TBCP"))
3220 {
3221 cgiSetArray("CHOICES", 1, "TBCP");
3222 cgiSetArray("TEXT", 1, "TBCP");
3223 }
3224 else
3225 {
3226 cgiSetArray("CHOICES", 1, "BCP");
3227 cgiSetArray("TEXT", 1, "BCP");
3228 }
3229
3230 cgiSetVariable("KEYWORD", "protocol");
3231 cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
3232 cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
3233
3234 cgiCopyTemplateLang("option-pickone.tmpl");
3235
3236 cgiCopyTemplateLang("option-trailer.tmpl");
3237 }
3238
3239 cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
3240 cgiEndHTML();
3241 }
3242 else
3243 {
3244 /*
3245 * Set default options...
3246 */
3247
3248 fputs("DEBUG: Setting options...\n", stderr);
3249
3250 if (filename)
3251 {
3252 out = cupsTempFile2(tempfile, sizeof(tempfile));
3253 in = cupsFileOpen(filename, "r");
3254
3255 if (!in || !out)
3256 {
3257 cgiSetVariable("ERROR", strerror(errno));
3258 cgiStartHTML(cgiText(_("Set Printer Options")));
3259 cgiCopyTemplateLang("error.tmpl");
3260 cgiEndHTML();
3261
3262 if (in)
3263 cupsFileClose(in);
3264
3265 if (out)
3266 {
3267 cupsFileClose(out);
3268 unlink(tempfile);
3269 }
3270
3271 unlink(filename);
3272 return;
3273 }
3274
3275 while (cupsFileGets(in, line, sizeof(line)))
3276 {
3277 if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol"))
3278 continue;
3279 else if (strncmp(line, "*Default", 8))
3280 cupsFilePrintf(out, "%s\n", line);
3281 else
3282 {
3283 /*
3284 * Get default option name...
3285 */
3286
3287 strlcpy(keyword, line + 8, sizeof(keyword));
3288
3289 for (keyptr = keyword; *keyptr; keyptr ++)
3290 if (*keyptr == ':' || isspace(*keyptr & 255))
3291 break;
3292
3293 *keyptr = '\0';
3294
3295 if (!strcmp(keyword, "PageRegion") ||
3296 !strcmp(keyword, "PaperDimension") ||
3297 !strcmp(keyword, "ImageableArea"))
3298 var = get_option_value(ppd, "PageSize", value, sizeof(value));
3299 else
3300 var = get_option_value(ppd, keyword, value, sizeof(value));
3301
3302 if (!var)
3303 cupsFilePrintf(out, "%s\n", line);
3304 else
3305 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
3306 }
3307 }
3308
3309 /*
3310 * TODO: We need to set the port-monitor attribute!
3311 */
3312
3313 if ((var = cgiGetVariable("protocol")) != NULL)
3314 cupsFilePrintf(out, "*cupsProtocol: %s\n", var);
3315
3316 cupsFileClose(in);
3317 cupsFileClose(out);
3318 }
3319 else
3320 {
3321 /*
3322 * Make sure temporary filename is cleared when there is no PPD...
3323 */
3324
3325 tempfile[0] = '\0';
3326 }
3327
3328 /*
3329 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
3330 * following attributes:
3331 *
3332 * attributes-charset
3333 * attributes-natural-language
3334 * printer-uri
3335 * job-sheets-default
3336 * printer-error-policy
3337 * printer-op-policy
3338 * [ppd file]
3339 */
3340
3341 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
3342 CUPS_ADD_MODIFY_PRINTER);
3343
3344 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3345 NULL, uri);
3346
3347 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3348 "job-sheets-default", 2, NULL, NULL);
3349 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
3350 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
3351
3352 if ((var = cgiGetVariable("printer_error_policy")) != NULL)
3353 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3354 "printer-error-policy", NULL, var);
3355
3356 if ((var = cgiGetVariable("printer_op_policy")) != NULL)
3357 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
3358 "printer-op-policy", NULL, var);
3359
3360 /*
3361 * Do the request and get back a response...
3362 */
3363
3364 if (filename)
3365 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
3366 else
3367 ippDelete(cupsDoRequest(http, request, "/admin/"));
3368
3369 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3370 {
3371 puts("Status: 401\n");
3372 exit(0);
3373 }
3374 else if (cupsLastError() > IPP_OK_CONFLICT)
3375 {
3376 cgiStartHTML(title);
3377 cgiShowIPPError(_("Unable to set options:"));
3378 }
3379 else
3380 {
3381 /*
3382 * Redirect successful updates back to the printer page...
3383 */
3384
3385 char refresh[1024]; /* Refresh URL */
3386
3387
3388 cgiFormEncode(uri, printer, sizeof(uri));
3389 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
3390 is_class ? "classes" : "printers", uri);
3391 cgiSetVariable("refresh_page", refresh);
3392
3393 cgiStartHTML(title);
3394
3395 cgiCopyTemplateLang("printer-configured.tmpl");
3396 }
3397
3398 cgiEndHTML();
3399
3400 if (filename)
3401 unlink(tempfile);
3402 }
3403
3404 if (filename)
3405 unlink(filename);
3406 }
3407
3408
3409 /*
3410 * 'do_set_sharing()' - Set printer-is-shared value.
3411 */
3412
3413 static void
3414 do_set_sharing(http_t *http) /* I - HTTP connection */
3415 {
3416 ipp_t *request, /* IPP request */
3417 *response; /* IPP response */
3418 char uri[HTTP_MAX_URI]; /* Printer URI */
3419 const char *printer, /* Printer name */
3420 *is_class, /* Is a class? */
3421 *shared; /* Sharing value */
3422
3423
3424 is_class = cgiGetVariable("IS_CLASS");
3425 printer = cgiGetVariable("PRINTER_NAME");
3426 shared = cgiGetVariable("SHARED");
3427
3428 if (!printer || !shared)
3429 {
3430 cgiSetVariable("ERROR", cgiText(_("Missing form variable!")));
3431 cgiStartHTML(cgiText(_("Set Publishing")));
3432 cgiCopyTemplateLang("error.tmpl");
3433 cgiEndHTML();
3434 return;
3435 }
3436
3437 /*
3438 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
3439 * following attributes:
3440 *
3441 * attributes-charset
3442 * attributes-natural-language
3443 * printer-uri
3444 * printer-is-shared
3445 */
3446
3447 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
3448
3449 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3450 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
3451 printer);
3452 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
3453 NULL, uri);
3454
3455 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared));
3456
3457 /*
3458 * Do the request and get back a response...
3459 */
3460
3461 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
3462 {
3463 cgiSetIPPVars(response, NULL, NULL, NULL, 0);
3464
3465 ippDelete(response);
3466 }
3467
3468 if (cupsLastError() == IPP_NOT_AUTHORIZED)
3469 {
3470 puts("Status: 401\n");
3471 exit(0);
3472 }
3473 else if (cupsLastError() > IPP_OK_CONFLICT)
3474 {
3475 cgiStartHTML(cgiText(_("Set Publishing")));
3476 cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
3477 }
3478 else
3479 {
3480 /*
3481 * Redirect successful updates back to the printer page...
3482 */
3483
3484 char url[1024], /* Printer/class URL */
3485 refresh[1024]; /* Refresh URL */
3486
3487
3488 cgiRewriteURL(uri, url, sizeof(url), NULL);
3489 cgiFormEncode(uri, url, sizeof(uri));
3490 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
3491 cgiSetVariable("refresh_page", refresh);
3492
3493 cgiStartHTML(cgiText(_("Set Publishing")));
3494 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
3495 "printer-modified.tmpl");
3496 }
3497
3498 cgiEndHTML();
3499 }
3500
3501
3502 /*
3503 * 'get_option_value()' - Return the value of an option.
3504 *
3505 * This function also handles generation of custom option values.
3506 */
3507
3508 static char * /* O - Value string or NULL on error */
3509 get_option_value(
3510 ppd_file_t *ppd, /* I - PPD file */
3511 const char *name, /* I - Option name */
3512 char *buffer, /* I - String buffer */
3513 size_t bufsize) /* I - Size of buffer */
3514 {
3515 char *bufptr, /* Pointer into buffer */
3516 *bufend; /* End of buffer */
3517 ppd_coption_t *coption; /* Custom option */
3518 ppd_cparam_t *cparam; /* Current custom parameter */
3519 char keyword[256]; /* Parameter name */
3520 const char *val, /* Parameter value */
3521 *uval; /* Units value */
3522 long integer; /* Integer value */
3523 double number, /* Number value */
3524 number_points; /* Number in points */
3525
3526
3527 /*
3528 * See if we have a custom option choice...
3529 */
3530
3531 if ((val = cgiGetVariable(name)) == NULL)
3532 {
3533 /*
3534 * Option not found!
3535 */
3536
3537 return (NULL);
3538 }
3539 else if (strcasecmp(val, "Custom") ||
3540 (coption = ppdFindCustomOption(ppd, name)) == NULL)
3541 {
3542 /*
3543 * Not a custom choice...
3544 */
3545
3546 strlcpy(buffer, val, bufsize);
3547 return (buffer);
3548 }
3549
3550 /*
3551 * OK, we have a custom option choice, format it...
3552 */
3553
3554 *buffer = '\0';
3555
3556 if (!strcmp(coption->keyword, "PageSize"))
3557 {
3558 const char *lval; /* Length string value */
3559 double width, /* Width value */
3560 width_points, /* Width in points */
3561 length, /* Length value */
3562 length_points; /* Length in points */
3563
3564
3565 val = cgiGetVariable("PageSize.Width");
3566 lval = cgiGetVariable("PageSize.Height");
3567 uval = cgiGetVariable("PageSize.Units");
3568
3569 if (!val || !lval || !uval ||
3570 (width = strtod(val, NULL)) == 0.0 ||
3571 (length = strtod(lval, NULL)) == 0.0 ||
3572 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3573 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3574 return (NULL);
3575
3576 width_points = get_points(width, uval);
3577 length_points = get_points(length, uval);
3578
3579 if (width_points < ppd->custom_min[0] ||
3580 width_points > ppd->custom_max[0] ||
3581 length_points < ppd->custom_min[1] ||
3582 length_points > ppd->custom_max[1])
3583 return (NULL);
3584
3585 snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
3586 }
3587 else if (cupsArrayCount(coption->params) == 1)
3588 {
3589 cparam = ppdFirstCustomParam(coption);
3590 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
3591
3592 if ((val = cgiGetVariable(keyword)) == NULL)
3593 return (NULL);
3594
3595 switch (cparam->type)
3596 {
3597 case PPD_CUSTOM_CURVE :
3598 case PPD_CUSTOM_INVCURVE :
3599 case PPD_CUSTOM_REAL :
3600 if ((number = strtod(val, NULL)) == 0.0 ||
3601 number < cparam->minimum.custom_real ||
3602 number > cparam->maximum.custom_real)
3603 return (NULL);
3604
3605 snprintf(buffer, bufsize, "Custom.%g", number);
3606 break;
3607
3608 case PPD_CUSTOM_INT :
3609 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
3610 integer == LONG_MAX ||
3611 integer < cparam->minimum.custom_int ||
3612 integer > cparam->maximum.custom_int)
3613 return (NULL);
3614
3615 snprintf(buffer, bufsize, "Custom.%ld", integer);
3616 break;
3617
3618 case PPD_CUSTOM_POINTS :
3619 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
3620
3621 if ((number = strtod(val, NULL)) == 0.0 ||
3622 (uval = cgiGetVariable(keyword)) == NULL ||
3623 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
3624 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
3625 return (NULL);
3626
3627 number_points = get_points(number, uval);
3628 if (number_points < cparam->minimum.custom_points ||
3629 number_points > cparam->maximum.custom_points)
3630 return (NULL);
3631
3632 snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
3633 break;
3634
3635 case PPD_CUSTOM_PASSCODE :
3636 for (uval = val; *uval; uval ++)
3637 if (!isdigit(*uval & 255))
3638 return (NULL);
3639
3640 case PPD_CUSTOM_PASSWORD :
3641 case PPD_CUSTOM_STRING :
3642 integer = (long)strlen(val);
3643 if (integer < cparam->minimum.custom_string ||
3644 integer > cparam->maximum.custom_string)
3645 return (NULL);
3646
3647 snprintf(buffer, bufsize, "Custom.%s", val);
3648 break;
3649 }
3650 }
3651 else
3652 {
3653 const char *prefix = "{"; /* Prefix string */
3654
3655
3656 bufptr = buffer;
3657 bufend = buffer + bufsize;
3658
3659 for (cparam = ppdFirstCustomParam(coption);
3660 cparam;
3661 cparam = ppdNextCustomParam(coption))
3662 {
3663 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
3664 cparam->name);
3665
3666 if ((val = cgiGetVariable(keyword)) == NULL)
3667 return (NULL);
3668
3669 snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
3670 bufptr += strlen(bufptr);
3671 prefix = " ";
3672
3673 switch (cparam->type)
3674 {
3675 case PPD_CUSTOM_CURVE :
3676 case PPD_CUSTOM_INVCURVE :
3677 case PPD_CUSTOM_REAL :
3678 if ((number = strtod(val, NULL)) == 0.0 ||
3679 number < cparam->minimum.custom_real ||
3680 number > cparam->maximum.custom_real)
3681 return (NULL);
3682
3683 snprintf(bufptr, bufend - bufptr, "%g", number);
3684 break;
3685
3686 case PPD_CUSTOM_INT :
3687 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
3688 integer == LONG_MAX ||
3689 integer < cparam->minimum.custom_int ||
3690 integer > cparam->maximum.custom_int)
3691 return (NULL);
3692
3693 snprintf(bufptr, bufend - bufptr, "%ld", integer);
3694 break;
3695
3696 case PPD_CUSTOM_POINTS :
3697 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
3698
3699 if ((number = strtod(val, NULL)) == 0.0 ||
3700 (uval = cgiGetVariable(keyword)) == NULL ||
3701 (strcmp(uval, "pt") && strcmp(uval, "in") &&
3702 strcmp(uval, "ft") && strcmp(uval, "cm") &&
3703 strcmp(uval, "mm") && strcmp(uval, "m")))
3704 return (NULL);
3705
3706 number_points = get_points(number, uval);
3707 if (number_points < cparam->minimum.custom_points ||
3708 number_points > cparam->maximum.custom_points)
3709 return (NULL);
3710
3711 snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
3712 break;
3713
3714 case PPD_CUSTOM_PASSCODE :
3715 for (uval = val; *uval; uval ++)
3716 if (!isdigit(*uval & 255))
3717 return (NULL);
3718
3719 case PPD_CUSTOM_PASSWORD :
3720 case PPD_CUSTOM_STRING :
3721 integer = (long)strlen(val);
3722 if (integer < cparam->minimum.custom_string ||
3723 integer > cparam->maximum.custom_string)
3724 return (NULL);
3725
3726 if ((bufptr + 2) > bufend)
3727 return (NULL);
3728
3729 bufend --;
3730 *bufptr++ = '\"';
3731
3732 while (*val && bufptr < bufend)
3733 {
3734 if (*val == '\\' || *val == '\"')
3735 {
3736 if ((bufptr + 1) >= bufend)
3737 return (NULL);
3738
3739 *bufptr++ = '\\';
3740 }
3741
3742 *bufptr++ = *val++;
3743 }
3744
3745 if (bufptr >= bufend)
3746 return (NULL);
3747
3748 *bufptr++ = '\"';
3749 *bufptr = '\0';
3750 bufend ++;
3751 break;
3752 }
3753
3754 bufptr += strlen(bufptr);
3755 }
3756
3757 if (bufptr == buffer || (bufend - bufptr) < 2)
3758 return (NULL);
3759
3760 strcpy(bufptr, "}");
3761 }
3762
3763 return (buffer);
3764 }
3765
3766
3767 /*
3768 * 'get_points()' - Get a value in points.
3769 */
3770
3771 static double /* O - Number in points */
3772 get_points(double number, /* I - Original number */
3773 const char *uval) /* I - Units */
3774 {
3775 if (!strcmp(uval, "mm")) /* Millimeters */
3776 return (number * 72.0 / 25.4);
3777 else if (!strcmp(uval, "cm")) /* Centimeters */
3778 return (number * 72.0 / 2.54);
3779 else if (!strcmp(uval, "in")) /* Inches */
3780 return (number * 72.0);
3781 else if (!strcmp(uval, "ft")) /* Feet */
3782 return (number * 72.0 * 12.0);
3783 else if (!strcmp(uval, "m")) /* Meters */
3784 return (number * 72.0 / 0.0254);
3785 else /* Points */
3786 return (number);
3787 }
3788
3789
3790 /*
3791 * 'match_string()' - Return the number of matching characters.
3792 */
3793
3794 static int /* O - Number of matching characters */
3795 match_string(const char *a, /* I - First string */
3796 const char *b) /* I - Second string */
3797 {
3798 int count; /* Number of matching characters */
3799
3800
3801 /*
3802 * Loop through both strings until we hit the end of either or we find
3803 * a non-matching character. For the purposes of comparison, we ignore
3804 * whitespace and do a case-insensitive comparison so that we have a
3805 * better chance of finding a match...
3806 */
3807
3808 for (count = 0; *a && *b; a++, b++, count ++)
3809 {
3810 /*
3811 * Skip leading whitespace characters...
3812 */
3813
3814 while (isspace(*a & 255))
3815 a ++;
3816
3817 while (isspace(*b & 255))
3818 b ++;
3819
3820 /*
3821 * Break out if we run out of characters...
3822 */
3823
3824 if (!*a || !*b)
3825 break;
3826
3827 /*
3828 * Do a case-insensitive comparison of the next two chars...
3829 */
3830
3831 if (tolower(*a & 255) != tolower(*b & 255))
3832 break;
3833 }
3834
3835 return (count);
3836 }
3837
3838
3839 /*
3840 * End of "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $".
3841 */