remmina_protocol_widget.c 27.4 KB
Newer Older
1 2
/*
 * Remmina - The GTK+ Remote Desktop Client
llyzs's avatar
llyzs committed
3
 * Copyright (C) 2009-2011 Vic Lee
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, 
 * Boston, MA 02111-1307, USA.
 */

#include <gtk/gtk.h>
#include <glib/gi18n.h>
23
#include <stdlib.h>
24
#include "config.h"
25 26 27 28 29 30 31
#include "remmina_public.h"
#include "remmina_pref.h"
#include "remmina_ssh.h"
#include "remmina_chat_window.h"
#include "remmina_plugin_manager.h"
#include "remmina_connection_window.h"
#include "remmina_protocol_widget.h"
32 33 34

struct _RemminaProtocolWidgetPriv
{
35
	GtkWidget* init_dialog;
36

37 38 39
	RemminaFile* remmina_file;
	RemminaProtocolPlugin* plugin;
	RemminaProtocolFeature* features;
40

41 42 43 44
	gint width;
	gint height;
	gboolean scale;
	gboolean expand;
45

46
	gboolean has_error;
47 48
	gchar* error_message;
	RemminaSSHTunnel* ssh_tunnel;
49
	RemminaTunnelInitFunc init_func;
50

51
	GtkWidget* chat_window;
52

53
	gboolean closed;
54

55 56
	RemminaHostkeyFunc hostkey_func;
	gpointer hostkey_func_data;
57 58
};

59
G_DEFINE_TYPE(RemminaProtocolWidget, remmina_protocol_widget, GTK_TYPE_EVENT_BOX)
60

61 62
enum
{
63 64 65 66 67
	CONNECT_SIGNAL,
	DISCONNECT_SIGNAL,
	DESKTOP_RESIZE_SIGNAL,
	UPDATE_ALIGN_SIGNAL,
	LAST_SIGNAL
68 69 70 71
};

typedef struct _RemminaProtocolWidgetSignalData
{
72
	RemminaProtocolWidget* gp;
73
	const gchar* signal_name;
74 75
} RemminaProtocolWidgetSignalData;

76 77 78 79 80 81 82 83 84
static guint remmina_protocol_widget_signals[LAST_SIGNAL] =
{ 0 };

