diff options
-rw-r--r-- | cmake/FindJSONGLIB.cmake | 44 | ||||
-rw-r--r-- | cmake/FindLIBSOUP24.cmake | 46 | ||||
-rw-r--r-- | remmina/CMakeLists.txt | 18 | ||||
-rw-r--r-- | remmina/src/remmina.c | 4 | ||||
-rw-r--r-- | remmina/src/remmina_main.c | 46 | ||||
-rw-r--r-- | remmina/src/remmina_main.h | 1 | ||||
-rw-r--r-- | remmina/src/remmina_pref.c | 19 | ||||
-rw-r--r-- | remmina/src/remmina_pref.h | 6 | ||||
-rw-r--r-- | remmina/src/remmina_stats.c | 204 | ||||
-rw-r--r-- | remmina/src/remmina_stats.h | 47 | ||||
-rw-r--r-- | remmina/src/remmina_stats_sender.c | 200 | ||||
-rw-r--r-- | remmina/src/remmina_stats_sender.h | 48 | ||||
-rw-r--r-- | remmina/ui/remmina_main.glade | 70 | ||||
-rw-r--r-- | snap/snapcraft.yaml.in | 2 |
14 files changed, 751 insertions, 4 deletions
diff --git a/cmake/FindJSONGLIB.cmake b/cmake/FindJSONGLIB.cmake new file mode 100644 index 000000000..1bcfdcf67 --- /dev/null +++ b/cmake/FindJSONGLIB.cmake @@ -0,0 +1,44 @@ +# Remmina - The GTK+ Remote Desktop Client +# +# Copyright (C) 2011 Marc-Andre Moreau +# Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo +# Copyright (C) 2016-2018 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. + +include(FindPackageHandleStandardArgs) + +pkg_check_modules(PC_JSONGLIB json-glib-1.0) + +find_path(JSONGLIB_INCLUDE_DIR NAMES json-glib/json-glib.h + HINTS ${PC_JSONGLIB_INCLUDEDIR} ${PC_JSONGLIB_INCLUDE_DIRS} +) + +find_library(JSONGLIB_LIBRARY NAMES json-glib-1.0 + HINTS ${PC_JSONGLIB_LIBDIR} ${PC_JSONGLIB_LIBRARY_DIRS} +) + +if (JSONGLIB_INCLUDE_DIR AND JSONGLIB_LIBRARY) + find_package_handle_standard_args(JSONGLIB DEFAULT_MSG JSONGLIB_LIBRARY JSONGLIB_INCLUDE_DIR) +endif() + +if (JSONGLIB_FOUND) + set(JSONGLIB_LIBRARIES ${JSONGLIB_LIBRARY}) + set(JSONGLIB_INCLUDE_DIRS ${JSONGLIB_INCLUDE_DIR}) +endif() + +mark_as_advanced(JSONGLIB_INCLUDE_DIR JSONGLIB_LIBRARY) + diff --git a/cmake/FindLIBSOUP24.cmake b/cmake/FindLIBSOUP24.cmake new file mode 100644 index 000000000..ab84f6229 --- /dev/null +++ b/cmake/FindLIBSOUP24.cmake @@ -0,0 +1,46 @@ +# Remmina - The GTK+ Remote Desktop Client +# +# Copyright (C) 2011 Marc-Andre Moreau +# Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo +# Copyright (C) 2016-2018 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. + +include(FindPackageHandleStandardArgs) + +pkg_check_modules(PC_LIBSOUP24 libsoup-2.4) + + +find_path(LIBSOUP24_INCLUDE_DIR NAMES libsoup/soup.h + HINTS ${PC_LIBSOUP24_INCLUDEDIR} ${PC_LIBSOUP24_INCLUDE_DIRS} +) + +find_library(LIBSOUP24_LIBRARY + NAMES soup-2.4 + HINTS ${PC_LIBSOUP24_LIBDIR} ${PC_LIBSOUP24_LIBRARY_DIRS} + ) + +if (LIBSOUP24_INCLUDE_DIR AND LIBSOUP24_LIBRARY) + find_package_handle_standard_args(LIBSOUP24 DEFAULT_MSG LIBSOUP24_LIBRARY LIBSOUP24_INCLUDE_DIR) +endif() + +if (LIBSOUP24_FOUND) + set(LIBSOUP24_LIBRARIES ${LIBSOUP24_LIBRARY}) + set(LIBSOUP24_INCLUDE_DIRS ${LIBSOUP24_INCLUDE_DIR}) +endif() + +mark_as_advanced(LIBSOUP24_INCLUDE_DIR LIBSOUP24_LIBRARY) + diff --git a/remmina/CMakeLists.txt b/remmina/CMakeLists.txt index cc35b7401..bb28730b5 100644 --- a/remmina/CMakeLists.txt +++ b/remmina/CMakeLists.txt @@ -112,6 +112,10 @@ list(APPEND REMMINA_SRCS "src/remmina_connection_window.h" "src/remmina_mpchange.c" "src/remmina_mpchange.h" + "src/remmina_stats.c" + "src/remmina_stats.h" + "src/remmina_stats_sender.c" + "src/remmina_stats_sender.h" ) add_executable(remmina ${REMMINA_SRCS}) @@ -174,6 +178,20 @@ if(GTK3_FOUND) include_directories(${APPINDICATOR_INCLUDE_DIRS}) target_link_libraries(remmina ${APPINDICATOR_LIBRARIES}) endif() + find_required_package(JSONGLIB) + if (JSONGLIB_FOUND) + include_directories(${JSONGLIB_INCLUDE_DIRS}) + target_link_libraries(remmina ${JSONGLIB_LIBRARIES}) + else() + message(FATAL_ERROR "json-glib library not found") + endif() + find_required_package(LIBSOUP24) + if (LIBSOUP24_FOUND) + include_directories(${LIBSOUP24_INCLUDE_DIRS}) + target_link_libraries(remmina ${LIBSOUP24_LIBRARIES}) + else() + message(FATAL_ERROR "libsoup 2.4 library not found") + endif() endif() find_package(Intl) diff --git a/remmina/src/remmina.c b/remmina/src/remmina.c index 8af86bb53..51ac39cca 100644 --- a/remmina/src/remmina.c +++ b/remmina/src/remmina.c @@ -53,6 +53,8 @@ #include "remmina_ssh_plugin.h" #include "remmina_widget_pool.h" #include "remmina/remmina_trace_calls.h" +#include "remmina_stats_sender.h" + #ifdef HAVE_ERRNO_H #include <errno.h> @@ -201,6 +203,8 @@ static void remmina_on_startup(GApplication *app) gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), REMMINA_RUNTIME_DATADIR G_DIR_SEPARATOR_S "icons"); g_application_hold(app); + + remmina_stats_sender_schedule(); } static gint remmina_on_local_cmdline(GApplication *app, GVariantDict *options, gpointer user_data) diff --git a/remmina/src/remmina_main.c b/remmina/src/remmina_main.c index a1d8d7ef6..41af16a2c 100644 --- a/remmina/src/remmina_main.c +++ b/remmina/src/remmina_main.c @@ -2,7 +2,7 @@ * Remmina - The GTK+ Remote Desktop Client * Copyright (C) 2009-2011 Vic Lee * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo - * Copyright (C) 2016-2017 Antenore Gatta, Giovanni Panozzo + * Copyright (C) 2016-2018 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 @@ -56,6 +56,7 @@ #include "remmina_mpchange.h" #include "remmina_external_tools.h" #include "remmina/remmina_trace_calls.h" +#include "remmina_stats_sender.h" static RemminaMain *remminamain; @@ -1094,6 +1095,38 @@ static void remmina_main_init(void) remmina_widget_pool_register(GTK_WIDGET(remminamain->window)); } +/* Signal handler for "show" on remminamain->window */ +void remmina_main_on_show(GtkWidget *w, gpointer user_data) +{ + TRACE_CALL(__func__); + if (!remmina_pref.periodic_usage_stats_permission_asked) { + gtk_widget_set_visible(GTK_WIDGET(remminamain->box_ustat), TRUE); + } +} + +void remmina_main_on_click_ustat_yes(GtkWidget *w, gpointer user_data) +{ + remmina_pref.periodic_usage_stats_permission_asked = TRUE; + remmina_pref.periodic_usage_stats_permitted = TRUE; + remmina_pref_save(); + gtk_widget_set_visible(GTK_WIDGET(remminamain->box_ustat), FALSE); + remmina_stats_sender_schedule(); +} + +void remmina_main_on_click_ustat_no(GtkWidget *w, gpointer user_data) +{ + remmina_pref.periodic_usage_stats_permission_asked = TRUE; + remmina_pref.periodic_usage_stats_permitted = FALSE; + remmina_pref_save(); + gtk_widget_set_visible(GTK_WIDGET(remminamain->box_ustat), FALSE); +} + +static void remmina_main_on_click_test(GtkWidget *w, gpointer user_data) +{ + remmina_stats_sender_send(); +} + + /* RemminaMain instance */ GtkWidget* remmina_main_new(void) { @@ -1117,6 +1150,7 @@ GtkWidget* remmina_main_new(void) remminamain->tree_files_list = GTK_TREE_VIEW(GET_OBJECT("tree_files_list")); remminamain->column_files_list_group = GTK_TREE_VIEW_COLUMN(GET_OBJECT("column_files_list_group")); remminamain->statusbar_main = GTK_STATUSBAR(GET_OBJECT("statusbar_main")); + remminamain->box_ustat = GTK_BOX(GET_OBJECT("box_ustat")); /* Non widget objects */ remminamain->accelgroup_shortcuts = GTK_ACCEL_GROUP(GET_OBJECT("accelgroup_shortcuts")); G_GNUC_BEGIN_IGNORE_DEPRECATIONS @@ -1146,6 +1180,16 @@ GtkWidget* remmina_main_new(void) remminamain->action_help_wiki = GTK_ACTION(GET_OBJECT("action_help_wiki")); remminamain->action_help_debug = GTK_ACTION(GET_OBJECT("action_help_debug")); G_GNUC_END_IGNORE_DEPRECATIONS + + /* Temporary code to test statistics: add a button */ + GtkHeaderBar *hb = GTK_HEADER_BAR(GET_OBJECT("main_headerbar")); + GtkWidget *statbutton = gtk_button_new_with_label("Send test stats"); + gtk_header_bar_pack_end(hb, statbutton); + gtk_widget_show(statbutton); + g_signal_connect(G_OBJECT(statbutton), "clicked", + G_CALLBACK(remmina_main_on_click_test), NULL); + + /* Connect signals */ gtk_builder_connect_signals(remminamain->builder, NULL); /* Initialize the window and load the preferences */ diff --git a/remmina/src/remmina_main.h b/remmina/src/remmina_main.h index dbabf1e71..a680c1b8f 100644 --- a/remmina/src/remmina_main.h +++ b/remmina/src/remmina_main.h @@ -59,6 +59,7 @@ typedef struct _RemminaMain { GtkTreeView *tree_files_list; GtkTreeViewColumn *column_files_list_group; GtkStatusbar *statusbar_main; + GtkBox *box_ustat; /* Non widget objects */ GtkAccelGroup *accelgroup_shortcuts; GtkActionGroup *actiongroup_connection; diff --git a/remmina/src/remmina_pref.c b/remmina/src/remmina_pref.c index 14e32ef5d..ce4b1e8d9 100644 --- a/remmina/src/remmina_pref.c +++ b/remmina/src/remmina_pref.c @@ -674,6 +674,21 @@ void remmina_pref_init(void) else remmina_pref.color15 = "#d5ccba"; + if (g_key_file_has_key(gkeyfile, "usage_stats", "periodic_usage_stats_permission_asked", NULL)) + remmina_pref.periodic_usage_stats_permission_asked = g_key_file_get_boolean(gkeyfile, "usage_stats", "periodic_usage_stats_permission_asked", NULL); + else + remmina_pref.periodic_usage_stats_permission_asked = FALSE; + + if (g_key_file_has_key(gkeyfile, "usage_stats", "periodic_usage_stats_permitted", NULL)) + remmina_pref.periodic_usage_stats_permitted = g_key_file_get_boolean(gkeyfile, "usage_stats", "periodic_usage_stats_permitted", NULL); + else + remmina_pref.periodic_usage_stats_permitted = FALSE; + + if (g_key_file_has_key(gkeyfile, "usage_stats", "periodic_usage_stats_last_sent", NULL)) + remmina_pref.periodic_usage_stats_last_sent = g_key_file_get_int64(gkeyfile, "usage_stats", "periodic_usage_stats_last_sent", NULL); + else + remmina_pref.periodic_usage_stats_last_sent = 0; + g_key_file_free(gkeyfile); #if 0 @@ -772,6 +787,10 @@ void remmina_pref_save(void) g_key_file_set_string(gkeyfile, "ssh_colors", "color14", remmina_pref.color14 ? remmina_pref.color14 : ""); g_key_file_set_string(gkeyfile, "ssh_colors", "color15", remmina_pref.color15 ? remmina_pref.color15 : ""); + g_key_file_set_boolean(gkeyfile, "usage_stats", "periodic_usage_stats_permission_asked", remmina_pref.periodic_usage_stats_permission_asked); + g_key_file_set_boolean(gkeyfile, "usage_stats", "periodic_usage_stats_permitted", remmina_pref.periodic_usage_stats_permitted); + g_key_file_set_int64(gkeyfile, "usage_stats", "periodic_usage_stats_last_sent", remmina_pref.periodic_usage_stats_last_sent); + content = g_key_file_to_data(gkeyfile, &length, NULL); g_file_set_contents(remmina_pref_file, content, length, NULL); diff --git a/remmina/src/remmina_pref.h b/remmina/src/remmina_pref.h index dc701e271..64164a85b 100644 --- a/remmina/src/remmina_pref.h +++ b/remmina/src/remmina_pref.h @@ -183,6 +183,12 @@ typedef struct _RemminaPref { gchar *color14; gchar *color15; + /* Usage stats */ + gboolean periodic_usage_stats_permission_asked; + gboolean periodic_usage_stats_permitted; + glong periodic_usage_stats_last_sent; + + } RemminaPref; #define DEFAULT_SSH_PARSECONFIG TRUE diff --git a/remmina/src/remmina_stats.c b/remmina/src/remmina_stats.c new file mode 100644 index 000000000..deeaf7018 --- /dev/null +++ b/remmina/src/remmina_stats.c @@ -0,0 +1,204 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2009-2011 Vic Lee + * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo + * Copyright (C) 2016-2018 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. + * + */ + +#include "config.h" +#include <gtk/gtk.h> +#include <string.h> +#include "remmina/remmina_trace_calls.h" + +#ifdef GDK_WINDOWING_WAYLAND + #include <gdk/gdkwayland.h> +#endif +#ifdef GDK_WINDOWING_X11 + #include <gdk/gdkx.h> +#endif +#include "remmina_stats.h" + +JsonNode *remmina_stats_get_gtk_version() +{ + TRACE_CALL(__func__); + JsonBuilder *b; + JsonNode *r; + + /* WARNING: this function is usually executed on a dedicated thread, + * not on the main thread */ + + b = json_builder_new(); + json_builder_begin_object(b); + json_builder_set_member_name(b, "major"); + json_builder_add_int_value(b, gtk_get_major_version()); + json_builder_set_member_name(b, "minor"); + json_builder_add_int_value(b, gtk_get_minor_version()); + json_builder_set_member_name(b, "micro"); + json_builder_add_int_value(b, gtk_get_micro_version()); + json_builder_end_object (b); + r = json_builder_get_root(b); + g_object_unref(b); + return r; + +} + +JsonNode *remmina_stats_get_gtk_backend() +{ + TRACE_CALL(__func__); + JsonNode *r; + GdkDisplay *disp; + gchar *bkend; + + /* WARNING: this function is usually executed on a dedicated thread, + * not on the main thread */ + + disp = gdk_display_get_default(); + +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY(disp)) + { + bkend = "Wayland"; + } + else +#endif +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY (disp)) + { + bkend = "X11"; + } + else +#endif + bkend = "Unknown"; + + r = json_node_alloc(); + json_node_init_string(r, bkend); + + return r; + +} + +JsonNode *remmina_stats_get_uid() +{ + TRACE_CALL(__func__); + JsonNode *r; + + /* WARNING: this function is usually executed on a dedicated thread, + * not on the main thread */ + + /* ToDo: Improve UID */ + GChecksum *chs; + const gchar *uname, *hname; + const gchar *chss; + uname = g_get_user_name(); + hname = g_get_host_name(); + chs = g_checksum_new(G_CHECKSUM_SHA256); + g_checksum_update(chs, (const guchar*)uname, strlen(uname)); + g_checksum_update(chs, (const guchar*)hname, strlen(hname)); + chss = g_checksum_get_string(chs); + + r = json_node_alloc(); + json_node_init_string(r, chss); + g_checksum_free(chs); + + return r; + +} + +JsonNode *remmina_stats_get_version() +{ + TRACE_CALL(__func__); + JsonBuilder *b; + JsonNode *r; + + /* WARNING: this function is usually executed on a dedicated thread, + * not on the main thread */ + + b = json_builder_new(); + json_builder_begin_object(b); + json_builder_set_member_name(b, "version"); + json_builder_add_string_value(b, VERSION); + json_builder_set_member_name(b, "git_revision"); + json_builder_add_string_value(b, REMMINA_GIT_REVISION); + json_builder_set_member_name(b, "snap_build"); +#ifdef SNAP_BUILD + json_builder_add_int_value(b, 1); +#else + json_builder_add_int_value(b, 0); +#endif + json_builder_end_object (b); + r = json_builder_get_root(b); + g_object_unref(b); + return r; + +} + +JsonNode *remmina_stats_get_all() +{ + /* Get all statistics in json format to send periodically to the PHP server. + * Return a pointer to the JSON string. + * The caller should free the returned buffer with g_free() */ + + /* WARNING: this function is usually executed on a dedicated thread, + * not on the main thread */ + + + TRACE_CALL(__func__); + + JsonBuilder *b; + JsonNode *n; + b = json_builder_new(); + json_builder_begin_object(b); + + n = remmina_stats_get_uid(); + json_builder_set_member_name(b, "UID"); + json_builder_add_value(b, n); + + n = remmina_stats_get_version(); + json_builder_set_member_name(b, "REMMINAVERSION"); + json_builder_add_value(b, n); + + + n = remmina_stats_get_gtk_version(); + json_builder_set_member_name(b, "GTKVERSION"); + json_builder_add_value(b, n); + + n = remmina_stats_get_gtk_backend(); + json_builder_set_member_name(b, "GTKBACKEND"); + json_builder_add_value(b, n); + + json_builder_end_object(b); + n = json_builder_get_root(b); + g_object_unref(b); + + return n; + +} diff --git a/remmina/src/remmina_stats.h b/remmina/src/remmina_stats.h new file mode 100644 index 000000000..b4617da81 --- /dev/null +++ b/remmina/src/remmina_stats.h @@ -0,0 +1,47 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2009-2011 Vic Lee + * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo + * Copyright (C) 2016-2018 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. + * + */ + +#pragma once + +G_BEGIN_DECLS + +#include "json-glib/json-glib.h" + +JsonNode *remmina_stats_get_all(void); + +G_END_DECLS + + diff --git a/remmina/src/remmina_stats_sender.c b/remmina/src/remmina_stats_sender.c new file mode 100644 index 000000000..e62a52700 --- /dev/null +++ b/remmina/src/remmina_stats_sender.c @@ -0,0 +1,200 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2009-2011 Vic Lee + * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo + * Copyright (C) 2016-2018 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. + * + */ + +#include "config.h" +#include <gtk/gtk.h> +#include <string.h> +#include <libsoup/soup.h> +#include "remmina/remmina_trace_calls.h" +#include "remmina_stats.h" +#include "remmina_pref.h" + +#if !JSON_CHECK_VERSION(1,2,0) + #define json_node_unref(x) json_node_free(x) +#endif + +/* Timers */ +#define PERIODIC_CHECK_1ST_MS 60000 +#define PERIODIC_CHECK_INTERVAL_MS 600000 + +#define PERIODIC_UPLOAD_INTERVAL_SEC 604800 + +#define PERIODIC_UPLOAD_URL "http://s1.casa.panozzo.it/remmina/upload_stats.php" + + +static gint periodic_check_source; +static gint periodic_check_counter; + +#define DEBUG_HTTP_SERVER_RESPONSE + + +static void soup_callback(SoupSession *session, SoupMessage *msg, gpointer user_data) +{ + TRACE_CALL(__func__); + gchar *s = (gchar *)user_data; + SoupBuffer *sb; + gboolean passed; + GTimeVal t; + + g_free(s); + +#ifdef DEBUG_HTTP_SERVER_RESPONSE + printf("soup_callback status code is %d\n", msg->status_code); +#endif + + if (msg->status_code != 200) + return; + + passed = FALSE; + sb = soup_message_body_flatten(msg->response_body); + if (strncmp(sb->data,"200 ", 4) != 0) { +#ifdef DEBUG_HTTP_SERVER_RESPONSE + puts("Error from server side script:"); + puts(sb->data); +#endif + } else { + passed = TRUE; + } + soup_buffer_free(sb); + + if (passed) { + g_get_current_time(&t); + remmina_pref.periodic_usage_stats_last_sent = t.tv_sec; + remmina_pref_save(); + } + +} + +static gboolean remmina_stats_collector_done(gpointer data) +{ + TRACE_CALL(__func__); + JsonNode *n; + JsonGenerator *g; + gchar *s; + SoupSession *ss; + SoupMessage *msg; + + n = (JsonNode *)data; + if (n == NULL) + return G_SOURCE_REMOVE; + + g = json_generator_new(); + json_generator_set_root(g, n); + s = json_generator_to_data(g, NULL); + g_object_unref(g); + json_node_unref(n); + + ss = soup_session_new(); + msg = soup_message_new("POST", PERIODIC_UPLOAD_URL); + soup_message_set_request(msg, "application/json", + SOUP_MEMORY_COPY, s, strlen (s)); + soup_session_queue_message(ss, msg, soup_callback, s); + +#ifdef DEBUG_HTTP_SERVER_RESPONSE + printf("Starting upload to url %s\n", PERIODIC_UPLOAD_URL); +#endif + + return G_SOURCE_REMOVE; +} + +static gpointer remmina_stats_collector(gpointer data) +{ + TRACE_CALL(__func__); + JsonNode *n; + n = remmina_stats_get_all(); + + /* stats collecting is done. Notify main thread calling + * remmina_stats_collector_done() */ + g_idle_add(remmina_stats_collector_done, n); + + return NULL; +} + +void remmina_stats_sender_send() +{ + TRACE_CALL(__func__); + + g_thread_new("stats_collector", remmina_stats_collector, NULL); + + +} + + +static gboolean remmina_stats_sender_periodic_check(gpointer user_data) +{ + TRACE_CALL(__func__); + GTimeVal t; + glong next; + + if (!remmina_pref.periodic_usage_stats_permission_asked || !remmina_pref.periodic_usage_stats_permitted) + return G_SOURCE_REMOVE; + + /* Calculate "next" upload time based on last sent time */ + next = remmina_pref.periodic_usage_stats_last_sent + PERIODIC_UPLOAD_INTERVAL_SEC; + g_get_current_time(&t); + /* If current time is after "next" or clock is going back (but > 1/1/2018), then do send stats */ + if (t.tv_sec > next || (t.tv_sec < remmina_pref.periodic_usage_stats_last_sent && t.tv_sec > 1514764800)) { + remmina_stats_sender_send(); + } else { +#ifdef DEBUG_HTTP_SERVER_RESPONSE + printf("Doing nothing: next upload is scheduled in %ld seconds\n", (next-t.tv_sec)); +#endif + } + + periodic_check_counter ++; + if (periodic_check_counter <= 1) { + /* Reschedule periodic check less frequently after 1st tick. + * Note that PERIODIC_CHECK_INTERVAL_MS becomes also a retry interval in case of + * upload failure */ + periodic_check_source = g_timeout_add_full(G_PRIORITY_LOW, PERIODIC_CHECK_INTERVAL_MS, remmina_stats_sender_periodic_check, NULL, NULL); + return G_SOURCE_REMOVE; + } + return G_SOURCE_CONTINUE; +} + +void remmina_stats_sender_schedule() +{ + TRACE_CALL(__func__); + /* If permitted, schedule the 1st statistics periodic check */ + if (remmina_pref.periodic_usage_stats_permission_asked && remmina_pref.periodic_usage_stats_permitted) { + periodic_check_counter = 0; + periodic_check_source = g_timeout_add_full(G_PRIORITY_LOW, PERIODIC_CHECK_1ST_MS, remmina_stats_sender_periodic_check, NULL, NULL); + } else + periodic_check_source = 0; +} + + + diff --git a/remmina/src/remmina_stats_sender.h b/remmina/src/remmina_stats_sender.h new file mode 100644 index 000000000..2b2703e17 --- /dev/null +++ b/remmina/src/remmina_stats_sender.h @@ -0,0 +1,48 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2009-2011 Vic Lee + * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo + * Copyright (C) 2016-2018 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. + * + */ + +#pragma once + +G_BEGIN_DECLS + +void remmina_stats_sender_schedule(void); + +/* This is only for testing purposes: force a SEND */ +void remmina_stats_sender_send(void); + +G_END_DECLS + + diff --git a/remmina/ui/remmina_main.glade b/remmina/ui/remmina_main.glade index 5722d2468..3c300e4ae 100644 --- a/remmina/ui/remmina_main.glade +++ b/remmina/ui/remmina_main.glade @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.20.0 +<!-- Generated with glade 3.20.2 Remmina - The GTK+ Remmina Remote Desktop Client Copyright (C) Antenore Gatta & Giovanni Panozzo 2014-2017 @@ -238,6 +238,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <signal name="delete-event" handler="remmina_main_on_delete_event" swapped="no"/> <signal name="destroy" handler="remmina_main_destroy" swapped="no"/> <signal name="drag-data-received" handler="remmina_main_on_drag_data_received" swapped="no"/> + <signal name="show" handler="remmina_main_on_show" swapped="no"/> <signal name="window-state-event" handler="remmina_main_on_window_state_event" swapped="no"/> <child> <object class="GtkBox" id="box_main"> @@ -618,7 +619,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="position">2</property> + <property name="position">1</property> </packing> </child> <child> @@ -709,7 +710,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <packing> <property name="expand">True</property> <property name="fill">True</property> - <property name="position">3</property> + <property name="position">2</property> </packing> </child> <child> @@ -720,6 +721,69 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <packing> <property name="expand">False</property> <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box_ustat"> + <property name="can_focus">False</property> + <property name="margin_left">4</property> + <property name="margin_right">4</property> + <property name="margin_top">4</property> + <property name="margin_bottom">4</property> + <property name="spacing">5</property> + <child> + <object class="GtkLabel" id="ustat_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Do you allow Remmina to send periodic anonymous usage statistics to its developers?</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="ustat_no"> + <property name="label">gtk-no</property> + <property name="width_request">60</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="valign">center</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="remmina_main_on_click_ustat_no" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="ustat_yes"> + <property name="label">gtk-yes</property> + <property name="width_request">70</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="valign">center</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="remmina_main_on_click_ustat_yes" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="padding">3</property> <property name="position">4</property> </packing> </child> diff --git a/snap/snapcraft.yaml.in b/snap/snapcraft.yaml.in index 30364b2d9..989d7fe87 100644 --- a/snap/snapcraft.yaml.in +++ b/snap/snapcraft.yaml.in @@ -99,6 +99,8 @@ parts: - libgcrypt20-dev - libgnome-keyring-dev - libgtk-3-dev + - libjson-glib-dev + - libsoup2.4-dev - libspice-client-gtk-3.0-dev - libspice-protocol-dev - libtelepathy-glib-dev |