]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lpadmin.c
Full sweep of all Clang warnings, plus some bug fixes for incorrect memcpy usage.
[thirdparty/cups.git] / systemv / lpadmin.c
1 /*
2 * "$Id$"
3 *
4 * "lpadmin" command for CUPS.
5 *
6 * Copyright 2007-2014 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; /* 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 *protocol, /* Old protocol option */
1247 *customval, /* Custom option value */
1248 *boolval; /* Boolean value */
1249 int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */
1250 wrote_snmp_supplies = 0;/* Wrote cupsSNMPSupplies keyword? */
1251
1252
1253 DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, "
1254 "options=%p, file=\"%s\")\n", http, printer, num_options,
1255 options, file));
1256
1257 /*
1258 * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which
1259 * requires the following attributes:
1260 *
1261 * attributes-charset
1262 * attributes-natural-language
1263 * printer-uri
1264 * requesting-user-name
1265 * other options
1266 */
1267
1268 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS)
1269 request = ippNewRequest(CUPS_ADD_MODIFY_CLASS);
1270 else
1271 request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
1272
1273 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1274 "printer-uri", NULL, uri);
1275 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1276 "requesting-user-name", NULL, cupsUser());
1277
1278 /*
1279 * Add the options...
1280 */
1281
1282 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
1283 cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER);
1284
1285 if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL)
1286 {
1287 if (!_cups_strcasecmp(protocol, "bcp"))
1288 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1289 NULL, "bcp");
1290 else if (!_cups_strcasecmp(protocol, "tbcp"))
1291 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
1292 NULL, "tbcp");
1293 }
1294
1295 if (file)
1296 ppdfile = file;
1297 else if (request->request.op.operation_id == CUPS_ADD_MODIFY_PRINTER)
1298 ppdfile = cupsGetPPD(printer);
1299 else
1300 ppdfile = NULL;
1301
1302 if (ppdfile != NULL)
1303 {
1304 /*
1305 * Set default options in the PPD file...
1306 */
1307
1308 ppd = ppdOpenFile(ppdfile);
1309 ppdMarkDefaults(ppd);
1310 cupsMarkOptions(ppd, num_options, options);
1311
1312 if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
1313 {
1314 _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file"));
1315 ippDelete(request);
1316 if (ppdfile != file)
1317 unlink(ppdfile);
1318 return (1);
1319 }
1320
1321 if ((in = cupsFileOpen(ppdfile, "r")) == NULL)
1322 {
1323 _cupsLangPrintf(stderr,
1324 _("lpadmin: Unable to open PPD file \"%s\" - %s"),
1325 ppdfile, strerror(errno));
1326 ippDelete(request);
1327 if (ppdfile != file)
1328 unlink(ppdfile);
1329 cupsFileClose(out);
1330 unlink(tempfile);
1331 return (1);
1332 }
1333
1334 ppdchanged = 0;
1335
1336 while (cupsFileGets(in, line, sizeof(line)))
1337 {
1338 if (!strncmp(line, "*cupsIPPSupplies:", 17) &&
1339 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1340 options)) != NULL)
1341 {
1342 wrote_ipp_supplies = 1;
1343 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1344 (!_cups_strcasecmp(boolval, "true") ||
1345 !_cups_strcasecmp(boolval, "yes") ||
1346 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1347 }
1348 else if (!strncmp(line, "*cupsSNMPSupplies:", 18) &&
1349 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1350 options)) != NULL)
1351 {
1352 wrote_snmp_supplies = 1;
1353 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1354 (!_cups_strcasecmp(boolval, "true") ||
1355 !_cups_strcasecmp(boolval, "yes") ||
1356 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1357 }
1358 else if (strncmp(line, "*Default", 8))
1359 cupsFilePrintf(out, "%s\n", line);
1360 else
1361 {
1362 /*
1363 * Get default option name...
1364 */
1365
1366 strlcpy(keyword, line + 8, sizeof(keyword));
1367
1368 for (keyptr = keyword; *keyptr; keyptr ++)
1369 if (*keyptr == ':' || isspace(*keyptr & 255))
1370 break;
1371
1372 *keyptr++ = '\0';
1373 while (isspace(*keyptr & 255))
1374 keyptr ++;
1375
1376 if (!strcmp(keyword, "PageRegion") ||
1377 !strcmp(keyword, "PageSize") ||
1378 !strcmp(keyword, "PaperDimension") ||
1379 !strcmp(keyword, "ImageableArea"))
1380 {
1381 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL)
1382 choice = ppdFindMarkedChoice(ppd, "PageRegion");
1383 }
1384 else
1385 choice = ppdFindMarkedChoice(ppd, keyword);
1386
1387 if (choice && strcmp(choice->choice, keyptr))
1388 {
1389 if (strcmp(choice->choice, "Custom"))
1390 {
1391 cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice);
1392 ppdchanged = 1;
1393 }
1394 else if ((customval = cupsGetOption(keyword, num_options,
1395 options)) != NULL)
1396 {
1397 cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval);
1398 ppdchanged = 1;
1399 }
1400 else
1401 cupsFilePrintf(out, "%s\n", line);
1402 }
1403 else
1404 cupsFilePrintf(out, "%s\n", line);
1405 }
1406 }
1407
1408 if (!wrote_ipp_supplies &&
1409 (boolval = cupsGetOption("cupsIPPSupplies", num_options,
1410 options)) != NULL)
1411 {
1412 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
1413 (!_cups_strcasecmp(boolval, "true") ||
1414 !_cups_strcasecmp(boolval, "yes") ||
1415 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1416 }
1417
1418 if (!wrote_snmp_supplies &&
1419 (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
1420 options)) != NULL)
1421 {
1422 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
1423 (!_cups_strcasecmp(boolval, "true") ||
1424 !_cups_strcasecmp(boolval, "yes") ||
1425 !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
1426 }
1427
1428 cupsFileClose(in);
1429 cupsFileClose(out);
1430 ppdClose(ppd);
1431
1432 /*
1433 * Do the request...
1434 */
1435
1436 ippDelete(cupsDoFileRequest(http, request, "/admin/",
1437 ppdchanged ? tempfile : file));
1438
1439 /*
1440 * Clean up temp files... (TODO: catch signals in case we CTRL-C during
1441 * lpadmin)
1442 */
1443
1444 if (ppdfile != file)
1445 unlink(ppdfile);
1446 unlink(tempfile);
1447 }
1448 else
1449 {
1450 /*
1451 * No PPD file - just set the options...
1452 */
1453
1454 ippDelete(cupsDoRequest(http, request, "/admin/"));
1455 }
1456
1457 /*
1458 * Check the response...
1459 */
1460
1461 if (cupsLastError() > IPP_OK_CONFLICT)
1462 {
1463 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
1464
1465 return (1);
1466 }
1467 else
1468 return (0);
1469 }
1470
1471
1472 /*
1473 * 'validate_name()' - Make sure the printer name only contains valid chars.
1474 */
1475
1476 static int /* O - 0 if name is no good, 1 if name is good */
1477 validate_name(const char *name) /* I - Name to check */
1478 {
1479 const char *ptr; /* Pointer into name */
1480
1481
1482 /*
1483 * Scan the whole name...
1484 */
1485
1486 for (ptr = name; *ptr; ptr ++)
1487 if (*ptr == '@')
1488 break;
1489 else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
1490 *ptr == '#')
1491 return (0);
1492
1493 /*
1494 * All the characters are good; validate the length, too...
1495 */
1496
1497 return ((ptr - name) < 128);
1498 }
1499
1500
1501 /*
1502 * End of "$Id$".
1503 */