static void remmina_protocol_widget_class_init(RemminaProtocolWidgetClass *klass)
{
	remmina_protocol_widget_signals[CONNECT_SIGNAL] = g_signal_new("connect", G_TYPE_FROM_CLASS(klass),
			G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, connect), NULL, NULL,
			g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
	remmina_protocol_widget_signals[DISCONNECT_SIGNAL] = g_signal_new("disconnect", G_TYPE_FROM_CLASS(klass),
85 86
			G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, disconnect), NULL, NULL,
			g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
87
	remmina_protocol_widget_signals[DESKTOP_RESIZE_SIGNAL] = g_signal_new("desktop-resize", G_TYPE_FROM_CLASS(klass),
88 89
			G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, desktop_resize), NULL, NULL,
			g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
90
	remmina_protocol_widget_signals[UPDATE_ALIGN_SIGNAL] = g_signal_new("update-align", G_TYPE_FROM_CLASS(klass),
91 92
			G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(RemminaProtocolWidgetClass, update_align), NULL, NULL,
			g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
93 94
}

95
static void remmina_protocol_widget_init_cancel(RemminaInitDialog *dialog, gint response_id, RemminaProtocolWidget* gp)
96
{
97 98 99 100 101
	if ((response_id == GTK_RESPONSE_CANCEL || response_id == GTK_RESPONSE_DELETE_EVENT)
			&& dialog->mode == REMMINA_INIT_MODE_CONNECTING)
	{
		remmina_protocol_widget_close_connection(gp);
	}
102 103
}

104
static void remmina_protocol_widget_show_init_dialog(RemminaProtocolWidget* gp, const gchar *name)
105
{
106 107 108 109 110 111 112
	if (gp->priv->init_dialog)
	{
		gtk_widget_destroy(gp->priv->init_dialog);
	}
	gp->priv->init_dialog = remmina_init_dialog_new(_("Connecting to '%s'..."), (name ? name : "*"));
	g_signal_connect(G_OBJECT(gp->priv->init_dialog), "response", G_CALLBACK(remmina_protocol_widget_init_cancel), gp);
	gtk_widget_show(gp->priv->init_dialog);
113 114
}

115
static void remmina_protocol_widget_hide_init_dialog(RemminaProtocolWidget* gp)
116
{
117 118
	if (gp->priv->init_dialog && GTK_IS_WIDGET(gp->priv->init_dialog))
		gtk_widget_destroy(gp->priv->init_dialog);
119

120
	gp->priv->init_dialog = NULL;
121 122
}

123
static void remmina_protocol_widget_destroy(RemminaProtocolWidget* gp, gpointer data)
124 125 126 127 128 129 130
{
	remmina_protocol_widget_hide_init_dialog(gp);
	g_free(gp->priv->features);
	g_free(gp->priv->error_message);
	g_free(gp->priv);
}

131
static void remmina_protocol_widget_connect(RemminaProtocolWidget* gp, gpointer data)
132
{
133
#ifdef HAVE_LIBSSH
134 135 136 137
	if (gp->priv->ssh_tunnel)
	{
		remmina_ssh_tunnel_cancel_accept (gp->priv->ssh_tunnel);
	}
138
#endif
139
	remmina_protocol_widget_hide_init_dialog(gp);
140 141
}

142
static void remmina_protocol_widget_disconnect(RemminaProtocolWidget* gp, gpointer data)
143
{
144
	remmina_protocol_widget_hide_init_dialog(gp);
145 146
}

147
void remmina_protocol_widget_grab_focus(RemminaProtocolWidget* gp)
148
{
149
	GtkWidget* child;
150

151
	child = gtk_bin_get_child(GTK_BIN(gp));
152

153 154 155 156 157
	if (child)
	{
		gtk_widget_set_can_focus(child, TRUE);
		gtk_widget_grab_focus(child);
	}
158 159
}

160
static void remmina_protocol_widget_init(RemminaProtocolWidget* gp)
161
{
162
	RemminaProtocolWidgetPriv *priv;
163

164 165
	priv = g_new0(RemminaProtocolWidgetPriv, 1);
	gp->priv = priv;
166

167 168 169
	g_signal_connect(G_OBJECT(gp), "destroy", G_CALLBACK(remmina_protocol_widget_destroy), NULL);
	g_signal_connect(G_OBJECT(gp), "connect", G_CALLBACK(remmina_protocol_widget_connect), NULL);
	g_signal_connect(G_OBJECT(gp), "disconnect", G_CALLBACK(remmina_protocol_widget_disconnect), NULL);
170 171
}

172
void remmina_protocol_widget_open_connection_real(gpointer data)
173
{
174
	RemminaProtocolWidget* gp = REMMINA_PROTOCOL_WIDGET(data);
175 176 177
	RemminaProtocolPlugin* plugin;
	RemminaFile* remminafile = gp->priv->remmina_file;
	RemminaProtocolFeature* feature;
178 179
	gint num_plugin;
	gint num_ssh;
180

181
	/* Locate the protocol plugin */
182
	plugin = (RemminaProtocolPlugin*) remmina_plugin_manager_get_plugin(REMMINA_PLUGIN_TYPE_PROTOCOL,
183
			remmina_file_get_string(remminafile, "protocol"));
184

185 186 187 188 189 190 191
	if (!plugin || !plugin->init || !plugin->open_connection)
	{
		remmina_protocol_widget_set_error(gp, _("Protocol plugin %s is not installed."),
				remmina_file_get_string(remminafile, "protocol"));
		remmina_protocol_widget_close_connection(gp);
		return;
	}
192

193
	plugin->init(gp);
194

195
	gp->priv->plugin = plugin;
196

197 198
	for (num_plugin = 0, feature = (RemminaProtocolFeature*) plugin->features; feature && feature->type; num_plugin++, feature++)
	{
199
	}
200

201
	num_ssh = 0;
202
#ifdef HAVE_LIBSSH
203
	if (remmina_file_get_int(gp->priv->remmina_file, "ssh_enabled", FALSE))
204 205 206
	{
		num_ssh += 2;
	}
207
#endif
208 209 210 211 212 213 214 215 216 217 218 219 220
	if (num_plugin + num_ssh == 0)
	{
		gp->priv->features = NULL;
	}
	else
	{
		gp->priv->features = g_new0(RemminaProtocolFeature, num_plugin + num_ssh + 1);
		feature = gp->priv->features;
		if (plugin->features)
		{
			memcpy(feature, plugin->features, sizeof(RemminaProtocolFeature) * num_plugin);
			feature += num_plugin;
		}
221
#ifdef HAVE_LIBSSH
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
		if (num_ssh)
		{
			feature->type = REMMINA_PROTOCOL_FEATURE_TYPE_TOOL;
			feature->id = REMMINA_PROTOCOL_FEATURE_TOOL_SSH;
			feature->opt1 = _("Open Secure Shell in New Terminal...");
			feature->opt2 = "utilities-terminal";
			feature++;

			feature->type = REMMINA_PROTOCOL_FEATURE_TYPE_TOOL;
			feature->id = REMMINA_PROTOCOL_FEATURE_TOOL_SFTP;
			feature->opt1 = _("Open Secure File Transfer...");
			feature->opt2 = "folder-remote";
			feature++;
		}
		feature->type = REMMINA_PROTOCOL_FEATURE_TYPE_END;
237
#endif
238
	}
239

240 241 242 243
	if (!plugin->open_connection(gp))
	{
		remmina_protocol_widget_close_connection(gp);
	}
244 245
}

246
void remmina_protocol_widget_open_connection(RemminaProtocolWidget* gp, RemminaFile* remminafile)
247
{
248 249
	gp->priv->remmina_file = remminafile;
	gp->priv->scale = remmina_file_get_int(remminafile, "scale", FALSE);
250

251
	remmina_protocol_widget_show_init_dialog(gp, remmina_file_get_string(remminafile, "name"));
252

253
	remmina_protocol_widget_open_connection_real(gp);
254 255
}

256
gboolean remmina_protocol_widget_close_connection(RemminaProtocolWidget* gp)
257
{
Jean-Louis's avatar
Jean-Louis committed
258 259 260 261
	GdkDisplay *display;
	GdkDeviceManager *manager;
	GdkDevice *device = NULL;

262 263
	if (!GTK_IS_WIDGET(gp) || gp->priv->closed)
		return FALSE;
264

265
	gp->priv->closed = TRUE;
Jean-Louis's avatar
Jean-Louis committed
266 267 268 269 270 271 272
	display = gtk_widget_get_display(GTK_WIDGET(gp));
	manager = gdk_display_get_device_manager(display);
	device = gdk_device_manager_get_client_pointer(manager);
	if (device != NULL)
	{
		gdk_device_ungrab(device, GDK_CURRENT_TIME);
	}
273

274 275 276 277 278
	if (gp->priv->chat_window)
	{
		gtk_widget_destroy(gp->priv->chat_window);
		gp->priv->chat_window = NULL;
	}
279 280

#ifdef HAVE_LIBSSH
281 282
	if (gp->priv->ssh_tunnel)
	{
283
		remmina_ssh_tunnel_free(gp->priv->ssh_tunnel);
284 285
		gp->priv->ssh_tunnel = NULL;
	}
286 287
#endif

288 289 290 291 292
	if (!gp->priv->plugin || !gp->priv->plugin->close_connection)
	{
		remmina_protocol_widget_emit_signal(gp, "disconnect");
		return FALSE;
	}
293

294
	return gp->priv->plugin->close_connection(gp);
295 296
}

297
static gboolean remmina_protocol_widget_emit_signal_timeout(gpointer user_data)
298
{
299
	RemminaProtocolWidgetSignalData* data = (RemminaProtocolWidgetSignalData*) user_data;
300 301 302
	g_signal_emit_by_name(G_OBJECT(data->gp), data->signal_name);
	g_free(data);
	return FALSE;
303 304
}

305
void remmina_protocol_widget_emit_signal(RemminaProtocolWidget* gp, const gchar* signal_name)
306
{
307
	RemminaProtocolWidgetSignalData* data;
308

309 310 311 312
	data = g_new(RemminaProtocolWidgetSignalData, 1);
	data->gp = gp;
	data->signal_name = signal_name;
	TIMEOUT_ADD(0, remmina_protocol_widget_emit_signal_timeout, data);
313 314
}

315
const RemminaProtocolFeature* remmina_protocol_widget_get_features(RemminaProtocolWidget* gp)
316
{
317
	return gp->priv->features;
318 319
}

320
const gchar* remmina_protocol_widget_get_domain(RemminaProtocolWidget* gp)
321
{
322
	return gp->priv->plugin->domain;
323 324
}

325
gboolean remmina_protocol_widget_query_feature_by_type(RemminaProtocolWidget* gp, RemminaProtocolFeatureType type)
326
{
327
	const RemminaProtocolFeature *feature;
328

329
#ifdef HAVE_LIBSSH
330 331 332 333 334
	if (type == REMMINA_PROTOCOL_FEATURE_TYPE_TOOL &&
			remmina_file_get_int (gp->priv->remmina_file, "ssh_enabled", FALSE))
	{
		return TRUE;
	}
335
#endif
336 337 338 339 340 341
	for (feature = gp->priv->plugin->features; feature && feature->type; feature++)
	{
		if (feature->type == type)
			return TRUE;
	}
	return FALSE;
342 343
}

344
gboolean remmina_protocol_widget_query_feature_by_ref(RemminaProtocolWidget* gp, const RemminaProtocolFeature *feature)
345
{
346
	return gp->priv->plugin->query_feature(gp, feature);
347 348
}

349
void remmina_protocol_widget_call_feature_by_type(RemminaProtocolWidget* gp, RemminaProtocolFeatureType type, gint id)
350
{
351
	const RemminaProtocolFeature *feature;
352

353 354 355 356 357 358 359 360
	for (feature = gp->priv->plugin->features; feature && feature->type; feature++)
	{
		if (feature->type == type && (id == 0 || feature->id == id))
		{
			remmina_protocol_widget_call_feature_by_ref(gp, feature);
			break;
		}
	}
361 362
}

363
void remmina_protocol_widget_call_feature_by_ref(RemminaProtocolWidget* gp, const RemminaProtocolFeature *feature)
364
{
365 366
	switch (feature->id)
	{
367
#ifdef HAVE_LIBSSH
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
		case REMMINA_PROTOCOL_FEATURE_TOOL_SSH:
		if (gp->priv->ssh_tunnel)
		{
			remmina_connection_window_open_from_file_full (
					remmina_file_dup_temp_protocol (gp->priv->remmina_file, "SSH"), NULL, gp->priv->ssh_tunnel, NULL);
			return;
		}
		break;

		case REMMINA_PROTOCOL_FEATURE_TOOL_SFTP:
		if (gp->priv->ssh_tunnel)
		{
			remmina_connection_window_open_from_file_full (
					remmina_file_dup_temp_protocol (gp->priv->remmina_file, "SFTP"), NULL, gp->priv->ssh_tunnel, NULL);
			return;
		}
		break;
385
#endif
386 387 388 389
		default:
			break;
	}
	gp->priv->plugin->call_feature(gp, feature);
390 391
}

392
static gboolean remmina_protocol_widget_on_key_press(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget* gp)
393
{
394 395 396 397 398
	if (gp->priv->hostkey_func)
	{
		return gp->priv->hostkey_func(gp, event->keyval, FALSE, gp->priv->hostkey_func_data);
	}
	return FALSE;
399 400
}

401
static gboolean remmina_protocol_widget_on_key_release(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget* gp)
402
{
403 404 405 406 407
	if (gp->priv->hostkey_func)
	{
		return gp->priv->hostkey_func(gp, event->keyval, TRUE, gp->priv->hostkey_func_data);
	}
	return FALSE;
408 409
}

410
void remmina_protocol_widget_register_hostkey(RemminaProtocolWidget* gp, GtkWidget *widget)
411
{
412 413
	g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(remmina_protocol_widget_on_key_press), gp);
	g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(remmina_protocol_widget_on_key_release), gp);
