/** * @file gnome-cmd-con-remote.cc * @copyright (C) 2001-2006 Marcus Bjurman\n * @copyright (C) 2007-2012 Piotr Eljasiak\n * @copyright (C) 2013-2023 Uwe Scholz\n * * @copyright 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. * * @copyright 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. * * @copyright 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "gnome-cmd-includes.h" #include "gnome-cmd-data.h" #include "gnome-cmd-con-remote.h" #include "gnome-cmd-main-win.h" #include "gnome-cmd-plain-path.h" #include "imageloader.h" #include "utils.h" using namespace std; static GnomeCmdConClass *parent_class = nullptr; static void set_con_mount_failed(GnomeCmdCon *con) { g_return_if_fail(GNOME_CMD_IS_CON(con)); con->base_gFileInfo = nullptr; con->open_result = GnomeCmdCon::OPEN_FAILED; con->state = GnomeCmdCon::STATE_CLOSED; con->open_failed_msg = con->open_failed_error->message; } static void mount_remote_finish_callback(GObject *gobj, GAsyncResult *result, gpointer user_data) { auto con = GNOME_CMD_CON(user_data); g_return_if_fail(GNOME_CMD_IS_CON(user_data)); g_return_if_fail(gobj != nullptr); auto gFile = G_FILE(gobj); g_return_if_fail(G_IS_FILE(gFile)); GError *error = nullptr; g_file_mount_enclosing_volume_finish(gFile, result, &error); if (error && !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED)) { DEBUG('m', "Unable to mount enclosing volume: %s\n", error->message); con->open_failed_error = g_error_copy(error); g_error_free(error); set_con_mount_failed(con); g_object_unref(gFile); return; } set_con_base_gfileinfo(con); con->state = GnomeCmdCon::STATE_OPEN; con->open_result = GnomeCmdCon::OPEN_OK; g_object_unref(gFile); } static void mount_func (GnomeCmdCon *con) { g_return_if_fail(GNOME_CMD_IS_CON(con)); auto gFile = gnome_cmd_con_create_gfile(con); auto uri = g_file_get_uri(gFile); DEBUG('m', "Connecting to %s\n", uri); auto gMountOperation = gtk_mount_operation_new ((GtkWindow*) main_win); g_file_mount_enclosing_volume (gFile, G_MOUNT_MOUNT_NONE, gMountOperation, nullptr, mount_remote_finish_callback, con); } static gboolean start_mount_func (GnomeCmdCon *con) { g_thread_new (nullptr, (GThreadFunc) mount_func, con); return FALSE; } static void remote_open (GnomeCmdCon *con) { DEBUG('m', "Opening remote connection\n"); g_return_if_fail (con->uri != nullptr); con->state = GnomeCmdCon::STATE_OPENING; con->open_result = GnomeCmdCon::OPEN_IN_PROGRESS; if (!con->base_path) con->base_path = new GnomeCmdPlainPath(G_DIR_SEPARATOR_S); g_timeout_add (1, (GSourceFunc) start_mount_func, con); } static void remote_close_callback(GObject *gobj, GAsyncResult *result, gpointer user_data) { auto gMount = (GMount*) gobj; auto con = (GnomeCmdCon*) user_data; GError *error = nullptr; g_mount_unmount_with_operation_finish(gMount, result, &error); if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) { gnome_cmd_error_message(_("Disconnect error"), error); g_error_free(error); return; } if (error) g_error_free(error); con->state = GnomeCmdCon::STATE_CLOSED; con->open_result = GnomeCmdCon::OPEN_NOT_STARTED; } static gboolean remote_close (GnomeCmdCon *con) { GError *error = nullptr; gnome_cmd_con_set_default_dir (con, nullptr); delete con->base_path; con->base_path = nullptr; auto uri = gnome_cmd_con_get_uri(con); auto gFileTmp = g_file_new_for_uri(uri); DEBUG ('m', "Closing connection to %s\n", uri); auto gMount = g_file_find_enclosing_mount (gFileTmp, nullptr, &error); if (error) { g_warning("remote_close - g_file_find_enclosing_mount error: %s - %s", uri, error->message); g_error_free(error); g_object_unref(gFileTmp); return false; } g_mount_unmount_with_operation ( gMount, G_MOUNT_UNMOUNT_NONE, nullptr, nullptr, remote_close_callback, con ); g_object_unref(gFileTmp); return TRUE; } static void remote_cancel_open (GnomeCmdCon *con) { DEBUG('m', "Setting state CANCELLING\n"); con->state = GnomeCmdCon::STATE_CANCELLING; } static gboolean remote_open_is_needed (GnomeCmdCon *con) { return TRUE; } static GFile *create_remote_gfile_with_path(GnomeCmdCon *con, GnomeCmdPath *path) { auto gUri = g_uri_build(G_URI_FLAGS_NONE, con->scheme, nullptr, con->hostname, con->port, path->get_path(), nullptr, nullptr); auto gFilePathUriString = g_uri_to_string(gUri); auto gFile = g_file_new_for_uri(gFilePathUriString); g_free(gFilePathUriString); return gFile; } static GFile *remote_create_gfile (GnomeCmdCon *con, GnomeCmdPath *path) { g_return_val_if_fail (con->uri != nullptr, nullptr); if (path) { return create_remote_gfile_with_path(con, path); } else { auto gFile = g_file_new_for_uri (con->uri); return gFile; } } static GnomeCmdPath *remote_create_path (GnomeCmdCon *con, const gchar *path_str) { return new GnomeCmdPlainPath(path_str); } /******************************* * Gtk class implementation *******************************/ static void destroy (GtkObject *object) { auto con_remote = GNOME_CMD_CON_REMOTE (object); gnome_cmd_pixmap_free (con_remote->parent.go_pixmap); gnome_cmd_pixmap_free (con_remote->parent.open_pixmap); gnome_cmd_pixmap_free (con_remote->parent.close_pixmap); if (GTK_OBJECT_CLASS (parent_class)->destroy) (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); } static void class_init (GnomeCmdConRemoteClass *klass) { GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); GnomeCmdConClass *con_class = GNOME_CMD_CON_CLASS (klass); parent_class = static_cast (gtk_type_class (GNOME_CMD_TYPE_CON)); object_class->destroy = destroy; con_class->open = remote_open; con_class->close = remote_close; con_class->cancel_open = remote_cancel_open; con_class->open_is_needed = remote_open_is_needed; con_class->create_gfile = remote_create_gfile; con_class->create_path = remote_create_path; } static void init (GnomeCmdConRemote *remote_con) { guint dev_icon_size = gnome_cmd_data.dev_icon_size; gint icon_size; g_assert (gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &icon_size, nullptr)); GnomeCmdCon *con = GNOME_CMD_CON (remote_con); con->method = CON_FTP; con->should_remember_dir = TRUE; con->needs_open_visprog = TRUE; con->needs_list_visprog = TRUE; con->can_show_free_space = FALSE; con->is_local = FALSE; con->is_closeable = TRUE; con->go_pixmap = gnome_cmd_pixmap_new_from_icon (gnome_cmd_con_get_icon_name (con), dev_icon_size); con->open_pixmap = gnome_cmd_pixmap_new_from_icon (gnome_cmd_con_get_icon_name (con), dev_icon_size); con->close_pixmap = gnome_cmd_pixmap_new_from_icon (gnome_cmd_con_get_icon_name (con), icon_size); if (con->close_pixmap) { GdkPixbuf *overlay = gdk_pixbuf_copy (con->close_pixmap->pixbuf); if (overlay) { GdkPixbuf *umount = IMAGE_get_pixbuf (PIXMAP_OVERLAY_UMOUNT); if (umount) { gdk_pixbuf_copy_area (umount, 0, 0, MIN (gdk_pixbuf_get_width (umount), icon_size), MIN (gdk_pixbuf_get_height (umount), icon_size), overlay, 0, 0); // FIXME: free con->close_pixmap here con->close_pixmap = gnome_cmd_pixmap_new_from_pixbuf (overlay); } g_object_unref (overlay); } } } /*********************************** * Public functions ***********************************/ GtkType gnome_cmd_con_remote_get_type () { static GtkType type = 0; if (type == 0) { GtkTypeInfo info = { (gchar*) "GnomeCmdConRemote", sizeof (GnomeCmdConRemote), sizeof (GnomeCmdConRemoteClass), (GtkClassInitFunc) class_init, (GtkObjectInitFunc) init, /* reserved_1 */ nullptr, /* reserved_2 */ nullptr, (GtkClassInitFunc) nullptr }; type = gtk_type_unique (GNOME_CMD_TYPE_CON, &info); } return type; } /** * Logic for setting up a new remote connection accordingly to the given uri_str. */ GnomeCmdConRemote *gnome_cmd_con_remote_new (const gchar *alias, const string &uri_str) { auto gnomeCmdConRemote = static_cast (g_object_new (GNOME_CMD_TYPE_CON_REMOTE, nullptr)); g_return_val_if_fail (gnomeCmdConRemote != nullptr, nullptr); GError *error = nullptr; gchar *scheme = nullptr; gchar *user = nullptr; gchar *host = nullptr; gint port = -1; gchar *path = nullptr; g_uri_split_with_user ( uri_str.c_str(), G_URI_FLAGS_HAS_PASSWORD, &scheme, &user, nullptr, //password nullptr, //auth_params &host, //host &port, //port &path, //path nullptr, //query nullptr, //fragment &error ); if (error) { g_warning("gnome_cmd_con_remote_new - g_uri_split error: %s", error->message); g_error_free(error); return nullptr; } GnomeCmdCon *con = GNOME_CMD_CON (gnomeCmdConRemote); gnome_cmd_con_set_alias (con, alias); gnome_cmd_con_set_uri (con, uri_str.c_str()); gnome_cmd_con_set_scheme(con, scheme); gnome_cmd_con_set_user_name (con, user); gnome_cmd_con_set_host_name (con, host); gnome_cmd_con_set_port (con, port); gnome_cmd_con_set_root_path (con, path); gnome_cmd_con_remote_set_tooltips (gnomeCmdConRemote, host); con->method = gnome_cmd_con_get_scheme (uri_str.c_str()); g_free (scheme); g_free(host); g_free (path); g_free (user); return gnomeCmdConRemote; } void gnome_cmd_con_remote_set_tooltips (GnomeCmdConRemote *con, const gchar *host_name) { g_return_if_fail (con != nullptr); if (!host_name) { return; } GNOME_CMD_CON (con)->open_tooltip = g_strdup_printf (_("Opens remote connection to %s"), host_name); GNOME_CMD_CON (con)->close_tooltip = g_strdup_printf (_("Closes remote connection to %s"), host_name); }