]> git.ipfire.org Git - thirdparty/cups.git/blame - notifier/dbus.c
Merge changes from CUPS 1.6svn-r10024.
[thirdparty/cups.git] / notifier / dbus.c
CommitLineData
c5571a1d
MS
1/*
2 * "$Id$"
3 *
71e16022 4 * D-Bus notifier for CUPS.
c5571a1d 5 *
71e16022 6 * Copyright 2008-2010 by Apple Inc.
c5571a1d
MS
7 * Copyright (C) 2007 Red Hat, Inc.
8 * Copyright (C) 2007 Tim Waugh <twaugh@redhat.com>
9 * Copyright 1997-2005 by Easy Software Products.
10 *
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/".
16 *
17 * Contents:
18 *
49d87452
MS
19 * main() - Read events and send DBUS notifications.
20 * acquire_lock() - Acquire a lock so we only have a single notifier running.
c5571a1d
MS
21 */
22
23/*
24 * Include necessary headers...
25 */
26
27#include <cups/cups.h>
71e16022 28#include <cups/string-private.h>
c5571a1d
MS
29#include <fcntl.h>
30#include <signal.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <unistd.h>
34
35#include <dbus/dbus.h>
36#ifdef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND
37# define dbus_message_append_iter_init dbus_message_iter_init_append
38# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, v)
39# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, v)
40# define dbus_message_iter_append_boolean(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, v)
41#endif /* HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */
42
43
44/*
45 * D-Bus object: org.cups.cupsd.Notifier
46 * D-Bus object path: /org/cups/cupsd/Notifier
47 *
48 * D-Bus interface name: org.cups.cupsd.Notifier
49 *
50 * Signals:
51 *
52 * ServerRestarted(STRING text)
53 * Server has restarted.
54 *
55 * ServerStarted(STRING text)
56 * Server has started.
57 *
58 * ServerStopped(STRING text)
59 * Server has stopped.
60 *
61 * ServerAudit(STRING text)
62 * Security-related event.
63 *
64 * PrinterRestarted(STRING text,
65 * STRING printer-uri,
66 * STRING printer-name,
67 * UINT32 printer-state,
68 * STRING printer-state-reasons,
69 * BOOLEAN printer-is-accepting-jobs)
70 * Printer has restarted.
71 *
72 * PrinterShutdown(STRING text,
73 * STRING printer-uri,
74 * STRING printer-name,
75 * UINT32 printer-state,
76 * STRING printer-state-reasons,
77 * BOOLEAN printer-is-accepting-jobs)
78 * Printer has shutdown.
79 *
80 * PrinterStopped(STRING text,
81 * STRING printer-uri,
82 * STRING printer-name,
83 * UINT32 printer-state,
84 * STRING printer-state-reasons,
85 * BOOLEAN printer-is-accepting-jobs)
86 * Printer has stopped.
87 *
88 * PrinterStateChanged(STRING text,
89 * STRING printer-uri,
90 * STRING printer-name,
91 * UINT32 printer-state,
92 * STRING printer-state-reasons,
93 * BOOLEAN printer-is-accepting-jobs)
94 * Printer state has changed.
95 *
96 * PrinterFinishingsChanged(STRING text,
97 * STRING printer-uri,
98 * STRING printer-name,
99 * UINT32 printer-state,
100 * STRING printer-state-reasons,
101 * BOOLEAN printer-is-accepting-jobs)
102 * Printer's finishings-supported attribute has changed.
103 *
104 * PrinterMediaChanged(STRING text,
105 * STRING printer-uri,
106 * STRING printer-name,
107 * UINT32 printer-state,
108 * STRING printer-state-reasons,
109 * BOOLEAN printer-is-accepting-jobs)
110 * Printer's media-supported attribute has changed.
111 *
112 * PrinterAdded(STRING text,
113 * STRING printer-uri,
114 * STRING printer-name,
115 * UINT32 printer-state,
116 * STRING printer-state-reasons,
117 * BOOLEAN printer-is-accepting-jobs)
118 * Printer has been added.
119 *
120 * PrinterDeleted(STRING text,
121 * STRING printer-uri,
122 * STRING printer-name,
123 * UINT32 printer-state,
124 * STRING printer-state-reasons,
125 * BOOLEAN printer-is-accepting-jobs)
126 * Printer has been deleted.
127 *
128 * PrinterModified(STRING text,
129 * STRING printer-uri,
130 * STRING printer-name,
131 * UINT32 printer-state,
132 * STRING printer-state-reasons,
133 * BOOLEAN printer-is-accepting-jobs)
134 * Printer has been modified.
135 *
136 * text describes the event.
137 * printer-state-reasons is a comma-separated list.
138 * If printer-uri is "" in a Job* signal, the other printer-* parameters
139 * must be ignored.
140 * If the job name is not know, job-name will be "".
141 */
142
143/*
144 * Constants...
145 */
146
147enum
148{
149 PARAMS_NONE,
150 PARAMS_PRINTER,
151 PARAMS_JOB
152};
153
154
155/*
156 * Local functions...
157 */
158
49d87452 159static int acquire_lock(int *fd, char *lockfile, size_t locksize);
c5571a1d
MS
160
161
162/*
163 * 'main()' - Read events and send DBUS notifications.
164 */
165
166int /* O - Exit status */
167main(int argc, /* I - Number of command-line args */
168 char *argv[]) /* I - Command-line arguments */
169{
170 ipp_t *msg; /* Event message from scheduler */
171 ipp_state_t state; /* IPP event state */
172 struct sigaction action; /* POSIX sigaction data */
173 DBusConnection *con = NULL; /* Connection to DBUS server */
174 DBusError error; /* Error, if any */
175 DBusMessage *message; /* Message to send */
176 DBusMessageIter iter; /* Iterator for message data */
177 int lock_fd = -1; /* Lock file descriptor */
178 char lock_filename[1024];
179 /* Lock filename */
180
181
182 /*
183 * Don't buffer stderr...
184 */
185
186 setbuf(stderr, NULL);
187
188 /*
189 * Ignore SIGPIPE signals...
190 */
191
192 memset(&action, 0, sizeof(action));
193 action.sa_handler = SIG_IGN;
194 sigaction(SIGPIPE, &action, NULL);
195
196 /*
197 * Validate command-line options...
198 */
199
200 if (argc != 3)
201 {
202 fputs("Usage: dbus dbus:/// notify-user-data\n", stderr);
203 return (1);
204 }
205
49d87452 206 if (strncmp(argv[1], "dbus:", 5))
c5571a1d
MS
207 {
208 fprintf(stderr, "ERROR: Bad URI \"%s\"!\n", argv[1]);
209 return (1);
210 }
211
212 /*
213 * Loop forever until we run out of events...
214 */
215
216 for (;;)
217 {
218 ipp_attribute_t *attr; /* Current attribute */
219 const char *event; /* Event name */
220 const char *signame = NULL;/* DBUS signal name */
221 char *printer_reasons = NULL;
222 /* Printer reasons string */
223 const char *nul = ""; /* Empty string value */
224 int no = 0; /* Boolean "no" value */
225 int params = PARAMS_NONE;
226 /* What parameters to include? */
227
228
229 /*
230 * Get the next event...
231 */
232
233 msg = ippNew();
234 while ((state = ippReadFile(0, msg)) != IPP_DATA)
235 {
236 if (state <= IPP_IDLE)
237 break;
238 }
239
240 fprintf(stderr, "DEBUG: state=%d\n", state);
241
242 if (state == IPP_ERROR)
243 fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
244
245 if (state <= IPP_IDLE)
246 {
247 /*
248 * Out of messages, free memory and then exit...
249 */
250
251 ippDelete(msg);
252 break;
253 }
254
255 /*
256 * Verify connection to DBUS server...
257 */
258
259 if (con && !dbus_connection_get_is_connected(con))
260 {
261 dbus_connection_unref(con);
262 con = NULL;
263 }
264
265 if (!con)
266 {
267 dbus_error_init(&error);
268
269 con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
270 if (!con)
271 dbus_error_free(&error);
272 else
273 fputs("DEBUG: Connected to D-BUS\n", stderr);
274 }
275
276 if (!con)
277 continue;
278
279 if (lock_fd == -1 &&
280 acquire_lock(&lock_fd, lock_filename, sizeof(lock_filename)))
281 continue;
282
283 attr = ippFindAttribute(msg, "notify-subscribed-event",
284 IPP_TAG_KEYWORD);
285 if (!attr)
286 continue;
287
288 event = attr->values[0].string.text;
289 if (!strncmp(event, "server-", 7))
290 {
291 const char *word2 = event + 7; /* Second word */
292
293 if (!strcmp(word2, "restarted"))
294 signame = "ServerRestarted";
295 else if (!strcmp(word2, "started"))
296 signame = "ServerStarted";
297 else if (!strcmp(word2, "stopped"))
298 signame = "ServerStopped";
299 else if (!strcmp(word2, "audit"))
300 signame = "ServerAudit";
301 else
302 continue;
303 }
304 else if (!strncmp(event, "printer-", 8))
305 {
306 const char *word2 = event + 8; /* Second word */
307
308 params = PARAMS_PRINTER;
309 if (!strcmp(word2, "restarted"))
310 signame = "PrinterRestarted";
311 else if (!strcmp(word2, "shutdown"))
312 signame = "PrinterShutdown";
313 else if (!strcmp(word2, "stopped"))
314 signame = "PrinterStopped";
315 else if (!strcmp(word2, "state-changed"))
316 signame = "PrinterStateChanged";
317 else if (!strcmp(word2, "finishings-changed"))
318 signame = "PrinterFinishingsChanged";
319 else if (!strcmp(word2, "media-changed"))
320 signame = "PrinterMediaChanged";
321 else if (!strcmp(word2, "added"))
322 signame = "PrinterAdded";
323 else if (!strcmp(word2, "deleted"))
324 signame = "PrinterDeleted";
325 else if (!strcmp(word2, "modified"))
326 signame = "PrinterModified";
327 else
328 continue;
329 }
330 else if (!strncmp(event, "job-", 4))
331 {
332 const char *word2 = event + 4; /* Second word */
333
334 params = PARAMS_JOB;
f14324a7 335 if (!strcmp(word2, "state-changed"))
c5571a1d
MS
336 signame = "JobState";
337 else if (!strcmp(word2, "created"))
338 signame = "JobCreated";
339 else if (!strcmp(word2, "completed"))
340 signame = "JobCompleted";
341 else if (!strcmp(word2, "stopped"))
342 signame = "JobStopped";
343 else if (!strcmp(word2, "config-changed"))
344 signame = "JobConfigChanged";
345 else if (!strcmp(word2, "progress"))
346 signame = "JobProgress";
347 else
348 continue;
349 }
350 else
351 continue;
352
353 /*
354 * Create and send the new message...
355 */
356
357 fprintf(stderr, "DEBUG: %s\n", signame);
358 message = dbus_message_new_signal("/org/cups/cupsd/Notifier",
359 "org.cups.cupsd.Notifier",
360 signame);
361
362 dbus_message_append_iter_init(message, &iter);
363 attr = ippFindAttribute(msg, "notify-text", IPP_TAG_TEXT);
364 if (!attr)
365 goto bail;
366 dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
367
368 if (params >= PARAMS_PRINTER)
369 {
370 char *p; /* Pointer into printer_reasons */
371 size_t reasons_length; /* Required size of printer_reasons */
372 int i; /* Looping var */
373 int have_printer_params = 1;/* Do we have printer URI? */
374
375 /* STRING printer-uri or "" */
376 attr = ippFindAttribute(msg, "notify-printer-uri", IPP_TAG_URI);
377 if (attr)
378 dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
379 else
380 {
381 have_printer_params = 0;
382 dbus_message_iter_append_string(&iter, &nul);
383 }
384
385 /* STRING printer-name */
386 if (have_printer_params)
387 {
388 attr = ippFindAttribute(msg, "printer-name", IPP_TAG_NAME);
389 if (attr)
390 dbus_message_iter_append_string(&iter,
391 &(attr->values[0].string.text));
392 else
393 goto bail;
394 }
395 else
396 dbus_message_iter_append_string(&iter, &nul);
397
398 /* UINT32 printer-state */
399 if (have_printer_params)
400 {
401 attr = ippFindAttribute(msg, "printer-state", IPP_TAG_ENUM);
402 if (attr)
403 dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
404 else
405 goto bail;
406 }
407 else
408 dbus_message_iter_append_uint32(&iter, &no);
409
410 /* STRING printer-state-reasons */
411 if (have_printer_params)
412 {
413 attr = ippFindAttribute(msg, "printer-state-reasons",
414 IPP_TAG_KEYWORD);
415 if (attr)
416 {
417 for (reasons_length = 0, i = 0; i < attr->num_values; i++)
418 /* All need commas except the last, which needs a nul byte. */
419 reasons_length += 1 + strlen(attr->values[i].string.text);
420 printer_reasons = malloc(reasons_length);
421 if (!printer_reasons)
422 goto bail;
423 p = printer_reasons;
424 for (i = 0; i < attr->num_values; i++)
425 {
426 strcpy(p, attr->values[i].string.text);
427 p += strlen(p);
428 if (i)
429 *p++ = ',';
430 }
431 dbus_message_iter_append_string(&iter, &printer_reasons);
432 }
433 else
434 goto bail;
435 }
436 else
437 dbus_message_iter_append_string(&iter, &nul);
438
439 /* BOOL printer-is-accepting-jobs */
440 if (have_printer_params)
441 {
442 attr = ippFindAttribute(msg, "printer-is-accepting-jobs",
443 IPP_TAG_BOOLEAN);
444 if (attr)
445 dbus_message_iter_append_boolean(&iter, &(attr->values[0].boolean));
446 else
447 goto bail;
448 }
449 else
450 dbus_message_iter_append_boolean(&iter, &no);
451 }
452
453 if (params >= PARAMS_JOB)
454 {
455 /* UINT32 job-id */
456 attr = ippFindAttribute(msg, "notify-job-id", IPP_TAG_INTEGER);
457 if (!attr)
458 goto bail;
459 dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
460
461 /* UINT32 job-state */
462 attr = ippFindAttribute(msg, "job-state", IPP_TAG_ENUM);
463 if (!attr)
464 goto bail;
465 dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
466
467 /* STRING job-state-reasons */
468 attr = ippFindAttribute(msg, "job-state-reasons", IPP_TAG_KEYWORD);
469 if (!attr)
470 goto bail;
471 dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
472
473 /* STRING job-name or "" */
474 attr = ippFindAttribute(msg, "job-name", IPP_TAG_NAME);
475 if (attr)
476 dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
477 else
478 dbus_message_iter_append_string(&iter, &nul);
479
480 /* UINT32 job-impressions-completed */
481 attr = ippFindAttribute(msg, "job-impressions-completed",
482 IPP_TAG_INTEGER);
483 if (!attr)
484 goto bail;
485 dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
486 }
487
488 dbus_connection_send(con, message, NULL);
489 dbus_connection_flush(con);
490
491 /*
492 * Cleanup...
493 */
494
495 bail:
496
497 if (printer_reasons)
498 free(printer_reasons);
499
500 dbus_message_unref(message);
501 ippDelete(msg);
502 }
503
504 /*
505 * Remove lock file...
506 */
507
508 if (lock_fd >= 0)
509 {
510 close(lock_fd);
511 unlink(lock_filename);
512 }
513
514 return (0);
515}
516
517
518/*
519 * 'acquire_lock()' - Acquire a lock so we only have a single notifier running.
520 */
521
522static int /* O - 0 on success, -1 on failure */
523acquire_lock(int *fd, /* O - Lock file descriptor */
524 char *lockfile, /* I - Lock filename buffer */
525 size_t locksize) /* I - Size of filename buffer */
526{
527 const char *tmpdir; /* Temporary directory */
528
529
530 /*
531 * Figure out where to put the lock file...
532 */
533
534 if ((tmpdir = getenv("TMPDIR")) == NULL)
535 tmpdir = "/tmp";
536
537 snprintf(lockfile, locksize, "%s/cups-dbus-notifier-lockfile", tmpdir);
538
539 /*
540 * Create the lock file and fail if it already exists...
541 */
542
543 if ((*fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
544 return (-1);
545 else
546 return (0);
547}
548
549
550/*
551 * End of "$Id$".
552 */