414 415
}

416
void remmina_protocol_widget_set_hostkey_func(RemminaProtocolWidget* gp, RemminaHostkeyFunc func, gpointer data)
417
{
418 419
	gp->priv->hostkey_func = func;
	gp->priv->hostkey_func_data = data;
420 421 422
}

#ifdef HAVE_LIBSSH
423
static gboolean remmina_protocol_widget_init_tunnel (RemminaProtocolWidget* gp)
424
{
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
	RemminaSSHTunnel *tunnel;
	gint ret;

	/* Reuse existing SSH connection if it's reconnecting to destination */
	if (gp->priv->ssh_tunnel == NULL)
	{
		tunnel = remmina_ssh_tunnel_new_from_file (gp->priv->remmina_file);

		THREADS_ENTER
		remmina_init_dialog_set_status (REMMINA_INIT_DIALOG (gp->priv->init_dialog),
				_("Connecting to SSH server %s..."), REMMINA_SSH (tunnel)->server);
		THREADS_LEAVE

		if (!remmina_ssh_init_session (REMMINA_SSH (tunnel)))
		{
			remmina_protocol_widget_set_error (gp, REMMINA_SSH (tunnel)->error);
			remmina_ssh_tunnel_free (tunnel);
			return FALSE;
		}

		ret = remmina_ssh_auth_gui (REMMINA_SSH (tunnel), REMMINA_INIT_DIALOG (gp->priv->init_dialog), TRUE);
		if (ret <= 0)
		{
			if (ret == 0)
			{
				remmina_protocol_widget_set_error (gp, REMMINA_SSH (tunnel)->error);
			}
			remmina_ssh_tunnel_free (tunnel);
			return FALSE;
		}

		gp->priv->ssh_tunnel = tunnel;
	}

	return TRUE;
460 461 462
}
#endif

