#include <cups/cups.h>
#include <stdlib.h>
#include <cups/language.h>
#include <cups/string.h>
int poll_server(http_t *http, cups_lang_t *language, ipp_op_t op,
int sock, int port, int interval);
int
main(int argc,
char *argv[])
{
http_t *http;
cups_lang_t *language;
int interval;
int sock;
int port;
int val;
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 ((http = httpConnectEncrypt(argv[1], atoi(argv[2]),
cupsEncryption())) == NULL)
{
perror("cups-polld");
return (1);
}
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("cups-polld");
httpClose(http);
return (1);
}
val = 1;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
{
perror("cups-polld");
close(sock);
httpClose(http);
return (1);
}
language = cupsLangDefault();
for (;;)
{
if (!poll_server(http, language, CUPS_GET_PRINTERS, sock, port,
interval / 2))
{
poll_server(http, language, CUPS_GET_CLASSES, sock, port, interval / 2);
}
else
{
sleep(interval);
}
}
}
int
poll_server(http_t *http,
cups_lang_t *language,
ipp_op_t op,
int sock,
int port,
int interval)
{
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 *attrs[] =
{
"printer-info",
"printer-location",
"printer-make-and-model",
"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;
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);
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, "cups-polld: get-%s failed: %s\n",
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 ++);
count = 0;
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);
puts(packet);
if (sendto(sock, packet, strlen(packet), 0,
(struct sockaddr *)&addr, sizeof(addr)) <= 0)
{
perror("cups-polld");
return (-1);
}
count ++;
if (count >= max_count)
{
count = 0;
sleep(1);
interval --;
}
}
if (attr == NULL)
break;
}
ippDelete(response);
}
else
{
fprintf(stderr, "cups-polld: get-%s failed: %s\n",
op == CUPS_GET_PRINTERS ? "printers" : "classes",
ippErrorString(cupsLastError()));
return (-1);
}
if (interval)
sleep(interval);
return (0);
}