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