]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lpadmin.c
Fully deprecate PPD API - no more _PPD_DEPRECATED cheat.
[thirdparty/cups.git] / systemv / lpadmin.c
1 /*
2 * "lpadmin" command for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 */
9
10 /*
11 * Include necessary headers...
12 */
13
14 #include <cups/cups-private.h>
15 #include <cups/ppd-private.h>
16
17
18 /*
19 * Local functions...
20 */
21
22 static int add_printer_to_class(http_t *http, char *printer, char *pclass);
23 static int default_printer(http_t *http, char *printer);
24 static int delete_printer(http_t *http, char *printer);
25 static int delete_printer_from_class(http_t *http, char *printer,
26 char *pclass);
27 static int delete_printer_option(http_t *http, char *printer,
28 char *option);
29 static int enable_printer(http_t *http, char *printer);
30 static char *get_printer_ppd(const char *uri, char *buffer, size_t bufsize, int *num_options, cups_option_t **options);
31 static cups_ptype_t get_printer_type(http_t *http, char *printer, char *uri,
32 size_t urisize);
33 static int set_printer_options(http_t *http, char *printer,
34 int num_options, cups_option_t *options,
35 char *file);
36 static int validate_name(const char *name);
37
38
39 /*
40 * 'main()' - Parse options and configure the scheduler.
41 */
42
43 int /* O - Exit status */
44 main(int argc, /* I - Number of command-line arguments */
45 char *argv[]) /* I - Command-line arguments */
46 {
47 int i; /* Looping var */
48 http_t *http; /* Connection to server */
49 char *printer, /* Destination printer */
50 *pclass, /* Printer class name */
51 *opt, /* Option pointer */
52 *val; /* Pointer to allow/deny value */
53 int num_options; /* Number of options */
54 cups_option_t *options; /* Options */
55 char *file, /* New PPD file */
56 evefile[1024] = ""; /* IPP Everywhere PPD */
57 const char *ppd_name, /* ppd-name value */
58 *device_uri; /* device-uri value */
59
60
61 _cupsSetLocale(argv);
62
63 http = NULL;
64 printer = NULL;
65 num_options = 0;
66 options = NULL;
67 file = NULL;
68
69 for (i = 1; i < argc; i ++)
70 {
71 if (argv[i][0] == '-')
72 {
73 for (opt = argv[i] + 1; *opt; opt ++)
74 {
75 switch (*opt)
76 {
77 case 'c' : /* Add printer to class */
78 if (!http)
79 {
80 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
81
82 if (http == NULL)
83 {
84 _cupsLangPrintf(stderr, _("lpadmin: Unable to connect to server: %s"), strerror(errno));
85 return (1);
86 }
87 }
88
89 if (printer == NULL)
90 {
91 _cupsLangPuts(stderr,
92 _("lpadmin: Unable to add a printer to the class:\n"
93 " You must specify a printer name first."));
94 return (1);
95 }
96
97 if (opt[1] != '\0')
98 {
99 pclass = opt + 1;
100 opt += strlen(opt) - 1;
101 }
102 else
103 {
104 i ++;
105
106 if (i >= argc)
107 {
108 _cupsLangPuts(stderr, _("lpadmin: Expected class name after \"-c\" option."));
109 return (1);
110 }
111
112 pclass = argv[i];
113 }
114
115 if (!validate_name(pclass))
116 {
117 _cupsLangPuts(stderr,
118 _("lpadmin: Class name can only contain printable "
119 "characters."));
120 return (1);
121 }
122
123 if (add_printer_to_class(http, printer, pclass))
124 return (1);
125 break;
126
127 case 'd' : /* Set as default destination */
128 if (!http)
129 {
130 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
131
132 if (http == NULL)
133 {
134 _cupsLangPrintf(stderr, _("lpadmin: Unable to connect to server: %s"), strerror(errno));
135 return (1);
136 }
137 }
138
139 if (opt[1] != '\0')
140 {
141 printer = opt + 1;
142 opt += strlen(opt) - 1;
143 }
144 else
145 {
146 i ++;
147
148 if (i >= argc)
149 {
150 _cupsLangPuts(stderr, _("lpadmin: Expected printer name after \"-d\" option."));
151 return (1);
152 }
153
154 printer = argv[i];
155 }
156
157 if (!validate_name(printer))
158 {
159 _cupsLangPuts(stderr, _("lpadmin: Printer name can only contain printable characters."));
160 return (1);
161 }
162
163 if (default_printer(http, printer))
164 return (1);
165
166 i = argc;
167 break;
168
169 case 'h' : /* Connect to host */
170 if (http)
171 {
172 httpClose(http);
173 http = NULL;
174 }
175
176 if (opt[1] != '\0')
177 {
178 cupsSetServer(opt + 1);
179 opt += strlen(opt) - 1;
180 }
181 else
182 {
183 i ++;
184
185 if (i >= argc)
186 {
187 _cupsLangPuts(stderr, _("lpadmin: Expected hostname after \"-h\" option."));
188 return (1);
189 }
190
191 cupsSetServer(argv[i]);
192 }
193 break;
194
195 case 'P' : /* Use the specified PPD file */
196 case 'i' : /* Use the specified PPD file */
197 if (opt[1] != '\0')
198 {
199 file = opt + 1;
200 opt += strlen(opt) - 1;
201 }
202 else
203 {
204 i ++;
205
206 if (i >= argc)
207 {
208 _cupsLangPrintf(stderr, _("lpadmin: Expected PPD after \"-%c\" option."), argv[i - 1][1]);
209 return (1);
210 }
211
212 file = argv[i];
213 }
214
215 if (*opt == 'i')
216 {
217 /*
218 * Check to see that the specified file is, in fact, a PPD...
219 */
220
221 cups_file_t *fp = cupsFileOpen(file, "r");
222 char line[256];
223
224 if (!cupsFileGets(fp, line, sizeof(line)) || strncmp(line, "*PPD-Adobe", 10))
225 {
226 _cupsLangPuts(stderr, _("lpadmin: System V interface scripts are no longer supported for security reasons."));
227 cupsFileClose(fp);
228 return (1);
229 }
230
231 cupsFileClose(fp);
232 }
233 break;
234
235 case 'E' : /* Enable the printer/enable encryption */
236 if (printer == NULL)
237 {
238 #ifdef HAVE_SSL
239 cupsSetEncryption(HTTP_ENCRYPTION_REQUIRED);
240
241 if (http)
242 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
243 #else
244 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
245 #endif /* HAVE_SSL */
246 break;
247 }
248
249 if (!http)
250 {
251 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
252
253 if (http == NULL)
254 {
255 _cupsLangPrintf(stderr,
256 _("lpadmin: Unable to connect to server: %s"),
257 strerror(errno));
258 return (1);
259 }
260 }
261
262 if (enable_printer(http, printer))
263 return (1);
264 break;
265
266 case 'm' : /* Use the specified standard script/PPD file */
267 if (opt[1] != '\0')
268 {
269 num_options = cupsAddOption("ppd-name", opt + 1, num_options, &options);
270 opt += strlen(opt) - 1;
271 }
272 else
273 {
274 i ++;
275
276 if (i >= argc)
277 {
278 _cupsLangPuts(stderr, _("lpadmin: Expected model after \"-m\" option."));
279 return (1);
280 }
281
282 num_options = cupsAddOption("ppd-name", argv[i], num_options, &options);
283 }
284 break;
285
286 case 'o' : /* Set option */
287 if (opt[1] != '\0')
288 {
289 num_options = cupsParseOptions(opt + 1, num_options, &options);
290 opt += strlen(opt) - 1;
291 }
292 else
293 {
294 i ++;
295
296 if (i >= argc)
297 {
298 _cupsLangPuts(stderr, _("lpadmin: Expected name=value after \"-o\" option."));
299 return (1);
300 }
301
302 num_options = cupsParseOptions(argv[i], num_options, &options);
303 }
304 break;
305
306 case 'p' : /* Add/modify a printer */
307 if (opt[1] != '\0')
308 {
309 printer = opt + 1;
310 opt += strlen(opt) - 1;
311 }
312 else
313 {
314 i ++;
315
316 if (i >= argc)
317 {
318 _cupsLangPuts(stderr, _("lpadmin: Expected printer after \"-p\" option."));
319 return (1);
320 }
321
322 printer = argv[i];
323 }
324
325 if (!validate_name(printer))
326 {
327 _cupsLangPuts(stderr, _("lpadmin: Printer name can only contain printable characters."));
328 return (1);
329 }
330 break;
331
332 case 'r' : /* Remove printer from class */
333 if (!http)
334 {
335 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
336
337 if (http == NULL)
338 {
339 _cupsLangPrintf(stderr,
340 _("lpadmin: Unable to connect to server: %s"),
341 strerror(errno));
342 return (1);
343 }
344 }
345
346 if (printer == NULL)
347 {
348 _cupsLangPuts(stderr,
349 _("lpadmin: Unable to remove a printer from the class:\n"
350 " You must specify a printer name first."));
351 return (1);
352 }
353
354 if (opt[1] != '\0')
355 {
356 pclass = opt + 1;
357 opt += strlen(opt) - 1;
358 }
359 else
360 {
361 i ++;
362
363 if (i >= argc)
364 {
365 _cupsLangPuts(stderr, _("lpadmin: Expected class after \"-r\" option."));
366 return (1);
367 }
368
369 pclass = argv[i];
370 }
371
372 if (!validate_name(pclass))
373 {
374 _cupsLangPuts(stderr, _("lpadmin: Class name can only contain printable characters."));
375 return (1);
376 }
377
378 if (delete_printer_from_class(http, printer, pclass))
379 return (1);
380 break;
381
382 case 'R' : /* Remove option */
383 if (!http)
384 {
385 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
386
387 if (http == NULL)
388 {
389 _cupsLangPrintf(stderr, _("lpadmin: Unable to connect to server: %s"), strerror(errno));
390 return (1);
391 }
392 }
393
394 if (printer == NULL)
395 {
396 _cupsLangPuts(stderr,
397 _("lpadmin: Unable to delete option:\n"
398 " You must specify a printer name first."));
399 return (1);
400 }
401
402 if (opt[1] != '\0')
403 {
404 val = opt + 1;
405 opt += strlen(opt) - 1;
406 }
407 else
408 {
409 i ++;
410
411 if (i >= argc)
412 {
413 _cupsLangPuts(stderr, _("lpadmin: Expected name after \"-R\" option."));
414 return (1);
415 }
416
417 val = argv[i];
418 }
419
420 if (delete_printer_option(http, printer, val))
421 return (1);
422 break;
423
424 case 'U' : /* Username */
425 if (opt[1] != '\0')
426 {
427 cupsSetUser(opt + 1);
428 opt += strlen(opt) - 1;
429 }
430 else
431 {
432 i ++;
433 if (i >= argc)
434 {
435 _cupsLangPrintf(stderr, _("%s: Error - expected username after \"-U\" option."), argv[0]);
436 return (1);
437 }
438
439 cupsSetUser(argv[i]);
440 }
441 break;
442
443 case 'u' : /* Allow/deny users */
444 if (opt[1] != '\0')
445 {
446 val = opt + 1;
447 opt += strlen(opt) - 1;
448 }
449 else
450 {
451 i ++;
452
453 if (i >= argc)
454 {
455 _cupsLangPuts(stderr, _("lpadmin: Expected allow/deny:userlist after \"-u\" option."));
456 return (1);
457 }
458
459 val = argv[i];
460 }
461
462 if (!_cups_strncasecmp(val, "allow:", 6))
463 num_options = cupsAddOption("requesting-user-name-allowed", val + 6, num_options, &options);
464 else if (!_cups_strncasecmp(val, "deny:", 5))
465 num_options = cupsAddOption("requesting-user-name-denied", val + 5, num_options, &options);
466 else
467 {
468 _cupsLangPrintf(stderr, _("lpadmin: Unknown allow/deny option \"%s\"."), val);
469 return (1);
470 }
471 break;
472
473 case 'v' : /* Set the device-uri attribute */
474 if (opt[1] != '\0')
475 {
476 num_options = cupsAddOption("device-uri", opt + 1, num_options, &options);
477 opt += strlen(opt) - 1;
478 }
479 else
480 {
481 i ++;
482
483 if (i >= argc)
484 {
485 _cupsLangPuts(stderr, _("lpadmin: Expected device URI after \"-v\" option."));
486 return (1);
487 }
488
489 num_options = cupsAddOption("device-uri", argv[i], num_options, &options);
490 }
491 break;
492
493 case 'x' : /* Delete a printer */
494 if (!http)
495 {
496 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL);
497
498 if (http == NULL)
499 {
500 _cupsLangPrintf(stderr,
501 _("lpadmin: Unable to connect to server: %s"),
502 strerror(errno));
503 return (1);
504 }
505 }
506
507 if (opt[1] != '\0')
508 {
509 printer = opt + 1;
510 opt += strlen(opt) - 1;
511 }
512 else
513 {
514 i ++;
515
516 if (i >= argc)
517 {
518 _cupsLangPuts(stderr, _("lpadmin: Expected printer or class after \"-x\" option."));
519 return (1);
520 }
521
522 printer = argv[i];
523 }
524
525 if (!validate_name(printer))
526 {
527 _cupsLangPuts(stderr, _("lpadmin: Printer name can only contain printable characters."));
528 return (1);
529 }
530
531 if (delete_printer(http, printer))
532 return (1);
533
534 i = argc;
535 break;
536
537 case 'D' : /* Set the printer-info attribute */
538 if (opt[1] != '\0')
539 {
540 num_options = cupsAddOption("printer-info", opt + 1, num_options, &options);
541 opt += strlen(opt) - 1;
542 }
543 else
544 {
545 i ++;
546
547 if (i >= argc)
548 {
549 _cupsLangPuts(stderr, _("lpadmin: Expected description after \"-D\" option."));
550 return (1);
551 }
552
553 num_options = cupsAddOption("printer-info", argv[i], num_options, &options);
554 }
555 break;
556
557 case 'I' : /* Set the supported file types (ignored) */
558 i ++;
559
560 if (i >= argc)
561 {
562 _cupsLangPuts(stderr, _("lpadmin: Expected file type(s) after \"-I\" option."));
563 return (1);
564 }
565
566 _cupsLangPuts(stderr, _("lpadmin: Warning - content type list ignored."));
567 break;
568
569 case 'L' : /* Set the printer-location attribute */
570 if (opt[1] != '\0')
571 {
572 num_options = cupsAddOption("printer-location", opt + 1, num_options, &options);
573 opt += strlen(opt) - 1;
574 }
575 else
576 {
577 i ++;
578
579 if (i >= argc)
580 {
581 _cupsLangPuts(stderr, _("lpadmin: Expected location after \"-L\" option."));
582 return (1);
583 }
584
585 num_options = cupsAddOption("printer-location", argv[i], num_options, &options);
586 }
587 break;
588
589 default :
590 _cupsLangPrintf(stderr, _("lpadmin: Unknown option \"%c\"."), *opt);
591 return (1);
592 }
593 }
594 }
595 else
596 {
597 _cupsLangPrintf(stderr, _("lpadmin: Unknown argument \"%s\"."), argv[i]);
598 return (1);
599 }
600 }
601
602 /*
603 * Set options as needed...
604 */
605
606 ppd_name = cupsGetOption("ppd-name", num_options, options);
607 device_uri = cupsGetOption("device-uri", num_options, options);
608
609 if (ppd_name && !strcmp(ppd_name, "raw"))
610 {
611 _cupsLangPuts(stderr, _("lpadmin: Raw queues are deprecated and will stop working in a future version of CUPS."));
612
613 if (device_uri && (!strncmp(device_uri, "ipp://", 6) || !strncmp(device_uri, "ipps://", 7)) && strstr(device_uri, "/printers/"))
614 _cupsLangPuts(stderr, _("lpadmin: Use the 'everywhere' model for shared printers."));
615 }
616 else if (ppd_name && !strcmp(ppd_name, "everywhere") && device_uri)
617 {
618 if ((file = get_printer_ppd(device_uri, evefile, sizeof(evefile), &num_options, &options)) == NULL)
619 return (1);
620
621 num_options = cupsRemoveOption("ppd-name", num_options, &options);
622 }
623 else if (ppd_name || file)
624 {
625 _cupsLangPuts(stderr, _("lpadmin: Printer drivers are deprecated and will stop working in a future version of CUPS."));
626 }
627
628 if (num_options || file)
629 {
630 if (printer == NULL)
631 {
632 _cupsLangPuts(stderr,
633 _("lpadmin: Unable to set the printer options:\n"
634 " You must specify a printer name first."));
635 return (1);
636 }
637
638 if (!http)
639 {
640 http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC,
641 cupsEncryption(), 1, 30000, NULL);
642
643 if (http == NULL) {
644 _cupsLangPrintf(stderr, _("lpadmin: Unable to connect to server: %s"),
645 strerror(errno));
646 return (1);
647 }
648 }
649
650 if (set_printer_options(http, printer, num_options, options, file))
651 return (1);
652 }
653
654 if (evefile[0])
655 unlink(evefile);
656
657 if (printer == NULL)
658 {
659 _cupsLangPuts(stdout,
660 _("Usage:\n"
661 "\n"
662 " lpadmin [-h server] -d destination\n"
663 " lpadmin [-h server] -x destination\n"
664 " lpadmin [-h server] -p printer [-c add-class] "
665 "[-i interface] [-m model]\n"
666 " [-r remove-class] [-v device] "
667 "[-D description]\n"
668 " [-P ppd-file] [-o name=value]\n"
669 " [-u allow:user,user] "
670 "[-u deny:user,user]"));
671 }
672
673 if (http)
674 httpClose(http);
675
676 return (0);
677 }
678
679
680 /*
681 * 'add_printer_to_class()' - Add a printer to a class.
682 */
683
684 static int /* O - 0 on success, 1 on fail */
685 add_printer_to_class(http_t *http, /* I - Server connection */
686 char *printer, /* I - Printer to add */
687 char *pclass) /* I - Class to add to */
688 {
689 int i; /* Looping var */
690 ipp_t *request, /* IPP Request */
691 *response; /* IPP Response */
692 ipp_attribute_t *attr, /* Current attribute */
693 *members; /* Members in class */
694 char uri[HTTP_MAX_URI]; /* URI for printer/class */
695
696
697 DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http,
698 printer, pclass));
699
700 /*
701 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
702 * attributes:
703 *
704 * attributes-charset
705 * attributes-natural-language
706 * printer-uri
707 * requesting-user-name
708 */
709
710 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
711
712 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
713 "localhost", 0, "/classes/%s", pclass);
714 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
715 "printer-uri", NULL, uri);
716 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
717 NULL, cupsUser());
718
719 /*
720 * Do the request and get back a response...
721 */
722
723 response = cupsDoRequest(http, request, "/");
724
725 /*
726 * Build a CUPS-Add-Modify-Class request, which requires the following
727 * attributes:
728 *
729 * attributes-charset
730 * attributes-natural-language
731 * printer-uri
732 * requesting-user-name
733 * member-uris
734 */
735
736 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
737
738 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
739 "printer-uri", NULL, uri);
740 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
741 NULL, cupsUser());
742
743 /*
744 * See if the printer is already in the class...
745 */
746
747 if (response != NULL &&
748 (members = ippFindAttribute(response, "member-names",
749 IPP_TAG_NAME)) != NULL)
750 for (i = 0; i < members->num_values; i ++)
751 if (_cups_strcasecmp(printer, members->values[i].string.text) == 0)
752 {
753 _cupsLangPrintf(stderr,
754 _("lpadmin: Printer %s is already a member of class "
755 "%s."), printer, pclass);
756 ippDelete(request);
757 ippDelete(response);
758 return (0);
759 }
760
761 /*
762 * OK, the printer isn't part of the class, so add it...
763 */
764
765 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
766 "localhost", 0, "/printers/%s", printer);
767
768 if (response != NULL &&
769 (members = ippFindAttribute(response, "member-uris",
770 IPP_TAG_URI)) != NULL)
771 {
772 /*
773 * Add the printer to the existing list...
774 */
775
776 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
777 "member-uris", members->num_values + 1, NULL, NULL);
778 for (i = 0; i < members->num_values; i ++)
779 attr->values[i].string.text =
780 _cupsStrAlloc(members->values[i].string.text);
781
782 attr->values[i].string.text = _cupsStrAlloc(uri);
783 }
784 else
785 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL,
786 uri);
787
788 /*
789 * Then send the request...
790 */
791
792 ippDelete(response);
793
794 ippDelete(cupsDoRequest(http, request, "/admin/"));
795 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
796 {
797 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
798
799 return (1);
800 }
801 else
802 return (0);
803 }
804
805
806 /*
807 * 'default_printer()' - Set the default printing destination.
808 */
809
810 static int /* O - 0 on success, 1 on fail */
811 default_printer(http_t *http, /* I - Server connection */
812 char *printer) /* I - Printer name */
813 {
814 ipp_t *request; /* IPP Request */
815 char uri[HTTP_MAX_URI]; /* URI for printer/class */
816
817
818 DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
819
820 /*
821 * Build a CUPS-Set-Default request, which requires the following
822 * attributes:
823 *
824 * attributes-charset
825 * attributes-natural-language
826 * printer-uri
827 * requesting-user-name
828 */
829
830 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
831 "localhost", 0, "/printers/%s", printer);
832
833 request = ippNewRequest(IPP_OP_CUPS_SET_DEFAULT);
834
835 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
836 "printer-uri", NULL, uri);
837 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
838 NULL, cupsUser());
839
840 /*
841 * Do the request and get back a response...
842 */
843
844 ippDelete(cupsDoRequest(http, request, "/admin/"));
845
846 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
847 {
848 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
849
850 return (1);
851 }
852 else
853 return (0);
854 }
855
856
857 /*
858 * 'delete_printer()' - Delete a printer from the system...
859 */
860
861 static int /* O - 0 on success, 1 on fail */
862 delete_printer(http_t *http, /* I - Server connection */
863 char *printer) /* I - Printer to delete */
864 {
865 ipp_t *request; /* IPP Request */
866 char uri[HTTP_MAX_URI]; /* URI for printer/class */
867
868
869 DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
870
871 /*
872 * Build a CUPS-Delete-Printer request, which requires the following
873 * attributes:
874 *
875 * attributes-charset
876 * attributes-natural-language
877 * printer-uri
878 * requesting-user-name
879 */
880
881 request = ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER);
882
883 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
884 "localhost", 0, "/printers/%s", printer);
885 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
886 "printer-uri", NULL, uri);
887 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
888 NULL, cupsUser());
889
890 /*
891 * Do the request and get back a response...
892 */
893
894 ippDelete(cupsDoRequest(http, request, "/admin/"));
895
896 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
897 {
898 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
899
900 return (1);
901 }
902 else
903 return (0);
904 }
905
906
907 /*
908 * 'delete_printer_from_class()' - Delete a printer from a class.
909 */
910
911 static int /* O - 0 on success, 1 on fail */
912 delete_printer_from_class(
913 http_t *http, /* I - Server connection */
914 char *printer, /* I - Printer to remove */
915 char *pclass) /* I - Class to remove from */
916 {
917 int i, j, k; /* Looping vars */
918 ipp_t *request, /* IPP Request */
919 *response; /* IPP Response */
920 ipp_attribute_t *attr, /* Current attribute */
921 *members; /* Members in class */
922 char uri[HTTP_MAX_URI]; /* URI for printer/class */
923
924
925 DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http,
926 printer, pclass));
927
928 /*
929 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
930 * attributes:
931 *
932 * attributes-charset
933 * attributes-natural-language
934 * printer-uri
935 * requesting-user-name
936 */
937
938 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
939
940 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
941 "localhost", 0, "/classes/%s", pclass);
942 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
943 "printer-uri", NULL, uri);
944 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
945 NULL, cupsUser());
946
947 /*
948 * Do the request and get back a response...
949 */
950
951 if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
952 response->request.status.status_code == IPP_STATUS_ERROR_NOT_FOUND)
953 {
954 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
955
956 ippDelete(response);
957
958 return (1);
959 }
960
961 /*
962 * See if the printer is already in the class...
963 */
964
965 if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
966 {
967 _cupsLangPuts(stderr, _("lpadmin: No member names were seen."));
968
969 ippDelete(response);
970
971 return (1);
972 }
973
974 for (i = 0; i < members->num_values; i ++)
975 if (!_cups_strcasecmp(printer, members->values[i].string.text))
976 break;
977
978 if (i >= members->num_values)
979 {
980 _cupsLangPrintf(stderr,
981 _("lpadmin: Printer %s is not a member of class %s."),
982 printer, pclass);
983
984 ippDelete(response);
985
986 return (1);
987 }
988
989 if (members->num_values == 1)
990 {
991 /*
992 * Build a CUPS-Delete-Class request, which requires the following
993 * attributes:
994 *
995 * attributes-charset
996 * attributes-natural-language
997 * printer-uri
998 * requesting-user-name
999 */
1000
1001 request = ippNewRequest(IPP_OP_CUPS_DELETE_CLASS);
1002
1003 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1004 "printer-uri", NULL, uri);
1005 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1006 "requesting-user-name", NULL, cupsUser());
1007 }
1008 else
1009 {
1010 /*
1011 * Build a IPP_OP_CUPS_ADD_MODIFY_CLASS request, which requires the following
1012 * attributes:
1013 *
1014 * attributes-charset
1015 * attributes-natural-language
1016 * printer-uri
1017 * requesting-user-name
1018 * member-uris
1019 */
1020
1021 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1022
1023 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1024 "printer-uri", NULL, uri);
1025 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1026 "requesting-user-name", NULL, cupsUser());
1027
1028 /*
1029 * Delete the printer from the class...
1030 */
1031
1032 members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
1033 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
1034 "member-uris", members->num_values - 1, NULL, NULL);
1035
1036 for (j = 0, k = 0; j < members->num_values; j ++)
1037 if (j != i)
1038 attr->values[k ++].string.text =
1039 _cupsStrAlloc(members->values[j].string.text);
1040 }
1041
1042 /*
1043 * Then send the request...
1044 */
1045
1046 ippDelete(response);
1047
1048 ippDelete(cupsDoRequest(http, request, "/admin/"));
1049
1050 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1051 {
1052 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1053
1054 return (1);
1055 }
1056 else
1057 return (0);
1058 }
1059
1060
1061 /*
1062 * 'delete_printer_option()' - Delete a printer option.
1063 */
1064
1065 static int /* O - 0 on success, 1 on fail */
1066 delete_printer_option(http_t *http, /* I - Server connection */
1067 char *printer, /* I - Printer */
1068 char *option) /* I - Option to delete */
1069 {
1070 ipp_t *request; /* IPP request */
1071 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1072
1073
1074 /*
1075 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
1076 * requires the following attributes:
1077 *
1078 * attributes-charset
1079 * attributes-natural-language
1080 * printer-uri
1081 * requesting-user-name
1082 * option with deleteAttr tag
1083 */
1084
1085 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
1086 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1087 else
1088 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
1089
1090 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1091 "printer-uri", NULL, uri);
1092 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1093 "requesting-user-name", NULL, cupsUser());
1094 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_DELETEATTR, option, 0);
1095
1096 /*
1097 * Do the request and get back a response...
1098 */
1099
1100 ippDelete(cupsDoRequest(http, request, "/admin/"));
1101
1102 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1103 {
1104 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1105
1106 return (1);
1107 }
1108 else
1109 return (0);
1110 }
1111
1112
1113 /*
1114 * 'enable_printer()' - Enable a printer...
1115 */
1116
1117 static int /* O - 0 on success, 1 on fail */
1118 enable_printer(http_t *http, /* I - Server connection */
1119 char *printer) /* I - Printer to enable */
1120 {
1121 ipp_t *request; /* IPP Request */
1122 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1123
1124
1125 DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
1126
1127 /*
1128 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
1129 * require the following attributes:
1130 *
1131 * attributes-charset
1132 * attributes-natural-language
1133 * printer-uri
1134 * requesting-user-name
1135 * printer-state
1136 * printer-is-accepting-jobs
1137 */
1138
1139 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
1140 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1141 else
1142 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
1143
1144 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1145 "printer-uri", NULL, uri);
1146 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1147 "requesting-user-name", NULL, cupsUser());
1148 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
1149 IPP_PSTATE_IDLE);
1150 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1151
1152 /*
1153 * Do the request and get back a response...
1154 */
1155
1156 ippDelete(cupsDoRequest(http, request, "/admin/"));
1157
1158 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1159 {
1160 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1161
1162 return (1);
1163 }
1164 else
1165 return (0);
1166 }
1167
1168
1169 /*
1170 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
1171 */
1172
1173 static char * /* O - Filename or NULL */
1174 get_printer_ppd(
1175 const char *uri, /* I - Printer URI */
1176 char *buffer, /* I - Filename buffer */
1177 size_t bufsize, /* I - Size of filename buffer */
1178 int *num_options, /* IO - Number of options */
1179 cups_option_t **options) /* IO - Options */
1180 {
1181 http_t *http; /* Connection to printer */
1182 ipp_t *request, /* Get-Printer-Attributes request */
1183 *response; /* Get-Printer-Attributes response */
1184 ipp_attribute_t *attr; /* Attribute from response */
1185 char resolved[1024], /* Resolved URI */
1186 scheme[32], /* URI scheme */
1187 userpass[256], /* Username:password */
1188 host[256], /* Hostname */
1189 resource[256]; /* Resource path */
1190 int port; /* Port number */
1191 static const char * const pattrs[] = /* Attributes to use */
1192 {
1193 "job-template",
1194 "printer-defaults",
1195 "printer-description",
1196 "media-col-database"
1197 };
1198
1199
1200 /*
1201 * Connect to the printer...
1202 */
1203
1204 if (strstr(uri, "._tcp"))
1205 {
1206 /*
1207 * Resolve URI...
1208 */
1209
1210 if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
1211 {
1212 _cupsLangPrintf(stderr, _("%s: Unable to resolve \"%s\"."), "lpadmin", uri);
1213 return (NULL);
1214 }
1215
1216 uri = resolved;
1217 }
1218
1219 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
1220 {
1221 _cupsLangPrintf(stderr, _("%s: Bad printer URI \"%s\"."), "lpadmin", uri);
1222 return (NULL);
1223 }
1224
1225 http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
1226 if (!http)
1227 {
1228 _cupsLangPrintf(stderr, _("%s: Unable to connect to \"%s:%d\": %s"), "lpadmin", host, port, cupsLastErrorString());
1229 return (NULL);
1230 }
1231
1232 /*
1233 * Send a Get-Printer-Attributes request...
1234 */
1235
1236 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1237 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1238 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
1239 response = cupsDoRequest(http, request, resource);
1240
1241 if (_ppdCreateFromIPP(buffer, bufsize, response))
1242 {
1243 if (!cupsGetOption("printer-geo-location", *num_options, *options) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL)
1244 *num_options = cupsAddOption("printer-geo-location", ippGetString(attr, 0, NULL), *num_options, options);
1245
1246 if (!cupsGetOption("printer-info", *num_options, *options) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL)
1247 *num_options = cupsAddOption("printer-info", ippGetString(attr, 0, NULL), *num_options, options);
1248
1249 if (!cupsGetOption("printer-location", *num_options, *options) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL)
1250 *num_options = cupsAddOption("printer-location", ippGetString(attr, 0, NULL), *num_options, options);
1251 }
1252 else
1253 _cupsLangPrintf(stderr, _("%s: Unable to create PPD file: %s"), "lpadmin", strerror(errno));
1254
1255 ippDelete(response);
1256 httpClose(http);
1257
1258 if (buffer[0])
1259 return (buffer);
1260 else
1261 return (NULL);
1262 }
1263
1264
1265 /*
1266 * 'get_printer_type()' - Determine the printer type and URI.
1267 */
1268
1269 static cups_ptype_t /* O - printer-type value */
1270 get_printer_type(http_t *http, /* I - Server connection */
1271 char *printer, /* I - Printer name */
1272 char *uri, /* I - URI buffer */
1273 size_t urisize) /* I - Size of URI buffer */
1274 {
1275 ipp_t *request, /* IPP request */
1276 *response; /* IPP response */
1277 ipp_attribute_t *attr; /* printer-type attribute */
1278 cups_ptype_t type; /* printer-type value */
1279
1280
1281 /*
1282 * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
1283 * attributes:
1284 *
1285 * attributes-charset
1286 * attributes-natural-language
1287 * printer-uri
1288 * requested-attributes
1289 * requesting-user-name
1290 */
1291
1292 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer);
1293
1294 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1295 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1296 "printer-uri", NULL, uri);
1297 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1298 "requested-attributes", NULL, "printer-type");
1299 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1300 "requesting-user-name", NULL, cupsUser());
1301
1302 /*
1303 * Do the request...
1304 */
1305
1306 response = cupsDoRequest(http, request, "/");
1307 if ((attr = ippFindAttribute(response, "printer-type",
1308 IPP_TAG_ENUM)) != NULL)
1309 {
1310 type = (cups_ptype_t)attr->values[0].integer;
1311
1312 if (type & CUPS_PRINTER_CLASS)
1313 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/classes/%s", printer);
1314 }
1315 else
1316 type = CUPS_PRINTER_LOCAL;
1317
1318 ippDelete(response);
1319
1320 return (type);
1321 }
1322
1323
1324 /*
1325 * 'set_printer_options()' - Set the printer options.
1326 */
1327
1328 static int /* O - 0 on success, 1 on fail */
1329 set_printer_options(
1330 http_t *http, /* I - Server connection */
1331 char *printer, /* I - Printer */
1332 int num_options, /* I - Number of options */
1333 cups_option_t *options, /* I - Options */
1334 char *file) /* I - PPD file/interface script */
1335 {
1336 ipp_t *request; /* IPP Request */
1337 const char *ppdfile; /* PPD filename */
1338 int ppdchanged = 0; /* PPD changed? */
1339 ppd_file_t *ppd; /* PPD file */
1340 ppd_choice_t *choice; /* Marked choice */
1341 char uri[HTTP_MAX_URI], /* URI for printer/class */
1342 line[1024], /* Line from PPD file */
1343 keyword[1024], /* Keyword from Default line */
1344 *keyptr, /* Pointer into keyword... */
1345 tempfile[1024]; /* Temporary filename */
1346 cups_file_t *in, /* PPD file */
1347 *out; /* Temporary file */
1348 const char *ppdname, /* ppd-name value */
1349 *protocol, /* Old protocol option */
1350 *customval, /* Custom option value */
1351 *boolval; /* Boolean value */
1352 int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */
1353 wrote_snmp_supplies = 0,/* Wrote cupsSNMPSupplies keyword? */
1354 copied_options = 0; /* Copied options? */
1355
1356
1357 DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, "
1358 "options=%p, file=\"%s\")\n", http, printer, num_options,
1359 options, file));
1360
1361 /*
1362 * Build a CUPS-Add-Modify-Printer or CUPS-Add-Modify-Class request,
1363 * which requires the following attributes:
1364 *
1365 * attributes-charset
1366 * attributes-natural-language
1367 * printer-uri
1368 * requesting-user-name
1369 * other options
1370 */
1371
1372 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
1373 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1374 else
1375 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
1376
1377 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1378 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
1379
1380 /*
1381 * Add the options...
1382 */
1383
1384 if (file)
1385 ppdfile = file;
1386 else if ((ppdname = cupsGetOption("ppd-name", num_options, options)) != NULL && strcmp(ppdname, "raw") && num_options > 1)
1387 {
1388 if ((ppdfile = cupsGetServerPPD(http, ppdname)) != NULL)
1389 {
1390 /*
1391 * Copy options array and remove ppd-name from it...
1392 */
1393
1394 cups_option_t *temp = NULL, *optr;
1395 int i, num_temp = 0;
1396 for (i = num_options, optr = options; i > 0; i --, optr ++)
1397 if (strcmp(optr->name, "ppd-name"))
1398 num_temp = cupsAddOption(optr->name, optr->value, num_temp, &temp);
1399
1400 copied_options = 1;
1401 ppdchanged = 1;
1402 num_options = num_temp;
1403 options = temp;
1404 }
1405 }
1406 else if (request->request.op.operation_id == IPP_OP_CUPS_ADD_MODIFY_PRINTER)
1407 ppdfile = cupsGetPPD(printer);
1408 else
1409 ppdfile = NULL;
1410
1411 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
1412 cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER);
1413
1414 if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL)
1415 {
1416 if (!_cups_strcasecmp(protocol, "bcp"))
1417 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1418 NULL, "bcp");
1419 else if (!_cups_strcasecmp(protocol, "tbcp"))
1420 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1421 NULL, "tbcp");
1422 }
1423
1424 if (ppdfile)
1425 {
1426 /*
1427 * Set default options in the PPD file...
1428 */
1429
1430 if ((ppd = ppdOpenFile(ppdfile)) == NULL)
1431 {
1432 int linenum; /* Line number of error */
1433 ppd_status_t status = ppdLastError(&linenum);
1434 /* Status code */
1435
1436 _cupsLangPrintf(stderr, _("lpadmin: Unable to open PPD \"%s\": %s on line %d."), ppdfile, ppdErrorString(status), linenum);
1437 }
1438
1439 ppdMarkDefaults(ppd);
1440 cupsMarkOptions(ppd, num_options, options);
1441
1442 if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
1443 {
1444 _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file"));
1445 ippDelete(request);
1446 if (ppdfile != file)
1447 unlink(ppdfile);
1448 if (copied_options)
1449 cupsFreeOptions(num_options, options);
1450 return (1);
1451 }
1452
1453 if ((in = cupsFileOpen(ppdfile, "r")) == NULL)
1454 {
1455 _cupsLangPrintf(stderr,
1456 _("lpadmin: Unable to open PPD file \"%s\" - %s"),
1457 ppdfile, strerror(errno));
1458 ippDelete(request);
1459 if (ppdfile != file)
1460 unlink(ppdfile);
1461 if (copied_options)
1462 cupsFreeOptions(num_options, options);
1463 cupsFileClose(out);
1464 unlink(tempfile);
1465 return (1);
1466 }
1467
1468 while (cupsFileGets(in, line, sizeof(line)))
1469 {
1470 if (!strncmp(line, "*cupsIPPSupplies:", 17) &&
1471 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1472 options)) != NULL)
1473 {
1474 wrote_ipp_supplies = 1;
1475 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1476 (!_cups_strcasecmp(boolval, "true") ||
1477 !_cups_strcasecmp(boolval, "yes") ||
1478 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1479 }
1480 else if (!strncmp(line, "*cupsSNMPSupplies:", 18) &&
1481 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1482 options)) != NULL)
1483 {
1484 wrote_snmp_supplies = 1;
1485 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1486 (!_cups_strcasecmp(boolval, "true") ||
1487 !_cups_strcasecmp(boolval, "yes") ||
1488 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1489 }
1490 else if (strncmp(line, "*Default", 8))
1491 cupsFilePrintf(out, "%s\n", line);
1492 else
1493 {
1494 /*
1495 * Get default option name...
1496 */
1497
1498 strlcpy(keyword, line + 8, sizeof(keyword));
1499
1500 for (keyptr = keyword; *keyptr; keyptr ++)
1501 if (*keyptr == ':' || isspace(*keyptr & 255))
1502 break;
1503
1504 *keyptr++ = '\0';
1505 while (isspace(*keyptr & 255))
1506 keyptr ++;
1507
1508 if (!strcmp(keyword, "PageRegion") ||
1509 !strcmp(keyword, "PageSize") ||
1510 !strcmp(keyword, "PaperDimension") ||
1511 !strcmp(keyword, "ImageableArea"))
1512 {
1513 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL)
1514 choice = ppdFindMarkedChoice(ppd, "PageRegion");
1515 }
1516 else
1517 choice = ppdFindMarkedChoice(ppd, keyword);
1518
1519 if (choice && strcmp(choice->choice, keyptr))
1520 {
1521 if (strcmp(choice->choice, "Custom"))
1522 {
1523 cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice);
1524 ppdchanged = 1;
1525 }
1526 else if ((customval = cupsGetOption(keyword, num_options,
1527 options)) != NULL)
1528 {
1529 cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval);
1530 ppdchanged = 1;
1531 }
1532 else
1533 cupsFilePrintf(out, "%s\n", line);
1534 }
1535 else
1536 cupsFilePrintf(out, "%s\n", line);
1537 }
1538 }
1539
1540 if (!wrote_ipp_supplies &&
1541 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1542 options)) != NULL)
1543 {
1544 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1545 (!_cups_strcasecmp(boolval, "true") ||
1546 !_cups_strcasecmp(boolval, "yes") ||
1547 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1548 }
1549
1550 if (!wrote_snmp_supplies &&
1551 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1552 options)) != NULL)
1553 {
1554 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1555 (!_cups_strcasecmp(boolval, "true") ||
1556 !_cups_strcasecmp(boolval, "yes") ||
1557 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1558 }
1559
1560 cupsFileClose(in);
1561 cupsFileClose(out);
1562 ppdClose(ppd);
1563
1564 /*
1565 * Do the request...
1566 */
1567
1568 ippDelete(cupsDoFileRequest(http, request, "/admin/",
1569 ppdchanged ? tempfile : file));
1570
1571 /*
1572 * Clean up temp files... (TODO: catch signals in case we CTRL-C during
1573 * lpadmin)
1574 */
1575
1576 if (ppdfile != file)
1577 unlink(ppdfile);
1578 unlink(tempfile);
1579 }
1580 else
1581 {
1582 /*
1583 * No PPD file - just set the options...
1584 */
1585
1586 ippDelete(cupsDoRequest(http, request, "/admin/"));
1587 }
1588
1589 if (copied_options)
1590 cupsFreeOptions(num_options, options);
1591
1592 /*
1593 * Check the response...
1594 */
1595
1596 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1597 {
1598 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1599
1600 return (1);
1601 }
1602 else
1603 return (0);
1604 }
1605
1606
1607 /*
1608 * 'validate_name()' - Make sure the printer name only contains valid chars.
1609 */
1610
1611 static int /* O - 0 if name is no good, 1 if name is good */
1612 validate_name(const char *name) /* I - Name to check */
1613 {
1614 const char *ptr; /* Pointer into name */
1615
1616
1617 /*
1618 * Scan the whole name...
1619 */
1620
1621 for (ptr = name; *ptr; ptr ++)
1622 if (*ptr == '@')
1623 break;
1624 else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '\\' || *ptr == '?' || *ptr == '\'' || *ptr == '\"' || *ptr == '#')
1625 return (0);
1626
1627 /*
1628 * All the characters are good; validate the length, too...
1629 */
1630
1631 return ((ptr - name) < 128);
1632 }