48 #ifdef GDK_WINDOWING_X11 50 #elif defined(GDK_WINDOWING_WAYLAND) 51 #include <gdk/gdkwayland.h> 55 #include <X11/XKBlib.h> 56 #include <X11/extensions/XKBrules.h> 58 #include <sys/types.h> 63 #define FEATURE_AVAILABLE(gpdata, feature) \ 64 gpdata->available_features ? (g_list_find_custom( \ 65 gpdata->available_features, \ 67 (GCompareFunc) g_strcmp0 \ 68 ) ? TRUE : FALSE) : FALSE 70 #define FEATURE_NOT_AVAIL_STR(feature) \ 71 g_strdup_printf(_("The command-line feature '%s' is not available! Attempting " \ 72 "to start PyHoca-CLI without using this feature…"), feature) 74 #define GET_PLUGIN_DATA(gp) \ 75 (RemminaPluginX2GoData*) g_object_get_data(G_OBJECT(gp), "plugin-data") 78 #define SET_RESUME_SESSION(gp, resume_data) \ 79 g_object_set_data_full(G_OBJECT(gp), "resume-session-data", \ 83 #define GET_RESUME_SESSION(gp) \ 84 (gchar*) g_object_get_data(G_OBJECT(gp), "resume-session-data") 87 #define IS_SESSION_SELECTED(gp) \ 88 g_object_get_data(G_OBJECT(gp), "session-selected") ? TRUE : FALSE 91 #define SET_SESSION_SELECTED(gp, is_session_selected) \ 92 g_object_set_data_full(G_OBJECT(gp), "session-selected", \ 93 is_session_selected, \ 97 #define REMMINA_PLUGIN_INFO(fmt, ...) \ 98 rm_plugin_service->_remmina_info("[%s] " fmt, \ 99 PLUGIN_NAME, ##__VA_ARGS__) 101 #define REMMINA_PLUGIN_MESSAGE(fmt, ...) \ 102 rm_plugin_service->_remmina_message("[%s] " fmt, \ 103 PLUGIN_NAME, ##__VA_ARGS__) 105 #define REMMINA_PLUGIN_DEBUG(fmt, ...) \ 106 rm_plugin_service->_remmina_debug(__func__, "[%s] " fmt, \ 107 PLUGIN_NAME, ##__VA_ARGS__) 109 #define REMMINA_PLUGIN_WARNING(fmt, ...) \ 110 rm_plugin_service->_remmina_warning(__func__, "[%s] " fmt, \ 111 PLUGIN_NAME, ##__VA_ARGS__) 113 #define REMMINA_PLUGIN_AUDIT(fmt, ...) \ 114 rm_plugin_service->_remmina_audit(__func__, fmt, ##__VA_ARGS__) 116 #define REMMINA_PLUGIN_ERROR(fmt, ...) \ 117 rm_plugin_service->_remmina_error(__func__, "[%s] " fmt, \ 118 PLUGIN_NAME, ##__VA_ARGS__) 120 #define REMMINA_PLUGIN_CRITICAL(fmt, ...) \ 121 rm_plugin_service->_remmina_critical(__func__, "[%s] " fmt, \ 122 PLUGIN_NAME, ##__VA_ARGS__) 124 #define GET_PLUGIN_STRING(value) \ 125 g_strdup(rm_plugin_service->file_get_string(remminafile, value)) 127 #define GET_PLUGIN_PASSWORD(value) \ 128 GET_PLUGIN_STRING(value) 130 #define GET_PLUGIN_INT(value, default_value) \ 131 rm_plugin_service->file_get_int(remminafile, value, default_value) 133 #define GET_PLUGIN_BOOLEAN(value) \ 134 rm_plugin_service->file_get_int(remminafile, value, FALSE) 226 glong l = strtol(s, &end, base);
229 if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
return STR2INT_OVERFLOW;
292 REMMINA_PLUGIN_DEBUG(
"Function entry.");
294 if (!custom_data || !custom_data->
gp || !custom_data->
dialog_data) {
295 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
296 _(
"Internal error: %s"),
297 _(
"Parameter 'custom_data' is not initialized!")
300 return G_SOURCE_REMOVE;
309 if (!ddata->title || !ddata->message) {
310 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Broken `DialogData`! Aborting…"));
311 return G_SOURCE_REMOVE;
314 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Can't retrieve `DialogData`! Aborting…"));
315 return G_SOURCE_REMOVE;
318 REMMINA_PLUGIN_DEBUG(
"`DialogData` checks passed. Now showing dialog…");
320 GtkWidget* widget_gtk_dialog = NULL;
322 if (ddata->dialog_factory_func != NULL) {
323 REMMINA_PLUGIN_DEBUG(
"Calling *custom* dialog factory function…");
324 GCallback dialog_factory_func = G_CALLBACK(ddata->dialog_factory_func);
325 gpointer dialog_factory_data = ddata->dialog_factory_data;
329 dialog_factory_func)(custom_data, dialog_factory_data);
331 widget_gtk_dialog = gtk_message_dialog_new(ddata->parent,
337 gtk_message_dialog_format_secondary_text(
338 GTK_MESSAGE_DIALOG(widget_gtk_dialog),
"%s", ddata->message);
341 if (!widget_gtk_dialog) {
342 REMMINA_PLUGIN_CRITICAL(
"Error! Aborting.");
343 return G_SOURCE_REMOVE;
346 if (ddata->callbackfunc) {
347 g_signal_connect_swapped(G_OBJECT(widget_gtk_dialog),
"response",
348 G_CALLBACK(ddata->callbackfunc),
351 g_signal_connect(G_OBJECT(widget_gtk_dialog),
"response",
352 G_CALLBACK(gtk_widget_destroy),
356 gtk_widget_show_all(widget_gtk_dialog);
359 g_object_set_data(G_OBJECT(gp),
"dialog-data", NULL);
361 return G_SOURCE_REMOVE;
384 const gchar* parent_name = gtk_widget_get_name((GtkWidget*) parent);
385 if (g_ascii_strcasecmp(parent_name, (gchar*) name) == 0) {
389 if (GTK_IS_BIN(parent)) {
390 GtkWidget *child = gtk_bin_get_child(GTK_BIN(parent));
394 if (GTK_IS_CONTAINER(parent)) {
395 GList *children = gtk_container_get_children(GTK_CONTAINER(parent));
396 while (children != NULL) {
398 if (widget != NULL) {
402 children = g_list_next(children);
421 GtkTreeViewColumn *column,
424 REMMINA_PLUGIN_DEBUG(
"Function entry.");
426 if (!custom_data || !custom_data->
gp || !custom_data->
opt1) {
427 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
428 _(
"Internal error: %s"),
429 _(
"Parameter 'custom_data' is not initialized!")
432 return G_SOURCE_REMOVE;
438 GtkWidget* dialog = GTK_WIDGET(custom_data->
opt1);
442 GtkTreeModel *model = gtk_tree_view_get_model(treeview);
444 if (gtk_tree_model_get_iter(model, &iter, path)) {
445 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
449 if (!session_id || strlen(session_id) <= 0)
return G_SOURCE_REMOVE;
451 SET_RESUME_SESSION(gp, session_id);
456 SET_SESSION_SELECTED(gp, (gpointer) TRUE);
457 gtk_widget_hide(GTK_WIDGET(dialog));
458 gtk_widget_destroy(GTK_WIDGET(dialog));
461 return G_SOURCE_REMOVE;
472 gchar* return_char = NULL;
474 switch (session_property) {
510 GList *sessions_list)
512 REMMINA_PLUGIN_DEBUG(
"Function entry.");
514 if (!custom_data || !custom_data->
gp ||
516 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
517 _(
"Internal error: %s"),
518 _(
"Parameter 'custom_data' is not initialized!")
526 if (!ddata || !sessions_list || !ddata->
title) {
527 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Could not retrieve valid `DialogData` or " 528 "`sessions_list`! Aborting…"));
532 GtkWidget *widget_gtk_dialog = NULL;
533 widget_gtk_dialog = gtk_dialog_new_with_buttons(ddata->
title, ddata->
parent,
545 GtkWidget *button = gtk_dialog_get_widget_for_response(
546 GTK_DIALOG(widget_gtk_dialog),
550 gtk_widget_set_tooltip_text(button, _(
"Terminating X2Go sessions can take a moment."));
552 #define DEFAULT_DIALOG_WIDTH 720 553 #define DEFAULT_DIALOG_HEIGHT (DEFAULT_DIALOG_WIDTH * 9) / 16 555 gtk_widget_set_size_request(GTK_WIDGET(widget_gtk_dialog),
556 DEFAULT_DIALOG_WIDTH, DEFAULT_DIALOG_HEIGHT);
557 gtk_window_set_default_size(GTK_WINDOW(widget_gtk_dialog),
558 DEFAULT_DIALOG_WIDTH, DEFAULT_DIALOG_HEIGHT);
560 gtk_window_set_resizable(GTK_WINDOW(widget_gtk_dialog), TRUE);
562 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
565 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(
566 GTK_DIALOG(widget_gtk_dialog))
567 ), GTK_WIDGET(scrolled_window), TRUE, TRUE, 5);
569 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled_window),
570 GTK_POLICY_AUTOMATIC,
571 GTK_POLICY_AUTOMATIC);
583 types[i] = G_TYPE_BOOLEAN;
585 types[i] = G_TYPE_STRING;
590 GtkListStore *store = gtk_list_store_newv(SESSION_NUM_PROPERTIES, types);
592 GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER(
593 gtk_tree_model_filter_new(GTK_TREE_MODEL(store),
598 GtkWidget *tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter));
599 g_object_unref (G_OBJECT (store));
600 gtk_widget_set_size_request(tree_view, -1, 300);
603 gtk_widget_set_name(GTK_WIDGET(tree_view),
"session_chooser_treeview");
606 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), TRUE);
607 gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(tree_view), FALSE);
608 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree_view), TRUE);
609 gtk_widget_show (tree_view);
610 gtk_container_add (GTK_CONTAINER(scrolled_window), tree_view);
612 GtkTreeViewColumn *tree_view_col = NULL;
613 GtkCellRenderer *cell_renderer = NULL;
614 gchar *header_title = NULL;
623 REMMINA_PLUGIN_WARNING(
"%s", g_strdup_printf(
624 _(
"Internal error: %s"), g_strdup_printf(
625 _(
"Unknown property '%i'"), i
627 header_title = g_strdup_printf(_(
"Unknown property '%i'"), i);
630 tree_view_col = gtk_tree_view_column_new();
631 gtk_tree_view_column_set_title(tree_view_col, header_title);
632 gtk_tree_view_column_set_clickable(tree_view_col, FALSE);
633 gtk_tree_view_column_set_sizing (tree_view_col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
634 gtk_tree_view_column_set_resizable(tree_view_col, TRUE);
636 cell_renderer = gtk_cell_renderer_text_new();
637 gtk_tree_view_column_pack_start(tree_view_col, cell_renderer, TRUE);
638 gtk_tree_view_column_add_attribute(tree_view_col, cell_renderer,
"text", i);
639 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), tree_view_col);
645 for (elem = sessions_list; elem; elem = elem->next) {
646 gchar** session = (gchar**) elem->data;
647 g_assert(session != NULL);
649 gtk_list_store_append(store, &iter);
652 gchar*
property = session[i];
653 GValue a = G_VALUE_INIT;
658 g_value_init(&a, G_TYPE_BOOLEAN);
659 g_assert(G_VALUE_HOLDS_BOOLEAN(&a) &&
"GValue does not " 662 g_value_set_boolean(&a, TRUE);
664 g_value_init(&a, G_TYPE_STRING);
665 g_assert(G_VALUE_HOLDS_STRING(&a) &&
"GValue does not " 667 g_value_set_static_string (&a, property);
670 gtk_list_store_set_value(store, &iter, i, &a);
681 custom_data->
opt1 = widget_gtk_dialog;
683 g_signal_connect(tree_view,
"row-activated",
687 return widget_gtk_dialog;
703 GtkTreeView* treeview)
706 GtkTreeModel *return_model = NULL;
708 if (!treeview && dialog) {
710 "session_chooser_treeview");
713 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
714 _(
"Internal error: %s"),
715 _(
"Could not find child GtkTreeView of " 716 "session chooser dialog.")
721 return_model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview_new));
722 }
else if (treeview) {
723 return_model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
725 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
726 _(
"Internal error: %s"),
727 _(
"Neither the 'dialog' nor 'treeview' parameters are initialized! " 728 "At least one of them must be given.")
733 if (!return_model || !GTK_TREE_MODEL_FILTER(return_model)) {
734 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
735 _(
"Internal error: %s"),
736 _(
"Could not obtain \"GtkTreeModelFilter*\" of the session chooser dialog, " 737 "for unknown reason.")
741 return GTK_TREE_MODEL_FILTER(return_model);
755 REMMINA_PLUGIN_DEBUG(
"Function entry.");
758 "session_chooser_treeview");
760 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
761 _(
"Internal error: %s"),
762 _(
"Could not find child GtkTreeView of session chooser dialog.")
767 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
769 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
770 _(
"Internal error: %s"),
771 _(
"Could not get currently selected row (session)!")
777 NULL, GTK_TREE_VIEW(treeview));
778 GtkTreeModel *model = gtk_tree_model_filter_get_model(filter);
779 if (!model)
return NULL;
781 GtkTreeModel *filter_model = GTK_TREE_MODEL(filter);
782 g_assert(filter_model &&
"Could not cast 'filter' to a GtkTreeModel!");
783 GList *selected_rows = gtk_tree_selection_get_selected_rows(selection, &filter_model);
786 gint selected_rows_num = gtk_tree_selection_count_selected_rows(selection);
787 if (selected_rows_num != 1) {
788 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
789 _(
"Internal error: %s"), g_strdup_printf(
790 _(
"Exactly one session should be selectable but '%i' rows " 791 "(sessions) are selected."),
799 GtkTreePath *path = selected_rows->data;
802 path = gtk_tree_model_filter_convert_child_path_to_path(filter, path);
823 GValue ret_value = G_VALUE_INIT;
827 if (!selected_row)
return ret_value;
832 GtkTreeModel *model = gtk_tree_model_filter_get_model(filter);
833 if (!model)
return ret_value;
836 gboolean success = gtk_tree_model_get_iter(model, &iter, row);
838 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
839 _(
"Internal error: %s"),
840 _(
"Failed to fill 'GtkTreeIter'.")
846 GValue
property = G_VALUE_INIT;
847 gtk_tree_model_get_value(model, &iter, property_index, &property);
899 GError** error, gchar** env)
901 REMMINA_PLUGIN_DEBUG(
"Function entry.");
904 gchar* errmsg = g_strdup_printf(
905 _(
"Internal error: %s"),
906 _(
"parameter 'argv' is 'NULL'.")
908 REMMINA_PLUGIN_CRITICAL(
"%s", errmsg);
909 g_set_error(error, 1, 1,
"%s", errmsg);
915 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
916 _(
"Internal error: %s"),
917 _(
"parameter 'error' is 'NULL'.")
922 if (!env || !env[0]) {
923 gchar* errmsg = g_strdup_printf(
924 _(
"Internal error: %s"),
925 _(
"parameter 'env' is either invalid or uninitialized.")
927 REMMINA_PLUGIN_CRITICAL(
"%s", errmsg);
928 g_set_error(error, 1, 1,
"%s", errmsg);
937 gboolean success_ret = g_spawn_sync(NULL, argv, env, G_SPAWN_SEARCH_PATH, NULL,
938 NULL, &standard_out, &standard_err,
941 REMMINA_PLUGIN_INFO(
"%s", _(
"Started PyHoca-CLI with the following arguments:"));
943 for (gint i = 0; i < argc - 1; i++) {
944 gchar* curr_arg = argv[i];
946 if (g_str_equal(curr_arg,
"--password") ||
947 g_str_equal(curr_arg,
"--ssh-passphrase")) {
948 g_printf(
"%s ", curr_arg);
954 g_printf(
"%s ", curr_arg);
967 if (standard_err && strlen(standard_err) > 0) {
968 if (g_str_has_prefix(standard_err,
"pyhoca-cli: error: a socket error " 969 "occured while establishing the connection:")) {
971 gchar* errmsg = g_strdup_printf(
972 _(
"The necessary PyHoca-CLI process has encountered a " 973 "internet connection problem.")
977 REMMINA_PLUGIN_CRITICAL(
"%s:\n%s", errmsg, standard_err);
978 g_set_error(error, 1, 1,
"%s", errmsg);
981 gchar* errmsg = g_strdup_printf(
986 REMMINA_PLUGIN_CRITICAL(
"%s", errmsg);
987 g_set_error(error, 1, 1,
"%s", errmsg);
990 }
else if (!success_ret || (*error) || strlen(standard_out) <= 0 || exit_code) {
992 gchar* errmsg = g_strdup_printf(
993 _(
"An unknown error occured while trying " 994 "to start PyHoca-CLI. Exit code: %i"),
996 REMMINA_PLUGIN_WARNING(
"%s", errmsg);
997 g_set_error(error, 1, 1,
"%s", errmsg);
999 gchar* errmsg = g_strdup_printf(
1000 _(
"An unknown error occured while trying to start " 1001 "PyHoca-CLI. Exit code: %i. Error: '%s'"),
1002 exit_code, (*error)->message);
1003 REMMINA_PLUGIN_WARNING(
"%s", errmsg);
1009 return standard_out;
1038 GtkDialog *dialog) {
1039 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1041 if (!path || !dialog) {
1042 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
1043 _(
"Internal error: %s"),
1044 _(
"Neither the 'path' nor 'dialog' parameters are initialized.")
1050 GTK_WIDGET(dialog), NULL);
1051 GtkTreeModel *model = gtk_tree_model_filter_get_model(filter);
1054 if (!model)
return FALSE;
1057 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path)) {
1058 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
1059 _(
"Internal error: %s"),
1060 _(
"GtkTreePath 'path' describes a non-existing row!")
1067 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1071 gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
1081 GtkWidget *term_button = gtk_dialog_get_widget_for_response(
1084 GtkWidget *resume_button = gtk_dialog_get_widget_for_response(
1089 gint rows_amount = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter), NULL);
1090 if (rows_amount <= 0) {
1091 gtk_widget_set_sensitive(term_button, FALSE);
1092 gtk_widget_set_sensitive(resume_button, FALSE);
1094 gtk_widget_set_sensitive(term_button, TRUE);
1095 gtk_widget_set_sensitive(resume_button, TRUE);
1104 if (!connect_data ||
1105 !connect_data->
host ||
1107 strlen(connect_data->
host) <= 0 ||
1108 strlen(connect_data->
username) <= 0)
1110 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
1111 _(
"Internal error: %s"),
1112 _(
"'Invalid connection data.'")
1120 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
1121 _(
"Internal error: %s"),
1122 _(
"'Invalid connection data.'")
1147 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1149 if (!custom_data || !custom_data->
gp ||
1151 !custom_data->
opt1 || !custom_data->
opt2) {
1152 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
1153 _(
"Internal error: %s"),
1154 _(
"Parameter 'custom_data' is not fully initialized!")
1157 return G_SOURCE_REMOVE;
1164 GtkTreePath* selected_row = (GtkTreePath*) custom_data->
opt1;
1165 GtkDialog *dialog = GTK_DIALOG(custom_data->
opt2);
1183 host = connect_data->
host;
1186 return G_SOURCE_REMOVE;
1193 if (!G_VALUE_HOLDS_STRING(&value))
return G_SOURCE_REMOVE;
1194 const gchar *session_id = g_value_get_string(&value);
1201 argv[argc++] = g_strdup(
"pyhoca-cli");
1203 argv[argc++] = g_strdup(
"--server");
1204 argv[argc++] = g_strdup_printf(
"%s", host);
1206 if (FEATURE_AVAILABLE(gpdata,
"USERNAME")) {
1207 argv[argc++] = g_strdup(
"-u");
1209 argv[argc++] = g_strdup_printf(
"%s", username);
1211 argv[argc++] = g_strdup_printf(
"%s", g_get_user_name());
1214 REMMINA_PLUGIN_CRITICAL(
"%s", FEATURE_NOT_AVAIL_STR(
"USERNAME"));
1215 return G_SOURCE_REMOVE;
1218 if (password && FEATURE_AVAILABLE(gpdata,
"PASSWORD")) {
1219 if (FEATURE_AVAILABLE(gpdata,
"AUTH_ATTEMPTS")) {
1220 argv[argc++] = g_strdup(
"--auth-attempts");
1221 argv[argc++] = g_strdup_printf (
"%i", 0);
1223 REMMINA_PLUGIN_WARNING(
"%s", FEATURE_NOT_AVAIL_STR(
"AUTH_ATTEMPTS"));
1225 if (strlen(password) > 0) {
1226 argv[argc++] = g_strdup(
"--force-password");
1227 argv[argc++] = g_strdup(
"--password");
1228 argv[argc++] = g_strdup_printf(
"%s", password);
1230 }
else if (!password) {
1231 REMMINA_PLUGIN_CRITICAL(
"%s", FEATURE_NOT_AVAIL_STR(
"PASSWORD"));
1232 return G_SOURCE_REMOVE;
1235 if (FEATURE_AVAILABLE(gpdata,
"TERMINATE")) {
1236 argv[argc++] = g_strdup(
"--terminate");
1237 argv[argc++] = g_strdup_printf(
"%s", session_id);
1239 REMMINA_PLUGIN_CRITICAL(
"%s", FEATURE_NOT_AVAIL_STR(
"TERMINATE"));
1240 return G_SOURCE_REMOVE;
1243 if (FEATURE_AVAILABLE(gpdata,
"NON_INTERACTIVE")) {
1244 argv[argc++] = g_strdup(
"--non-interactive");
1246 REMMINA_PLUGIN_WARNING(
"%s", FEATURE_NOT_AVAIL_STR(
"NON_INTERACTIVE"));
1249 if (FEATURE_AVAILABLE(gpdata,
"SSH_PRIVKEY")) {
1250 if (ssh_privatekey && !g_str_equal(ssh_privatekey,
"")) {
1251 argv[argc++] = g_strdup(
"--ssh-privkey");
1252 argv[argc++] = g_strdup_printf(
"%s", ssh_privatekey);
1254 if (ssh_passphrase && !g_str_equal(ssh_passphrase,
"")) {
1255 if (FEATURE_AVAILABLE(gpdata,
"SSH_PASSPHRASE")) {
1256 argv[argc++] = g_strdup(
"--ssh-passphrase");
1257 argv[argc++] = g_strdup_printf(
"%s", ssh_passphrase);
1259 REMMINA_PLUGIN_MESSAGE(
"%s", FEATURE_NOT_AVAIL_STR(
"SSH_PASSPHRASE"));
1264 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"SSH_PRIVKEY"));
1267 argv[argc++] = NULL;
1269 GError* error = NULL;
1270 gchar** envp = g_get_environ();
1275 gchar *err_msg = g_strdup_printf(
1276 _(
"Could not terminate X2Go session '%s':\n%s"),
1281 REMMINA_PLUGIN_CRITICAL(
"%s", err_msg);
1284 err_ddata->
parent = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(dialog)));
1285 err_ddata->
flags = GTK_DIALOG_MODAL;
1286 err_ddata->
type = GTK_MESSAGE_ERROR;
1287 err_ddata->
buttons = GTK_BUTTONS_OK;
1288 err_ddata->
title = _(
"An error occured.");
1300 custom_data->
gp = custom_data->
gp;
1303 custom_data->
opt1 = NULL;
1304 custom_data->
opt2 = NULL;
1318 return G_SOURCE_REMOVE;
1322 return G_SOURCE_REMOVE;
1343 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1345 if (!custom_data || !custom_data->
gp || !custom_data->
dialog_data ||
1347 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
1348 _(
"Internal error: %s"),
1349 _(
"Parameter 'custom_data' is not initialized!")
1352 return G_SOURCE_REMOVE;
1359 REMMINA_PLUGIN_DEBUG(
"The user explicitly requested a new session. " 1360 "Creating a new session…");
1361 SET_RESUME_SESSION(gp, NULL);
1366 SET_SESSION_SELECTED(gp, (gpointer) TRUE);
1368 gtk_widget_destroy(GTK_WIDGET(
self));
1370 return G_SOURCE_REMOVE;
1381 if (!G_VALUE_HOLDS_STRING(&value))
return G_SOURCE_REMOVE;
1383 gchar *session_id = (gchar*) g_value_get_string(&value);
1386 if (!session_id || strlen(session_id) <= 0) {
1387 REMMINA_PLUGIN_DEBUG(
1389 _(
"Could not get session ID from session chooser dialog.")
1391 SET_RESUME_SESSION(gp, NULL);
1393 SET_RESUME_SESSION(gp, session_id);
1395 REMMINA_PLUGIN_MESSAGE(
"%s", g_strdup_printf(
1396 _(
"Resuming session: '%s'"),
1401 if (!session_id || strlen(session_id) <= 0) {
1402 REMMINA_PLUGIN_DEBUG(
1404 _(
"Could not get session ID from session chooser dialog.")
1406 SET_RESUME_SESSION(gp, NULL);
1408 SET_RESUME_SESSION(gp, session_id);
1410 REMMINA_PLUGIN_MESSAGE(
"%s", g_strdup_printf(
1411 _(
"Terminating session: '%s'"),
1419 if (!path)
return G_SOURCE_REMOVE;
1424 return G_SOURCE_REMOVE;
1435 custom_data->
opt1 = path;
1436 custom_data->
opt2 =
self;
1439 g_thread_new(
"terminate-session-thread",
1444 return G_SOURCE_CONTINUE;
1446 REMMINA_PLUGIN_DEBUG(
"User clicked dialog away. " 1447 "Creating a new session then.");
1448 SET_RESUME_SESSION(gp, NULL);
1454 SET_SESSION_SELECTED(gp, (gpointer) TRUE);
1456 gtk_widget_destroy(GTK_WIDGET(
self));
1458 return G_SOURCE_REMOVE;
1461 #define RMPLUGIN_X2GO_FEATURE_GTKSOCKET 1 1475 enum { FUNC_GTK_SOCKET_ADD_ID } func;
1488 TRACE_CALL(__func__);
1491 case FUNC_GTK_SOCKET_ADD_ID:
1492 gtk_socket_add_id(d->
sk, d->
w);
1495 pthread_mutex_unlock(&d->
mu);
1500 return G_SOURCE_REMOVE;
1506 TRACE_CALL(__func__);
1513 TRACE_CALL(__func__);
1516 pthread_mutex_init(&d->
mu, NULL);
1517 pthread_mutex_lock(&d->
mu);
1520 pthread_mutex_lock(&d->mu);
1522 pthread_cleanup_pop(0);
1523 pthread_mutex_unlock(&d->mu);
1524 pthread_mutex_destroy(&d->mu);
1529 TRACE_CALL(__func__);
1546 gboolean already_seen = FALSE;
1551 already_seen = TRUE;
1552 REMMINA_PLUGIN_DEBUG(
"Window of X2Go Agent with ID [0x%lx] seen already.",
1560 REMMINA_PLUGIN_DEBUG(
"Forgetting about window of X2Go Agent with ID [0x%lx]…",
1574 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1585 REMMINA_PLUGIN_AUDIT(_(
"Disconnected from %s:%d via X2Go"), server, port);
1586 g_free(server), server = NULL;
1589 if (gpdata == NULL) {
1590 REMMINA_PLUGIN_DEBUG(
"Exiting since gpdata is already 'NULL'…");
1591 return G_SOURCE_REMOVE;
1595 pthread_cancel(gpdata->
thread);
1596 if (gpdata->
thread) pthread_join(gpdata->
thread, NULL);
1604 kill(gpdata->
pidx2go, SIGTERM);
1605 g_spawn_close_pid(gpdata->
pidx2go);
1611 XCloseDisplay(gpdata->
display);
1615 g_object_steal_data(G_OBJECT(gp),
"plugin-data");
1618 return G_SOURCE_REMOVE;
1623 TRACE_CALL(__func__);
1626 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1629 REMMINA_PLUGIN_DEBUG(
"Doing nothing since the plugin is already disconnected.");
1630 return G_SOURCE_REMOVE;
1636 return G_SOURCE_CONTINUE;
1643 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1647 REMMINA_PLUGIN_DEBUG(
"Doing nothing as the disconnection " 1648 "has already been handled.");
1653 REMMINA_PLUGIN_DEBUG(
"Doing nothing since pyhoca-cli was expected to stop.");
1657 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"PyHoca-CLI exited unexpectedly. " 1658 "This connection will now be closed."));
1661 ddata->
parent = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(gp)));
1662 ddata->
flags = GTK_DIALOG_MODAL;
1663 ddata->
type = GTK_MESSAGE_ERROR;
1664 ddata->
buttons = GTK_BUTTONS_OK;
1665 ddata->
title = _(
"An error occured.");
1666 ddata->
message = _(
"The necessary child process 'pyhoca-cli' stopped unexpectedly.\n" 1667 "Please check your profile settings and PyHoca-CLI's output for " 1668 "possible errors. Also ensure the remote server is " 1669 "reachable and you're using the right credentials.");
1681 g_assert(custom_data &&
"custom_data could not be initialized.");
1683 custom_data->
gp = gp;
1686 custom_data->
opt1 = NULL;
1691 usleep(1000 * 1000);
1701 gchar* s_username, gchar* s_password,
1707 if (s_password && s_username) {
1708 if (g_strcmp0(s_username,
"") == 0) {
1709 g_strlcpy(errmsg, _(
"Can't save empty username!"), 512);
1721 g_strlcpy(errmsg, g_strdup_printf(
1722 _(
"Internal error: %s"),
1723 _(
"Could not save new credentials.")
1726 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Could not save " 1727 "new credentials: 's_password' or " 1728 "'s_username' strings were not set."));
1747 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1749 g_assert(errmsg != NULL);
1750 g_assert(gp != NULL);
1752 if ((*passphrase) == NULL) {
1754 (*passphrase) = g_strdup(
"");
1758 gp, 0, _(
"Enter password to unlock the SSH key:"),
1759 NULL, *passphrase, NULL, NULL
1762 if (ret == GTK_RESPONSE_OK) {
1765 (*passphrase) = g_strdup(s_passphrase);
1766 g_free(s_passphrase);
1769 g_strlcpy(errmsg, _(
"Password input cancelled. Aborting…"), 512);
1787 gchar** default_username, gchar** default_password)
1789 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1791 g_assert(errmsg != NULL);
1792 g_assert(gp != NULL);
1793 g_assert(default_username != NULL);
1794 g_assert(default_password != NULL);
1798 if ((*default_username) == NULL) {
1799 gchar* l_errmsg = g_strdup_printf(
1800 _(
"Tip: Check the 'Save password' checkbox or manually input your " 1801 "X2Go username and password in the profile settings to store " 1802 "them for faster logins.")
1804 REMMINA_PLUGIN_MESSAGE(
"%s", l_errmsg);
1805 (*default_username) = g_strdup(
"");
1811 if ((*default_password) == NULL) {
1812 (*default_password) = g_strdup(
"");
1815 gchar *s_username, *s_password;
1818 gboolean disable_password_storing;
1823 disable_password_storing = rm_plugin_service->
file_get_int(
1824 remminafile,
"disablepasswordstoring", FALSE
1828 gp, (disable_password_storing ? 0 :
1831 _(
"Enter X2Go credentials"),
1832 (*default_username), (*default_password), NULL, NULL
1835 if (ret == GTK_RESPONSE_OK) {
1840 remminafile,
"password", s_password
1847 s_password, errmsg)) {
1852 (*default_username) = g_strdup(s_username);
1856 (*default_password) = g_strdup(s_password);
1860 g_strlcpy(errmsg, _(
"Authentication cancelled. Aborting…"), 512);
1881 REMMINA_PLUGIN_DEBUG(
"Function entry.");
1885 gchar *username = NULL;
1886 gchar *password = NULL;
1887 gchar *ssh_privatekey = NULL;
1888 gchar *ssh_passphrase = NULL;
1901 host = connect_data->
host;
1904 return G_SOURCE_REMOVE;
1912 argv[argc++] = g_strdup(
"pyhoca-cli");
1913 argv[argc++] = g_strdup(
"--list-sessions");
1915 argv[argc++] = g_strdup(
"--server");
1916 argv[argc++] = g_strdup_printf(
"%s", host);
1918 if (FEATURE_AVAILABLE(gpdata,
"USERNAME")) {
1919 argv[argc++] = g_strdup(
"-u");
1921 argv[argc++] = g_strdup_printf(
"%s", username);
1923 argv[argc++] = g_strdup_printf(
"%s", g_get_user_name());
1926 g_set_error(error, 1, 1,
"%s", FEATURE_NOT_AVAIL_STR(
"USERNAME"));
1927 REMMINA_PLUGIN_CRITICAL(
"%s", FEATURE_NOT_AVAIL_STR(
"USERNAME"));
1931 if (FEATURE_AVAILABLE(gpdata,
"NON_INTERACTIVE")) {
1932 argv[argc++] = g_strdup(
"--non-interactive");
1934 REMMINA_PLUGIN_WARNING(
"%s", FEATURE_NOT_AVAIL_STR(
"NON_INTERACTIVE"));
1937 if (password && FEATURE_AVAILABLE(gpdata,
"PASSWORD")) {
1938 if (FEATURE_AVAILABLE(gpdata,
"AUTH_ATTEMPTS")) {
1939 argv[argc++] = g_strdup(
"--auth-attempts");
1940 argv[argc++] = g_strdup_printf (
"%i", 0);
1942 REMMINA_PLUGIN_WARNING(
"%s", FEATURE_NOT_AVAIL_STR(
"AUTH_ATTEMPTS"));
1944 if (strlen(password) > 0) {
1945 argv[argc++] = g_strdup(
"--force-password");
1946 argv[argc++] = g_strdup(
"--password");
1947 argv[argc++] = g_strdup_printf(
"%s", password);
1949 }
else if (!password) {
1950 g_set_error(error, 1, 1,
"%s", FEATURE_NOT_AVAIL_STR(
"PASSWORD"));
1951 REMMINA_PLUGIN_CRITICAL(
"%s", FEATURE_NOT_AVAIL_STR(
"PASSWORD"));
1957 if (FEATURE_AVAILABLE(gpdata,
"QUIET")) {
1958 argv[argc++] = g_strdup(
"--quiet");
1961 if (FEATURE_AVAILABLE(gpdata,
"SSH_PRIVKEY")) {
1962 if (ssh_privatekey && !g_str_equal(ssh_privatekey,
"")) {
1963 argv[argc++] = g_strdup(
"--ssh-privkey");
1964 argv[argc++] = g_strdup_printf(
"%s", ssh_privatekey);
1966 if (ssh_passphrase && !g_str_equal(ssh_passphrase,
"")) {
1967 if (FEATURE_AVAILABLE(gpdata,
"SSH_PASSPHRASE")) {
1968 argv[argc++] = g_strdup(
"--ssh-passphrase");
1969 argv[argc++] = g_strdup_printf(
"%s", ssh_passphrase);
1971 REMMINA_PLUGIN_MESSAGE(
"%s", FEATURE_NOT_AVAIL_STR(
"SSH_PASSPHRASE"));
1976 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"SSH_PRIVKEY"));
1980 argv[argc++] = NULL;
1983 gchar** envp = g_get_environ();
1984 gchar* envp_splitted = g_strjoinv(
";", envp);
1985 envp_splitted = g_strconcat(envp_splitted,
";LANG=C", (
void*) NULL);
1986 envp = g_strsplit(envp_splitted,
";", 0);
2000 if (!std_out || *error) {
2004 g_assert((*error) != NULL);
2030 REMMINA_PLUGIN_DEBUG(
"Function entry.");
2032 gchar *pyhoca_output = NULL;
2035 if (!pyhoca_output || *error) {
2039 g_assert((*error) != NULL);
2044 gchar **lines_list = g_strsplit(pyhoca_output,
"\n", -1);
2046 if (lines_list == NULL || lines_list[0] == NULL || lines_list[1] == NULL) {
2047 g_set_error(error, 1, 1,
"%s", _(
"Could not parse the output of PyHoca-CLI's " 2048 "--list-sessions option. Creating a new " 2053 gboolean found_session = FALSE;
2054 GList* sessions = NULL;
2055 gchar** session = NULL;
2057 for (guint i = 0; lines_list[i] != NULL; i++) {
2058 gchar* current_line = lines_list[i];
2064 if (!g_str_has_prefix(current_line,
"Session Name: ") && !found_session) {
2070 if (g_str_has_prefix(current_line,
"Session Name: ")) {
2071 gchar* session_id = NULL;
2072 gchar** line_list = g_strsplit(current_line,
": ", 0);
2074 if (line_list == NULL ||
2075 line_list[0] == NULL ||
2076 line_list[1] == NULL ||
2077 strlen(line_list[0]) <= 0 ||
2078 strlen(line_list[1]) <= 0)
2080 found_session = FALSE;
2086 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Could not allocate " 2090 sessions = g_list_append(sessions, session);
2092 session_id = line_list[1];
2095 REMMINA_PLUGIN_INFO(
"%s", g_strdup_printf(
2096 _(
"Found already existing X2Go session with ID: '%s'"),
2100 found_session = TRUE;
2104 if (!found_session) {
2108 if (g_strcmp0(current_line,
"-------------") == 0) {
2112 gchar* value = NULL;
2113 gchar** line_list = g_strsplit(current_line,
": ", 0);
2115 if (line_list == NULL ||
2116 line_list[0] == NULL ||
2117 line_list[1] == NULL ||
2118 strlen(line_list[0]) <= 0 ||
2119 strlen(line_list[1]) <= 0)
2122 found_session = FALSE;
2125 value = line_list[1];
2127 if (g_str_has_prefix(current_line,
"cookie: ")) {
2128 REMMINA_PLUGIN_DEBUG(
"cookie:\t'%s'", value);
2130 }
else if (g_str_has_prefix(current_line,
"agent PID: ")) {
2131 REMMINA_PLUGIN_DEBUG(
"agent PID:\t'%s'", value);
2133 }
else if (g_str_has_prefix(current_line,
"display: ")) {
2134 REMMINA_PLUGIN_DEBUG(
"display:\t'%s'", value);
2136 }
else if (g_str_has_prefix(current_line,
"status: ")) {
2137 if (g_strcmp0(value,
"S") == 0) {
2139 value = _(
"Suspended");
2140 }
else if (g_strcmp0(value,
"R") == 0) {
2142 value = _(
"Running");
2143 }
else if (g_strcmp0(value,
"T") == 0) {
2145 value = _(
"Terminated");
2147 REMMINA_PLUGIN_DEBUG(
"status:\t'%s'", value);
2149 }
else if (g_str_has_prefix(current_line,
"graphic port: ")) {
2150 REMMINA_PLUGIN_DEBUG(
"graphic port:\t'%s'", value);
2152 }
else if (g_str_has_prefix(current_line,
"snd port: ")) {
2153 REMMINA_PLUGIN_DEBUG(
"snd port:\t'%s'", value);
2155 }
else if (g_str_has_prefix(current_line,
"sshfs port: ")) {
2156 REMMINA_PLUGIN_DEBUG(
"sshfs port:\t'%s'", value);
2158 }
else if (g_str_has_prefix(current_line,
"username: ")) {
2159 REMMINA_PLUGIN_DEBUG(
"username:\t'%s'", value);
2161 }
else if (g_str_has_prefix(current_line,
"hostname: ")) {
2162 REMMINA_PLUGIN_DEBUG(
"hostname:\t'%s'", value);
2164 }
else if (g_str_has_prefix(current_line,
"create date: ")) {
2165 REMMINA_PLUGIN_DEBUG(
"create date:\t'%s'", value);
2167 }
else if (g_str_has_prefix(current_line,
"suspended since: ")) {
2168 REMMINA_PLUGIN_DEBUG(
"suspended since:\t'%s'", value);
2171 REMMINA_PLUGIN_DEBUG(
"Not supported:\t'%s'", value);
2172 found_session = FALSE;
2177 g_set_error(error, 1, 1,
2178 "%s", _(
"Could not find any sessions on remote machine. Creating a new " 2201 if (!connect_data ||
2202 !connect_data->
host ||
2205 strlen(connect_data->
host) <= 0 ||
2206 strlen(connect_data->
username) <= 0)
2209 g_set_error(error, 1, 1,
"%s", g_strdup_printf(
2210 _(
"Internal error: %s"),
2211 _(
"'Invalid connection data.'")
2216 GList *sessions_list = NULL;
2219 if (!sessions_list || *error) {
2223 g_assert(*error != NULL);
2229 ddata->
parent = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(gp)));
2230 ddata->
flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
2233 ddata->
title = _(
"Choose a session to resume:");
2258 g_assert(custom_data &&
"custom_data could not be initialized.");
2260 custom_data->
gp = gp;
2263 custom_data->
opt1 = NULL;
2270 while (!IS_SESSION_SELECTED(gp)) {
2275 if (counter % 10 == 0 || counter == 0) {
2276 REMMINA_PLUGIN_MESSAGE(
"%s", _(
"Waiting for user to select a session…"));
2281 gchar* chosen_resume_session = GET_RESUME_SESSION(gp);
2283 if (!chosen_resume_session || strlen(chosen_resume_session) <= 0) {
2284 g_set_error(error, 1, 1,
"%s", _(
"No session was selected. Creating a new one."));
2288 return chosen_resume_session;
2302 gchar *ssh_privatekey,
2306 TRACE_CALL(__func__);
2314 gchar *ssh_passphrase = NULL;
2316 if (!username || strlen(username) <= 0) {
2325 password = g_strdup(
"");
2328 if (ssh_privatekey && strlen(ssh_privatekey) > 0) {
2345 GError *session_error = NULL;
2349 if (!resume_session_id || session_error || strlen(resume_session_id) <= 0) {
2353 g_assert(session_error != NULL);
2355 REMMINA_PLUGIN_WARNING(
"%s", g_strdup_printf(
2356 _(
"A non-critical error happened: %s"),
2357 session_error->message
2360 REMMINA_PLUGIN_INFO(
"%s", g_strdup_printf(
2361 _(
"User chose to resume session with ID: '%s'"),
2367 argv[argc++] = g_strdup(
"pyhoca-cli");
2369 argv[argc++] = g_strdup(
"--server");
2370 argv[argc++] = g_strdup_printf (
"%s", host);
2372 if (FEATURE_AVAILABLE(gpdata,
"REMOTE_SSH_PORT")) {
2373 argv[argc++] = g_strdup(
"-p");
2374 argv[argc++] = g_strdup_printf (
"%d", sshport);
2376 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"REMOTE_SSH_PORT"));
2379 if (resume_session_id && strlen(resume_session_id) > 0) {
2380 REMMINA_PLUGIN_INFO(
"%s", g_strdup_printf(
2382 _(
"Resuming session '%s'…"),
2386 if (FEATURE_AVAILABLE(gpdata,
"RESUME")) {
2387 argv[argc++] = g_strdup(
"--resume");
2388 argv[argc++] = g_strdup_printf(
"%s", resume_session_id);
2390 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"RESUME"));
2404 if (FEATURE_AVAILABLE(gpdata,
"USERNAME")) {
2405 argv[argc++] = g_strdup(
"-u");
2407 argv[argc++] = g_strdup_printf (
"%s", username);
2409 argv[argc++] = g_strdup_printf (
"%s", g_get_user_name());
2412 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"USERNAME"));
2415 if (password && FEATURE_AVAILABLE(gpdata,
"PASSWORD")) {
2416 if (strlen(password) > 0) {
2417 argv[argc++] = g_strdup(
"--force-password");
2418 argv[argc++] = g_strdup(
"--password");
2419 argv[argc++] = g_strdup_printf (
"%s", password);
2422 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"PASSWORD"));
2425 if (FEATURE_AVAILABLE(gpdata,
"AUTH_ATTEMPTS")) {
2426 argv[argc++] = g_strdup(
"--auth-attempts");
2427 argv[argc++] = g_strdup_printf (
"%i", 0);
2429 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"AUTH_ATTEMPTS"));
2432 if (FEATURE_AVAILABLE(gpdata,
"NON_INTERACTIVE")) {
2433 argv[argc++] = g_strdup(
"--non-interactive");
2435 REMMINA_PLUGIN_WARNING(
"%s", FEATURE_NOT_AVAIL_STR(
"NON_INTERACTIVE"));
2438 if (FEATURE_AVAILABLE(gpdata,
"COMMAND")) {
2439 argv[argc++] = g_strdup(
"-c");
2443 argv[argc++] = g_strdup(command);
2445 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"COMMAND"));
2448 if (FEATURE_AVAILABLE(gpdata,
"KBD_LAYOUT")) {
2450 argv[argc++] = g_strdup(
"--kbd-layout");
2451 argv[argc++] = g_strdup_printf (
"%s", kbdlayout);
2453 argv[argc++] = g_strdup(
"--kbd-layout");
2454 argv[argc++] = g_strdup(
"auto");
2457 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"KBD_LAYOUT"));
2460 if (FEATURE_AVAILABLE(gpdata,
"KBD_TYPE")) {
2462 argv[argc++] = g_strdup(
"--kbd-type");
2463 argv[argc++] = g_strdup_printf (
"%s", kbdtype);
2465 argv[argc++] = g_strdup(
"--kbd-type");
2466 argv[argc++] = g_strdup(
"auto");
2469 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"KBD_TYPE"));
2472 if (FEATURE_AVAILABLE(gpdata,
"GEOMETRY")) {
2474 resolution =
"800x600";
2475 argv[argc++] = g_strdup(
"-g");
2476 argv[argc++] = g_strdup_printf (
"%s", resolution);
2478 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"GEOMETRY"));
2481 if (FEATURE_AVAILABLE(gpdata,
"TERMINATE_ON_CTRL_C")) {
2482 argv[argc++] = g_strdup(
"--terminate-on-ctrl-c");
2484 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"TERMINATE_ON_CTRL_C"));
2487 if (FEATURE_AVAILABLE(gpdata,
"SOUND")) {
2489 argv[argc++] = g_strdup(
"--sound");
2490 argv[argc++] = g_strdup_printf (
"%s", audio);
2492 argv[argc++] = g_strdup(
"--sound");
2493 argv[argc++] = g_strdup(
"none");
2496 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"SOUND"));
2499 if (FEATURE_AVAILABLE(gpdata,
"CLIPBOARD_MODE")) {
2501 argv[argc++] = g_strdup(
"--clipboard-mode");
2502 argv[argc++] = g_strdup_printf(
"%s", clipboard);
2505 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"CLIPBOARD_MODE"));
2508 if (FEATURE_AVAILABLE(gpdata,
"DPI")) {
2512 if (dpi < 20 || dpi > 400) {
2513 g_strlcpy(errmsg, _(
"DPI setting is out of bounds. Please adjust " 2514 "it in profile settings."), 512);
2519 argv[argc++] = g_strdup(
"--dpi");
2520 argv[argc++] = g_strdup_printf (
"%i", dpi);
2522 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"DPI"));
2525 if (FEATURE_AVAILABLE(gpdata,
"SSH_PRIVKEY")) {
2526 if (ssh_privatekey && !g_str_equal(ssh_privatekey,
"")) {
2527 argv[argc++] = g_strdup(
"--ssh-privkey");
2528 argv[argc++] = g_strdup_printf(
"%s", ssh_privatekey);
2530 if (ssh_passphrase && !g_str_equal(ssh_passphrase,
"")) {
2531 if (FEATURE_AVAILABLE(gpdata,
"SSH_PASSPHRASE")) {
2532 argv[argc++] = g_strdup(
"--ssh-passphrase");
2533 argv[argc++] = g_strdup_printf(
"%s", ssh_passphrase);
2535 REMMINA_PLUGIN_MESSAGE(
"%s", FEATURE_NOT_AVAIL_STR(
"SSH_PASSPHRASE"));
2540 REMMINA_PLUGIN_DEBUG(
"%s", FEATURE_NOT_AVAIL_STR(
"SSH_PRIVKEY"));
2543 argv[argc++] = NULL;
2545 GError *error = NULL;
2546 gchar **envp = g_get_environ();
2547 gboolean success = g_spawn_async_with_pipes (NULL, argv, envp,
2548 (G_SPAWN_DO_NOT_REAP_CHILD |
2549 G_SPAWN_SEARCH_PATH), NULL,
2551 NULL, NULL, NULL, &error);
2553 REMMINA_PLUGIN_INFO(
"%s", _(
"Started PyHoca-CLI with the following arguments:"));
2555 for (gint i = 0; i < argc - 1; i++) {
2556 gchar* curr_arg = argv[i];
2558 if (g_str_equal(curr_arg,
"--password") ||
2559 g_str_equal(curr_arg,
"--ssh-passphrase")) {
2560 g_printf(
"%s ", curr_arg);
2561 g_printf(
"XXXXXX ");
2566 g_printf(
"%s ", curr_arg);
2572 if (!success || error) {
2574 if (!error) error = g_error_new(0, 0, _(
"Internal error."));
2576 gchar *error_title = _(
"Could not start X2Go session…");
2579 ddata->
parent = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(gp)));
2580 ddata->
flags = GTK_DIALOG_MODAL;
2581 ddata->
type = GTK_MESSAGE_ERROR;
2582 ddata->
buttons = GTK_BUTTONS_OK;
2583 ddata->
title = _(
"Could not start X2Go session.");
2584 ddata->
message = g_strdup_printf(_(
"Could not start PyHoca-CLI (%i): '%s'"),
2598 g_assert(custom_data &&
"Could not initialise Custom_data.");
2600 custom_data->
gp = gp;
2603 custom_data->
opt1 = NULL;
2607 g_strlcpy(errmsg, error_title, 512);
2611 g_error_free(error);
2621 ts.tv_nsec = 1 * 1000 * 1000;
2623 while (gpdata->
pidx2go == 0) {
2624 nanosleep(&ts, NULL);
2625 REMMINA_PLUGIN_DEBUG(
"Waiting for PyHoca-CLI to start…");
2628 REMMINA_PLUGIN_DEBUG(
"Watching child 'pyhoca-cli' process now…");
2629 g_child_watch_add(gpdata->
pidx2go,
2641 REMMINA_PLUGIN_DEBUG(
"Function entry.");
2643 #define AMOUNT_FEATURES 43 2644 gchar* features[AMOUNT_FEATURES] = {
2645 "ADD_TO_KNOWN_HOSTS",
"AUTH_ATTEMPTS",
"BROKER_PASSWORD",
"BROKER_URL",
2646 "CLEAN_SESSIONS",
"COMMAND",
"DEBUG",
"FORCE_PASSWORD",
"FORWARD_SSHAGENT",
2647 "GEOMETRY",
"KBD_LAYOUT",
"KBD_TYPE",
"LIBDEBUG",
"LIBDEBUG_SFTPXFER",
"LINK",
2648 "LIST_CLIENT_FEATURES",
"LIST_DESKTOPS",
"LIST_SESSIONS",
"NEW",
"PACK",
2649 "PASSWORD",
"PDFVIEW_CMD",
"PRINTER",
"PRINTING",
"PRINT_ACTION",
"PRINT_CMD",
2650 "QUIET",
"REMOTE_SSH_PORT",
"RESUME",
"SAVE_TO_FOLDER",
"SESSION_PROFILE",
2651 "SESSION_TYPE",
"SHARE_DESKTOP",
"SHARE_LOCAL_FOLDERS",
"SHARE_MODE",
"SOUND",
2652 "SSH_PRIVKEY",
"SUSPEND",
"TERMINATE",
"TERMINATE_ON_CTRL_C",
"TRY_RESUME",
2653 "USERNAME",
"XINERAMA" 2656 GList *features_list = NULL;
2657 for (
int i = 0; i < AMOUNT_FEATURES; i++) {
2658 features_list = g_list_append(features_list, features[i]);
2661 return features_list;
2669 REMMINA_PLUGIN_DEBUG(
"Function entry.");
2671 GList* returning_glist = NULL;
2680 argv[argc++] = g_strdup(
"pyhoca-cli");
2681 argv[argc++] = g_strdup(
"--list-cmdline-features");
2682 argv[argc++] = NULL;
2684 GError* error = NULL;
2687 gchar** envp = g_get_environ();
2692 if (!features_string || error) {
2698 REMMINA_PLUGIN_WARNING(
"%s",
2699 _(
"Could not get PyHoca-CLI's command-line features. This " 2700 "indicates it is either too old, or not installed. " 2701 "An old limited set of features will be used for now."));
2705 gchar **features_list = g_strsplit(features_string,
"\n", 0);
2707 if (features_list == NULL) {
2708 gchar *error_msg = _(
"Could not parse PyHoca-CLI's command-line " 2709 "features. Using a limited feature-set for now.");
2710 REMMINA_PLUGIN_WARNING(
"%s", error_msg);
2714 REMMINA_PLUGIN_INFO(
"%s", _(
"Retrieved the following PyHoca-CLI " 2715 "command-line features:"));
2717 for(
int k = 0; features_list[k] != NULL; k++) {
2719 if (strlen(features_list[k]) <= 0)
continue;
2721 REMMINA_PLUGIN_INFO(
"%s",
2722 g_strdup_printf(_(
"Available feature[%i]: '%s'"),
2723 k+1, features_list[k]));
2724 returning_glist = g_list_append(returning_glist, features_list[k]);
2726 return returning_glist;
2732 TRACE_CALL(__func__);
2738 REMMINA_PLUGIN_DEBUG(
"Socket %d", gpdata->
socket_id);
2747 REMMINA_PLUGIN_AUDIT(_(
"Connected to %s:%d via X2Go"), server, port);
2748 g_free(server), server = NULL;
2755 TRACE_CALL(__func__);
2756 REMMINA_PLUGIN_DEBUG(
"Function entry.");
2758 return G_SOURCE_CONTINUE;
2763 TRACE_CALL(__func__);
2764 REMMINA_PLUGIN_DEBUG(
"Function entry.", PLUGIN_NAME);
2768 g_object_set_data_full(G_OBJECT(gp),
"plugin-data", gpdata, g_free);
2789 gpdata->
socket = gtk_socket_new();
2791 gtk_widget_show(gpdata->
socket);
2793 g_signal_connect(G_OBJECT(gpdata->
socket),
"plug-added",
2795 g_signal_connect(G_OBJECT(gpdata->
socket),
"plug-removed",
2797 gtk_container_add(GTK_CONTAINER(gp), gpdata->
socket);
2802 TRACE_CALL(__func__);
2804 gboolean already_seen = FALSE;
2806 REMMINA_PLUGIN_DEBUG(
"Check if the window of X2Go Agent with ID [0x%lx] is already known or if " 2807 "it needs registration", window_id);
2812 already_seen = TRUE;
2813 REMMINA_PLUGIN_DEBUG(
"Window of X2Go Agent with ID [0x%lx] " 2814 "already seen.", window_id);
2818 if (!already_seen) {
2820 REMMINA_PLUGIN_DEBUG(
"Registered new window for X2Go Agent with " 2821 "ID [0x%lx].", window_id);
2825 return (!already_seen);
2830 TRACE_CALL(__func__);
2836 TRACE_CALL(__func__);
2839 gpdata->
display = XOpenDisplay(gdk_display_get_name(gdk_display_get_default()));
2840 if (gpdata->
display == NULL) {
2841 g_strlcpy(errmsg, _(
"Could not open X11 DISPLAY."), 512);
2848 XDefaultRootWindow(gpdata->
display),
2849 SubstructureNotifyMask);
2851 REMMINA_PLUGIN_DEBUG(
"X11 event-watcher created.");
2860 TRACE_CALL(__func__);
2863 gboolean agent_window_found = FALSE;
2869 unsigned long nitems, rest;
2870 unsigned char *data = NULL;
2872 guint16 non_createnotify_count = 0;
2877 int wait_amount = 100;
2881 REMMINA_PLUGIN_DEBUG(
"%s", _(
"Waiting for window of X2Go Agent to appear…"));
2883 gpdata = GET_PLUGIN_DATA(gp);
2884 atom = XInternAtom(gpdata->
display,
"WM_COMMAND", True);
2892 ts.tv_nsec = 200000000;
2894 while (wait_amount > 0) {
2895 pthread_testcancel();
2897 nanosleep(&ts, NULL);
2898 REMMINA_PLUGIN_DEBUG(
"Waiting for X2Go session to start…");
2902 while (!XPending(gpdata->
display)) {
2903 nanosleep(&ts, NULL);
2906 if (wait_amount % 5 == 0) {
2907 REMMINA_PLUGIN_INFO(
"%s", _(
"Waiting for PyHoca-CLI to " 2908 "show the session's window…"));
2913 XNextEvent(gpdata->
display, &xev);
2915 if (xev.type != CreateNotify) {
2916 non_createnotify_count++;
2917 if (non_createnotify_count % 5 == 0) {
2918 REMMINA_PLUGIN_DEBUG(
"Saw '%i' X11 events, which weren't " 2919 "CreateNotify.", non_createnotify_count);
2924 w = xev.xcreatewindow.window;
2925 if (XGetWindowProperty(gpdata->
display, w, atom, 0, 255, False,
2926 AnyPropertyType, &type, &format, &nitems, &rest,
2927 &data) != Success) {
2928 REMMINA_PLUGIN_DEBUG(
"Could not get WM_COMMAND property from X11 " 2929 "window ID [0x%lx].", w);
2934 REMMINA_PLUGIN_DEBUG(
"Saw '%i' X11 events, which weren't " 2935 "CreateNotify.", non_createnotify_count);
2936 REMMINA_PLUGIN_DEBUG(
"Found X11 window with WM_COMMAND set " 2937 "to '%s', the window ID is [0x%lx].",
2940 if (data && g_strrstr((gchar*)data, cmd) &&
2943 agent_window_found = TRUE;
2952 XCloseDisplay(gpdata->
display);
2957 if (!agent_window_found) {
2958 g_strlcpy(errmsg, _(
"No X2Go session window appeared. " 2959 "Something went wrong…"), 512);
2968 TRACE_CALL(__func__);
2969 REMMINA_PLUGIN_DEBUG(
"Function entry.");
2973 const gchar errmsg[512] = {0};
2974 gboolean ret = TRUE;
2976 gchar *servstr, *host, *username, *password, *command, *kbdlayout, *kbdtype,
2977 *audio, *clipboard, *res, *ssh_privatekey;
2979 GdkDisplay *default_dsp;
2983 default_dsp = gdk_display_get_default();
2984 const gchar *default_dsp_name = gdk_display_get_name(default_dsp);
2985 REMMINA_PLUGIN_DEBUG(
"Default display is '%s'.", default_dsp_name);
2989 servstr = GET_PLUGIN_STRING(
"server");
2996 if (!sshport) sshport=22;
2998 username = GET_PLUGIN_STRING(
"username");
2999 password = GET_PLUGIN_PASSWORD(
"password");
3001 command = GET_PLUGIN_STRING(
"command");
3002 if (!command) command =
"TERMINAL";
3004 kbdlayout = GET_PLUGIN_STRING(
"kbdlayout");
3005 kbdtype = GET_PLUGIN_STRING(
"kbdtype");
3007 audio = GET_PLUGIN_STRING(
"audio");
3009 clipboard = GET_PLUGIN_STRING(
"clipboard");
3011 dpi = GET_PLUGIN_INT(
"dpi", 80);
3013 ssh_privatekey = GET_PLUGIN_STRING(
"ssh_privatekey");
3016 if(ssh_privatekey && g_str_equal(ssh_privatekey,
"")) {
3017 ssh_privatekey = NULL;
3023 width = (width + 3) & ~0x3;
3024 height = (height + 3) & ~0x3;
3025 if ((width > 0) && (height > 0)) {
3026 res = g_strdup_printf (
"%dx%d", width, height);
3030 REMMINA_PLUGIN_DEBUG(
"Resolution set by user: '%s'.", res);
3032 REMMINA_PLUGIN_DEBUG(
"Attached window to socket '%d'.", gpdata->
socket_id);
3039 kbdlayout, kbdtype, audio, clipboard, dpi,
3040 res, ssh_privatekey, gp,
3048 REMMINA_PLUGIN_CRITICAL(
"%s", errmsg);
3061 TRACE_CALL(__func__);
3063 gboolean ret = FALSE;
3073 TRACE_CALL(__func__);
3075 REMMINA_PLUGIN_CRITICAL(
"%s", g_strdup_printf(
3076 _(
"Internal error: %s"),
3077 _(
"RemminaProtocolWidget* gp is 'NULL'!")
3082 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
3094 TRACE_CALL(__func__);
3099 "unavailable because GtkSocket only works under X.org"),
3108 "pthread. Falling back to non-threaded mode…"));
3119 TRACE_CALL(__func__);
3140 const guint current_element,
3141 gchar* element_to_add,
3144 if (max_elements > 2) {
3145 if (current_element == max_elements - 1) {
3150 return g_strdup_printf(_(
"%sand '%s'"),
string, element_to_add);
3151 }
else if (current_element == max_elements - 2) {
3155 return g_strdup_printf(_(
"%s'%s' "),
string, element_to_add);
3160 return g_strdup_printf(_(
"%s'%s', "),
string, element_to_add);
3162 }
else if (max_elements == 2) {
3163 if (current_element == max_elements - 1) {
3168 return g_strdup_printf(_(
"%sand '%s'"),
string, element_to_add);
3173 return g_strdup_printf(_(
"%s'%s' "),
string, element_to_add);
3176 return g_strdup(element_to_add);
3196 GError *error = NULL;
3199 gchar *error_msg = _(
"Invalid validation data in ProtocolSettings array!");
3200 REMMINA_PLUGIN_CRITICAL(
"%s", error_msg);
3201 g_set_error(&error, 1, 1,
"%s", error_msg);
3205 gchar **elements_list = g_strsplit(data,
",", 0);
3207 guint elements_amount = 0;
3208 elements_amount = g_strv_length(elements_list);
3210 if (elements_list == NULL ||
3211 elements_list[0] == NULL ||
3212 strlen(elements_list[0]) <= 0)
3214 gchar *error_msg = _(
"Validation data in ProtocolSettings array is invalid!");
3215 REMMINA_PLUGIN_CRITICAL(
"%s", error_msg);
3216 g_set_error(&error, 1, 1,
"%s", error_msg);
3220 gchar *data_str =
"";
3222 if (!key || !value) {
3223 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Parameters 'key' or 'value' are 'NULL'!"));
3224 g_set_error(&error, 1, 1,
"%s", _(
"Internal error."));
3228 for (guint i = 0; elements_list[i] != NULL; i++) {
3230 gchar* element = elements_list[i] ? elements_list[i] :
"";
3231 if (g_strcmp0(value, element) == 0) {
3240 if (elements_amount > 1) {
3241 g_set_error(&error, 1, 1, _(
"Allowed values are %s."), data_str);
3243 g_set_error(&error, 1, 1, _(
"The only allowed value is '%s'."), data_str);
3247 g_strfreev(elements_list);
3269 GError *error = NULL;
3271 gchar **integer_list = g_strsplit(data,
";", 0);
3273 if (integer_list == NULL ||
3274 integer_list[0] == NULL ||
3275 integer_list[1] == NULL ||
3276 strlen(integer_list[0]) <= 0 ||
3277 strlen(integer_list[1]) <= 0)
3279 gchar *error_msg = _(
"Validation data in ProtocolSettings array is invalid!");
3280 REMMINA_PLUGIN_CRITICAL(
"%s", error_msg);
3281 g_set_error(&error, 1, 1,
"%s", error_msg);
3288 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3289 _(
"Internal error: %s"),
3290 _(
"The lower limit is not a valid integer!")
3293 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3294 _(
"Internal error: %s"),
3295 _(
"The lower limit is too high!")
3298 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3299 _(
"Internal error: %s"),
3300 _(
"The lower limit is too low!")
3303 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3304 _(
"Internal error: %s"),
3305 _(
"Something unknown went wrong.")
3310 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Please check the RemminaProtocolSetting " 3311 "array for possible errors."));
3316 err =
str2int(&maximum, integer_list[1], 10);
3318 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3319 _(
"Internal error: %s"),
3320 _(
"The upper limit is not a valid integer!")
3323 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3324 _(
"Internal error: %s"),
3325 _(
"The upper limit is too high!")
3328 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3329 _(
"Internal error: %s"),
3330 _(
"The upper limit is too low!")
3333 g_set_error(&error, 1, 1,
"%s", g_strdup_printf(
3334 _(
"Internal error: %s"),
3335 _(
"Something unknown went wrong.")
3340 REMMINA_PLUGIN_CRITICAL(
"%s", _(
"Please check the RemminaProtocolSetting " 3341 "array for possible errors."));
3346 err =
str2int(&int_value, value, 10);
3350 g_set_error(&error, 1, 1,
"%s", _(
"The input is not a valid integer!"));
3352 g_set_error(&error, 1, 1, _(
"Input must be a number between %i and %i."),
3355 g_set_error(&error, 1, 1,
"%s", _(
"Something unknown went wrong."));
3368 if (err ==
STR2INT_SUCCESS && (minimum > int_value || int_value > maximum)) {
3369 g_set_error(&error, 1, 1, _(
"Input must be a number between %i and %i."),
3399 "MATE,KDE,XFCE,LXDE,TERMINAL",
3400 N_(
"Which command should be executed after creating the X2Go session?"), NULL, NULL},
3406 N_(
"The sound system of the X2Go server (default: 'pulse')."),
3410 "none,server,client,both",
3411 N_(
"Which direction should clipboard content be copied? " 3412 "(default: 'both')."),
3413 "none,server,client,both",
3416 N_(
"Launch session with a specific resolution (in dots per inch). " 3417 "Must be between 20 and 400."),
3447 TRACE_CALL(
"remmina_plugin_entry");
3448 rm_plugin_service = service;
3450 bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
3451 bind_textdomain_codeset(GETTEXT_PACKAGE,
"UTF-8");
3460 REMMINA_PLUGIN_MESSAGE(
"%s", _(
"X2Go plugin loaded."));
static gboolean rmplugin_x2go_start_create_notify(RemminaProtocolWidget *gp, gchar *errmsg)
enum _str2int_errno str2int_errno
static const RemminaProtocolFeature rmplugin_x2go_features[]
static gboolean rmplugin_x2go_monitor_create_notify(RemminaProtocolWidget *gp, const gchar *cmd, gchar *errmsg)
Stores all necessary information needed for retrieving sessions from a X2Go server.
static GList * rmplugin_x2go_parse_pyhoca_sessions(RemminaProtocolWidget *gp, GError **error, struct _ConnectionData *connect_data)
This function is used to parse the output of rmplugin_x2go_get_pyhoca_sessions(). ...
static void rmplugin_x2go_init(RemminaProtocolWidget *gp)
void(* protocol_plugin_set_error)(RemminaProtocolWidget *gp, const gchar *fmt,...)
static RemminaProtocolPlugin rmplugin_x2go
static gboolean rmplugin_x2go_verify_connection_data(struct _ConnectionData *connect_data)
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
static GError * rmplugin_x2go_int_setting_validator(gchar *key, gpointer value, gchar *data)
Validator-functions are getting executed when the user wants to save profile settings.
static GValue rmplugin_x2go_session_chooser_get_property(GtkWidget *dialog, gint property_index, GtkTreePath *row)
Finds the GtkTreeView inside of the session chooser dialog, determines the selected row and extracts ...
GCallback dialog_factory_func
static gchar * rmplugin_x2go_spawn_pyhoca_process(guint argc, gchar *argv[], GError **error, gchar **env)
This function dumps all properties of a session to the console.
static GList * rmplugin_x2go_old_pyhoca_features()
RemminaProtocolWidget * gp
static const RemminaProtocolSetting rmplugin_x2go_basic_settings[]
static pthread_mutex_t remmina_x2go_init_mutex
static gboolean rmplugin_x2go_close_connection(RemminaProtocolWidget *gp)
static gchar * rmplugin_x2go_get_pyhoca_sessions(RemminaProtocolWidget *gp, GError **error, struct _ConnectionData *connect_data)
Executes 'pyhoca-cli –list-sessions' for username.
SESSION_PROPERTIES
Used for the session chooser dialog (GtkListStore) See the example at: https://docs.gtk.org/gtk3/class.ListStore.html The order is the exact same as the user sees in the dialog.
static gboolean rmplugin_x2go_session_chooser_set_row_visible(GtkTreePath *path, gboolean value, GtkDialog *dialog)
Either sets a specific row visible or invisible.
static void rmplugin_x2go_remove_window_id(Window window_id)
static gboolean rmplugin_x2go_get_ssh_passphrase(RemminaProtocolWidget *gp, gchar *errmsg, gchar **passphrase)
Asks the user for a username and password.
static gchar * rmplugin_x2go_ask_session(RemminaProtocolWidget *gp, GError **error, struct _ConnectionData *connect_data)
Asks the user, with the help of a dialog, to continue an already existing session, terminate or create a new one.
static gboolean rmplugin_x2go_try_window_id(Window window_id)
int(* orig_handler)(Display *, XErrorEvent *)
static gboolean onMainThread_cb(struct onMainThread_cb_data *d)
void(* protocol_plugin_signal_connection_closed)(RemminaProtocolWidget *gp)
static gboolean rmplugin_x2go_start_session(RemminaProtocolWidget *gp)
void(* get_server_port)(const gchar *server, gint defaultport, gchar **host, gint *port)
static GtkTreePath * rmplugin_x2go_session_chooser_get_selected_row(GtkWidget *dialog)
Gets the selected row of the Session-Chooser-Dialog.
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
static GError * rmplugin_x2go_string_setting_validator(gchar *key, gchar *value, gchar *data)
Validator-functions are getting executed when the user wants to save profile settings.
void(* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp)
gpointer dialog_factory_data
static gchar * rmplugin_x2go_enumeration_prettifier(const guint max_elements, const guint current_element, gchar *element_to_add, gchar *string)
This function builds a string like: "'value1', 'value2' and 'value3'" To be used in a loop...
static gboolean rmplugin_x2go_on_plug_removed(GtkSocket *socket, RemminaProtocolWidget *gp)
gboolean(* protocol_plugin_init_get_savepassword)(RemminaProtocolWidget *gp)
gboolean(* register_plugin)(RemminaPlugin *plugin)
gboolean(* gtksocket_available)(void)
static gpointer rmplugin_x2go_main_thread(RemminaProtocolWidget *gp)
SESSION_CHOOSER_RESPONSE_TYPE
These define the responses of session-chooser-dialog's buttons.
static GtkTreeModelFilter * rmplugin_x2go_session_chooser_get_filter_model(GtkWidget *dialog, GtkTreeView *treeview)
Uses either 'dialog' or 'treeview' to return the GtkTreeModel of the Session-Chooser-Dialog.
GList * available_features
static gboolean rmplugin_x2go_pyhoca_terminate_session(X2GoCustomUserData *custom_data)
Terminates a specific X2Go session using pyhoca-cli.
enum onMainThread_cb_data::@61 func
static GtkWidget * rmplugin_x2go_choose_session_dialog_factory(X2GoCustomUserData *custom_data, GList *sessions_list)
Builds a dialog which contains all found X2Go-Sessions of the remote server.
static GtkWidget * rmplugin_x2go_find_child(GtkWidget *parent, const gchar *name)
Finds a child GtkWidget of a parent GtkWidget.
static gboolean rmplugin_x2go_exec_x2go(gchar *host, gint sshport, gchar *username, gchar *password, gchar *command, gchar *kbdlayout, gchar *kbdtype, gchar *audio, gchar *clipboard, gint dpi, gchar *resolution, gchar *ssh_privatekey, RemminaProtocolWidget *gp, gchar *errmsg)
static gboolean rmplugin_x2go_save_credentials(RemminaFile *remminafile, gchar *s_username, gchar *s_password, gchar *errmsg)
Saves s_password and s_username if set.
static gboolean rmplugin_x2go_open_dialog(X2GoCustomUserData *custom_data)
static gboolean rmplugin_x2go_session_chooser_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, X2GoCustomUserData *custom_data)
Gets executed on "row-activated" signal.
static gboolean rmplugin_x2go_get_auth(RemminaProtocolWidget *gp, gchar *errmsg, gchar **default_username, gchar **default_password)
Asks the user for a username and password.
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)
static gboolean rmplugin_x2go_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
gint(* get_profile_remote_height)(RemminaProtocolWidget *gp)
static void rmplugin_x2go_pyhoca_cli_exited(GPid pid, gint status, RemminaProtocolWidget *gp)
static gboolean rmplugin_x2go_open_connection(RemminaProtocolWidget *gp)
RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
static void rmplugin_x2go_on_plug_added(GtkSocket *socket, RemminaProtocolWidget *gp)
static void onMainThread_schedule_callback_and_wait(struct onMainThread_cb_data *d)
gchar *(* protocol_plugin_init_get_username)(RemminaProtocolWidget *gp)
static gchar * rmplugin_x2go_session_property_to_string(guint session_property)
Translates a session property (described by SESSION_PROPERTIES enum) to a string containing it's disp...
gint(* get_profile_remote_width)(RemminaProtocolWidget *gp)
gchar *(* protocol_plugin_init_get_password)(RemminaProtocolWidget *gp)
struct _X2GoCustomUserData X2GoCustomUserData
Can be used to pass custom user data between functions and threads.
static gboolean rmplugin_x2go_cleanup(RemminaProtocolWidget *gp)
Can be used to pass custom user data between functions and threads.
void(* protocol_plugin_register_hostkey)(RemminaProtocolWidget *gp, GtkWidget *widget)
static GArray * remmina_x2go_window_id_array
G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
RemminaProtocolWidget * gp
void(* file_set_string)(RemminaFile *remminafile, const gchar *setting, const gchar *value)
static RemminaPluginService * rm_plugin_service
static gboolean rmplugin_x2go_session_chooser_callback(X2GoCustomUserData *custom_data, gint response_id, GtkDialog *self)
Gets executed on dialog's 'response' signal.
static void onMainThread_cleanup_handler(gpointer data)
struct _RemminaPluginX2GoData RemminaPluginX2GoData
static gboolean rmplugin_x2go_main(RemminaProtocolWidget *gp)
const gchar *(* file_get_string)(RemminaFile *remminafile, const gchar *setting)
static void onMainThread_gtk_socket_add_id(GtkSocket *sk, Window w)
N_("Unable to connect to VNC server")
str2int_errno str2int(gint *out, gchar *s, gint base)
Convert string s to int out.
static GList * rmplugin_x2go_populate_available_features_list()
static int rmplugin_x2go_dummy_handler(Display *dsp, XErrorEvent *err)