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