Remmina - The GTK+ Remote Desktop Client  v1.4.33
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
www_plugin.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * In addition, as a special exception, the copyright holders give
21  * permission to link the code of portions of this program with the
22  * OpenSSL library under certain conditions as described in each
23  * individual source file, and distribute linked combinations
24  * including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL.
27  * If you modify file(s) with this exception, you may extend this exception
28  * to your version of the file(s), but you are not obligated to do so.
29  * If you do not wish to do so, delete this exception statement from your
30  * version.
31  * If you delete this exception statement from all source
32  * files in the program, then also delete it here.
33  *
34  */
35 
36 #include "www_config.h"
37 
38 #include "common/remmina_plugin.h"
39 
40 #include <gdk/gdkkeysyms.h>
41 #include <gtk/gtk.h>
42 #include <glib.h>
43 #include <glib.h>
44 #include <glib/gprintf.h>
45 #include <stdlib.h>
46 
47 #include <webkit2/webkit2.h>
48 #if WEBKIT_CHECK_VERSION(2, 21, 1)
49 #include <jsc/jsc.h>
50 #endif
51 #include "www_utils.h"
52 #include "www_plugin.h"
53 
54 #define UNUSED(x) (void)(x)
55 
56 #define GET_PLUGIN_DATA(gp) (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data")
57 
58 typedef struct _RemminaPluginWWWData {
60  GtkWidget * box;
61  WebKitSettings * settings;
62  WebKitWebContext * context;
63  WebKitWebsiteDataManager * data_mgr;
64  WebKitCredential * credentials;
65  WebKitAuthenticationRequest * request;
66  WebKitWebView * webview;
67  WebKitLoadEvent load_event;
68 
69  gchar * url;
70  gboolean authenticated;
73 
75 
77  WebKitDownload *download, RemminaProtocolWidget *gp)
78 {
79  TRACE_CALL(__func__);
80  webkit_download_set_allow_overwrite(download, TRUE);
81  g_signal_connect(G_OBJECT(download), "notify::response",
82  G_CALLBACK(remmina_plugin_www_response_received), gp);
83  g_signal_connect(download, "created-destination",
84  G_CALLBACK(remmina_plugin_www_notify_download), gp);
85 }
86 
87 void remmina_plugin_www_response_received(WebKitDownload *download, GParamSpec *ps, RemminaProtocolWidget *gp)
88 {
89  TRACE_CALL(__func__);
90  REMMINA_PLUGIN_DEBUG("Download response received");
91 }
92 
93 void remmina_plugin_www_notify_download(WebKitDownload *download, gchar *destination, RemminaProtocolWidget *gp)
94 {
95  TRACE_CALL(__func__);
96  REMMINA_PLUGIN_DEBUG("Download is finished");
97  const gchar *dest = webkit_download_get_destination(download);
98 
99  www_utils_send_notification("www-plugin-download-completed-id", _("File downloaded"), dest);
100  //download(gp, webkit_download_get_response(download));
101  //webkit_download_cancel(download);
102 }
103 
105  WebKitWebView * webview,
106  WebKitPolicyDecision * decision,
107  WebKitPolicyDecisionType decision_type,
109 {
110  TRACE_CALL(__func__);
111 
112  gboolean res = TRUE;
113 
114  switch (decision_type) {
115  case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
116  remmina_plugin_www_decide_nav(decision, gp);
117  break;
118  case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
119  remmina_plugin_www_decide_newwin(decision, gp);
120  break;
121  case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
122  res = remmina_plugin_www_decide_resource(decision, gp);
123  break;
124  default:
125  webkit_policy_decision_ignore(decision);
126  break;
127  }
128  return res;
129 }
130 void remmina_plugin_www_decide_nav(WebKitPolicyDecision *decision, RemminaProtocolWidget *gp)
131 {
132  TRACE_CALL(__func__);
133  REMMINA_PLUGIN_DEBUG("Policy decision navigation");
134  const gchar *url = NULL;
135  WebKitNavigationAction *a =
136  webkit_navigation_policy_decision_get_navigation_action(
137  WEBKIT_NAVIGATION_POLICY_DECISION(decision));
138 
139  switch (webkit_navigation_action_get_navigation_type(a)) {
140  case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
141  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_LINK_CLICKED");
142  url = webkit_uri_request_get_uri(
143  webkit_navigation_action_get_request(a));
144  REMMINA_PLUGIN_DEBUG("url is %s ", url);
145  break;
146  case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
147  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED");
148  break;
149  case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
150  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_BACK_FORWARD");
151  break;
152  case WEBKIT_NAVIGATION_TYPE_RELOAD:
153  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_RELOAD");
154  break;
155  case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
156  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED");
157  break;
158  case WEBKIT_NAVIGATION_TYPE_OTHER:
159  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_OTHER");
160  break;
161  default:
162  /* Do not navigate to links with a "_blank" target (popup) */
163  if (webkit_navigation_policy_decision_get_frame_name(
164  WEBKIT_NAVIGATION_POLICY_DECISION(decision))) {
165  webkit_policy_decision_ignore(decision);
166  } else {
167  /* Filter out navigation to different domain ? */
168  /* get action→urirequest, copy and load in new window+view
169  * on Ctrl+Click ? */
170  webkit_policy_decision_use(decision);
171  }
172  break;
173  }
174 }
175 
176 void remmina_plugin_www_on_create(WebKitWebView *webview, WebKitNavigationAction *a, RemminaProtocolWidget *gp)
177 {
178  TRACE_CALL(__func__);
179  REMMINA_PLUGIN_DEBUG("New web-view");
180 
181  const gchar *url = NULL;
182 
183  RemminaPluginWWWData *gpdata;
184 
185  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
186 
187  switch (webkit_navigation_action_get_navigation_type(a)) {
188  case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
189  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_LINK_CLICKED");
190  url = webkit_uri_request_get_uri(
191  webkit_navigation_action_get_request(a));
192  REMMINA_PLUGIN_DEBUG("Downloading url %s ", url);
193  WebKitDownload *d = webkit_web_view_download_uri(gpdata->webview, url);
194  UNUSED(d);
195 
196  break;
197  case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
198  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED");
199  break;
200  case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
201  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_BACK_FORWARD");
202  break;
203  case WEBKIT_NAVIGATION_TYPE_RELOAD:
204  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_RELOAD");
205  break;
206  case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
207  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED");
208  /* Filter domains here */
209  /* If the value of “mouse-button” is not 0, then the navigation was triggered by a mouse event.
210  * test for link clicked but no button ? */
211  url = webkit_uri_request_get_uri(
212  webkit_navigation_action_get_request(a));
213  REMMINA_PLUGIN_DEBUG("Trying to open url: %s", url);
214  webkit_web_view_load_uri(gpdata->webview, url);
215  break;
216  case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */
217  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_OTHER");
218  /* Filter domains here */
219  /* If the value of “mouse-button” is not 0, then the navigation was triggered by a mouse event.
220  * test for link clicked but no button ? */
221  url = webkit_uri_request_get_uri(
222  webkit_navigation_action_get_request(a));
223  REMMINA_PLUGIN_DEBUG("Trying to open url: %s", url);
224  webkit_web_view_load_uri(gpdata->webview, url);
225  break;
226  default:
227  break;
228  }
229  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE is %d", webkit_navigation_action_get_navigation_type(a));
230 }
231 
232 void remmina_plugin_www_decide_newwin(WebKitPolicyDecision *decision, RemminaProtocolWidget *gp)
233 {
234  TRACE_CALL(__func__);
235  REMMINA_PLUGIN_DEBUG("Policy decision new window");
236 
237  const gchar *url = NULL;
238 
239  RemminaPluginWWWData *gpdata;
240 
241  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
242 
243  WebKitNavigationAction *a =
244  webkit_navigation_policy_decision_get_navigation_action(
245  WEBKIT_NAVIGATION_POLICY_DECISION(decision));
246 
247  switch (webkit_navigation_action_get_navigation_type(a)) {
248  case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
249  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_LINK_CLICKED");
250  url = webkit_uri_request_get_uri(
251  webkit_navigation_action_get_request(a));
252  REMMINA_PLUGIN_DEBUG("Downloading url %s ", url);
253  WebKitDownload *d = webkit_web_view_download_uri(gpdata->webview, url);
254  UNUSED(d);
255 
256 
257  break;
258  case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
259  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED");
260  break;
261  case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
262  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_BACK_FORWARD");
263  break;
264  case WEBKIT_NAVIGATION_TYPE_RELOAD:
265  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_RELOAD");
266  break;
267  case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
268  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED");
269  /* Filter domains here */
270  /* If the value of “mouse-button” is not 0, then the navigation was triggered by a mouse event.
271  * test for link clicked but no button ? */
272  url = webkit_uri_request_get_uri(
273  webkit_navigation_action_get_request(a));
274  REMMINA_PLUGIN_DEBUG("Trying to open url: %s", url);
275  webkit_web_view_load_uri(gpdata->webview, url);
276  break;
277  case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */
278  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE_OTHER");
279  /* Filter domains here */
280  /* If the value of “mouse-button” is not 0, then the navigation was triggered by a mouse event.
281  * test for link clicked but no button ? */
282  url = webkit_uri_request_get_uri(
283  webkit_navigation_action_get_request(a));
284  REMMINA_PLUGIN_DEBUG("Trying to open url: %s", url);
285  webkit_web_view_load_uri(gpdata->webview, url);
286  break;
287  default:
288  break;
289  }
290  REMMINA_PLUGIN_DEBUG("WEBKIT_NAVIGATION_TYPE is %d", webkit_navigation_action_get_navigation_type(a));
291 
292  webkit_policy_decision_ignore(decision);
293 }
294 gboolean remmina_plugin_www_decide_resource(WebKitPolicyDecision *decision, RemminaProtocolWidget *gp)
295 {
296  TRACE_CALL(__func__);
297  REMMINA_PLUGIN_DEBUG("Policy decision resource");
298  WebKitResponsePolicyDecision *response_decision =
299  WEBKIT_RESPONSE_POLICY_DECISION(decision);
300  WebKitURIResponse *response =
301  webkit_response_policy_decision_get_response(response_decision);;
302  const gchar *request_uri = webkit_uri_response_get_uri(response);
303 
304  WebKitURIRequest *request;
305  WebKitWebResource *main_resource;
307  const char *mime_type;
308 
309  RemminaPluginWWWData *gpdata;
310 
311  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
312 
313  mime_type = webkit_uri_response_get_mime_type(response);
314 
315  REMMINA_PLUGIN_DEBUG("The media type is %s", mime_type);
316 
317  /* If WebKit can't handle the media type, start the download
318  * process */
319  if (webkit_response_policy_decision_is_mime_type_supported(response_decision))
320  return FALSE;
321 
322  /* If it's not the main resource we don't need to set the document type. */
323  request = webkit_response_policy_decision_get_request(response_decision);
324  request_uri = webkit_uri_request_get_uri(request);
325  main_resource = webkit_web_view_get_main_resource(gpdata->webview);
326  if (g_strcmp0(webkit_web_resource_get_uri(main_resource), request_uri) != 0)
327  return FALSE;
328 
330  if (!strcmp(mime_type, "text/html") || !strcmp(mime_type, "text/plain"))
332  else if (!strcmp(mime_type, "application/xhtml+xml"))
334  else if (!strncmp(mime_type, "image/", 6))
336  else if (!strncmp(mime_type, "application/octet-stream", 6))
338 
339  REMMINA_PLUGIN_DEBUG("Document type is %i", type);
340 
341  /* FIXME: Maybe it makes more sense to have an API to query the media
342  * type when the load of a page starts than doing this here.
343  */
344  if (gpdata->document_type != type) {
345  gpdata->document_type = type;
346 
347  //g_object_notify_by_pspec (G_OBJECT (webview), obj_properties[PROP_DOCUMENT_TYPE]);
348  }
349 
350  webkit_policy_decision_download(decision);
351  return TRUE;
352 }
353 
354 static void remmina_www_web_view_js_finished(GObject *object, GAsyncResult *result, gpointer user_data)
355 {
356  TRACE_CALL(__func__);
357 
358  WebKitJavascriptResult *js_result;
359  GError *error = NULL;
360 
361  js_result = webkit_web_view_run_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error);
362  if (!js_result) {
363  REMMINA_PLUGIN_DEBUG("Could not run JavaScript code: %s", error->message);
364  g_error_free(error);
365  return;
366  }
367 
368 #if WEBKIT_CHECK_VERSION(2, 21, 1)
369  gchar *str_value;
370  JSCValue *value = webkit_javascript_result_get_js_value(js_result);
371  if (jsc_value_is_string(value) || jsc_value_is_boolean(value)) {
372  JSCException *exception;
373 
374  str_value = jsc_value_to_string(value);
375  exception = jsc_context_get_exception(jsc_value_get_context(value));
376  if (exception)
377  REMMINA_PLUGIN_DEBUG("Could not run JavaScript code: %s", jsc_exception_get_message(exception));
378  else
379  g_print("Script result: %s\n", str_value);
380  g_free(str_value);
381  } else {
382  str_value = jsc_value_to_string(value);
383  REMMINA_PLUGIN_DEBUG("Received something other than a string from JavaScript: %s", str_value);
384  g_free(str_value);
385  }
386 #endif
387  if (js_result) webkit_javascript_result_unref(js_result);
388 }
389 
391 {
392  TRACE_CALL(__func__);
393  return TRUE;
394 }
395 
396 static gboolean remmina_plugin_www_load_failed_tls_cb(WebKitWebView *webview, gchar *failing_uri, GTlsCertificate *certificate, GTlsCertificateFlags errors, RemminaProtocolWidget *gp) __attribute__ ((unused));
397 static gboolean remmina_plugin_www_load_failed_tls_cb(WebKitWebView *webview,
398  gchar *failing_uri, GTlsCertificate *certificate,
399  GTlsCertificateFlags errors, RemminaProtocolWidget *gp)
400 {
401  TRACE_CALL(__func__);
402  /* Avoid failing if certificate is not good. TODO: Add widgets to let the user decide */
403  REMMINA_PLUGIN_DEBUG("Ignoring certificate and return TRUE");
404  return TRUE;
405 }
406 
408 {
409  TRACE_CALL(__func__);
410 
411  RemminaPluginWWWData *gpdata;
412  RemminaFile *remminafile;
413  gchar *datapath;
414  gchar *cache_dir;
415 
416  gpdata = g_new0(RemminaPluginWWWData, 1);
417  g_object_set_data_full(G_OBJECT(gp), "plugin-data", gpdata, g_free);
418 
419  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
420 
421  /* RemminaPluginWWWData initialization */
422 
423  gpdata->authenticated = FALSE;
424  gpdata->formauthenticated = FALSE;
426 
427  datapath = g_build_path("/",
428  g_path_get_dirname(remmina_plugin_service->file_get_path(remminafile)),
429  PLUGIN_NAME,
430  NULL);
431  cache_dir = g_build_path("/", datapath, "cache", NULL);
432  REMMINA_PLUGIN_DEBUG("WWW data path is %s", datapath);
433 
434  if (datapath) {
435  gchar *indexeddb_dir = g_build_filename(datapath, "indexeddb", NULL);
436  gchar *local_storage_dir = g_build_filename(datapath, "local_storage", NULL);
437  gchar *applications_dir = g_build_filename(datapath, "applications", NULL);
438  gchar *websql_dir = g_build_filename(datapath, "websql", NULL);
439  gpdata->data_mgr = webkit_website_data_manager_new(
440  "disk-cache-directory", cache_dir,
441  "indexeddb-directory", indexeddb_dir,
442  "local-storage-directory", local_storage_dir,
443  "offline-application-cache-directory", applications_dir,
444  "websql-directory", websql_dir,
445  NULL
446  );
447  g_free(indexeddb_dir);
448  g_free(local_storage_dir);
449  g_free(applications_dir);
450  g_free(websql_dir);
451  g_free(datapath);
452  } else {
453  gpdata->data_mgr = webkit_website_data_manager_new_ephemeral();
454  }
455 
456 
457  if (remmina_plugin_service->file_get_string(remminafile, "server"))
458  gpdata->url = g_strdup(remmina_plugin_service->file_get_string(remminafile, "server"));
459  else
460  gpdata->url = "https://remmina.org";
461  REMMINA_PLUGIN_DEBUG("URL is set to %s", gpdata->url);
462 
463  gpdata->settings = webkit_settings_new();
464  gpdata->context = webkit_web_context_new_with_website_data_manager(gpdata->data_mgr);
465 
466  /* enable-fullscreen, default TRUE, TODO: Try FALSE */
467 
468 #ifdef DEBUG
469  /* Turn on the developer extras */
470  webkit_settings_set_enable_developer_extras(gpdata->settings, TRUE);
471  webkit_settings_set_enable_write_console_messages_to_stdout(gpdata->settings, TRUE);
472 #endif
473 
474  /* allow-file-access-from-file-urls */
475  webkit_settings_set_allow_file_access_from_file_urls(gpdata->settings, TRUE);
476  /* allow-modal-dialogs */
477  webkit_settings_set_allow_modal_dialogs(gpdata->settings, TRUE);
478  /* enable-caret-browsing */
479  webkit_settings_set_enable_caret_browsing(gpdata->settings, TRUE);
480  /* enable-html5-database */
481  webkit_settings_set_enable_html5_database(gpdata->settings, TRUE);
482 
483  /* user-agent. */
484  if (remmina_plugin_service->file_get_string(remminafile, "user-agent")) {
485  gchar *useragent = g_strdup(remmina_plugin_service->file_get_string(remminafile, "user-agent"));
486  webkit_settings_set_user_agent(gpdata->settings, useragent);
487  REMMINA_PLUGIN_DEBUG("User Agent set to: %s", useragent);
488  g_free(useragent);
489  }
490  /* enable-java */
491  if (remmina_plugin_service->file_get_int(remminafile, "enable-java", FALSE)) {
492  webkit_settings_set_enable_java(gpdata->settings, TRUE);
493  REMMINA_PLUGIN_DEBUG("Enable Java");
494  }
495  /* enable-smooth-scrolling */
496  if (remmina_plugin_service->file_get_int(remminafile, "enable-smooth-scrolling", FALSE)) {
497  webkit_settings_set_enable_smooth_scrolling(gpdata->settings, TRUE);
498  REMMINA_PLUGIN_DEBUG("enable-smooth-scrolling enabled");
499  }
500  /* enable-spatial-navigation */
501  if (remmina_plugin_service->file_get_int(remminafile, "enable-spatial-navigation", FALSE)) {
502  webkit_settings_set_enable_spatial_navigation(gpdata->settings, TRUE);
503  REMMINA_PLUGIN_DEBUG("enable-spatial-navigation enabled");
504  }
505  /* enable-webaudio */
506  if (remmina_plugin_service->file_get_int(remminafile, "enable-webaudio", FALSE)) {
507  webkit_settings_set_enable_webaudio(gpdata->settings, TRUE);
508  REMMINA_PLUGIN_DEBUG("enable-webaudio enabled");
509  }
510  /* enable-plugins */
511 #if WEBKIT_CHECK_VERSION(2, 32, 0)
512 #else
513  if (remmina_plugin_service->file_get_int(remminafile, "enable-plugins", FALSE)) {
514  webkit_settings_set_enable_plugins(gpdata->settings, TRUE);
515  REMMINA_PLUGIN_DEBUG("Enable plugins");
516  }
517 #endif
518  /* enable-webgl */
519 #if WEBKIT_CHECK_VERSION(2, 32, 0)
520 #else
521  if (remmina_plugin_service->file_get_int(remminafile, "enable-webgl", FALSE)) {
522  webkit_settings_set_enable_webgl(gpdata->settings, TRUE);
523  webkit_settings_set_enable_accelerated_2d_canvas(gpdata->settings, TRUE);
524  REMMINA_PLUGIN_DEBUG("enable-webgl enabled");
525  }
526 #endif
527 
528  if (remmina_plugin_service->file_get_int(remminafile, "ignore-tls-errors", FALSE)) {
529 #if WEBKIT_CHECK_VERSION(2, 32, 0)
530  webkit_website_data_manager_set_tls_errors_policy(
531  gpdata->data_mgr, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
532 #else
533  webkit_web_context_set_tls_errors_policy(
534  gpdata->context, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
535 #endif
536  REMMINA_PLUGIN_DEBUG("Ignore TLS errors");
537  }
538  if (remmina_plugin_service->file_get_string(remminafile, "proxy-url")) {
539  gchar *proxyurl = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy-url"));
540  WebKitNetworkProxySettings *proxy_settings = webkit_network_proxy_settings_new(proxyurl, NULL);
541 #if WEBKIT_CHECK_VERSION(2, 32, 0)
542  webkit_website_data_manager_set_network_proxy_settings(
543  gpdata->data_mgr, WEBKIT_NETWORK_PROXY_MODE_CUSTOM, proxy_settings);
544 #else
545  webkit_web_context_set_network_proxy_settings(
546  gpdata->context, WEBKIT_NETWORK_PROXY_MODE_CUSTOM, proxy_settings);
547 #endif
548  webkit_network_proxy_settings_free(proxy_settings);
549  g_free(proxyurl);
550  }
551 
552  webkit_web_context_set_automation_allowed(gpdata->context, TRUE);
553  webkit_settings_set_javascript_can_open_windows_automatically(gpdata->settings, TRUE);
554  webkit_settings_set_allow_modal_dialogs(gpdata->settings, TRUE);
555 
556 #if !WEBKIT_CHECK_VERSION(2, 38, 0)
557 
562  if (!webkit_settings_get_enable_frame_flattening(gpdata->settings))
563  webkit_settings_set_enable_frame_flattening(gpdata->settings, true);
564 #endif
565 
566  webkit_settings_set_enable_resizable_text_areas(gpdata->settings, true);
567 
568  g_signal_connect(G_OBJECT(gpdata->context), "download-started",
569  G_CALLBACK(remmina_plugin_www_download_started), gp);
570 }
571 
572 static gboolean remmina_plugin_www_on_auth(WebKitWebView *webview, WebKitAuthenticationRequest *request, RemminaProtocolWidget *gp)
573 {
574  TRACE_CALL(__func__);
575 
576  gchar *s_username, *s_password;
577  gint ret;
578  RemminaPluginWWWData *gpdata;
579  gboolean save;
580  gboolean disablepasswordstoring;
581  RemminaFile *remminafile;
582 
583  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
584 
585  REMMINA_PLUGIN_DEBUG("Authenticate");
586 
587  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
588 
589  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
590  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
592  _("Enter WWW authentication credentials"),
593  remmina_plugin_service->file_get_string(remminafile, "username"),
594  remmina_plugin_service->file_get_string(remminafile, "password"),
595  NULL,
596  NULL);
597  if (ret == GTK_RESPONSE_OK) {
598  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
599  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
600 
601  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
602  if (save) {
603  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
604  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
605  } else {
606  remmina_plugin_service->file_set_string(remminafile, "username", NULL);
607  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
608  }
609  if (request) {
610  gpdata->credentials = webkit_credential_new(
611  g_strdup(s_username),
612  g_strdup(s_password),
613  WEBKIT_CREDENTIAL_PERSISTENCE_FOR_SESSION);
614  webkit_authentication_request_authenticate(request, gpdata->credentials);
615  webkit_credential_free(gpdata->credentials);
616  }
617  if (s_username) g_free(s_username);
618  if (s_password) g_free(s_password);
619  gpdata->authenticated = TRUE;
620  } else {
621  gpdata->authenticated = FALSE;
622  }
623 
624  return gpdata->authenticated;
625 }
626 
627 static void remmina_plugin_www_form_auth(WebKitWebView *webview,
628  WebKitLoadEvent load_event, RemminaProtocolWidget *gp)
629 {
630  TRACE_CALL(__func__);
631  gchar *s_js;
632  GString *jsstr;
633  RemminaPluginWWWData *gpdata;
634  RemminaFile *remminafile;
635  gchar *remmina_dir;
636  gchar *www_js_file = NULL;
637  GError *error = NULL;
638 
639  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
640  if (gpdata && !gpdata->formauthenticated)
641  gpdata->formauthenticated = FALSE;
642 
643  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
644 
645  REMMINA_PLUGIN_DEBUG("load-changed emitted");
646 
647 
648  const gchar *const *dirs = g_get_system_data_dirs();
649 
650  unsigned int i = 0;
651 
652  for (i = 0; dirs[i] != NULL; ++i) {
653  remmina_dir = g_build_path("/", dirs[i], "remmina", "res", NULL);
654  GDir *system_data_dir = g_dir_open(remmina_dir, 0, &error);
655  // ignoring this error is ok, because the folder may not exists
656  if (error) {
657  g_error_free(error);
658  error = NULL;
659  } else {
660  if (system_data_dir) {
661  g_dir_close(system_data_dir);
662  g_free(www_js_file);
663  www_js_file = g_strdup_printf("%s/www-js.js", remmina_dir);
664  if (g_file_test(www_js_file, G_FILE_TEST_EXISTS))
665  break;
666  }
667  }
668  g_free(remmina_dir);
669  }
670 
671  switch (load_event) {
672  case WEBKIT_LOAD_STARTED:
673  REMMINA_PLUGIN_DEBUG("Load started");
674  break;
675  case WEBKIT_LOAD_REDIRECTED:
676  REMMINA_PLUGIN_DEBUG("Load redirected");
677  break;
678  case WEBKIT_LOAD_COMMITTED:
679  /* The load is being performed. Current URI is
680  * the final one and it won't change unless a new
681  * load is requested or a navigation within the
682  * same page is performed
683  * uri = webkit_web_view_get_uri (webview); */
684  REMMINA_PLUGIN_DEBUG("Load committed");
685  break;
686  case WEBKIT_LOAD_FINISHED:
687  /* Load finished, we can now set user/password
688  * in the HTML form */
689  REMMINA_PLUGIN_DEBUG("Load finished");
690  if (gpdata && gpdata->formauthenticated == TRUE)
691  break;
692 
693  if (remmina_plugin_service->file_get_string(remminafile, "username") ||
694  remmina_plugin_service->file_get_string(remminafile, "password")) {
695  REMMINA_PLUGIN_DEBUG("Authentication is enabled");
696  if (www_js_file) {
697  error = NULL;
698  if (g_file_get_contents(www_js_file, &s_js, NULL, &error)) {
699  jsstr = g_string_new(s_js);
700  if (remmina_plugin_service->file_get_string(remminafile, "username"))
701  www_utils_string_replace_all(jsstr, "USRPLACEHOLDER",
702  remmina_plugin_service->file_get_string(remminafile, "username"));
703  if (remmina_plugin_service->file_get_string(remminafile, "password"))
704  www_utils_string_replace_all(jsstr, "PWDPLACEHOLDER",
705  remmina_plugin_service->file_get_string(remminafile, "password"));
706  s_js = g_string_free(jsstr, FALSE);
707 
708  if (!s_js || s_js[0] == '\0') {
709  break;
710  } else {
711  REMMINA_PLUGIN_DEBUG("Trying to send this JavaScript: %s", s_js);
712  webkit_web_view_run_javascript(
713  webview,
714  s_js,
715  NULL,
717  gp);
718  g_free(s_js);
719  }
720  } else {
721  if (error) {
722  REMMINA_PLUGIN_DEBUG("Unable to read file: %s\n", error->message);
723  g_error_free(error);
724  } else {
725  REMMINA_PLUGIN_DEBUG("Unable to read file. No error returned from glib.\n");
726  }
727  }
728  }
729  }
730  break;
731  }
732 }
733 
735 {
736  TRACE_CALL(__func__);
737  RemminaPluginWWWData *gpdata;
738 
739  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
740 
741  webkit_web_view_stop_loading(gpdata->webview);
742  webkit_web_view_try_close(gpdata->webview);
743 
744  if (gpdata->url) g_free(gpdata->url);
745  gpdata->authenticated = FALSE;
746  gpdata->formauthenticated = FALSE;
747  gpdata->webview = NULL;
748  gpdata->data_mgr = NULL;
749  gpdata->settings = NULL;
750  gpdata->context = NULL;
751 
752  /* Remove instance->context from gp object data to avoid double free */
753  g_object_steal_data(G_OBJECT(gp), "plugin-data");
754 
755  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
756  return FALSE;
757 }
758 
760 {
761  TRACE_CALL(__func__);
762 
763  RemminaPluginWWWData *gpdata;
764  RemminaFile *remminafile;
765 
766  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
767 
768  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
769 
770  gpdata->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
771  gtk_container_add(GTK_CONTAINER(gp), gpdata->box);
772 
773  remmina_plugin_service->protocol_plugin_register_hostkey(gp, gpdata->box);
774 
775  gpdata->webview = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(gpdata->context));
776  webkit_web_view_set_settings(gpdata->webview, gpdata->settings);
777 
778  if (remmina_plugin_service->file_get_string(remminafile, "username") ||
779  remmina_plugin_service->file_get_string(remminafile, "password")) {
780  REMMINA_PLUGIN_DEBUG("Authentication is enabled");
781  remmina_plugin_www_on_auth(gpdata->webview, NULL, gp);
782  }
783 
784  //"signal::load-failed-with-tls-errors", G_CALLBACK(remmina_plugin_www_load_failed_tls_cb), gp,
785  g_object_connect(
786  G_OBJECT(gpdata->webview),
787  "signal::create", G_CALLBACK(remmina_plugin_www_on_create), gp,
788  "signal::load-changed", G_CALLBACK(remmina_plugin_www_form_auth), gp,
789  "signal::authenticate", G_CALLBACK(remmina_plugin_www_on_auth), gp,
790  "signal::decide-policy", G_CALLBACK(remmina_plugin_www_decide_policy_cb), gp,
791  NULL);
792 
793  gtk_widget_set_hexpand(GTK_WIDGET(gpdata->webview), TRUE);
794  gtk_widget_set_vexpand(GTK_WIDGET(gpdata->webview), TRUE);
795  gtk_container_add(GTK_CONTAINER(gpdata->box), GTK_WIDGET(gpdata->webview));
796  webkit_web_view_load_uri(gpdata->webview, gpdata->url);
797 #ifdef DEBUG
798  if (remmina_plugin_service->file_get_int(remminafile, "enable-webinspector", FALSE)) {
799  REMMINA_PLUGIN_DEBUG("WebInspector enabled");
800  WebKitWebInspector *inspector = webkit_web_view_get_inspector(WEBKIT_WEB_VIEW(gpdata->webview));
801  webkit_web_inspector_attach(inspector);
802  webkit_web_inspector_show(WEBKIT_WEB_INSPECTOR(inspector));
803  }
804 #endif
805  remmina_plugin_service->protocol_plugin_signal_connection_opened(gp);
806  gtk_widget_show_all(gpdata->box);
807 
808  return TRUE;
809 }
810 
811 static void remmina_plugin_www_save_snapshot(GObject *object, GAsyncResult *result, RemminaProtocolWidget *gp)
812 {
813  TRACE_CALL(__func__);
814 
815  WebKitWebView *webview = WEBKIT_WEB_VIEW(object);
816 
817  RemminaFile *remminafile;
818 
819  GError *err = NULL;
820  cairo_surface_t *surface;
821  //unsigned char* buffer;
822  int width;
823  int height;
824  GdkPixbuf *screenshot;
825  GString *pngstr;
826  gchar *pngname;
827  //cairo_forma_t* cairo_format;
828  GDateTime *date = g_date_time_new_now_utc();
829 
830  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
831 
832  surface = webkit_web_view_get_snapshot_finish(WEBKIT_WEB_VIEW(webview), result, &err);
833  if (err)
834  REMMINA_PLUGIN_DEBUG("An error happened generating the snapshot: %s\n", err->message);
835  //buffer = cairo_image_surface_get_data (surface);
836  width = cairo_image_surface_get_width(surface);
837  height = cairo_image_surface_get_height(surface);
838  //cairo_format = cairo_image_surface_get_format (surface);
839 
840  screenshot = gdk_pixbuf_get_from_surface(surface, 0, 0, width, height);
841  if (screenshot == NULL)
842  REMMINA_PLUGIN_DEBUG("WWW: gdk_pixbuf_get_from_surface failed");
843 
844  pngstr = g_string_new(g_strdup_printf("%s/%s.png",
845  remmina_plugin_service->pref_get_value("screenshot_path"),
846  remmina_plugin_service->pref_get_value("screenshot_name")));
847  www_utils_string_replace_all(pngstr, "%p",
848  remmina_plugin_service->file_get_string(remminafile, "name"));
849  www_utils_string_replace_all(pngstr, "%h", "URL");
850  www_utils_string_replace_all(pngstr, "%Y",
851  g_strdup_printf("%d", g_date_time_get_year(date)));
852  www_utils_string_replace_all(pngstr, "%m", g_strdup_printf("%d",
853  g_date_time_get_month(date)));
854  www_utils_string_replace_all(pngstr, "%d",
855  g_strdup_printf("%d", g_date_time_get_day_of_month(date)));
856  www_utils_string_replace_all(pngstr, "%H",
857  g_strdup_printf("%d", g_date_time_get_hour(date)));
858  www_utils_string_replace_all(pngstr, "%M",
859  g_strdup_printf("%d", g_date_time_get_minute(date)));
860  www_utils_string_replace_all(pngstr, "%S",
861  g_strdup_printf("%f", g_date_time_get_seconds(date)));
862  g_date_time_unref(date);
863  pngname = g_string_free(pngstr, FALSE);
864  REMMINA_PLUGIN_DEBUG("Saving screenshot as %s", pngname);
865 
866  cairo_surface_write_to_png(surface, pngname);
867  if (g_file_test(pngname, G_FILE_TEST_EXISTS))
868  www_utils_send_notification("www-plugin-screenshot-is-ready-id", _("Screenshot taken"), pngname);
869 
870  cairo_surface_destroy(surface);
871 }
873 {
874  TRACE_CALL(__func__);
875  RemminaPluginWWWData *gpdata;
876 
877  gpdata = (RemminaPluginWWWData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
878 
879  webkit_web_view_get_snapshot(gpdata->webview,
880  WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT,
881  WEBKIT_SNAPSHOT_OPTIONS_NONE,
882  NULL,
883  (GAsyncReadyCallback)remmina_plugin_www_save_snapshot,
884  gp);
885  return FALSE;
886 }
887 
888 /* Array of RemminaProtocolSetting for basic settings.
889  * Each item is composed by:
890  * a) RemminaProtocolSettingType for setting type
891  * b) Setting name
892  * c) Setting description
893  * d) Compact disposition
894  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
895  * f) Setting tooltip
896  * g) Validation data pointer, will be passed to the validation callback method.
897  * h) Validation callback method (Can be NULL. Every entry will be valid then.)
898  * use following prototype:
899  * gboolean mysetting_validator_method(gpointer key, gpointer value,
900  * gpointer validator_data);
901  * gpointer key is a gchar* containing the setting's name,
902  * gpointer value contains the value which should be validated,
903  * gpointer validator_data contains your passed data.
904  */
906 {
907  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "server", N_("URL"), FALSE, NULL, N_("http://address or https://address"), NULL, NULL },
908  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL, NULL, NULL },
909  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL, NULL, NULL },
910  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
911 };
912 
913 /* Array of RemminaProtocolSetting for advanced settings.
914  * Each item is composed by:
915  * a) RemminaProtocolSettingType for setting type
916  * b) Setting name
917  * c) Setting description
918  * d) Compact disposition
919  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
920  * f) Setting Tooltip
921  */
923 {
924  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "user-agent", N_("User agent"), FALSE, NULL, NULL },
925  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "proxy-url", N_("Proxy URL"), FALSE, NULL, N_("E.g. https://example.org, socks://mysocks:1080") },
926  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-java", N_("Turn on Java support"), TRUE, NULL, NULL },
927  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-smooth-scrolling", N_("Turn on smooth scrolling"), TRUE, NULL, NULL },
928  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-spatial-navigation", N_("Turn on spatial navigation"), TRUE, NULL, NULL },
929 #if WEBKIT_CHECK_VERSION(2, 32, 0)
930 #else
931  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-plugins", N_("Turn on plugin support"), TRUE, NULL, NULL },
932  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-webgl", N_("Turn on WebGL support"), TRUE, NULL, NULL },
933 #endif
934  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-webaudio", N_("Turn on HTML5 audio support"), TRUE, NULL, NULL },
935  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "ignore-tls-errors", N_("Ignore TLS errors"), TRUE, NULL, NULL },
936  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Forget passwords after use"), TRUE, NULL, NULL },
937 #ifdef DEBUG
938  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-webinspector", N_("Turn on Web Inspector"), TRUE, NULL, NULL },
939 #endif
940  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
941 };
942 
943 /* Array for available features.
944  * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */
946 {
947  { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL }
948 };
949 
950 /* Protocol plugin definition and features */
952 {
954  PLUGIN_NAME, // Name
955  PLUGIN_DESCRIPTION, // Description
956  GETTEXT_PACKAGE, // Translation domain
957  PLUGIN_VERSION, // Version number
958  PLUGIN_APPICON, // Icon for normal connection
959  NULL, // Icon for SSH connection
960  remmina_plugin_www_basic_settings, // Array for basic settings
961  remmina_plugin_www_advanced_settings, // Array for advanced settings
962  REMMINA_PROTOCOL_SSH_SETTING_NONE, // SSH settings type
963  remmina_www_features, // Array for available features
964  remmina_plugin_www_init, // Plugin initialization
965  remmina_plugin_www_open_connection, // Plugin open connection
966  remmina_plugin_www_close_connection, // Plugin close connection
967  remmina_www_query_feature, // Query for available features
968  NULL, // Call feature
969  NULL, // Send keystroke
970  remmina_plugin_www_get_snapshot, // Capture screenshot
971  NULL, // RCW map event
972  NULL // RCW unmap event
973 };
974 
975 G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
976 {
977  TRACE_CALL(__func__);
978  remmina_plugin_service = service;
979 
980  bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
981  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
982 
983 
984  if (!service->register_plugin((RemminaPlugin *)&remmina_plugin))
985  return FALSE;
986  return TRUE;
987 }
static void remmina_plugin_www_save_snapshot(GObject *object, GAsyncResult *result, RemminaProtocolWidget *gp)
Definition: www_plugin.c:811
static void remmina_plugin_www_init(RemminaProtocolWidget *gp)
Definition: www_plugin.c:407
void remmina_plugin_www_decide_newwin(WebKitPolicyDecision *decision, RemminaProtocolWidget *gp)
Definition: www_plugin.c:232
WebKitCredential * credentials
Definition: www_plugin.c:64
gboolean formauthenticated
Definition: www_plugin.c:71
static gboolean remmina_plugin_www_close_connection(RemminaProtocolWidget *gp)
Definition: www_plugin.c:734
static gboolean remmina_plugin_www_get_snapshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: www_plugin.c:872
WWWWebViewDocumentType
Definition: www_plugin.h:42
static gboolean remmina_plugin_www_on_auth(WebKitWebView *webview, WebKitAuthenticationRequest *request, RemminaProtocolWidget *gp)
Definition: www_plugin.c:572
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
RemminaPluginService * remmina_plugin_service
Definition: www_plugin.c:74
G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
Definition: www_plugin.c:975
static void remmina_plugin_www_form_auth(WebKitWebView *webview, WebKitLoadEvent load_event, RemminaProtocolWidget *gp)
Definition: www_plugin.c:627
WebKitWebContext * context
Definition: www_plugin.c:62
void(* protocol_plugin_signal_connection_closed)(RemminaProtocolWidget *gp)
Definition: plugin.h:185
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: plugin.h:222
static gboolean remmina_plugin_www_open_connection(RemminaProtocolWidget *gp)
Definition: www_plugin.c:759
WebKitWebView * webview
Definition: www_plugin.c:66
guint www_utils_string_replace_all(GString *haystack, const gchar *needle, const gchar *replace)
Replaces all occurrences of needle in haystack with replace.
Definition: www_utils.c:137
void(* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp)
Definition: plugin.h:186
WWWWebViewDocumentType document_type
Definition: www_plugin.c:59
static gboolean remmina_plugin_www_load_failed_tls_cb(WebKitWebView *webview, gchar *failing_uri, GTlsCertificate *certificate, GTlsCertificateFlags errors, RemminaProtocolWidget *gp) __attribute__((unused))
Definition: www_plugin.c:397
static const RemminaProtocolFeature remmina_www_features[]
Definition: www_plugin.c:945
gboolean(* protocol_plugin_init_get_savepassword)(RemminaProtocolWidget *gp)
Definition: plugin.h:197
gboolean(* register_plugin)(RemminaPlugin *plugin)
Definition: plugin.h:166
static const RemminaProtocolSetting remmina_plugin_www_basic_settings[]
Definition: www_plugin.c:905
static const RemminaProtocolSetting remmina_plugin_www_advanced_settings[]
Definition: www_plugin.c:922
static gboolean remmina_www_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: www_plugin.c:390
void remmina_plugin_www_download_started(WebKitWebContext *context, WebKitDownload *download, RemminaProtocolWidget *gp)
Definition: www_plugin.c:76
gchar *(* pref_get_value)(const gchar *key)
Definition: plugin.h:227
WebKitLoadEvent load_event
Definition: www_plugin.c:67
gboolean remmina_plugin_www_decide_resource(WebKitPolicyDecision *decision, RemminaProtocolWidget *gp)
Definition: www_plugin.c:294
gint(* protocol_plugin_init_auth)(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
Definition: plugin.h:191
struct _RemminaPluginWWWData RemminaPluginWWWData
RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
Definition: plugin.h:178
const gchar *(* file_get_path)(RemminaFile *remminafile)
Definition: plugin.h:217
void remmina_plugin_www_decide_nav(WebKitPolicyDecision *decision, RemminaProtocolWidget *gp)
Definition: www_plugin.c:130
void remmina_plugin_www_response_received(WebKitDownload *download, GParamSpec *ps, RemminaProtocolWidget *gp)
Definition: www_plugin.c:87
static RemminaProtocolPlugin remmina_plugin
Definition: www_plugin.c:951
gchar *(* protocol_plugin_init_get_username)(RemminaProtocolWidget *gp)
Definition: plugin.h:194
gchar *(* protocol_plugin_init_get_password)(RemminaProtocolWidget *gp)
Definition: plugin.h:195
WebKitSettings * settings
Definition: www_plugin.c:61
void(* protocol_plugin_register_hostkey)(RemminaProtocolWidget *gp, GtkWidget *widget)
Definition: plugin.h:180
void www_utils_send_notification(const gchar *notification_id, const gchar *notification_title, const gchar *notification_message)
Definition: www_utils.c:53
void(* file_set_string)(RemminaFile *remminafile, const gchar *setting, const gchar *value)
Definition: plugin.h:218
gboolean authenticated
Definition: www_plugin.c:70
static gboolean remmina_plugin_www_decide_policy_cb(WebKitWebView *webview, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decision_type, RemminaProtocolWidget *gp)
Definition: www_plugin.c:104
void remmina_plugin_www_notify_download(WebKitDownload *download, gchar *destination, RemminaProtocolWidget *gp)
Definition: www_plugin.c:93
const gchar *(* file_get_string)(RemminaFile *remminafile, const gchar *setting)
Definition: plugin.h:219
WebKitAuthenticationRequest * request
Definition: www_plugin.c:65
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
static void remmina_www_web_view_js_finished(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: www_plugin.c:354
WebKitWebsiteDataManager * data_mgr
Definition: www_plugin.c:63
void remmina_plugin_www_on_create(WebKitWebView *webview, WebKitNavigationAction *a, RemminaProtocolWidget *gp)
Definition: www_plugin.c:176