]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lpadmin.c
Greatly simplify the man page handling.
[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 usage();
673
674 if (http)
675 httpClose(http);
676
677 return (0);
678 }
679
680
681 /*
682 * 'add_printer_to_class()' - Add a printer to a class.
683 */
684
685 static int /* O - 0 on success, 1 on fail */
686 add_printer_to_class(http_t *http, /* I - Server connection */
687 char *printer, /* I - Printer to add */
688 char *pclass) /* I - Class to add to */
689 {
690 int i; /* Looping var */
691 ipp_t *request, /* IPP Request */
692 *response; /* IPP Response */
693 ipp_attribute_t *attr, /* Current attribute */
694 *members; /* Members in class */
695 char uri[HTTP_MAX_URI]; /* URI for printer/class */
696
697
698 /*
699 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
700 * attributes:
701 *
702 * attributes-charset
703 * attributes-natural-language
704 * printer-uri
705 * requesting-user-name
706 */
707
708 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
709
710 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
711 "localhost", 0, "/classes/%s", pclass);
712 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
713 "printer-uri", NULL, uri);
714 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
715 NULL, cupsUser());
716
717 /*
718 * Do the request and get back a response...
719 */
720
721 response = cupsDoRequest(http, request, "/");
722
723 /*
724 * Build a CUPS-Add-Modify-Class request, which requires the following
725 * attributes:
726 *
727 * attributes-charset
728 * attributes-natural-language
729 * printer-uri
730 * requesting-user-name
731 * member-uris
732 */
733
734 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
735
736 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
737 "printer-uri", NULL, uri);
738 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
739 NULL, cupsUser());
740
741 /*
742 * See if the printer is already in the class...
743 */
744
745 if (response != NULL &&
746 (members = ippFindAttribute(response, "member-names",
747 IPP_TAG_NAME)) != NULL)
748 for (i = 0; i < members->num_values; i ++)
749 if (_cups_strcasecmp(printer, members->values[i].string.text) == 0)
750 {
751 _cupsLangPrintf(stderr,
752 _("lpadmin: Printer %s is already a member of class "
753 "%s."), printer, pclass);
754 ippDelete(request);
755 ippDelete(response);
756 return (0);
757 }
758
759 /*
760 * OK, the printer isn't part of the class, so add it...
761 */
762
763 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
764 "localhost", 0, "/printers/%s", printer);
765
766 if (response != NULL &&
767 (members = ippFindAttribute(response, "member-uris",
768 IPP_TAG_URI)) != NULL)
769 {
770 /*
771 * Add the printer to the existing list...
772 */
773
774 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
775 "member-uris", members->num_values + 1, NULL, NULL);
776 for (i = 0; i < members->num_values; i ++)
777 attr->values[i].string.text =
778 _cupsStrAlloc(members->values[i].string.text);
779
780 attr->values[i].string.text = _cupsStrAlloc(uri);
781 }
782 else
783 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL,
784 uri);
785
786 /*
787 * Then send the request...
788 */
789
790 ippDelete(response);
791
792 ippDelete(cupsDoRequest(http, request, "/admin/"));
793 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
794 {
795 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
796
797 return (1);
798 }
799 else
800 return (0);
801 }
802
803
804 /*
805 * 'default_printer()' - Set the default printing destination.
806 */
807
808 static int /* O - 0 on success, 1 on fail */
809 default_printer(http_t *http, /* I - Server connection */
810 char *printer) /* I - Printer name */
811 {
812 ipp_t *request; /* IPP Request */
813 char uri[HTTP_MAX_URI]; /* URI for printer/class */
814
815
816 /*
817 * Build a CUPS-Set-Default request, which requires the following
818 * attributes:
819 *
820 * attributes-charset
821 * attributes-natural-language
822 * printer-uri
823 * requesting-user-name
824 */
825
826 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
827 "localhost", 0, "/printers/%s", printer);
828
829 request = ippNewRequest(IPP_OP_CUPS_SET_DEFAULT);
830
831 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
832 "printer-uri", NULL, uri);
833 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
834 NULL, cupsUser());
835
836 /*
837 * Do the request and get back a response...
838 */
839
840 ippDelete(cupsDoRequest(http, request, "/admin/"));
841
842 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
843 {
844 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
845
846 return (1);
847 }
848 else
849 return (0);
850 }
851
852
853 /*
854 * 'delete_printer()' - Delete a printer from the system...
855 */
856
857 static int /* O - 0 on success, 1 on fail */
858 delete_printer(http_t *http, /* I - Server connection */
859 char *printer) /* I - Printer to delete */
860 {
861 ipp_t *request; /* IPP Request */
862 char uri[HTTP_MAX_URI]; /* URI for printer/class */
863
864
865 /*
866 * Build a CUPS-Delete-Printer request, which requires the following
867 * attributes:
868 *
869 * attributes-charset
870 * attributes-natural-language
871 * printer-uri
872 * requesting-user-name
873 */
874
875 request = ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER);
876
877 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
878 "localhost", 0, "/printers/%s", printer);
879 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
880 "printer-uri", NULL, uri);
881 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
882 NULL, cupsUser());
883
884 /*
885 * Do the request and get back a response...
886 */
887
888 ippDelete(cupsDoRequest(http, request, "/admin/"));
889
890 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
891 {
892 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
893
894 return (1);
895 }
896 else
897 return (0);
898 }
899
900
901 /*
902 * 'delete_printer_from_class()' - Delete a printer from a class.
903 */
904
905 static int /* O - 0 on success, 1 on fail */
906 delete_printer_from_class(
907 http_t *http, /* I - Server connection */
908 char *printer, /* I - Printer to remove */
909 char *pclass) /* I - Class to remove from */
910 {
911 int i, j, k; /* Looping vars */
912 ipp_t *request, /* IPP Request */
913 *response; /* IPP Response */
914 ipp_attribute_t *attr, /* Current attribute */
915 *members; /* Members in class */
916 char uri[HTTP_MAX_URI]; /* URI for printer/class */
917
918
919 /*
920 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
921 * attributes:
922 *
923 * attributes-charset
924 * attributes-natural-language
925 * printer-uri
926 * requesting-user-name
927 */
928
929 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
930
931 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
932 "localhost", 0, "/classes/%s", pclass);
933 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
934 "printer-uri", NULL, uri);
935 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
936 NULL, cupsUser());
937
938 /*
939 * Do the request and get back a response...
940 */
941
942 if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
943 response->request.status.status_code == IPP_STATUS_ERROR_NOT_FOUND)
944 {
945 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
946
947 ippDelete(response);
948
949 return (1);
950 }
951
952 /*
953 * See if the printer is already in the class...
954 */
955
956 if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
957 {
958 _cupsLangPuts(stderr, _("lpadmin: No member names were seen."));
959
960 ippDelete(response);
961
962 return (1);
963 }
964
965 for (i = 0; i < members->num_values; i ++)
966 if (!_cups_strcasecmp(printer, members->values[i].string.text))
967 break;
968
969 if (i >= members->num_values)
970 {
971 _cupsLangPrintf(stderr,
972 _("lpadmin: Printer %s is not a member of class %s."),
973 printer, pclass);
974
975 ippDelete(response);
976
977 return (1);
978 }
979
980 if (members->num_values == 1)
981 {
982 /*
983 * Build a CUPS-Delete-Class request, which requires the following
984 * attributes:
985 *
986 * attributes-charset
987 * attributes-natural-language
988 * printer-uri
989 * requesting-user-name
990 */
991
992 request = ippNewRequest(IPP_OP_CUPS_DELETE_CLASS);
993
994 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
995 "printer-uri", NULL, uri);
996 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
997 "requesting-user-name", NULL, cupsUser());
998 }
999 else
1000 {
1001 /*
1002 * Build a IPP_OP_CUPS_ADD_MODIFY_CLASS request, which requires the following
1003 * attributes:
1004 *
1005 * attributes-charset
1006 * attributes-natural-language
1007 * printer-uri
1008 * requesting-user-name
1009 * member-uris
1010 */
1011
1012 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1013
1014 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1015 "printer-uri", NULL, uri);
1016 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1017 "requesting-user-name", NULL, cupsUser());
1018
1019 /*
1020 * Delete the printer from the class...
1021 */
1022
1023 members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
1024 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
1025 "member-uris", members->num_values - 1, NULL, NULL);
1026
1027 for (j = 0, k = 0; j < members->num_values; j ++)
1028 if (j != i)
1029 attr->values[k ++].string.text =
1030 _cupsStrAlloc(members->values[j].string.text);
1031 }
1032
1033 /*
1034 * Then send the request...
1035 */
1036
1037 ippDelete(response);
1038
1039 ippDelete(cupsDoRequest(http, request, "/admin/"));
1040
1041 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1042 {
1043 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1044
1045 return (1);
1046 }
1047 else
1048 return (0);
1049 }
1050
1051
1052 /*
1053 * 'delete_printer_option()' - Delete a printer option.
1054 */
1055
1056 static int /* O - 0 on success, 1 on fail */
1057 delete_printer_option(http_t *http, /* I - Server connection */
1058 char *printer, /* I - Printer */
1059 char *option) /* I - Option to delete */
1060 {
1061 ipp_t *request; /* IPP request */
1062 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1063
1064
1065 /*
1066 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
1067 * requires the following attributes:
1068 *
1069 * attributes-charset
1070 * attributes-natural-language
1071 * printer-uri
1072 * requesting-user-name
1073 * option with deleteAttr tag
1074 */
1075
1076 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
1077 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1078 else
1079 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
1080
1081 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1082 "printer-uri", NULL, uri);
1083 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1084 "requesting-user-name", NULL, cupsUser());
1085 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_DELETEATTR, option, 0);
1086
1087 /*
1088 * Do the request and get back a response...
1089 */
1090
1091 ippDelete(cupsDoRequest(http, request, "/admin/"));
1092
1093 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1094 {
1095 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1096
1097 return (1);
1098 }
1099 else
1100 return (0);
1101 }
1102
1103
1104 /*
1105 * 'enable_printer()' - Enable a printer...
1106 */
1107
1108 static int /* O - 0 on success, 1 on fail */
1109 enable_printer(http_t *http, /* I - Server connection */
1110 char *printer) /* I - Printer to enable */
1111 {
1112 ipp_t *request; /* IPP Request */
1113 char uri[HTTP_MAX_URI]; /* URI for printer/class */
1114
1115
1116 /*
1117 * Send IPP_OP_ENABLE_PRINTER and IPP_OP_RESUME_PRINTER requests, which
1118 * require the following attributes:
1119 *
1120 * attributes-charset
1121 * attributes-natural-language
1122 * printer-uri
1123 * requesting-user-name
1124 */
1125
1126 request = ippNewRequest(IPP_OP_ENABLE_PRINTER);
1127
1128 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer);
1129 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1130 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
1131
1132 ippDelete(cupsDoRequest(http, request, "/admin/"));
1133
1134 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1135 {
1136 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1137
1138 return (1);
1139 }
1140
1141 request = ippNewRequest(IPP_OP_RESUME_PRINTER);
1142
1143 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1144 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
1145
1146 ippDelete(cupsDoRequest(http, request, "/admin/"));
1147
1148 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1149 {
1150 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1151
1152 return (1);
1153 }
1154
1155 return (0);
1156 }
1157
1158
1159 /*
1160 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
1161 */
1162
1163 static char * /* O - Filename or NULL */
1164 get_printer_ppd(
1165 const char *uri, /* I - Printer URI */
1166 char *buffer, /* I - Filename buffer */
1167 size_t bufsize, /* I - Size of filename buffer */
1168 int *num_options, /* IO - Number of options */
1169 cups_option_t **options) /* IO - Options */
1170 {
1171 http_t *http; /* Connection to printer */
1172 ipp_t *request, /* Get-Printer-Attributes request */
1173 *response; /* Get-Printer-Attributes response */
1174 ipp_attribute_t *attr; /* Attribute from response */
1175 char resolved[1024], /* Resolved URI */
1176 scheme[32], /* URI scheme */
1177 userpass[256], /* Username:password */
1178 host[256], /* Hostname */
1179 resource[256]; /* Resource path */
1180 int port; /* Port number */
1181 static const char * const pattrs[] = /* Attributes to use */
1182 {
1183 "all",
1184 "media-col-database"
1185 };
1186
1187
1188 /*
1189 * Connect to the printer...
1190 */
1191
1192 if (strstr(uri, "._tcp"))
1193 {
1194 /*
1195 * Resolve URI...
1196 */
1197
1198 if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
1199 {
1200 _cupsLangPrintf(stderr, _("%s: Unable to resolve \"%s\"."), "lpadmin", uri);
1201 return (NULL);
1202 }
1203
1204 uri = resolved;
1205 }
1206
1207 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
1208 {
1209 _cupsLangPrintf(stderr, _("%s: Bad printer URI \"%s\"."), "lpadmin", uri);
1210 return (NULL);
1211 }
1212
1213 http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
1214 if (!http)
1215 {
1216 _cupsLangPrintf(stderr, _("%s: Unable to connect to \"%s:%d\": %s"), "lpadmin", host, port, cupsLastErrorString());
1217 return (NULL);
1218 }
1219
1220 /*
1221 * Send a Get-Printer-Attributes request...
1222 */
1223
1224 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1225 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1226 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
1227 response = cupsDoRequest(http, request, resource);
1228
1229 if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
1230 {
1231 _cupsLangPrintf(stderr, _("%s: Unable to query printer: %s"), "lpadmin", cupsLastErrorString());
1232 buffer[0] = '\0';
1233 }
1234 else if (_ppdCreateFromIPP(buffer, bufsize, response))
1235 {
1236 if (!cupsGetOption("printer-geo-location", *num_options, *options) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL)
1237 *num_options = cupsAddOption("printer-geo-location", ippGetString(attr, 0, NULL), *num_options, options);
1238
1239 if (!cupsGetOption("printer-info", *num_options, *options) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL)
1240 *num_options = cupsAddOption("printer-info", ippGetString(attr, 0, NULL), *num_options, options);
1241
1242 if (!cupsGetOption("printer-location", *num_options, *options) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL)
1243 *num_options = cupsAddOption("printer-location", ippGetString(attr, 0, NULL), *num_options, options);
1244 }
1245 else
1246 _cupsLangPrintf(stderr, _("%s: Unable to create PPD file: %s"), "lpadmin", strerror(errno));
1247
1248 ippDelete(response);
1249 httpClose(http);
1250
1251 if (buffer[0])
1252 return (buffer);
1253 else
1254 return (NULL);
1255 }
1256
1257
1258 /*
1259 * 'get_printer_type()' - Determine the printer type and URI.
1260 */
1261
1262 static cups_ptype_t /* O - printer-type value */
1263 get_printer_type(http_t *http, /* I - Server connection */
1264 char *printer, /* I - Printer name */
1265 char *uri, /* I - URI buffer */
1266 size_t urisize) /* I - Size of URI buffer */
1267 {
1268 ipp_t *request, /* IPP request */
1269 *response; /* IPP response */
1270 ipp_attribute_t *attr; /* printer-type attribute */
1271 cups_ptype_t type; /* printer-type value */
1272
1273
1274 /*
1275 * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
1276 * attributes:
1277 *
1278 * attributes-charset
1279 * attributes-natural-language
1280 * printer-uri
1281 * requested-attributes
1282 * requesting-user-name
1283 */
1284
1285 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer);
1286
1287 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1288 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1289 "printer-uri", NULL, uri);
1290 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1291 "requested-attributes", NULL, "printer-type");
1292 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1293 "requesting-user-name", NULL, cupsUser());
1294
1295 /*
1296 * Do the request...
1297 */
1298
1299 response = cupsDoRequest(http, request, "/");
1300 if ((attr = ippFindAttribute(response, "printer-type",
1301 IPP_TAG_ENUM)) != NULL)
1302 {
1303 type = (cups_ptype_t)attr->values[0].integer;
1304
1305 if (type & CUPS_PRINTER_CLASS)
1306 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/classes/%s", printer);
1307 }
1308 else
1309 type = CUPS_PRINTER_LOCAL;
1310
1311 ippDelete(response);
1312
1313 return (type);
1314 }
1315
1316
1317 /*
1318 * 'set_printer_options()' - Set the printer options.
1319 */
1320
1321 static int /* O - 0 on success, 1 on fail */
1322 set_printer_options(
1323 http_t *http, /* I - Server connection */
1324 char *printer, /* I - Printer */
1325 int num_options, /* I - Number of options */
1326 cups_option_t *options, /* I - Options */
1327 char *file, /* I - PPD file */
1328 int enable) /* I - Enable printer? */
1329 {
1330 ipp_t *request; /* IPP Request */
1331 const char *ppdfile; /* PPD filename */
1332 int ppdchanged = 0; /* PPD changed? */
1333 ppd_file_t *ppd; /* PPD file */
1334 ppd_choice_t *choice; /* Marked choice */
1335 char uri[HTTP_MAX_URI], /* URI for printer/class */
1336 line[1024], /* Line from PPD file */
1337 keyword[1024], /* Keyword from Default line */
1338 *keyptr, /* Pointer into keyword... */
1339 tempfile[1024]; /* Temporary filename */
1340 cups_file_t *in, /* PPD file */
1341 *out; /* Temporary file */
1342 const char *ppdname, /* ppd-name value */
1343 *protocol, /* Old protocol option */
1344 *customval, /* Custom option value */
1345 *boolval; /* Boolean value */
1346 int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */
1347 wrote_snmp_supplies = 0,/* Wrote cupsSNMPSupplies keyword? */
1348 copied_options = 0; /* Copied options? */
1349
1350
1351 /*
1352 * Build a CUPS-Add-Modify-Printer or CUPS-Add-Modify-Class request,
1353 * which requires the following attributes:
1354 *
1355 * attributes-charset
1356 * attributes-natural-language
1357 * printer-uri
1358 * requesting-user-name
1359 * other options
1360 */
1361
1362 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
1363 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1364 else
1365 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
1366
1367 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1368 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
1369
1370 /*
1371 * Add the options...
1372 */
1373
1374 if (file)
1375 ppdfile = file;
1376 else if ((ppdname = cupsGetOption("ppd-name", num_options, options)) != NULL && strcmp(ppdname, "raw") && num_options > 1)
1377 {
1378 if ((ppdfile = cupsGetServerPPD(http, ppdname)) != NULL)
1379 {
1380 /*
1381 * Copy options array and remove ppd-name from it...
1382 */
1383
1384 cups_option_t *temp = NULL, *optr;
1385 int i, num_temp = 0;
1386 for (i = num_options, optr = options; i > 0; i --, optr ++)
1387 if (strcmp(optr->name, "ppd-name"))
1388 num_temp = cupsAddOption(optr->name, optr->value, num_temp, &temp);
1389
1390 copied_options = 1;
1391 ppdchanged = 1;
1392 num_options = num_temp;
1393 options = temp;
1394 }
1395 }
1396 else if (request->request.op.operation_id == IPP_OP_CUPS_ADD_MODIFY_PRINTER)
1397 ppdfile = cupsGetPPD(printer);
1398 else
1399 ppdfile = NULL;
1400
1401 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
1402
1403 if (enable)
1404 {
1405 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PSTATE_IDLE);
1406 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1407 }
1408
1409 cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER);
1410
1411 if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL)
1412 {
1413 if (!_cups_strcasecmp(protocol, "bcp"))
1414 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1415 NULL, "bcp");
1416 else if (!_cups_strcasecmp(protocol, "tbcp"))
1417 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1418 NULL, "tbcp");
1419 }
1420
1421 if (ppdfile)
1422 {
1423 /*
1424 * Set default options in the PPD file...
1425 */
1426
1427 if ((ppd = ppdOpenFile(ppdfile)) == NULL)
1428 {
1429 int linenum; /* Line number of error */
1430 ppd_status_t status = ppdLastError(&linenum);
1431 /* Status code */
1432
1433 _cupsLangPrintf(stderr, _("lpadmin: Unable to open PPD \"%s\": %s on line %d."), ppdfile, ppdErrorString(status), linenum);
1434 return (1);
1435 }
1436
1437 ppdMarkDefaults(ppd);
1438 cupsMarkOptions(ppd, num_options, options);
1439
1440 if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
1441 {
1442 _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file"));
1443 ippDelete(request);
1444 if (ppdfile != file)
1445 unlink(ppdfile);
1446 if (copied_options)
1447 cupsFreeOptions(num_options, options);
1448 return (1);
1449 }
1450
1451 if ((in = cupsFileOpen(ppdfile, "r")) == NULL)
1452 {
1453 _cupsLangPrintf(stderr, _("lpadmin: Unable to open PPD \"%s\": %s"), ppdfile, strerror(errno));
1454 ippDelete(request);
1455 if (ppdfile != file)
1456 unlink(ppdfile);
1457 if (copied_options)
1458 cupsFreeOptions(num_options, options);
1459 cupsFileClose(out);
1460 unlink(tempfile);
1461 return (1);
1462 }
1463
1464 while (cupsFileGets(in, line, sizeof(line)))
1465 {
1466 if (!strncmp(line, "*cupsIPPSupplies:", 17) &&
1467 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1468 options)) != NULL)
1469 {
1470 wrote_ipp_supplies = 1;
1471 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1472 (!_cups_strcasecmp(boolval, "true") ||
1473 !_cups_strcasecmp(boolval, "yes") ||
1474 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1475 }
1476 else if (!strncmp(line, "*cupsSNMPSupplies:", 18) &&
1477 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1478 options)) != NULL)
1479 {
1480 wrote_snmp_supplies = 1;
1481 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1482 (!_cups_strcasecmp(boolval, "true") ||
1483 !_cups_strcasecmp(boolval, "yes") ||
1484 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1485 }
1486 else if (strncmp(line, "*Default", 8))
1487 cupsFilePrintf(out, "%s\n", line);
1488 else
1489 {
1490 /*
1491 * Get default option name...
1492 */
1493
1494 strlcpy(keyword, line + 8, sizeof(keyword));
1495
1496 for (keyptr = keyword; *keyptr; keyptr ++)
1497 if (*keyptr == ':' || isspace(*keyptr & 255))
1498 break;
1499
1500 *keyptr++ = '\0';
1501 while (isspace(*keyptr & 255))
1502 keyptr ++;
1503
1504 if (!strcmp(keyword, "PageRegion") ||
1505 !strcmp(keyword, "PageSize") ||
1506 !strcmp(keyword, "PaperDimension") ||
1507 !strcmp(keyword, "ImageableArea"))
1508 {
1509 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL)
1510 choice = ppdFindMarkedChoice(ppd, "PageRegion");
1511 }
1512 else
1513 choice = ppdFindMarkedChoice(ppd, keyword);
1514
1515 if (choice && strcmp(choice->choice, keyptr))
1516 {
1517 if (strcmp(choice->choice, "Custom"))
1518 {
1519 cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice);
1520 ppdchanged = 1;
1521 }
1522 else if ((customval = cupsGetOption(keyword, num_options,
1523 options)) != NULL)
1524 {
1525 cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval);
1526 ppdchanged = 1;
1527 }
1528 else
1529 cupsFilePrintf(out, "%s\n", line);
1530 }
1531 else
1532 cupsFilePrintf(out, "%s\n", line);
1533 }
1534 }
1535
1536 if (!wrote_ipp_supplies &&
1537 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1538 options)) != NULL)
1539 {
1540 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1541 (!_cups_strcasecmp(boolval, "true") ||
1542 !_cups_strcasecmp(boolval, "yes") ||
1543 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1544 }
1545
1546 if (!wrote_snmp_supplies &&
1547 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1548 options)) != NULL)
1549 {
1550 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1551 (!_cups_strcasecmp(boolval, "true") ||
1552 !_cups_strcasecmp(boolval, "yes") ||
1553 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1554 }
1555
1556 cupsFileClose(in);
1557 cupsFileClose(out);
1558 ppdClose(ppd);
1559
1560 /*
1561 * Do the request...
1562 */
1563
1564 ippDelete(cupsDoFileRequest(http, request, "/admin/",
1565 ppdchanged ? tempfile : file));
1566
1567 /*
1568 * Clean up temp files... (TODO: catch signals in case we CTRL-C during
1569 * lpadmin)
1570 */
1571
1572 if (ppdfile != file)
1573 unlink(ppdfile);
1574 unlink(tempfile);
1575 }
1576 else
1577 {
1578 /*
1579 * No PPD file - just set the options...
1580 */
1581
1582 ippDelete(cupsDoRequest(http, request, "/admin/"));
1583 }
1584
1585 if (copied_options)
1586 cupsFreeOptions(num_options, options);
1587
1588 /*
1589 * Check the response...
1590 */
1591
1592 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1593 {
1594 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1595
1596 return (1);
1597 }
1598 else
1599 return (0);
1600 }
1601
1602
1603 /*
1604 * 'usage()' - Show program usage and exit.
1605 */
1606
1607 static void
1608 usage(void)
1609 {
1610 _cupsLangPuts(stdout, _("Usage: lpadmin [options] -d destination\n"
1611 " lpadmin [options] -p destination\n"
1612 " lpadmin [options] -p destination -c class\n"
1613 " lpadmin [options] -p destination -r class\n"
1614 " lpadmin [options] -x destination"));
1615 _cupsLangPuts(stdout, _("Options:"));
1616 _cupsLangPuts(stdout, _("-c class Add the named destination to a class"));
1617 _cupsLangPuts(stdout, _("-d destination Set the named destination as the server default"));
1618 _cupsLangPuts(stdout, _("-D description Specify the textual description of the printer"));
1619 _cupsLangPuts(stdout, _("-E Encrypt the connection to the server"));
1620 _cupsLangPuts(stdout, _("-E Enable and accept jobs on the printer (after -p)"));
1621 _cupsLangPuts(stdout, _("-h server[:port] Connect to the named server and port"));
1622 _cupsLangPuts(stdout, _("-i ppd-file Specify a PPD file for the printer"));
1623 _cupsLangPuts(stdout, _("-L location Specify the textual location of the printer"));
1624 _cupsLangPuts(stdout, _("-m model Specify a standard model/PPD file for the printer"));
1625 _cupsLangPuts(stdout, _("-m everywhere Specify the printer is compatible with IPP Everywhere"));
1626 _cupsLangPuts(stdout, _("-o name-default=value Specify the default value for the named option"));
1627 _cupsLangPuts(stdout, _("-o Name=Value Specify the default value for the named PPD option "));
1628 _cupsLangPuts(stdout, _("-o cupsIPPSupplies=false\n"
1629 " Disable supply level reporting via IPP"));
1630 _cupsLangPuts(stdout, _("-o cupsSNMPSupplies=false\n"
1631 " Disable supply level reporting via SNMP"));
1632 _cupsLangPuts(stdout, _("-o job-k-limit=N Specify the kilobyte limit for per-user quotas"));
1633 _cupsLangPuts(stdout, _("-o job-page-limit=N Specify the page limit for per-user quotas"));
1634 _cupsLangPuts(stdout, _("-o job-quota-period=N Specify the per-user quota period in seconds"));
1635 _cupsLangPuts(stdout, _("-o printer-error-policy=name\n"
1636 " Specify the printer error policy"));
1637 _cupsLangPuts(stdout, _("-o printer-is-shared=true\n"
1638 " Share the printer"));
1639 _cupsLangPuts(stdout, _("-o printer-op-policy=name\n"
1640 " Specify the printer operation policy"));
1641 _cupsLangPuts(stdout, _("-p destination Specify/add the named destination"));
1642 _cupsLangPuts(stdout, _("-r class Remove the named destination from a class"));
1643 _cupsLangPuts(stdout, _("-R name-default Remove the default value for the named option"));
1644 _cupsLangPuts(stdout, _("-u allow:all Allow all users to print"));
1645 _cupsLangPuts(stdout, _("-u allow:list Allow the list of users or groups (@name) to print"));
1646 _cupsLangPuts(stdout, _("-u deny:list Prevent the list of users or groups (@name) to print"));
1647 _cupsLangPuts(stdout, _("-U username Specify the username to use for authentication"));
1648 _cupsLangPuts(stdout, _("-v device-uri Specify the device URI for the printer"));
1649 _cupsLangPuts(stdout, _("-x destination Remove the named destination"));
1650
1651 exit(1);
1652 }
1653
1654
1655 /*
1656 * 'validate_name()' - Make sure the printer name only contains valid chars.
1657 */
1658
1659 static int /* O - 0 if name is no good, 1 if name is good */
1660 validate_name(const char *name) /* I - Name to check */
1661 {
1662 const char *ptr; /* Pointer into name */
1663
1664
1665 /*
1666 * Scan the whole name...
1667 */
1668
1669 for (ptr = name; *ptr; ptr ++)
1670 if (*ptr == '@')
1671 break;
1672 else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '\\' || *ptr == '?' || *ptr == '\'' || *ptr == '\"' || *ptr == '#')
1673 return (0);
1674
1675 /*
1676 * All the characters are good; validate the length, too...
1677 */
1678
1679 return ((ptr - name) < 128);
1680 }