move notification text escaping into dbus notify method callback

this ensures that notification text reaching the module can be considered
"usable" without forcing multiple escape passes onto the same notification

fix T2757
This commit is contained in:
Mike Blumenkrantz 2016-03-30 16:08:05 -04:00
parent ee16177660
commit 7ae25149c7
2 changed files with 160 additions and 160 deletions

View File

@ -69,12 +69,169 @@ hints_dict_iter(void *data, const void *key, Eldbus_Message_Iter *var)
}
}
/* this function should be external in edje for use in cases such as this module.
*
* happily, it was decided that the function would not be external so that it could
* be duplicated into the module in full.
*/
static int
_text_escape(Eina_Strbuf *txt, const char *text)
{
const char *escaped;
int advance;
escaped = evas_textblock_string_escape_get(text, &advance);
if (!escaped)
{
eina_strbuf_append_char(txt, text[0]);
advance = 1;
}
else
eina_strbuf_append(txt, escaped);
return advance;
}
/* hardcoded list of allowed tags based on
* https://people.gnome.org/~mccann/docs/notification-spec/notification-spec-latest.html#markup
*/
static const char *tags[] =
{
"<b",
"<i",
"<u",
//"<a", FIXME: we can't actually display these right now
//"<img",
};
static const char *
_get_tag(const char *c)
{
unsigned int i;
if (c[1] != '>') return NULL;
for (i = 0; i < EINA_C_ARRAY_LENGTH(tags); i++)
if (tags[i][1] == c[0]) return tags[i];
return NULL;
}
char *
_nedje_text_escape(const char *text)
{
Eina_Strbuf *txt;
char *ret;
const char *text_end;
size_t text_len;
Eina_Array *arr;
const char *cur_tag = NULL;
if (!text) return NULL;
txt = eina_strbuf_new();
text_len = strlen(text);
arr = eina_array_new(3);
text_end = text + text_len;
while (text < text_end)
{
int advance;
if ((text[0] == '<') && text[1])
{
const char *tag, *popped;
Eina_Bool closing = EINA_FALSE;
if (text[1] == '/') //closing tag
{
closing = EINA_TRUE;
tag = _get_tag(text + 2);
}
else
tag = _get_tag(text + 1);
if (closing)
{
if (cur_tag && (tag != cur_tag))
{
/* tag mismatch: autoclose all failure tags
* not technically required by the spec,
* but it makes me feel better about myself
*/
do
{
popped = eina_array_pop(arr);
if (eina_array_count(arr))
cur_tag = eina_array_data_get(arr, eina_array_count(arr) - 1);
else
cur_tag = NULL;
eina_strbuf_append_printf(txt, "</%c>", popped[1]);
} while (cur_tag && (popped != tag));
advance = 4;
}
else if (cur_tag)
{
/* tag match: just pop */
popped = eina_array_pop(arr);
if (eina_array_count(arr))
cur_tag = eina_array_data_get(arr, eina_array_count(arr) - 1);
else
cur_tag = NULL;
eina_strbuf_append_printf(txt, "</%c>", popped[1]);
advance = 4;
}
else
{
/* no current tag: escape */
advance = _text_escape(txt, text);
}
}
else
{
if (tag)
{
cur_tag = tag;
eina_array_push(arr, tag);
eina_strbuf_append_printf(txt, "<%c>", tag[1]);
advance = 3;
}
else
advance = _text_escape(txt, text);
}
}
else if (text[0] == '&')
{
const char *s;
s = strchr(text, ';');
if (s)
s = evas_textblock_escape_string_range_get(text, s + 1);
if (s)
{
eina_strbuf_append_char(txt, text[0]);
advance = 1;
}
else
advance = _text_escape(txt, text);
}
else
advance = _text_escape(txt, text);
text += advance;
}
eina_array_free(arr);
ret = eina_strbuf_string_steal(txt);
eina_strbuf_free(txt);
return ret;
}
static Eldbus_Message *
notify_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
E_Notification_Notify *n;
Eldbus_Message_Iter *actions_iter, *hints_iter;
Eldbus_Message *reply;
char *txt;
if (!n_data->notify_cb)
return NULL;
@ -100,7 +257,9 @@ notify_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Messag
n->app_name = eina_stringshare_add(n->app_name);
n->icon.icon = eina_stringshare_add(n->icon.icon);
n->summary = eina_stringshare_add(n->summary);
n->body = eina_stringshare_add(n->body);
txt = _nedje_text_escape(n->body);
n->body = eina_stringshare_add(txt);
free(txt);
e_object_ref(E_OBJECT(n));
n->id = n_data->notify_cb(n_data->data, n);

