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