]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lpadmin.c
733559c2a5b7e8564a7ba2efc449b6c732c98d45
[thirdparty/cups.git] / systemv / lpadmin.c
1 /*
2 * "lpadmin" command for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
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 "job-template",
1196 "printer-defaults",
1197 "printer-description",
1198 "media-col-database"
1199 };
1200
1201
1202 /*
1203 * Connect to the printer...
1204 */
1205
1206 if (strstr(uri, "._tcp"))
1207 {
1208 /*
1209 * Resolve URI...
1210 */
1211
1212 if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
1213 {
1214 _cupsLangPrintf(stderr, _("%s: Unable to resolve \"%s\"."), "lpadmin", uri);
1215 return (NULL);
1216 }
1217
1218 uri = resolved;
1219 }
1220
1221 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
1222 {
1223 _cupsLangPrintf(stderr, _("%s: Bad printer URI \"%s\"."), "lpadmin", uri);
1224 return (NULL);
1225 }
1226
1227 http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
1228 if (!http)
1229 {
1230 _cupsLangPrintf(stderr, _("%s: Unable to connect to \"%s:%d\": %s"), "lpadmin", host, port, cupsLastErrorString());
1231 return (NULL);
1232 }
1233
1234 /*
1235 * Send a Get-Printer-Attributes request...
1236 */
1237
1238 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1239 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1240 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
1241 response = cupsDoRequest(http, request, resource);
1242
1243 if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
1244 {
1245 _cupsLangPrintf(stderr, _("%s: Unable to query printer: %s"), "lpadmin", cupsLastErrorString());
1246 buffer[0] = '\0';
1247 }
1248 else if (_ppdCreateFromIPP(buffer, bufsize, response))
1249 {
1250 if (!cupsGetOption("printer-geo-location", *num_options, *options) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL)
1251 *num_options = cupsAddOption("printer-geo-location", ippGetString(attr, 0, NULL), *num_options, options);
1252
1253 if (!cupsGetOption("printer-info", *num_options, *options) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL)
1254 *num_options = cupsAddOption("printer-info", ippGetString(attr, 0, NULL), *num_options, options);
1255
1256 if (!cupsGetOption("printer-location", *num_options, *options) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL)
1257 *num_options = cupsAddOption("printer-location", ippGetString(attr, 0, NULL), *num_options, options);
1258 }
1259 else
1260 _cupsLangPrintf(stderr, _("%s: Unable to create PPD file: %s"), "lpadmin", strerror(errno));
1261
1262 ippDelete(response);
1263 httpClose(http);
1264
1265 if (buffer[0])
1266 return (buffer);
1267 else
1268 return (NULL);
1269 }
1270
1271
1272 /*
1273 * 'get_printer_type()' - Determine the printer type and URI.
1274 */
1275
1276 static cups_ptype_t /* O - printer-type value */
1277 get_printer_type(http_t *http, /* I - Server connection */
1278 char *printer, /* I - Printer name */
1279 char *uri, /* I - URI buffer */
1280 size_t urisize) /* I - Size of URI buffer */
1281 {
1282 ipp_t *request, /* IPP request */
1283 *response; /* IPP response */
1284 ipp_attribute_t *attr; /* printer-type attribute */
1285 cups_ptype_t type; /* printer-type value */
1286
1287
1288 /*
1289 * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
1290 * attributes:
1291 *
1292 * attributes-charset
1293 * attributes-natural-language
1294 * printer-uri
1295 * requested-attributes
1296 * requesting-user-name
1297 */
1298
1299 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer);
1300
1301 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1302 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1303 "printer-uri", NULL, uri);
1304 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1305 "requested-attributes", NULL, "printer-type");
1306 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1307 "requesting-user-name", NULL, cupsUser());
1308
1309 /*
1310 * Do the request...
1311 */
1312
1313 response = cupsDoRequest(http, request, "/");
1314 if ((attr = ippFindAttribute(response, "printer-type",
1315 IPP_TAG_ENUM)) != NULL)
1316 {
1317 type = (cups_ptype_t)attr->values[0].integer;
1318
1319 if (type & CUPS_PRINTER_CLASS)
1320 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/classes/%s", printer);
1321 }
1322 else
1323 type = CUPS_PRINTER_LOCAL;
1324
1325 ippDelete(response);
1326
1327 return (type);
1328 }
1329
1330
1331 /*
1332 * 'set_printer_options()' - Set the printer options.
1333 */
1334
1335 static int /* O - 0 on success, 1 on fail */
1336 set_printer_options(
1337 http_t *http, /* I - Server connection */
1338 char *printer, /* I - Printer */
1339 int num_options, /* I - Number of options */
1340 cups_option_t *options, /* I - Options */
1341 char *file, /* I - PPD file */
1342 int enable) /* I - Enable printer? */
1343 {
1344 ipp_t *request; /* IPP Request */
1345 const char *ppdfile; /* PPD filename */
1346 int ppdchanged = 0; /* PPD changed? */
1347 ppd_file_t *ppd; /* PPD file */
1348 ppd_choice_t *choice; /* Marked choice */
1349 char uri[HTTP_MAX_URI], /* URI for printer/class */
1350 line[1024], /* Line from PPD file */
1351 keyword[1024], /* Keyword from Default line */
1352 *keyptr, /* Pointer into keyword... */
1353 tempfile[1024]; /* Temporary filename */
1354 cups_file_t *in, /* PPD file */
1355 *out; /* Temporary file */
1356 const char *ppdname, /* ppd-name value */
1357 *protocol, /* Old protocol option */
1358 *customval, /* Custom option value */
1359 *boolval; /* Boolean value */
1360 int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */
1361 wrote_snmp_supplies = 0,/* Wrote cupsSNMPSupplies keyword? */
1362 copied_options = 0; /* Copied options? */
1363
1364
1365 /*
1366 * Build a CUPS-Add-Modify-Printer or CUPS-Add-Modify-Class request,
1367 * which requires the following attributes:
1368 *
1369 * attributes-charset
1370 * attributes-natural-language
1371 * printer-uri
1372 * requesting-user-name
1373 * other options
1374 */
1375
1376 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
1377 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS);
1378 else
1379 request = ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER);
1380
1381 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1382 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
1383
1384 /*
1385 * Add the options...
1386 */
1387
1388 if (file)
1389 ppdfile = file;
1390 else if ((ppdname = cupsGetOption("ppd-name", num_options, options)) != NULL && strcmp(ppdname, "raw") && num_options > 1)
1391 {
1392 if ((ppdfile = cupsGetServerPPD(http, ppdname)) != NULL)
1393 {
1394 /*
1395 * Copy options array and remove ppd-name from it...
1396 */
1397
1398 cups_option_t *temp = NULL, *optr;
1399 int i, num_temp = 0;
1400 for (i = num_options, optr = options; i > 0; i --, optr ++)
1401 if (strcmp(optr->name, "ppd-name"))
1402 num_temp = cupsAddOption(optr->name, optr->value, num_temp, &temp);
1403
1404 copied_options = 1;
1405 ppdchanged = 1;
1406 num_options = num_temp;
1407 options = temp;
1408 }
1409 }
1410 else if (request->request.op.operation_id == IPP_OP_CUPS_ADD_MODIFY_PRINTER)
1411 ppdfile = cupsGetPPD(printer);
1412 else
1413 ppdfile = NULL;
1414
1415 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
1416
1417 if (enable)
1418 {
1419 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PSTATE_IDLE);
1420 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
1421 }
1422
1423 cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER);
1424
1425 if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL)
1426 {
1427 if (!_cups_strcasecmp(protocol, "bcp"))
1428 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1429 NULL, "bcp");
1430 else if (!_cups_strcasecmp(protocol, "tbcp"))
1431 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1432 NULL, "tbcp");
1433 }
1434
1435 if (ppdfile)
1436 {
1437 /*
1438 * Set default options in the PPD file...
1439 */
1440
1441 if ((ppd = ppdOpenFile(ppdfile)) == NULL)
1442 {
1443 int linenum; /* Line number of error */
1444 ppd_status_t status = ppdLastError(&linenum);
1445 /* Status code */
1446
1447 _cupsLangPrintf(stderr, _("lpadmin: Unable to open PPD \"%s\": %s on line %d."), ppdfile, ppdErrorString(status), linenum);
1448 }
1449
1450 ppdMarkDefaults(ppd);
1451 cupsMarkOptions(ppd, num_options, options);
1452
1453 if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
1454 {
1455 _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file"));
1456 ippDelete(request);
1457 if (ppdfile != file)
1458 unlink(ppdfile);
1459 if (copied_options)
1460 cupsFreeOptions(num_options, options);
1461 return (1);
1462 }
1463
1464 if ((in = cupsFileOpen(ppdfile, "r")) == NULL)
1465 {
1466 _cupsLangPrintf(stderr,
1467 _("lpadmin: Unable to open PPD file \"%s\" - %s"),
1468 ppdfile, strerror(errno));
1469 ippDelete(request);
1470 if (ppdfile != file)
1471 unlink(ppdfile);
1472 if (copied_options)
1473 cupsFreeOptions(num_options, options);
1474 cupsFileClose(out);
1475 unlink(tempfile);
1476 return (1);
1477 }
1478
1479 while (cupsFileGets(in, line, sizeof(line)))
1480 {
1481 if (!strncmp(line, "*cupsIPPSupplies:", 17) &&
1482 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1483 options)) != NULL)
1484 {
1485 wrote_ipp_supplies = 1;
1486 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1487 (!_cups_strcasecmp(boolval, "true") ||
1488 !_cups_strcasecmp(boolval, "yes") ||
1489 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1490 }
1491 else if (!strncmp(line, "*cupsSNMPSupplies:", 18) &&
1492 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1493 options)) != NULL)
1494 {
1495 wrote_snmp_supplies = 1;
1496 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1497 (!_cups_strcasecmp(boolval, "true") ||
1498 !_cups_strcasecmp(boolval, "yes") ||
1499 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1500 }
1501 else if (strncmp(line, "*Default", 8))
1502 cupsFilePrintf(out, "%s\n", line);
1503 else
1504 {
1505 /*
1506 * Get default option name...
1507 */
1508
1509 strlcpy(keyword, line + 8, sizeof(keyword));
1510
1511 for (keyptr = keyword; *keyptr; keyptr ++)
1512 if (*keyptr == ':' || isspace(*keyptr & 255))
1513 break;
1514
1515 *keyptr++ = '\0';
1516 while (isspace(*keyptr & 255))
1517 keyptr ++;
1518
1519 if (!strcmp(keyword, "PageRegion") ||
1520 !strcmp(keyword, "PageSize") ||
1521 !strcmp(keyword, "PaperDimension") ||
1522 !strcmp(keyword, "ImageableArea"))
1523 {
1524 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL)
1525 choice = ppdFindMarkedChoice(ppd, "PageRegion");
1526 }
1527 else
1528 choice = ppdFindMarkedChoice(ppd, keyword);
1529
1530 if (choice && strcmp(choice->choice, keyptr))
1531 {
1532 if (strcmp(choice->choice, "Custom"))
1533 {
1534 cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice);
1535 ppdchanged = 1;
1536 }
1537 else if ((customval = cupsGetOption(keyword, num_options,
1538 options)) != NULL)
1539 {
1540 cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval);
1541 ppdchanged = 1;
1542 }
1543 else
1544 cupsFilePrintf(out, "%s\n", line);
1545 }
1546 else
1547 cupsFilePrintf(out, "%s\n", line);
1548 }
1549 }
1550
1551 if (!wrote_ipp_supplies &&
1552 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1553 options)) != NULL)
1554 {
1555 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1556 (!_cups_strcasecmp(boolval, "true") ||
1557 !_cups_strcasecmp(boolval, "yes") ||
1558 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1559 }
1560
1561 if (!wrote_snmp_supplies &&
1562 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1563 options)) != NULL)
1564 {
1565 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1566 (!_cups_strcasecmp(boolval, "true") ||
1567 !_cups_strcasecmp(boolval, "yes") ||
1568 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1569 }
1570
1571 cupsFileClose(in);
1572 cupsFileClose(out);
1573 ppdClose(ppd);
1574
1575 /*
1576 * Do the request...
1577 */
1578
1579 ippDelete(cupsDoFileRequest(http, request, "/admin/",
1580 ppdchanged ? tempfile : file));
1581
1582 /*
1583 * Clean up temp files... (TODO: catch signals in case we CTRL-C during
1584 * lpadmin)
1585 */
1586
1587 if (ppdfile != file)
1588 unlink(ppdfile);
1589 unlink(tempfile);
1590 }
1591 else
1592 {
1593 /*
1594 * No PPD file - just set the options...
1595 */
1596
1597 ippDelete(cupsDoRequest(http, request, "/admin/"));
1598 }
1599
1600 if (copied_options)
1601 cupsFreeOptions(num_options, options);
1602
1603 /*
1604 * Check the response...
1605 */
1606
1607 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1608 {
1609 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1610
1611 return (1);
1612 }
1613 else
1614 return (0);
1615 }
1616
1617
1618 /*
1619 * 'usage()' - Show program usage and exit.
1620 */
1621
1622 static void
1623 usage(void)
1624 {
1625 _cupsLangPuts(stdout, _("Usage: lpadmin [options] -d destination\n"
1626 " lpadmin [options] -p destination\n"
1627 " lpadmin [options] -p destination -c class\n"
1628 " lpadmin [options] -p destination -r class\n"
1629 " lpadmin [options] -x destination"));
1630 _cupsLangPuts(stdout, _("Options:"));
1631 _cupsLangPuts(stdout, _("-c class Add the named destination to a class"));
1632 _cupsLangPuts(stdout, _("-d destination Set the named destination as the server default"));
1633 _cupsLangPuts(stdout, _("-D description Specify the textual description of the printer"));
1634 _cupsLangPuts(stdout, _("-E Encrypt the connection to the server"));
1635 _cupsLangPuts(stdout, _("-E Enable and accept jobs on the printer (after -p)"));
1636 _cupsLangPuts(stdout, _("-h server[:port] Connect to the named server and port"));
1637 _cupsLangPuts(stdout, _("-i ppd-file Specify a PPD file for the printer"));
1638 _cupsLangPuts(stdout, _("-L location Specify the textual location of the printer"));
1639 _cupsLangPuts(stdout, _("-m model Specify a standard model/PPD file for the printer"));
1640 _cupsLangPuts(stdout, _("-m everywhere Specify the printer is compatible with IPP Everywhere™"));
1641 _cupsLangPuts(stdout, _("-o name-default=value Specify the default value for the named option"));
1642 _cupsLangPuts(stdout, _("-o Name=Value Specify the default value for the named PPD option "));
1643 _cupsLangPuts(stdout, _("-o cupsIPPSupplies=false\n"
1644 " Disable supply level reporting via IPP"));
1645 _cupsLangPuts(stdout, _("-o cupsSNMPSupplies=false\n"
1646 " Disable supply level reporting via SNMP"));
1647 _cupsLangPuts(stdout, _("-o job-k-limit=N Specify the kilobyte limit for per-user quotas"));
1648 _cupsLangPuts(stdout, _("-o job-page-limit=N Specify the page limit for per-user quotas"));
1649 _cupsLangPuts(stdout, _("-o job-quota-period=N Specify the per-user quota period in seconds"));
1650 _cupsLangPuts(stdout, _("-o printer-error-policy=name\n"
1651 " Specify the printer error policy"));
1652 _cupsLangPuts(stdout, _("-o printer-is-shared=true\n"
1653 " Share the printer"));
1654 _cupsLangPuts(stdout, _("-o printer-op-policy=name\n"
1655 " Specify the printer operation policy"));
1656 _cupsLangPuts(stdout, _("-p destination Specify/add the named destination"));
1657 _cupsLangPuts(stdout, _("-r class Remove the named destination from a class"));
1658 _cupsLangPuts(stdout, _("-R name-default Remove the default value for the named option"));
1659 _cupsLangPuts(stdout, _("-u allow:all Allow all users to print"));
1660 _cupsLangPuts(stdout, _("-u allow:list Allow the list of users or groups (@name) to print"));
1661 _cupsLangPuts(stdout, _("-u deny:list Prevent the list of users or groups (@name) to print"));
1662 _cupsLangPuts(stdout, _("-U username Specify the username to use for authentication"));
1663 _cupsLangPuts(stdout, _("-v device-uri Specify the device URI for the printer"));
1664 _cupsLangPuts(stdout, _("-x destination Remove the named destination"));
1665
1666 exit(1);
1667 }
1668
1669
1670 /*
1671 * 'validate_name()' - Make sure the printer name only contains valid chars.
1672 */
1673
1674 static int /* O - 0 if name is no good, 1 if name is good */
1675 validate_name(const char *name) /* I - Name to check */
1676 {
1677 const char *ptr; /* Pointer into name */
1678
1679
1680 /*
1681 * Scan the whole name...
1682 */
1683
1684 for (ptr = name; *ptr; ptr ++)
1685 if (*ptr == '@')
1686 break;
1687 else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '\\' || *ptr == '?' || *ptr == '\'' || *ptr == '\"' || *ptr == '#')
1688 return (0);
1689
1690 /*
1691 * All the characters are good; validate the length, too...
1692 */
1693
1694 return ((ptr - name) < 128);
1695 }