summaryrefslogtreecommitdiffstats
path: root/plugins/exec
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/exec')
-rw-r--r--plugins/exec/CMakeLists.txt55
-rw-r--r--plugins/exec/exec_plugin.c340
-rw-r--r--plugins/exec/exec_plugin_config.h64
-rw-r--r--plugins/exec/scalable/emblems/org.remmina.Remmina-tool-symbolic.svg85
4 files changed, 544 insertions, 0 deletions
diff --git a/plugins/exec/CMakeLists.txt b/plugins/exec/CMakeLists.txt
new file mode 100644
index 0000000..4906f3b
--- /dev/null
+++ b/plugins/exec/CMakeLists.txt
@@ -0,0 +1,55 @@
+# remmina-plugin-tool_hello_world - The GTK+ Remote Desktop Client
+#
+# Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
+# Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the
+# OpenSSL library under certain conditions as described in each
+# individual source file, and distribute linked combinations
+# including the two.
+# You must obey the GNU General Public License in all respects
+# for all of the code used other than OpenSSL. If you modify
+# file(s) with this exception, you may extend this exception to your
+# version of the file(s), but you are not obligated to do so. If you
+# do not wish to do so, delete this exception statement from your
+# version. If you delete this exception statement from all source
+# files in the program, then also delete it here.
+
+
+set(REMMINA_PLUGIN_EXEC_SRCS
+ exec_plugin_config.h
+ exec_plugin.c
+)
+
+add_library(remmina-plugin-exec MODULE ${REMMINA_PLUGIN_EXEC_SRCS})
+set_target_properties(remmina-plugin-exec PROPERTIES PREFIX "")
+set_target_properties(remmina-plugin-exec PROPERTIES NO_SONAME 1)
+
+include_directories(${REMMINA_COMMON_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS})
+target_link_libraries(remmina-plugin-exec ${REMMINA_COMMON_LIBRARIES})
+
+install(TARGETS remmina-plugin-exec DESTINATION ${REMMINA_PLUGINDIR})
+
+install(FILES
+ scalable/emblems/org.remmina.Remmina-tool-symbolic.svg
+ DESTINATION ${APPICONSCALE_EMBLEMS_DIR})
+
+if(WITH_ICON_CACHE)
+ gtk_update_icon_cache("${REMMINA_DATADIR}/icons/hicolor")
+endif()
diff --git a/plugins/exec/exec_plugin.c b/plugins/exec/exec_plugin.c
new file mode 100644
index 0000000..f22b535
--- /dev/null
+++ b/plugins/exec/exec_plugin.c
@@ -0,0 +1,340 @@
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2017-2023 Antenore Gatta, Giovanni Panozzo
+ *
+ * Initially based on the plugin "Remmina Plugin EXEC", created and written by
+ * Fabio Castelli (Muflone) <muflone@vbsimple.net>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. * If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. * If you
+ * do not wish to do so, delete this exception statement from your
+ * version. * If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ *
+ */
+
+#include "exec_plugin_config.h"
+
+#include "common/remmina_plugin.h"
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define GET_PLUGIN_DATA(gp) (RemminaPluginExecData*)g_object_get_data(G_OBJECT(gp), "plugin-data")
+
+typedef struct _RemminaPluginExecData {
+ GtkWidget *log_view;
+ GtkTextBuffer *log_buffer;
+ GtkTextBuffer *err;
+ GtkWidget *sw;
+ GPid pid;
+} RemminaPluginExecData;
+
+static RemminaPluginService *remmina_plugin_service = NULL;
+#define REMMINA_PLUGIN_DEBUG(fmt, ...) remmina_plugin_service->_remmina_debug(__func__, fmt, ##__VA_ARGS__)
+
+
+ static void
+cb_child_watch( GPid pid, gint status)
+{
+ /* Close pid */
+ g_spawn_close_pid( pid );
+}
+
+static void cb_child_setup(gpointer data){
+ int pid = getpid();
+ setpgid(pid, 0);
+}
+
+ static gboolean
+cb_out_watch (GIOChannel *channel, GIOCondition cond, RemminaProtocolWidget *gp)
+{
+ gchar *string;
+ gsize size;
+
+ RemminaPluginExecData *gpdata = GET_PLUGIN_DATA(gp);
+
+ if( cond == G_IO_HUP )
+ {
+ g_io_channel_unref( channel );
+ return FALSE;
+ }
+
+ g_io_channel_read_line( channel, &string, &size, NULL, NULL );
+ gtk_text_buffer_insert_at_cursor( gpdata->log_buffer, string, -1 );
+ g_free( string );
+
+ return TRUE;
+}
+
+ static gboolean
+cb_err_watch (GIOChannel *channel, GIOCondition cond, RemminaProtocolWidget *gp)
+{
+ gchar *string;
+ gsize size;
+
+ RemminaPluginExecData *gpdata = GET_PLUGIN_DATA(gp);
+
+ if( cond == G_IO_HUP )
+ {
+ g_io_channel_unref( channel );
+ return FALSE;
+ }
+
+ g_io_channel_read_line( channel, &string, &size, NULL, NULL );
+ gtk_text_buffer_insert_at_cursor( gpdata->err, string, -1 );
+ g_free( string );
+
+ return TRUE;
+}
+
+static void remmina_plugin_exec_init(RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
+ RemminaPluginExecData *gpdata;
+
+ REMMINA_PLUGIN_DEBUG("[%s] Plugin init", PLUGIN_NAME);
+
+ gpdata = g_new0(RemminaPluginExecData, 1);
+ g_object_set_data_full(G_OBJECT(gp), "plugin-data", gpdata, g_free);
+
+ gpdata->pid = 0;
+ gpdata->log_view = gtk_text_view_new();
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gpdata->log_view), GTK_WRAP_CHAR);
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(gpdata->log_view), FALSE);
+ gtk_text_view_set_left_margin (GTK_TEXT_VIEW (gpdata->log_view), 20);
+ gtk_text_view_set_right_margin (GTK_TEXT_VIEW (gpdata->log_view), 20);
+ gpdata->log_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gpdata->log_view));
+ gpdata->sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_set_size_request (gpdata->sw, 640, 480);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (gpdata->sw),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(gp), gpdata->sw);
+ gtk_container_add(GTK_CONTAINER(gpdata->sw), gpdata->log_view);
+ gtk_text_buffer_set_text (gpdata->log_buffer, "Remmina Exec Plugin Logger", -1);
+
+ gtk_widget_show_all(gpdata->sw);
+}
+
+static gboolean remmina_plugin_exec_run(RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
+ RemminaFile* remminafile;
+ const gchar *cmd;
+ gchar *stdout_buffer;
+ gchar *stderr_buffer;
+ char **argv;
+ GError *error = NULL;
+ GPid child_pid;
+ gint child_stdout, child_stderr;
+ GtkDialog *dialog;
+ GIOChannel *out_ch, *err_ch;
+
+ REMMINA_PLUGIN_DEBUG("[%s] Plugin run", PLUGIN_NAME);
+ RemminaPluginExecData *gpdata = GET_PLUGIN_DATA(gp);
+ remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
+
+ cmd = remmina_plugin_service->file_get_string(remminafile, "execcommand");
+ if (!cmd) {
+ gtk_text_buffer_set_text (gpdata->log_buffer,
+ _("You did not set any command to be executed"), -1);
+ remmina_plugin_service->protocol_plugin_signal_connection_opened(gp);
+ return TRUE;
+ }
+
+ g_shell_parse_argv(cmd, NULL, &argv, &error);
+ if (error) {
+ gtk_text_buffer_set_text (gpdata->log_buffer, error->message, -1);
+ remmina_plugin_service->protocol_plugin_signal_connection_opened(gp);
+ g_error_free(error);
+ return TRUE;
+ }
+
+ if (remmina_plugin_service->file_get_int(remminafile, "runasync", FALSE)) {
+ REMMINA_PLUGIN_DEBUG("[%s] Run Async", PLUGIN_NAME);
+ g_spawn_async_with_pipes( NULL,
+ argv,
+ NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD |
+ G_SPAWN_SEARCH_PATH_FROM_ENVP |
+ G_SPAWN_SEARCH_PATH,
+ cb_child_setup,
+ NULL,
+ &child_pid,
+ NULL,
+ &child_stdout,
+ &child_stderr,
+ &error);
+ if (error != NULL) {
+ gtk_text_buffer_set_text (gpdata->log_buffer, error->message, -1);
+ g_error_free(error);
+ remmina_plugin_service->protocol_plugin_signal_connection_opened(gp);
+ return TRUE;
+ }
+ g_child_watch_add(child_pid, (GChildWatchFunc)cb_child_watch, gp );
+
+ gpdata->pid = child_pid;
+ /* Create channels that will be used to read data from pipes. */
+ out_ch = g_io_channel_unix_new(child_stdout);
+ err_ch = g_io_channel_unix_new(child_stderr);
+ /* Add watches to channels */
+ g_io_add_watch(out_ch, G_IO_IN | G_IO_HUP, (GIOFunc)cb_out_watch, gp );
+ g_io_add_watch(err_ch, G_IO_IN | G_IO_HUP, (GIOFunc)cb_err_watch, gp );
+
+ }else {
+ dialog = GTK_DIALOG(gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+ _("Warning: Running a command synchronously may cause Remmina not to respond.\nDo you really want to continue?")));
+ gint result = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ switch (result)
+ {
+ case GTK_RESPONSE_YES:
+ break;
+ default:
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ return FALSE;
+ break;
+ }
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ REMMINA_PLUGIN_DEBUG("[%s] Run Sync", PLUGIN_NAME);
+ g_spawn_sync (NULL, // CWD or NULL
+ argv,
+ NULL, // ENVP or NULL
+ G_SPAWN_SEARCH_PATH |
+ G_SPAWN_SEARCH_PATH_FROM_ENVP,
+ NULL,
+ NULL,
+ &stdout_buffer, // STDOUT
+ &stderr_buffer, // STDERR
+ NULL, // Exit status
+ &error);
+ if (!error) {
+ REMMINA_PLUGIN_DEBUG("[%s] Command executed", PLUGIN_NAME);
+ gtk_text_buffer_set_text (gpdata->log_buffer, stdout_buffer, -1);
+ }else {
+ g_warning("Command %s exited with error: %s\n", cmd, error->message);
+ gtk_text_buffer_set_text (gpdata->log_buffer, error->message, -1);
+ g_error_free(error);
+ }
+ }
+
+ g_strfreev(argv);
+
+ remmina_plugin_service->protocol_plugin_signal_connection_opened(gp);
+ return TRUE;
+}
+
+static gboolean remmina_plugin_exec_close(RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
+ REMMINA_PLUGIN_DEBUG("[%s] Plugin close", PLUGIN_NAME);
+ RemminaPluginExecData *gpdata = GET_PLUGIN_DATA(gp);
+ //if async process was started, make sure it's dead if option is selected
+ RemminaFile* remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
+ if (remmina_plugin_service->file_get_int(remminafile, "kill_proc", FALSE)) {
+ if (gpdata->pid !=0 ){
+ int pgid = getpgid(gpdata->pid);
+ if (pgid != 0){
+ kill(-gpdata->pid, SIGHUP);
+ }
+ else{
+ kill(gpdata->pid, SIGHUP);
+ }
+
+ }
+ }
+ remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
+ return FALSE;
+}
+
+/* Array of RemminaProtocolSetting for basic settings.
+ * Each item is composed by:
+ * a) RemminaProtocolSettingType for setting type
+ * b) Setting name
+ * c) Setting description
+ * d) Compact disposition
+ * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
+ * f) Setting tooltip
+ * g) Validation data pointer, will be passed to the validation callback method.
+ * h) Validation callback method (Can be NULL. Every entry will be valid then.)
+ * use following prototype:
+ * gboolean mysetting_validator_method(gpointer key, gpointer value,
+ * gpointer validator_data);
+ * gpointer key is a gchar* containing the setting's name,
+ * gpointer value contains the value which should be validated,
+ * gpointer validator_data contains your passed data.
+ */
+static const RemminaProtocolSetting remmina_plugin_exec_basic_settings[] =
+{
+ { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execcommand", N_("Command"), FALSE, NULL, NULL, NULL, NULL },
+ { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "runasync", N_("Asynchronous execution"), FALSE, NULL, NULL, NULL, NULL },
+ { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "kill_proc", N_("Kill process on disconnect"), FALSE, NULL, NULL, NULL, NULL },
+ { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
+};
+
+/* Protocol plugin definition and features */
+static RemminaProtocolPlugin remmina_plugin = {
+ REMMINA_PLUGIN_TYPE_PROTOCOL, // Type
+ PLUGIN_NAME, // Name
+ PLUGIN_DESCRIPTION, // Description
+ GETTEXT_PACKAGE, // Translation domain
+ PLUGIN_VERSION, // Version number
+ PLUGIN_APPICON, // Icon for normal connection
+ PLUGIN_APPICON, // Icon for SSH connection
+ remmina_plugin_exec_basic_settings, // Array for basic settings
+ NULL, // Array for advanced settings
+ REMMINA_PROTOCOL_SSH_SETTING_NONE, // SSH settings type
+ NULL, // Array for available features
+ remmina_plugin_exec_init, // Plugin initialization
+ remmina_plugin_exec_run, // Plugin open connection
+ remmina_plugin_exec_close, // Plugin close connection
+ NULL, // Query for available features
+ NULL, // Call a feature
+ NULL, // Send a keystroke
+ NULL, // No screenshot support available
+ NULL, // RCW map event
+ NULL // RCW unmap event
+};
+
+G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
+{
+ TRACE_CALL(__func__);
+ remmina_plugin_service = service;
+
+ bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+
+ if (!service->register_plugin((RemminaPlugin*)&remmina_plugin)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/plugins/exec/exec_plugin_config.h b/plugins/exec/exec_plugin_config.h
new file mode 100644
index 0000000..d62a4fa
--- /dev/null
+++ b/plugins/exec/exec_plugin_config.h
@@ -0,0 +1,64 @@
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
+ *
+ * Initially based on the plugin "Remmina Plugin EXEC", created and written by
+ * Fabio Castelli (Muflone) <muflone@vbsimple.net>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. * If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. * If you
+ * do not wish to do so, delete this exception statement from your
+ * version. * If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ *
+ */
+
+#pragma once
+
+#define PLUGIN_NAME "EXEC"
+#define PLUGIN_DESCRIPTION N_("Execute a command")
+#define PLUGIN_VERSION "1.0"
+#define PLUGIN_APPICON "org.remmina.Remmina-tool-symbolic"
+
+#define REMMINA_PLUGIN_INFO(fmt, ...) \
+ remmina_plugin_service->_remmina_info(__func__, fmt, ##__VA_ARGS__)
+
+#define REMMINA_PLUGIN_MESSAGE(fmt, ...) \
+ remmina_plugin_service->_remmina_message(__func, fmt, ##__VA_ARGS__)
+
+#define REMMINA_PLUGIN_DEBUG(fmt, ...) \
+ remmina_plugin_service->_remmina_debug(__func__, fmt, ##__VA_ARGS__)
+
+#define REMMINA_PLUGIN_WARNING(fmt, ...) \
+ remmina_plugin_service->_remmina_warning(__func__, fmt, ##__VA_ARGS__)
+
+/* This will intentionally crash Remmina */
+#define REMMINA_PLUGIN_ERROR(fmt, ...) \
+ remmina_plugin_service->_remmina_error(__func__, fmt, ##__VA_ARGS__)
+
+#define REMMINA_PLUGIN_CRITICAL(fmt, ...) \
+ remmina_plugin_service->_remmina_critical(__func__, fmt, ##__VA_ARGS__)
+#define REMMINA_PLUGIN_AUDIT(fmt, ...) \
+ remmina_plugin_service->_remmina_audit(__func__, fmt, ##__VA_ARGS__)
diff --git a/plugins/exec/scalable/emblems/org.remmina.Remmina-tool-symbolic.svg b/plugins/exec/scalable/emblems/org.remmina.Remmina-tool-symbolic.svg
new file mode 100644
index 0000000..f383629
--- /dev/null
+++ b/plugins/exec/scalable/emblems/org.remmina.Remmina-tool-symbolic.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ version="1.1"
+ id="svg8"
+ inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
+ sodipodi:docname="org.remmina.Remmina-tool-symbolic.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.871974"
+ inkscape:cx="34.28242"
+ inkscape:cy="27.670209"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ showgrid="false"
+ borderlayer="true"
+ inkscape:showpageshadow="true"
+ units="px"
+ inkscape:pagecheckerboard="false"
+ showguides="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="995"
+ inkscape:window-x="1080"
+ inkscape:window-y="427"
+ inkscape:window-maximized="1"
+ objecttolerance="10"
+ guidetolerance="10"
+ inkscape:snap-tangential="true"
+ inkscape:snap-perpendicular="true"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:deskcolor="#d1d1d1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid10"
+ dotted="false"
+ originx="-171.36869"
+ originy="-105.18186" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-171.36866,-165.16877)">
+ <path
+ d="m 187.77406,165.16877 v 0.20572 l -7.85028,10.64488 c 0.22721,0.0656 0.45083,0.14294 0.66991,0.23189 -0.77754,-0.31322 -1.62348,-0.4954 -2.51368,-0.4954 -1.77942,0 -3.48494,0.70612 -4.74227,1.95807 -0.35468,0.35318 -0.66823,0.74465 -0.93515,1.16728 l 3.12261,3.10514 -2.0827,2.82424 c 0.4982,0.95633 1.28315,1.73475 2.24581,2.22754 l 2.83728,-2.06819 3.12548,3.10799 c 0.42429,-0.26637 0.817,-0.57912 1.17098,-0.93253 1.25898,-1.25029 1.96741,-2.94651 1.96908,-4.71574 0,-0.8619 -0.17842,-1.6798 -0.47762,-2.43611 0.0814,0.19645 0.15331,0.39646 0.21549,0.59958 l 10.70216,-8.009 z m -12.05944,0.3332 -4.21776,4.19702 5.47604,5.44278 4.21801,-4.19416 z m 13.91206,13.83421 -4.21801,4.19703 5.47628,5.44563 4.21801,-4.19726 z m -17.14253,6.67356 -1.11549,1.63082 1.49123,1.48312 1.52064,-1.10949 c -0.75315,-0.49516 -1.39819,-1.13659 -1.89638,-1.88553 z"
+ id="path32"
+ inkscape:connector-curvature="0"
+ style="isolation:isolate;fill:#171717;stroke-width:0.2385" />
+ </g>
+</svg>