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