2
* "$Id: dbus.c 3933 2012-10-01 03:01:10Z msweet $"
4
* D-Bus notifier for CUPS.
6
* Copyright 2008-2012 by Apple Inc.
7
* Copyright (C) 2011 Red Hat, Inc.
8
* Copyright (C) 2007 Tim Waugh <twaugh@redhat.com>
9
* Copyright 1997-2005 by Easy Software Products.
11
* These coded instructions, statements, and computer programs are the
12
* property of Apple Inc. and are protected by Federal copyright
13
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
14
* which should have been included with this file. If this file is
15
* file is missing or damaged, see the license at "http://www.cups.org/".
19
* main() - Read events and send DBUS notifications.
20
* acquire_lock() - Acquire a lock so we only have a single notifier running.
24
* Include necessary headers...
27
#include <cups/cups.h>
28
#include <cups/string-private.h>
32
#include <sys/types.h>
39
# include <dbus/dbus.h>
40
# ifdef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND
41
# define dbus_message_append_iter_init dbus_message_iter_init_append
42
# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, v)
43
# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, v)
44
# define dbus_message_iter_append_boolean(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, v)
45
# endif /* HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */
49
* D-Bus object: org.cups.cupsd.Notifier
50
* D-Bus object path: /org/cups/cupsd/Notifier
52
* D-Bus interface name: org.cups.cupsd.Notifier
56
* ServerRestarted(STRING text)
57
* Server has restarted.
59
* ServerStarted(STRING text)
62
* ServerStopped(STRING text)
65
* ServerAudit(STRING text)
66
* Security-related event.
68
* PrinterRestarted(STRING text,
70
* STRING printer-name,
71
* UINT32 printer-state,
72
* STRING printer-state-reasons,
73
* BOOLEAN printer-is-accepting-jobs)
74
* Printer has restarted.
76
* PrinterShutdown(STRING text,
78
* STRING printer-name,
79
* UINT32 printer-state,
80
* STRING printer-state-reasons,
81
* BOOLEAN printer-is-accepting-jobs)
82
* Printer has shutdown.
84
* PrinterStopped(STRING text,
86
* STRING printer-name,
87
* UINT32 printer-state,
88
* STRING printer-state-reasons,
89
* BOOLEAN printer-is-accepting-jobs)
90
* Printer has stopped.
92
* PrinterStateChanged(STRING text,
94
* STRING printer-name,
95
* UINT32 printer-state,
96
* STRING printer-state-reasons,
97
* BOOLEAN printer-is-accepting-jobs)
98
* Printer state has changed.
100
* PrinterFinishingsChanged(STRING text,
101
* STRING printer-uri,
102
* STRING printer-name,
103
* UINT32 printer-state,
104
* STRING printer-state-reasons,
105
* BOOLEAN printer-is-accepting-jobs)
106
* Printer's finishings-supported attribute has changed.
108
* PrinterMediaChanged(STRING text,
109
* STRING printer-uri,
110
* STRING printer-name,
111
* UINT32 printer-state,
112
* STRING printer-state-reasons,
113
* BOOLEAN printer-is-accepting-jobs)
114
* Printer's media-supported attribute has changed.
116
* PrinterAdded(STRING text,
117
* STRING printer-uri,
118
* STRING printer-name,
119
* UINT32 printer-state,
120
* STRING printer-state-reasons,
121
* BOOLEAN printer-is-accepting-jobs)
122
* Printer has been added.
124
* PrinterDeleted(STRING text,
125
* STRING printer-uri,
126
* STRING printer-name,
127
* UINT32 printer-state,
128
* STRING printer-state-reasons,
129
* BOOLEAN printer-is-accepting-jobs)
130
* Printer has been deleted.
132
* PrinterModified(STRING text,
133
* STRING printer-uri,
134
* STRING printer-name,
135
* UINT32 printer-state,
136
* STRING printer-state-reasons,
137
* BOOLEAN printer-is-accepting-jobs)
138
* Printer has been modified.
140
* text describes the event.
141
* printer-state-reasons is a comma-separated list.
142
* If printer-uri is "" in a Job* signal, the other printer-* parameters
144
* If the job name is not know, job-name will be "".
163
static int acquire_lock(int *fd, char *lockfile, size_t locksize);
164
static const char *validate_utf8(const char *str);
168
* 'validate_utf8()' - Convert to valid UTF-8
172
validate_utf8 (const char *str)
174
static char *buffer = NULL;
175
static size_t buflen = 0;
179
mbstate_t instate, outstate;
189
/* Is it already valid? */
190
if (mbstowcs (NULL, str, 0) != (size_t) -1)
193
/* Make sure our buffer is at least as large as the input string */
194
str_len = strlen (str);
195
if (str_len >= buflen)
198
/* Set encoding type to UTF-8 the first time we need to */
199
setlocale (LC_CTYPE, "C.UTF-8");
201
buflen = str_len + 1;
202
buffer = realloc (buffer, buflen);
205
memset (&instate, '\0', sizeof (mbstate_t));
206
memset (&outstate, '\0', sizeof (mbstate_t));
212
size_t used, written;
213
mbstate_t orig_instate = instate;
214
used = mbrtowc (&wc, str + i, str_len - i, &instate);
219
wc = L'?'; /* so replacement is never longer than original char */
220
instate = orig_instate;
226
written = wcrtomb (p, wc, &outstate);
230
assert (p - buffer < buflen);
241
* 'main()' - Read events and send DBUS notifications.
244
int /* O - Exit status */
245
main(int argc, /* I - Number of command-line args */
246
char *argv[]) /* I - Command-line arguments */
248
ipp_t *msg; /* Event message from scheduler */
249
ipp_state_t state; /* IPP event state */
250
struct sigaction action; /* POSIX sigaction data */
251
DBusConnection *con = NULL; /* Connection to DBUS server */
252
DBusError error; /* Error, if any */
253
DBusMessage *message; /* Message to send */
254
DBusMessageIter iter; /* Iterator for message data */
255
int lock_fd = -1; /* Lock file descriptor */
256
char lock_filename[1024];
261
* Don't buffer stderr...
264
setbuf(stderr, NULL);
267
* Ignore SIGPIPE signals...
270
memset(&action, 0, sizeof(action));
271
action.sa_handler = SIG_IGN;
272
sigaction(SIGPIPE, &action, NULL);
275
* Validate command-line options...
280
fputs("Usage: dbus dbus:/// notify-user-data\n", stderr);
284
if (strncmp(argv[1], "dbus:", 5))
286
fprintf(stderr, "ERROR: Bad URI \"%s\"!\n", argv[1]);
291
* Loop forever until we run out of events...
296
ipp_attribute_t *attr; /* Current attribute */
297
const char *event; /* Event name */
298
const char *signame = NULL;/* DBUS signal name */
299
char *printer_reasons = NULL;
300
/* Printer reasons string */
301
char *job_reasons = NULL;
302
/* Job reasons string */
303
const char *nul = ""; /* Empty string value */
304
int no = 0; /* Boolean "no" value */
305
int params = PARAMS_NONE;
306
/* What parameters to include? */
311
* Get the next event...
315
while ((state = ippReadFile(0, msg)) != IPP_DATA)
317
if (state <= IPP_IDLE)
321
fprintf(stderr, "DEBUG: state=%d\n", state);
323
if (state == IPP_ERROR)
324
fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
326
if (state <= IPP_IDLE)
329
* Out of messages, free memory and then exit...
337
* Verify connection to DBUS server...
340
if (con && !dbus_connection_get_is_connected(con))
342
dbus_connection_unref(con);
348
dbus_error_init(&error);
350
con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
352
dbus_error_free(&error);
354
fputs("DEBUG: Connected to D-BUS\n", stderr);
361
acquire_lock(&lock_fd, lock_filename, sizeof(lock_filename)))
364
attr = ippFindAttribute(msg, "notify-subscribed-event",
369
event = ippGetString(attr, 0, NULL);
370
if (!strncmp(event, "server-", 7))
372
const char *word2 = event + 7; /* Second word */
374
if (!strcmp(word2, "restarted"))
375
signame = "ServerRestarted";
376
else if (!strcmp(word2, "started"))
377
signame = "ServerStarted";
378
else if (!strcmp(word2, "stopped"))
379
signame = "ServerStopped";
380
else if (!strcmp(word2, "audit"))
381
signame = "ServerAudit";
385
else if (!strncmp(event, "printer-", 8))
387
const char *word2 = event + 8; /* Second word */
389
params = PARAMS_PRINTER;
390
if (!strcmp(word2, "restarted"))
391
signame = "PrinterRestarted";
392
else if (!strcmp(word2, "shutdown"))
393
signame = "PrinterShutdown";
394
else if (!strcmp(word2, "stopped"))
395
signame = "PrinterStopped";
396
else if (!strcmp(word2, "state-changed"))
397
signame = "PrinterStateChanged";
398
else if (!strcmp(word2, "finishings-changed"))
399
signame = "PrinterFinishingsChanged";
400
else if (!strcmp(word2, "media-changed"))
401
signame = "PrinterMediaChanged";
402
else if (!strcmp(word2, "added"))
403
signame = "PrinterAdded";
404
else if (!strcmp(word2, "deleted"))
405
signame = "PrinterDeleted";
406
else if (!strcmp(word2, "modified"))
407
signame = "PrinterModified";
411
else if (!strncmp(event, "job-", 4))
413
const char *word2 = event + 4; /* Second word */
416
if (!strcmp(word2, "state-changed"))
417
signame = "JobState";
418
else if (!strcmp(word2, "created"))
419
signame = "JobCreated";
420
else if (!strcmp(word2, "completed"))
421
signame = "JobCompleted";
422
else if (!strcmp(word2, "stopped"))
423
signame = "JobStopped";
424
else if (!strcmp(word2, "config-changed"))
425
signame = "JobConfigChanged";
426
else if (!strcmp(word2, "progress"))
427
signame = "JobProgress";
435
* Create and send the new message...
438
fprintf(stderr, "DEBUG: %s\n", signame);
439
message = dbus_message_new_signal("/org/cups/cupsd/Notifier",
440
"org.cups.cupsd.Notifier",
443
dbus_message_append_iter_init(message, &iter);
444
attr = ippFindAttribute(msg, "notify-text", IPP_TAG_TEXT);
447
const char *val = validate_utf8 (ippGetString(attr, 0, NULL));
448
if (!dbus_message_iter_append_string(&iter, &val))
454
if (params >= PARAMS_PRINTER)
456
char *p; /* Pointer into printer_reasons */
457
size_t reasons_length; /* Required size of printer_reasons */
458
int i; /* Looping var */
459
int have_printer_params = 1;/* Do we have printer URI? */
461
/* STRING printer-uri or "" */
462
attr = ippFindAttribute(msg, "notify-printer-uri", IPP_TAG_URI);
465
const char *val = ippGetString(attr, 0, NULL);
466
if (!dbus_message_iter_append_string(&iter, &val))
471
have_printer_params = 0;
472
dbus_message_iter_append_string(&iter, &nul);
475
/* STRING printer-name */
476
if (have_printer_params)
478
attr = ippFindAttribute(msg, "printer-name", IPP_TAG_NAME);
481
const char *val = ippGetString(attr, 0, NULL);
482
if (!dbus_message_iter_append_string(&iter, &val))
489
dbus_message_iter_append_string(&iter, &nul);
491
/* UINT32 printer-state */
492
if (have_printer_params)
494
attr = ippFindAttribute(msg, "printer-state", IPP_TAG_ENUM);
497
dbus_uint32_t val = ippGetInteger(attr, 0);
498
dbus_message_iter_append_uint32(&iter, &val);
504
dbus_message_iter_append_uint32(&iter, &no);
506
/* STRING printer-state-reasons */
507
if (have_printer_params)
509
attr = ippFindAttribute(msg, "printer-state-reasons",
513
int num_values = ippGetCount(attr);
514
for (reasons_length = 0, i = 0; i < num_values; i++)
515
/* All need commas except the last, which needs a nul byte. */
516
reasons_length += 1 + strlen(ippGetString(attr, i, NULL));
517
printer_reasons = malloc(reasons_length);
518
if (!printer_reasons)
521
for (i = 0; i < num_values; i++)
526
strlcpy(p, ippGetString(attr, i, NULL),
527
reasons_length - (p - printer_reasons));
530
if (!dbus_message_iter_append_string(&iter, &printer_reasons))
537
dbus_message_iter_append_string(&iter, &nul);
539
/* BOOL printer-is-accepting-jobs */
540
if (have_printer_params)
542
attr = ippFindAttribute(msg, "printer-is-accepting-jobs",
546
dbus_bool_t val = ippGetBoolean(attr, 0);
547
dbus_message_iter_append_boolean(&iter, &val);
553
dbus_message_iter_append_boolean(&iter, &no);
556
if (params >= PARAMS_JOB)
558
char *p; /* Pointer into job_reasons */
559
size_t reasons_length; /* Required size of job_reasons */
560
int i; /* Looping var */
563
attr = ippFindAttribute(msg, "notify-job-id", IPP_TAG_INTEGER);
566
dbus_uint32_t val = ippGetInteger(attr, 0);
567
dbus_message_iter_append_uint32(&iter, &val);
572
/* UINT32 job-state */
573
attr = ippFindAttribute(msg, "job-state", IPP_TAG_ENUM);
576
dbus_uint32_t val = ippGetInteger(attr, 0);
577
dbus_message_iter_append_uint32(&iter, &val);
582
/* STRING job-state-reasons */
583
attr = ippFindAttribute(msg, "job-state-reasons", IPP_TAG_KEYWORD);
586
int num_values = ippGetCount(attr);
587
for (reasons_length = 0, i = 0; i < num_values; i++)
588
/* All need commas except the last, which needs a nul byte. */
589
reasons_length += 1 + strlen(ippGetString(attr, i, NULL));
590
job_reasons = malloc(reasons_length);
594
for (i = 0; i < num_values; i++)
599
strlcpy(p, ippGetString(attr, i, NULL),
600
reasons_length - (p - job_reasons));
603
if (!dbus_message_iter_append_string(&iter, &job_reasons))
609
/* STRING job-name or "" */
610
attr = ippFindAttribute(msg, "job-name", IPP_TAG_NAME);
613
const char *val = validate_utf8(ippGetString(attr, 0, NULL));
614
if (!dbus_message_iter_append_string(&iter, &val))
618
dbus_message_iter_append_string(&iter, &nul);
620
/* UINT32 job-impressions-completed */
621
attr = ippFindAttribute(msg, "job-impressions-completed",
625
dbus_uint32_t val = ippGetInteger(attr, 0);
626
dbus_message_iter_append_uint32(&iter, &val);
632
dbus_connection_send(con, message, NULL);
633
dbus_connection_flush(con);
641
dbus_message_unref(message);
644
free(printer_reasons);
653
* Remove lock file...
659
unlink(lock_filename);
667
* 'acquire_lock()' - Acquire a lock so we only have a single notifier running.
670
static int /* O - 0 on success, -1 on failure */
671
acquire_lock(int *fd, /* O - Lock file descriptor */
672
char *lockfile, /* I - Lock filename buffer */
673
size_t locksize) /* I - Size of filename buffer */
675
const char *tmpdir; /* Temporary directory */
679
* Figure out where to put the lock file...
682
if ((tmpdir = getenv("TMPDIR")) == NULL)
685
snprintf(lockfile, locksize, "%s/cups-dbus-notifier-lockfile", tmpdir);
688
* Create the lock file and fail if it already exists...
691
if ((*fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
696
#else /* !HAVE_DBUS */
702
#endif /* HAVE_DBUS */
706
* End of "$Id: dbus.c 3933 2012-10-01 03:01:10Z msweet $".