View File

@ -12,160 +12,6 @@ static void _notification_popup_del(unsigned int id,
static void _notification_popdown(Popup_Data *popup,
E_Notification_Notify_Closed_Reason reason);
/* this function should be external in edje for use in cases such as this module.
*
* happily, it was decided that the function would not be external so that it could
* be duplicated into the module in full.
*/
static int
_text_escape(Eina_Strbuf *txt, const char *text)
{
const char *escaped;
int advance;
escaped = evas_textblock_string_escape_get(text, &advance);
if (!escaped)
{
eina_strbuf_append_char(txt, text[0]);
advance = 1;
}
else
eina_strbuf_append(txt, escaped);
return advance;
}
/* hardcoded list of allowed tags based on
* https://people.gnome.org/~mccann/docs/notification-spec/notification-spec-latest.html#markup
*/
static const char *tags[] =
{
"<b",
"<i",
"<u",
//"<a", FIXME: we can't actually display these right now
//"<img",
};
static const char *
_get_tag(const char *c)
{
unsigned int i;
if (c[1] != '>') return NULL;
for (i = 0; i < EINA_C_ARRAY_LENGTH(tags); i++)
if (tags[i][1] == c[0]) return tags[i];
return NULL;
}
char *
_nedje_text_escape(const char *text)
{
Eina_Strbuf *txt;
char *ret;
const char *text_end;
size_t text_len;
Eina_Array *arr;
const char *cur_tag = NULL;
if (!text) return NULL;
txt = eina_strbuf_new();
text_len = strlen(text);
arr = eina_array_new(3);
text_end = text + text_len;
while (text < text_end)
{
int advance;
if ((text[0] == '<') && text[1])
{
const char *tag, *popped;
Eina_Bool closing = EINA_FALSE;
if (text[1] == '/') //closing tag
{
closing = EINA_TRUE;
tag = _get_tag(text + 2);
}
else
tag = _get_tag(text + 1);
if (closing)
{
if (cur_tag && (tag != cur_tag))
{
/* tag mismatch: autoclose all failure tags
* not technically required by the spec,
* but it makes me feel better about myself
*/
do
{
popped = eina_array_pop(arr);
if (eina_array_count(arr))
cur_tag = eina_array_data_get(arr, eina_array_count(arr) - 1);
else
cur_tag = NULL;
eina_strbuf_append_printf(txt, "</%c>", popped[1]);
} while (cur_tag && (popped != tag));
advance = 4;
}
else if (cur_tag)
{
/* tag match: just pop */
popped = eina_array_pop(arr);
if (eina_array_count(arr))
cur_tag = eina_array_data_get(arr, eina_array_count(arr) - 1);
else
cur_tag = NULL;
eina_strbuf_append_printf(txt, "</%c>", popped[1]);
advance = 4;
}
else
{
/* no current tag: escape */
advance = _text_escape(txt, text);
}
}
else
{
if (tag)
{
cur_tag = tag;
eina_array_push(arr, tag);
eina_strbuf_append_printf(txt, "<%c>", tag[1]);
advance = 3;
}
else
advance = _text_escape(txt, text);
}
}
else if (text[0] == '&')
{
const char *s;
s = strchr(text, ';');
if (s)
s = evas_textblock_escape_string_range_get(text, s + 1);
if (s)
{
eina_strbuf_append_char(txt, text[0]);
advance = 1;
}
else
advance = _text_escape(txt, text);
}
else
advance = _text_escape(txt, text);
text += advance;
}
eina_array_free(arr);
ret = eina_strbuf_string_steal(txt);
eina_strbuf_free(txt);
return ret;
}
#define POPUP_GAP 10
#define POPUP_TO_EDGE 15
@ -259,7 +105,6 @@ notification_popup_notify(E_Notification_Notify *n,
unsigned int id)
{
Popup_Data *popup = NULL;
char *esc;
switch (n->urgency)
{
@ -280,10 +125,6 @@ notification_popup_notify(E_Notification_Notify *n,
if (notification_cfg->ignore_replacement)
n->replaces_id = 0;
esc = _nedje_text_escape(n->body);
eina_stringshare_replace(&n->body, esc);
free(esc);
if (n->replaces_id && (popup = _notification_popup_find(n->replaces_id)))
{
if (popup->notif)