diff --git a/data/org.freedesktop.portal.Notification.xml b/data/org.freedesktop.portal.Notification.xml
index 1c068b6dc..a4fa4ead3 100644
--- a/data/org.freedesktop.portal.Notification.xml
+++ b/data/org.freedesktop.portal.Notification.xml
@@ -118,6 +118,7 @@
Target parameter to send along when activating the action.
-->
+
diff --git a/src/notification.c b/src/notification.c
index ccceac17a..3876cfe99 100644
--- a/src/notification.c
+++ b/src/notification.c
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include "notification.h"
@@ -107,6 +108,7 @@ struct _CallData {
char *sender;
char *id;
GVariant *notification;
+ GUnixFDList *fd_list;
};
G_DECLARE_FINAL_TYPE (CallData, call_data, CALL, DATA, GObject)
@@ -124,7 +126,8 @@ call_data_new (GDBusMethodInvocation *inv,
XdpAppInfo *app_info,
const char *sender,
const char *id,
- GVariant *notification)
+ GVariant *notification,
+ GUnixFDList *fd_list)
{
CallData *call_data = g_object_new (call_data_get_type(), NULL);
@@ -134,6 +137,8 @@ call_data_new (GDBusMethodInvocation *inv,
call_data->id = g_strdup (id);
if (notification)
call_data->notification = g_variant_ref (notification);
+ if (fd_list)
+ call_data->fd_list = g_object_ref (fd_list);
return call_data;
}
@@ -149,6 +154,8 @@ call_data_finalize (GObject *object)
g_free (call_data->sender);
if (call_data->notification)
g_variant_unref (call_data->notification);
+ if (call_data->fd_list)
+ g_object_unref (call_data->fd_list);
G_OBJECT_CLASS (call_data_parent_class)->finalize (object);
}
@@ -346,9 +353,50 @@ parse_buttons (GVariantBuilder *builder,
return result;
}
+static gboolean
+parse_serialized_fd_icon (GVariantBuilder *builder,
+ GVariant *handle,
+ XdpAppInfo *app_info,
+ GUnixFDList *fd_list,
+ GError **error)
+{
+ int fd_id, fd;
+ g_autofree char *path = NULL;
+ GVariant *serialized_file_icon = NULL;
+
+ if (!check_value_type ("file-descriptor", handle, G_VARIANT_TYPE_HANDLE, error))
+ return FALSE;
+
+
+ fd_id = g_variant_get_handle (handle);
+ fd = g_unix_fd_list_get (fd_list, fd_id, error);
+
+ if (fd == -1)
+ return FALSE;
+
+ path = xdp_app_info_get_path_for_fd (app_info, fd, 0, NULL, NULL, error);
+ close (fd);
+
+ if (path == NULL)
+ return FALSE;
+
+ /* This is a serialized GFileIcon but there is no point in creating an object and then deserializing it */
+ serialized_file_icon = g_variant_new ("(sv)",
+ "file",
+ g_variant_new_take_string (g_steal_pointer (&path)));
+
+ if (xdp_validate_serialized_icon (serialized_file_icon, FALSE, NULL, NULL))
+ g_variant_builder_add_value (builder, serialized_file_icon);
+
+ return TRUE;
+}
+
+
static gboolean
parse_serialized_icon (GVariantBuilder *builder,
GVariant *icon,
+ XdpAppInfo *app_info,
+ GUnixFDList *fd_list,
GError **error)
{
const char *key;
@@ -369,6 +417,8 @@ parse_serialized_icon (GVariantBuilder *builder,
g_prefix_error (error, "invalid icon: ");
return FALSE;
}
+ if (xdp_validate_serialized_icon (value, FALSE, NULL, NULL))
+ g_variant_builder_add_value (builder, value);
}
else if (strcmp (key, "bytes") == 0)
{
@@ -377,6 +427,16 @@ parse_serialized_icon (GVariantBuilder *builder,
g_prefix_error (error, "invalid icon: ");
return FALSE;
}
+ if (xdp_validate_serialized_icon (value, FALSE, NULL, NULL))
+ g_variant_builder_add_value (builder, value);
+ }
+ else if (strcmp (key, "file-descriptor") == 0)
+ {
+ if (!parse_serialized_fd_icon (builder, value, app_info, fd_list, error))
+ {
+ g_prefix_error (error, "invalid icon: ");
+ return FALSE;
+ }
}
else
{
@@ -384,15 +444,14 @@ parse_serialized_icon (GVariantBuilder *builder,
return TRUE;
}
- if (xdp_validate_serialized_icon (value, FALSE, NULL, NULL))
- g_variant_builder_add_value (builder, value);
-
return TRUE;
}
static gboolean
parse_notification (GVariantBuilder *builder,
GVariant *notification,
+ XdpAppInfo *app_info,
+ GUnixFDList *fd_list,
GError **error)
{
int i;
@@ -416,7 +475,7 @@ parse_notification (GVariantBuilder *builder,
}
else if (strcmp (key, "icon") == 0)
{
- if (!parse_serialized_icon (builder, value, error))
+ if (!parse_serialized_icon (builder, value, app_info, fd_list, error))
return FALSE;
}
else if (strcmp (key, "priority") == 0)
@@ -464,7 +523,8 @@ add_in_thread_finished_cb (GObject *source_object,
if (g_task_propagate_boolean (G_TASK (result), &error))
{
xdp_dbus_notification_complete_add_notification (XDP_DBUS_NOTIFICATION (source_object),
- call_data->inv);
+ call_data->inv,
+ NULL);
}
else
{
@@ -500,7 +560,11 @@ handle_add_in_thread_func (GTask *task,
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
- if (!parse_notification (&builder, call_data->notification, &error))
+ if (!parse_notification (&builder,
+ call_data->notification,
+ call_data->app_info,
+ call_data->fd_list,
+ &error))
{
g_variant_builder_clear (&builder);
@@ -523,6 +587,7 @@ handle_add_in_thread_func (GTask *task,
static gboolean
notification_handle_add_notification (XdpDbusNotification *object,
GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
const char *arg_id,
GVariant *notification)
{
@@ -531,7 +596,12 @@ notification_handle_add_notification (XdpDbusNotification *object,
g_autoptr(GError) error = NULL;
CallData *call_data;
- call_data = call_data_new (invocation, call->app_info, call->sender, arg_id, notification);
+ call_data = call_data_new (invocation,
+ call->app_info,
+ call->sender,
+ arg_id,
+ notification,
+ fd_list);
task = g_task_new (object, NULL, add_in_thread_finished_cb, NULL);
g_task_set_task_data (task, call_data, g_object_unref);
g_task_run_in_thread (task, handle_add_in_thread_func);
@@ -571,7 +641,12 @@ notification_handle_remove_notification (XdpDbusNotification *object,
const char *arg_id)
{
Call *call = call_from_invocation (invocation);
- CallData *call_data = call_data_new (invocation, call->app_info, call->sender, arg_id, NULL);
+ CallData *call_data = call_data_new (invocation,
+ call->app_info,
+ call->sender,
+ arg_id,
+ NULL,
+ NULL);
xdp_dbus_impl_notification_call_remove_notification (impl,
xdp_app_info_get_id (call->app_info),
diff --git a/src/xdp-utils.c b/src/xdp-utils.c
index eb59444a4..3cfb4058d 100644
--- a/src/xdp-utils.c
+++ b/src/xdp-utils.c
@@ -2296,6 +2296,7 @@ xdp_validate_serialized_icon (GVariant *v,
g_autoptr(GIcon) icon = NULL;
GBytes *bytes;
__attribute__((cleanup(cleanup_temp_file))) char *name = NULL;
+ g_autofree char *path = NULL;
xdp_autofd int fd = -1;
g_autoptr(GOutputStream) stream = NULL;
int status;
@@ -2327,11 +2328,6 @@ xdp_validate_serialized_icon (GVariant *v,
return TRUE;
}
- if (!G_IS_BYTES_ICON (icon))
- {
- g_warning ("Unexpected icon type: %s", G_OBJECT_TYPE_NAME (icon));
- return FALSE;
- }
if (!g_file_test (icon_validator, G_FILE_TEST_EXISTS))
{
@@ -2339,29 +2335,47 @@ xdp_validate_serialized_icon (GVariant *v,
return FALSE;
}
- bytes = g_bytes_icon_get_bytes (G_BYTES_ICON (icon));
- fd = g_file_open_tmp ("iconXXXXXX", &name, &error);
- if (fd == -1)
+ if (G_IS_BYTES_ICON (icon))
{
- g_warning ("Icon validation: %s", error->message);
- return FALSE;
- }
+ bytes = g_bytes_icon_get_bytes (G_BYTES_ICON (icon));
+ fd = g_file_open_tmp ("iconXXXXXX", &name, &error);
+ if (fd == -1)
+ {
+ g_warning ("Icon validation: %s", error->message);
+ return FALSE;
+ }
- stream = g_unix_output_stream_new (fd, FALSE);
+ stream = g_unix_output_stream_new (fd, FALSE);
- /* Use write_all() instead of write_bytes() so we don't have to worry about
- * partial writes (https://gitlab.gnome.org/GNOME/glib/-/issues/570).
- */
- bytes_data = g_bytes_get_data (bytes, &bytes_len);
- if (!g_output_stream_write_all (stream, bytes_data, bytes_len, NULL, NULL, &error))
- {
- g_warning ("Icon validation: %s", error->message);
- return FALSE;
+ /* Use write_all() instead of write_bytes() so we don't have to worry about
+ * partial writes (https://gitlab.gnome.org/GNOME/glib/-/issues/570).
+ */
+ bytes_data = g_bytes_get_data (bytes, &bytes_len);
+ if (!g_output_stream_write_all (stream, bytes_data, bytes_len, NULL, NULL, &error))
+ {
+ g_warning ("Icon validation: %s", error->message);
+ return FALSE;
+ }
+
+ if (!g_output_stream_close (stream, NULL, &error))
+ {
+ g_warning ("Icon validation: %s", error->message);
+ return FALSE;
+ }
}
+ else if (G_IS_FILE_ICON (icon) && !bytes_only)
+ {
+ path = g_file_get_path (g_file_icon_get_file (G_FILE_ICON (icon)));
- if (!g_output_stream_close (stream, NULL, &error))
+ if (!path)
+ {
+ g_warning ("Icon validation: Invalid icon path");
+ return FALSE;
+ }
+ }
+ else
{
- g_warning ("Icon validation: %s", error->message);
+ g_warning ("Unexpected icon type: %s", G_OBJECT_TYPE_NAME (icon));
return FALSE;
}
@@ -2369,7 +2383,7 @@ xdp_validate_serialized_icon (GVariant *v,
args[1] = "--sandbox";
args[2] = MAX_ICON_SIZE;
args[3] = MAX_ICON_SIZE;
- args[4] = name;
+ args[4] = (name) ? name : path;
args[5] = NULL;
if (!g_spawn_sync (NULL, (char **)args, NULL, 0, NULL, NULL, &stdoutlog, &stderrlog, &status, &error))