Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/Remmina/Remmina.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntenore Gatta <antenore@simbiosi.org>2019-05-14 00:16:12 +0300
committerAntenore Gatta <antenore@simbiosi.org>2019-05-14 00:16:12 +0300
commit9e1e7e6f314df21e155652eec145659b20c51139 (patch)
tree18d49cbb585033ebb6d9d0b4f8c884d95d2b002a
parent35e0ae83657ce05ff5d0c27a209ac25d74f226ac (diff)
Remmina news dialog
- A new scheduler that is used by the stat sender and by the remmina news - A dialog that show the latest news per each Remmina version, starting from this commit
-rw-r--r--data/ui/CMakeLists.txt1
-rw-r--r--data/ui/remmina_news.glade98
-rw-r--r--data/ui/remmina_preferences.glade6
-rw-r--r--data/ui/remmina_unlock.glade32
-rw-r--r--src/CMakeLists.txt278
-rw-r--r--src/remmina.c2
-rw-r--r--src/remmina_pref.c6
-rw-r--r--src/remmina_pref.h2
-rw-r--r--src/remmina_scheduler.c90
-rw-r--r--src/remmina_scheduler.h49
-rw-r--r--src/remmina_stats_sender.c26
-rw-r--r--src/remmina_unlock.c3
-rw-r--r--src/remmina_utils.c52
-rw-r--r--src/remmina_utils.h1
-rw-r--r--src/rmnews.c321
-rw-r--r--src/rmnews.h51
16 files changed, 852 insertions, 166 deletions
diff --git a/data/ui/CMakeLists.txt b/data/ui/CMakeLists.txt
index 2bb9f9ea6..416bb254c 100644
--- a/data/ui/CMakeLists.txt
+++ b/data/ui/CMakeLists.txt
@@ -34,6 +34,7 @@
install(FILES remmina_about.glade DESTINATION "${REMMINA_UIDIR}")
install(FILES remmina_main.glade DESTINATION "${REMMINA_UIDIR}")
+install(FILES remmina_news.glade DESTINATION "${REMMINA_UIDIR}")
install(FILES remmina_spinner.glade DESTINATION "${REMMINA_UIDIR}")
install(FILES remmina_preferences.glade DESTINATION "${REMMINA_UIDIR}")
install(FILES remmina_key_chooser.glade DESTINATION "${REMMINA_UIDIR}")
diff --git a/data/ui/remmina_news.glade b/data/ui/remmina_news.glade
new file mode 100644
index 000000000..bb91ad66e
--- /dev/null
+++ b/data/ui/remmina_news.glade
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.4
+
+-
+Copyright (C) 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.
+
+Author: Antenore Gatta
+
+-->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <!-- interface-license-type gplv2 -->
+ <!-- interface-copyright Antenore Gatta & Giovanni Panozzo -->
+ <!-- interface-authors Antenore Gatta -->
+ <object class="GtkDialog" id="RemminaNewsDialog">
+ <property name="can_focus">False</property>
+ <property name="default_width">640</property>
+ <property name="default_height">480</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="rmnews_button_close">
+ <property name="label" translatable="yes">Close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="rmnews_scrolled_window">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="rmnews_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ <property name="selectable">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/data/ui/remmina_preferences.glade b/data/ui/remmina_preferences.glade
index fa278c912..2843f6945 100644
--- a/data/ui/remmina_preferences.glade
+++ b/data/ui/remmina_preferences.glade
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1
+<!-- Generated with glade 3.22.1
Remmina Preferences Dialog -
Copyright (C) Antenore Gatta & Giovanni Panozzo 2014-2019
@@ -476,11 +476,11 @@ Author: Antenore Gatta
<object class="GtkLabel" id="label_options_file_name">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes">Each Remmina connection profile is stored with a name you can set its template</property>
+ <property name="tooltip_text" translatable="yes">Set a custom filename for your Remmina connection profiles, using a formatting string.</property>
<property name="halign">start</property>
<property name="margin_left">18</property>
<property name="hexpand">False</property>
- <property name="label" translatable="yes">Profile filename template</property>
+ <property name="label" translatable="yes">Profiles filename template</property>
<property name="justify">right</property>
</object>
<packing>
diff --git a/data/ui/remmina_unlock.glade b/data/ui/remmina_unlock.glade
index 57a2d06f6..20f7c8872 100644
--- a/data/ui/remmina_unlock.glade
+++ b/data/ui/remmina_unlock.glade
@@ -1,10 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.4 -->
+<!-- Generated with glade 3.22.1
+
+-
+Copyright (C) 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.
+
+Author: Antenore Gatta
+
+-->
<interface>
<requires lib="gtk+" version="3.20"/>
+ <!-- interface-license-type gplv2 -->
+ <!-- interface-copyright Antenore Gatta & Giovanni Panozzo -->
+ <!-- interface-authors Antenore Gatta -->
<object class="GtkDialog" id="RemminaUnlockDialog">
<property name="can_focus">False</property>
<property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
@@ -125,8 +152,5 @@
</child>
</object>
</child>
- <child>
- <placeholder/>
- </child>
</object>
</interface>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bcdbf2465..e6b9458f6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -36,99 +36,103 @@
cmake_minimum_required(VERSION 2.8)
list(APPEND REMMINA_SRCS
- "remmina_about.c"
- "remmina_about.h"
- "remmina_applet_menu.c"
- "remmina_applet_menu.h"
- "remmina_applet_menu_item.c"
- "remmina_applet_menu_item.h"
- "remmina_avahi.c"
- "remmina_avahi.h"
- "remmina.c"
- "remmina.h"
- "remmina_chat_window.c"
- "remmina_chat_window.h"
- "remmina_crypt.c"
- "remmina_crypt.h"
- "remmina_exec.c"
- "remmina_exec.h"
- "remmina_file.c"
- "remmina_file_editor.c"
- "remmina_file_editor.h"
- "remmina_file.h"
- "remmina_file_manager.c"
- "remmina_file_manager.h"
- "remmina_ftp_client.c"
- "remmina_ftp_client.h"
- "remmina_icon.c"
- "remmina_icon.h"
- "remmina_key_chooser.c"
- "remmina_key_chooser.h"
- "remmina_log.c"
- "remmina_log.h"
- "remmina_main.c"
- "remmina_main.h"
- "remmina_marshals.c"
- "remmina_marshals.h"
- "remmina_marshals.list"
- "remmina_masterthread_exec.c"
- "remmina_masterthread_exec.h"
- "remmina_message_panel.c"
- "remmina_message_panel.h"
- "remmina_plugin_manager.c"
- "remmina_plugin_manager.h"
- "remmina_ext_exec.c"
- "remmina_ext_exec.h"
- "remmina_pref.c"
- "remmina_pref_dialog.c"
- "remmina_pref_dialog.h"
- "remmina_pref.h"
- "remmina_protocol_widget.c"
- "remmina_protocol_widget.h"
- "remmina_public.c"
- "remmina_public.h"
- "remmina_scrolled_viewport.c"
- "remmina_scrolled_viewport.h"
- "remmina_sftp_client.c"
- "remmina_sftp_client.h"
- "remmina_sftp_plugin.c"
- "remmina_sftp_plugin.h"
- "remmina_sodium.c"
- "remmina_sodium.h"
- "remmina_ssh.c"
- "remmina_ssh.h"
- "remmina_ssh_plugin.c"
- "remmina_ssh_plugin.h"
- "remmina_string_array.c"
- "remmina_string_array.h"
- "remmina_string_list.c"
- "remmina_string_list.h"
- "remmina_unlock.c"
- "remmina_unlock.h"
- "remmina_utils.c"
- "remmina_utils.h"
- "remmina_widget_pool.c"
- "remmina_widget_pool.h"
- "remmina_external_tools.c"
- "remmina_external_tools.h"
- "remmina_sysinfo.h"
- "remmina_sysinfo.c"
- "rcw.c"
- "rcw.h"
- "remmina_mpchange.c"
- "remmina_mpchange.h"
- "remmina_stats.c"
- "remmina_stats.h"
- "remmina_stats_sender.c"
- "remmina_stats_sender.h"
- )
+ "remmina_about.c"
+ "remmina_about.h"
+ "remmina_applet_menu.c"
+ "remmina_applet_menu.h"
+ "remmina_applet_menu_item.c"
+ "remmina_applet_menu_item.h"
+ "remmina_avahi.c"
+ "remmina_avahi.h"
+ "remmina.c"
+ "remmina.h"
+ "remmina_chat_window.c"
+ "remmina_chat_window.h"
+ "remmina_crypt.c"
+ "remmina_crypt.h"
+ "remmina_exec.c"
+ "remmina_exec.h"
+ "remmina_file.c"
+ "remmina_file_editor.c"
+ "remmina_file_editor.h"
+ "remmina_file.h"
+ "remmina_file_manager.c"
+ "remmina_file_manager.h"
+ "remmina_ftp_client.c"
+ "remmina_ftp_client.h"
+ "remmina_icon.c"
+ "remmina_icon.h"
+ "remmina_key_chooser.c"
+ "remmina_key_chooser.h"
+ "remmina_log.c"
+ "remmina_log.h"
+ "remmina_main.c"
+ "remmina_main.h"
+ "remmina_marshals.c"
+ "remmina_marshals.h"
+ "remmina_marshals.list"
+ "remmina_masterthread_exec.c"
+ "remmina_masterthread_exec.h"
+ "remmina_message_panel.c"
+ "remmina_message_panel.h"
+ "remmina_plugin_manager.c"
+ "remmina_plugin_manager.h"
+ "remmina_ext_exec.c"
+ "remmina_ext_exec.h"
+ "remmina_pref.c"
+ "remmina_pref_dialog.c"
+ "remmina_pref_dialog.h"
+ "remmina_pref.h"
+ "remmina_protocol_widget.c"
+ "remmina_protocol_widget.h"
+ "remmina_public.c"
+ "remmina_public.h"
+ "remmina_scrolled_viewport.c"
+ "remmina_scrolled_viewport.h"
+ "remmina_sftp_client.c"
+ "remmina_sftp_client.h"
+ "remmina_sftp_plugin.c"
+ "remmina_sftp_plugin.h"
+ "remmina_sodium.c"
+ "remmina_sodium.h"
+ "remmina_ssh.c"
+ "remmina_ssh.h"
+ "remmina_ssh_plugin.c"
+ "remmina_ssh_plugin.h"
+ "remmina_string_array.c"
+ "remmina_string_array.h"
+ "remmina_string_list.c"
+ "remmina_string_list.h"
+ "remmina_unlock.c"
+ "remmina_unlock.h"
+ "remmina_utils.c"
+ "remmina_utils.h"
+ "remmina_widget_pool.c"
+ "remmina_widget_pool.h"
+ "remmina_external_tools.c"
+ "remmina_external_tools.h"
+ "remmina_sysinfo.h"
+ "remmina_sysinfo.c"
+ "rcw.c"
+ "rcw.h"
+ "rmnews.c"
+ "rmnews.h"
+ "remmina_mpchange.c"
+ "remmina_mpchange.h"
+ "remmina_scheduler.c"
+ "remmina_scheduler.h"
+ "remmina_stats.c"
+ "remmina_stats.h"
+ "remmina_stats_sender.c"
+ "remmina_stats_sender.h"
+ )
add_executable(remmina ${REMMINA_SRCS})
include_directories(${GTK_INCLUDE_DIRS})
target_link_libraries(remmina ${GTK_LIBRARIES})
if(WITH_MANPAGES)
- install(FILES remmina.1 DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1)
+ install(FILES remmina.1 DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1)
endif()
find_package(X11)
@@ -139,87 +143,87 @@ target_link_libraries(remmina ${CMAKE_THREAD_LIBS_INIT})
find_package(Intl)
if(INTL_FOUND AND "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD|OpenBSD|NetBSD")
- message(STATUS "${CMAKE_SYSTEM_NAME} detected, building with Intl")
- include_directories(${Intl_INCLUDE_DIRS})
- target_link_libraries(remmina ${Intl_LIBRARIES})
+ message(STATUS "${CMAKE_SYSTEM_NAME} detected, building with Intl")
+ include_directories(${Intl_INCLUDE_DIRS})
+ target_link_libraries(remmina ${Intl_LIBRARIES})
endif()
find_suggested_package(LIBSSH)
if(LIBSSH_FOUND)
- add_definitions(-DHAVE_LIBSSH)
- include_directories(${LIBSSH_INCLUDE_DIRS})
- target_link_libraries(remmina ${LIBSSH_LIBRARIES})
+ add_definitions(-DHAVE_LIBSSH)
+ include_directories(${LIBSSH_INCLUDE_DIRS})
+ target_link_libraries(remmina ${LIBSSH_LIBRARIES})
endif()
if(GCRYPT_FOUND)
- include_directories(${GCRYPT_INCLUDE_DIRS})
- target_link_libraries(remmina ${GCRYPT_LIBRARIES})
+ include_directories(${GCRYPT_INCLUDE_DIRS})
+ target_link_libraries(remmina ${GCRYPT_LIBRARIES})
endif()
if(AVAHI_FOUND)
- include_directories(${AVAHI_INCLUDE_DIRS})
- target_link_libraries(remmina ${AVAHI_LIBRARIES})
+ include_directories(${AVAHI_INCLUDE_DIRS})
+ target_link_libraries(remmina ${AVAHI_LIBRARIES})
endif()
if(OPENSSL_FOUND)
- include_directories(${OPENSSL_INCLUDE_DIRS})
- target_link_libraries(remmina ${OPENSSL_LIBRARIES})
+ include_directories(${OPENSSL_INCLUDE_DIRS})
+ target_link_libraries(remmina ${OPENSSL_LIBRARIES})
endif()
option(WITH_VTE "Build with support for VTE" ON)
if(GTK3_FOUND AND WITH_VTE)
- set(_VTE_VERSION_NUMS 2.91 2.90)
- foreach(__VTE_VERSION ${_VTE_VERSION_NUMS})
- set(_VTE_VERSION_NUM ${__VTE_VERSION})
- find_package(VTE)
- if(VTE_FOUND)
- break()
- endif()
- message(STATUS "VTE ${__VTE_VERSION} not found")
- endforeach()
+ set(_VTE_VERSION_NUMS 2.91 2.90)
+ foreach(__VTE_VERSION ${_VTE_VERSION_NUMS})
+ set(_VTE_VERSION_NUM ${__VTE_VERSION})
+ find_package(VTE)
+ if(VTE_FOUND)
+ break()
+ endif()
+ message(STATUS "VTE ${__VTE_VERSION} not found")
+ endforeach()
elseif(WITH_VTE)
- set(_VTE_VERSION_NUM)
- find_package(VTE)
+ set(_VTE_VERSION_NUM)
+ find_package(VTE)
endif()
if(VTE_FOUND)
- add_definitions(-DHAVE_LIBVTE)
- include_directories(${VTE_INCLUDE_DIRS})
- target_link_libraries(remmina ${VTE_LIBRARIES})
+ add_definitions(-DHAVE_LIBVTE)
+ include_directories(${VTE_INCLUDE_DIRS})
+ target_link_libraries(remmina ${VTE_LIBRARIES})
endif()
if(sodium_FOUND)
- include_directories(${sodium_INCLUDE_DIR})
- target_link_libraries(remmina sodium)
+ include_directories(${sodium_INCLUDE_DIR})
+ target_link_libraries(remmina sodium)
endif()
if(GTK3_FOUND)
- find_suggested_package(APPINDICATOR)
- if(APPINDICATOR_FOUND)
- add_definitions(-DHAVE_LIBAPPINDICATOR)
- 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()
+ find_suggested_package(APPINDICATOR)
+ if(APPINDICATOR_FOUND)
+ add_definitions(-DHAVE_LIBAPPINDICATOR)
+ 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()
add_subdirectory(external_tools)
install(TARGETS remmina DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY include/remmina/
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/remmina
- FILES_MATCHING PATTERN "*.h")
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/remmina
+ FILES_MATCHING PATTERN "*.h")
diff --git a/src/remmina.c b/src/remmina.c
index fa085b907..abf80ddad 100644
--- a/src/remmina.c
+++ b/src/remmina.c
@@ -55,6 +55,7 @@
#include "remmina_ssh_plugin.h"
#include "remmina_widget_pool.h"
#include "remmina/remmina_trace_calls.h"
+#include "rmnews.h"
#include "remmina_stats_sender.h"
@@ -240,6 +241,7 @@ static void remmina_on_startup(GApplication *app)
g_application_hold(app);
remmina_stats_sender_schedule();
+ rmnews_schedule();
/* Check for secret plugin and service initialization and show some warnings on the console if
* there is something missing */
diff --git a/src/remmina_pref.c b/src/remmina_pref.c
index 673c9632a..b248bcd80 100644
--- a/src/remmina_pref.c
+++ b/src/remmina_pref.c
@@ -663,6 +663,11 @@ void remmina_pref_init(void)
remmina_pref.periodic_usage_stats_uuid_prefix = NULL;
+ if (g_key_file_has_key(gkeyfile, "remmina_news", "periodic_rmnews_last_get", NULL))
+ remmina_pref.periodic_rmnews_last_get = g_key_file_get_int64(gkeyfile, "remmina_news", "periodic_rmnews_last_get", NULL);
+ else
+ remmina_pref.periodic_rmnews_last_get = 0;
+
g_key_file_free(gkeyfile);
if (remmina_pref.secret == NULL)
@@ -774,6 +779,7 @@ gboolean remmina_pref_save(void)
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);
+ g_key_file_set_int64(gkeyfile, "remmina_news", "periodic_rmnews_last_get", remmina_pref.periodic_rmnews_last_get);
g_key_file_set_string(gkeyfile, "usage_stats", "periodic_usage_stats_uuid_prefix",
remmina_pref.periodic_usage_stats_uuid_prefix ? remmina_pref.periodic_usage_stats_uuid_prefix : "");
diff --git a/src/remmina_pref.h b/src/remmina_pref.h
index 4ff2d27a0..609048c10 100644
--- a/src/remmina_pref.h
+++ b/src/remmina_pref.h
@@ -202,6 +202,8 @@ typedef struct _RemminaPref {
gchar *periodic_usage_stats_uuid_prefix;
gchar *last_success;
+ /* Remmina news */
+ glong periodic_rmnews_last_get;
} RemminaPref;
diff --git a/src/remmina_scheduler.c b/src/remmina_scheduler.c
new file mode 100644
index 000000000..9d36595dd
--- /dev/null
+++ b/src/remmina_scheduler.c
@@ -0,0 +1,90 @@
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2016-2019 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 <stdlib.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include "remmina_scheduler.h"
+#include "remmina/remmina_trace_calls.h"
+
+static gboolean remmina_scheduler_periodic_check(gpointer user_data)
+{
+ TRACE_CALL(__func__);
+ rsSchedData *rssd = (rsSchedData *)user_data;
+
+ rssd->count++;
+ if (rssd->cb_func_ptr(rssd->cb_func_data) == G_SOURCE_REMOVE) {
+ g_free(rssd);
+ return G_SOURCE_REMOVE;
+ }
+ if (rssd->count <= 1) {
+ rssd->source = g_timeout_add_full(G_PRIORITY_LOW,
+ rssd->interval,
+ remmina_scheduler_periodic_check,
+ rssd,
+ NULL);
+ return G_SOURCE_REMOVE;
+ }
+ return G_SOURCE_CONTINUE;
+}
+
+void *remmina_scheduler_setup(GSourceFunc cb,
+ gpointer cb_data,
+ guint first_interval,
+ guint interval)
+{
+ TRACE_CALL(__func__);
+ rsSchedData *rssd;
+ rssd = g_malloc(sizeof(rsSchedData));
+ rssd->cb_func_ptr = cb;
+ rssd->cb_func_data = cb_data;
+ rssd->interval = interval;
+ rssd->count = 0;
+ rssd->source = g_timeout_add_full(G_PRIORITY_LOW,
+ first_interval,
+ remmina_scheduler_periodic_check,
+ rssd,
+ NULL);
+ return (void *)rssd;
+}
+
+void remmina_schedluer_remove(void *s)
+{
+ TRACE_CALL(__func__);
+ rsSchedData *rssd = (rsSchedData *)s;
+ g_source_remove(rssd->source);
+ g_free(rssd);
+}
diff --git a/src/remmina_scheduler.h b/src/remmina_scheduler.h
new file mode 100644
index 000000000..5668fd43f
--- /dev/null
+++ b/src/remmina_scheduler.h
@@ -0,0 +1,49 @@
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2016-2019 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
+
+typedef struct {
+ GSourceFunc cb_func_ptr;
+ gpointer cb_func_data;
+ guint interval;
+ guint source;
+ guint count;
+} rsSchedData;
+
+G_BEGIN_DECLS
+
+void *remmina_scheduler_setup(GSourceFunc cb, gpointer cb_data, guint first_interval, guint interval);
+
+G_END_DECLS
diff --git a/src/remmina_stats_sender.c b/src/remmina_stats_sender.c
index 4c33f6326..5d42f61e6 100644
--- a/src/remmina_stats_sender.c
+++ b/src/remmina_stats_sender.c
@@ -39,6 +39,7 @@
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
+#include "remmina_scheduler.h"
#include "remmina/remmina_trace_calls.h"
#include "remmina_log.h"
#include "remmina_stats.h"
@@ -57,8 +58,8 @@
#define PERIODIC_UPLOAD_URL "https://www.remmina.org/stats/upload_stats.php"
-static gint periodic_check_source;
-static gint periodic_check_counter;
+//static gint periodic_check_source;
+//static gint periodic_check_counter;
static char *remmina_RSA_PubKey_v1 =
"-----BEGIN PUBLIC KEY-----\n"
@@ -315,27 +316,14 @@ static gboolean remmina_stats_sender_periodic_check(gpointer user_data)
remmina_stats_sender_send(FALSE);
}
- 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_stat_sender_can_send()) {
- 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;
+ remmina_scheduler_setup(remmina_stats_sender_periodic_check,
+ NULL,
+ PERIODIC_CHECK_1ST_MS,
+ PERIODIC_CHECK_INTERVAL_MS);
}
-
-
-
diff --git a/src/remmina_unlock.c b/src/remmina_unlock.c
index 8e468bb7c..2050193c2 100644
--- a/src/remmina_unlock.c
+++ b/src/remmina_unlock.c
@@ -118,17 +118,14 @@ gint remmina_unlock_new(GtkWindow *parent)
unlock_timeout = remmina_pref.unlock_timeout;
- g_print ("%f unlock_timeout\n", unlock_timeout);
remmina_unlock_dialog = g_new0(RemminaUnlockDialog, 1);
remmina_unlock_dialog->retval = 1;
- //gtk_widget_destroy(GTK_WIDGET(remmina_unlock_dialog->dialog));
if (timer == NULL)
remmina_unlock_timer_init();
if (timer != NULL)
elapsed = g_timer_elapsed(timer, NULL);
- g_print ("elapsed %f\n", elapsed);
if (((int)unlock_timeout - elapsed) < 0) lock = TRUE;
if (((int)unlock_timeout - elapsed) >= 0) lock = FALSE;
/* timer & timout = 0 */
diff --git a/src/remmina_utils.c b/src/remmina_utils.c
index 90f1d8f57..adc34b5ba 100644
--- a/src/remmina_utils.c
+++ b/src/remmina_utils.c
@@ -427,3 +427,55 @@ const gchar* remmina_utils_get_os_info()
return kernel_string;
}
+/**
+ * Create a hexadecimal string version of the SHA-1 digest of the
+ * contents of the named file.
+ *
+ * @return a newly allocated string which the caller
+ * should free() when finished.
+ *
+ * If any error occurs while reading the file, (permission denied,
+ * file not found, etc.), this function returns NULL.
+ *
+ * Taken from https://github.com/ttuegel/notmuch do PR in case of substantial modifications.
+ *
+ */
+gchar* remmina_sha1_file (const gchar *filename)
+{
+ FILE *file;
+#define BLOCK_SIZE 4096
+ unsigned char block[BLOCK_SIZE];
+ size_t bytes_read;
+ GChecksum *sha1;
+ char *digest = NULL;
+
+ file = fopen (filename, "r");
+ if (file == NULL)
+ return NULL;
+
+ sha1 = g_checksum_new (G_CHECKSUM_SHA1);
+ if (sha1 == NULL)
+ goto DONE;
+
+ while (1) {
+ bytes_read = fread (block, 1, 4096, file);
+ if (bytes_read == 0) {
+ if (feof (file))
+ break;
+ else if (ferror (file))
+ goto DONE;
+ } else {
+ g_checksum_update (sha1, block, bytes_read);
+ }
+ }
+
+ digest = g_strdup (g_checksum_get_string (sha1));
+
+ DONE:
+ if (sha1)
+ g_checksum_free (sha1);
+ if (file)
+ fclose (file);
+
+ return digest;
+}
diff --git a/src/remmina_utils.h b/src/remmina_utils.h
index f1f96fe1c..156dce934 100644
--- a/src/remmina_utils.h
+++ b/src/remmina_utils.h
@@ -54,3 +54,4 @@ gchar* remmina_utils_get_lsb_release();
gchar* remmina_utils_get_lsb_codename();
GHashTable* remmina_utils_get_etc_release();
const gchar* remmina_utils_get_os_info();
+gchar* remmina_sha1_file (const gchar *filename);
diff --git a/src/rmnews.c b/src/rmnews.c
new file mode 100644
index 000000000..6f35e1dc1
--- /dev/null
+++ b/src/rmnews.c
@@ -0,0 +1,321 @@
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2016-2019 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 "remmina/remmina_trace_calls.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+#include <libsoup/soup.h>
+
+#include "remmina_main.h"
+#include "remmina_pref.h"
+#include "remmina_public.h"
+#include "remmina_utils.h"
+#include "remmina_scheduler.h"
+#include "rmnews.h"
+
+/* Neas file buffer */
+#define READ_BUFFER_LEN 1024
+/* Timers */
+#define RMNEWS_CHECK_1ST_MS 3000
+#define RMNEWS_CHECK_INTERVAL_MS 12000
+/* How many seconds before to get news */
+#define RMNEWS_INTERVAL_SEC 604800
+/* TODO: move in config.h */
+#define REMMINA_URL "https://remmina.org/"
+#define RMNEWS_OUTPUT "/var/tmp/latest_news.md"
+
+static RemminaNewsDialog *rmnews_news_dialog;
+#define GET_OBJ(object_name) gtk_builder_get_object(rmnews_news_dialog->builder, object_name)
+
+static SoupSession *session;
+static const gchar *rmnews_url = NULL;
+static const gchar *output_file_path = NULL;
+
+static gchar *rmnews_get_file_contents(gchar *path)
+{
+ gsize size;
+ gchar *content;
+
+ if (g_file_get_contents(path, &content, &size, NULL)) {
+ if (!g_utf8_validate(content, size, NULL)) {
+ g_error("%s content is not UTF-8", path);
+ g_free(content);
+ }
+ }
+ //return g_markup_escape_text(content, strlen(content));
+ return content;
+}
+
+static void rmnews_close_clicked(GtkButton *btn, gpointer user_data)
+{
+ TRACE_CALL(__func__);
+ gtk_widget_destroy(GTK_WIDGET(rmnews_news_dialog->dialog));
+ rmnews_news_dialog->dialog = NULL;
+}
+static gint rmnews_show_news(GtkWindow *parent)
+{
+ TRACE_CALL(__func__);
+
+ rmnews_news_dialog = g_new0(RemminaNewsDialog, 1);
+ rmnews_news_dialog->retval = 1;
+
+ rmnews_news_dialog->builder = remmina_public_gtk_builder_new_from_file("remmina_news.glade");
+ rmnews_news_dialog->dialog = GTK_DIALOG(gtk_builder_get_object(rmnews_news_dialog->builder, "RemminaNewsDialog"));
+ if (parent)
+ gtk_window_set_transient_for(GTK_WINDOW(rmnews_news_dialog->dialog), parent);
+
+ rmnews_news_dialog->rmnews_text_view = GTK_TEXT_VIEW(GET_OBJ("rmnews_text_view"));
+ rmnews_news_dialog->rmnews_label = GTK_LABEL(GET_OBJ("rmnews_label"));
+ rmnews_news_dialog->rmnews_button_close = GTK_BUTTON(GET_OBJ("rmnews_button_close"));
+ gtk_widget_set_can_default(GTK_WIDGET(rmnews_news_dialog->rmnews_button_close), TRUE);
+ gtk_widget_grab_default(GTK_WIDGET(rmnews_news_dialog->rmnews_button_close));
+
+ gchar *contents = rmnews_get_file_contents(g_strdup(output_file_path));
+ if (contents) {
+ gtk_label_set_markup(rmnews_news_dialog->rmnews_label, contents);
+ g_free(contents);
+ }
+
+ g_signal_connect(rmnews_news_dialog->rmnews_button_close, "clicked",
+ G_CALLBACK(rmnews_close_clicked), (gpointer)rmnews_news_dialog);
+ g_signal_connect(rmnews_news_dialog->dialog, "close",
+ G_CALLBACK(rmnews_close_clicked), (gpointer)rmnews_news_dialog);
+
+ /* Connect signals */
+ gtk_builder_connect_signals(rmnews_news_dialog->builder, NULL);
+ gtk_dialog_run(rmnews_news_dialog->dialog);
+ return rmnews_news_dialog->retval;
+}
+
+static void rmnews_get_url_cb(SoupSession *session, SoupMessage *msg, gpointer data)
+{
+ TRACE_CALL(__func__);
+ const char *name;
+ const char *header;
+ FILE *output_file = NULL;
+ gchar *filesha = NULL;
+ gchar *filesha_after = NULL;
+ GTimeVal t;
+
+ g_info("Status code %d", msg->status_code);
+
+ name = soup_message_get_uri(msg)->path;
+
+ if (SOUP_STATUS_IS_CLIENT_ERROR(msg->status_code)) {
+ g_info("Status 404 - Release file not available");
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ remmina_pref_save();
+ return;
+ }
+
+ if (SOUP_STATUS_IS_SERVER_ERROR(msg->status_code)) {
+ g_info("Server not available");
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ remmina_pref_save();
+ return;
+ }
+
+ if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
+ g_info("Transport Error");
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ remmina_pref_save();
+ return;
+ }
+
+ if (msg->status_code == SOUP_STATUS_SSL_FAILED) {
+ GTlsCertificateFlags flags;
+
+ if (soup_message_get_https_status(msg, NULL, &flags))
+ g_warning("%s: %d %s (0x%x)\n", name, msg->status_code, msg->reason_phrase, flags);
+ else
+ g_warning("%s: %d %s (no handshake status)\n", name, msg->status_code, msg->reason_phrase);
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ remmina_pref_save();
+ return;
+ } else if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
+ g_warning("%s: %d %s\n", name, msg->status_code, msg->reason_phrase);
+ }
+
+ if (SOUP_STATUS_IS_REDIRECTION(msg->status_code)) {
+ header = soup_message_headers_get_one(msg->response_headers,
+ "Location");
+ g_warning("Redirection detected");
+ if (header) {
+ SoupURI *uri;
+ char *uri_string;
+
+ g_info(" -> %s\n", header);
+
+ uri = soup_uri_new_with_base(soup_message_get_uri(msg), header);
+ uri_string = soup_uri_to_string(uri, FALSE);
+ rmnews_get_url(uri_string);
+ g_free(uri_string);
+ soup_uri_free(uri);
+ }
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ remmina_pref_save();
+ return;
+ } else if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
+ g_info("Status 200");
+ if (output_file_path) {
+ g_info("Calculating the SHA1 of the local file");
+ filesha = remmina_sha1_file(output_file_path);
+ g_info("SHA1 is %s", filesha);
+ if (filesha == NULL || filesha[0] == 0)
+ filesha = "0\0";
+ g_info("Opening %s output file for writing", output_file_path);
+ output_file = fopen(output_file_path, "w");
+ if (!output_file) {
+ g_printerr("Error trying to create file %s.\n", output_file_path);
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ remmina_pref_save();
+ return;
+ }
+ } else {
+ g_error("Cannot open output file for writing, because output_file_path is NULL");
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ remmina_pref_save();
+ return;
+ }
+
+
+ if (output_file) {
+ fwrite(msg->response_body->data,
+ 1,
+ msg->response_body->length,
+ output_file);
+
+ if (output_file_path)
+ fclose(output_file);
+ if (output_file_path)
+ filesha_after = remmina_sha1_file(output_file_path);
+ g_info("SHA1 after download is %s", filesha_after);
+ if (g_strcmp0(filesha, filesha_after) != 0) {
+ g_info("SHA1 differs, we show the news and reset the counter");
+ remmina_pref.periodic_rmnews_last_get = 0;
+ rmnews_show_news(remmina_main_get_window());
+ } else {
+ g_get_current_time(&t);
+ remmina_pref.periodic_rmnews_last_get = t.tv_sec;
+ }
+ remmina_pref_save();
+ }
+ }
+ g_object_unref(msg);
+}
+
+void rmnews_get_url(const char *url)
+{
+ TRACE_CALL(__func__);
+
+ SoupMessage *msg;
+
+ msg = soup_message_new("GET", url);
+ soup_message_set_flags(msg, SOUP_MESSAGE_NO_REDIRECT);
+
+ g_info("Fetching %s", url);
+
+ g_object_ref(msg);
+ soup_session_queue_message(session, msg, rmnews_get_url_cb, NULL);
+}
+
+void rmnews_get_news()
+{
+ TRACE_CALL(__func__);
+
+ SoupLogger *logger = NULL;
+
+ gchar *cachedir = g_build_path("/", g_get_user_cache_dir(), REMMINA_APP_ID, NULL);
+ g_mkdir_with_parents(cachedir, 0750);
+ output_file_path = g_build_path("/", cachedir, "latest_news.md", NULL);
+
+ if (output_file_path) {
+ g_info("Output file set to %s", output_file_path);
+ } else {
+ output_file_path = RMNEWS_OUTPUT;
+ g_warning("Output file set to %s", output_file_path);
+ }
+
+ g_info("Gathering news");
+ session = g_object_new(SOUP_TYPE_SESSION,
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
+ SOUP_SESSION_USER_AGENT, "get ",
+ SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+ NULL);
+ logger = soup_logger_new(SOUP_LOGGER_LOG_BODY, -1);
+ soup_session_add_feature(session, SOUP_SESSION_FEATURE(logger));
+ g_object_unref(logger);
+
+ rmnews_get_url(g_strconcat(REMMINA_URL,
+ "remmina_news.",
+ VERSION,
+ ".md",
+ NULL));
+
+ g_object_unref(session);
+}
+
+static gboolean rmnews_periodic_check(gpointer user_data)
+{
+ TRACE_CALL(__func__);
+ GTimeVal t;
+ glong next;
+
+ next = remmina_pref.periodic_rmnews_last_get + RMNEWS_INTERVAL_SEC;
+ g_get_current_time(&t);
+ if (t.tv_sec > next || (t.tv_sec < remmina_pref.periodic_rmnews_last_get && t.tv_sec > 1514764800))
+ rmnews_get_news();
+ return G_SOURCE_CONTINUE;
+}
+void rmnews_schedule()
+{
+ TRACE_CALL(__func__);
+ remmina_scheduler_setup(rmnews_periodic_check,
+ NULL,
+ RMNEWS_CHECK_1ST_MS,
+ RMNEWS_CHECK_INTERVAL_MS);
+}
diff --git a/src/rmnews.h b/src/rmnews.h
new file mode 100644
index 000000000..e76a87b76
--- /dev/null
+++ b/src/rmnews.h
@@ -0,0 +1,51 @@
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2016-2019 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.
+ *
+ */
+
+typedef struct _RemminaNewsDialog {
+ GtkBuilder * builder;
+ GtkDialog * dialog;
+
+ GtkTextView * rmnews_text_view;
+ GtkLabel * rmnews_label;
+ GtkButton * rmnews_button_close;
+
+ gint retval;
+} RemminaNewsDialog;
+
+#pragma once
+
+G_BEGIN_DECLS
+void rmnews_schedule();
+void rmnews_get_url(const char *url);
+G_END_DECLS