463
gchar* remmina_protocol_widget_start_direct_tunnel(RemminaProtocolWidget* gp, gint default_port, gboolean port_plus)
464
{
465 466 467
	const gchar *server;
	gchar *host, *dest;
	gint port;
468

469
	server = remmina_file_get_string(gp->priv->remmina_file, "server");
470

471 472 473 474
	if (!server)
	{
		return g_strdup("");
	}
475

476
	remmina_public_get_server_port(server, default_port, &host, &port);
477

478 479 480 481 482
	if (port_plus && port < 100)
	{
		/* Protocols like VNC supports using instance number :0, :1, etc as port number. */
		port += default_port;
	}
483 484

#ifdef HAVE_LIBSSH
485 486
	if (!remmina_file_get_int (gp->priv->remmina_file, "ssh_enabled", FALSE))
	{
487 488
		dest = g_strdup_printf("[%s]:%i", host, port);
		g_free(host);
489 490 491 492 493
		return dest;
	}

	if (!remmina_protocol_widget_init_tunnel (gp))
	{
494
		g_free(host);
495 496 497 498 499 500 501 502 503 504
		return NULL;
	}

	THREADS_ENTER
	remmina_init_dialog_set_status (REMMINA_INIT_DIALOG (gp->priv->init_dialog),
			_("Connecting to %s through SSH tunnel..."), server);
	THREADS_LEAVE

	if (remmina_file_get_int (gp->priv->remmina_file, "ssh_loopback", FALSE))
	{
505
		g_free(host);
506 507 508 509 510
		host = g_strdup ("127.0.0.1");
	}

	if (!remmina_ssh_tunnel_open (gp->priv->ssh_tunnel, host, port, remmina_pref.sshtunnel_port))
	{
511
		g_free(host);
512 513 514 515
		remmina_protocol_widget_set_error (gp, REMMINA_SSH (gp->priv->ssh_tunnel)->error);
		return NULL;
	}

516 517
	g_free(host);
	return g_strdup_printf("127.0.0.1:%i", remmina_pref.sshtunnel_port);
518 519 520

#else

521 522 523
	dest = g_strdup_printf("[%s]:%i", host, port);
	g_free(host);
	return dest;
524 525 526 527

#endif
}

