Merge pull request #204 from wavexx/rule_allow_markup

Fix markup handling.
This commit is contained in:
Sascha Kruse 2014-12-17 11:35:52 +01:00
commit 56b0a7c7d9
12 changed files with 145 additions and 58 deletions

View File

@ -2,6 +2,7 @@
char *font = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*"; char *font = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
bool allow_markup = false; bool allow_markup = false;
bool plain_text = true;
char *normbgcolor = "#1793D1"; char *normbgcolor = "#1793D1";
char *normfgcolor = "#DDDDDD"; char *normfgcolor = "#DDDDDD";
char *critbgcolor = "#ffaaaa"; char *critbgcolor = "#ffaaaa";
@ -90,11 +91,11 @@ keyboard_shortcut context_ks = {.str = "none",
rule_t default_rules[] = { rule_t default_rules[] = {
/* name can be any unique string. It is used to identify the rule in dunstrc to override it there */ /* 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 */ /* 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, NULL, NULL, NULL, NULL}, { "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, NULL, NULL, "%s %b", 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, NULL, NULL, NULL, 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, 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, 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, NULL, "#00FF00", NULL, NULL }, */ /* { "rule5", NULL, "*foobar*", NULL, NULL, NULL, -1, -1, -1, -1, -1, NULL, NULL, "#00FF00", NULL, NULL }, */
}; };

3
dbus.c
View File

@ -9,6 +9,7 @@
#include "dbus.h" #include "dbus.h"
#include "notification.h" #include "notification.h"
#include "utils.h" #include "utils.h"
#include "settings.h"
GDBusConnection *dbus_conn; GDBusConnection *dbus_conn;
@ -283,6 +284,8 @@ static void onNotify(GDBusConnection * connection,
n->body = body; n->body = body;
n->icon = icon; n->icon = icon;
n->timeout = timeout; 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->progress = (progress < 0 || progress > 100) ? 0 : progress + 1;
n->urgency = urgency; n->urgency = urgency;
n->category = category; n->category = category;

View File

@ -327,6 +327,8 @@ int main(int argc, char *argv[])
n->body = strdup("dunst is up and running"); n->body = strdup("dunst is up and running");
n->progress = 0; n->progress = 0;
n->timeout = 10; n->timeout = 10;
n->allow_markup = false;
n->plain_text = true;
n->urgency = LOW; n->urgency = LOW;
n->icon = NULL; n->icon = NULL;
n->category = NULL; n->category = NULL;

View File

@ -1,7 +1,7 @@
[global] [global]
font = Monospace 8 font = Monospace 8
# Allow a small subset of html markup: # Allow a small subset of html markup in notifications and formats:
# <b>bold</b> # <b>bold</b>
# <i>italic</i> # <i>italic</i>
# <s>strikethrough</s> # <s>strikethrough</s>
@ -13,6 +13,9 @@
# message. # message.
allow_markup = yes allow_markup = yes
# Treat incoming notifications as plain text
plain_text = no
# The format of the message. Possible variables are: # The format of the message. Possible variables are:
# %a appname # %a appname
# %s summary # %s summary

View File

@ -161,8 +161,7 @@ void notification_free(notification * n)
/* /*
* Strip any markup from text * Strip any markup from text
*/ */
char *notification_strip_markup(char *str)
char *notification_fix_markup(char *str)
{ {
char *replace_buf, *start, *end; char *replace_buf, *start, *end;
@ -210,9 +209,62 @@ char *notification_fix_markup(char *str)
} }
} }
return 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("&", "&amp;", str);
str = string_replace_all("\"", "&quot;", str);
str = string_replace_all("'", "&apos;", str);
str = string_replace_all("<", "&lt;", str);
str = string_replace_all(">", "&gt;", 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("<br>", "\n", tmp);
tmp = string_replace_all("<br/>", "\n", tmp);
tmp = string_replace_all("<br />", "\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 *notification_extract_markup_urls(char **str_ptr) {
char *start, *end, *replace_buf, *str, *urls = NULL, *url, *index_buf; 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) int notification_init(notification * n, int id)
{ {
if (n == NULL) if (n == NULL)
return -1; return -1;
@ -282,35 +333,29 @@ int notification_init(notification * n, int id)
n->urls = notification_extract_markup_urls(&(n->body)); n->urls = notification_extract_markup_urls(&(n->body));
n->msg = string_replace("%a", n->appname, g_strdup(n->format)); n->msg = string_replace_all("\\n", "\n", g_strdup(n->format));
n->msg = string_replace("%s", n->summary, n->msg); 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) { if (n->icon) {
n->msg = string_replace("%I", basename(n->icon), n->msg); n->msg = notification_replace_format("%I", basename(n->icon),
n->msg = string_replace("%i", n->icon, n->msg); 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) { if (n->progress) {
char pg[10]; char pg[10];
sprintf(pg, "[%3d%%]", n->progress - 1); sprintf(pg, "[%3d%%]", n->progress - 1);
n->msg = string_replace("%p", pg, n->msg); n->msg = string_replace_all("%p", pg, n->msg);
} else { } 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("<br>", "\n", n->msg);
n->msg = string_replace("<br />", "\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); n->msg = g_strstrip(n->msg);
if (id == 0) { if (id == 0) {

View File

@ -27,6 +27,8 @@ typedef struct _notification {
time_t timestamp; time_t timestamp;
int timeout; int timeout;
int urgency; int urgency;
bool allow_markup;
bool plain_text;
bool redisplayed; /* has been displayed before? */ bool redisplayed; /* has been displayed before? */
int id; int id;
int dup_count; 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); void notification_run_script(notification * n);
int notification_close(notification * n, int reason); int notification_close(notification * n, int reason);
void notification_print(notification * n); 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); void notification_update_text_to_render(notification *n);
int notification_get_ttl(notification *n); int notification_get_ttl(notification *n);
int notification_get_age(notification *n); int notification_get_age(notification *n);

View File

@ -15,6 +15,10 @@ void rule_apply(rule_t * r, notification * n)
n->timeout = r->timeout; n->timeout = r->timeout;
if (r->urgency != -1) if (r->urgency != -1)
n->urgency = r->urgency; 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) if (r->new_icon)
n->icon = r->new_icon; n->icon = r->new_icon;
if (r->fg) if (r->fg)
@ -54,6 +58,8 @@ void rule_init(rule_t * r)
r->msg_urgency = -1; r->msg_urgency = -1;
r->timeout = -1; r->timeout = -1;
r->urgency = -1; r->urgency = -1;
r->allow_markup = -1;
r->plain_text = -1;
r->new_icon = NULL; r->new_icon = NULL;
r->fg = NULL; r->fg = NULL;
r->bg = NULL; r->bg = NULL;
@ -65,7 +71,6 @@ void rule_init(rule_t * r)
*/ */
bool rule_matches_notification(rule_t * r, notification * n) bool rule_matches_notification(rule_t * r, notification * n)
{ {
return ((!r->appname || !fnmatch(r->appname, n->appname, 0)) return ((!r->appname || !fnmatch(r->appname, n->appname, 0))
&& (!r->summary || !fnmatch(r->summary, n->summary, 0)) && (!r->summary || !fnmatch(r->summary, n->summary, 0))
&& (!r->body || !fnmatch(r->body, n->body, 0)) && (!r->body || !fnmatch(r->body, n->body, 0))

View File

@ -19,6 +19,8 @@ typedef struct _rule_t {
/* actions */ /* actions */
int timeout; int timeout;
int urgency; int urgency;
int allow_markup;
int plain_text;
char *new_icon; char *new_icon;
char *fg; char *fg;
char *bg; char *bg;

View File

@ -85,7 +85,10 @@ void load_settings(char *cmdline_config_path)
"The font dunst should use."); "The font dunst should use.");
settings.allow_markup = settings.allow_markup =
option_get_bool("global", "allow_markup", "-markup", 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 = settings.format =
option_get_string("global", "format", "-format", format, option_get_string("global", "format", "-format", format,
"The format template for the notifictions"); "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->body = ini_get_string(cur_section, "body", r->body);
r->icon = ini_get_string(cur_section, "icon", r->icon); r->icon = ini_get_string(cur_section, "icon", r->icon);
r->timeout = ini_get_int(cur_section, "timeout", r->timeout); 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->urgency = ini_get_urgency(cur_section, "urgency", r->urgency);
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency); r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency);
r->fg = ini_get_string(cur_section, "foreground", r->fg); r->fg = ini_get_string(cur_section, "foreground", r->fg);

View File

@ -4,6 +4,7 @@
typedef struct _settings { typedef struct _settings {
bool print_notifications; bool print_notifications;
bool allow_markup; bool allow_markup;
bool plain_text;
bool stack_duplicates; bool stack_duplicates;
char *font; char *font;
char *normbgcolor; char *normbgcolor;

59
utils.c
View File

@ -17,39 +17,56 @@ char *string_replace_char(char needle, char replacement, char *haystack) {
return haystack; return haystack;
} }
char *string_replace_all(const char *needle, const char *replacement, char *string_replace_at(char *buf, int pos, int len, const char *repl)
char *haystack)
{ {
char *start; char *tmp;
start = strstr(haystack, needle); int size, buf_len, repl_len;
while (start != NULL) {
haystack = string_replace(needle, replacement, haystack); buf_len = strlen(buf);
start = strstr(haystack, needle); repl_len = strlen(repl);
} size = (buf_len - len) + repl_len + 1;
return haystack; 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 *string_replace(const char *needle, const char *replacement, char *haystack)
char *haystack)
{ {
char *tmp, *start; char *start;
int size;
start = strstr(haystack, needle); start = strstr(haystack, needle);
if (start == NULL) { if (start == NULL) {
return haystack; return haystack;
} }
size = (strlen(haystack) - strlen(needle)) + strlen(replacement) + 1; return string_replace_at(haystack, (start - haystack), strlen(needle), replacement);
tmp = calloc(sizeof(char), size); }
memset(tmp, '\0', size);
strncpy(tmp, haystack, start - haystack); char *string_replace_all(const char *needle, const char *replacement,
tmp[start - haystack] = '\0'; char *haystack)
{
char *start;
int needle_pos;
int needle_len, repl_len;
sprintf(tmp + strlen(tmp), "%s%s", replacement, start + strlen(needle)); needle_len = strlen(needle);
free(haystack); 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) char *string_append(char *a, const char *b, const char *sep)

2
x.c
View File

@ -382,7 +382,7 @@ static colored_layout *r_create_layout_from_notification(cairo_t *c, notificatio
pango_layout_set_attributes(cl->l, cl->attr); pango_layout_set_attributes(cl->l, cl->attr);
} else { } else {
/* remove markup and display plain message instead */ /* 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->text = NULL;
cl->attr = NULL; cl->attr = NULL;
pango_layout_set_text(cl->l, n->text_to_render, -1); pango_layout_set_text(cl->l, n->text_to_render, -1);