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