mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/virt-viewer
synced 2026-01-08 13:07:13 +00:00
Since oVirt engine version 4.3.2.1, the API returns certificate data for display connection in the VM XML, so users do not need to specify it from the command line anymore. The certificate obtained from the XML gets precedence over the one from the command line, which is still kept to keep compatibility of older versions of oVirt. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1402909 Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
828 lines
24 KiB
C
828 lines
24 KiB
C
/*
|
|
* Virt Viewer: A virtual machine console viewer
|
|
*
|
|
* Copyright (C) 2007-2012 Red Hat, Inc.
|
|
* Copyright (C) 2009-2012 Daniel P. Berrange
|
|
* Copyright (C) 2010 Marc-André Lureau
|
|
*
|
|
* 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
|
|
*
|
|
* Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <gio/gio.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib/gprintf.h>
|
|
#include <glib/gi18n.h>
|
|
#include <libxml/uri.h>
|
|
|
|
#ifdef HAVE_OVIRT
|
|
#include <govirt/govirt.h>
|
|
#include "ovirt-foreign-menu.h"
|
|
#include "virt-viewer-vm-connection.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_SPICE_GTK
|
|
#include "virt-viewer-session-spice.h"
|
|
#endif
|
|
|
|
#include "virt-viewer-app.h"
|
|
#include "virt-viewer-auth.h"
|
|
#include "virt-viewer-file.h"
|
|
#include "virt-viewer-session.h"
|
|
#include "virt-viewer-util.h"
|
|
#include "remote-viewer.h"
|
|
#include "remote-viewer-connect.h"
|
|
|
|
struct _RemoteViewerPrivate {
|
|
#ifdef HAVE_OVIRT
|
|
OvirtForeignMenu *ovirt_foreign_menu;
|
|
#endif
|
|
gboolean open_recent_dialog;
|
|
};
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (RemoteViewer, remote_viewer, VIRT_VIEWER_TYPE_APP)
|
|
|
|
enum RemoteViewerProperties {
|
|
PROP_0,
|
|
#ifdef HAVE_OVIRT
|
|
PROP_OVIRT_FOREIGN_MENU,
|
|
#endif
|
|
};
|
|
|
|
#ifdef HAVE_OVIRT
|
|
static OvirtVm * choose_vm(GtkWindow *main_window,
|
|
char **vm_name,
|
|
OvirtCollection *vms,
|
|
GError **error);
|
|
#endif
|
|
|
|
static gboolean remote_viewer_start(VirtViewerApp *self, GError **error);
|
|
|
|
static void
|
|
remote_viewer_dispose (GObject *object)
|
|
{
|
|
#if defined(HAVE_OVIRT)
|
|
RemoteViewer *self = REMOTE_VIEWER(object);
|
|
RemoteViewerPrivate *priv = self->priv;
|
|
#endif
|
|
|
|
#ifdef HAVE_OVIRT
|
|
if (priv->ovirt_foreign_menu) {
|
|
g_object_unref(priv->ovirt_foreign_menu);
|
|
priv->ovirt_foreign_menu = NULL;
|
|
}
|
|
#endif
|
|
|
|
G_OBJECT_CLASS(remote_viewer_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
remote_viewer_deactivated(VirtViewerApp *app, gboolean connect_error)
|
|
{
|
|
RemoteViewer *self = REMOTE_VIEWER(app);
|
|
RemoteViewerPrivate *priv = self->priv;
|
|
|
|
if (connect_error && priv->open_recent_dialog) {
|
|
if (virt_viewer_app_start(app, NULL)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
VIRT_VIEWER_APP_CLASS(remote_viewer_parent_class)->deactivated(app, connect_error);
|
|
}
|
|
|
|
static gchar **opt_args = NULL;
|
|
static char *opt_title = NULL;
|
|
|
|
static void
|
|
remote_viewer_add_option_entries(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group)
|
|
{
|
|
static const GOptionEntry options[] = {
|
|
{ "title", 't', 0, G_OPTION_ARG_STRING, &opt_title,
|
|
N_("Set window title"), NULL },
|
|
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &opt_args,
|
|
NULL, "URI|VV-FILE" },
|
|
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
|
|
};
|
|
|
|
VIRT_VIEWER_APP_CLASS(remote_viewer_parent_class)->add_option_entries(self, context, group);
|
|
g_option_context_set_summary(context, _("Remote viewer client"));
|
|
g_option_group_add_entries(group, options);
|
|
|
|
#ifdef HAVE_OVIRT
|
|
g_option_context_add_group (context, ovirt_get_option_group ());
|
|
#endif
|
|
}
|
|
|
|
static gboolean
|
|
remote_viewer_local_command_line (GApplication *gapp,
|
|
gchar ***args,
|
|
int *status)
|
|
{
|
|
gboolean ret = FALSE;
|
|
VirtViewerApp *app = VIRT_VIEWER_APP(gapp);
|
|
RemoteViewer *self = REMOTE_VIEWER(app);
|
|
|
|
ret = G_APPLICATION_CLASS(remote_viewer_parent_class)->local_command_line(gapp, args, status);
|
|
if (ret)
|
|
goto end;
|
|
|
|
if (!opt_args) {
|
|
self->priv->open_recent_dialog = TRUE;
|
|
} else {
|
|
if (g_strv_length(opt_args) > 1) {
|
|
g_printerr(_("\nError: can't handle multiple URIs\n\n"));
|
|
ret = TRUE;
|
|
*status = 1;
|
|
goto end;
|
|
}
|
|
|
|
g_object_set(app, "guri", opt_args[0], NULL);
|
|
}
|
|
|
|
if (opt_title)
|
|
g_object_set(app, "title", opt_title, NULL);
|
|
|
|
end:
|
|
if (ret && *status)
|
|
g_printerr(_("Run '%s --help' to see a full list of available command line options\n"), g_get_prgname());
|
|
|
|
g_strfreev(opt_args);
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
remote_viewer_get_property(GObject *object, guint property_id,
|
|
GValue *value G_GNUC_UNUSED,
|
|
GParamSpec *pspec)
|
|
{
|
|
#ifdef HAVE_OVIRT
|
|
RemoteViewer *self = REMOTE_VIEWER(object);
|
|
RemoteViewerPrivate *priv = self->priv;
|
|
#endif
|
|
|
|
switch (property_id) {
|
|
#ifdef HAVE_OVIRT
|
|
case PROP_OVIRT_FOREIGN_MENU:
|
|
g_value_set_object(value, priv->ovirt_foreign_menu);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
remote_viewer_class_init (RemoteViewerClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
VirtViewerAppClass *app_class = VIRT_VIEWER_APP_CLASS (klass);
|
|
GApplicationClass *g_app_class = G_APPLICATION_CLASS(klass);
|
|
|
|
object_class->get_property = remote_viewer_get_property;
|
|
object_class->dispose = remote_viewer_dispose;
|
|
|
|
g_app_class->local_command_line = remote_viewer_local_command_line;
|
|
|
|
app_class->start = remote_viewer_start;
|
|
app_class->deactivated = remote_viewer_deactivated;
|
|
app_class->add_option_entries = remote_viewer_add_option_entries;
|
|
|
|
#ifdef HAVE_OVIRT
|
|
g_object_class_install_property(object_class,
|
|
PROP_OVIRT_FOREIGN_MENU,
|
|
g_param_spec_object("ovirt-foreign-menu",
|
|
"oVirt Foreign Menu",
|
|
"Object which is used as interface to oVirt",
|
|
OVIRT_TYPE_FOREIGN_MENU,
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
remote_viewer_init(RemoteViewer *self)
|
|
{
|
|
self->priv = remote_viewer_get_instance_private(self);
|
|
}
|
|
|
|
RemoteViewer *
|
|
remote_viewer_new(void)
|
|
{
|
|
return g_object_new(REMOTE_VIEWER_TYPE,
|
|
"application-id", "org.virt-manager.remote-viewer",
|
|
"flags", G_APPLICATION_NON_UNIQUE,
|
|
NULL);
|
|
}
|
|
|
|
#if defined(HAVE_SPICE_GTK) && defined(HAVE_OVIRT)
|
|
static SpiceSession *
|
|
remote_viewer_get_spice_session(RemoteViewer *self)
|
|
{
|
|
VirtViewerSession *vsession = NULL;
|
|
SpiceSession *session = NULL;
|
|
|
|
g_object_get(self, "session", &vsession, NULL);
|
|
g_return_val_if_fail(vsession != NULL, NULL);
|
|
|
|
g_object_get(vsession, "spice-session", &session, NULL);
|
|
|
|
g_object_unref(vsession);
|
|
|
|
return session;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_OVIRT
|
|
static gboolean
|
|
parse_ovirt_uri(const gchar *uri_str, char **rest_uri, char **name, char **username)
|
|
{
|
|
char *vm_name = NULL;
|
|
char *rel_path;
|
|
xmlURIPtr uri;
|
|
gchar **path_elements;
|
|
guint element_count;
|
|
|
|
g_return_val_if_fail(uri_str != NULL, FALSE);
|
|
g_return_val_if_fail(rest_uri != NULL, FALSE);
|
|
g_return_val_if_fail(name != NULL, FALSE);
|
|
|
|
uri = xmlParseURI(uri_str);
|
|
g_return_val_if_fail(uri != NULL, FALSE);
|
|
|
|
if (g_strcmp0(uri->scheme, "ovirt") != 0) {
|
|
xmlFreeURI(uri);
|
|
return FALSE;
|
|
}
|
|
|
|
if (username && uri->user)
|
|
*username = g_strdup(uri->user);
|
|
|
|
if (uri->path == NULL) {
|
|
*name = NULL;
|
|
*rest_uri = g_strdup(uri->server);
|
|
xmlFreeURI(uri);
|
|
return TRUE;
|
|
}
|
|
|
|
if (*uri->path != '/') {
|
|
xmlFreeURI(uri);
|
|
return FALSE;
|
|
}
|
|
|
|
/* extract VM name from path */
|
|
path_elements = g_strsplit(uri->path, "/", -1);
|
|
|
|
element_count = g_strv_length(path_elements);
|
|
if (element_count == 0) {
|
|
g_strfreev(path_elements);
|
|
return FALSE;
|
|
}
|
|
vm_name = path_elements[element_count-1];
|
|
path_elements[element_count-1] = NULL;
|
|
|
|
/* build final URI */
|
|
rel_path = g_strjoinv("/", path_elements);
|
|
*rest_uri = g_strdup_printf("%s%s", uri->server, rel_path);
|
|
*name = vm_name;
|
|
g_free(rel_path);
|
|
g_strfreev(path_elements);
|
|
xmlFreeURI(uri);
|
|
|
|
g_debug("oVirt base URI: %s", *rest_uri);
|
|
g_debug("oVirt VM name: %s", *name);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
authenticate_cb(RestProxy *proxy, G_GNUC_UNUSED RestProxyAuth *auth,
|
|
G_GNUC_UNUSED gboolean retrying, gpointer user_data)
|
|
{
|
|
gchar *username = NULL;
|
|
gchar *password = NULL;
|
|
VirtViewerWindow *window;
|
|
gboolean success = FALSE;
|
|
gboolean kiosk = FALSE;
|
|
|
|
g_object_get(proxy,
|
|
"username", &username,
|
|
NULL);
|
|
|
|
g_object_get(G_OBJECT(user_data), "kiosk", &kiosk, NULL);
|
|
|
|
if (username == NULL || *username == '\0')
|
|
username = g_strdup(g_get_user_name());
|
|
|
|
window = virt_viewer_app_get_main_window(VIRT_VIEWER_APP(user_data));
|
|
do {
|
|
success = virt_viewer_auth_collect_credentials(virt_viewer_window_get_window(window),
|
|
"oVirt",
|
|
NULL,
|
|
&username, &password);
|
|
} while (kiosk && !success);
|
|
|
|
if (success) {
|
|
g_object_set(G_OBJECT(proxy),
|
|
"username", username,
|
|
"password", password,
|
|
NULL);
|
|
} else {
|
|
rest_proxy_auth_cancel(auth);
|
|
}
|
|
|
|
g_free(username);
|
|
g_free(password);
|
|
return success;
|
|
}
|
|
|
|
static void
|
|
ovirt_foreign_menu_update(GtkApplication *gtkapp, GtkWindow *gtkwin, G_GNUC_UNUSED gpointer data)
|
|
{
|
|
RemoteViewer *self = REMOTE_VIEWER(gtkapp);
|
|
VirtViewerWindow *win = g_object_get_data(G_OBJECT(gtkwin), "virt-viewer-window");
|
|
GtkBuilder *builder = virt_viewer_window_get_builder(win);
|
|
GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(builder, "menu-change-cd"));
|
|
gtk_widget_set_visible(menu, self->priv->ovirt_foreign_menu != NULL);
|
|
}
|
|
|
|
static void
|
|
ovirt_foreign_menu_update_each(gpointer value,
|
|
gpointer user_data)
|
|
{
|
|
ovirt_foreign_menu_update(GTK_APPLICATION(user_data),
|
|
virt_viewer_window_get_window(VIRT_VIEWER_WINDOW(value)),
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
ovirt_foreign_menu_updated(RemoteViewer *self)
|
|
{
|
|
GList *windows = virt_viewer_app_get_windows(VIRT_VIEWER_APP(self));
|
|
|
|
g_debug("Spice foreign menu updated");
|
|
|
|
g_list_foreach(windows, ovirt_foreign_menu_update_each, self);
|
|
}
|
|
|
|
static void
|
|
virt_viewer_app_set_ovirt_foreign_menu(VirtViewerApp *app,
|
|
OvirtForeignMenu *foreign_menu)
|
|
{
|
|
RemoteViewer *self;
|
|
g_return_if_fail(REMOTE_VIEWER_IS(app));
|
|
g_return_if_fail(OVIRT_IS_FOREIGN_MENU(foreign_menu));
|
|
|
|
self = REMOTE_VIEWER(app);
|
|
g_clear_object(&self->priv->ovirt_foreign_menu);
|
|
self->priv->ovirt_foreign_menu = foreign_menu;
|
|
g_signal_connect(G_OBJECT(app), "window-added",
|
|
(GCallback)ovirt_foreign_menu_update, NULL);
|
|
ovirt_foreign_menu_updated(self);
|
|
}
|
|
|
|
static gboolean
|
|
create_ovirt_session(VirtViewerApp *app, const char *uri, GError **err)
|
|
{
|
|
OvirtProxy *proxy = NULL;
|
|
OvirtApi *api = NULL;
|
|
OvirtCollection *vms;
|
|
OvirtVm *vm = NULL;
|
|
OvirtVmDisplay *display = NULL;
|
|
OvirtVmState state;
|
|
GError *error = NULL;
|
|
char *rest_uri = NULL;
|
|
char *vm_name = NULL;
|
|
char *username = NULL;
|
|
gboolean success = FALSE;
|
|
guint port;
|
|
guint secure_port;
|
|
char *proxy_url = NULL;
|
|
OvirtVmDisplayType type;
|
|
const char *session_type;
|
|
|
|
gchar *gport = NULL;
|
|
gchar *gtlsport = NULL;
|
|
gchar *ghost = NULL;
|
|
gchar *ticket = NULL;
|
|
gchar *host_subject = NULL;
|
|
gchar *guid = NULL;
|
|
|
|
g_return_val_if_fail(VIRT_VIEWER_IS_APP(app), FALSE);
|
|
|
|
if (!parse_ovirt_uri(uri, &rest_uri, &vm_name, &username)) {
|
|
g_set_error_literal(&error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_FAILED,
|
|
_("failed to parse ovirt uri"));
|
|
goto error;
|
|
}
|
|
|
|
proxy = ovirt_proxy_new(rest_uri);
|
|
g_object_set(proxy,
|
|
"username", username,
|
|
NULL);
|
|
ovirt_set_proxy_options(proxy);
|
|
g_signal_connect(G_OBJECT(proxy), "authenticate",
|
|
G_CALLBACK(authenticate_cb), app);
|
|
|
|
api = ovirt_proxy_fetch_api(proxy, &error);
|
|
if (error != NULL) {
|
|
g_debug("failed to get oVirt 'api' collection: %s", error->message);
|
|
if (g_error_matches(error, OVIRT_REST_CALL_ERROR, OVIRT_REST_CALL_ERROR_CANCELLED)) {
|
|
g_clear_error(&error);
|
|
g_set_error_literal(&error,
|
|
VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_CANCELLED,
|
|
_("Authentication was cancelled"));
|
|
}
|
|
goto error;
|
|
}
|
|
vms = ovirt_api_get_vms(api);
|
|
ovirt_collection_fetch(vms, proxy, &error);
|
|
if (error != NULL) {
|
|
g_debug("failed to fetch oVirt 'vms' collection: %s", error->message);
|
|
goto error;
|
|
}
|
|
if (vm_name == NULL ||
|
|
(vm = OVIRT_VM(ovirt_collection_lookup_resource(vms, vm_name))) == NULL) {
|
|
VirtViewerWindow *main_window = virt_viewer_app_get_main_window(app);
|
|
vm = choose_vm(virt_viewer_window_get_window(main_window),
|
|
&vm_name,
|
|
vms,
|
|
&error);
|
|
if (vm == NULL) {
|
|
goto error;
|
|
}
|
|
}
|
|
g_object_get(G_OBJECT(vm), "state", &state, NULL);
|
|
if (state != OVIRT_VM_STATE_UP) {
|
|
g_set_error(&error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_FAILED,
|
|
_("oVirt VM %s is not running"), vm_name);
|
|
g_debug("%s", error->message);
|
|
goto error;
|
|
}
|
|
g_object_set(app, "guest-name", vm_name, NULL);
|
|
|
|
if (!ovirt_vm_get_ticket(vm, proxy, &error)) {
|
|
g_debug("failed to get ticket for %s: %s", vm_name, error->message);
|
|
goto error;
|
|
}
|
|
|
|
g_object_get(G_OBJECT(vm), "display", &display, "guid", &guid, NULL);
|
|
if (display == NULL) {
|
|
g_set_error(&error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_FAILED,
|
|
_("oVirt VM %s has no display"), vm_name);
|
|
goto error;
|
|
}
|
|
|
|
if (guid != NULL) {
|
|
g_object_set(app, "uuid", guid, NULL);
|
|
}
|
|
|
|
g_object_get(G_OBJECT(display),
|
|
"type", &type,
|
|
"address", &ghost,
|
|
"port", &port,
|
|
"secure-port", &secure_port,
|
|
"ticket", &ticket,
|
|
"host-subject", &host_subject,
|
|
"proxy-url", &proxy_url,
|
|
NULL);
|
|
if (port != 0) {
|
|
gport = g_strdup_printf("%u", port);
|
|
}
|
|
if (secure_port != 0) {
|
|
gtlsport = g_strdup_printf("%u", secure_port);
|
|
}
|
|
|
|
if (ghost == NULL) {
|
|
g_set_error(&error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_FAILED,
|
|
_("oVirt VM %s has no host information"), vm_name);
|
|
g_debug("%s", error->message);
|
|
goto error;
|
|
}
|
|
|
|
if (type == OVIRT_VM_DISPLAY_SPICE) {
|
|
session_type = "spice";
|
|
} else if (type == OVIRT_VM_DISPLAY_VNC) {
|
|
session_type = "vnc";
|
|
} else {
|
|
g_set_error(&error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_FAILED,
|
|
_("oVirt VM %s has unknown display type: %u"), vm_name, type);
|
|
g_debug("%s", error->message);
|
|
goto error;
|
|
}
|
|
|
|
{
|
|
OvirtForeignMenu *ovirt_menu = ovirt_foreign_menu_new(proxy);
|
|
g_object_set(G_OBJECT(ovirt_menu), "api", api, "vm", vm, NULL);
|
|
virt_viewer_app_set_ovirt_foreign_menu(app, ovirt_menu);
|
|
}
|
|
|
|
virt_viewer_app_set_connect_info(app, NULL, ghost, gport, gtlsport,
|
|
session_type, NULL, NULL, 0, NULL);
|
|
|
|
if (!virt_viewer_app_create_session(app, session_type, &error))
|
|
goto error;
|
|
|
|
#ifdef HAVE_SPICE_GTK
|
|
if (type == OVIRT_VM_DISPLAY_SPICE) {
|
|
SpiceSession *session;
|
|
GByteArray *ca_cert = NULL;
|
|
const char *from = "display";
|
|
|
|
session = remote_viewer_get_spice_session(REMOTE_VIEWER(app));
|
|
g_object_set(G_OBJECT(session),
|
|
"password", ticket,
|
|
"cert-subject", host_subject,
|
|
"proxy", proxy_url,
|
|
NULL);
|
|
|
|
g_object_get(G_OBJECT(display), "ca-cert", &ca_cert, NULL);
|
|
if (ca_cert == NULL) {
|
|
g_object_get(G_OBJECT(proxy), "ca-cert", &ca_cert, NULL);
|
|
from = "proxy";
|
|
}
|
|
|
|
if (ca_cert != NULL) {
|
|
g_object_set(G_OBJECT(session),
|
|
"ca", ca_cert,
|
|
NULL);
|
|
g_byte_array_unref(ca_cert);
|
|
g_debug("Using ca-cert from %s", from);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
success = TRUE;
|
|
|
|
error:
|
|
g_free(username);
|
|
g_free(rest_uri);
|
|
g_free(vm_name);
|
|
g_free(ticket);
|
|
g_free(gport);
|
|
g_free(gtlsport);
|
|
g_free(ghost);
|
|
g_free(host_subject);
|
|
g_free(guid);
|
|
g_free(proxy_url);
|
|
|
|
if (error != NULL)
|
|
g_propagate_error(err, error);
|
|
if (display != NULL)
|
|
g_object_unref(display);
|
|
if (vm != NULL)
|
|
g_object_unref(vm);
|
|
if (proxy != NULL)
|
|
g_object_unref(proxy);
|
|
|
|
return success;
|
|
}
|
|
|
|
static OvirtVm *
|
|
choose_vm(GtkWindow *main_window,
|
|
char **vm_name,
|
|
OvirtCollection *vms_collection,
|
|
GError **error)
|
|
{
|
|
GtkListStore *model;
|
|
GtkTreeIter iter;
|
|
GHashTable *vms;
|
|
GHashTableIter vms_iter;
|
|
OvirtVmState state;
|
|
OvirtVm *vm;
|
|
|
|
g_return_val_if_fail(vm_name != NULL, NULL);
|
|
free(*vm_name);
|
|
|
|
model = gtk_list_store_new(1, G_TYPE_STRING);
|
|
|
|
vms = ovirt_collection_get_resources(vms_collection);
|
|
g_hash_table_iter_init(&vms_iter, vms);
|
|
while (g_hash_table_iter_next(&vms_iter, (gpointer *) vm_name, (gpointer *) &vm)) {
|
|
g_object_get(G_OBJECT(vm), "state", &state, NULL);
|
|
if (state == OVIRT_VM_STATE_UP) {
|
|
gtk_list_store_append(model, &iter);
|
|
gtk_list_store_set(model, &iter, 0, *vm_name, -1);
|
|
}
|
|
}
|
|
|
|
*vm_name = virt_viewer_vm_connection_choose_name_dialog(main_window,
|
|
GTK_TREE_MODEL(model),
|
|
error);
|
|
g_object_unref(model);
|
|
if (*vm_name == NULL)
|
|
return NULL;
|
|
|
|
vm = OVIRT_VM(ovirt_collection_lookup_resource(vms_collection, *vm_name));
|
|
|
|
return vm;
|
|
}
|
|
#endif /* HAVE_OVIRT */
|
|
|
|
static void
|
|
remote_viewer_recent_add(gchar *uri, const gchar *mime_type)
|
|
{
|
|
GtkRecentManager *recent;
|
|
GtkRecentData meta = {
|
|
.app_name = (char*)"remote-viewer",
|
|
.app_exec = (char*)"remote-viewer %u",
|
|
.mime_type = (char*)mime_type,
|
|
};
|
|
|
|
g_return_if_fail(uri != NULL);
|
|
|
|
recent = gtk_recent_manager_get_default();
|
|
meta.display_name = uri;
|
|
if (!gtk_recent_manager_add_full(recent, uri, &meta))
|
|
g_warning("Recent item couldn't be added");
|
|
}
|
|
|
|
static void
|
|
remote_viewer_session_connected(VirtViewerSession *session,
|
|
const gchar *guri)
|
|
{
|
|
gchar *uri = virt_viewer_session_get_uri(session);
|
|
const gchar *mime = virt_viewer_session_mime_type(session);
|
|
|
|
remote_viewer_recent_add(uri != NULL ? uri : (char *) guri, mime);
|
|
g_free(uri);
|
|
}
|
|
|
|
static gchar *
|
|
read_all_stdin(gsize *len, GError **err)
|
|
{
|
|
GIOChannel *ioc = g_io_channel_unix_new(fileno(stdin));
|
|
gchar *content = NULL;
|
|
GIOStatus status;
|
|
|
|
status = g_io_channel_read_to_end(ioc, &content, len, err);
|
|
g_assert(status != G_IO_STATUS_AGAIN);
|
|
|
|
g_io_channel_unref(ioc);
|
|
g_assert((content && !*err) || (!content && *err));
|
|
|
|
return content;
|
|
}
|
|
|
|
static gboolean
|
|
remote_viewer_initial_connect(RemoteViewer *self, const gchar *type, const gchar *guri,
|
|
VirtViewerFile *vvfile, GError **error)
|
|
{
|
|
VirtViewerApp *app = VIRT_VIEWER_APP(self);
|
|
|
|
#ifdef HAVE_OVIRT
|
|
if (g_strcmp0(type, "ovirt") == 0) {
|
|
if (!create_ovirt_session(app, guri, error)) {
|
|
g_prefix_error(error, _("Couldn't open oVirt session: "));
|
|
return FALSE;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
if (!virt_viewer_app_create_session(app, type, error))
|
|
return FALSE;
|
|
}
|
|
|
|
g_signal_connect(virt_viewer_app_get_session(app), "session-connected",
|
|
G_CALLBACK(remote_viewer_session_connected), (gpointer) g_intern_string(guri));
|
|
|
|
virt_viewer_session_set_file(virt_viewer_app_get_session(app), vvfile);
|
|
#ifdef HAVE_OVIRT
|
|
if (vvfile != NULL) {
|
|
OvirtForeignMenu *ovirt_menu;
|
|
ovirt_menu = ovirt_foreign_menu_new_from_file(vvfile);
|
|
if (ovirt_menu != NULL) {
|
|
virt_viewer_app_set_ovirt_foreign_menu(app, ovirt_menu);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!virt_viewer_app_initial_connect(app, error)) {
|
|
if (*error == NULL) {
|
|
g_set_error_literal(error,
|
|
VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_FAILED,
|
|
_("Failed to initiate connection"));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
remote_viewer_start(VirtViewerApp *app, GError **err)
|
|
{
|
|
g_return_val_if_fail(REMOTE_VIEWER_IS(app), FALSE);
|
|
|
|
RemoteViewer *self = REMOTE_VIEWER(app);
|
|
RemoteViewerPrivate *priv = self->priv;
|
|
GFile *file = NULL;
|
|
VirtViewerFile *vvfile = NULL;
|
|
gboolean ret = FALSE;
|
|
gchar *guri = NULL;
|
|
gchar *type = NULL;
|
|
GError *error = NULL;
|
|
|
|
retry_dialog:
|
|
{
|
|
if (priv->open_recent_dialog) {
|
|
VirtViewerWindow *main_window = virt_viewer_app_get_main_window(app);
|
|
if (!remote_viewer_connect_dialog(virt_viewer_window_get_window(main_window), &guri)) {
|
|
g_set_error_literal(&error,
|
|
VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_CANCELLED,
|
|
_("No connection was chosen"));
|
|
g_propagate_error(err, error);
|
|
return FALSE;
|
|
}
|
|
g_object_set(app, "guri", guri, NULL);
|
|
} else
|
|
g_object_get(app, "guri", &guri, NULL);
|
|
|
|
g_return_val_if_fail(guri != NULL, FALSE);
|
|
|
|
g_debug("Opening display to %s", guri);
|
|
|
|
if (!g_strcmp0(guri, "-")) {
|
|
gsize len = 0;
|
|
gchar *buf = read_all_stdin(&len, &error);
|
|
|
|
if (error) {
|
|
g_prefix_error(&error, _("Failed to read stdin: "));
|
|
g_warning("%s", error->message);
|
|
goto cleanup;
|
|
}
|
|
|
|
vvfile = virt_viewer_file_new_from_buffer(buf, len, &error);
|
|
g_free(buf);
|
|
} else {
|
|
file = g_file_new_for_commandline_arg(guri);
|
|
if (g_file_query_exists(file, NULL)) {
|
|
gchar *path = g_file_get_path(file);
|
|
vvfile = virt_viewer_file_new(path, &error);
|
|
g_free(path);
|
|
}
|
|
}
|
|
|
|
if (error) {
|
|
g_prefix_error(&error, _("Invalid file %s: "), guri);
|
|
g_warning("%s", error->message);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (vvfile) {
|
|
g_object_get(G_OBJECT(vvfile), "type", &type, NULL);
|
|
} else if (virt_viewer_util_extract_host(guri, &type, NULL, NULL, NULL, NULL) < 0 || type == NULL) {
|
|
g_set_error_literal(&error,
|
|
VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_FAILED,
|
|
_("Cannot determine the connection type from URI"));
|
|
goto cleanup;
|
|
}
|
|
if (!remote_viewer_initial_connect(self, type, guri, vvfile, &error))
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = VIRT_VIEWER_APP_CLASS(remote_viewer_parent_class)->start(app, &error);
|
|
|
|
cleanup:
|
|
g_clear_object(&file);
|
|
g_clear_object(&vvfile);
|
|
g_free(guri);
|
|
guri = NULL;
|
|
g_free(type);
|
|
type = NULL;
|
|
|
|
if (!ret && priv->open_recent_dialog) {
|
|
if (error != NULL) {
|
|
virt_viewer_app_simple_message_dialog(app, _("Unable to connect: %s"), error->message);
|
|
}
|
|
g_clear_error(&error);
|
|
goto retry_dialog;
|
|
}
|
|
if (error != NULL)
|
|
g_propagate_error(err, error);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 4
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|