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