-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathmain.c
More file actions
157 lines (142 loc) · 4.83 KB
/
Copy pathmain.c
File metadata and controls
157 lines (142 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* SPDX-License-Identifier: MIT */
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <unistd.h>
#include "log.h"
#include "notify.h"
static sd_bus* user_bus = NULL;
// Did we alread send a notification this decisecond (tenth of a second)?
bool over_ratelimit() {
static long decisec_last = 0;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
long decisec_now = now.tv_sec*10+now.tv_nsec/100000000;
// Decisec has rolled over?
if (decisec_last != decisec_now) {
decisec_last = decisec_now;
return false;
}
return true;
}
// handle_dbus_signal is called when a d-bus "Notify" signal is received.
int handle_dbus_signal(sd_bus_message* m, void* userdata, sd_bus_error* ret_error)
{
// unused
(void)userdata;
(void)ret_error;
// summary is optional. It stays NULL when the signal does not contain
// a string value.
const char* summary = NULL;
sd_bus_message_read_basic(m, 's', &summary);
// body is optional. It stays NULL when the signal does not contain
// a second string value.
const char* body = NULL;
sd_bus_message_read_basic(m, 's', &body);
debug("received d-bus signal on system bus: summary=%s body=%s\n", summary, body);
if(over_ratelimit()) {
fprintf(stderr, "over ratelimit, dropping message\n");
return 0;
}
notify(user_bus, summary, body);
return 0;
}
int main(int argc, char* argv[])
{
// Don't buffer our debug output to prevent interleaving
// with stderr.
setvbuf(stdout, NULL, _IONBF, 0);
setlinebuf(stdout);
// Parse command line
int c = 0;
const char* short_opt = "hq";
struct option long_opt[] = {
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 } /* end-of-array marker */
};
while ((c = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) {
switch (c) {
case -1: /* no more arguments */
case 0: /* long option toggles */
break;
case 'q':
quiet = 1;
break;
case 'h':
fprintf(stderr, "Usage: %s [-q] [-h]\n", argv[0]);
fprintf(stderr, " -q ........... quiet (show errors only)\n");
fprintf(stderr, " -h, --help ... this help text\n");
exit(0);
break;
case '?':
default:
// getopt already printed out something like this:
// ./systembus-notify: unrecognized option '--asdfasdf'
fprintf(stderr, "Try '--help' for more information.\n");
exit(FATAL_USAGE);
}
}
if (optind < argc) {
fprintf(stderr, "Extra argument not understood: '%s'\n", argv[optind]);
exit(FATAL_USAGE);
}
// Connect to D-Buses
while(1) {
debug("connecting to d-bus user bus: ");
int ret = sd_bus_default_user(&user_bus);
if(ret >= 0) {
const char* a = NULL;
sd_bus_get_address(user_bus, &a);
debug("ok: %s\n", a);
sd_bus_set_exit_on_disconnect(user_bus, 1);
break;
}
fprintf(stderr, "sd_bus_default_user: %s. Retrying\n", strerror(-ret));
sleep(1);
}
sd_bus* system_bus = NULL;
while(1) {
debug("connecting to d-bus system bus: ");
int ret = sd_bus_default_system(&system_bus);
if(ret >= 0) {
const char* a = NULL;
sd_bus_get_address(system_bus, &a);
debug("ok: %s\n", a);
sd_bus_set_exit_on_disconnect(system_bus, 1);
break;
}
fprintf(stderr, "sd_bus_default_system: %s. Retrying\n", strerror(-ret));
sleep(1);
}
// Connect D-Bus signal handler
const char* match_rule = "type='signal',interface='net.nuetzlich.SystemNotifications',member='Notify'";
int ret = sd_bus_add_match(system_bus, NULL, match_rule, handle_dbus_signal, NULL);
if (ret < 0) {
fprintf(stderr, "fatal: sd_bus_match_signal: %s\n", strerror(-ret));
exit(FATAL_SYSTEM_BUS);
}
debug("waiting for d-bus signals on system bus: %s\n", match_rule);
// Set up event loop
sd_event* event = NULL;
ret = sd_event_default(&event);
if (ret < 0) {
fprintf(stderr, "fatal: sd_event_default: %s\n", strerror(-ret));
exit(FATAL_EVENT);
}
ret = sd_bus_attach_event(user_bus, event, 0);
if (ret < 0) {
fprintf(stderr, "fatal: sd_bus_attach_event: %s\n", strerror(-ret));
exit(FATAL_EVENT);
}
ret = sd_bus_attach_event(system_bus, event, 0);
if (ret < 0) {
fprintf(stderr, "fatal: sd_bus_attach_event: %s\n", strerror(-ret));
exit(FATAL_EVENT);
}
// Run event loop (should not return)
ret = sd_event_loop(event);
fprintf(stderr, "fatal: sd_event_loop: %s\n", strerror(-ret));
exit(FATAL_EVENT);
}