/* Copyright (C) 2010 Red Hat, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include "click.h" static void shutdown (self_t *self); static int click (struct self_t *self, int x, int y, int b); static char *host; static char *port; static char *tls_port; static char *password; static char *uri; static char *ca_file; static char *host_subject; static char *smartcard_db; static char *smartcard_certificates; static gboolean smartcard = FALSE; static GOptionEntry spice_entries[] = { { .long_name = "spice-uri", .arg = G_OPTION_ARG_STRING, .arg_data = &uri, .description = N_("Spice server uri"), .arg_description = N_(""), },{ .long_name = "spice-host", .arg = G_OPTION_ARG_STRING, .arg_data = &host, .description = N_("Spice server address"), .arg_description = N_(""), },{ .long_name = "spice-port", .arg = G_OPTION_ARG_STRING, .arg_data = &port, .description = N_("Spice server port"), .arg_description = N_(""), },{ .long_name = "spice-secure-port", .arg = G_OPTION_ARG_STRING, .arg_data = &tls_port, .description = N_("Spice server secure port"), .arg_description = N_(""), },{ .long_name = "spice-ca-file", .arg = G_OPTION_ARG_FILENAME, .arg_data = &ca_file, .description = N_("Truststore file for secure connections"), .arg_description = N_(""), },{ .long_name = "spice-password", .arg = G_OPTION_ARG_STRING, .arg_data = &password, .description = N_("Server password"), .arg_description = N_(""), },{ .long_name = "spice-host-subject", .arg = G_OPTION_ARG_STRING, .arg_data = &host_subject, .description = N_("Subject of the host certificate (field=value pairs separated by commas)"), .arg_description = N_(""), },{ /* end of list */ } }; static GOptionGroup *spice_group; GOptionGroup * vc_spice_cmdline_get_option_group(void) { if (spice_group == NULL) { spice_group = g_option_group_new("spice", _("Spice Options:"), _("Show spice Options"), NULL, NULL); g_option_group_add_entries(spice_group, spice_entries); } return spice_group; } static void primary_create (SpiceChannel *channel, gint format, gint width, gint height, gint stride, gint shmid, gpointer imgdata, gpointer opaque) { self_t *self = opaque; if (verbose) fprintf (stderr, "Connected to spice server (primary display channel)\n"); /* Remember that we managed to connect. */ self->connected = TRUE; vc_issue_command (self); } static void channel_new (SpiceSession *s, SpiceChannel *channel, gpointer opaque) { self_t *self = opaque; if (SPICE_IS_INPUTS_CHANNEL (channel)) self->inputs_channel = channel; if (SPICE_IS_DISPLAY_CHANNEL (channel)) self->display_channel = channel; if (SPICE_IS_DISPLAY_CHANNEL (channel)) g_signal_connect (channel, "display-primary-create", G_CALLBACK (primary_create), self); spice_channel_connect (channel); } static callbacks_t callbacks = { .click = click, .shutdown = shutdown, }; void vc_spice_setup (self_t *self) { if (verbose) spice_util_set_debug (TRUE); self->callbacks = &callbacks; self->session = spice_session_new (); g_signal_connect (self->session, "channel-new", G_CALLBACK(channel_new), self); if (ca_file == NULL) { const char *homedir = g_getenv("HOME"); if (!homedir) homedir = g_get_home_dir(); ca_file = g_strdup_printf("%s/.spicec/spice_truststore.pem", homedir); } if (uri) g_object_set(self->session, "uri", uri, NULL); if (host) g_object_set(self->session, "host", host, NULL); if (port) g_object_set(self->session, "port", port, NULL); if (tls_port) g_object_set(self->session, "tls-port", tls_port, NULL); if (password) g_object_set(self->session, "password", password, NULL); if (ca_file) g_object_set(self->session, "ca-file", ca_file, NULL); if (host_subject) g_object_set(self->session, "cert-subject", host_subject, NULL); if (!spice_session_connect (self->session)) { fprintf (stderr, _("spice: session connection failed\n")); exit (EXIT_FAILURE); } } gboolean vc_spice_is_selected (void) { return uri != NULL || host != NULL; } static int get_channel_id (SpiceChannel *channel) { int id; g_object_get (channel, "channel-id", &id, NULL); return id; } static void shutdown (self_t *self) { spice_session_disconnect (self->session); g_object_unref (self->session); } static int click (struct self_t *self, int x, int y, int b) { int id = get_channel_id (self->display_channel); spice_inputs_position (SPICE_INPUTS_CHANNEL (self->inputs_channel), x, y, id, 0); switch (b) { case 0: b = 0; break; case 1: b = SPICE_MOUSE_BUTTON_LEFT; break; case 2: b = SPICE_MOUSE_BUTTON_MIDDLE; break; case 3: b = SPICE_MOUSE_BUTTON_RIGHT; break; case 4: b = SPICE_MOUSE_BUTTON_UP; break; case 5: b = SPICE_MOUSE_BUTTON_DOWN; break; default: fprintf (stderr, "spice: button %d is not supported\n", b); return -1; } if (b) spice_inputs_button_press (SPICE_INPUTS_CHANNEL (self->inputs_channel), b, 0); return 0; }