Merge pull request #365 from bebehei/issue-322
Prevent replacement of format strings in message
This commit is contained in:
commit
29aa4c7ec8
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- `new_icon` rule being ignored on notifications that had a raw icon
|
- `new_icon` rule being ignored on notifications that had a raw icon
|
||||||
|
- Do not replace format strings, which are in notification content
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- transient hints are now handled
|
- transient hints are now handled
|
||||||
|
@ -324,6 +324,8 @@ equivalent notification attribute.
|
|||||||
|
|
||||||
=item B<%n> progress value without any extra characters
|
=item B<%n> progress value without any extra characters
|
||||||
|
|
||||||
|
=item B<%%> Literal %
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
If any of these exists in the format but hasn't been specified in the
|
If any of these exists in the format but hasn't been specified in the
|
||||||
|
1
dunstrc
1
dunstrc
@ -123,6 +123,7 @@
|
|||||||
# %I iconname (without its path)
|
# %I iconname (without its path)
|
||||||
# %p progress value if set ([ 0%] to [100%]) or nothing
|
# %p progress value if set ([ 0%] to [100%]) or nothing
|
||||||
# %n progress value if set without any extra characters
|
# %n progress value if set without any extra characters
|
||||||
|
# %% Literal %
|
||||||
# Markup is allowed
|
# Markup is allowed
|
||||||
format = "<b>%s</b>\n%b"
|
format = "<b>%s</b>\n%b"
|
||||||
|
|
||||||
|
@ -200,19 +200,31 @@ void notification_free(notification *n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace all occurrences of "needle" with a quoted "replacement",
|
* Replace the two chars where **needle points
|
||||||
* according to the markup settings.
|
* with a quoted "replacement", according to the markup settings.
|
||||||
|
*
|
||||||
|
* The needle is a double pointer and gets updated upon return
|
||||||
|
* to point to the first char, which occurs after replacement.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
char *notification_replace_format(const char *needle, const char *replacement,
|
void notification_replace_single_field(char **haystack, char **needle,
|
||||||
char *haystack, enum markup_mode markup_mode) {
|
const char *replacement, enum markup_mode markup_mode) {
|
||||||
char *tmp;
|
|
||||||
char *ret;
|
|
||||||
|
|
||||||
tmp = markup_transform(g_strdup(replacement), markup_mode);
|
assert(*needle[0] == '%');
|
||||||
ret = string_replace_all(needle, tmp, haystack);
|
// needle has to point into haystack (but not on the last char)
|
||||||
g_free(tmp);
|
assert(*needle >= *haystack);
|
||||||
|
assert(*needle - *haystack < strlen(*haystack) - 1);
|
||||||
|
|
||||||
return ret;
|
int pos = *needle - *haystack;
|
||||||
|
|
||||||
|
char *input = markup_transform(g_strdup(replacement), markup_mode);
|
||||||
|
*haystack = string_replace_at(*haystack, pos, 2, input);
|
||||||
|
|
||||||
|
// point the needle to the next char
|
||||||
|
// which was originally in haystack
|
||||||
|
*needle = *haystack + pos + strlen(input);
|
||||||
|
|
||||||
|
g_free(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *notification_extract_markup_urls(char **str_ptr) {
|
char *notification_extract_markup_urls(char **str_ptr) {
|
||||||
@ -307,31 +319,89 @@ 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_all("\\n", "\n", g_strdup(n->format));
|
n->msg = string_replace_all("\\n", "\n", g_strdup(n->format));
|
||||||
n->msg = notification_replace_format("%a", n->appname, n->msg,
|
|
||||||
MARKUP_NO);
|
|
||||||
n->msg = notification_replace_format("%s", n->summary, n->msg,
|
|
||||||
n->markup);
|
|
||||||
n->msg = notification_replace_format("%b", n->body, n->msg,
|
|
||||||
n->markup);
|
|
||||||
|
|
||||||
if (n->icon) {
|
/* replace all formatter */
|
||||||
char *tmp = g_strdup(n->icon);
|
for(char *substr = strchr(n->msg, '%');
|
||||||
n->msg = notification_replace_format("%I", basename(tmp),
|
substr;
|
||||||
n->msg, MARKUP_NO);
|
substr = strchr(substr, '%')){
|
||||||
n->msg = notification_replace_format("%i", n->icon,
|
|
||||||
n->msg, MARKUP_NO);
|
|
||||||
g_free(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n->progress) {
|
char pg[16];
|
||||||
char pg[10];
|
|
||||||
sprintf(pg, "[%3d%%]", n->progress - 1);
|
switch(substr[1]){
|
||||||
n->msg = string_replace_all("%p", pg, n->msg);
|
case 'a':
|
||||||
sprintf(pg, "%d", n->progress - 1);
|
notification_replace_single_field(
|
||||||
n->msg = string_replace_all("%n", pg, n->msg);
|
&n->msg,
|
||||||
} else {
|
&substr,
|
||||||
n->msg = string_replace_all("%p", "", n->msg);
|
n->appname,
|
||||||
n->msg = string_replace_all("%n", "", n->msg);
|
MARKUP_NO);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
notification_replace_single_field(
|
||||||
|
&n->msg,
|
||||||
|
&substr,
|
||||||
|
n->summary,
|
||||||
|
n->markup);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
notification_replace_single_field(
|
||||||
|
&n->msg,
|
||||||
|
&substr,
|
||||||
|
n->body,
|
||||||
|
n->markup);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
notification_replace_single_field(
|
||||||
|
&n->msg,
|
||||||
|
&substr,
|
||||||
|
n->icon ? basename(n->icon) : "",
|
||||||
|
MARKUP_NO);
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
notification_replace_single_field(
|
||||||
|
&n->msg,
|
||||||
|
&substr,
|
||||||
|
n->icon ? n->icon : "",
|
||||||
|
MARKUP_NO);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (n->progress)
|
||||||
|
sprintf(pg, "[%3d%%]", n->progress - 1);
|
||||||
|
|
||||||
|
notification_replace_single_field(
|
||||||
|
&n->msg,
|
||||||
|
&substr,
|
||||||
|
n->progress ? pg : "",
|
||||||
|
MARKUP_NO);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
if (n->progress)
|
||||||
|
sprintf(pg, "%d", n->progress - 1);
|
||||||
|
|
||||||
|
notification_replace_single_field(
|
||||||
|
&n->msg,
|
||||||
|
&substr,
|
||||||
|
n->progress ? pg : "",
|
||||||
|
MARKUP_NO);
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
notification_replace_single_field(
|
||||||
|
&n->msg,
|
||||||
|
&substr,
|
||||||
|
"%",
|
||||||
|
MARKUP_NO);
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
fprintf(stderr, "WARNING: format_string has trailing %% character."
|
||||||
|
"To escape it use %%%%.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "WARNING: format_string %%%c"
|
||||||
|
" is unknown\n", substr[1]);
|
||||||
|
// shift substr pointer forward,
|
||||||
|
// as we can't interpret the format string
|
||||||
|
substr++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n->msg = g_strchomp(n->msg);
|
n->msg = g_strchomp(n->msg);
|
||||||
|
@ -73,7 +73,7 @@ int notification_is_duplicate(const notification *a, const notification *b);
|
|||||||
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_replace_format(const char *needle, const char *replacement, char *haystack, enum markup_mode markup);
|
void notification_replace_single_field(char **haystack, char **needle, const char *replacement, enum markup_mode markup_mode);
|
||||||
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);
|
||||||
|
@ -9,6 +9,9 @@ char *string_replace_char(char needle, char replacement, char *haystack);
|
|||||||
char *string_replace_all(const char *needle, const char *replacement,
|
char *string_replace_all(const char *needle, const char *replacement,
|
||||||
char *haystack);
|
char *haystack);
|
||||||
|
|
||||||
|
/* replace <len> characters with <repl> at position <pos> of the string <buf> */
|
||||||
|
char *string_replace_at(char *buf, int pos, int len, const char *repl);
|
||||||
|
|
||||||
/* replace needle with replacement in haystack */
|
/* replace needle with replacement in haystack */
|
||||||
char *string_replace(const char *needle, const char *replacement,
|
char *string_replace(const char *needle, const char *replacement,
|
||||||
char *haystack);
|
char *haystack);
|
||||||
|
@ -70,21 +70,28 @@ TEST test_notification_is_duplicate(void *notifications)
|
|||||||
PASS();
|
PASS();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST test_notification_replace_format(void)
|
TEST test_notification_replace_single_field(void)
|
||||||
{
|
{
|
||||||
char *str = g_malloc(128 * sizeof(char));
|
char *str = g_malloc(128 * sizeof(char));
|
||||||
|
char *substr = NULL;
|
||||||
strcpy(str, "Testing format replacement");
|
|
||||||
ASSERT_STR_EQ("Testing text replacement", (str = notification_replace_format("format", "text", str, MARKUP_FULL)));
|
|
||||||
|
|
||||||
strcpy(str, "Markup %a preserved");
|
strcpy(str, "Markup %a preserved");
|
||||||
ASSERT_STR_EQ("Markup and & <i>is</i> preserved", (str = notification_replace_format("%a", "and & <i>is</i>", str, MARKUP_FULL)));
|
substr = strchr(str, '%');
|
||||||
|
notification_replace_single_field(&str, &substr, "and & <i>is</i>", MARKUP_FULL);
|
||||||
|
ASSERT_STR_EQ("Markup and & <i>is</i> preserved", str);
|
||||||
|
ASSERT_EQ(26, substr - str);
|
||||||
|
|
||||||
strcpy(str, "Markup %a escaped");
|
strcpy(str, "Markup %a escaped");
|
||||||
ASSERT_STR_EQ("Markup and & <i>is</i> escaped", (str = notification_replace_format("%a", "and & <i>is</i>", str, MARKUP_NO)));
|
substr = strchr(str, '%');
|
||||||
|
notification_replace_single_field(&str, &substr, "and & <i>is</i>", MARKUP_NO);
|
||||||
|
ASSERT_STR_EQ("Markup and & <i>is</i> escaped", str);
|
||||||
|
ASSERT_EQ(38, substr - str);
|
||||||
|
|
||||||
strcpy(str, "Markup %a");
|
strcpy(str, "Markup %a");
|
||||||
ASSERT_STR_EQ("Markup is removed and & escaped", (str = notification_replace_format("%a", "<i>is removed</i> and & escaped", str, MARKUP_STRIP)));
|
substr = strchr(str, '%');
|
||||||
|
notification_replace_single_field(&str, &substr, "<i>is removed</i> and & escaped", MARKUP_STRIP);
|
||||||
|
ASSERT_STR_EQ("Markup is removed and & escaped", str);
|
||||||
|
ASSERT_EQ(35, substr - str);
|
||||||
|
|
||||||
g_free(str);
|
g_free(str);
|
||||||
PASS();
|
PASS();
|
||||||
@ -112,7 +119,7 @@ SUITE(suite_notification)
|
|||||||
g_free(a);
|
g_free(a);
|
||||||
g_free(b);
|
g_free(b);
|
||||||
|
|
||||||
RUN_TEST(test_notification_replace_format);
|
RUN_TEST(test_notification_replace_single_field);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user