diff options
author | lamp | 2023-03-05 21:41:49 +0000 |
---|---|---|
committer | lamp | 2023-03-05 21:41:49 +0000 |
commit | 14b336eb507c69706aacc55e872824b4fcf8acaa (patch) | |
tree | 69e686d95dcec8c419269e2eff9cb0c081b6fa3e |
init
-rw-r--r-- | LICENSE | 13 | ||||
-rw-r--r-- | README.md | 17 | ||||
-rw-r--r-- | main.c | 114 |
3 files changed, 144 insertions, 0 deletions
@@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0b7adaa --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# writed + +writed is a tiny daemon that displays messages received via the traditional `write`/`wall` mechanism as desktop notifications via `libnotify`. + +## building + +You'll need `libnotify`, `pkg-config`, and a C compiler. + +``` +gcc -std=c89 -lutil `pkg-config --cflags --libs libnotify` main.c -o writed +``` + +writed **must** be setgid `utmp`. `write` and `wall` only send messages to `pts` devices registered in `/var/run/utmp`, and without setgid `utmp`, writed will silently fail to receive messages. + +## usage + +Just run `writed` while you have a desktop notification daemon running. @@ -0,0 +1,114 @@ +#define _XOPEN_SOURCE 600 + +#include <ctype.h> +#include <fcntl.h> +#include <pwd.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <utmp.h> + +#include <libnotify/notify.h> + +char ut_line[UT_LINESIZE]; + +static void handle_exit(int signal) { + notify_uninit(); + logout(ut_line); +} + +static void clean_string(char *str) { + char *src, *dest; + bool stripped_start = false; + bool should_increment = false; + for (src = dest = str; *src != '\0'; src++) { + *dest = *src; + if (isprint(*dest) && *dest != ' ' && *dest != '\n' && *dest != '\r') { + stripped_start = true; + should_increment = true; + } + if (*dest == ' ' && stripped_start) { + should_increment = true; + } + if (*dest == '\n' || *dest == '\r') { + stripped_start = false; + } + if (should_increment) { + should_increment = false; + dest++; + } + } + *dest = '\0'; +} + +int main(int argc, char **argv) { + char *name_ptr; + int master_fd, slave_fd; + char buffer[1024]; + ssize_t bytes_read; + int uid; + struct utmp login_data; + struct passwd *pw_entry; + struct timeval current_time; + NotifyNotification *notification; + + if ((master_fd = posix_openpt(O_RDWR)) < 0) + return 1; + if (grantpt(master_fd) < 0) + return 1; + if (unlockpt(master_fd) < 0) + return 1; + if ((name_ptr = ptsname(master_fd)) == NULL) + return 1; + + if ((slave_fd = open(name_ptr, O_RDONLY)) < 0) + return 1; + + memset(&login_data, 0, sizeof(login_data)); + + uid = getuid(); + pw_entry = getpwuid(uid); + if (!pw_entry) + return 1; + strncpy(login_data.ut_name, pw_entry->pw_name, sizeof(login_data.ut_name)); + + if (!memcmp(name_ptr, "/dev/", 5)) + name_ptr += 5; + strncpy(login_data.ut_line, name_ptr, sizeof(login_data.ut_line)); + strncpy(ut_line, name_ptr, sizeof(ut_line)); + + notify_init("writed"); + + signal(SIGTERM, handle_exit); + signal(SIGINT, handle_exit); + signal(SIGHUP, handle_exit); + + gettimeofday(¤t_time, NULL); + memcpy(&login_data.ut_tv, ¤t_time, sizeof(login_data.ut_tv)); + + login_data.ut_type = USER_PROCESS; + login_data.ut_pid = getpid(); + dup2(slave_fd, 0); + login(&login_data); + + for (;;) { + bytes_read = read(master_fd, buffer, sizeof(buffer)); + if (bytes_read < 0) + break; + else if (bytes_read > 0) { + buffer[sizeof(buffer) - 1] = '\x0'; + clean_string(buffer); + notification = notify_notification_new("System Broadcast", buffer, 0); + notify_notification_show(notification, NULL); + g_object_unref(G_OBJECT(notification)); + } + } + + handle_exit(15); + return 0; +} |