528
gboolean remmina_protocol_widget_start_reverse_tunnel(RemminaProtocolWidget* gp, gint local_port)
529 530
{
#ifdef HAVE_LIBSSH
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
	if (!remmina_file_get_int (gp->priv->remmina_file, "ssh_enabled", FALSE))
	{
		return TRUE;
	}

	if (!remmina_protocol_widget_init_tunnel (gp))
	{
		return FALSE;
	}

	THREADS_ENTER
	remmina_init_dialog_set_status (REMMINA_INIT_DIALOG (gp->priv->init_dialog),
			_("Waiting for an incoming SSH tunnel at port %i..."), remmina_file_get_int (gp->priv->remmina_file, "listenport", 0));
	THREADS_LEAVE

	if (!remmina_ssh_tunnel_reverse (gp->priv->ssh_tunnel, remmina_file_get_int (gp->priv->remmina_file, "listenport", 0), local_port))
	{
		remmina_protocol_widget_set_error (gp, REMMINA_SSH (gp->priv->ssh_tunnel)->error);
		return FALSE;
	}
551 552
#endif

553
	return TRUE;
554 555
}

556
gboolean remmina_protocol_widget_ssh_exec(RemminaProtocolWidget* gp, gboolean wait, const gchar *fmt, ...)
557 558
{
#ifdef HAVE_LIBSSH
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
		RemminaSSHTunnel *tunnel = gp->priv->ssh_tunnel;
		ssh_channel channel;
		gint status;
		gboolean ret = FALSE;
		gchar *cmd, *ptr;
		va_list args;

		if ((channel = channel_new (REMMINA_SSH (tunnel)->session)) == NULL)
		{
			return FALSE;
		}

		va_start (args, fmt);
		cmd = g_strdup_vprintf (fmt, args);
		va_end (args);

		if (channel_open_session (channel) == SSH_OK &&
				channel_request_exec (channel, cmd) == SSH_OK)
		{
			if (wait)
			{
				channel_send_eof (channel);
				status = channel_get_exit_status (channel);
				ptr = strchr (cmd, ' ');
				if (ptr) *ptr = '\0';
				switch (status)
				{
					case 0:
					ret = TRUE;
					break;
					case 127:
					remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
							_("Command %s not found on SSH server"), cmd);
					break;
					default:
					remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
							_("Command %s failed on SSH server (status = %i)."), cmd,status);
596 597 598 599
                break;
            }
        }
        else
600 601 602 603
        {
            ret = TRUE;
        }
    }
604 605 606 607
    else
    {
        remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to execute command: %s"));
    }
608
    g_free(cmd);
609
    if (wait) channel_close (channel);
610 611 612 613 614 615 616 617 618 619 620
    channel_free (channel);
    return ret;

#else

    return FALSE;

#endif
}

#ifdef HAVE_LIBSSH
621
static gboolean remmina_protocol_widget_tunnel_init_callback (RemminaSSHTunnel *tunnel, gpointer data)
622
{
623
	RemminaProtocolWidget* gp = REMMINA_PROTOCOL_WIDGET (data);
624 625 626
	gchar *server;
	gint port;
	gboolean ret;
627

628 629 630
	remmina_public_get_server_port (remmina_file_get_string (gp->priv->remmina_file, "server"), 177, &server, &port);
	ret = ((RemminaXPortTunnelInitFunc) gp->priv->init_func) (gp,
			tunnel->remotedisplay, (tunnel->bindlocalhost ? "localhost" : server), port);
631
	g_free(server);
632

633
	return ret;
634 635
}

636
static gboolean remmina_protocol_widget_tunnel_connect_callback(RemminaSSHTunnel* tunnel, gpointer data)
637
{
638
	return TRUE;
639 640
}

