Skip to content

Commit 6fcdce8

Browse files
authored
Merge pull request #1333 from FreeRDP/issue1320_vtesave
Save SSH session to file, closes #1320
2 parents 6155345 + 7ee0995 commit 6fcdce8

3 files changed

Lines changed: 121 additions & 23 deletions

File tree

remmina/src/remmina_file_manager.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "remmina/remmina_trace_calls.h"
4747

4848
static gchar *remminadir;
49+
static gchar *cachedir;
4950

5051
/* return first found data dir as per XDG specs.
5152
* The returned string must be freed by the caller with g_free */
@@ -103,8 +104,11 @@ void remmina_file_manager_init(void)
103104
remminadir = g_build_path ( "/", g_get_user_data_dir (), g_get_prgname (), NULL);
104105
/* Create the XDG_USER_DATA directory */
105106
g_mkdir_with_parents (remminadir, 0750);
106-
107107
g_free (remminadir), remminadir = NULL;
108+
/* Create the XDG_CACHE_HOME directory */
109+
cachedir = g_build_path ( "/", g_get_user_cache_dir (), g_get_prgname (), NULL);
110+
g_mkdir_with_parents (cachedir, 0750);
111+
g_free (cachedir), cachedir = NULL;
108112
/* Empty legacy ~/.remmina */
109113
remminadir = g_build_path ("/", g_get_home_dir(), legacy, NULL);
110114
if (g_file_test (remminadir, G_FILE_TEST_IS_DIR))

remmina/src/remmina_pref_dialog.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
#include <glib/gi18n.h>
3939
#include <stdlib.h>
4040
#include "config.h"
41+
#ifdef HAVE_LIBSSH
4142
#include <vte/vte.h>
43+
#endif
4244
#include "remmina_public.h"
4345
#include "remmina_string_list.h"
4446
#include "remmina_widget_pool.h"

remmina/src/remmina_ssh_plugin.c

Lines changed: 114 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
#include <gtk/gtk.h>
4343
#include <glib/gi18n.h>
44+
#include <gio/gio.h>
4445
#include <vte/vte.h>
4546
#include <locale.h>
4647
#include <langinfo.h>
@@ -193,6 +194,7 @@ static struct {
193194
typedef struct _RemminaPluginSshData
194195
{
195196
RemminaSSHShell *shell;
197+
GFile *vte_session_file;
196198
GtkWidget *vte;
197199

198200
const GdkRGBA *palette;
@@ -377,22 +379,68 @@ remmina_plugin_ssh_set_vte_pref (RemminaProtocolWidget *gp)
377379
}
378380

379381
void
380-
remmina_plugin_ssh_vte_select_all (GtkMenuItem *menuitem, gpointer user_data)
382+
remmina_plugin_ssh_vte_select_all (GtkMenuItem *menuitem, gpointer vte)
381383
{
382-
vte_terminal_select_all (VTE_TERMINAL (user_data));
384+
TRACE_CALL(__func__);
385+
vte_terminal_select_all (VTE_TERMINAL(vte));
383386
/* TODO: we should add the vte_terminal_unselect_all as well */
384387
}
385388

386389
void
387-
remmina_plugin_ssh_vte_copy_clipboard (GtkMenuItem *menuitem, gpointer user_data)
390+
remmina_plugin_ssh_vte_copy_clipboard (GtkMenuItem *menuitem, gpointer vte)
388391
{
389-
vte_terminal_copy_clipboard (VTE_TERMINAL (user_data));
392+
TRACE_CALL(__func__);
393+
#if VTE_CHECK_VERSION(0,50,0)
394+
vte_terminal_copy_clipboard_format (VTE_TERMINAL(vte), VTE_FORMAT_TEXT);
395+
#else
396+
vte_terminal_copy_clipboard (VTE_TERMINAL(vte));
397+
#endif
398+
}
399+
400+
void
401+
remmina_plugin_ssh_vte_paste_clipboard (GtkMenuItem *menuitem, gpointer vte)
402+
{
403+
TRACE_CALL(__func__);
404+
vte_terminal_paste_clipboard (VTE_TERMINAL(vte));
390405
}
391406

392407
void
393-
remmina_plugin_ssh_vte_paste_clipboard (GtkMenuItem *menuitem, gpointer user_data)
408+
remmina_plugin_ssh_vte_save_session (GtkMenuItem *menuitem, RemminaProtocolWidget *gp)
394409
{
395-
vte_terminal_paste_clipboard (VTE_TERMINAL (user_data));
410+
TRACE_CALL(__func__);
411+
RemminaPluginSshData *gpdata = GET_PLUGIN_DATA(gp);
412+
413+
GError* err = NULL;
414+
415+
GFileOutputStream *stream = g_file_replace(gpdata->vte_session_file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &err);
416+
417+
if (err != NULL) {
418+
remmina_plugin_service->protocol_plugin_set_error (gp, "%s", err);
419+
return;
420+
}
421+
422+
if (stream != NULL)
423+
#if VTE_CHECK_VERSION(0,38,0)
424+
vte_terminal_write_contents_sync (VTE_TERMINAL(gpdata->vte), G_OUTPUT_STREAM(stream),
425+
VTE_WRITE_DEFAULT, NULL, &err);
426+
#else
427+
vte_terminal_write_contents (VTE_TERMINAL(gpdata->vte), G_OUTPUT_STREAM(stream),
428+
VTE_TERMINAL_WRITE_DEFAULT, NULL, &err);
429+
#endif
430+
431+
if (err == NULL) {
432+
remmina_public_send_notification ("remmina-terminal-saved",
433+
_("Terminal content saved under"),
434+
g_file_get_path(gpdata->vte_session_file));
435+
}
436+
else
437+
{
438+
439+
remmina_plugin_service->protocol_plugin_set_error (gp, "%s", err);
440+
}
441+
442+
g_free(err);
443+
g_object_unref(stream);
396444
}
397445

398446
/* Send a keystroke to the plugin window */
@@ -413,13 +461,8 @@ remmina_ssh_plugin_popup_menu(GtkWidget *widget, GdkEvent *event, GtkWidget *men
413461
#if GTK_CHECK_VERSION(3, 22, 0)
414462
gtk_menu_popup_at_pointer(GTK_MENU(menu), NULL);
415463
#else
416-
gtk_menu_popup(GTK_MENU(menu),
417-
NULL,
418-
NULL,
419-
NULL,
420-
NULL,
421-
((GdkEventButton*)event)->button,
422-
gtk_get_current_event_time());
464+
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
465+
((GdkEventButton*)event)->button, gtk_get_current_event_time());
423466
#endif
424467
return TRUE;
425468
}
@@ -437,20 +480,24 @@ void remmina_plugin_ssh_popup_ui(RemminaProtocolWidget *gp)
437480
GtkWidget *select_all = gtk_menu_item_new_with_label(_("Select All (Host+a)"));
438481
GtkWidget *copy = gtk_menu_item_new_with_label(_("Copy (Host+c)"));
439482
GtkWidget *paste = gtk_menu_item_new_with_label(_("Paste (Host+v)"));
483+
GtkWidget *save = gtk_menu_item_new_with_label(_("Save session to file (Host+v)"));
440484

