commit 5d8f9c1f832f856f3ca78bb27c82dd34dacc4e5d
parent 34a52e16680e70528855001aa4b7be724b1b7db9
Author: Santtu Lakkala <inz@inz.fi>
Date: Mon, 28 Feb 2022 14:31:30 +0200
Cleanups
Diffstat:
M | tmisu.c | | | 272 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
1 file changed, 149 insertions(+), 123 deletions(-)
diff --git a/tmisu.c b/tmisu.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <string.h>
#include <signal.h>
+#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
@@ -9,16 +10,20 @@
#include <sys/poll.h>
#include <sys/wait.h>
#include <fcntl.h>
+#include <errno.h>
#include <dbus/dbus.h>
#include "tmisu.h"
#include "output.h"
+#include "arg.h"
#define N_IF "org.freedesktop.Notifications"
#define N_SRV N_IF
#define N_PATH "/org/freedesktop/Notifications"
+char *argv0;
+
struct conf {
enum output_format fmt;
const char *delimiter;
@@ -30,7 +35,7 @@ struct notification {
dbus_uint32_t id;
time_t expiry;
const char *title;
- const char *action;
+ const char *body;
pid_t child;
};
@@ -43,14 +48,20 @@ static size_t nw = 1;
static const char *delimiter = ", ";
static int default_exp_timeout = 60;
static int need_dispatch = 0;
+static struct notification *notifications = NULL;
+static DBusConnection *connection = NULL;
+
int use_json = 0;
-int changed = 1;
+static int changed = 1;
static const char *cmd = NULL;
static time_t expirys[MAX_WATCH] = { 0 };
static DBusTimeout *timeouts[MAX_WATCH] = { 0 };
static size_t nt = 0;
+static void groan(const char *fmt, ...);
+static void die(const char *fmt, ...);
+
static short poll_flags(unsigned int dbf)
{
return (dbf & DBUS_WATCH_READABLE ? POLLIN : 0) |
@@ -147,8 +158,10 @@ void remove_timeout(DBusTimeout *timeout,
(void)data;
- memmove(&timeouts[i], &timeouts[i + 1], (nt - i - 1) * sizeof(*timeouts));
- memmove(&expirys[i], &expirys[i + 1], (nt - i - 1) * sizeof(*expirys));
+ memmove(&timeouts[i], &timeouts[i + 1],
+ (nt - i - 1) * sizeof(*timeouts));
+ memmove(&expirys[i], &expirys[i + 1],
+ (nt - i - 1) * sizeof(*expirys));
for (; i < nt - 1; i++)
dbus_timeout_set_data(timeouts[i], (void *)i, NULL);
@@ -192,14 +205,33 @@ time_t timeout_next_expiry(void)
return rv;
}
-static struct notification *notifications = NULL;
-static DBusConnection *connection = NULL;
+static void notif_spawn(struct notification *n)
+{
+ if (cmd) {
+ n->child = fork();
+ switch (n->child) {
+ case -1:
+ groan("fork() failed:");
+ n->child = 0;
+ break;
+ case 0:
+ close(STDIN_FILENO);
+ open("/dev/null", O_RDONLY);
+ close(STDOUT_FILENO);
+ open("/dev/null", O_WRONLY);
+ execlp(cmd, cmd, n->title, n->body, NULL);
+ exit(1);
+ break;
+ default:
+ break;
+ }
+ }
+}
const struct notification *notif_update(DBusMessage *msg,
dbus_uint32_t id,
const char *title,
const char *body,
- const char *action,
time_t expiry)
{
struct notification *i;
@@ -215,29 +247,11 @@ const struct notification *notif_update(DBusMessage *msg,
kill(i->child, SIGTERM);
i->title = title;
+ i->body = body;
i->expiry = expiry;
i->msg = dbus_message_ref(msg);
- i->action = action;
- if (cmd) {
- i->child = fork();
- switch (i->child) {
- case -1:
- fprintf(stderr, "fork() failed\n");
- i->child = 0;
- break;
- case 0:
- close(STDIN_FILENO);
- open("/dev/null", O_RDONLY);
- close(STDOUT_FILENO);
- open("/dev/null", O_WRONLY);
- execlp(cmd, cmd, title, body, NULL);
- exit(1);
- break;
- default:
- break;
- }
- }
+ notif_spawn(i);
return i;
}
@@ -245,7 +259,6 @@ const struct notification *notif_update(DBusMessage *msg,
const struct notification *notif_add(DBusMessage *msg,
const char *title,
const char *body,
- const char *action,
time_t expiry)
{
static dbus_uint32_t notification_id = 0;
@@ -256,8 +269,8 @@ const struct notification *notif_add(DBusMessage *msg,
nn->id = ++notification_id;
nn->msg = dbus_message_ref(msg);
nn->title = title;
+ nn->body = body;
nn->expiry = expiry;
- nn->action = action;
nn->next = NULL;
if (notifications) {
@@ -267,25 +280,7 @@ const struct notification *notif_add(DBusMessage *msg,
notifications = nn;
}
- if (cmd) {
- nn->child = fork();
- switch (nn->child) {
- case -1:
- fprintf(stderr, "fork() failed\n");
- nn->child = 0;
- break;
- case 0:
- close(STDIN_FILENO);
- open("/dev/null", O_RDONLY);
- close(STDOUT_FILENO);
- open("/dev/null", O_WRONLY);
- execlp(cmd, cmd, title, body, NULL);
- exit(1);
- break;
- default:
- break;
- }
- }
+ notif_spawn(nn);
changed = 1;
@@ -322,12 +317,11 @@ int notif_close(dbus_uint32_t id, pid_t pid, dbus_uint32_t reason)
}
if (reason == ACTION) {
- if (!n->action)
- n->action = "";
sig = dbus_message_new_signal(N_PATH, N_IF, "ActionInvoked");
dbus_message_append_args(sig,
DBUS_TYPE_UINT32, &n->id,
- DBUS_TYPE_STRING, &n->action,
+ DBUS_TYPE_STRING,
+ &(const char *){ "default" },
DBUS_TYPE_INVALID);
dbus_connection_send(connection, sig, NULL);
dbus_message_unref(sig);
@@ -381,19 +375,28 @@ void notif_check_expiry(void)
}
}
-static void print_sanitized(const char *string, const char *escape) {
+static const char *esc(const char *string, const char *escape) {
+ static char buffer[1024];
+ static const char *special = "\b\f\n\r\t";
+ static const char *sp_rep = "bfnrt";
+ size_t p = 0;
while (*string) {
size_t len = strcspn(string, escape);
- printf("%.*s", (int)len, string);
+ memcpy(buffer + p, string, len);
string += len;
+ p += len;
while (*string && strchr(escape, *string)) {
- if (*string == '\n')
- printf("\\n");
+ const char *sp;
+ buffer[p++] = '\\';
+ if ((sp = strchr(special, *string)))
+ buffer[p++] = sp_rep[sp - special];
else
- printf("\\%c", *string);
+ buffer[p++] = *string;
string++;
}
}
+ buffer[p] = '\0';
+ return buffer;
}
void notif_dump(void)
@@ -408,7 +411,7 @@ void notif_dump(void)
if (use_json)
output_notification(i->msg, i->id, FORMAT_JSON, "");
else
- print_sanitized(i->title, "\\\n");
+ printf("%s", esc(i->title, "\\\r\n\t\b\f"));
sep = delimiter;
}
if (use_json)
@@ -472,7 +475,6 @@ DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *messag
const struct notification *n = NULL;
struct notification_data d;
DBusMessageIter iter;
- const char *action = NULL;
time_t expiry;
if (!dbus_message_has_signature(message, "susssasa{sv}i"))
@@ -495,10 +497,6 @@ DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *messag
dbus_message_iter_next(&iter);
dbus_message_iter_get_basic(&iter, &d.expiry_ms);
- if (dbus_message_iter_get_arg_type(&d.actions) ==
- DBUS_TYPE_STRING)
- dbus_message_iter_get_basic(&d.actions, &action);
-
if (d.expiry_ms < 0)
d.expiry_ms = default_exp_timeout * 1000;
if (d.expiry_ms)
@@ -511,13 +509,11 @@ DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *messag
d.replaces,
d.summary,
d.body,
- action,
expiry);
if (!n)
n = notif_add(message,
d.summary,
d.body,
- action,
expiry);
reply = dbus_message_new_method_return(message);
@@ -535,7 +531,9 @@ DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *messag
if (notif_close(id, -1, REQUEST))
reply = dbus_message_new_method_return(message);
else
- reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Notification not found");
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_INVALID_ARGS,
+ "No such id");
} else {
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@@ -554,37 +552,65 @@ void sig_handler(int signal)
exit(1);
}
-int main(int argc, char **argv) {
+static void die(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ if (*fmt && fmt[strlen(fmt) - 1] == ':')
+ fprintf(stderr, " %s", strerror(errno));
+ fputs("\n", stderr);
+ exit(1);
+}
+
+static void groan(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ if (*fmt && fmt[strlen(fmt) - 1] == ':')
+ fprintf(stderr, " %s", strerror(errno));
+ fputs("\n", stderr);
+}
+
+static void usage(void)
+{
+ die("usage: %s [-d delim] [-j] [-c command]\n"
+ "-h\tThis help\n"
+ "-d\tDelimeter for default output style.\n"
+ "-j\tUse JSON output style\n"
+ "-c\tExecute command on notifications\n",
+ argv0);
+}
+
+int main(int argc, char **argv)
+{
+ int r;
+
+ ARGBEGIN {
+ case 'd':
+ delimiter = EARGF(usage());
+ break;
+ case 'j':
+ use_json = 1;
+ break;
+ case 'c':
+ cmd = EARGF(usage());
+ break;
+ default:
+ usage();
+ break;
+ } ARGEND;
- char argument;
- while ((argument = getopt(argc, argv, "hjad:c:")) >= 0) {
- switch (argument) {
- case 'd':
- delimiter = optarg;
- break;
- case 'h':
- printf("%s\n",
- "tiramisu -[h|d|j]\n"
- "-h\tHelp dialog\n"
- "-d\tDelimeter for default output style.\n"
- "-j\tUse JSON output style\n");
- return EXIT_SUCCESS;
- break;
- case 'j':
- use_json = 1;
- break;
- case 'c':
- cmd = optarg;
- break;
- default:
- break;
- }
- }
if (pipe(sfd))
- return 1;
+ die("Unable to create pipe:");
connection = dbus_bus_get_private(DBUS_BUS_SESSION, NULL);
+ if (!connection)
+ die("Failed to connect to session bus");
dbus_connection_set_watch_functions(connection,
add_watch,
@@ -603,29 +629,20 @@ int main(int argc, char **argv) {
dbus_connection_get_dispatch_status(connection),
NULL);
+ r = dbus_bus_request_name(connection,
+ N_SRV,
+ DBUS_NAME_FLAG_REPLACE_EXISTING |
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
- if (!connection) {
- fprintf(stderr, "Could not connect to D-Bus\n");
- return 1;
- }
-
- int result = dbus_bus_request_name(connection,
- N_SRV,
- DBUS_NAME_FLAG_REPLACE_EXISTING |
- DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
-
- if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- dbus_connection_close(connection);
- dbus_connection_unref(connection);
+ if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ die("Could not acquire service name, "
+ "is another notification daemon running?");
- fprintf(stderr,
- "Could not acquire service name, "
- "is another notification daemon running?\n");
- return 1;
- }
-
- dbus_bus_add_match(connection, "interface=" N_IF " ,path=" N_PATH ",type=method_call", NULL);
- dbus_bus_add_match(connection, "interface=org.freedesktop.DBus.Introspectable,method=Introspect,type=method_call", NULL);
+ dbus_bus_add_match(connection, "interface=" N_IF " ,path=" N_PATH ","
+ "type=method_call", NULL);
+ dbus_bus_add_match(connection,
+ "interface=org.freedesktop.DBus.Introspectable,"
+ "method=Introspect,type=method_call", NULL);
dbus_connection_add_filter(connection, handle_message, NULL, NULL);
signal(SIGINT, sig_handler);
@@ -676,27 +693,29 @@ int main(int argc, char **argv) {
if (s == SIGINT || s == SIGTERM)
break;
- if (s == SIGUSR1) {
+
+ if (s == SIGUSR1 || s == SIGUSR2) {
if (notifications)
- notif_close(notifications->id, -1, DISMISSED);
- } else if (s == SIGUSR2) {
- while (notifications)
- notif_close(notifications->id, -1, DISMISSED);
+ notif_close(notifications->id, -1,
+ s == SIGUSR1 ? DISMISSED :
+ ACTION);
} else if (s == SIGCHLD) {
int cstatus;
pid_t pid = waitpid(-1, &cstatus, WNOHANG);
if (pid < 0)
- fprintf(stderr, "waitpid() failed\n");
+ groan("waitpid() failed:");
else if (!pid)
- fprintf(stderr, "spurious SIGCHLD\n");
- else if (WIFEXITED(cstatus) && WEXITSTATUS(cstatus) == 0)
+ groan("Spurious SIGCHLD");
+ else if (WIFEXITED(cstatus) &&
+ WEXITSTATUS(cstatus) == 0)
notif_close(0, pid, ACTION);
else
notif_close(0, pid, DISMISSED);
}
signal(s, sig_handler);
}
+
for (i = 0; i < nw && r; i++) {
if (!pfds[i].revents)
continue;
@@ -707,10 +726,17 @@ int main(int argc, char **argv) {
}
}
- dbus_bus_release_name(connection, "org.freedesktop.Notifications", NULL);
+ dbus_bus_release_name(connection,
+ "org.freedesktop.Notifications", NULL);
dbus_connection_remove_filter(connection, handle_message, NULL);
- dbus_bus_remove_match(connection, "interface=org.freedesktop.Notifications,path=/org/freedesktop/Notifications,type=method_call", NULL);
- dbus_bus_remove_match(connection, "interface=org.freedesktop.DBus.Introspectable,method=Introspect,type=method_call", NULL);
+ dbus_bus_remove_match(connection,
+ "interface=" N_IF ","
+ "path=" N_PATH ","
+ "type=method_call", NULL);
+ dbus_bus_remove_match(connection,
+ "interface=org.freedesktop.DBus.Introspectable,"
+ "method=Introspect,"
+ "type=method_call", NULL);
dbus_connection_close(connection);
dbus_connection_unref(connection);