#include <cups/cups.h>
#include <cups/string-private.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_DBUS
# include <dbus/dbus.h>
# ifdef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND
# define dbus_message_append_iter_init dbus_message_iter_init_append
# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, v)
# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, v)
# define dbus_message_iter_append_boolean(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, v)
# endif
enum
{
PARAMS_NONE,
PARAMS_PRINTER,
PARAMS_JOB
};
static int acquire_lock(int *fd, char *lockfile, size_t locksize);
int
main(int argc,
char *argv[])
{
ipp_t *msg;
ipp_state_t state;
struct sigaction action;
DBusConnection *con = NULL;
DBusError error;
DBusMessage *message;
DBusMessageIter iter;
int lock_fd = -1;
char lock_filename[1024];
setbuf(stderr, NULL);
memset(&action, 0, sizeof(action));
action.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &action, NULL);
if (argc != 3)
{
fputs("Usage: dbus dbus:/// notify-user-data\n", stderr);
return (1);
}
if (strncmp(argv[1], "dbus:", 5))
{
fprintf(stderr, "ERROR: Bad URI \"%s\"!\n", argv[1]);
return (1);
}
for (;;)
{
ipp_attribute_t *attr;
const char *event;
const char *signame = NULL;
char *printer_reasons = NULL;
char *job_reasons = NULL;
const char *nul = "";
int no = 0;
int params = PARAMS_NONE;
msg = ippNew();
while ((state = ippReadFile(0, msg)) != IPP_DATA)
{
if (state <= IPP_IDLE)
break;
}
fprintf(stderr, "DEBUG: state=%d\n", state);
if (state == IPP_ERROR)
fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
if (state <= IPP_IDLE)
{
ippDelete(msg);
break;
}
if (con && !dbus_connection_get_is_connected(con))
{
dbus_connection_unref(con);
con = NULL;
}
if (!con)
{
dbus_error_init(&error);
con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if (!con)
dbus_error_free(&error);
else
fputs("DEBUG: Connected to D-BUS\n", stderr);
}
if (!con)
continue;
if (lock_fd == -1 &&
acquire_lock(&lock_fd, lock_filename, sizeof(lock_filename)))
continue;
attr = ippFindAttribute(msg, "notify-subscribed-event",
IPP_TAG_KEYWORD);
if (!attr)
continue;
event = ippGetString(attr, 0, NULL);
if (!strncmp(event, "server-", 7))
{
const char *word2 = event + 7;
if (!strcmp(word2, "restarted"))
signame = "ServerRestarted";
else if (!strcmp(word2, "started"))
signame = "ServerStarted";
else if (!strcmp(word2, "stopped"))
signame = "ServerStopped";
else if (!strcmp(word2, "audit"))
signame = "ServerAudit";
else
continue;
}
else if (!strncmp(event, "printer-", 8))
{
const char *word2 = event + 8;
params = PARAMS_PRINTER;
if (!strcmp(word2, "restarted"))
signame = "PrinterRestarted";
else if (!strcmp(word2, "shutdown"))
signame = "PrinterShutdown";
else if (!strcmp(word2, "stopped"))
signame = "PrinterStopped";
else if (!strcmp(word2, "state-changed"))
signame = "PrinterStateChanged";
else if (!strcmp(word2, "finishings-changed"))
signame = "PrinterFinishingsChanged";
else if (!strcmp(word2, "media-changed"))
signame = "PrinterMediaChanged";
else if (!strcmp(word2, "added"))
signame = "PrinterAdded";
else if (!strcmp(word2, "deleted"))
signame = "PrinterDeleted";
else if (!strcmp(word2, "modified"))
signame = "PrinterModified";
else
continue;
}
else if (!strncmp(event, "job-", 4))
{
const char *word2 = event + 4;
params = PARAMS_JOB;
if (!strcmp(word2, "state-changed"))
signame = "JobState";
else if (!strcmp(word2, "created"))
signame = "JobCreated";
else if (!strcmp(word2, "completed"))
signame = "JobCompleted";
else if (!strcmp(word2, "stopped"))
signame = "JobStopped";
else if (!strcmp(word2, "config-changed"))
signame = "JobConfigChanged";
else if (!strcmp(word2, "progress"))
signame = "JobProgress";
else
continue;
}
else
continue;
fprintf(stderr, "DEBUG: %s\n", signame);
message = dbus_message_new_signal("/org/cups/cupsd/Notifier",
"org.cups.cupsd.Notifier",
signame);
dbus_message_append_iter_init(message, &iter);
attr = ippFindAttribute(msg, "notify-text", IPP_TAG_TEXT);
if (attr)
{
const char *val = ippGetString(attr, 0, NULL);
if (!dbus_message_iter_append_string(&iter, &val))
goto bail;
}
else
goto bail;
if (params >= PARAMS_PRINTER)
{
char *p;
size_t reasons_length;
int i;
int have_printer_params = 1;
attr = ippFindAttribute(msg, "notify-printer-uri", IPP_TAG_URI);
if (attr)
{
const char *val = ippGetString(attr, 0, NULL);
if (!dbus_message_iter_append_string(&iter, &val))
goto bail;
}
else
{
have_printer_params = 0;
dbus_message_iter_append_string(&iter, &nul);
}
if (have_printer_params)
{
attr = ippFindAttribute(msg, "printer-name", IPP_TAG_NAME);
if (attr)
{
const char *val = ippGetString(attr, 0, NULL);
if (!dbus_message_iter_append_string(&iter, &val))
goto bail;
}
else
goto bail;
}
else
dbus_message_iter_append_string(&iter, &nul);
if (have_printer_params)
{
attr = ippFindAttribute(msg, "printer-state", IPP_TAG_ENUM);
if (attr)
{
dbus_uint32_t val = ippGetInteger(attr, 0);
dbus_message_iter_append_uint32(&iter, &val);
}
else
goto bail;
}
else
dbus_message_iter_append_uint32(&iter, &no);
if (have_printer_params)
{
attr = ippFindAttribute(msg, "printer-state-reasons",
IPP_TAG_KEYWORD);
if (attr)
{
int num_values = ippGetCount(attr);
for (reasons_length = 0, i = 0; i < num_values; i++)
reasons_length += 1 + strlen(ippGetString(attr, i, NULL));
printer_reasons = malloc(reasons_length);
if (!printer_reasons)
goto bail;
p = printer_reasons;
for (i = 0; i < num_values; i++)
{
if (i)
*p++ = ',';
strcpy(p, ippGetString(attr, i, NULL));
p += strlen(p);
}
if (!dbus_message_iter_append_string(&iter, &printer_reasons))
goto bail;
}
else
goto bail;
}
else
dbus_message_iter_append_string(&iter, &nul);
if (have_printer_params)
{
attr = ippFindAttribute(msg, "printer-is-accepting-jobs",
IPP_TAG_BOOLEAN);
if (attr)
{
dbus_bool_t val = ippGetBoolean(attr, 0);
dbus_message_iter_append_boolean(&iter, &val);
}
else
goto bail;
}
else
dbus_message_iter_append_boolean(&iter, &no);
}
if (params >= PARAMS_JOB)
{
char *p;
size_t reasons_length;
int i;
attr = ippFindAttribute(msg, "notify-job-id", IPP_TAG_INTEGER);
if (attr)
{
dbus_uint32_t val = ippGetInteger(attr, 0);
dbus_message_iter_append_uint32(&iter, &val);
}
else
goto bail;
attr = ippFindAttribute(msg, "job-state", IPP_TAG_ENUM);
if (attr)
{
dbus_uint32_t val = ippGetInteger(attr, 0);
dbus_message_iter_append_uint32(&iter, &val);
}
else
goto bail;
attr = ippFindAttribute(msg, "job-state-reasons", IPP_TAG_KEYWORD);
if (attr)
{
int num_values = ippGetCount(attr);
for (reasons_length = 0, i = 0; i < num_values; i++)
reasons_length += 1 + strlen(ippGetString(attr, i, NULL));
job_reasons = malloc(reasons_length);
if (!job_reasons)
goto bail;
p = job_reasons;
for (i = 0; i < num_values; i++)
{
if (i)
*p++ = ',';
strcpy(p, ippGetString(attr, i, NULL));
p += strlen(p);
}
if (!dbus_message_iter_append_string(&iter, &job_reasons))
goto bail;
}
else
goto bail;
attr = ippFindAttribute(msg, "job-name", IPP_TAG_NAME);
if (attr)
{
const char *val = ippGetString(attr, 0, NULL);
if (!dbus_message_iter_append_string(&iter, &val))
goto bail;
}
else
dbus_message_iter_append_string(&iter, &nul);
attr = ippFindAttribute(msg, "job-impressions-completed",
IPP_TAG_INTEGER);
if (attr)
{
dbus_uint32_t val = ippGetInteger(attr, 0);
dbus_message_iter_append_uint32(&iter, &val);
}
else
goto bail;
}
dbus_connection_send(con, message, NULL);
dbus_connection_flush(con);
bail:
dbus_message_unref(message);
if (printer_reasons)
free(printer_reasons);
if (job_reasons)
free(job_reasons);
ippDelete(msg);
}
if (lock_fd >= 0)
{
close(lock_fd);
unlink(lock_filename);
}
return (0);
}
static int
acquire_lock(int *fd,
char *lockfile,
size_t locksize)
{
const char *tmpdir;
if ((tmpdir = getenv("TMPDIR")) == NULL)
tmpdir = "/tmp";
snprintf(lockfile, locksize, "%s/cups-dbus-notifier-lockfile", tmpdir);
if ((*fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
return (-1);
else
return (0);
}
#else
int
main(void)
{
return (1);
}
#endif