#include "notify.h" #include #include #include #include #include #define LOG_MODULE "notify" #define LOG_ENABLE_DBG 0 #include "log.h" #include "config.h" #include "spawn.h" #include "xmalloc.h" void notify_notify(const struct terminal *term, const char *title, const char *body) { LOG_DBG("notify: title=\"%s\", msg=\"%s\"", title, msg); if (term->kbd_focus) { /* No notifications while we’re focused */ return; } if (title == NULL || body == NULL) return; if (term->conf->notify.argv == NULL) return; size_t argv_size = 0; for (; term->conf->notify.argv[argv_size] != NULL; argv_size++) ; #define append(s, n) \ do { \ expanded = xrealloc(expanded, len + (n) + 1); \ memcpy(&expanded[len], s, n); \ len += n; \ expanded[len] = '\0'; \ } while (0) char **argv = malloc((argv_size + 1) * sizeof(argv[0])); /* Expand ${title} and ${body} */ for (size_t i = 0; i < argv_size; i++) { size_t len = 0; char *expanded = NULL; char *start = NULL; char *last_end = term->conf->notify.argv[i]; while ((start = strstr(last_end, "${")) != NULL) { /* Append everything from the last template's end to this * one's beginning */ append(last_end, start - last_end); /* Find end of template */ start += 2; char *end = strstr(start, "}"); if (end == NULL) { /* Ensure final append() copies the unclosed '${' */ last_end = start - 2; LOG_WARN("notify: unclosed template: %s", last_end); break; } /* Expand template */ if (strncmp(start, "title", end - start) == 0) append(title, strlen(title)); else if (strncmp(start, "body", end - start) == 0) append(body, strlen(body)); else { /* Unrecognized template - append it as-is */ start -= 2; append(start, end + 1 - start); LOG_WARN("notify: unrecognized template: %.*s", (int)(end + 1 - start), start); } last_end = end + 1;; } append(last_end, term->conf->notify.argv[i] + strlen(term->conf->notify.argv[i]) - last_end); argv[i] = expanded; } argv[argv_size] = NULL; #undef append LOG_DBG("notify command:"); for (size_t i = 0; i < argv_size; i++) LOG_DBG(" argv[%zu] = \"%s\"", i, argv[i]); /* Redirect stdin to /dev/null, but ignore failure to open */ int devnull = open("/dev/null", O_RDONLY); spawn(term->reaper, NULL, argv, devnull, -1, -1); if (devnull >= 0) close(devnull); for (size_t i = 0; i < argv_size; i++) free(argv[i]); free(argv); }