641
static gboolean remmina_protocol_widget_tunnel_disconnect_callback(RemminaSSHTunnel* tunnel, gpointer data)
642
{
643
	RemminaProtocolWidget* gp = REMMINA_PROTOCOL_WIDGET (data);
644

645 646 647 648
	if (REMMINA_SSH (tunnel)->error)
	{
		remmina_protocol_widget_set_error (gp, "%s", REMMINA_SSH (tunnel)->error);
	}
649

650 651
	IDLE_ADD ((GSourceFunc) remmina_protocol_widget_close_connection, gp);
	return TRUE;
652 653 654
}
#endif

655
gboolean remmina_protocol_widget_start_xport_tunnel(RemminaProtocolWidget* gp, RemminaXPortTunnelInitFunc init_func)
656 657
{
#ifdef HAVE_LIBSSH
658 659
	gboolean bindlocalhost;
	gchar *server;
660

661
	if (!remmina_protocol_widget_init_tunnel (gp)) return FALSE;
662

663 664 665 666
	THREADS_ENTER
	remmina_init_dialog_set_status (REMMINA_INIT_DIALOG (gp->priv->init_dialog),
			_("Connecting to %s through SSH tunnel..."), remmina_file_get_string (gp->priv->remmina_file, "server"));
	THREADS_LEAVE
667

668 669 670 671 672
	gp->priv->init_func = init_func;
	gp->priv->ssh_tunnel->init_func = remmina_protocol_widget_tunnel_init_callback;
	gp->priv->ssh_tunnel->connect_func = remmina_protocol_widget_tunnel_connect_callback;
	gp->priv->ssh_tunnel->disconnect_func = remmina_protocol_widget_tunnel_disconnect_callback;
	gp->priv->ssh_tunnel->callback_data = gp;
673

674
	remmina_public_get_server_port (remmina_file_get_string (gp->priv->remmina_file, "server"), 0, &server, NULL);
675
	bindlocalhost = (g_strcmp0(REMMINA_SSH (gp->priv->ssh_tunnel)->server, server) == 0);
676
	g_free(server);
677

678 679 680 681 682 683
	if (!remmina_ssh_tunnel_xport (gp->priv->ssh_tunnel, bindlocalhost))
	{
		remmina_protocol_widget_set_error (gp, "Failed to open channel : %s",
				ssh_get_error (REMMINA_SSH (gp->priv->ssh_tunnel)->session));
		return FALSE;
	}
684

685
	return TRUE;
686 687

#else
688
	return FALSE;
689 690 691
#endif
}

692
void remmina_protocol_widget_set_display(RemminaProtocolWidget* gp, gint display)
693
{
694
#ifdef HAVE_LIBSSH
695 696
	if (gp->priv->ssh_tunnel->localdisplay) g_free(gp->priv->ssh_tunnel->localdisplay);
	gp->priv->ssh_tunnel->localdisplay = g_strdup_printf("unix:%i", display);
697
#endif
698 699
}

700
GtkWidget* remmina_protocol_widget_get_init_dialog(RemminaProtocolWidget* gp)
701
{
702
	return gp->priv->init_dialog;
703 704
}

705
gint remmina_protocol_widget_get_width(RemminaProtocolWidget* gp)
706
{
707
	return gp->priv->width;
708 709
}

710
void remmina_protocol_widget_set_width(RemminaProtocolWidget* gp, gint width)
711
{
712
	gp->priv->width = width;
713 714
}

715
gint remmina_protocol_widget_get_height(RemminaProtocolWidget* gp)
716
{
717
	return gp->priv->height;
718 719
}

720
void remmina_protocol_widget_set_height(RemminaProtocolWidget* gp, gint height)
721
{
722
	gp->priv->height = height;
723 724
}

725
gboolean remmina_protocol_widget_get_scale(RemminaProtocolWidget* gp)
726
{
727
	return gp->priv->scale;
728 729
}

730
void remmina_protocol_widget_set_scale(RemminaProtocolWidget* gp, gboolean scale)
731
{
732
	gp->priv->scale = scale;
733 734
}

735
gboolean remmina_protocol_widget_get_expand(RemminaProtocolWidget* gp)
736
{
737
	return gp->priv->expand;
738 739
}

740
void remmina_protocol_widget_set_expand(RemminaProtocolWidget* gp, gboolean expand)
741
{
742
	gp->priv->expand = expand;
743 744
}

745
gboolean remmina_protocol_widget_has_error(RemminaProtocolWidget* gp)
746
{
747
	return gp->priv->has_error;
748 749
}

750
gchar* remmina_protocol_widget_get_error_message(RemminaProtocolWidget* gp)
751
{
752
	return gp->priv->error_message;
753 754
}

