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