441-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_all);
442-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), copy);
443-
gtk_menu_shell_append(GTK_MENU_SHELL(menu), paste);
485+
gtk_menu_shell_append (GTK_MENU_SHELL(menu), select_all);
486+
gtk_menu_shell_append (GTK_MENU_SHELL(menu), copy);
487+
gtk_menu_shell_append (GTK_MENU_SHELL(menu), paste);
488+
gtk_menu_shell_append (GTK_MENU_SHELL(menu), save);
444489

445490
g_signal_connect (G_OBJECT(gpdata->vte), "button_press_event",
446491
G_CALLBACK(remmina_ssh_plugin_popup_menu), menu);
447492

448-
g_signal_connect(G_OBJECT(select_all), "activate",
493+
g_signal_connect (G_OBJECT(select_all), "activate",
449494
G_CALLBACK(remmina_plugin_ssh_vte_select_all), gpdata->vte);
450-
g_signal_connect(G_OBJECT(copy), "activate",
495+
g_signal_connect (G_OBJECT(copy), "activate",
451496
G_CALLBACK(remmina_plugin_ssh_vte_copy_clipboard), gpdata->vte);
452-
g_signal_connect(G_OBJECT(paste), "activate",
497+
g_signal_connect (G_OBJECT(paste), "activate",
453498
G_CALLBACK(remmina_plugin_ssh_vte_paste_clipboard), gpdata->vte);
499+
g_signal_connect (G_OBJECT(save), "activate",
500+
G_CALLBACK(remmina_plugin_ssh_vte_save_session), gp);
454501

455502
gtk_widget_show_all(menu);
456503
}
@@ -557,8 +604,9 @@ remmina_plugin_ssh_init (RemminaProtocolWidget *gp)
557604
gdk_rgba_parse(&cp[15], remmina_pref.color15);
558605

559606
const GdkRGBA custom_palette[PALETTE_SIZE] = {
560-
cp[0] , cp[1] , cp[2] , cp[3] , cp[4] , cp[5] ,
561-
cp[6] , cp[7] , cp[8] , cp[9] , cp[10], cp[11],
607+
cp[0], cp[1], cp[2], cp[3],
608+
cp[4], cp[5], cp[6], cp[7],
609+
cp[8], cp[9], cp[10], cp[11],
562610
cp[12], cp[13], cp[14], cp[15] };
563611

564612
remminavte.palette = custom_palette;
@@ -603,6 +651,34 @@ remmina_plugin_ssh_init (RemminaProtocolWidget *gp)
603651
gtk_widget_show(vscrollbar);
604652
gtk_box_pack_start (GTK_BOX (hbox), vscrollbar, FALSE, TRUE, 0);
605653

654+
const gchar *dir;
655+
const gchar *sshlogname;
656+
const gchar *fp;
657+
GFile *rf;
658+
659+
rf = g_file_new_for_path(remminafile->filename);
660+
661+
if (remmina_plugin_service->file_get_string (remminafile, "sshlogfolder") == NULL)
662+
{
663+
dir = g_build_path ( "/", g_get_user_cache_dir (), g_get_prgname (), NULL);
664+
}
665+
else
666+
{
667+
dir = remmina_plugin_service->file_get_string (remminafile, "sshlogfolder");
668+
}
669+
670+
if (remmina_plugin_service->file_get_string (remminafile, "sshlogname") == NULL)
671+
{
672+
sshlogname = g_strconcat (g_file_get_basename(rf), "." , "log", NULL);
673+
}
674+
else
675+
{
676+
sshlogname = remmina_plugin_service->file_get_string (remminafile, "sshlogname");
677+
}
678+
679+
fp = g_strconcat (dir, "/" , sshlogname, NULL);
680+
gpdata->vte_session_file = g_file_new_for_path (fp);
681+
606682
remmina_plugin_ssh_popup_ui(gp);
607683
}
608684

@@ -636,6 +712,14 @@ remmina_plugin_ssh_close_connection (RemminaProtocolWidget *gp)
636712
TRACE_CALL("remmina_plugin_ssh_close_connection");
637713
RemminaPluginSshData *gpdata = GET_PLUGIN_DATA(gp);
638714

715+
RemminaFile *remminafile;
716+
717+
remminafile = remmina_plugin_service->protocol_plugin_get_file (gp);
718+
719+
if (remmina_file_get_int (remminafile, "sshlogenabled", FALSE))
720+
{
721+
remmina_plugin_ssh_vte_save_session (NULL, gp);
722+
}
639723
if (gpdata->thread)
640724
{
641725
pthread_cancel (gpdata->thread);
@@ -677,7 +761,11 @@ remmina_plugin_ssh_call_feature (RemminaProtocolWidget *gp, const RemminaProtoco
677761
NULL, gpdata->shell, NULL);
678762
return;
679763
case REMMINA_PLUGIN_SSH_FEATURE_TOOL_COPY:
680-
vte_terminal_copy_clipboard (VTE_TERMINAL (gpdata->vte));
764+
#if VTE_CHECK_VERSION(0,50,0)
765+
vte_terminal_copy_clipboard_format (VTE_TERMINAL(gpdata->vte), VTE_FORMAT_TEXT);
766+
#else
767+
vte_terminal_copy_clipboard (VTE_TERMINAL(gpdata->vte));
768+
#endif
681769
return;
682770
case REMMINA_PLUGIN_SSH_FEATURE_TOOL_PASTE:
683771
vte_terminal_paste_clipboard (VTE_TERMINAL (gpdata->vte));
@@ -809,6 +897,9 @@ static const RemminaProtocolSetting remmina_ssh_advanced_settings[] =
809897
{ REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "ssh_color_scheme", N_("Terminal color scheme"), FALSE, ssh_terminal_palette, NULL },
810898
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "exec", N_("Startup program"), FALSE, NULL, NULL },
811899
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Disable password storing"), FALSE, NULL, NULL },
900+
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sshlogenabled", N_("Enable SSH session logging at exit"), FALSE, NULL, NULL },
901+
{ REMMINA_PROTOCOL_SETTING_TYPE_FOLDER, "sshlogfolder", N_("SSH session log folder"), FALSE, NULL, NULL },
902+
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "sshlogname", N_("SSH session log file name"), FALSE, NULL, NULL },
812903
{ REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
813904
};
814905

@@ -841,6 +932,7 @@ remmina_ssh_plugin_register (void)
841932
remmina_plugin_ssh_features[0].opt3 = GUINT_TO_POINTER (remmina_pref.vte_shortcutkey_copy);
842933
remmina_plugin_ssh_features[1].opt3 = GUINT_TO_POINTER (remmina_pref.vte_shortcutkey_paste);
843934
remmina_plugin_ssh_features[2].opt3 = GUINT_TO_POINTER (remmina_pref.vte_shortcutkey_select_all);
935+
remmina_plugin_ssh_features[3].opt3 = GUINT_TO_POINTER (remmina_pref.vte_shortcutkey_select_all);
844936

845937
remmina_plugin_service = &remmina_plugin_manager_service;
846938
remmina_plugin_service->register_plugin ((RemminaPlugin *) &remmina_plugin_ssh);

0 commit comments

Comments
 (0)