4 * "lpadmin" command for CUPS.
6 * Copyright 2007-2015 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
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/".
17 * Include necessary headers...
20 #define _CUPS_NO_DEPRECATED
21 #define _PPD_DEPRECATED
22 #include <cups/cups-private.h>
29 static int add_printer_to_class(http_t
*http
, char *printer
, char *pclass
);
30 static int default_printer(http_t
*http
, char *printer
);
31 static int delete_printer(http_t
*http
, char *printer
);
32 static int delete_printer_from_class(http_t
*http
, char *printer
,
34 static int delete_printer_option(http_t
*http
, char *printer
,
36 static int enable_printer(http_t
*http
, char *printer
);
37 static char *get_printer_ppd(const char *uri
, char *buffer
, size_t bufsize
);
38 static cups_ptype_t
get_printer_type(http_t
*http
, char *printer
, char *uri
,
40 static int set_printer_options(http_t
*http
, char *printer
,
41 int num_options
, cups_option_t
*options
,
43 static int validate_name(const char *name
);
47 * 'main()' - Parse options and configure the scheduler.
51 main(int argc
, /* I - Number of command-line arguments */
52 char *argv
[]) /* I - Command-line arguments */
54 int i
; /* Looping var */
55 http_t
*http
; /* Connection to server */
56 char *printer
, /* Destination printer */
57 *pclass
, /* Printer class name */
58 *val
; /* Pointer to allow/deny value */
59 int num_options
; /* Number of options */
60 cups_option_t
*options
; /* Options */
61 char *file
, /* New PPD file/interface script */
63 /* IPP Everywhere PPD */
64 const char *ppd_name
, /* ppd-name value */
65 *device_uri
; /* device-uri value */
76 for (i
= 1; i
< argc
; i
++)
77 if (argv
[i
][0] == '-')
80 case 'c' : /* Add printer to class */
83 http
= httpConnect2(cupsServer(), ippPort(), NULL
, AF_UNSPEC
, cupsEncryption(), 1, 30000, NULL
);
87 _cupsLangPrintf(stderr
,
88 _("lpadmin: Unable to connect to server: %s"),
97 _("lpadmin: Unable to add a printer to the class:\n"
98 " You must specify a printer name "
104 pclass
= argv
[i
] + 2;
111 _cupsLangPuts(stderr
,
112 _("lpadmin: Expected class name after \"-c\" "
120 if (!validate_name(pclass
))
122 _cupsLangPuts(stderr
,
123 _("lpadmin: Class name can only contain printable "
128 if (add_printer_to_class(http
, printer
, pclass
))
132 case 'd' : /* Set as default destination */
135 http
= httpConnect2(cupsServer(), ippPort(), NULL
, AF_UNSPEC
, cupsEncryption(), 1, 30000, NULL
);
139 _cupsLangPrintf(stderr
,
140 _("lpadmin: Unable to connect to server: %s"),
147 printer
= argv
[i
] + 2;
154 _cupsLangPuts(stderr
,
155 _("lpadmin: Expected printer name after \"-d\" "
163 if (!validate_name(printer
))
165 _cupsLangPuts(stderr
,
166 _("lpadmin: Printer name can only contain "
167 "printable characters."));
171 if (default_printer(http
, printer
))
177 case 'h' : /* Connect to host */
184 if (argv
[i
][2] != '\0')
185 cupsSetServer(argv
[i
] + 2);
192 _cupsLangPuts(stderr
,
193 _("lpadmin: Expected hostname after \"-h\" "
198 cupsSetServer(argv
[i
]);
202 case 'i' : /* Use the specified interface script */
211 _cupsLangPuts(stderr
,
212 _("lpadmin: Expected interface after \"-i\" "
221 case 'E' : /* Enable the printer */
225 cupsSetEncryption(HTTP_ENCRYPTION_REQUIRED
);
228 httpEncryption(http
, HTTP_ENCRYPTION_REQUIRED
);
230 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
232 #endif /* HAVE_SSL */
238 http
= httpConnect2(cupsServer(), ippPort(), NULL
, AF_UNSPEC
, cupsEncryption(), 1, 30000, NULL
);
242 _cupsLangPrintf(stderr
,
243 _("lpadmin: Unable to connect to server: %s"),
249 if (enable_printer(http
, printer
))
253 case 'm' : /* Use the specified standard script/PPD file */
255 num_options
= cupsAddOption("ppd-name", argv
[i
] + 2, num_options
,
263 _cupsLangPuts(stderr
,
264 _("lpadmin: Expected model after \"-m\" "
269 num_options
= cupsAddOption("ppd-name", argv
[i
], num_options
,
274 case 'o' : /* Set option */
276 num_options
= cupsParseOptions(argv
[i
] + 2, num_options
, &options
);
283 _cupsLangPuts(stderr
,
284 _("lpadmin: Expected name=value after \"-o\" "
289 num_options
= cupsParseOptions(argv
[i
], num_options
, &options
);
293 case 'p' : /* Add/modify a printer */
295 printer
= argv
[i
] + 2;
302 _cupsLangPuts(stderr
,
303 _("lpadmin: Expected printer after \"-p\" "
311 if (!validate_name(printer
))
313 _cupsLangPuts(stderr
,
314 _("lpadmin: Printer name can only contain "
315 "printable characters."));
320 case 'r' : /* Remove printer from class */
323 http
= httpConnect2(cupsServer(), ippPort(), NULL
, AF_UNSPEC
, cupsEncryption(), 1, 30000, NULL
);
327 _cupsLangPrintf(stderr
,
328 _("lpadmin: Unable to connect to server: %s"),
336 _cupsLangPuts(stderr
,
337 _("lpadmin: Unable to remove a printer from the "
339 " You must specify a printer name "
345 pclass
= argv
[i
] + 2;
352 _cupsLangPuts(stderr
,
353 _("lpadmin: Expected class after \"-r\" "
361 if (!validate_name(pclass
))
363 _cupsLangPuts(stderr
,
364 _("lpadmin: Class name can only contain printable "
369 if (delete_printer_from_class(http
, printer
, pclass
))
373 case 'R' : /* Remove option */
376 http
= httpConnect2(cupsServer(), ippPort(), NULL
, AF_UNSPEC
, cupsEncryption(), 1, 30000, NULL
);
380 _cupsLangPrintf(stderr
,
381 _("lpadmin: Unable to connect to server: %s"),
389 _cupsLangPuts(stderr
,
390 _("lpadmin: Unable to delete option:\n"
391 " You must specify a printer name "
404 _cupsLangPuts(stderr
,
405 _("lpadmin: Expected name after \"-R\" "
413 if (delete_printer_option(http
, printer
, val
))
417 case 'U' : /* Username */
418 if (argv
[i
][2] != '\0')
419 cupsSetUser(argv
[i
] + 2);
425 _cupsLangPrintf(stderr
,
426 _("%s: Error - expected username after "
427 "\"-U\" option."), argv
[0]);
431 cupsSetUser(argv
[i
]);
435 case 'u' : /* Allow/deny users */
444 _cupsLangPuts(stderr
,
445 _("lpadmin: Expected allow/deny:userlist after "
453 if (!_cups_strncasecmp(val
, "allow:", 6))
454 num_options
= cupsAddOption("requesting-user-name-allowed",
455 val
+ 6, num_options
, &options
);
456 else if (!_cups_strncasecmp(val
, "deny:", 5))
457 num_options
= cupsAddOption("requesting-user-name-denied",
458 val
+ 5, num_options
, &options
);
461 _cupsLangPrintf(stderr
,
462 _("lpadmin: Unknown allow/deny option \"%s\"."),
468 case 'v' : /* Set the device-uri attribute */
470 num_options
= cupsAddOption("device-uri", argv
[i
] + 2,
471 num_options
, &options
);
478 _cupsLangPuts(stderr
,
479 _("lpadmin: Expected device URI after \"-v\" "
484 num_options
= cupsAddOption("device-uri", argv
[i
],
485 num_options
, &options
);
489 case 'x' : /* Delete a printer */
492 http
= httpConnect2(cupsServer(), ippPort(), NULL
, AF_UNSPEC
, cupsEncryption(), 1, 30000, NULL
);
496 _cupsLangPrintf(stderr
,
497 _("lpadmin: Unable to connect to server: %s"),
504 printer
= argv
[i
] + 2;
511 _cupsLangPuts(stderr
,
512 _("lpadmin: Expected printer or class after "
520 if (!validate_name(printer
))
522 _cupsLangPuts(stderr
,
523 _("lpadmin: Printer name can only contain "
524 "printable characters."));
528 if (delete_printer(http
, printer
))
534 case 'D' : /* Set the printer-info attribute */
536 num_options
= cupsAddOption("printer-info", argv
[i
] + 2,
537 num_options
, &options
);
544 _cupsLangPuts(stderr
,
545 _("lpadmin: Expected description after "
550 num_options
= cupsAddOption("printer-info", argv
[i
],
551 num_options
, &options
);
555 case 'I' : /* Set the supported file types (ignored) */
560 _cupsLangPuts(stderr
,
561 _("lpadmin: Expected file type(s) after \"-I\" "
566 _cupsLangPuts(stderr
,
567 _("lpadmin: Warning - content type list ignored."));
570 case 'L' : /* Set the printer-location attribute */
572 num_options
= cupsAddOption("printer-location", argv
[i
] + 2,
573 num_options
, &options
);
580 _cupsLangPuts(stderr
,
581 _("lpadmin: Expected location after \"-L\" "
586 num_options
= cupsAddOption("printer-location", argv
[i
],
587 num_options
, &options
);
591 case 'P' : /* Use the specified PPD file */
600 _cupsLangPuts(stderr
,
601 _("lpadmin: Expected PPD after \"-P\" option."));
610 _cupsLangPrintf(stderr
,
611 _("lpadmin: Unknown option \"%c\"."), argv
[i
][1]);
616 _cupsLangPrintf(stderr
, _("lpadmin: Unknown argument \"%s\"."),
622 * Set options as needed...
625 if ((ppd_name
= cupsGetOption("ppd-name", num_options
, options
)) != NULL
&& !strcmp(ppd_name
, "everywhere") && (device_uri
= cupsGetOption("device-uri", num_options
, options
)) != NULL
)
627 if ((file
= get_printer_ppd(device_uri
, evefile
, sizeof(evefile
))) == NULL
)
630 num_options
= cupsRemoveOption("ppd-name", num_options
, &options
);
633 if (num_options
|| file
)
637 http
= httpConnect2(cupsServer(), ippPort(), NULL
, AF_UNSPEC
, cupsEncryption(), 1, 30000, NULL
);
641 _cupsLangPrintf(stderr
,
642 _("lpadmin: Unable to connect to server: %s"),
650 _cupsLangPuts(stderr
,
651 _("lpadmin: Unable to set the printer options:\n"
652 " You must specify a printer name first."));
656 if (set_printer_options(http
, printer
, num_options
, options
, file
))
665 _cupsLangPuts(stdout
,
668 " lpadmin [-h server] -d destination\n"
669 " lpadmin [-h server] -x destination\n"
670 " lpadmin [-h server] -p printer [-c add-class] "
671 "[-i interface] [-m model]\n"
672 " [-r remove-class] [-v device] "
674 " [-P ppd-file] [-o name=value]\n"
675 " [-u allow:user,user] "
676 "[-u deny:user,user]"));
687 * 'add_printer_to_class()' - Add a printer to a class.
690 static int /* O - 0 on success, 1 on fail */
691 add_printer_to_class(http_t
*http
, /* I - Server connection */
692 char *printer
, /* I - Printer to add */
693 char *pclass
) /* I - Class to add to */
695 int i
; /* Looping var */
696 ipp_t
*request
, /* IPP Request */
697 *response
; /* IPP Response */
698 ipp_attribute_t
*attr
, /* Current attribute */
699 *members
; /* Members in class */
700 char uri
[HTTP_MAX_URI
]; /* URI for printer/class */
703 DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http
,
707 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
711 * attributes-natural-language
713 * requesting-user-name
716 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
718 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
719 "localhost", 0, "/classes/%s", pclass
);
720 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
721 "printer-uri", NULL
, uri
);
722 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
726 * Do the request and get back a response...
729 response
= cupsDoRequest(http
, request
, "/");
732 * Build a CUPS-Add-Modify-Class request, which requires the following
736 * attributes-natural-language
738 * requesting-user-name
742 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS
);
744 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
745 "printer-uri", NULL
, uri
);
746 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
750 * See if the printer is already in the class...
753 if (response
!= NULL
&&
754 (members
= ippFindAttribute(response
, "member-names",
755 IPP_TAG_NAME
)) != NULL
)
756 for (i
= 0; i
< members
->num_values
; i
++)
757 if (_cups_strcasecmp(printer
, members
->values
[i
].string
.text
) == 0)
759 _cupsLangPrintf(stderr
,
760 _("lpadmin: Printer %s is already a member of class "
761 "%s."), printer
, pclass
);
768 * OK, the printer isn't part of the class, so add it...
771 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
772 "localhost", 0, "/printers/%s", printer
);
774 if (response
!= NULL
&&
775 (members
= ippFindAttribute(response
, "member-uris",
776 IPP_TAG_URI
)) != NULL
)
779 * Add the printer to the existing list...
782 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
783 "member-uris", members
->num_values
+ 1, NULL
, NULL
);
784 for (i
= 0; i
< members
->num_values
; i
++)
785 attr
->values
[i
].string
.text
=
786 _cupsStrAlloc(members
->values
[i
].string
.text
);
788 attr
->values
[i
].string
.text
= _cupsStrAlloc(uri
);
791 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
, "member-uris", NULL
,
795 * Then send the request...
800 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
801 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING
)
803 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
813 * 'default_printer()' - Set the default printing destination.
816 static int /* O - 0 on success, 1 on fail */
817 default_printer(http_t
*http
, /* I - Server connection */
818 char *printer
) /* I - Printer name */
820 ipp_t
*request
; /* IPP Request */
821 char uri
[HTTP_MAX_URI
]; /* URI for printer/class */
824 DEBUG_printf(("default_printer(%p, \"%s\")\n", http
, printer
));
827 * Build a CUPS-Set-Default request, which requires the following
831 * attributes-natural-language
833 * requesting-user-name
836 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
837 "localhost", 0, "/printers/%s", printer
);
839 request
= ippNewRequest(IPP_OP_CUPS_SET_DEFAULT
);
841 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
842 "printer-uri", NULL
, uri
);
843 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
847 * Do the request and get back a response...
850 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
852 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING
)
854 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
864 * 'delete_printer()' - Delete a printer from the system...
867 static int /* O - 0 on success, 1 on fail */
868 delete_printer(http_t
*http
, /* I - Server connection */
869 char *printer
) /* I - Printer to delete */
871 ipp_t
*request
; /* IPP Request */
872 char uri
[HTTP_MAX_URI
]; /* URI for printer/class */
875 DEBUG_printf(("delete_printer(%p, \"%s\")\n", http
, printer
));
878 * Build a CUPS-Delete-Printer request, which requires the following
882 * attributes-natural-language
884 * requesting-user-name
887 request
= ippNewRequest(IPP_OP_CUPS_DELETE_PRINTER
);
889 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
890 "localhost", 0, "/printers/%s", printer
);
891 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
892 "printer-uri", NULL
, uri
);
893 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
897 * Do the request and get back a response...
900 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
902 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING
)
904 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
914 * 'delete_printer_from_class()' - Delete a printer from a class.
917 static int /* O - 0 on success, 1 on fail */
918 delete_printer_from_class(
919 http_t
*http
, /* I - Server connection */
920 char *printer
, /* I - Printer to remove */
921 char *pclass
) /* I - Class to remove from */
923 int i
, j
, k
; /* Looping vars */
924 ipp_t
*request
, /* IPP Request */
925 *response
; /* IPP Response */
926 ipp_attribute_t
*attr
, /* Current attribute */
927 *members
; /* Members in class */
928 char uri
[HTTP_MAX_URI
]; /* URI for printer/class */
931 DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http
,
935 * Build an IPP_OP_GET_PRINTER_ATTRIBUTES request, which requires the following
939 * attributes-natural-language
941 * requesting-user-name
944 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
946 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
947 "localhost", 0, "/classes/%s", pclass
);
948 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
949 "printer-uri", NULL
, uri
);
950 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
954 * Do the request and get back a response...
957 if ((response
= cupsDoRequest(http
, request
, "/classes/")) == NULL
||
958 response
->request
.status
.status_code
== IPP_STATUS_ERROR_NOT_FOUND
)
960 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
968 * See if the printer is already in the class...
971 if ((members
= ippFindAttribute(response
, "member-names", IPP_TAG_NAME
)) == NULL
)
973 _cupsLangPuts(stderr
, _("lpadmin: No member names were seen."));
980 for (i
= 0; i
< members
->num_values
; i
++)
981 if (!_cups_strcasecmp(printer
, members
->values
[i
].string
.text
))
984 if (i
>= members
->num_values
)
986 _cupsLangPrintf(stderr
,
987 _("lpadmin: Printer %s is not a member of class %s."),
995 if (members
->num_values
== 1)
998 * Build a CUPS-Delete-Class request, which requires the following
1001 * attributes-charset
1002 * attributes-natural-language
1004 * requesting-user-name
1007 request
= ippNewRequest(IPP_OP_CUPS_DELETE_CLASS
);
1009 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1010 "printer-uri", NULL
, uri
);
1011 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1012 "requesting-user-name", NULL
, cupsUser());
1017 * Build a IPP_OP_CUPS_ADD_MODIFY_CLASS request, which requires the following
1020 * attributes-charset
1021 * attributes-natural-language
1023 * requesting-user-name
1027 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS
);
1029 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1030 "printer-uri", NULL
, uri
);
1031 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1032 "requesting-user-name", NULL
, cupsUser());
1035 * Delete the printer from the class...
1038 members
= ippFindAttribute(response
, "member-uris", IPP_TAG_URI
);
1039 attr
= ippAddStrings(request
, IPP_TAG_PRINTER
, IPP_TAG_URI
,
1040 "member-uris", members
->num_values
- 1, NULL
, NULL
);
1042 for (j
= 0, k
= 0; j
< members
->num_values
; j
++)
1044 attr
->values
[k
++].string
.text
=
1045 _cupsStrAlloc(members
->values
[j
].string
.text
);
1049 * Then send the request...
1052 ippDelete(response
);
1054 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1056 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING
)
1058 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
1068 * 'delete_printer_option()' - Delete a printer option.
1071 static int /* O - 0 on success, 1 on fail */
1072 delete_printer_option(http_t
*http
, /* I - Server connection */
1073 char *printer
, /* I - Printer */
1074 char *option
) /* I - Option to delete */
1076 ipp_t
*request
; /* IPP request */
1077 char uri
[HTTP_MAX_URI
]; /* URI for printer/class */
1081 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
1082 * requires the following attributes:
1084 * attributes-charset
1085 * attributes-natural-language
1087 * requesting-user-name
1088 * option with deleteAttr tag
1091 if (get_printer_type(http
, printer
, uri
, sizeof(uri
)) & CUPS_PRINTER_CLASS
)
1092 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS
);
1094 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER
);
1096 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1097 "printer-uri", NULL
, uri
);
1098 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1099 "requesting-user-name", NULL
, cupsUser());
1100 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_DELETEATTR
, option
, 0);
1103 * Do the request and get back a response...
1106 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1108 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING
)
1110 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
1120 * 'enable_printer()' - Enable a printer...
1123 static int /* O - 0 on success, 1 on fail */
1124 enable_printer(http_t
*http
, /* I - Server connection */
1125 char *printer
) /* I - Printer to enable */
1127 ipp_t
*request
; /* IPP Request */
1128 char uri
[HTTP_MAX_URI
]; /* URI for printer/class */
1131 DEBUG_printf(("enable_printer(%p, \"%s\")\n", http
, printer
));
1134 * Build a IPP_OP_CUPS_ADD_MODIFY_PRINTER or IPP_OP_CUPS_ADD_MODIFY_CLASS request, which
1135 * require the following attributes:
1137 * attributes-charset
1138 * attributes-natural-language
1140 * requesting-user-name
1142 * printer-is-accepting-jobs
1145 if (get_printer_type(http
, printer
, uri
, sizeof(uri
)) & CUPS_PRINTER_CLASS
)
1146 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS
);
1148 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER
);
1150 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1151 "printer-uri", NULL
, uri
);
1152 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1153 "requesting-user-name", NULL
, cupsUser());
1154 ippAddInteger(request
, IPP_TAG_PRINTER
, IPP_TAG_ENUM
, "printer-state",
1156 ippAddBoolean(request
, IPP_TAG_PRINTER
, "printer-is-accepting-jobs", 1);
1159 * Do the request and get back a response...
1162 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1164 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING
)
1166 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
1176 * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
1179 static char * /* O - Filename or NULL */
1180 get_printer_ppd(const char *uri
, /* I - Printer URI */
1181 char *buffer
, /* I - Filename buffer */
1182 size_t bufsize
) /* I - Size of filename buffer */
1184 http_t
*http
; /* Connection to printer */
1185 ipp_t
*request
, /* Get-Printer-Attributes request */
1186 *response
; /* Get-Printer-Attributes response */
1187 char resolved
[1024], /* Resolved URI */
1188 scheme
[32], /* URI scheme */
1189 userpass
[256], /* Username:password */
1190 host
[256], /* Hostname */
1191 resource
[256]; /* Resource path */
1192 int port
; /* Port number */
1196 * Connect to the printer...
1199 if (strstr(uri
, "._tcp"))
1205 if (!_httpResolveURI(uri
, resolved
, sizeof(resolved
), _HTTP_RESOLVE_DEFAULT
, NULL
, NULL
))
1207 _cupsLangPrintf(stderr
, _("%s: Unable to resolve \"%s\"."), "lpadmin", uri
);
1214 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), host
, sizeof(host
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
1216 _cupsLangPrintf(stderr
, _("%s: Bad printer URI \"%s\"."), "lpadmin", uri
);
1220 http
= httpConnect2(host
, port
, NULL
, AF_UNSPEC
, !strcmp(scheme
, "ipps") ? HTTP_ENCRYPTION_ALWAYS
: HTTP_ENCRYPTION_IF_REQUESTED
, 1, 30000, NULL
);
1223 _cupsLangPrintf(stderr
, _("%s: Unable to connect to \"%s:%d\": %s"), "lpadmin", host
, port
, cupsLastErrorString());
1228 * Send a Get-Printer-Attributes request...
1231 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
1232 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1233 response
= cupsDoRequest(http
, request
, resource
);
1235 if (!_ppdCreateFromIPP(buffer
, bufsize
, response
))
1236 _cupsLangPrintf(stderr
, _("%s: Unable to create PPD file: %s"), "lpadmin", strerror(errno
));
1238 ippDelete(response
);
1249 * 'get_printer_type()' - Determine the printer type and URI.
1252 static cups_ptype_t
/* O - printer-type value */
1253 get_printer_type(http_t
*http
, /* I - Server connection */
1254 char *printer
, /* I - Printer name */
1255 char *uri
, /* I - URI buffer */
1256 size_t urisize
) /* I - Size of URI buffer */
1258 ipp_t
*request
, /* IPP request */
1259 *response
; /* IPP response */
1260 ipp_attribute_t
*attr
; /* printer-type attribute */
1261 cups_ptype_t type
; /* printer-type value */
1265 * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
1268 * attributes-charset
1269 * attributes-natural-language
1271 * requested-attributes
1272 * requesting-user-name
1275 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, (int)urisize
, "ipp", NULL
, "localhost", ippPort(), "/printers/%s", printer
);
1277 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
1278 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1279 "printer-uri", NULL
, uri
);
1280 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1281 "requested-attributes", NULL
, "printer-type");
1282 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1283 "requesting-user-name", NULL
, cupsUser());
1289 response
= cupsDoRequest(http
, request
, "/");
1290 if ((attr
= ippFindAttribute(response
, "printer-type",
1291 IPP_TAG_ENUM
)) != NULL
)
1293 type
= (cups_ptype_t
)attr
->values
[0].integer
;
1295 if (type
& CUPS_PRINTER_CLASS
)
1296 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, (int)urisize
, "ipp", NULL
, "localhost", ippPort(), "/classes/%s", printer
);
1299 type
= CUPS_PRINTER_LOCAL
;
1301 ippDelete(response
);
1308 * 'set_printer_options()' - Set the printer options.
1311 static int /* O - 0 on success, 1 on fail */
1312 set_printer_options(
1313 http_t
*http
, /* I - Server connection */
1314 char *printer
, /* I - Printer */
1315 int num_options
, /* I - Number of options */
1316 cups_option_t
*options
, /* I - Options */
1317 char *file
) /* I - PPD file/interface script */
1319 ipp_t
*request
; /* IPP Request */
1320 const char *ppdfile
; /* PPD filename */
1321 int ppdchanged
= 0; /* PPD changed? */
1322 ppd_file_t
*ppd
; /* PPD file */
1323 ppd_choice_t
*choice
; /* Marked choice */
1324 char uri
[HTTP_MAX_URI
], /* URI for printer/class */
1325 line
[1024], /* Line from PPD file */
1326 keyword
[1024], /* Keyword from Default line */
1327 *keyptr
, /* Pointer into keyword... */
1328 tempfile
[1024]; /* Temporary filename */
1329 cups_file_t
*in
, /* PPD file */
1330 *out
; /* Temporary file */
1331 const char *ppdname
, /* ppd-name value */
1332 *protocol
, /* Old protocol option */
1333 *customval
, /* Custom option value */
1334 *boolval
; /* Boolean value */
1335 int wrote_ipp_supplies
= 0, /* Wrote cupsIPPSupplies keyword? */
1336 wrote_snmp_supplies
= 0,/* Wrote cupsSNMPSupplies keyword? */
1337 copied_options
= 0; /* Copied options? */
1340 DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, "
1341 "options=%p, file=\"%s\")\n", http
, printer
, num_options
,
1345 * Build a CUPS-Add-Modify-Printer or CUPS-Add-Modify-Class request,
1346 * which requires the following attributes:
1348 * attributes-charset
1349 * attributes-natural-language
1351 * requesting-user-name
1355 if (get_printer_type(http
, printer
, uri
, sizeof(uri
)) & CUPS_PRINTER_CLASS
)
1356 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_CLASS
);
1358 request
= ippNewRequest(IPP_OP_CUPS_ADD_MODIFY_PRINTER
);
1360 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1361 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name", NULL
, cupsUser());
1364 * Add the options...
1369 else if ((ppdname
= cupsGetOption("ppd-name", num_options
, options
)) != NULL
&& strcmp(ppdname
, "raw") && num_options
> 1)
1371 if ((ppdfile
= cupsGetServerPPD(http
, ppdname
)) != NULL
)
1374 * Copy options array and remove ppd-name from it...
1377 cups_option_t
*temp
= NULL
, *optr
;
1378 int i
, num_temp
= 0;
1379 for (i
= num_options
, optr
= options
; i
> 0; i
--, optr
++)
1380 if (strcmp(optr
->name
, "ppd-name"))
1381 num_temp
= cupsAddOption(optr
->name
, optr
->value
, num_temp
, &temp
);
1385 num_options
= num_temp
;
1389 else if (request
->request
.op
.operation_id
== IPP_OP_CUPS_ADD_MODIFY_PRINTER
)
1390 ppdfile
= cupsGetPPD(printer
);
1394 cupsEncodeOptions2(request
, num_options
, options
, IPP_TAG_OPERATION
);
1395 cupsEncodeOptions2(request
, num_options
, options
, IPP_TAG_PRINTER
);
1397 if ((protocol
= cupsGetOption("protocol", num_options
, options
)) != NULL
)
1399 if (!_cups_strcasecmp(protocol
, "bcp"))
1400 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "port-monitor",
1402 else if (!_cups_strcasecmp(protocol
, "tbcp"))
1403 ippAddString(request
, IPP_TAG_PRINTER
, IPP_TAG_NAME
, "port-monitor",
1410 * Set default options in the PPD file...
1413 if ((ppd
= ppdOpenFile(ppdfile
)) == NULL
)
1415 int linenum
; /* Line number of error */
1416 ppd_status_t status
= ppdLastError(&linenum
);
1419 _cupsLangPrintf(stderr
, _("lpadmin: Unable to open PPD \"%s\": %s on line %d."), ppdfile
, ppdErrorString(status
), linenum
);
1422 ppdMarkDefaults(ppd
);
1423 cupsMarkOptions(ppd
, num_options
, options
);
1425 if ((out
= cupsTempFile2(tempfile
, sizeof(tempfile
))) == NULL
)
1427 _cupsLangPrintError(NULL
, _("lpadmin: Unable to create temporary file"));
1429 if (ppdfile
!= file
)
1432 cupsFreeOptions(num_options
, options
);
1436 if ((in
= cupsFileOpen(ppdfile
, "r")) == NULL
)
1438 _cupsLangPrintf(stderr
,
1439 _("lpadmin: Unable to open PPD file \"%s\" - %s"),
1440 ppdfile
, strerror(errno
));
1442 if (ppdfile
!= file
)
1445 cupsFreeOptions(num_options
, options
);
1451 while (cupsFileGets(in
, line
, sizeof(line
)))
1453 if (!strncmp(line
, "*cupsIPPSupplies:", 17) &&
1454 (boolval
= cupsGetOption("cupsIPPSupplies", num_options
,
1457 wrote_ipp_supplies
= 1;
1458 cupsFilePrintf(out
, "*cupsIPPSupplies: %s\n",
1459 (!_cups_strcasecmp(boolval
, "true") ||
1460 !_cups_strcasecmp(boolval
, "yes") ||
1461 !_cups_strcasecmp(boolval
, "on")) ? "True" : "False");
1463 else if (!strncmp(line
, "*cupsSNMPSupplies:", 18) &&
1464 (boolval
= cupsGetOption("cupsSNMPSupplies", num_options
,
1467 wrote_snmp_supplies
= 1;
1468 cupsFilePrintf(out
, "*cupsSNMPSupplies: %s\n",
1469 (!_cups_strcasecmp(boolval
, "true") ||
1470 !_cups_strcasecmp(boolval
, "yes") ||
1471 !_cups_strcasecmp(boolval
, "on")) ? "True" : "False");
1473 else if (strncmp(line
, "*Default", 8))
1474 cupsFilePrintf(out
, "%s\n", line
);
1478 * Get default option name...
1481 strlcpy(keyword
, line
+ 8, sizeof(keyword
));
1483 for (keyptr
= keyword
; *keyptr
; keyptr
++)
1484 if (*keyptr
== ':' || isspace(*keyptr
& 255))
1488 while (isspace(*keyptr
& 255))
1491 if (!strcmp(keyword
, "PageRegion") ||
1492 !strcmp(keyword
, "PageSize") ||
1493 !strcmp(keyword
, "PaperDimension") ||
1494 !strcmp(keyword
, "ImageableArea"))
1496 if ((choice
= ppdFindMarkedChoice(ppd
, "PageSize")) == NULL
)
1497 choice
= ppdFindMarkedChoice(ppd
, "PageRegion");
1500 choice
= ppdFindMarkedChoice(ppd
, keyword
);
1502 if (choice
&& strcmp(choice
->choice
, keyptr
))
1504 if (strcmp(choice
->choice
, "Custom"))
1506 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, choice
->choice
);
1509 else if ((customval
= cupsGetOption(keyword
, num_options
,
1512 cupsFilePrintf(out
, "*Default%s: %s\n", keyword
, customval
);
1516 cupsFilePrintf(out
, "%s\n", line
);
1519 cupsFilePrintf(out
, "%s\n", line
);
1523 if (!wrote_ipp_supplies
&&
1524 (boolval
= cupsGetOption("cupsIPPSupplies", num_options
,
1527 cupsFilePrintf(out
, "*cupsIPPSupplies: %s\n",
1528 (!_cups_strcasecmp(boolval
, "true") ||
1529 !_cups_strcasecmp(boolval
, "yes") ||
1530 !_cups_strcasecmp(boolval
, "on")) ? "True" : "False");
1533 if (!wrote_snmp_supplies
&&
1534 (boolval
= cupsGetOption("cupsSNMPSupplies", num_options
,
1537 cupsFilePrintf(out
, "*cupsSNMPSupplies: %s\n",
1538 (!_cups_strcasecmp(boolval
, "true") ||
1539 !_cups_strcasecmp(boolval
, "yes") ||
1540 !_cups_strcasecmp(boolval
, "on")) ? "True" : "False");
1551 ippDelete(cupsDoFileRequest(http
, request
, "/admin/",
1552 ppdchanged
? tempfile
: file
));
1555 * Clean up temp files... (TODO: catch signals in case we CTRL-C during
1559 if (ppdfile
!= file
)
1566 * No PPD file - just set the options...
1569 ippDelete(cupsDoRequest(http
, request
, "/admin/"));
1573 cupsFreeOptions(num_options
, options
);
1576 * Check the response...
1579 if (cupsLastError() > IPP_STATUS_OK_CONFLICTING
)
1581 _cupsLangPrintf(stderr
, _("%s: %s"), "lpadmin", cupsLastErrorString());
1591 * 'validate_name()' - Make sure the printer name only contains valid chars.
1594 static int /* O - 0 if name is no good, 1 if name is good */
1595 validate_name(const char *name
) /* I - Name to check */
1597 const char *ptr
; /* Pointer into name */
1601 * Scan the whole name...
1604 for (ptr
= name
; *ptr
; ptr
++)
1607 else if ((*ptr
>= 0 && *ptr
<= ' ') || *ptr
== 127 || *ptr
== '/' ||
1612 * All the characters are good; validate the length, too...
1615 return ((ptr
- name
) < 128);