42 #if defined (HAVE_LIBSSH) && defined (HAVE_LIBVTE)
45 #include <glib/gi18n.h>
47 #include <glib-object.h>
48 #include <gobject/gvaluecollector.h>
61 #define PCRE2_CODE_UNIT_WIDTH 8
65 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_COPY 1
66 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_PASTE 2
67 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_SELECT_ALL 3
68 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_INCREASE_FONT 4
69 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_DECREASE_FONT 5
70 #define REMMINA_PLUGIN_SSH_FEATURE_TOOL_SEARCH 6
72 #define GET_PLUGIN_DATA(gp) (RemminaPluginSshData *)g_object_get_data(G_OBJECT(gp), "plugin-data");
75 #define PALETTE_SIZE 16
77 #define FONT_SCALE 0.75
78 #define SCALE_FACTOR 0.1
79 #define FONT_MINIMAL_SIZE (PANGO_SCALE * 6)
89 { 0.666667, 0, 0, 1 },
90 { 0, 0.666667, 0, 1 },
91 { 0.666667, 0.333333, 0, 1 },
92 { 0, 0, 0.666667, 1 },
93 { 0.666667, 0, 0.666667, 1 },
94 { 0, 0.666667, 0.666667, 1 },
95 { 0.666667, 0.666667, 0.666667, 1 },
96 { 0.333333, 0.333333, 0.333333, 1 },
97 { 1, 0.333333, 0.333333, 1 },
98 { 0.333333, 1, 0.333333, 1 },
99 { 1, 1, 0.333333, 1 },
100 { 0.333333, 0.333333, 1, 1 },
101 { 1, 0.333333, 1, 1 },
102 { 0.333333, 1, 1, 1 },
109 { 0.305882, 0.603922, 0.023529, 1 },
110 { 0.768627, 0.627451, 0, 1 },
111 { 0.203922, 0.396078, 0.643137, 1 },
112 { 0.458824, 0.313725, 0.482353, 1 },
113 { 0.0235294, 0.596078, 0.603922, 1 },
114 { 0.827451, 0.843137, 0.811765, 1 },
115 { 0.333333, 0.341176, 0.32549, 1 },
116 { 0.937255, 0.160784, 0.160784, 1 },
117 { 0.541176, 0.886275, 0.203922, 1 },
118 { 0.988235, 0.913725, 0.309804, 1 },
119 { 0.447059, 0.623529, 0.811765, 1 },
120 { 0.678431, 0.498039, 0.658824, 1 },
121 { 0.203922, 0.886275, 0.886275, 1 },
122 { 0.933333, 0.933333, 0.92549, 1 }
126 { 0.156863, 0.156863, 0.156863, 1.000000 },
127 { 0.800000, 0.141176, 0.113725, 1.000000 },
128 { 0.596078, 0.592157, 0.101961, 1.000000 },
129 { 0.843137, 0.600000, 0.129412, 1.000000 },
130 { 0.270588, 0.521569, 0.533333, 1.000000 },
131 { 0.694118, 0.384314, 0.525490, 1.000000 },
132 { 0.407843, 0.615686, 0.415686, 1.000000 },
133 { 0.658824, 0.600000, 0.517647, 1.000000 },
134 { 0.572549, 0.513725, 0.454902, 1.000000 },
135 { 0.984314, 0.286275, 0.203922, 1.000000 },
136 { 0.721569, 0.733333, 0.149020, 1.000000 },
137 { 0.980392, 0.741176, 0.184314, 1.000000 },
138 { 0.513725, 0.647059, 0.596078, 1.000000 },
139 { 0.827451, 0.525490, 0.607843, 1.000000 },
140 { 0.556863, 0.752941, 0.486275, 1.000000 },
141 { 0.921569, 0.858824, 0.698039, 1.000000 },
145 { 0.027451, 0.211765, 0.258824, 1 },
146 { 0.862745, 0.196078, 0.184314, 1 },
147 { 0.521569, 0.600000, 0.000000, 1 },
148 { 0.709804, 0.537255, 0.000000, 1 },
149 { 0.149020, 0.545098, 0.823529, 1 },
150 { 0.827451, 0.211765, 0.509804, 1 },
151 { 0.164706, 0.631373, 0.596078, 1 },
152 { 0.933333, 0.909804, 0.835294, 1 },
153 { 0.000000, 0.168627, 0.211765, 1 },
154 { 0.796078, 0.294118, 0.086275, 1 },
155 { 0.345098, 0.431373, 0.458824, 1 },
156 { 0.396078, 0.482353, 0.513725, 1 },
157 { 0.513725, 0.580392, 0.588235, 1 },
158 { 0.423529, 0.443137, 0.768627, 1 },
159 { 0.576471, 0.631373, 0.631373, 1 },
160 { 0.992157, 0.964706, 0.890196, 1 }
164 { 0.933333, 0.909804, 0.835294, 1 },
165 { 0.862745, 0.196078, 0.184314, 1 },
166 { 0.521569, 0.600000, 0.000000, 1 },
167 { 0.709804, 0.537255, 0.000000, 1 },
168 { 0.149020, 0.545098, 0.823529, 1 },
169 { 0.827451, 0.211765, 0.509804, 1 },
170 { 0.164706, 0.631373, 0.596078, 1 },
171 { 0.027451, 0.211765, 0.258824, 1 },
172 { 0.992157, 0.964706, 0.890196, 1 },
173 { 0.796078, 0.294118, 0.086275, 1 },
174 { 0.576471, 0.631373, 0.631373, 1 },
175 { 0.513725, 0.580392, 0.588235, 1 },
176 { 0.396078, 0.482353, 0.513725, 1 },
177 { 0.423529, 0.443137, 0.768627, 1 },
178 { 0.345098, 0.431373, 0.458824, 1 },
179 { 0.000000, 0.168627, 0.211765, 1 }
184 { 0.803922, 0, 0, 1 },
185 { 0, 0.803922, 0, 1 },
186 { 0.803922, 0.803922, 0, 1 },
187 { 0.117647, 0.564706, 1, 1 },
188 { 0.803922, 0, 0.803922, 1 },
189 { 0, 0.803922, 0.803922, 1 },
190 { 0.898039, 0.898039, 0.898039, 1 },
191 { 0.298039, 0.298039, 0.298039, 1 },
195 { 0.27451, 0.509804, 0.705882, 1 },
201 #define DEFAULT_PALETTE "linux_palette"
242 #define GET_OBJECT(object_name) gtk_builder_get_object(search_widget->builder, object_name)
252 return color->red >= 0. && color->red <= 1. &&
253 color->green >= 0. && color->green <= 1. &&
254 color->blue >= 0. && color->blue <= 1. &&
255 color->alpha >= 0. && color->alpha <= 1.;
268 TRACE_CALL(__func__);
274 gboolean cont = FALSE;
275 gboolean partial = FALSE;
279 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
282 gpdata = GET_PLUGIN_DATA(gp);
287 REMMINA_DEBUG(
"Tentatively create an SSH tunnel");
289 if (hostport == NULL) {
293 REMMINA_DEBUG(
"protocol_plugin_start_direct_tunnel returned hostport: %s", hostport);
295 ssh = g_object_get_data(G_OBJECT(gp),
"user-data");
297 REMMINA_DEBUG(
"Creating SSH shell based on existing SSH session");
299 REMMINA_DEBUG(
"Calling remmina_public_get_server_port");
310 REMMINA_DEBUG(
"Creating SSH shell based on a new SSH session");
312 ssh = REMMINA_SSH(shell);
313 REMMINA_DEBUG(
"Calling remmina_public_get_server_port");
320 REMMINA_DEBUG(
"init session error: %s", ssh->
error);
330 REMMINA_DEBUG(
"Authentication success");
343 REMMINA_AUDIT(_(
"Connected to %s:%d via SSH"), server, port);
344 g_free(server), server = NULL;
347 REMMINA_DEBUG(
"Continue with the next auth method");
353 REMMINA_DEBUG(
"Reconnecting…");
364 REMMINA_DEBUG(
"Interrupted by the user");
369 REMMINA_DEBUG(
"Error during the authentication: %s", ssh->
error);
382 REMMINA_DEBUG(
"Authentication terminated with exit status %d", ret);
392 gpdata->
shell = shell;
394 gchar *charset = REMMINA_SSH(shell)->charset;
409 TRACE_CALL(__func__);
414 d->
func = FUNC_VTE_TERMINAL_SET_ENCODING_AND_PTY;
423 setlocale(LC_ALL,
"");
424 if (codeset && codeset[0] !=
'\0') {
427 vte_terminal_set_backspace_binding(terminal, VTE_ERASE_ASCII_DELETE);
428 vte_terminal_set_delete_binding(terminal, VTE_ERASE_DELETE_SEQUENCE);
430 #if VTE_CHECK_VERSION(0, 38, 0)
432 vte_terminal_set_pty(terminal, vte_pty_new_foreign_sync(master, NULL, NULL));
434 vte_terminal_set_pty(terminal, master);
441 TRACE_CALL(__func__);
444 gtk_widget_grab_focus(gpdata->
vte);
451 TRACE_CALL(__func__);
455 if (!gtk_widget_get_mapped(widget))
return FALSE;
457 cols = vte_terminal_get_column_count(VTE_TERMINAL(widget));
458 rows = vte_terminal_get_row_count(VTE_TERMINAL(widget));
469 TRACE_CALL(__func__);
476 vte_terminal_set_audible_bell(VTE_TERMINAL(gpdata->
vte), TRUE);
477 g_info(
"audible_bell set to %i", vte_terminal_get_audible_bell(VTE_TERMINAL(gpdata->
vte)));
480 #if !VTE_CHECK_VERSION(0, 38, 0)
483 vte_terminal_set_font(VTE_TERMINAL(gpdata->
vte),
488 #if VTE_CHECK_VERSION(0, 51, 3)
489 REMMINA_DEBUG(
"Using vte_terminal_set_bold_is_bright instead of vte_terminal_set_allow_bold as deprecated");
501 TRACE_CALL(__func__);
502 vte_terminal_select_all(VTE_TERMINAL(vte));
509 TRACE_CALL(__func__);
510 vte_terminal_set_font_scale(VTE_TERMINAL(vte), vte_terminal_get_font_scale(VTE_TERMINAL(vte)) - SCALE_FACTOR);
516 TRACE_CALL(__func__);
517 vte_terminal_set_font_scale(VTE_TERMINAL(vte), vte_terminal_get_font_scale(VTE_TERMINAL(vte)) + SCALE_FACTOR);
523 TRACE_CALL(__func__);
524 #if VTE_CHECK_VERSION(0, 50, 0)
525 vte_terminal_copy_clipboard_format(VTE_TERMINAL(vte), VTE_FORMAT_TEXT);
527 vte_terminal_copy_clipboard(VTE_TERMINAL(vte));
534 TRACE_CALL(__func__);
535 vte_terminal_paste_clipboard(VTE_TERMINAL(vte));
541 TRACE_CALL(__func__);
547 GFileOutputStream *stream = g_file_replace(gpdata->
vte_session_file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &err);
551 widget = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _(
"Error: %s"), err->message);
552 g_signal_connect(G_OBJECT(widget),
"response", G_CALLBACK(gtk_widget_destroy), NULL);
553 gtk_widget_show(widget);
558 #if VTE_CHECK_VERSION(0, 38, 0)
559 vte_terminal_write_contents_sync(VTE_TERMINAL(gpdata->
vte), G_OUTPUT_STREAM(stream),
560 VTE_WRITE_DEFAULT, NULL, &err);
562 vte_terminal_write_contents(VTE_TERMINAL(gpdata->
vte), G_OUTPUT_STREAM(stream),
563 VTE_TERMINAL_WRITE_DEFAULT, NULL, &err);
568 _(
"Terminal content saved in"),
572 g_object_unref(stream);
579 TRACE_CALL(__func__);
583 keystrokes, keylen, GDK_KEY_PRESS | GDK_KEY_RELEASE);
590 static void jit_regex(VteRegex *regex,
char const *pattern)
592 TRACE_CALL(__func__);
595 if (!vte_regex_jit(regex, PCRE2_JIT_COMPLETE, &error) ||
596 !vte_regex_jit(regex, PCRE2_JIT_PARTIAL_SOFT, &error))
597 if (!g_error_matches(error, VTE_REGEX_ERROR, -45 ))
598 REMMINA_DEBUG(
"JITing regex “%s” failed: %s\n", pattern, error->message);
603 TRACE_CALL(__func__);
604 uint32_t flags = PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_MULTILINE;
607 flags |= PCRE2_CASELESS;
609 VteRegex *regex = vte_regex_new_for_search(pattern, strlen(pattern), flags, error);
620 TRACE_CALL(__func__);
621 gboolean can_search = search_widget->
has_regex;
630 TRACE_CALL(__func__);
631 GError *error = NULL;
634 char const *search_text = gtk_entry_get_text(GTK_ENTRY(search_widget->
search_entry));
640 pattern = g_strdup(search_text);
642 pattern = g_regex_escape_string(search_text, -1);
645 char *tmp = g_strdup_printf(
"\\b%s\\b", pattern);
658 if (search_text[0] !=
'\0') {
659 REMMINA_DEBUG(
"Search text is: %s", search_text);
661 vte_terminal_search_set_regex(VTE_TERMINAL(gpdata->
vte), regex, 0);
663 vte_regex_unref(regex);
669 gtk_widget_set_tooltip_text(search_widget->
search_entry, NULL);
672 REMMINA_DEBUG(
"Regex not set, cannot search");
673 gtk_widget_set_tooltip_text(search_widget->
search_entry, error->message);
686 TRACE_CALL(__func__);
688 vte_terminal_search_set_wrap_around(VTE_TERMINAL(gpdata->
vte), gtk_toggle_button_get_active(button));
694 TRACE_CALL(__func__);
700 vte_terminal_search_find_next(VTE_TERMINAL(gpdata->
vte));
706 TRACE_CALL(__func__);
712 vte_terminal_search_find_previous(VTE_TERMINAL(gpdata->
vte));
717 TRACE_CALL(__func__);
728 search_widget->
window = GTK_WIDGET(GET_OBJECT(
"RemminaSearchWidget"));
729 search_widget->
search_entry = GTK_WIDGET(GET_OBJECT(
"search_entry"));
732 search_widget->
close_button = GTK_WIDGET(GET_OBJECT(
"close_button"));
735 search_widget->
regex_checkbutton = GTK_TOGGLE_BUTTON(GET_OBJECT(
"regex_checkbutton"));
737 search_widget->
reveal_button = GTK_WIDGET(GET_OBJECT(
"reveal_button"));
738 search_widget->
revealer = GTK_WIDGET(GET_OBJECT(
"revealer"));
743 gtk_entry_set_activates_default(GTK_ENTRY(search_widget->
search_entry), TRUE);
746 gtk_builder_connect_signals(search_widget->
builder, NULL);
748 g_signal_connect_swapped(search_widget->
close_button,
"clicked", G_CALLBACK(gtk_widget_destroy), GTK_WIDGET(search_widget->
window));
750 g_object_bind_property(search_widget->
reveal_button,
"active",
751 search_widget->
revealer,
"reveal-child",
752 G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
769 return search_widget->
window;
774 TRACE_CALL(__func__);
777 GtkWindow *parent = NULL;
779 REMMINA_DEBUG(
"Before popover");
781 GtkWidget *toplevel = gtk_widget_get_toplevel(gpdata->
vte);
783 if (GTK_IS_WINDOW(toplevel)) {
784 parent = GTK_WINDOW(toplevel);
785 gtk_window_set_transient_for(GTK_WINDOW(window), parent);
786 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
788 gtk_widget_show(window);
789 REMMINA_DEBUG(
"After popover");
794 TRACE_CALL(__func__);
801 if ((event->type == GDK_BUTTON_PRESS) && (((GdkEventButton *)event)->button == 3)) {
802 #if GTK_CHECK_VERSION(3, 22, 0)
803 gtk_menu_popup_at_pointer(GTK_MENU(menu), NULL);
805 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
806 ((GdkEventButton *)event)->button, gtk_get_current_event_time());
829 TRACE_CALL(__func__);
832 GtkWidget *menu = gtk_menu_new();
834 GtkWidget *select_all = gtk_menu_item_new_with_label(_(
"Select All (host+A)"));
835 GtkWidget *copy = gtk_menu_item_new_with_label(_(
"Copy (host+C)"));
836 GtkWidget *paste = gtk_menu_item_new_with_label(_(
"Paste (host+V)"));
837 GtkWidget *save = gtk_menu_item_new_with_label(_(
"Save session to file"));
838 GtkWidget *font_incr = gtk_menu_item_new_with_label(_(
"Increase font size (host+Page Up)"));
839 GtkWidget *font_decr = gtk_menu_item_new_with_label(_(
"Decrease font size (host+Page Down)"));
840 GtkWidget *find_text = gtk_menu_item_new_with_label(_(
"Find text (host+G)"));
841 GtkWidget *sftp = gtk_menu_item_new_with_label(_(
"Open SFTP transfer…"));
843 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_all);
844 gtk_menu_shell_append(GTK_MENU_SHELL(menu), copy);
845 gtk_menu_shell_append(GTK_MENU_SHELL(menu), paste);
846 gtk_menu_shell_append(GTK_MENU_SHELL(menu), save);
847 gtk_menu_shell_append(GTK_MENU_SHELL(menu), font_incr);
848 gtk_menu_shell_append(GTK_MENU_SHELL(menu), font_decr);
849 gtk_menu_shell_append(GTK_MENU_SHELL(menu), find_text);
850 gtk_menu_shell_append(GTK_MENU_SHELL(menu), sftp);
852 g_signal_connect(G_OBJECT(gpdata->
vte),
"button_press_event",
855 g_signal_connect(G_OBJECT(select_all),
"activate",
857 g_signal_connect(G_OBJECT(copy),
"activate",
859 g_signal_connect(G_OBJECT(paste),
"activate",
861 g_signal_connect(G_OBJECT(save),
"activate",
863 g_signal_connect(G_OBJECT(font_incr),
"activate",
865 g_signal_connect(G_OBJECT(font_decr),
"activate",
867 g_signal_connect(G_OBJECT(find_text),
"activate",
869 g_signal_connect(G_OBJECT(sftp),
"activate",
872 gtk_widget_show_all(menu);
878 TRACE_CALL(__func__);
896 REMMINA_AUDIT(_(
"Disconnected from %s:%d via SSH"), server, port);
897 g_free(server), server = NULL;
904 TRACE_CALL(__func__);
909 REMMINA_DEBUG(
"Requesting to close the connection");
917 pthread_cancel(gpdata->
thread);
922 gpdata->
shell = NULL;
944 TRACE_CALL(__func__);
948 GtkAdjustment *vadjustment;
949 GtkWidget *vscrollbar;
951 GdkRGBA foreground_color;
952 GdkRGBA background_color;
953 GdkRGBA palette[PALETTE_SIZE];
956 #if !VTE_CHECK_VERSION(0, 38, 0)
957 GdkColor foreground_gdkcolor;
958 GdkColor background_gdkcolor;
962 g_object_set_data_full(G_OBJECT(gp),
"plugin-data", gpdata, g_free);
966 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
967 gtk_widget_show(hbox);
968 gtk_container_add(GTK_CONTAINER(gp), hbox);
971 vte = vte_terminal_new();
973 vte_terminal_set_size(VTE_TERMINAL(vte), 80, 25);
974 vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(vte), TRUE);
975 #if !VTE_CHECK_VERSION(0, 38, 0)
982 #if VTE_CHECK_VERSION(0, 38, 0)
983 GdkRGBA cp[PALETTE_SIZE];
984 GdkRGBA cursor_color;
985 GdkRGBA cursor_foreground;
987 GdkRGBA highlight_foreground;
999 gchar *remmina_dir = g_build_path(
"/", g_get_user_config_dir(),
"remmina",
"theme", NULL);
1001 g_free(remmina_dir);
1007 GError *error = NULL;
1008 const gchar *
const *dirs = g_get_system_data_dirs();
1010 for (i = 0; dirs[i] != NULL; ++i) {
1011 remmina_dir = g_build_path(
"/", dirs[i],
"remmina",
"theme", NULL);
1012 GDir *system_data_dir = g_dir_open(remmina_dir, 0, &error);
1015 g_error_free(error);
1018 if (system_data_dir) {
1019 g_dir_close(system_data_dir);
1026 g_free(remmina_dir);
1034 gkeyfile = g_key_file_new();
1038 REMMINA_DEBUG(
"Load custom theme for SSH teminal");
1039 g_warn_if_fail(gdk_rgba_parse(&foreground_color, color_pref.
foreground));
1040 g_warn_if_fail(gdk_rgba_parse(&background_color, color_pref.
background));
1041 g_warn_if_fail(gdk_rgba_parse(&cursor_color, color_pref.
cursor));
1042 g_warn_if_fail(gdk_rgba_parse(&cursor_foreground, color_pref.
cursor_foreground));
1043 g_warn_if_fail(gdk_rgba_parse(&highlight, color_pref.
highlight));
1045 g_warn_if_fail(gdk_rgba_parse(&colorBD, color_pref.
colorBD));
1047 g_warn_if_fail(gdk_rgba_parse(&cp[0], color_pref.
color0));
1048 g_warn_if_fail(gdk_rgba_parse(&cp[1], color_pref.
color1));
1049 g_warn_if_fail(gdk_rgba_parse(&cp[2], color_pref.
color2));
1050 g_warn_if_fail(gdk_rgba_parse(&cp[3], color_pref.
color3));
1051 g_warn_if_fail(gdk_rgba_parse(&cp[4], color_pref.
color4));
1052 g_warn_if_fail(gdk_rgba_parse(&cp[5], color_pref.
color5));
1053 g_warn_if_fail(gdk_rgba_parse(&cp[6], color_pref.
color6));
1054 g_warn_if_fail(gdk_rgba_parse(&cp[7], color_pref.
color7));
1055 g_warn_if_fail(gdk_rgba_parse(&cp[8], color_pref.
color8));
1056 g_warn_if_fail(gdk_rgba_parse(&cp[9], color_pref.
color9));
1057 g_warn_if_fail(gdk_rgba_parse(&cp[10], color_pref.
color10));
1058 g_warn_if_fail(gdk_rgba_parse(&cp[11], color_pref.
color11));
1059 g_warn_if_fail(gdk_rgba_parse(&cp[12], color_pref.
color12));
1060 g_warn_if_fail(gdk_rgba_parse(&cp[13], color_pref.
color13));
1061 g_warn_if_fail(gdk_rgba_parse(&cp[14], color_pref.
color14));
1062 g_warn_if_fail(gdk_rgba_parse(&cp[15], color_pref.
color15));
1064 const GdkRGBA custom_palette[PALETTE_SIZE] = {
1065 cp[0], cp[1], cp[2], cp[3],
1066 cp[4], cp[5], cp[6], cp[7],
1067 cp[8], cp[9], cp[10], cp[11],
1068 cp[12], cp[13], cp[14], cp[15]
1071 for (i = 0; i < PALETTE_SIZE; i++)
1072 palette[i] = custom_palette[i];
1077 gdk_rgba_parse(&foreground_color,
"#ffffff");
1078 gdk_rgba_parse(&background_color,
"#000000");
1079 gdk_rgba_parse(&cursor_color,
"#ffffff");
1080 gdk_rgba_parse(&cursor_foreground,
"#00000");
1081 gdk_rgba_parse(&highlight,
"#ffffff");
1082 gdk_rgba_parse(&highlight_foreground,
"#00000");
1083 gdk_rgba_parse(&colorBD,
"#ffffff");
1084 for (i = 0; i < PALETTE_SIZE; i++)
1088 gdk_rgba_parse(&foreground_color,
"#ffffff");
1089 gdk_rgba_parse(&background_color,
"#000000");
1090 gdk_rgba_parse(&cursor_color,
"#000000");
1091 gdk_rgba_parse(&cursor_foreground,
"#ffffff");
1092 gdk_rgba_parse(&highlight,
"#ffffff");
1093 gdk_rgba_parse(&highlight_foreground,
"#00000");
1094 gdk_rgba_parse(&colorBD,
"#000000");
1095 for (i = 0; i < PALETTE_SIZE; i++)
1099 gdk_rgba_parse(&foreground_color,
"#e6d4a3");
1100 gdk_rgba_parse(&background_color,
"#1e1e1e");
1101 gdk_rgba_parse(&cursor_color,
"#e6d4a3");
1102 gdk_rgba_parse(&cursor_foreground,
"#e6d4a3");
1103 gdk_rgba_parse(&highlight,
"#e6d4a3");
1104 gdk_rgba_parse(&highlight_foreground,
"#1e1e1e");
1105 gdk_rgba_parse(&colorBD,
"#ffffff");
1106 for (i = 0; i < PALETTE_SIZE; i++)
1110 gdk_rgba_parse(&foreground_color,
"#839496");
1111 gdk_rgba_parse(&background_color,
"#002b36");
1112 gdk_rgba_parse(&cursor_color,
"#93a1a1");
1113 gdk_rgba_parse(&cursor_foreground,
"#839496");
1114 gdk_rgba_parse(&highlight,
"#839496");
1115 gdk_rgba_parse(&highlight_foreground,
"#002b36");
1116 gdk_rgba_parse(&colorBD,
"#819090");
1117 for (i = 0; i < PALETTE_SIZE; i++)
1121 gdk_rgba_parse(&foreground_color,
"#657b83");
1122 gdk_rgba_parse(&background_color,
"#fdf6e3");
1123 gdk_rgba_parse(&cursor_color,
"#586e75");
1124 gdk_rgba_parse(&cursor_foreground,
"#657b83");
1125 gdk_rgba_parse(&highlight,
"#657b83");
1126 gdk_rgba_parse(&highlight_foreground,
"#fdf6e3");
1127 gdk_rgba_parse(&colorBD,
"#475b62");
1128 for (i = 0; i < PALETTE_SIZE; i++)
1132 gdk_rgba_parse(&foreground_color,
"#000000");
1133 gdk_rgba_parse(&background_color,
"#ffffff");
1134 gdk_rgba_parse(&cursor_color,
"#000000");
1135 gdk_rgba_parse(&cursor_foreground,
"#ffffff");
1136 gdk_rgba_parse(&highlight,
"#000000");
1137 gdk_rgba_parse(&highlight_foreground,
"#ffffff");
1138 gdk_rgba_parse(&colorBD,
"#000000");
1139 for (i = 0; i < PALETTE_SIZE; i++)
1143 REMMINA_DEBUG(
"Custom colors");
1169 const GdkRGBA custom_palette[PALETTE_SIZE] = {
1188 for (i = 0; i < PALETTE_SIZE; i++)
1189 palette[i] = custom_palette[i];
1192 REMMINA_DEBUG(
"Linux paelette colors");
1193 for (i = 0; i < PALETTE_SIZE; i++)
1199 REMMINA_DEBUG(
"foreground_color.red %f, background_color.red %f", foreground_color.red, background_color.red);
1200 REMMINA_DEBUG(
"foreground_color.blue %f, background_color.blue %f", foreground_color.blue, background_color.blue);
1201 REMMINA_DEBUG(
"foreground_color.green %f, background_color.green %f", foreground_color.green, background_color.green);
1202 REMMINA_DEBUG(
"foreground_color.alpha %f, background_color.alpha %f", foreground_color.alpha, background_color.alpha);
1203 for (i = 0; i < PALETTE_SIZE; i++) {
1204 REMMINA_DEBUG(
"index: %d, palette validation for red: %f", i, palette[i].red);
1205 REMMINA_DEBUG(
"index: %d, palette validation for green: %f", i, palette[i].green);
1206 REMMINA_DEBUG(
"index: %d, palette validation for blue: %f", i, palette[i].blue);
1207 REMMINA_DEBUG(
"index: %d, palette validation for alpha: %f", i, palette[i].alpha);
1210 vte_terminal_set_colors(VTE_TERMINAL(vte), &foreground_color, &background_color, palette, PALETTE_SIZE);
1211 vte_terminal_set_color_foreground(VTE_TERMINAL(vte), &foreground_color);
1212 vte_terminal_set_color_background(VTE_TERMINAL(vte), &background_color);
1213 vte_terminal_set_color_cursor(VTE_TERMINAL(vte), &cursor_color);
1214 vte_terminal_set_color_cursor_foreground(VTE_TERMINAL(vte), &cursor_foreground);
1215 vte_terminal_set_color_highlight(VTE_TERMINAL(vte), &highlight);
1216 vte_terminal_set_color_highlight_foreground(VTE_TERMINAL(vte), &highlight_foreground);
1217 vte_terminal_set_color_bold(VTE_TERMINAL(vte), &colorBD);
1221 foreground_gdkcolor.red = (guint16)(foreground_color.red * 0xFFFF);
1222 foreground_gdkcolor.green = (guint16)(foreground_color.green * 0xFFFF);
1223 foreground_gdkcolor.blue = (guint16)(foreground_color.blue * 0xFFFF);
1224 background_gdkcolor.red = (guint16)(background_color.red * 0xFFFF);
1225 background_gdkcolor.green = (guint16)(background_color.green * 0xFFFF);
1226 background_gdkcolor.blue = (guint16)(background_color.blue * 0xFFFF);
1228 vte_terminal_set_colors(VTE_TERMINAL(vte), &foreground_gdkcolor, &background_gdkcolor, NULL, 0);
1231 gtk_box_pack_start(GTK_BOX(hbox), vte, TRUE, TRUE, 0);
1237 #if VTE_CHECK_VERSION(0, 28, 0)
1238 vadjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(vte));
1240 vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->vte.terminal));
1243 vscrollbar = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, vadjustment);
1245 gtk_widget_show(vscrollbar);
1246 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, TRUE, 0);
1249 const gchar *sshlogname;
1252 GFile *rf = g_file_new_for_path(remminafile->filename);
1255 dir = g_build_path(
"/", g_get_user_cache_dir(),
"remmina", NULL);
1260 sshlogname = g_strconcat(g_file_get_basename(rf),
".",
"log", NULL);
1266 fp = g_strconcat(dir,
"/", sshlogname, NULL);
1267 g_free((gpointer) sshlogname);
1277 gtk_widget_show_all(hbox);
1290 TRACE_CALL(__func__);
1299 "Failed to initialize pthread. Falling back to non-thread mode…");
1316 TRACE_CALL(__func__);
1339 TRACE_CALL(__func__);
1342 switch (feature->
id) {
1343 case REMMINA_PROTOCOL_FEATURE_TOOL_SSH:
1346 NULL, gpdata->
shell, NULL);
1348 case REMMINA_PROTOCOL_FEATURE_TOOL_SFTP:
1352 NULL, gpdata->
shell, NULL);
1354 case REMMINA_PLUGIN_SSH_FEATURE_TOOL_COPY:
1355 #if VTE_CHECK_VERSION(0, 50, 0)
1356 vte_terminal_copy_clipboard_format(VTE_TERMINAL(gpdata->
vte), VTE_FORMAT_TEXT);
1358 vte_terminal_copy_clipboard(VTE_TERMINAL(gpdata->
vte));
1361 case REMMINA_PLUGIN_SSH_FEATURE_TOOL_PASTE:
1362 vte_terminal_paste_clipboard(VTE_TERMINAL(gpdata->
vte));
1364 case REMMINA_PLUGIN_SSH_FEATURE_TOOL_SELECT_ALL:
1365 vte_terminal_select_all(VTE_TERMINAL(gpdata->
vte));
1367 case REMMINA_PLUGIN_SSH_FEATURE_TOOL_INCREASE_FONT:
1368 vte_terminal_set_font_scale(VTE_TERMINAL(gpdata->
vte),
1369 vte_terminal_get_font_scale(VTE_TERMINAL(gpdata->
vte)) + SCALE_FACTOR);
1371 case REMMINA_PLUGIN_SSH_FEATURE_TOOL_DECREASE_FONT:
1372 vte_terminal_set_font_scale(VTE_TERMINAL(gpdata->
vte),
1373 vte_terminal_get_font_scale(VTE_TERMINAL(gpdata->
vte)) - SCALE_FACTOR);
1375 case REMMINA_PLUGIN_SSH_FEATURE_TOOL_SEARCH:
1394 "0",
N_(
"Password"),
1395 "1",
N_(
"SSH identity file"),
1396 "2",
N_(
"SSH agent"),
1397 "3",
N_(
"Public key (automatic)"),
1398 "4",
N_(
"Kerberos (GSSAPI)"),
1460 "3",
"Solarized Dark",
1461 "4",
"Solarized Light",
1463 "6",
"Custom (Configured in Remmina preferences)",
1507 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0)
1517 N_(
"The filename can use the following placeholders:\n\n"
1518 " • %h is substituted with the server name\n"
1519 " • %t is substituted with the SSH server name\n"
1520 " • %u is substituted with the username\n"
1521 " • %U is substituted with the SSH username\n"
1522 " • %p is substituted with Remmina profile name\n"
1523 " • %g is substituted with Remmina profile group name\n"
1524 " • %d is substituted with local date and time in ISO 8601 format\n");
1567 N_(
"SSH - Secure Shell"),
1570 "org.remmina.Remmina-ssh-symbolic",
1571 "org.remmina.Remmina-ssh-symbolic",
1596 return strcmp((gchar *)a, (gchar *)b);
1604 GError *error = NULL;
1605 GList *files = NULL;
1606 unsigned int rec_size = 0;
1611 const gchar *
const *dirs = g_get_system_data_dirs();
1615 for (i = 0; dirs[i] != NULL; ++i) {
1616 GDir *system_data_dir = NULL;
1617 gchar *remmina_dir = g_build_path(
"/", dirs[i],
"remmina",
"theme", NULL);
1618 system_data_dir = g_dir_open(remmina_dir, 0, &error);
1619 g_free(remmina_dir);
1622 g_error_free(error);
1625 if (system_data_dir) {
1626 const gchar *filename;
1627 while ((filename = g_dir_read_name(system_data_dir))) {
1628 if (!g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1629 if (g_str_has_suffix(filename,
".colors")) {
1630 gsize len = strrchr(filename,
'.') - filename;
1631 gchar *menu_str = g_strndup(filename, len);
1632 if (g_list_find_custom(files, menu_str,
compare) == NULL)
1633 files = g_list_insert_sorted(files, menu_str,
compare);
1642 gchar *remmina_dir = g_build_path(
"/", g_get_user_config_dir(),
"remmina",
"theme", NULL);
1643 GDir *user_data_dir;
1645 user_data_dir = g_dir_open(remmina_dir, 0, &error);
1646 g_free(remmina_dir);
1648 g_error_free(error);
1651 if (user_data_dir) {
1652 const gchar *filename;
1653 while ((filename = g_dir_read_name(user_data_dir))) {
1654 if (!g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1655 if (g_str_has_suffix(filename,
".colors")) {
1656 char *menu_str = g_malloc(strlen(filename) + 1);
1657 strcpy(menu_str, filename);
1658 char *t2 = strrchr(menu_str,
'.');
1660 if (g_list_find_custom(files, menu_str,
compare) == NULL)
1661 files = g_list_insert_sorted(files, menu_str,
compare);
1668 rec_size = g_list_length(files) * 2;
1670 gpointer *color_palette = g_malloc((preset_rec_size + rec_size) *
sizeof(gpointer));
1672 unsigned int field_idx = 0;
1674 *ssh_terminal_palette_new = color_palette;
1676 for (; field_idx < preset_rec_size; field_idx++) {
1678 if (!color_palette[field_idx])
1682 GList *l_files = NULL;
1684 for (l_files = g_list_first(files); l_files != NULL; l_files = l_files->next) {
1685 gchar *menu_str = (gchar *)l_files->data;
1687 color_palette[field_idx++] = menu_str;
1688 color_palette[field_idx++] = menu_str;
1692 color_palette[field_idx] = NULL;
1698 TRACE_CALL(__func__);
1711 #if GLIB_CHECK_VERSION(2,68,0)
1718 gpointer ssh_terminal_palette_new = NULL;
1722 settings[0].
opt1 = ssh_terminal_palette_new;
1727 ssh_threads_set_callbacks(ssh_threads_get_pthread());
1735 TRACE_CALL(__func__);
@ REMMINA_PLUGIN_TYPE_PROTOCOL
gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
RemminaFile * remmina_file_dup_temp_protocol(RemminaFile *remminafile, const gchar *new_protocol)
gchar * remmina_file_format_properties(RemminaFile *remminafile, const gchar *setting)
void remmina_masterthread_exec_and_wait(RemminaMTExecData *d)
gboolean remmina_masterthread_exec_is_main_thread()
RemminaPluginService remmina_plugin_manager_service
void remmina_pref_file_load_colors(GKeyFile *gkeyfile, RemminaColorPref *color_pref)
gchar * remmina_colors_file
GtkBuilder * remmina_public_gtk_builder_new_from_resource(gchar *resource)
void remmina_public_send_notification(const gchar *notification_id, const gchar *notification_title, const gchar *notification_message)
enum remmina_ssh_auth_result remmina_ssh_auth(RemminaSSH *ssh, const gchar *password, RemminaProtocolWidget *gp, RemminaFile *remminafile)
gboolean remmina_ssh_shell_open(RemminaSSHShell *shell, RemminaSSHExitFunc exit_callback, gpointer data)
RemminaSSHShell * remmina_ssh_shell_new_from_file(RemminaFile *remminafile)
void remmina_ssh_shell_free(RemminaSSHShell *shell)
void(* RemminaSSHExitFunc)(gpointer data)
gboolean remmina_ssh_init_session(RemminaSSH *ssh)
@ REMMINA_SSH_AUTH_PARTIAL
@ REMMINA_SSH_AUTH_USERCANCEL
@ REMMINA_SSH_AUTH_RECONNECT
@ REMMINA_SSH_AUTH_SUCCESS
void remmina_ssh_shell_set_size(RemminaSSHShell *shell, gint columns, gint rows)
enum remmina_ssh_auth_result remmina_ssh_auth_gui(RemminaSSH *ssh, RemminaProtocolWidget *gp, RemminaFile *remminafile)
RemminaSSHShell * remmina_ssh_shell_new_from_ssh(RemminaSSH *ssh)
static gboolean remmina_plugin_ssh_open_connection(RemminaProtocolWidget *gp)
Initialize the main window properties and the pthread.
void remmina_ssh_plugin_load_terminal_palettes(gpointer *ssh_terminal_palette_new)
void remmina_plugin_pop_search(GtkMenuItem *menuitem, RemminaProtocolWidget *gp)
static void remmina_search_widget_update_regex(RemminaPluginSshData *gpdata)
static void remmina_search_widget_update_sensitivity(RemminaSshSearch *search_widget)
const GdkRGBA tango_palette[PALETTE_SIZE]
static gint compare(gconstpointer a, gconstpointer b)
static const RemminaProtocolSetting remmina_ssh_basic_settings[]
static gboolean remmina_plugin_ssh_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Not used by the plugin.
void remmina_plugin_ssh_vte_select_all(GtkMenuItem *menuitem, gpointer vte)
static gboolean valid_color(GdkRGBA const *color)
struct _RemminaPluginSshData RemminaPluginSshData
static RemminaProtocolPlugin remmina_plugin_ssh
SSH Protocol plugin definition and features.
gboolean remmina_ssh_plugin_popup_menu(GtkWidget *widget, GdkEvent *event, GtkWidget *menu)
void remmina_plugin_ssh_vte_increase_font(GtkMenuItem *menuitem, gpointer vte)
void remmina_plugin_ssh_popup_ui(RemminaProtocolWidget *gp)
Remmina SSH plugin terminal popup menu.
static gpointer remmina_plugin_ssh_main_thread(gpointer data)
Remmina protocol plugin main function.
void remmina_plugin_ssh_vte_save_session(GtkMenuItem *menuitem, RemminaProtocolWidget *gp)
static const RemminaProtocolSetting remmina_ssh_advanced_settings[]
Array of RemminaProtocolSetting for advanced settings.
const GdkRGBA solarized_light_palette[PALETTE_SIZE]
static void remmina_plugin_ssh_init(RemminaProtocolWidget *gp)
Remmina SSH plugin initialization.
static gboolean remmina_plugin_ssh_close_connection(RemminaProtocolWidget *gp)
const GdkRGBA linux_palette[PALETTE_SIZE]
16 colour palettes in GdkRGBA format (red, green, blue, alpha).
static void remmina_plugin_ssh_eof(VteTerminal *vteterminal, RemminaProtocolWidget *gp)
void remmina_ssh_plugin_register(void)
static gboolean remmina_plugin_ssh_on_focus_in(GtkWidget *widget, GdkEventFocus *event, RemminaProtocolWidget *gp)
static gpointer ssh_charset_list[]
Charset list.
static RemminaPluginService * remmina_plugin_service
static void jit_regex(VteRegex *regex, char const *pattern)
const GdkRGBA xterm_palette[PALETTE_SIZE]
static void remmina_search_widget_search_forward(RemminaPluginSshData *gpdata)
static void remmina_plugin_ssh_set_vte_pref(RemminaProtocolWidget *gp)
static VteRegex * compile_regex_for_search(char const *pattern, gboolean caseless, GError **error)
static RemminaProtocolFeature remmina_plugin_ssh_features[]
Array for available features.
static void remmina_search_widget_search_backward(RemminaPluginSshData *gpdata)
static void remmina_ssh_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Send a keystroke to the plugin window.
static gpointer ssh_auth[]
Array of key/value pairs for SSH auth type libssh methods:
struct _RemminaSshSearch RemminaSshSearch
The SSH plugin implementation.
static void remmina_search_widget_wrap_around_toggled(GtkToggleButton *button, RemminaPluginSshData *gpdata)
static gboolean remmina_plugin_ssh_on_size_allocate(GtkWidget *widget, GtkAllocation *alloc, RemminaProtocolWidget *gp)
static void remmina_plugin_ssh_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Functions to call when an entry in the Tool menu in the Remmina Connection Window is clicked.
void remmina_plugin_ssh_vte_copy_clipboard(GtkMenuItem *menuitem, gpointer vte)
GtkWidget * remmina_plugin_pop_search_new(GtkWidget *relative_to, RemminaProtocolWidget *gp)
void remmina_plugin_ssh_vte_decrease_font(GtkMenuItem *menuitem, gpointer vte)
void remmina_plugin_ssh_vte_terminal_set_encoding_and_pty(VteTerminal *terminal, const char *codeset, int master, int slave)
static gpointer ssh_terminal_palette[]
void remmina_plugin_ssh_vte_paste_clipboard(GtkMenuItem *menuitem, gpointer vte)
void remmina_plugin_ssh_call_sftp(GtkMenuItem *menuitem, RemminaProtocolWidget *gp)
const GdkRGBA gruvbox_palette[PALETTE_SIZE]
const GdkRGBA solarized_dark_palette[PALETTE_SIZE]
gchar * cursor_foreground
gchar * highlight_foreground
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
void(* protocol_plugin_set_height)(RemminaProtocolWidget *gp, gint height)
void(* protocol_plugin_send_keys_signals)(GtkWidget *widget, const guint *keyvals, int length, GdkEventType action)
void(* protocol_plugin_set_expand)(RemminaProtocolWidget *gp, gboolean expand)
gboolean(* register_plugin)(RemminaPlugin *plugin)
const gchar *(* file_get_string)(RemminaFile *remminafile, const gchar *setting)
void(* get_server_port)(const gchar *server, gint defaultport, gchar **host, gint *port)
void(* protocol_plugin_set_error)(RemminaProtocolWidget *gp, const gchar *fmt,...)
GtkWidget *(* open_connection)(RemminaFile *remminafile, GCallback disconnect_cb, gpointer data, guint *handler)
void(* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp)
void(* protocol_plugin_signal_connection_closed)(RemminaProtocolWidget *gp)
void(* protocol_plugin_set_width)(RemminaProtocolWidget *gp, gint width)
void(* protocol_plugin_register_hostkey)(RemminaProtocolWidget *gp, GtkWidget *widget)
gchar *(* protocol_plugin_start_direct_tunnel)(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus)
RemminaSshSearch * search_widget
guint vte_shortcutkey_decrease_font
guint vte_shortcutkey_search_text
gboolean vte_allow_bold_text
guint vte_shortcutkey_copy
RemminaColorPref color_pref
guint vte_shortcutkey_paste
guint vte_shortcutkey_increase_font
guint vte_shortcutkey_select_all
const RemminaProtocolSetting * advanced_settings
gint tunnel_entrance_port
gchar * tunnel_entrance_host
The SSH plugin implementation.
GtkToggleButton * regex_checkbutton
GtkWidget * search_next_button
GtkToggleButton * wrap_around_checkbutton
GtkWidget * reveal_button
GtkToggleButton * entire_word_checkbutton
GtkToggleButton * match_case_checkbutton
GtkWidget * search_prev_button
struct remmina_masterthread_exec_data::@12::@26 vte_terminal_set_encoding_and_pty
union remmina_masterthread_exec_data::@12 p
enum remmina_masterthread_exec_data::@11 func
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
@ REMMINA_PROTOCOL_SSH_SETTING_TUNNEL
@ REMMINA_PROTOCOL_FEATURE_TYPE_END
@ REMMINA_PROTOCOL_FEATURE_TYPE_TOOL
@ REMMINA_PROTOCOL_SETTING_TYPE_SELECT
@ REMMINA_PROTOCOL_SETTING_TYPE_FILE
@ REMMINA_PROTOCOL_SETTING_TYPE_CHECK
@ REMMINA_PROTOCOL_SETTING_TYPE_SERVER
@ REMMINA_PROTOCOL_SETTING_TYPE_TEXT
@ REMMINA_PROTOCOL_SETTING_TYPE_END
@ REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD
N_("Unable to connect to VNC server")