41 #include <glib/gi18n.h> 58 #ifdef GDK_WINDOWING_WAYLAND 59 #include <gdk/gdkwayland.h> 115 DESKTOP_RESIZE_SIGNAL,
117 UNLOCK_DYNRES_SIGNAL,
131 TRACE_CALL(__func__);
134 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
137 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
140 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
143 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
146 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
152 TRACE_CALL(__func__);
160 g_debug (
"LibSSH support turned off, no need to free SSH tunnel data");
170 TRACE_CALL(__func__);
214 TRACE_CALL(__func__);
217 child = gtk_bin_get_child(GTK_BIN(gp));
220 gtk_widget_set_can_focus(child, TRUE);
221 gtk_widget_grab_focus(child);
227 TRACE_CALL(__func__);
240 TRACE_CALL(__func__);
262 if (num_plugin + num_ssh == 0) {
269 feature += num_plugin;
274 feature->
id = REMMINA_PROTOCOL_FEATURE_TOOL_SSH;
275 feature->
opt1 = _(
"Connect via SSH from a new terminal");
276 feature->
opt2 =
"utilities-terminal";
280 feature->
id = REMMINA_PROTOCOL_FEATURE_TOOL_SFTP;
281 feature->
opt1 = _(
"Open SFTP transfer…");
282 feature->
opt2 =
"folder-remote";
302 TRACE_CALL(__func__);
305 RemminaMessagePanel *mp;
316 s = g_strdup_printf(_(
"Connecting to \"%s\"…"), (name ? name :
"*"));
329 TRACE_CALL(__func__);
339 g_signal_emit_by_name(G_OBJECT(gp),
"disconnect");
340 return G_SOURCE_REMOVE;
347 TRACE_CALL(__func__);
354 TRACE_CALL(__func__);
373 g_signal_emit_by_name(G_OBJECT(gp),
"connect");
374 return G_SOURCE_REMOVE;
381 TRACE_CALL(__func__);
387 TRACE_CALL(__func__);
390 g_signal_emit_by_name(G_OBJECT(gp),
"update-align");
391 return G_SOURCE_REMOVE;
397 TRACE_CALL(__func__);
403 TRACE_CALL(__func__);
405 g_signal_emit_by_name(G_OBJECT(gp),
"unlock-dynres");
406 return G_SOURCE_REMOVE;
412 TRACE_CALL(__func__);
418 TRACE_CALL(__func__);
420 g_signal_emit_by_name(G_OBJECT(gp),
"desktop-resize");
421 return G_SOURCE_REMOVE;
427 TRACE_CALL(__func__);
434 TRACE_CALL(__func__);
439 if (!GTK_IS_WIDGET(gp))
451 g_signal_emit_by_name(G_OBJECT(gp),
"disconnect");
476 TRACE_CALL(__func__);
477 gchar *keystrokes = g_object_get_data(G_OBJECT(widget),
"keystrokes");
480 GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
481 gchar *iter = keystrokes;
487 typedef struct _KeystrokeReplace {
493 KeystrokeReplace keystrokes_replaces[] =
495 {
"\\n",
"\n", GDK_KEY_Return },
496 {
"\\t",
"\t", GDK_KEY_Tab },
497 {
"\\b",
"\b", GDK_KEY_BackSpace },
498 {
"\\e",
"\e", GDK_KEY_Escape },
499 {
"\\\\",
"\\", GDK_KEY_backslash },
505 for (i = 0; keystrokes_replaces[i].replace; i++) {
507 keystrokes_replaces[i].search,
508 keystrokes_replaces[i].replace);
510 keyvals = (guint *)g_malloc(strlen(keystrokes));
513 character = g_utf8_get_char_validated(iter, -1);
516 keyval = gdk_unicode_to_keyval(character);
518 for (i = 0; keystrokes_replaces[i].replace; i++) {
519 if (character == keystrokes_replaces[i].replace[0]) {
520 keys = g_new0(GdkKeymapKey, 1);
521 keyval = keystrokes_replaces[i].keyval;
530 if (!gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
531 g_warning(
"keyval 0x%04x has no keycode!", keyval);
532 iter = g_utf8_find_next_char(iter, NULL);
539 keyvals[n_keys++] = GDK_KEY_Shift_L;
541 keyvals[n_keys++] = GDK_KEY_Alt_R;
542 keyvals[n_keys++] = keyval;
547 iter = g_utf8_find_next_char(iter, NULL);
558 remmina_debug(
"plugin screenshot function is not implemented, using core Remmina functionality");
567 TRACE_CALL(__func__);
569 g_print(
"Emitting signals should be used from the object itself, not from another object");
576 d->
func = FUNC_PROTOCOLWIDGET_EMIT_SIGNAL;
583 g_signal_emit_by_name(G_OBJECT(gp), signal_name);
588 TRACE_CALL(__func__);
594 TRACE_CALL(__func__);
604 if (feature->
type == type)
611 TRACE_CALL(__func__);
617 TRACE_CALL(__func__);
621 if (feature->
type == type && (
id == 0 || feature->
id ==
id)) {
630 TRACE_CALL(__func__);
631 switch (feature->
id) {
633 case REMMINA_PROTOCOL_FEATURE_TOOL_SSH:
642 case REMMINA_PROTOCOL_FEATURE_TOOL_SFTP:
659 TRACE_CALL(__func__);
667 TRACE_CALL(__func__);
676 TRACE_CALL(__func__);
683 TRACE_CALL(__func__);
689 RemminaMessagePanel *mp;
695 d->
func = FUNC_PROTOCOLWIDGET_MPPROGRESS;
718 d->
func = FUNC_PROTOCOLWIDGET_MPDESTROY;
731 printf(
"Remmina: Cancelling an opening tunnel is not implemented\n");
736 TRACE_CALL(__func__);
740 RemminaMessagePanel *mp;
744 g_debug (
"[RPW] %s creating SSH tunnel to \"%s\" via SSH…", __func__, REMMINA_SSH(tunnel)->server);
745 msg = g_strdup_printf(_(
"Connecting to \"%s\" via SSH…"), REMMINA_SSH(tunnel)->server);
751 remmina_debug (
"%s Cannot init SSH session with tunnel struct", __func__);
776 printf(
"Remmina: Cancelling start_direct_tunnel is not implemented\n");
782 TRACE_CALL(__func__);
787 #if GLIB_CHECK_VERSION(2,54,0) 800 printf(
"Tunnel %s found at idx = %d\n", found ?
"yes":
"not", idx);
804 g_debug(
"[RPW] tunnel with idx %u has been disconnected", idx);
818 TRACE_CALL(__func__);
820 const gchar *ssh_tunnel_server;
822 gchar *ssh_tunnel_host, *srv_host, *dest;
823 gint srv_port, ssh_tunnel_port;
825 g_debug (
"SSH tunnel initialization…");
836 g_debug (
"server: %s, port: %d", srv_host, srv_port);
838 if (port_plus && srv_port < 100)
840 srv_port += default_port;
844 RemminaMessagePanel *mp;
848 dest = g_strdup_printf(
"[%s]:%i", srv_host, srv_port);
850 g_free(ssh_tunnel_host);
857 g_free(ssh_tunnel_host);
858 remmina_debug (
"%s remmina_protocol_widget_init_tunnel failed with error is %s",
863 msg = g_strdup_printf(_(
"Connecting to \"%s\" via SSH…"), server);
869 g_free(ssh_tunnel_host);
870 ssh_tunnel_host = NULL;
871 srv_host = g_strdup(
"127.0.0.1");
874 g_debug (
"%s: starting tunnel to: %s, port: %d", __func__, ssh_tunnel_host, ssh_tunnel_port);
877 g_free(ssh_tunnel_host);
883 g_free(ssh_tunnel_host);
896 dest = g_strdup_printf(
"[%s]:%i", srv_host, srv_port);
898 g_free(ssh_tunnel_host);
907 printf(
"Remmina: Cancelling start_reverse_tunnel is not implemented\n");
914 TRACE_CALL(__func__);
917 RemminaMessagePanel *mp;
944 TRACE_CALL(__func__);
949 gboolean ret = FALSE;
958 if ((channel = ssh_channel_new(REMMINA_SSH(tunnel)->
session)) == NULL)
962 cmd = g_strdup_vprintf(fmt, args);
965 if (ssh_channel_open_session(channel) == SSH_OK &&
966 ssh_channel_request_exec(channel, cmd) == SSH_OK) {
968 ssh_channel_send_eof(channel);
969 status = ssh_channel_get_exit_status(channel);
970 ptr = strchr(cmd,
' ');
971 if (ptr) *ptr =
'\0';
978 _(
"The \"%s\" command is not available on the SSH server."), cmd);
982 _(
"Could not run the \"%s\" command on the SSH server (status = %i)."), cmd, status);
994 ssh_channel_close(channel);
995 ssh_channel_free(channel);
1008 TRACE_CALL(__func__);
1024 TRACE_CALL(__func__);
1030 TRACE_CALL(__func__);
1033 if (REMMINA_SSH(tunnel)->error)
1043 printf(
"Remmina: Cancelling an XPort connection is not implemented\n");
1048 TRACE_CALL(__func__);
1050 gboolean bindlocalhost;
1053 RemminaMessagePanel *mp;
1069 bindlocalhost = (g_strcmp0(REMMINA_SSH(tunnel)->server, server) == 0);
1074 ssh_get_error(REMMINA_SSH(tunnel)->
session));
1091 TRACE_CALL(__func__);
1098 tunnel->
localdisplay = g_strdup_printf(
"unix:%i", display);
1104 TRACE_CALL(__func__);
1111 TRACE_CALL(__func__);
1119 TRACE_CALL(__func__);
1125 TRACE_CALL(__func__);
1131 TRACE_CALL(__func__);
1137 TRACE_CALL(__func__);
1143 TRACE_CALL(__func__);
1149 TRACE_CALL(__func__);
1155 TRACE_CALL(__func__);
1161 TRACE_CALL(__func__);
1168 TRACE_CALL(__func__);
1174 TRACE_CALL(__func__);
1180 TRACE_CALL(__func__);
1191 va_start(args, fmt);
1200 TRACE_CALL(__func__);
1206 TRACE_CALL(__func__);
1233 if (button == GTK_RESPONSE_OK) {
1253 pthread_cond_signal(&d->
pt_cond);
1254 pthread_mutex_unlock(&d->
pt_mutex);
1266 RemminaMessagePanel *mp;
1300 RemminaMessagePanel *
mp;
1308 if (g_main_loop_is_running(mpri->
loop))
1309 g_main_loop_quit(mpri->
loop);
1324 mpri->
response = GTK_RESPONSE_CANCEL;
1333 mpri->
response = GTK_RESPONSE_CANCEL;
1338 const gchar *title,
const gchar *default_username,
const gchar *default_password,
const gchar *default_domain,
1339 const gchar *strpasswordlabel)
1341 TRACE_CALL(__func__);
1349 d->
title = g_strdup(title);
1358 MpRunInfo mpri = { NULL, NULL, GTK_RESPONSE_CANCEL, FALSE };
1360 gulong unmap_handler;
1361 gulong destroy_handler;
1362 gulong response_handler;
1368 if (!gtk_widget_get_visible(GTK_WIDGET(mpri.
mp)))
1369 gtk_widget_show(GTK_WIDGET(mpri.
mp));
1374 g_object_ref(mpri.
mp);
1376 mpri.
loop = g_main_loop_new(NULL, FALSE);
1377 g_main_loop_run(mpri.
loop);
1378 g_main_loop_unref(mpri.
loop);
1381 g_signal_handler_disconnect(mpri.
mp, response_handler);
1382 g_signal_handler_disconnect(mpri.
mp, destroy_handler);
1383 g_signal_handler_disconnect(mpri.
mp, unmap_handler);
1385 g_object_unref(mpri.
mp);
1393 pthread_cond_init(&d->
pt_cond, NULL);
1394 pthread_mutex_init(&d->
pt_mutex, NULL);
1399 pthread_mutex_destroy(&d->
pt_mutex);
1400 pthread_cond_destroy(&d->
pt_cond);
1422 TRACE_CALL(__func__);
1424 default_password, default_domain, password_prompt == NULL ? _(
"Password") : password_prompt);
1429 TRACE_CALL(__func__);
1436 !remminafile->prevent_saving && allow_password_saving)
1443 password, NULL, _(
"Password"));
1483 TRACE_CALL(__func__);
1491 TRACE_CALL(__func__);
1496 s = g_strdup_printf(
1497 "<big>%s</big>\n\n%s %s\n%s %s\n%s %s\n\n<big>%s</big>",
1498 _(
"Certificate details:"),
1499 _(
"Subject:"), subject,
1500 _(
"Issuer:"), issuer,
1501 _(
"Fingerprint:"), fingerprint,
1502 _(
"Accept certificate?"));
1507 return rc == GTK_RESPONSE_YES ? GTK_RESPONSE_OK : rc;
1512 TRACE_CALL(__func__);
1517 s = g_strdup_printf(
1518 "<big>%s</big>\n\n%s %s\n%s %s\n%s %s\n%s %s\n\n<big>%s</big>",
1519 _(
"The certificate changed! Details:"),
1520 _(
"Subject:"), subject,
1521 _(
"Issuer:"), issuer,
1522 _(
"Old fingerprint:"), old_fingerprint,
1523 _(
"New fingerprint:"), new_fingerprint,
1524 _(
"Accept changed certificate?"));
1529 return rc == GTK_RESPONSE_YES ? GTK_RESPONSE_OK : rc;
1534 TRACE_CALL(__func__);
1540 TRACE_CALL(__func__);
1546 TRACE_CALL(__func__);
1552 TRACE_CALL(__func__);
1558 TRACE_CALL(__func__);
1562 return s && s[0] ? g_strdup(s) : NULL;
1567 TRACE_CALL(__func__);
1571 return s && s[0] ? g_strdup(s) : NULL;
1576 TRACE_CALL(__func__);
1580 return s && s[0] ? g_strdup(s) : NULL;
1585 TRACE_CALL(__func__);
1589 return s && s[0] ? g_strdup(s) : NULL;
1594 TRACE_CALL(__func__);
1598 gboolean save = FALSE;
1604 d->
func = FUNC_INIT_SAVE_CRED;
1648 TRACE_CALL(__func__);
1649 RemminaMessagePanel *mp;
1656 d->
func = FUNC_PROTOCOLWIDGET_PANELSHOWLISTEN;
1665 s = g_strdup_printf(
1666 _(
"Listening on port %i for an incoming %s connection…"), port,
1676 TRACE_CALL(__func__);
1677 RemminaMessagePanel *mp;
1683 d->
func = FUNC_PROTOCOLWIDGET_MPSHOWRETRY;
1697 TRACE_CALL(__func__);
1698 printf(
"Remmina: The %s function is not implemented, and is left here only for plugin API compatibility.\n", __func__);
1703 TRACE_CALL(__func__);
1704 printf(
"Remmina: The %s function is not implemented, and is left here only for plugin API compatibility.\n", __func__);
1709 TRACE_CALL(__func__);
1716 TRACE_CALL(__func__);
1721 g_signal_connect_swapped(G_OBJECT(gp->
priv->
chat_window),
"send", G_CALLBACK(on_send), gp);
1724 g_signal_connect_swapped(G_OBJECT(gp->
priv->
chat_window),
"destroy", G_CALLBACK(on_destroy), gp);
1731 TRACE_CALL(__func__);
1738 TRACE_CALL(__func__);
1746 d->
func = FUNC_CHAT_RECEIVE;
1783 return GTK_WIDGET(g_object_new(REMMINA_TYPE_PROTOCOL_WIDGET, NULL));
1792 TRACE_CALL(__func__);
1796 GdkKeymap *keymap = gdk_keymap_get_for_display(gdk_display_get_default());
1798 event.window = gtk_widget_get_window(widget);
1799 event.send_event = TRUE;
1800 event.time = GDK_CURRENT_TIME;
1806 if (action & GDK_KEY_PRESS) {
1808 event.type = GDK_KEY_PRESS;
1809 for (i = 0; i < keyvals_length; i++) {
1810 event.keyval = keyvals[i];
1813 g_signal_emit_by_name(G_OBJECT(widget),
"key-press-event", &event, &result);
1817 if (action & GDK_KEY_RELEASE) {
1819 event.type = GDK_KEY_RELEASE;
1820 for (i = (keyvals_length - 1); i >= 0; i--) {
1821 event.keyval = keyvals[i];
1824 g_signal_emit_by_name(G_OBJECT(widget),
"key-release-event", &event, &result);
1831 TRACE_CALL(__func__);
1850 if (wfile <= 0 || hfile <= 0)
1859 gtk_widget_get_allocation(GTK_WIDGET(gp), &al);
1863 printf(
"Remmina warning: %s RemminaProtocolWidget w=%d h=%d are too small, adjusting to 640x480\n", __func__, w, h);
1871 if (h > rect.height)
enum remmina_ssh_auth_result remmina_ssh_auth_gui(RemminaSSH *ssh, RemminaProtocolWidget *gp, RemminaFile *remminafile)
const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
RemminaSSHTunnelCallback destroy_func
gboolean remmina_ssh_tunnel_reverse(RemminaSSHTunnel *tunnel, gint port, gint local_port)
void remmina_message_panel_setup_auth(RemminaMessagePanel *mp, RemminaMessagePanelCallback response_callback, gpointer response_callback_data, const gchar *title, const gchar *password_prompt, unsigned flags)
void(* call_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
void remmina_message_panel_setup_question(RemminaMessagePanel *mp, const gchar *message, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
gchar * remmina_message_panel_field_get_filename(RemminaMessagePanel *mp, int entryid)
const gchar * remmina_file_get_filename(RemminaFile *remminafile)
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
struct remmina_masterthread_exec_data::@11::@18 protocolwidget_emit_signal
void rco_show_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
Each cnnobj->page can have more than one RemminaMessagePanel, but 0 or 1 are visible.
gpointer destroy_func_callback_data
RemminaFile * remmina_file_dup_temp_protocol(RemminaFile *remminafile, const gchar *new_protocol)
GtkWidget * rcw_open_from_file_full(RemminaFile *remminafile, GCallback disconnect_cb, gpointer data, guint *handler)
void remmina_message_panel_setup_auth_x509(RemminaMessagePanel *mp, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
void(* init)(RemminaProtocolWidget *gp)
const RemminaProtocolFeature * features
enum remmina_masterthread_exec_data::@10 func
struct remmina_masterthread_exec_data::@11::@20 protocolwidget_mpdestroy
void rco_destroy_message_panel(RemminaConnectionObject *cnnobj, RemminaMessagePanel *mp)
Deletes a RemminaMessagePanel from the current cnnobj and if it was visible, make visible the last re...
struct remmina_masterthread_exec_data::@11::@14 chat_receive
gboolean(* open_connection)(RemminaProtocolWidget *gp)
void remmina_message_panel_field_set_string(RemminaMessagePanel *mp, int entryid, const gchar *text)
RemminaProtocolWidgetResolutionMode
RemminaSSHTunnelCallback disconnect_func
void remmina_debug(const gchar *fmt,...)
Print a string in the Remmina Debug Windows and in the terminal.
gchar * remmina_public_str_replace_in_place(gchar *string, const gchar *search, const gchar *replacement)
GtkDialog * remmina_ext_exec_new(RemminaFile *remminafile, const char *remmina_ext_exec_type)
void remmina_message_panel_field_set_filename(RemminaMessagePanel *mp, int entryid, const gchar *filename)
gboolean remmina_masterthread_exec_is_main_thread()
union remmina_masterthread_exec_data::@11 p
static SoupSession * session
RemminaProtocolFeatureType type
void(* send_keystrokes)(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
void remmina_ssh_set_error(RemminaSSH *ssh, const gchar *fmt)
gboolean remmina_ssh_tunnel_xport(RemminaSSHTunnel *tunnel, gboolean bindlocalhost)
RemminaSSHTunnel * remmina_ssh_tunnel_new_from_file(RemminaFile *remminafile)
RemminaSSHTunnelCallback init_func
void remmina_message_panel_field_set_switch(RemminaMessagePanel *mp, int entryid, gboolean state)
struct remmina_masterthread_exec_data::@11::@13 init_save_creds
struct remmina_masterthread_exec_data::@11::@21 protocolwidget_mpshowretry
void remmina_ssh_tunnel_cancel_accept(RemminaSSHTunnel *tunnel)
void remmina_ssh_tunnel_free(RemminaSSHTunnel *tunnel)
RemminaProtocolFeatureType
gboolean(* close_connection)(RemminaProtocolWidget *gp)
void remmina_masterthread_exec_and_wait(RemminaMTExecData *d)
void(* RemminaMessagePanelCallback)(void *user_data, int button)
gchar * remmina_message_panel_field_get_string(RemminaMessagePanel *mp, int entryid)
struct remmina_masterthread_exec_data::@11::@19 protocolwidget_mpprogress
void remmina_message_panel_setup_progress(RemminaMessagePanel *mp, const gchar *message, RemminaMessagePanelCallback response_callback, gpointer response_callback_data)
gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
gboolean(* query_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
guint16 remmina_public_get_keycode_for_keyval(GdkKeymap *keymap, guint keyval)
gpointer RemminaTunnelInitFunc
gboolean remmina_public_get_modifier_for_keycode(GdkKeymap *keymap, guint16 keycode)
gboolean(* get_plugin_screenshot)(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
gboolean remmina_message_panel_field_get_switch_state(RemminaMessagePanel *mp, int entryid)
void remmina_file_set_string(RemminaFile *remminafile, const gchar *setting, const gchar *value)
void remmina_file_save(RemminaFile *remminafile)
void rco_get_monitor_geometry(RemminaConnectionObject *cnnobj, GdkRectangle *sz)
void remmina_ssh_set_application_error(RemminaSSH *ssh, const gchar *fmt,...)
void remmina_chat_window_receive(RemminaChatWindow *window, const gchar *name, const gchar *text)
void remmina_public_get_server_port(const gchar *server, gint defaultport, gchar **host, gint *port)
gboolean remmina_ssh_tunnel_open(RemminaSSHTunnel *tunnel, const gchar *host, gint port, gint local_port)
struct remmina_masterthread_exec_data::@11::@22 protocolwidget_panelshowlisten
GtkWidget * remmina_chat_window_new(GtkWindow *parent, const gchar *chat_with)
gboolean(* RemminaXPortTunnelInitFunc)(RemminaProtocolWidget *gp, gint remotedisplay, const gchar *server, gint port)
void remmina_message_panel_response(RemminaMessagePanel *mp, gint response_id)
RemminaMessagePanel * remmina_message_panel_new()
RemminaSSHTunnelCallback connect_func
gboolean remmina_ssh_init_session(RemminaSSH *ssh)