#include <cups/cups.h>
#include <stdlib.h>
#include <errno.h>
#include <cups/language.h>
#include <cups/string.h>
#ifndef HAVE_HSTRERROR
# define hstrerror cups_hstrerror
const char *
cups_hstrerror(int error)
{
static const char * const errors[] =
{
"OK",
"Host not found.",
"Try again.",
"Unrecoverable lookup error.",
"No data associated with name."
};
if (error < 0 || error > 4)
return ("Unknown hostname lookup error.");
else
return (errors[error]);
}
#endif
int poll_server(http_t *http, cups_lang_t *language, ipp_op_t op,
int sock, int port, int interval, const char *prefix);
int
main(int argc,
char *argv[])
{
http_t *http;
cups_lang_t *language;
int interval;
int sock;
int port;
int val;
int seconds,
remain;
char prefix[1024];
setbuf(stderr, NULL);
if (argc != 5)
{
fputs("Usage: cups-polld server server-port interval port\n", stderr);
return (1);
}
interval = atoi(argv[3]);
port = atoi(argv[4]);
if (interval < 2)
interval = 2;
snprintf(prefix, sizeof(prefix), "[cups-polld %s:%d]", argv[1], atoi(argv[2]));
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
fprintf(stderr, "ERROR: %s Unable to open broadcast socket: %s\n", prefix,
strerror(errno));
return (1);
}
val = 1;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
{
fprintf(stderr, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
prefix, strerror(errno));
close(sock);
return (1);
}
while ((http = httpConnectEncrypt(argv[1], atoi(argv[2]),
cupsEncryption())) == NULL)
{
fprintf(stderr, "ERROR: %s Unable to connect to %s on port %s: %s\n",
prefix, argv[1], argv[2],
h_errno ? hstrerror(h_errno) : strerror(errno));
sleep (interval);
}
language = cupsLangDefault();
for (;;)
{
remain = interval;
if ((seconds = poll_server(http, language, CUPS_GET_PRINTERS, sock, port,
interval / 2, prefix)) > 0)
remain -= seconds;
if ((seconds = poll_server(http, language, CUPS_GET_CLASSES, sock, port,
interval / 2, prefix)) > 0)
remain -= seconds;
if (remain > 0)
sleep(remain);
}
return (0);
}
int
poll_server(http_t *http,
cups_lang_t *language,
ipp_op_t op,
int sock,
int port,
int interval,
const char *prefix)
{
int seconds;
int count,
max_count;
ipp_t *request,
*response;
ipp_attribute_t *attr;
const char *uri,
*info,
*location,
*make_model;
cups_ptype_t type;
ipp_pstate_t state;
struct sockaddr_in addr;
char packet[1540];
static const char * const attrs[] =
{
"printer-info",
"printer-location",
"printer-make-and-model",
"printer-name",
"printer-state",
"printer-type",
"printer-uri-supported"
};
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(0x7f000001);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
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);
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
NULL, attrs);
if ((response = cupsDoRequest(http, request, "/")) != NULL)
{
if (response->request.status.status_code > IPP_OK_CONFLICT)
{
fprintf(stderr, "ERROR: %s get-%s failed: %s\n", prefix,
op == CUPS_GET_PRINTERS ? "printers" : "classes",
ippErrorString(response->request.status.status_code));
ippDelete(response);
return (-1);
}
for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME),
max_count = 0;
attr != NULL;
attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME),
max_count ++);
fprintf(stderr, "DEBUG: %s found %d %s.\n", prefix, max_count,
op == CUPS_GET_PRINTERS ? "printers" : "classes");
count = 0;
seconds = time(NULL);
max_count = max_count / interval + 1;
for (attr = response->attrs; attr != NULL; attr = attr->next)
{
while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
attr = attr->next;
if (attr == NULL)
break;
uri = NULL;
info = "";
location = "";
make_model = "";
type = CUPS_PRINTER_REMOTE;
state = IPP_PRINTER_IDLE;
while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
{
if (strcmp(attr->name, "printer-uri-supported") == 0 &&
attr->value_tag == IPP_TAG_URI)
uri = attr->values[0].string.text;
if (strcmp(attr->name, "printer-info") == 0 &&
attr->value_tag == IPP_TAG_TEXT)
info = attr->values[0].string.text;
if (strcmp(attr->name, "printer-location") == 0 &&
attr->value_tag == IPP_TAG_TEXT)
location = attr->values[0].string.text;
if (strcmp(attr->name, "printer-make-and-model") == 0 &&
attr->value_tag == IPP_TAG_TEXT)
make_model = attr->values[0].string.text;
if (strcmp(attr->name, "printer-state") == 0 &&
attr->value_tag == IPP_TAG_ENUM)
state = (ipp_pstate_t)attr->values[0].integer;
if (strcmp(attr->name, "printer-type") == 0 &&
attr->value_tag == IPP_TAG_ENUM)
type = (cups_ptype_t)attr->values[0].integer;
attr = attr->next;
}
if (uri == NULL)
{
if (attr == NULL)
break;
else
continue;
}
if (!(type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
{
snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
type | CUPS_PRINTER_REMOTE, state, uri,
location, info, make_model);
fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet);
if (sendto(sock, packet, strlen(packet), 0,
(struct sockaddr *)&addr, sizeof(addr)) <= 0)
{
ippDelete(response);
perror("cups-polld");
return (-1);
}
count ++;
if (count >= max_count)
{
count = 0;
sleep(1);
}
}
if (attr == NULL)
break;
}
ippDelete(response);
}
else
{
fprintf(stderr, "ERROR: %s get-%s failed: %s\n", prefix,
op == CUPS_GET_PRINTERS ? "printers" : "classes",
ippErrorString(cupsLastError()));
return (-1);
}
return (time(NULL) - seconds);
}