755
void remmina_protocol_widget_set_error(RemminaProtocolWidget* gp, const gchar *fmt, ...)
756
{
757
	va_list args;
758

759
	if (gp->priv->error_message) g_free(gp->priv->error_message);
760

761 762 763
	va_start (args, fmt);
	gp->priv->error_message = g_strdup_vprintf (fmt, args);
	va_end (args);
764

765
	gp->priv->has_error = TRUE;
766 767
}

768
gboolean remmina_protocol_widget_is_closed(RemminaProtocolWidget* gp)
769
{
770
	return gp->priv->closed;
771 772
}

773
RemminaFile* remmina_protocol_widget_get_file(RemminaProtocolWidget* gp)
774
{
775
	return gp->priv->remmina_file;
776 777
}

778
gint remmina_protocol_widget_init_authpwd(RemminaProtocolWidget* gp, RemminaAuthpwdType authpwd_type)
779
{
780 781
	RemminaFile* remminafile = gp->priv->remmina_file;
	gchar* s;
782
	gint ret;
783

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
	switch (authpwd_type)
	{
		case REMMINA_AUTHPWD_TYPE_PROTOCOL:
			s = g_strdup_printf(_("%s password"), remmina_file_get_string(remminafile, "protocol"));
			break;
		case REMMINA_AUTHPWD_TYPE_SSH_PWD:
			s = g_strdup(_("SSH password"));
			break;
		case REMMINA_AUTHPWD_TYPE_SSH_PRIVKEY:
			s = g_strdup(_("SSH private key passphrase"));
			break;
		default:
			s = g_strdup(_("Password"));
			break;
	}
	ret = remmina_init_dialog_authpwd(
			REMMINA_INIT_DIALOG(gp->priv->init_dialog),
			s,
			remmina_file_get_filename(remminafile) != NULL && authpwd_type != REMMINA_AUTHPWD_TYPE_SSH_PWD
					&& authpwd_type != REMMINA_AUTHPWD_TYPE_SSH_PRIVKEY);
	g_free(s);
805

806
	return ret;
807 808
}

809
gint remmina_protocol_widget_init_authuserpwd(RemminaProtocolWidget* gp, gboolean want_domain)
810
{
811
	RemminaFile* remminafile = gp->priv->remmina_file;
812

813 814 815 816
	return remmina_init_dialog_authuserpwd(REMMINA_INIT_DIALOG(gp->priv->init_dialog), want_domain,
			remmina_file_get_string(remminafile, "username"),
			want_domain ? remmina_file_get_string(remminafile, "domain") : NULL,
			(remmina_file_get_filename(remminafile) != NULL));
817 818
}

819 820 821 822 823 824
gint remmina_protocol_widget_init_certificate(RemminaProtocolWidget* gp, const gchar* subject, const gchar* issuer, const gchar* fingerprint)
{
	return remmina_init_dialog_certificate(REMMINA_INIT_DIALOG(gp->priv->init_dialog), subject, issuer, fingerprint);
}

gchar* remmina_protocol_widget_init_get_username(RemminaProtocolWidget* gp)
825
{
826
	return g_strdup(REMMINA_INIT_DIALOG(gp->priv->init_dialog)->username);
827 828
}

829
gchar* remmina_protocol_widget_init_get_password(RemminaProtocolWidget* gp)
830
{
831
	return g_strdup(REMMINA_INIT_DIALOG(gp->priv->init_dialog)->password);
832 833
}

834
gchar* remmina_protocol_widget_init_get_domain(RemminaProtocolWidget* gp)
llyzs's avatar
llyzs committed
835
{
836
	return g_strdup(REMMINA_INIT_DIALOG(gp->priv->init_dialog)->domain);
llyzs's avatar
llyzs committed
837 838
}

839
gint remmina_protocol_widget_init_authx509(RemminaProtocolWidget* gp)
840
{
841
	RemminaFile* remminafile = gp->priv->remmina_file;
842

843 844 845
	return remmina_init_dialog_authx509(REMMINA_INIT_DIALOG(gp->priv->init_dialog),
			remmina_file_get_string(remminafile, "cacert"), remmina_file_get_string(remminafile, "cacrl"),
			remmina_file_get_string(remminafile, "clientcert"), remmina_file_get_string(remminafile, "clientkey"));
846 847
}

848
gchar* remmina_protocol_widget_init_get_cacert(RemminaProtocolWidget* gp)
849
{
850
	gchar* s;
851

852 853
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->cacert;
	return (s && s[0] ? g_strdup(s) : NULL);
854 855
}

856
gchar* remmina_protocol_widget_init_get_cacrl(RemminaProtocolWidget* gp)
857
{
858
	gchar* s;
859

860 861
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->cacrl;
	return (s && s[0] ? g_strdup(s) : NULL);
862 863
}

864
gchar* remmina_protocol_widget_init_get_clientcert(RemminaProtocolWidget* gp)
865
{
866
	gchar* s;
867

868 869
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->clientcert;
	return (s && s[0] ? g_strdup(s) : NULL);
870 871
}

