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