/* Copyright 2016 Software Freedom Conservancy Inc. * * Copyright 2011 Valentín Barros Puertas * Copyright 2018 Ricardo Fantin da Costa * Copyright 2018 Narendra A * * This software is licensed under the GNU LGPL (version 2.1 or later). * See the COPYING file in this distribution. */ #include "shotwell-facedetect.hpp" #include "dbus-interface.h" #include #include #include constexpr std::string_view FACEDETECT_INTERFACE_NAME{ "org.gnome.Shotwell.Faces1" }; constexpr std::string_view FACEDETECT_PATH{ "/org/gnome/shotwell/faces" }; GVariant *FaceRect::serialize() const { return g_variant_new("(dddd@ad)", x, y, width, height, g_variant_new_fixed_array(G_VARIANT_TYPE_DOUBLE, vec.data(), vec.size(), sizeof(double))); } // DBus binding functions static gboolean on_handle_detect_faces(ShotwellFaces1 *object, GDBusMethodInvocation *invocation, [[maybe_unused]]const gchar *arg_image, const gchar *arg_cascade, gdouble arg_scale, gboolean arg_infer) { g_auto(GVariantBuilder) builder = G_VARIANT_BUILDER_INIT(G_VARIANT_TYPE("a(ddddad)")); auto rects = detectFaces(arg_image, arg_scale, arg_infer == TRUE); // Construct return value for(const auto &rect : rects) { g_variant_builder_add(&builder, "@(ddddad)", rect.serialize()); g_debug("Returning %f,%f-%f", rect.x, rect.y, rect.vec.back()); } // Call return shotwell_faces1_complete_detect_faces(object, invocation, g_variant_builder_end(&builder)); return TRUE; } static gboolean on_handle_load_net(ShotwellFaces1 *object, GDBusMethodInvocation *invocation, const gchar *arg_net) { // Call return shotwell_faces1_complete_load_net(object, invocation, loadNet(arg_net) ? TRUE : FALSE); return TRUE; } static gboolean on_handle_terminate(ShotwellFaces1 *object, GDBusMethodInvocation *invocation, gpointer user_data) { g_debug("Exiting..."); shotwell_faces1_complete_terminate(object, invocation); g_main_loop_quit(static_cast(user_data)); return TRUE; } static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { g_debug("Got name %s", name); auto *interface = shotwell_faces1_skeleton_new(); g_signal_connect(interface, "handle-detect-faces", G_CALLBACK (on_handle_detect_faces), nullptr); g_signal_connect(interface, "handle-terminate", G_CALLBACK (on_handle_terminate), user_data); g_signal_connect(interface, "handle-load-net", G_CALLBACK (on_handle_load_net), nullptr); g_autoptr(GError) error = nullptr; g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(interface), connection, FACEDETECT_PATH.data(), &error); if (error != nullptr) { g_print("Failed to export interface: %s", error->message); } } static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) { if (connection == nullptr) { g_debug("Unable to establish connection for name %s", name); } else { g_debug("Connection for name %s disconnected", name); } g_main_loop_quit(static_cast(user_data)); } static char* address = nullptr; static GOptionEntry entries[] = { { "address", 'a', 0, G_OPTION_ARG_STRING, &address, "Use private DBus ADDRESS instead of session", "ADDRESS" }, { nullptr } }; static gboolean on_authorize_authenticated_peer([[maybe_unused]] GIOStream *iostream, GCredentials *credentials, [[maybe_unused]] gpointer user_data) { g_autoptr(GCredentials) own_credentials = nullptr; g_debug("Authorizing peer with credentials %s\n", g_credentials_to_string(credentials)); if(credentials == nullptr) { return FALSE; } own_credentials = g_credentials_new(); { g_autoptr(GError) error = nullptr; if(g_credentials_is_same_user(credentials, own_credentials, &error) == FALSE) { g_warning("Unable to authorize peer: %s", error->message); return FALSE; } } return TRUE; } int main(int argc, char **argv) { GMainLoop *loop; GError *error = nullptr; GOptionContext *context; context = g_option_context_new ("- Shotwell face detection helper service"); g_option_context_add_main_entries (context, entries, "shotwell"); if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { g_print ("Failed to parse options: %s\n", error->message); exit(1); } loop = g_main_loop_new (nullptr, FALSE); // We are running on the session bus if (address == nullptr) { g_debug("Starting %s on G_BUS_TYPE_SESSION", argv[0]); g_bus_own_name(G_BUS_TYPE_SESSION, FACEDETECT_INTERFACE_NAME.data(), G_BUS_NAME_OWNER_FLAGS_NONE, nullptr, on_name_acquired, on_name_lost, loop, nullptr); } else { g_debug("Starting %s on %s", argv[0], address); GDBusAuthObserver *observer = g_dbus_auth_observer_new (); g_signal_connect (G_OBJECT (observer), "authorize-authenticated-peer", G_CALLBACK (on_authorize_authenticated_peer), nullptr); GDBusConnection *connection = g_dbus_connection_new_for_address_sync (address, G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, observer, nullptr, &error); if (connection != nullptr) { on_name_acquired (connection, FACEDETECT_INTERFACE_NAME.data (), loop); } } if (error != nullptr) { g_error("Failed to get connection on %s bus: %s", address == nullptr ? "session" : "private", error->message); } g_main_loop_run (loop); return 0; }