/* * Copyright © 2012 Canonical Ltd. * Copyright © 2015 The Arctica Project * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . * * Authors: Ted Gould * Mike Gabriel */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "server.h" #include "defines.h" #include "citrix-server.h" #include "rdp-server.h" #include "uccs-server.h" #include "x2go-server.h" static void server_class_init (ServerClass *klass); static void server_init (Server *self); static void server_dispose (GObject *object); static void server_finalize (GObject *object); /* Signals */ enum { STATE_CHANGED, LAST_SIGNAL }; G_DEFINE_TYPE (Server, server, G_TYPE_OBJECT); static guint signals[LAST_SIGNAL] = { 0 }; static void server_class_init (ServerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = server_dispose; object_class->finalize = server_finalize; signals[STATE_CHANGED] = g_signal_new(SERVER_SIGNAL_STATE_CHANGED, G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(ServerClass, state_changed), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT, G_TYPE_NONE); return; } static void server_init (Server *self) { self->name = NULL; self->uri = NULL; self->last_used = FALSE; self->state = SERVER_STATE_ALLGOOD; return; } static void server_dispose (GObject *object) { G_OBJECT_CLASS (server_parent_class)->dispose (object); return; } static void server_finalize (GObject *object) { Server * server = SERVER(object); g_free(server->name); g_free(server->uri); G_OBJECT_CLASS (server_parent_class)->finalize (object); return; } /** * server_new_from_keyfile: * @keyfile: The keyfile with the @group in it to define the server * @group: Group name for this server * * Looks at a group within the keyfile and builds a server based on * it's type. Mostly works with a subclass based on the type. * * Return value: A new Server object or NULL if error */ Server * server_new_from_keyfile (GKeyFile * keyfile, const gchar * group) { g_return_val_if_fail(keyfile != NULL, NULL); g_return_val_if_fail(group != NULL, NULL); if (!g_key_file_has_group(keyfile, group)) { return NULL; } gchar * type = NULL; if (g_key_file_has_key(keyfile, group, CONFIG_SERVER_TYPE, NULL)) { type = g_key_file_get_string(keyfile, group, CONFIG_SERVER_TYPE, NULL); } if (g_strcmp0(type, CONFIG_SERVER_TYPE_RDP) == 0) { return SERVER(rdp_server_new_from_keyfile(keyfile, group)); } else if (g_strcmp0(type, CONFIG_SERVER_TYPE_ICA) == 0) { return SERVER(citrix_server_new_from_keyfile(keyfile, group)); } else { return SERVER(uccs_server_new_from_keyfile(keyfile, group)); } return NULL; } /** * server_new_from_json: * @object: JSON object with server definition * * Looks at the type and then uses a subclassed function to build the * server. * * Return value: A new Server object or NULL if error */ Server * server_new_from_json (JsonObject * object) { g_return_val_if_fail(object != NULL, NULL); if (!json_object_has_member(object, "Protocol")) { return NULL; } JsonNode * proto_node = json_object_get_member(object, "Protocol"); if (JSON_NODE_TYPE(proto_node) != JSON_NODE_VALUE) { return NULL; } if (json_node_get_value_type(proto_node) != G_TYPE_STRING) { return NULL; } const gchar * proto = json_node_get_string(proto_node); Server * newserver = NULL; if (g_strcmp0(proto, "ICA") == 0 || g_strcmp0(proto, "ica") == 0) { newserver = citrix_server_new_from_json(object); } else if (g_strcmp0(proto, "freerdp") == 0 || g_strcmp0(proto, "rdp") == 0 || g_strcmp0(proto, "freerdp2") == 0 || g_strcmp0(proto, "RDP") == 0 || g_strcmp0(proto, "FreeRDP") == 0 || g_strcmp0(proto, "FreeRDP2") == 0) { newserver = rdp_server_new_from_json(object); } else if (g_strcmp0(proto, "x2go") == 0 || g_strcmp0(proto, "X2go") == 0 || g_strcmp0(proto, "X2Go") == 0 || g_strcmp0(proto, "X2GO") == 0 || g_strcmp0(proto, "x2GO") == 0 || g_strcmp0(proto, "x2gO") == 0) { newserver = x2go_server_new_from_json(object); } return newserver; } GVariant * server_get_variant (Server * server) { /* Okay, this doesn't do anything useful, but it will generate an error which could be a good thing */ g_return_val_if_fail(IS_SERVER(server), NULL); ServerClass * klass = SERVER_GET_CLASS(server); if (klass->get_properties != NULL) { GVariantBuilder tuple; g_variant_builder_init(&tuple, G_VARIANT_TYPE_TUPLE); if (IS_CITRIX_SERVER(server)) { g_variant_builder_add_value(&tuple, g_variant_new_string("ica")); } else if (IS_RDP_SERVER(server)) { g_variant_builder_add_value(&tuple, g_variant_new_string("freerdp2")); } else if (IS_UCCS_SERVER(server)) { g_variant_builder_add_value(&tuple, g_variant_new_string("uccs")); } else if (IS_X2GO_SERVER(server)) { g_variant_builder_add_value(&tuple, g_variant_new_string("x2go")); } else { g_assert_not_reached(); } if (server->name != NULL) { g_variant_builder_add_value(&tuple, g_variant_new_string(server->name)); } else { g_warning("Server has no name"); g_variant_builder_add_value(&tuple, g_variant_new_string("")); } if (server->uri != NULL) { g_variant_builder_add_value(&tuple, g_variant_new_string(server->uri)); } else { g_warning("Server has no URI"); g_variant_builder_add_value(&tuple, g_variant_new_string("")); } g_variant_builder_add_value(&tuple, g_variant_new_boolean(server->last_used)); GVariant * props = klass->get_properties(server); g_variant_builder_add_value(&tuple, props); if (klass->get_applications != NULL) { GVariant * array = klass->get_applications(server); g_variant_builder_add_value(&tuple, array); } else { /* NULL array of applications */ g_variant_builder_add_value(&tuple, g_variant_new_array(G_VARIANT_TYPE("(si)"), NULL, 0)); } return g_variant_builder_end(&tuple); } return NULL; } /** * server_cached_domains: * @server: Where should we find those domains? * * Gets a list of cached domains for a particular server, if this function * isn't overriden, then a null array is returned. */ GVariant * server_cached_domains (Server * server) { g_return_val_if_fail(IS_SERVER(server), NULL); ServerClass * klass = SERVER_GET_CLASS(server); if (klass->get_domains != NULL) { return klass->get_domains(server); } return g_variant_new_array(G_VARIANT_TYPE_STRING, NULL, 0); } /** * server_find_uri: * @server: Server to look in * @uri: URI to search for * * Checks the URI of this server to see if it matches, and then look * to see if subclasses have a way to match it another way. */ Server * server_find_uri (Server * server, const gchar * uri) { g_return_val_if_fail(IS_SERVER(server), NULL); if (g_strcmp0(server->uri, uri) == 0) { return server; } ServerClass * klass = SERVER_GET_CLASS(server); if (klass->find_uri != NULL) { return klass->find_uri(server, uri); } return NULL; } /** * server_set_last_used: * @server: Server to look in * @uri: URI to set as last used * * Checks the URI of this server to see if it matches, and then look * to see if subclasses have a way to match it another way. */ void server_set_last_used_server (Server * server, const gchar * uri) { g_return_if_fail(IS_SERVER(server)); if (g_strcmp0(server->uri, uri) == 0) { server->last_used = TRUE; } else { ServerClass * klass = SERVER_GET_CLASS(server); if (klass->set_last_used_server != NULL) { klass->set_last_used_server(server, uri); } } }