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