#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <cups/cups.h>
#include <cups/string.h>
#include <cups/language.h>
#include <cups/debug.h>
#include <config.h>
#ifdef HAVE_LIBZ
# include <zlib.h>
#endif
static int add_printer_to_class(http_t *, char *, char *);
static int default_printer(http_t *, char *);
static int delete_printer(http_t *, char *);
static int delete_printer_from_class(http_t *, char *, char *);
static int enable_printer(http_t *, char *);
static char *get_line(char *, int, FILE *fp);
static int set_printer_device(http_t *, char *, char *);
static int set_printer_file(http_t *, char *, char *);
static int set_printer_info(http_t *, char *, char *);
static int set_printer_location(http_t *, char *, char *);
static int set_printer_model(http_t *, char *, char *);
static int set_printer_options(http_t *, char *, int, cups_option_t *);
static int validate_name(const char *);
int
main(int argc,
char *argv[])
{
int i;
http_t *http;
char *printer,
*pclass,
*val;
int num_options;
cups_option_t *options;
http = NULL;
printer = NULL;
num_options = 0;
options = NULL;
for (i = 1; i < argc; i ++)
if (argv[i][0] == '-')
switch (argv[i][1])
{
case 'c' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to add a printer to the class:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
pclass = argv[i] + 2;
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected class name after \'-c\' option!\n", stderr);
return (1);
}
pclass = argv[i];
}
if (!validate_name(pclass))
{
fputs("lpadmin: Class name can only contain printable characters!\n", stderr);
return (1);
}
if (add_printer_to_class(http, printer, pclass))
return (1);
break;
case 'd' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (argv[i][2])
printer = argv[i] + 2;
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected printer name after \'-d\' option!\n", stderr);
return (1);
}
printer = argv[i];
}
if (!validate_name(printer))
{
fputs("lpadmin: Printer name can only contain printable characters!\n", stderr);
return (1);
}
if (default_printer(http, printer))
return (1);
i = argc;
break;
case 'h' :
if (http)
{
httpClose(http);
http = NULL;
}
if (argv[i][2] != '\0')
cupsSetServer(argv[i] + 2);
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected hostname after \'-h\' option!\n", stderr);
return (1);
}
cupsSetServer(argv[i]);
}
break;
case 'i' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to set the interface script:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
{
if (set_printer_file(http, printer, argv[i] + 2))
return (1);
}
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected interface after \'-i\' option!\n", stderr);
return (1);
}
if (set_printer_file(http, printer, argv[i]))
return (1);
}
break;
case 'E' :
if (printer == NULL)
{
#ifdef HAVE_SSL
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
if (http)
httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
#else
fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
argv[0]);
#endif
break;
}
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (enable_printer(http, printer))
return (1);
break;
case 'm' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to set the interface script or PPD file:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
{
if (set_printer_model(http, printer, argv[i] + 2))
return (1);
}
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected model after \'-m\' option!\n", stderr);
return (1);
}
if (set_printer_model(http, printer, argv[i]))
return (1);
}
break;
case 'o' :
if (argv[i][2])
num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected name=value after \'-o\' option!\n", stderr);
return (1);
}
num_options = cupsParseOptions(argv[i], num_options, &options);
}
break;
case 'p' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (argv[i][2])
printer = argv[i] + 2;
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected printer after \'-p\' option!\n", stderr);
return (1);
}
printer = argv[i];
}
if (!validate_name(printer))
{
fputs("lpadmin: Printer name can only contain printable characters!\n", stderr);
return (1);
}
break;
case 'r' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to remove a printer from the class:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
pclass = argv[i] + 2;
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected class after \'-r\' option!\n", stderr);
return (1);
}
pclass = argv[i];
}
if (!validate_name(pclass))
{
fputs("lpadmin: Class name can only contain printable characters!\n", stderr);
return (1);
}
if (delete_printer_from_class(http, printer, pclass))
return (1);
break;
case 'u' :
if (argv[i][2])
val = argv[i] + 2;
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected allow/deny:userlist after \'-u\' option!\n", stderr);
return (1);
}
val = argv[i];
}
if (strncasecmp(val, "allow:", 6) == 0)
num_options = cupsAddOption("requesting-user-name-allowed",
val + 6, num_options, &options);
else if (strncasecmp(val, "deny:", 5) == 0)
num_options = cupsAddOption("requesting-user-name-denied",
val + 5, num_options, &options);
else
{
fprintf(stderr, "lpadmin: Unknown allow/deny option \"%s\"!\n",
val);
return (1);
}
break;
case 'v' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to set the device URI:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
{
if (set_printer_device(http, printer, argv[i] + 2))
return (1);
}
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected device URI after \'-v\' option!\n", stderr);
return (1);
}
if (set_printer_device(http, printer, argv[i]))
return (1);
}
break;
case 'x' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (argv[i][2])
printer = argv[i] + 2;
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected printer or class after \'-x\' option!\n", stderr);
return (1);
}
printer = argv[i];
}
if (!validate_name(printer))
{
fputs("lpadmin: Printer name can only contain printable characters!\n", stderr);
return (1);
}
if (delete_printer(http, printer))
return (1);
i = argc;
break;
case 'D' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to set the printer description:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
{
if (set_printer_info(http, printer, argv[i] + 2))
return (1);
}
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected description after \'-D\' option!\n", stderr);
return (1);
}
if (set_printer_info(http, printer, argv[i]))
return (1);
}
break;
case 'I' :
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected file type(s) after \'-I\' option!\n", stderr);
return (1);
}
fputs("lpadmin: Warning - content type list ignored!\n", stderr);
break;
case 'L' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to set the printer location:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
{
if (set_printer_location(http, printer, argv[i] + 2))
return (1);
}
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected location after \'-L\' option!\n", stderr);
return (1);
}
if (set_printer_location(http, printer, argv[i]))
return (1);
}
break;
case 'P' :
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to set the PPD file:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (argv[i][2])
{
if (set_printer_file(http, printer, argv[i] + 2))
return (1);
}
else
{
i ++;
if (i >= argc)
{
fputs("lpadmin: Expected PPD after \'-P\' option!\n", stderr);
return (1);
}
if (set_printer_file(http, printer, argv[i]))
return (1);
}
break;
default :
fprintf(stderr, "lpadmin: Unknown option \'%c\'!\n", argv[i][1]);
return (1);
}
else
{
fprintf(stderr, "lpadmin: Unknown argument \'%s\'!\n", argv[i]);
return (1);
}
if (num_options)
{
if (!http)
{
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
if (http == NULL)
{
perror("lpadmin: Unable to connect to server");
return (1);
}
}
if (printer == NULL)
{
fputs("lpadmin: Unable to set the printer options:\n", stderr);
fputs(" You must specify a printer name first!\n", stderr);
return (1);
}
if (set_printer_options(http, printer, num_options, options))
return (1);
}
if (printer == NULL)
{
puts("Usage:");
puts("");
puts(" lpadmin [-h server] -d destination");
puts(" lpadmin [-h server] -x destination");
puts(" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]");
puts(" [-r remove-class] [-v device] [-D description]");
puts(" [-P ppd-file] [-o name=value]");
puts(" [-u allow:user,user] [-u deny:user,user]");
puts("");
}
if (http)
httpClose(http);
return (0);
}
static int
add_printer_to_class(http_t *http,
char *printer,
char *pclass)
{
int i;
ipp_t *request,
*response;
ipp_attribute_t *attr,
*members;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http,
printer, pclass));
snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass);
request = ippNew();
request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
response = cupsDoRequest(http, request, "/");
request = ippNew();
request->request.op.operation_id = CUPS_ADD_CLASS;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
if (response != NULL &&
(members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) != NULL)
for (i = 0; i < members->num_values; i ++)
if (strcasecmp(printer, members->values[i].string.text) == 0)
{
fprintf(stderr, "lpadmin: Printer %s is already a member of class %s.\n",
printer, pclass);
ippDelete(request);
ippDelete(response);
return (0);
}
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
if (response != NULL &&
(members = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
{
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
"member-uris", members->num_values + 1, NULL, NULL);
for (i = 0; i < members->num_values; i ++)
attr->values[i].string.text = strdup(members->values[i].string.text);
attr->values[i].string.text = strdup(uri);
}
else
attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL, uri);
ippDelete(response);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: add-class failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add-class failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
default_printer(http_t *http,
char *printer)
{
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_SET_DEFAULT;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: set-default failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: set-default failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
delete_printer(http_t *http,
char *printer)
{
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_DELETE_PRINTER;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: delete-printer failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: delete-printer failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
delete_printer_from_class(http_t *http,
char *printer,
char *pclass)
{
int i, j, k;
ipp_t *request,
*response;
ipp_attribute_t *attr,
*members;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http,
printer, pclass));
snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass);
request = ippNew();
request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
response->request.status.status_code == IPP_NOT_FOUND)
{
ippDelete(response);
fprintf(stderr, "lpadmin: Class %s does not exist!\n", pclass);
return (1);
}
if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
{
ippDelete(response);
fputs("lpadmin: No member names were seen!\n", stderr);
return (1);
}
for (i = 0; i < members->num_values; i ++)
if (strcasecmp(printer, members->values[i].string.text) == 0)
break;
if (i >= members->num_values)
{
fprintf(stderr, "lpadmin: Printer %s is not a member of class %s.\n",
printer, pclass);
ippDelete(response);
return (1);
}
if (members->num_values == 1)
{
request = ippNew();
request->request.op.operation_id = CUPS_DELETE_CLASS;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
}
else
{
request = ippNew();
request->request.op.operation_id = CUPS_ADD_CLASS;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
"member-uris", members->num_values - 1, NULL, NULL);
for (j = 0, k = 0; j < members->num_values; j ++)
if (j != i)
attr->values[k ++].string.text = strdup(members->values[j].string.text);
}
ippDelete(response);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: add/delete-class failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add/delete-class failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
enable_printer(http_t *http,
char *printer)
{
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_ADD_PRINTER;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
IPP_PRINTER_IDLE);
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: add-printer (enable) failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add-printer (enable) failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static char *
get_line(char *buf,
int length,
FILE *fp)
{
char *bufptr;
int ch;
length --;
bufptr = buf;
while ((ch = getc(fp)) != EOF)
{
if (ch == '\n')
break;
else if (ch == '\r')
{
ch = getc(fp);
if (ch != '\n' && ch != EOF)
ungetc(ch, fp);
break;
}
*bufptr++ = ch;
length --;
if (length == 0)
break;
}
*bufptr = '\0';
if (ch == EOF)
return (NULL);
else
return (buf);
}
static int
set_printer_device(http_t *http,
char *printer,
char *device)
{
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("set_printer_device(%p, \"%s\", \"%s\")\n", http, printer,
device));
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_ADD_PRINTER;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
if (device[0] == '/')
{
snprintf(uri, sizeof(uri), "file:%s", device);
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
uri);
}
else
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
device);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: add-printer (set device) failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add-printer (set device) failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
set_printer_file(http_t *http,
char *printer,
char *file)
{
ipp_status_t status;
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
#ifdef HAVE_LIBZ
char tempfile[1024];
int fd;
gzFile *gz;
char buffer[8192];
int bytes;
DEBUG_printf(("set_printer_file(%p, \"%s\", \"%s\")\n", http, printer,
file));
if (strcmp(file + strlen(file) - 3, ".gz") == 0)
{
if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
{
perror("lpadmin: Unable to create temporary file");
return (1);
}
if ((gz = gzopen(file, "rb")) == NULL)
{
perror("lpadmin: Unable to open file");
close(fd);
unlink(tempfile);
return (1);
}
while ((bytes = gzread(gz, buffer, sizeof(buffer))) > 0)
write(fd, buffer, bytes);
close(fd);
gzclose(gz);
file = tempfile;
}
#endif
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_ADD_PRINTER;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
if ((response = cupsDoFileRequest(http, request, "/admin/", file)) == NULL)
status = cupsLastError();
else
{
status = response->request.status.status_code;
ippDelete(response);
}
#ifdef HAVE_LIBZ
if (file == tempfile)
unlink(tempfile);
#endif
if (status > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add-printer (set model) failed: %s\n",
ippErrorString(status));
return (1);
}
else
return (0);
}
static int
set_printer_info(http_t *http,
char *printer,
char *info)
{
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("set_printer_info(%p, \"%s\", \"%s\")\n", http, printer,
info));
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_ADD_PRINTER;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL,
info);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: add-printer (set description) failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add-printer (set description) failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
set_printer_location(http_t *http,
char *printer,
char *location)
{
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
DEBUG_printf(("set_printer_location(%p, \"%s\", \"%s\")\n", http, printer,
location));
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_ADD_PRINTER;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL,
location);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: add-printer (set location) failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add-printer (set location) failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
set_printer_model(http_t *http,
char *printer,
char *model)
{
ipp_t *request,
*response;
cups_lang_t *language;
char uri[HTTP_MAX_URI];
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = CUPS_ADD_PRINTER;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"ppd-name", NULL, model);
if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
{
fprintf(stderr, "lpadmin: add-printer (set model) failed: %s\n",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: add-printer (set model) failed: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
set_printer_options(http_t *http,
char *printer,
int num_options,
cups_option_t *options)
{
ipp_t *request,
*response;
ipp_attribute_t *attr;
cups_lang_t *language;
ipp_op_t op;
const char *val,
*ppdfile;
char uri[HTTP_MAX_URI],
line[1024],
keyword[1024],
*keyptr,
tempfile[1024];
FILE *in,
*out;
int outfd;
const char *protocol;
DEBUG_printf(("set_printer_options(%p, \"%s\", %d, %p)\n", http, printer,
num_options, options));
language = cupsLangDefault();
snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
request = ippNew();
request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
request->request.op.request_id = 1;
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", NULL, "printer-type");
op = CUPS_ADD_PRINTER;
if ((response = cupsDoRequest(http, request, "/")) != NULL)
{
if ((attr = ippFindAttribute(response, "printer-type", IPP_TAG_ENUM)) != NULL)
{
if (attr->values[0].integer & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
{
op = CUPS_ADD_CLASS;
snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", printer);
}
}
ippDelete(response);
}
request = ippNew();
request->request.op.operation_id = op;
request->request.op.request_id = 1;
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
cupsEncodeOptions(request, num_options, options);
if (op == CUPS_ADD_PRINTER)
ppdfile = cupsGetPPD(printer);
else
ppdfile = NULL;
if (ppdfile != NULL)
{
if ((outfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
{
fprintf(stderr, "lpadmin: Unable to create temporary file - %s\n",
strerror(errno));
ippDelete(request);
unlink(ppdfile);
return (1);
}
if ((in = fopen(ppdfile, "rb")) == NULL)
{
fprintf(stderr, "lpadmin: Unable to open PPD file \"%s\" - %s\n",
ppdfile, strerror(errno));
ippDelete(request);
unlink(ppdfile);
close(outfd);
unlink(tempfile);
return (1);
}
out = fdopen(outfd, "wb");
protocol = cupsGetOption("protocol", num_options, options);
while (get_line(line, sizeof(line), in) != NULL)
{
if (!strncmp(line, "*cupsProtocol:", 14) && protocol)
{
continue;
}
else if (strncmp(line, "*Default", 8))
fprintf(out, "%s\n", line);
else
{
strlcpy(keyword, line + 8, sizeof(keyword));
for (keyptr = keyword; *keyptr; keyptr ++)
if (*keyptr == ':' || isspace(*keyptr & 255))
break;
*keyptr = '\0';
if (strcmp(keyword, "PageRegion") == 0)
val = cupsGetOption("PageSize", num_options, options);
else
val = cupsGetOption(keyword, num_options, options);
if (val != NULL)
fprintf(out, "*Default%s: %s\n", keyword, val);
else
fprintf(out, "%s\n", line);
}
}
if (protocol)
fprintf(out, "*cupsProtocol: \"%s\"\n", protocol);
fclose(in);
fclose(out);
close(outfd);
response = cupsDoFileRequest(http, request, "/admin/", tempfile);
unlink(ppdfile);
unlink(tempfile);
}
else
{
response = cupsDoRequest(http, request, "/admin/");
}
if (response == NULL)
{
fprintf(stderr, "lpadmin: %s failed: %s\n",
op == CUPS_ADD_PRINTER ? "add-printer" : "add-class",
ippErrorString(cupsLastError()));
return (1);
}
else if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "lpadmin: %s failed: %s\n",
op == CUPS_ADD_PRINTER ? "add-printer" : "add-class",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (1);
}
else
{
ippDelete(response);
return (0);
}
}
static int
validate_name(const char *name)
{
const char *ptr;
for (ptr = name; *ptr; ptr ++)
if (*ptr == '@')
break;
else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/')
return (0);
return ((ptr - name) < 128);
}