872
gchar* remmina_protocol_widget_init_get_clientkey(RemminaProtocolWidget* gp)
873
{
874
	gchar* s;
875

876 877
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->clientkey;
	return (s && s[0] ? g_strdup(s) : NULL);
878 879
}

880
void remmina_protocol_widget_init_save_cred(RemminaProtocolWidget* gp)
881
{
882 883
	RemminaFile* remminafile = gp->priv->remmina_file;
	gchar* s;
884
	gboolean save = FALSE;
885

886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
	/* Save user name and certificates if any; save the password if it's requested to do so */
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->username;
	if (s && s[0])
	{
		remmina_file_set_string(remminafile, "username", s);
		save = TRUE;
	}
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->cacert;
	if (s && s[0])
	{
		remmina_file_set_string(remminafile, "cacert", s);
		save = TRUE;
	}
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->cacrl;
	if (s && s[0])
	{
		remmina_file_set_string(remminafile, "cacrl", s);
		save = TRUE;
	}
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->clientcert;
	if (s && s[0])
	{
		remmina_file_set_string(remminafile, "clientcert", s);
		save = TRUE;
	}
	s = REMMINA_INIT_DIALOG(gp->priv->init_dialog)->clientkey;
	if (s && s[0])
	{
		remmina_file_set_string(remminafile, "clientkey", s);
		save = TRUE;
	}
	if (REMMINA_INIT_DIALOG(gp->priv->init_dialog)->save_password)
	{
		remmina_file_set_string(remminafile, "password", REMMINA_INIT_DIALOG(gp->priv->init_dialog)->password);
		save = TRUE;
	}
	if (save)
	{
		remmina_file_save_group(remminafile, REMMINA_SETTING_GROUP_CREDENTIAL);
	}
926 927
}

928
void remmina_protocol_widget_init_show_listen(RemminaProtocolWidget* gp, gint port)
929
{
930 931 932
	remmina_init_dialog_set_status(REMMINA_INIT_DIALOG(gp->priv->init_dialog),
			_("Listening on port %i for an incoming %s connection..."), port,
			remmina_file_get_string(gp->priv->remmina_file, "protocol"));
933 934
}

935
void remmina_protocol_widget_init_show_retry(RemminaProtocolWidget* gp)
936
{
937 938
	remmina_init_dialog_set_status_temp(REMMINA_INIT_DIALOG(gp->priv->init_dialog),
			_("Authentication failed. Trying to reconnect..."));
939 940
}

941
void remmina_protocol_widget_init_show(RemminaProtocolWidget* gp)
942
{
943
	gtk_widget_show(gp->priv->init_dialog);
944 945
}

946
void remmina_protocol_widget_init_hide(RemminaProtocolWidget* gp)
947
{
948
	gtk_widget_hide(gp->priv->init_dialog);
949 950
}

951
static void remmina_protocol_widget_chat_on_destroy(RemminaProtocolWidget* gp)
952
{
953
	gp->priv->chat_window = NULL;
954 955
}

956 957
void remmina_protocol_widget_chat_open(RemminaProtocolWidget* gp, const gchar *name,
		void(*on_send)(RemminaProtocolWidget* gp, const gchar *text), void(*on_destroy)(RemminaProtocolWidget* gp))
958
{
959 960 961 962 963 964 965 966 967 968 969 970 971
	if (gp->priv->chat_window)
	{
		gtk_window_present(GTK_WINDOW(gp->priv->chat_window));
	}
	else
	{
		gp->priv->chat_window = remmina_chat_window_new(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(gp))), name);
		g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "send", G_CALLBACK(on_send), gp);
		g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "destroy",
				G_CALLBACK(remmina_protocol_widget_chat_on_destroy), gp);
		g_signal_connect_swapped(G_OBJECT(gp->priv->chat_window), "destroy", G_CALLBACK(on_destroy), gp);
		gtk_widget_show(gp->priv->chat_window);
	}
972 973
}

974
void remmina_protocol_widget_chat_close(RemminaProtocolWidget* gp)
975
{
976 977 978 979
	if (gp->priv->chat_window)
	{
		gtk_widget_destroy(gp->priv->chat_window);
	}
980 981
}

982
void remmina_protocol_widget_chat_receive(RemminaProtocolWidget* gp, const gchar* text)
983
{
984 985 986 987 988
	if (gp->priv->chat_window)
	{
		remmina_chat_window_receive(REMMINA_CHAT_WINDOW(gp->priv->chat_window), _("Server"), text);
		gtk_window_present(GTK_WINDOW(gp->priv->chat_window));
	}
989 990
}

991
GtkWidget* remmina_protocol_widget_new(void)
992
{
993
	return GTK_WIDGET(g_object_new(REMMINA_TYPE_PROTOCOL_WIDGET, NULL));
994
}