42 #include <gio/gdesktopappinfo.h> 43 #include <glib/gi18n.h> 44 #include <libsoup/soup.h> 45 #include <glib/gstdio.h> 47 #include <sys/types.h> 62 #define ARR_SIZE(arr) ( sizeof((arr)) / sizeof((arr[0])) ) 64 #define READ_BUFFER_LEN 1024 66 #define RMNEWS_CHECK_1ST_MS 3000 67 #define RMNEWS_CHECK_INTERVAL_MS 12000 69 #define RMNEWS_INTERVAL_SEC 604800 71 #define REMMINA_URL "https://remmina.org/" 72 #define RMNEWS_OUTPUT "/var/tmp/latest_news.md" 75 #define GET_OBJ(object_name) gtk_builder_get_object(rmnews_news_dialog->builder, object_name) 83 "x-scheme-handler/rdp",
84 "x-scheme-handler/spice",
85 "x-scheme-handler/vnc",
86 "x-scheme-handler/remmina",
87 "application/x-remmina",
103 TRACE_CALL(__func__);
118 TRACE_CALL(__func__);
119 g_autoptr(GError) error = NULL;
120 GDesktopAppInfo *desktop_info;
121 GAppInfo *info = NULL;
122 g_autofree gchar *
id = g_strconcat (REMMINA_APP_ID,
".desktop", NULL);
125 desktop_info = g_desktop_app_info_new (
id);
129 info = G_APP_INFO (desktop_info);
133 g_warning (
"Failed to set '%s' as the default application for secondary content type '%s': %s",
136 g_debug (
"Set '%s' as the default application for '%s'",
137 g_app_info_get_name (info),
147 if (g_file_get_contents(path, &content, &size, NULL)) {
148 if (!g_utf8_validate(content, size, NULL)) {
149 g_warning(
"%s content is not UTF-8", path);
160 TRACE_CALL(__func__);
161 gtk_widget_destroy(GTK_WIDGET(rmnews_news_dialog->
dialog));
162 rmnews_news_dialog->
dialog = NULL;
163 g_free(rmnews_news_dialog);
164 rmnews_news_dialog = NULL;
170 TRACE_CALL(__func__);
171 gtk_widget_destroy(GTK_WIDGET(rmnews_news_dialog->
dialog));
172 rmnews_news_dialog->
dialog = NULL;
173 g_free(rmnews_news_dialog);
174 rmnews_news_dialog = NULL;
181 TRACE_CALL(__func__);
184 rmnews_news_dialog->
retval = 1;
187 rmnews_news_dialog->
dialog = GTK_DIALOG(gtk_builder_get_object(rmnews_news_dialog->
builder,
"RemminaNewsDialog"));
189 rmnews_news_dialog->
rmnews_text_view = GTK_TEXT_VIEW(GET_OBJ(
"rmnews_text_view"));
190 rmnews_news_dialog->
rmnews_label = GTK_LABEL(GET_OBJ(
"rmnews_label"));
204 gtk_label_set_markup(rmnews_news_dialog->
rmnews_label, contents);
210 g_signal_connect(rmnews_news_dialog->dialog,
"close",
212 g_signal_connect(rmnews_news_dialog->dialog,
"delete-event",
216 gtk_builder_connect_signals(rmnews_news_dialog->builder, NULL);
219 gtk_widget_show_all(GTK_WIDGET(rmnews_news_dialog->dialog));
220 gtk_window_present(GTK_WINDOW(rmnews_news_dialog->dialog));
222 gtk_window_set_transient_for(GTK_WINDOW(rmnews_news_dialog->dialog), parent);
223 gtk_window_set_modal (GTK_WINDOW(rmnews_news_dialog->dialog), TRUE);
230 TRACE_CALL(__func__);
234 FILE *output_file = NULL;
235 gchar *filesha = NULL;
236 gchar *filesha_after = NULL;
239 g_info(
"Status code %d", msg->status_code);
241 name = soup_message_get_uri(msg)->path;
243 if (SOUP_STATUS_IS_CLIENT_ERROR(msg->status_code)) {
244 g_info(
"Status 404 - Release file not available");
245 g_get_current_time(&t);
251 if (SOUP_STATUS_IS_SERVER_ERROR(msg->status_code)) {
252 g_info(
"Server not available");
253 g_get_current_time(&t);
259 if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
260 g_info(
"Transport Error");
261 g_get_current_time(&t);
267 if (msg->status_code == SOUP_STATUS_SSL_FAILED) {
268 GTlsCertificateFlags flags;
270 if (soup_message_get_https_status(msg, NULL, &flags))
271 g_warning(
"%s: %d %s (0x%x)\n", name, msg->status_code, msg->reason_phrase, flags);
273 g_warning(
"%s: %d %s (no handshake status)\n", name, msg->status_code, msg->reason_phrase);
274 g_get_current_time(&t);
278 }
else if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
279 g_warning(
"%s: %d %s\n", name, msg->status_code, msg->reason_phrase);
282 if (SOUP_STATUS_IS_REDIRECTION(msg->status_code)) {
283 header = soup_message_headers_get_one(msg->response_headers,
285 g_warning(
"Redirection detected");
290 g_info(
" -> %s\n", header);
292 uri = soup_uri_new_with_base(soup_message_get_uri(msg), header);
293 uri_string = soup_uri_to_string(uri, FALSE);
298 g_get_current_time(&t);
302 }
else if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
303 g_info(
"Status 200");
305 g_info(
"Calculating the SHA1 of the local file");
307 g_info(
"SHA1 is %s", filesha);
308 if (filesha == NULL || filesha[0] == 0)
314 g_get_current_time(&t);
320 g_warning(
"Cannot open output file for writing, because output_file_path is NULL");
321 g_get_current_time(&t);
328 sb = soup_message_body_flatten (msg->response_body);
330 fwrite(sb->data, 1, sb->length, output_file);
336 g_info(
"SHA1 after download is %s", filesha_after);
337 if (g_strcmp0(filesha, filesha_after) != 0) {
338 g_info(
"SHA1 differs, we show the news and reset the counter");
344 g_get_current_time(&t);
362 TRACE_CALL(__func__);
364 const gchar *uname, *hname;
365 const gchar *uid_suffix;
380 uname = g_get_user_name();
381 hname = g_get_host_name();
382 chs = g_checksum_new(G_CHECKSUM_SHA256);
383 g_checksum_update(chs, (
const guchar*)uname, strlen(uname));
384 g_checksum_update(chs, (
const guchar*)hname, strlen(hname));
385 uid_suffix = g_checksum_get_string(chs);
388 g_checksum_free(chs);
396 TRACE_CALL(__func__);
400 msg = soup_message_new(
"GET", url);
401 soup_message_set_flags(msg, SOUP_MESSAGE_NO_REDIRECT);
403 g_debug(
"Fetching %s", url);
411 TRACE_CALL(__func__);
413 SoupLogger *logger = NULL;
416 gchar mage[20], gcount[20];
420 gchar *
cachedir = g_build_path(
"/", g_get_user_cache_dir(), REMMINA_APP_ID, NULL);
421 gint d = g_mkdir_with_parents(cachedir, 0750);
440 g_debug (
"Cannot store the remmina news file");
452 g_info(
"Gathering news");
453 session = g_object_new(SOUP_TYPE_SESSION,
454 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
455 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
456 SOUP_SESSION_USER_AGENT,
"get ",
457 SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
460 logger = soup_logger_new(SOUP_LOGGER_LOG_NONE, -1);
461 soup_session_add_feature(
session, SOUP_SESSION_FEATURE(logger));
462 g_object_unref(logger);
465 g_debug(
"Language %s", lang);
476 if (stat(
"/etc/machine-id", &sb) == 0)
477 sprintf(mage,
"%ld", (
long)(time(NULL) - sb.st_mtim.tv_sec));
484 "news/remmina_news.php?lang=",
504 TRACE_CALL(__func__);
510 g_get_current_time(&t);
514 gint randidx = rand() % 7;
517 g_debug (
"Setting a random periodic_rmnews_last_get");
525 return G_SOURCE_CONTINUE;
530 TRACE_CALL(__func__);
534 RMNEWS_CHECK_INTERVAL_MS);
GtkWindow * remmina_main_get_window()
void rmnews_show_news(GtkWindow *parent)
static void rmnews_close_clicked(GtkButton *btn, gpointer user_data)
GtkLabel * rmnews_defaultcl_label
GtkBuilder * remmina_public_gtk_builder_new_from_file(gchar *filename)
GtkButton * rmnews_button_close
static const gchar * supported_mime_types[]
static gboolean rmnews_dialog_deleted(GtkButton *btn, gpointer user_data)
void * remmina_scheduler_setup(GSourceFunc cb, gpointer cb_data, guint first_interval, guint interval)
GtkTextView * rmnews_text_view
General utility functions, non-GTK related.
void rmnews_stats_switch_state_set_cb()
gchar * remmina_gen_random_uuid()
Generate a random sting of chars to be used as part of UID for news or stats.
static SoupSession * session
gchar * periodic_usage_stats_uuid_prefix
gchar * remmina_utils_get_lang()
Return the current language defined in the LC_ALL.
gchar * periodic_rmnews_uuid_prefix
gchar * remmina_sha1_file(const gchar *filename)
Create a hexadecimal string version of the SHA-1 digest of the contents of the named file...
static const gchar * output_file_path
static RemminaNewsDialog * rmnews_news_dialog
glong periodic_rmnews_get_count
GtkSwitch * rmnews_stats_switch
gboolean periodic_usage_stats_permitted
static void rmnews_get_url_cb(SoupSession *session, SoupMessage *msg, gpointer data)
static gboolean rmnews_periodic_check(gpointer user_data)
void remmina_stats_sender_schedule()
gboolean remmina_pref_save(void)
static gchar * rmnews_get_file_contents(gchar *path)
void rmnews_get_url(const char *url)
gchar * rmnews_get_uid()
Try to get a unique system+user ID to identify this remmina user and avoid some duplicated task...
void rmnews_defaultcl_on_click()
gboolean remmina_pref_is_rw(void)
glong periodic_rmnews_last_get
GtkButton * rmnews_defaultcl_button