diff --git a/config.def.h b/config.def.h
index 65e36d8..fe5b79f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,6 +2,7 @@
char *font = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
bool allow_markup = false;
+bool plain_text = true;
char *normbgcolor = "#1793D1";
char *normfgcolor = "#DDDDDD";
char *critbgcolor = "#ffaaaa";
@@ -90,11 +91,11 @@ keyboard_shortcut context_ks = {.str = "none",
rule_t default_rules[] = {
/* name can be any unique string. It is used to identify the rule in dunstrc to override it there */
- /* name, appname, summary, body, icon, category, msg_urgency, timeout, urgency, fg, bg, format, script */
- { "empty", NULL, NULL, NULL, NULL, NULL, -1, -1, -1, NULL, NULL, NULL, NULL},
- /* { "rule1", "notify-send", NULL, NULL, NULL, NULL, -1, -1, -1, NULL, NULL, "%s %b", NULL }, */
- /* { "rule2", "Pidgin", "*says*, NULL, NULL, NULL, -1, -1, CRITICAL, NULL, NULL, NULL, NULL }, */
- /* { "rule3", "Pidgin", "*signed on*", NULL, NULL, NULL, -1, -1, LOW, NULL, NULL, NULL, NULL }, */
- /* { "rule4", "Pidgin", "*signed off*", NULL, NULL, NULL, -1, -1, LOW, NULL, NULL, NULL, NULL }, */
- /* { "rule5", NULL, "*foobar*", NULL, NULL, NULL, -1, -1, -1, NULL, "#00FF00", NULL, NULL }, */
+ /* name, appname, summary, body, icon, category, msg_urgency, timeout, urgency, allow_markup, plain_text, new_icon, fg, bg, format, script */
+ { "empty", NULL, NULL, NULL, NULL, NULL, -1, -1, -1, -1, -1, NULL, NULL, NULL, NULL, NULL},
+ /* { "rule1", "notify-send", NULL, NULL, NULL, NULL, -1, -1, -1, -1, -1, NULL, NULL, NULL, "%s %b", NULL }, */
+ /* { "rule2", "Pidgin", "*says*, NULL, NULL, NULL, -1, -1, CRITICAL, -1, -1, NULL, NULL, NULL, NULL, NULL }, */
+ /* { "rule3", "Pidgin", "*signed on*", NULL, NULL, NULL, -1, -1, LOW, -1, -1, NULL, NULL, NULL, NULL, NULL }, */
+ /* { "rule4", "Pidgin", "*signed off*", NULL, NULL, NULL, -1, -1, LOW, -1, -1, NULL, NULL, NULL, NULL, NULL }, */
+ /* { "rule5", NULL, "*foobar*", NULL, NULL, NULL, -1, -1, -1, -1, -1, NULL, NULL, "#00FF00", NULL, NULL }, */
};
diff --git a/dbus.c b/dbus.c
index 2080639..fd5b0d8 100644
--- a/dbus.c
+++ b/dbus.c
@@ -9,6 +9,7 @@
#include "dbus.h"
#include "notification.h"
#include "utils.h"
+#include "settings.h"
GDBusConnection *dbus_conn;
@@ -283,6 +284,8 @@ static void onNotify(GDBusConnection * connection,
n->body = body;
n->icon = icon;
n->timeout = timeout;
+ n->allow_markup = settings.allow_markup;
+ n->plain_text = settings.plain_text;
n->progress = (progress < 0 || progress > 100) ? 0 : progress + 1;
n->urgency = urgency;
n->category = category;
diff --git a/dunst.c b/dunst.c
index 493803d..d8bf621 100644
--- a/dunst.c
+++ b/dunst.c
@@ -327,6 +327,8 @@ int main(int argc, char *argv[])
n->body = strdup("dunst is up and running");
n->progress = 0;
n->timeout = 10;
+ n->allow_markup = false;
+ n->plain_text = true;
n->urgency = LOW;
n->icon = NULL;
n->category = NULL;
diff --git a/dunstrc b/dunstrc
index e28b1c4..6eaeb1c 100644
--- a/dunstrc
+++ b/dunstrc
@@ -1,7 +1,7 @@
[global]
font = Monospace 8
- # Allow a small subset of html markup:
+ # Allow a small subset of html markup in notifications and formats:
# bold
# italic
# strikethrough
@@ -13,6 +13,9 @@
# message.
allow_markup = yes
+ # Treat incoming notifications as plain text
+ plain_text = no
+
# The format of the message. Possible variables are:
# %a appname
# %s summary
diff --git a/notification.c b/notification.c
index ecc8b6b..ede3622 100644
--- a/notification.c
+++ b/notification.c
@@ -161,8 +161,7 @@ void notification_free(notification * n)
/*
* Strip any markup from text
*/
-
-char *notification_fix_markup(char *str)
+char *notification_strip_markup(char *str)
{
char *replace_buf, *start, *end;
@@ -210,9 +209,62 @@ char *notification_fix_markup(char *str)
}
}
return str;
-
}
+ /*
+ * Quote a text string for rendering with pango
+ */
+char *notification_quote_markup(char *str)
+{
+ if (str == NULL) {
+ return NULL;
+ }
+
+ str = string_replace_all("&", "&", str);
+ str = string_replace_all("\"", """, str);
+ str = string_replace_all("'", "'", str);
+ str = string_replace_all("<", "<", str);
+ str = string_replace_all(">", ">", str);
+
+ return str;
+}
+
+ /*
+ * Replace all occurrences of "needle" with a quoted "replacement",
+ * according to the allow_markup/plain_text settings.
+ */
+char *notification_replace_format(const char *needle, const char *replacement,
+ char *haystack, bool allow_markup,
+ bool plain_text) {
+ char* tmp;
+ char* ret;
+
+ if (plain_text) {
+ tmp = strdup(replacement);
+ tmp = string_replace_all("\\n", "\n", tmp);
+ if (settings.ignore_newline) {
+ tmp = string_replace_all("\n", " ", tmp);
+ }
+ tmp = notification_quote_markup(tmp);
+ ret = string_replace_all(needle, tmp, haystack);
+ free(tmp);
+ } else if (!allow_markup) {
+ tmp = strdup(replacement);
+ if (!settings.ignore_newline) {
+ tmp = string_replace_all("
", "\n", tmp);
+ tmp = string_replace_all("
", "\n", tmp);
+ tmp = string_replace_all("
", "\n", tmp);
+ }
+ tmp = notification_strip_markup(tmp);
+ tmp = notification_quote_markup(tmp);
+ ret = string_replace_all(needle, tmp, haystack);
+ free(tmp);
+ } else {
+ ret = string_replace_all(needle, replacement, haystack);
+ }
+
+ return ret;
+}
char *notification_extract_markup_urls(char **str_ptr) {
char *start, *end, *replace_buf, *str, *urls = NULL, *url, *index_buf;
@@ -259,7 +311,6 @@ char *notification_extract_markup_urls(char **str_ptr) {
*/
int notification_init(notification * n, int id)
{
-
if (n == NULL)
return -1;
@@ -282,35 +333,29 @@ int notification_init(notification * n, int id)
n->urls = notification_extract_markup_urls(&(n->body));
- n->msg = string_replace("%a", n->appname, g_strdup(n->format));
- n->msg = string_replace("%s", n->summary, n->msg);
+ n->msg = string_replace_all("\\n", "\n", g_strdup(n->format));
+ n->msg = notification_replace_format("%a", n->appname, n->msg,
+ false, true);
+ n->msg = notification_replace_format("%s", n->summary, n->msg,
+ n->allow_markup, n->plain_text);
+ n->msg = notification_replace_format("%b", n->body, n->msg,
+ n->allow_markup, n->plain_text);
+
if (n->icon) {
- n->msg = string_replace("%I", basename(n->icon), n->msg);
- n->msg = string_replace("%i", n->icon, n->msg);
+ n->msg = notification_replace_format("%I", basename(n->icon),
+ n->msg, false, true);
+ n->msg = notification_replace_format("%i", n->icon,
+ n->msg, false, true);
}
- n->msg = string_replace("%b", n->body, n->msg);
+
if (n->progress) {
char pg[10];
sprintf(pg, "[%3d%%]", n->progress - 1);
- n->msg = string_replace("%p", pg, n->msg);
+ n->msg = string_replace_all("%p", pg, n->msg);
} else {
- n->msg = string_replace("%p", "", n->msg);
+ n->msg = string_replace_all("%p", "", n->msg);
}
- if (!settings.allow_markup)
- n->msg = notification_fix_markup(n->msg);
- else if (!settings.ignore_newline) {
- n->msg = string_replace("
", "\n", n->msg);
- n->msg = string_replace("
", "\n", n->msg);
- }
-
- while (strstr(n->msg, "\\n") != NULL)
- n->msg = string_replace("\\n", "\n", n->msg);
-
- if (settings.ignore_newline)
- while (strstr(n->msg, "\n") != NULL)
- n->msg = string_replace("\n", " ", n->msg);
-
n->msg = g_strstrip(n->msg);
if (id == 0) {
diff --git a/notification.h b/notification.h
index ba5d4a5..71422ea 100644
--- a/notification.h
+++ b/notification.h
@@ -27,6 +27,8 @@ typedef struct _notification {
time_t timestamp;
int timeout;
int urgency;
+ bool allow_markup;
+ bool plain_text;
bool redisplayed; /* has been displayed before? */
int id;
int dup_count;
@@ -49,7 +51,8 @@ int notification_cmp_data(const void *a, const void *b, void *data);
void notification_run_script(notification * n);
int notification_close(notification * n, int reason);
void notification_print(notification * n);
-char *notification_fix_markup(char *str);
+char *notification_strip_markup(char *str);
+char *notification_quote_markup(char *str);
void notification_update_text_to_render(notification *n);
int notification_get_ttl(notification *n);
int notification_get_age(notification *n);
diff --git a/rules.c b/rules.c
index 6934601..8687f07 100644
--- a/rules.c
+++ b/rules.c
@@ -15,6 +15,10 @@ void rule_apply(rule_t * r, notification * n)
n->timeout = r->timeout;
if (r->urgency != -1)
n->urgency = r->urgency;
+ if (r->allow_markup != -1)
+ n->allow_markup = r->allow_markup;
+ if (r->plain_text != -1)
+ n->plain_text = r->plain_text;
if (r->new_icon)
n->icon = r->new_icon;
if (r->fg)
@@ -54,6 +58,8 @@ void rule_init(rule_t * r)
r->msg_urgency = -1;
r->timeout = -1;
r->urgency = -1;
+ r->allow_markup = -1;
+ r->plain_text = -1;
r->new_icon = NULL;
r->fg = NULL;
r->bg = NULL;
@@ -65,7 +71,6 @@ void rule_init(rule_t * r)
*/
bool rule_matches_notification(rule_t * r, notification * n)
{
-
return ((!r->appname || !fnmatch(r->appname, n->appname, 0))
&& (!r->summary || !fnmatch(r->summary, n->summary, 0))
&& (!r->body || !fnmatch(r->body, n->body, 0))
diff --git a/rules.h b/rules.h
index 71796c6..f7fc734 100644
--- a/rules.h
+++ b/rules.h
@@ -19,6 +19,8 @@ typedef struct _rule_t {
/* actions */
int timeout;
int urgency;
+ int allow_markup;
+ int plain_text;
char *new_icon;
char *fg;
char *bg;
diff --git a/settings.c b/settings.c
index e982fcf..531dd1f 100644
--- a/settings.c
+++ b/settings.c
@@ -85,7 +85,10 @@ void load_settings(char *cmdline_config_path)
"The font dunst should use.");
settings.allow_markup =
option_get_bool("global", "allow_markup", "-markup", allow_markup,
- "Allow markups.");
+ "Allow markups in notifications/formats.");
+ settings.plain_text =
+ option_get_bool("global", "plain_text", "-plain", plain_text,
+ "Treat incoming notifications as plain text.");
settings.format =
option_get_string("global", "format", "-format", format,
"The format template for the notifictions");
@@ -352,6 +355,8 @@ void load_settings(char *cmdline_config_path)
r->body = ini_get_string(cur_section, "body", r->body);
r->icon = ini_get_string(cur_section, "icon", r->icon);
r->timeout = ini_get_int(cur_section, "timeout", r->timeout);
+ r->allow_markup = ini_get_bool(cur_section, "allow_markup", r->allow_markup);
+ r->plain_text = ini_get_bool(cur_section, "plain_text", r->plain_text);
r->urgency = ini_get_urgency(cur_section, "urgency", r->urgency);
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency);
r->fg = ini_get_string(cur_section, "foreground", r->fg);
diff --git a/settings.h b/settings.h
index 26a049f..bebecb2 100644
--- a/settings.h
+++ b/settings.h
@@ -4,6 +4,7 @@
typedef struct _settings {
bool print_notifications;
bool allow_markup;
+ bool plain_text;
bool stack_duplicates;
char *font;
char *normbgcolor;
diff --git a/utils.c b/utils.c
index 2f590ff..0ab4b3a 100644
--- a/utils.c
+++ b/utils.c
@@ -17,39 +17,56 @@ char *string_replace_char(char needle, char replacement, char *haystack) {
return haystack;
}
-char *string_replace_all(const char *needle, const char *replacement,
- char *haystack)
+char *string_replace_at(char *buf, int pos, int len, const char *repl)
{
- char *start;
- start = strstr(haystack, needle);
- while (start != NULL) {
- haystack = string_replace(needle, replacement, haystack);
- start = strstr(haystack, needle);
- }
- return haystack;
+ char *tmp;
+ int size, buf_len, repl_len;
+
+ buf_len = strlen(buf);
+ repl_len = strlen(repl);
+ size = (buf_len - len) + repl_len + 1;
+ tmp = malloc(size);
+
+ memcpy(tmp, buf, pos);
+ memcpy(tmp + pos, repl, repl_len);
+ memcpy(tmp + pos + repl_len, buf + pos + len, buf_len - (pos + len) + 1);
+
+ free(buf);
+ return tmp;
}
-char *string_replace(const char *needle, const char *replacement,
- char *haystack)
+char *string_replace(const char *needle, const char *replacement, char *haystack)
{
- char *tmp, *start;
- int size;
+ char *start;
start = strstr(haystack, needle);
if (start == NULL) {
return haystack;
}
- size = (strlen(haystack) - strlen(needle)) + strlen(replacement) + 1;
- tmp = calloc(sizeof(char), size);
- memset(tmp, '\0', size);
+ return string_replace_at(haystack, (start - haystack), strlen(needle), replacement);
+}
- strncpy(tmp, haystack, start - haystack);
- tmp[start - haystack] = '\0';
+char *string_replace_all(const char *needle, const char *replacement,
+ char *haystack)
+{
+ char *start;
+ int needle_pos;
+ int needle_len, repl_len;
- sprintf(tmp + strlen(tmp), "%s%s", replacement, start + strlen(needle));
- free(haystack);
+ needle_len = strlen(needle);
+ if (needle_len == 0) {
+ return haystack;
+ }
- return tmp;
+ start = strstr(haystack, needle);
+ repl_len = strlen(replacement);
+
+ while (start != NULL) {
+ needle_pos = start - haystack;
+ haystack = string_replace_at(haystack, needle_pos, needle_len, replacement);
+ start = strstr(haystack + needle_pos + repl_len, needle);
+ }
+ return haystack;
}
char *string_append(char *a, const char *b, const char *sep)
diff --git a/x.c b/x.c
index 62ecde9..06301e5 100644
--- a/x.c
+++ b/x.c
@@ -382,7 +382,7 @@ static colored_layout *r_create_layout_from_notification(cairo_t *c, notificatio
pango_layout_set_attributes(cl->l, cl->attr);
} else {
/* remove markup and display plain message instead */
- n->text_to_render = notification_fix_markup(n->text_to_render);
+ n->text_to_render = notification_strip_markup(n->text_to_render);
cl->text = NULL;
cl->attr = NULL;
pango_layout_set_text(cl->l, n->text_to_render, -1);