/* Glimmer - file-io.c * * 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 #include #include #include #include #include #include #include #include #include "declarations.h" #include "file-io.h" #include "dialogs.h" #include "main.h" #include "misc.h" #include "macro-language.h" #include "mdi-routines.h" #include "menus.h" #include "properties.h" #include "settings.h" #include "session.h" #include "signals.h" #include "syntax-highlight.h" #include "widgets/gdstearaway.h" #include "widgets/gnome-password-dialog.h" #include "getprefs.h" gchar *last_dir = NULL; GList *recent_files = NULL; GList *directory_history = NULL; static void open_file_real_finish (GdsFile * gds_file, gpointer data); static void revert_file_finish (GdsFile * gds_file, gpointer data); static void reload_file_finish (GdsFile * gds_file, gpointer data); static void main_quit (GtkWidget * widget, gpointer data); static void save_file_real_finish (GdsFile * gds_file, gpointer data); static void save_file_as_real_finish (GdsFile * gds_file, GnomeVFSURI * uri); static void save_file_or_dialog_finish (GdsFile * gds_file, gpointer data); static void save_file_async_open_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file); static void save_file_async_write_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, gpointer buffer, GnomeVFSFileSize bytes_requested, GnomeVFSFileSize bytes_written, GdsFile * gds_file); static void save_file_async_close_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file); static void get_file_info_before_save_async_cb (GnomeVFSAsyncHandle * handle, GList * results, GList * carrier); static void open_file_async_open_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file); static void open_file_async_read_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, gpointer buffer, GnomeVFSFileSize bytes_requested, GnomeVFSFileSize bytes_read, GdsFile * gds_file); static void open_file_async_close_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file); static gboolean check_if_file_is_symlink (gchar * filename); //static gint get_file_read_buffer_size(gchar *filename); void save_file_directory_history (void) { save_directory_history (directory_history, "file"); } void load_file_directory_history (void) { get_directory_history (&directory_history, "file"); } void new_file_real (char *filename) { GnomeVFSURI *uri; gchar cwd[MAXPATHLEN]; gchar *full; getcwd (cwd, sizeof(cwd)); full = g_strconcat (cwd, "/", filename, NULL); uri = gnome_vfs_uri_new (full); g_free (full); cur_file = construct_file (uri); gtk_widget_grab_focus (cur_file->text); attach_highlight_tables (cur_file, NULL); adjust_sensitivity (); display_message (_("New file created."), FLASH); } void new_file_cb (GtkWidget * widget, gpointer data) { new_file_real ("Untitled"); } void open_file_cb (GtkWidget * widget, gpointer data) { static GtkWidget *file_selector = NULL; if (!file_selector) { file_selector = gnome_file_selector_new_with_path (last_dir ? last_dir : general_preferences.default_dir, GNOME_FILE_SELECTOR_MULTIPLE, general_preferences.show_dots, general_preferences.show_details, &directory_history); gnome_file_selector_set_title (GNOME_FILE_SELECTOR (file_selector), _("Open File...")); gtk_signal_connect (GTK_OBJECT (GNOME_FILE_SELECTOR (file_selector)->ok_button), "clicked", GTK_SIGNAL_FUNC (open_file_cb_continue), file_selector); gtk_signal_connect_object (GTK_OBJECT (GNOME_FILE_SELECTOR (file_selector)-> cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_hide), GTK_OBJECT (file_selector)); gtk_window_set_transient_for (GTK_WINDOW (file_selector), GTK_WINDOW (window)); gtk_widget_show (file_selector); } else { gtk_entry_set_text (GTK_ENTRY (GNOME_FILE_SELECTOR (file_selector)-> selection_entry), ""); gtk_clist_unselect_all (GTK_CLIST (GNOME_FILE_SELECTOR (file_selector)-> file_selector)); gnome_file_selector_set_history (GNOME_FILE_SELECTOR (file_selector), &directory_history); gnome_file_selector_get_listing (GNOME_FILE_SELECTOR (file_selector)); gtk_widget_show (file_selector); } } void open_file_cb_continue (GtkWidget * widget, GnomeFileSelector * file_selector) { GList *strings = NULL; GList *iter; gint files = 0; GnomeVFSURI *uri; gchar *string = 0; gtk_widget_hide (GTK_WIDGET (file_selector)); strings = gnome_file_selector_get_uri_list (GNOME_FILE_SELECTOR (file_selector)); files = g_list_length (strings); for (iter = strings; iter; iter = iter->next) { uri = (GnomeVFSURI *) iter->data; string = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); if (check_if_file_exists (string)) { open_file_real (string); } else { if (check_if_file_can_exist (string)) { if (file_dne_error (string, GTK_SIGNAL_FUNC (open_file_error_cb)) && files == 1) gtk_widget_show (GTK_WIDGET (file_selector)); } else { read_error (string); if (files == 1) gtk_widget_show (GTK_WIDGET (file_selector)); } } gnome_vfs_uri_unref (uri); g_free (string); } g_list_free (strings); } void open_file_error_cb (GtkWidget * widget, gchar * filename) { open_file_real (filename); } void open_file_real (gchar * filename) { GdsFile *file; GnomeVFSURI *uri; gchar *temp = NULL; uri = gnome_vfs_uri_new (filename); gnome_vfs_uri_ref (uri); if (general_preferences.untitled && (total_files >= 1) && (file = (GdsFile *) g_list_nth_data (files_list, 0))) { if (gds_file_is_untitled (file) && !GDS_EDITOR (file->text)->changed) close_file_real (file); } temp = gnome_vfs_uri_get_host_path (uri); if (temp) { if (last_dir) g_free (last_dir); last_dir = temp; } cur_file = construct_file (uri); if (open_file_full (cur_file, uri)) { open_file_real_finish (cur_file, NULL); } else if (cur_file->xfering) { cur_file->xfer_finish = GTK_SIGNAL_FUNC (open_file_real_finish); cur_file->xfer_data = NULL; adjust_sensitivity (); } gnome_vfs_uri_unref (uri); } // Call this when open_file_real is actually done static void open_file_real_finish (GdsFile * gds_file, gpointer data) { gchar *temp = NULL; add_file_to_recent_list (gds_file->filename); attach_highlight_tables (gds_file, NULL); check_if_read_only (gds_file, gds_file->uri); temp = gds_file->props.dir; if (gds_file->tables) copy_properties (&gds_file->props, &gds_file->tables->props); gds_file->props.dir = temp; gtk_extext_undo_clear_all (GTK_EXTEXT (gds_file->text)); GDS_EDITOR (gds_file->text)->changed = FALSE; gds_file->modtime = get_modification_time (gds_file->uri); adjust_sensitivity (); #ifdef WITH_PYTHON adjust_popup_menu (); #endif if (general_preferences.auto_save) save_session_cb (NULL, NULL); display_message (_("File opened."), FLASH); } void revert_file_cb (GtkWidget * widget, gpointer data) { if (gtk_extext_get_editable (GTK_EXTEXT (cur_file->text))) { gtk_extext_delete_text (GTK_EXTEXT (cur_file->text), 0, gtk_extext_get_length (GTK_EXTEXT (cur_file->text))); if (open_file_full (cur_file, cur_file->uri)) { revert_file_finish (cur_file, NULL); } else if (cur_file->xfering) { cur_file->xfer_finish = GTK_SIGNAL_FUNC (revert_file_finish); cur_file->xfer_data = NULL; adjust_sensitivity (); } } else if (gds_file_is_untitled (cur_file)) { gtk_extext_delete_text (GTK_EXTEXT (cur_file->text), 0, gtk_extext_get_length (GTK_EXTEXT (cur_file->text))); revert_file_finish (cur_file, NULL); } } static void revert_file_finish (GdsFile * gds_file, gpointer data) { GDS_EDITOR (gds_file->text)->changed = FALSE; gds_file->modtime = get_modification_time (gds_file->uri); gtk_signal_emit_by_name (GTK_OBJECT (cur_file->text), "move_to_column", 0, NULL); adjust_sensitivity (); #ifdef WITH_PYTHON app_emit_scripting_signal ("revert-file"); #endif display_message (_("File reverted to previous state."), FLASH); } void save_file_cb (GtkWidget * widget, gpointer data) { save_file_real (cur_file); } void save_file_error_cb (GtkWidget * widget, GdsFile * file) { save_file_real (file); } void save_file_real (GdsFile * gds_file) { g_return_if_fail (gds_file != NULL); g_return_if_fail (GDS_IS_FILE (gds_file)); if (gds_file_is_untitled (gds_file)) { save_file_as_cb (NULL, NULL); return; } if (save_file_full (gds_file, gds_file->uri)) { save_file_real_finish (gds_file, NULL); } else if (gds_file->xfering) { gds_file->xfer_finish = GTK_SIGNAL_FUNC (save_file_real_finish); adjust_sensitivity (); } } static void save_file_real_finish (GdsFile * gds_file, gpointer data) { GdsFile *back_file; GDS_EDITOR (gds_file->text)->changed = FALSE; gds_file->modtime = get_modification_time (gds_file->uri); gtk_signal_emit_by_name (GTK_OBJECT (gds_file->text), "move_to_column", 0, NULL); back_file = cur_file; cur_file = gds_file; #ifdef WITH_PYTHON app_emit_scripting_signal ("save-file"); #endif cur_file = back_file; adjust_sensitivity (); display_message (_("File Saved."), FLASH); } void save_file_as_cb (GtkWidget * widget, gpointer data) { gchar *str = NULL; str = gnome_vfs_uri_get_host_path (cur_file->uri); widget = gnome_file_selector_new_with_path (str, GNOME_FILE_SELECTOR_SINGLE, general_preferences.show_dots, general_preferences.show_details, &directory_history); g_free (str); gnome_file_selector_set_title (GNOME_FILE_SELECTOR (widget), _("Save file with new name...")); gtk_signal_connect (GTK_OBJECT (GNOME_FILE_SELECTOR (widget)->ok_button), "clicked", GTK_SIGNAL_FUNC (save_file_as_continue), widget); gtk_signal_connect_object (GTK_OBJECT (GNOME_FILE_SELECTOR (widget)->cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (widget)); gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (window)); gtk_window_set_modal (GTK_WINDOW (widget), TRUE); gtk_signal_connect_object (GTK_OBJECT (widget), "destroy", GTK_SIGNAL_FUNC (gtk_grab_remove), GTK_OBJECT (widget)); gtk_widget_show (widget); str = gnome_vfs_uri_extract_short_name (cur_file->uri); if (str) { gtk_entry_set_text (GTK_ENTRY (GNOME_FILE_SELECTOR (widget)->selection_entry), str); g_free (str); } gtk_widget_grab_focus (GNOME_FILE_SELECTOR (widget)->selection_entry); } void save_file_as_continue (GtkWidget * widget, GnomeFileSelector * file_selector) { gchar *string; gint result; string = gnome_file_selector_get_filename (GNOME_FILE_SELECTOR (file_selector)); if (check_if_file_exists (string)) { gtk_widget_hide (GTK_WIDGET (file_selector)); result = file_exists_error (string, GTK_SIGNAL_FUNC (save_file_as_error_cb)); if (result == 0) gtk_widget_destroy (GTK_WIDGET (file_selector)); else gtk_widget_show (GTK_WIDGET (file_selector)); } else { gtk_widget_destroy (GTK_WIDGET (file_selector)); save_file_as_real (cur_file, string); } g_free (string); } void save_file_as_error_cb (GtkWidget * widget, gchar * filename) { save_file_as_real (cur_file, filename); } void save_file_as_real (GdsFile * gds_file, gchar * filename) { GnomeVFSURI *uri; g_return_if_fail (gds_file != NULL); g_return_if_fail (GDS_IS_FILE (gds_file)); uri = gnome_vfs_uri_new (filename); // FIXME: Unref this somewhere later if the save fails? // This should be handled if (save_file_full (gds_file, uri)) { save_file_as_real_finish (gds_file, uri); } else if (gds_file->xfering) { gds_file->xfer_finish = GTK_SIGNAL_FUNC (save_file_as_real_finish); adjust_sensitivity (); } } // We had better be getting a uri as the second arg here. static void save_file_as_real_finish (GdsFile * gds_file, GnomeVFSURI * uri) { gchar *temp; GdsFile *back_file; gds_file_set_uri (gds_file, uri, general_preferences.full_filenames); temp = (gchar *) gnome_vfs_uri_get_host_path (gds_file->uri); if (!gds_file->props.dir || !strcmp (temp, gds_file->props.dir)) { g_free (gds_file->props.dir); gds_file->props.dir = gnome_vfs_unescape_string (temp, "/");; } g_free (temp); add_file_to_recent_list (gds_file->filename); if (gds_file->default_lang) { attach_highlight_tables (gds_file, NULL); if (gds_file->tables && !gds_file->props.over_ride) copy_properties (&gds_file->props, &gds_file->tables->props); } gds_editor_set_editable (GDS_EDITOR (gds_file->text), TRUE); GDS_EDITOR (gds_file->text)->changed = FALSE; gds_file->modtime = get_modification_time (gds_file->uri); gtk_signal_emit_by_name (GTK_OBJECT (gds_file->text), "move_to_column", 0, NULL); adjust_sensitivity (); set_window_title (); back_file = cur_file; cur_file = gds_file; #ifdef WITH_PYTHON app_emit_scripting_signal ("save-as-file"); #endif cur_file = back_file; if (general_preferences.auto_save) save_session_cb (NULL, NULL); display_message (_("File saved with new name."), FLASH); } void save_all_files_cb (GtkWidget * widget, gpointer data) { GdsFile *file; gint i = 0; display_message (_("Saving all open files..."), FLASH); for (i = total_files - 1; i >= 0; i--) { file = (GdsFile *) g_list_nth_data (files_list, i); save_file_or_dialog (file); } display_message (_("All files saved."), FLASH); } void reload_file_cb (GtkWidget * widget, GdsFile * gds_file) { gtk_extext_delete_text (GTK_EXTEXT (gds_file->text), 0, GTK_EXTEXT (gds_file->text)->length); if (open_file_full (gds_file, gds_file->uri)) { reload_file_finish (gds_file, NULL); } else if (gds_file->xfering) { gds_file->xfer_finish = GTK_SIGNAL_FUNC (reload_file_finish); gds_file->xfer_data = NULL; adjust_sensitivity (); } } static void reload_file_finish (GdsFile * gds_file, gpointer data) { GDS_EDITOR (gds_file->text)->changed = FALSE; gds_file->modtime = get_modification_time (gds_file->uri); display_message (_("File reloaded."), FLASH); } static void main_quit (GtkWidget * widget, gpointer data) { gtk_main_quit (); } void save_file_or_dialog (GdsFile * gds_file) { gchar *str = NULL; GtkWidget *widget; g_return_if_fail (gds_file != NULL); g_return_if_fail (GDS_IS_FILE (gds_file)); if (gds_file_is_untitled (gds_file)) { file_change (NULL, gds_file); str = (gchar *) gnome_vfs_uri_get_host_path (gds_file->uri); widget = gnome_file_selector_new_with_path (str, GNOME_FILE_SELECTOR_SINGLE, general_preferences.show_dots, general_preferences.show_details, &directory_history); g_free (str); gnome_file_selector_set_title (GNOME_FILE_SELECTOR (widget), _("Save file with new name...")); gtk_signal_connect (GTK_OBJECT (GNOME_FILE_SELECTOR (widget)->ok_button), "clicked", GTK_SIGNAL_FUNC (save_file_as_continue), widget); gtk_signal_connect_object (GTK_OBJECT (GNOME_FILE_SELECTOR (widget)->ok_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (widget)); gtk_signal_connect_object (GTK_OBJECT (GNOME_FILE_SELECTOR (widget)-> cancel_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (widget)); gtk_window_set_modal (GTK_WINDOW (widget), TRUE); gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (window)); gtk_widget_show (widget); str = gnome_vfs_uri_extract_short_name (gds_file->uri); if (str) { gtk_entry_set_text (GTK_ENTRY (GNOME_FILE_SELECTOR (widget)->selection_entry), str); g_free (str); } gtk_widget_grab_focus (GNOME_FILE_SELECTOR (widget)->selection_entry); gtk_signal_connect_object (GTK_OBJECT (widget), "destroy", GTK_SIGNAL_FUNC (gtk_grab_remove), GTK_OBJECT (widget)); gtk_signal_connect (GTK_OBJECT (widget), "destroy", GTK_SIGNAL_FUNC (main_quit), NULL); gtk_main (); return; } else { if (save_file_full (gds_file, gds_file->uri)) { save_file_or_dialog_finish (gds_file, NULL); } else if (gds_file->xfering) { gds_file->xfer_finish = GTK_SIGNAL_FUNC (save_file_or_dialog_finish); adjust_sensitivity (); } } } static void save_file_or_dialog_finish (GdsFile * gds_file, gpointer data) { GdsFile *back_file; GDS_EDITOR (gds_file->text)->changed = FALSE; gds_file->modtime = get_modification_time (gds_file->uri); gtk_signal_emit_by_name (GTK_OBJECT (gds_file->text), "move_to_column", 0, NULL); back_file = cur_file; cur_file = gds_file; #ifdef WITH_PYTHON app_emit_scripting_signal ("save-file"); #endif cur_file = back_file; display_message (_("File Saved."), FLASH); } void close_file_cb (GtkWidget * widget, gpointer data) { GdsFile *file; file = cur_file; if (gds_editor_changed (GDS_EDITOR (cur_file->text)) && gds_file_is_untitled (cur_file)) file_not_saved_save_as (cur_file->filename, cur_file, NULL, NULL); else if (gds_editor_changed (GDS_EDITOR (cur_file->text))) file_not_saved (cur_file->filename, cur_file, NULL, NULL); else { close_file_real (file); if ((total_files < 1) && general_preferences.untitled) new_file_cb (NULL, NULL); } if (general_preferences.auto_save) save_session_cb (NULL, NULL); } void close_file_error_cb (GtkWidget * widget, GdsFile * file) { g_return_if_fail (file != NULL); g_return_if_fail (GDS_IS_FILE (file)); close_file_real (file); if ((total_files < 1) && general_preferences.untitled) new_file_cb (NULL, NULL); } void close_file_real (GdsFile * file) { gint old_page; g_return_if_fail (file != NULL); g_return_if_fail (GDS_IS_FILE (file)); if (GDS_TEAR_AWAY (file->tear_away)->torn) gds_tear_away_bust_a_switch (GDS_TEAR_AWAY (file->tear_away)); #ifdef WITH_PYTHON app_emit_scripting_signal ("close-file"); #endif detach_highlight_tables (file); files_list = g_list_remove (files_list, file); total_files--; if (!total_files) files_list = NULL; old_page = cur_page; gtk_widget_destroy (GTK_WIDGET (file)); if (old_page == 0) { cur_page = old_page; } cur_file = NULL; gtk_notebook_set_page (GTK_NOTEBOOK (files_book), cur_page); set_notebook_page (GTK_NOTEBOOK (files_book), NULL, cur_page, NULL); adjust_sensitivity (); display_message (_("File closed."), FLASH); } void close_all_files_cb (GtkWidget * widget, gpointer data) { GdsFile *file; gchar *filename; gint i = 0; for (i = total_files - 1; i >= 0; i--) { file = (GdsFile *) g_list_nth_data (files_list, i); file_change (widget, file); if (gds_editor_changed (GDS_EDITOR (file->text))) { filename = gnome_vfs_uri_extract_short_name (file->uri); file_not_saved (filename, file, GTK_SIGNAL_FUNC (close_all_files_cb), GTK_SIGNAL_FUNC (close_all_files_cb)); g_free (filename); return; } else { close_file_real (file); } } } static void set_uri_info_cb (GtkWidget * widget, GnomePasswordDialog * dialog) { gnome_vfs_uri_set_user_name (dialog->uri, gnome_password_dialog_get_username (dialog)); gnome_vfs_uri_set_password (dialog->uri, gnome_password_dialog_get_password (dialog)); } gboolean save_file_full (GdsFile * gds_file, GnomeVFSURI * uri) { gchar *all_text = NULL; GnomeVFSHandle *handle = NULL; GnomeVFSAsyncHandle *ahandle = NULL; GnomeVFSFileSize bytes = 0; GnomeVFSResult result; GList *urilist = NULL; GList *carrier = NULL; gint length = 0; gboolean retval = FALSE; gchar *password; gboolean remove_pass = FALSE; if (cur_file->need_pass) { password = (gchar *) gnome_vfs_uri_get_password (uri); if (!password) { GnomePasswordDialog *dialog; dialog = (GnomePasswordDialog *) gnome_password_dialog_new ((gchar *) gnome_vfs_uri_get_path (uri)); gnome_password_dialog_set_username (dialog, (gchar *) gnome_vfs_uri_get_user_name (uri)); dialog->uri = uri; gtk_signal_connect (GTK_OBJECT (dialog), "delete_event", GTK_SIGNAL_FUNC (main_quit), NULL); gtk_signal_connect (GTK_OBJECT (dialog->cancel_button), "clicked", GTK_SIGNAL_FUNC (main_quit), NULL); gtk_signal_connect (GTK_OBJECT (dialog->ok_button), "clicked", GTK_SIGNAL_FUNC (set_uri_info_cb), dialog); gtk_signal_connect (GTK_OBJECT (dialog->ok_button), "clicked", GTK_SIGNAL_FUNC (main_quit), NULL); gtk_widget_show (GTK_WIDGET (dialog)); gtk_widget_grab_focus (dialog->password_entry); gtk_main (); remove_pass = !gnome_password_dialog_get_save_pass (dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); } } if (gnome_vfs_uri_is_local (uri) && !general_preferences.async_xfer) { if (!check_if_file_exists ((gchar *) gnome_vfs_uri_get_path (uri))) { if (!create_file ((gchar *) gnome_vfs_uri_get_path (uri))) { generic_dialog_with_text (_("File could not be created!")); return (FALSE); } } else if (general_preferences.copy_sym_on_write) { if (check_if_file_is_symlink ((gchar *) gnome_vfs_uri_get_path (uri))) { result = gnome_vfs_unlink_from_uri (uri); if (result != GNOME_VFS_OK) { generic_dialog_with_text (_ ("Symlink could not be removed!")); return (FALSE); } if (!create_file ((gchar *) gnome_vfs_uri_get_path (uri))) { generic_dialog_with_text (_("File could not be created!")); return (FALSE); } } } all_text = gtk_extext_get_chars (GTK_EXTEXT (gds_file->text), 0, gtk_extext_get_length (GTK_EXTEXT (gds_file->text))); length = all_text ? strlen (all_text) : 0; if ((gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE) == GNOME_VFS_OK)) { if (all_text) { result = gnome_vfs_write (handle, (gconstpointer) all_text, GTK_EXTEXT (gds_file->text)->length, &bytes); if (result != GNOME_VFS_OK) generic_dialog_with_text ((gchar *) gnome_vfs_result_to_string (result)); } gnome_vfs_truncate_handle (handle, (GnomeVFSFileSize) length); gnome_vfs_close (handle); gds_file->changed_set = FALSE; set_label_colors (gds_file); gds_file->xfering = FALSE; retval = TRUE; } else { gchar *filename; filename = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD); save_error (filename); g_free (filename); gds_file->xfering = FALSE; retval = FALSE; } if (all_text) g_free (all_text); } else { gds_file->xfering = TRUE; gds_file->xfer_data = (gpointer) uri; gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), FALSE); if (general_preferences.copy_sym_on_write) { urilist = g_list_append (urilist, uri); carrier = g_list_append (carrier, uri); carrier = g_list_append (carrier, gds_file); gnome_vfs_async_get_file_info (&ahandle, urilist, GNOME_VFS_FILE_INFO_DEFAULT, (GnomeVFSAsyncGetFileInfoCallback) get_file_info_before_save_async_cb, carrier); g_list_free (urilist); } else { gnome_vfs_async_open_uri (&ahandle, uri, GNOME_VFS_OPEN_WRITE, (GnomeVFSAsyncOpenCallback) save_file_async_open_cb, gds_file); } gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), FALSE); gnome_vfs_async_open_uri (&ahandle, uri, GNOME_VFS_OPEN_WRITE, (GnomeVFSAsyncOpenCallback) save_file_async_open_cb, gds_file); g_print ("Requesting remote file handle...\n"); retval = FALSE; } if (remove_pass) gnome_vfs_uri_set_password (uri, NULL); return (retval); } static void get_file_info_before_save_async_cb (GnomeVFSAsyncHandle * handle, GList * results, GList * carrier) { GnomeVFSGetFileInfoResult *result; GnomeVFSResult deletionresult; GnomeVFSAsyncHandle *ahandle; GnomeVFSURI *uricopy; GnomeVFSURI *uri; GdsFile *gds_file; result = g_list_first (results)->data; uri = g_list_first (carrier)->data; gds_file = g_list_last (carrier)->data; g_list_free (carrier); if ((result->result == GNOME_VFS_OK) && (result->file_info->type == GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK)) { uricopy = gnome_vfs_uri_dup (uri); deletionresult = gnome_vfs_unlink_from_uri (uricopy); gnome_vfs_uri_unref (uricopy); if (deletionresult != GNOME_VFS_OK) { generic_dialog_with_text ((gchar *) gnome_vfs_result_to_string (deletionresult)); } /* try to save in non-copy mode anyway */ gnome_vfs_async_open_uri (&ahandle, uri, GNOME_VFS_OPEN_WRITE, (GnomeVFSAsyncOpenCallback) save_file_async_open_cb, gds_file); } else { /* either the file does not exist or is not a symbolic link or some other problem occurred, return to main program */ gnome_vfs_async_open_uri (&ahandle, uri, GNOME_VFS_OPEN_WRITE, (GnomeVFSAsyncOpenCallback) save_file_async_open_cb, gds_file); } } static void save_file_async_open_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file) { gint write_size; if (result == GNOME_VFS_OK) { write_size = gtk_extext_get_length (GTK_EXTEXT (gds_file->text)); gtk_extext_freeze (GTK_EXTEXT (gds_file->text)); /* Take care of NULL files too */ if (write_size) { gds_file->storage = gtk_extext_get_chars (GTK_EXTEXT (gds_file->text), 0, write_size); g_print ("Requesting to send %d bytes of data.\n", write_size); gnome_vfs_async_write (handle, gds_file->storage, write_size, (GnomeVFSAsyncWriteCallback) save_file_async_write_cb, gds_file); } else { gds_file->storage = NULL; save_file_async_write_cb (handle, GNOME_VFS_OK, NULL, 0, 0, gds_file); } } else if (result == GNOME_VFS_ERROR_NOT_FOUND) { gnome_vfs_async_create_uri (&handle, (GnomeVFSURI *) gds_file->xfer_data, GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE | GNOME_VFS_PERM_OTHER_READ, (GnomeVFSAsyncOpenCallback) save_file_async_open_cb, gds_file); } else { error_dialog_with_text (gnome_vfs_result_to_string (result)); gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), TRUE); // This means we have a save_as op, and it has failed. if (gds_file->xfer_data) gnome_vfs_uri_unref (gds_file->xfer_data); gds_file->xfer_finish = NULL; gds_file->xfer_data = NULL; gds_file->xfering = FALSE; adjust_sensitivity (); } } static void save_file_async_write_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, gpointer buffer, GnomeVFSFileSize bytes_requested, GnomeVFSFileSize bytes_written, GdsFile * gds_file) { if (result == GNOME_VFS_OK) { g_print ("Sent %d bytes of data.\n", (gint) bytes_written); if (bytes_written == bytes_requested) { if (gds_file->storage) g_free (gds_file->storage); gnome_vfs_async_close (handle, (GnomeVFSAsyncCloseCallback) save_file_async_close_cb, gds_file); } } else { if (gds_file->storage) g_free (gds_file->storage); error_dialog_with_text ((gchar *) gnome_vfs_result_to_string (result)); // This means we have a save_as op, and it has failed. if (gds_file->xfer_data) gnome_vfs_uri_unref (gds_file->xfer_data); gds_file->xfer_finish = NULL; gds_file->xfer_data = NULL; gds_file->xfering = FALSE; gtk_extext_thaw (GTK_EXTEXT (gds_file->text)); gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), TRUE); adjust_sensitivity (); } } static void save_file_async_close_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file) { GnomeVFSHandle *vhandle; GnomeVFSURI *temp; // If this is a save as op, we will have the new uri as xfer data, else use the regular uri temp = gds_file->xfer_data ? gds_file->xfer_data : gds_file->uri; if (gnome_vfs_open_uri (&vhandle, temp, GNOME_VFS_OPEN_WRITE) == GNOME_VFS_OK) { gnome_vfs_truncate_handle (vhandle, (GnomeVFSFileSize) gtk_extext_get_length (GTK_EXTEXT (gds_file->text))); gnome_vfs_close (vhandle); } gtk_extext_thaw (GTK_EXTEXT (gds_file->text)); gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), TRUE); gds_file->changed_set = FALSE; set_label_colors (gds_file); gds_file->xfering = FALSE; if (gds_file->xfer_finish) gds_file->xfer_finish (gds_file, gds_file->xfer_data); gds_file->xfer_finish = NULL; gds_file->xfer_data = NULL; } gboolean open_file_full (GdsFile * gds_file, GnomeVFSURI * uri) { GnomeVFSHandle *handle; GnomeVFSAsyncHandle *ahandle; gpointer buffer; GnomeVFSFileSize bytes; gint read_size; gint pos; gboolean retval = FALSE; pos = gtk_extext_get_position (GTK_EXTEXT (gds_file->text)); if (gnome_vfs_uri_is_local (uri) && !general_preferences.async_xfer) { read_size = 64 * 1024; if ((gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_READ) == GNOME_VFS_OK)) { gtk_extext_freeze (GTK_EXTEXT (gds_file->text)); buffer = g_new (char, read_size); while ((gnome_vfs_read (handle, buffer, read_size, &bytes) == GNOME_VFS_OK)) { gtk_extext_insert_text (GTK_EXTEXT (gds_file->text), (gchar *) buffer, bytes, (gint *) & GTK_EXTEXT (gds_file->text)-> current_pos); if (bytes < read_size) break; } g_free (buffer); gnome_vfs_close (handle); gtk_extext_set_position (GTK_EXTEXT (gds_file->text), pos); gtk_extext_thaw (GTK_EXTEXT (gds_file->text)); gds_file->xfering = FALSE; retval = TRUE; } } else // Async xfer this bitch { gds_file->xfering = TRUE; gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), FALSE); gnome_vfs_async_open_uri (&ahandle, uri, GNOME_VFS_OPEN_READ, (GnomeVFSAsyncOpenCallback) open_file_async_open_cb, gds_file); g_print ("Requesting remote file handle...\n"); retval = FALSE; } return (retval); } static void open_file_async_open_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file) { gpointer buffer; gint read_size; g_print ("We got to the open file async open callback.\n"); if (result == GNOME_VFS_OK) { read_size = 32 * 1024; gds_file->storage = (gpointer) gtk_extext_get_position (GTK_EXTEXT (gds_file->text)); gtk_extext_freeze (GTK_EXTEXT (gds_file->text)); buffer = g_new (char, read_size); g_print ("Requesting %d bytes of data.\n", read_size); gnome_vfs_async_read (handle, buffer, read_size, (GnomeVFSAsyncReadCallback) open_file_async_read_cb, gds_file); } else { error_dialog_with_text (gnome_vfs_result_to_string (result)); gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), TRUE); gds_file->xfering = FALSE; adjust_sensitivity (); } } static void open_file_async_read_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, gpointer buffer, GnomeVFSFileSize bytes_requested, GnomeVFSFileSize bytes_read, GdsFile * gds_file) { /* Reading went well, or the file was empty...both are ok */ if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_EOF) { gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), TRUE); if (bytes_read) gtk_extext_insert_text (GTK_EXTEXT (gds_file->text), (gchar *) buffer, bytes_read, (gint *) & GTK_EXTEXT (gds_file->text)-> current_pos); gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), FALSE); g_print ("Received %d bytes of data.\n", (gint) bytes_read); if (bytes_read < bytes_requested) { if (buffer) g_free (buffer); gnome_vfs_async_close (handle, (GnomeVFSAsyncCloseCallback) open_file_async_close_cb, gds_file); } else // read more data { gnome_vfs_async_read (handle, buffer, bytes_requested, (GnomeVFSAsyncReadCallback) open_file_async_read_cb, gds_file); g_print ("Requesting %d more bytes of data.\n", (gint) bytes_requested); } } else { error_dialog_with_text (gnome_vfs_result_to_string (result)); gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), TRUE); gds_file->xfering = FALSE; adjust_sensitivity (); } } static void open_file_async_close_cb (GnomeVFSAsyncHandle * handle, GnomeVFSResult result, GdsFile * gds_file) { gds_file->xfering = FALSE; gtk_extext_set_editable (GTK_EXTEXT (gds_file->text), TRUE); gtk_extext_set_position (GTK_EXTEXT (gds_file->text), (gint) gds_file->storage); gtk_extext_thaw (GTK_EXTEXT (gds_file->text)); if (gds_file->xfer_finish) gds_file->xfer_finish (gds_file, gds_file->xfer_data); gds_file->xfer_finish = NULL; gds_file->xfer_data = NULL; } gboolean check_if_dir_exists (gchar * path) { GnomeVFSResult result; GnomeVFSFileInfo *finfo; gboolean exists = FALSE; if (!path) return (FALSE); finfo = gnome_vfs_file_info_new (); result = gnome_vfs_get_file_info (path, finfo, GNOME_VFS_FILE_INFO_FOLLOW_LINKS); if (result == GNOME_VFS_OK) { if (finfo->type == GNOME_VFS_FILE_TYPE_DIRECTORY) { exists = TRUE; } } gnome_vfs_file_info_unref (finfo); return (exists); } gboolean check_if_file_exists (gchar * filename) { GnomeVFSResult result; GnomeVFSFileInfo *finfo; gboolean exists = FALSE; finfo = gnome_vfs_file_info_new (); result = gnome_vfs_get_file_info (filename, finfo, GNOME_VFS_FILE_INFO_FOLLOW_LINKS); if (result == GNOME_VFS_OK) { if (finfo->type == GNOME_VFS_FILE_TYPE_REGULAR) { exists = TRUE; } } gnome_vfs_file_info_unref (finfo); return (exists); } // This is only called when the file selector returns a file that does not exist. // We then check to see if it can exist, and then ask the user if they want to create it. gboolean check_if_file_can_exist (gchar * filename) { GnomeVFSResult result; GnomeVFSFileInfo *finfo; gboolean can_exist = FALSE; gchar *path; gint uid; gint gid; path = get_path_from_filename (filename); if (!check_path_is_local (path)) return (can_exist); uid = getuid (); gid = getgid (); finfo = gnome_vfs_file_info_new (); if ((result = gnome_vfs_get_file_info (path, finfo, GNOME_VFS_FILE_INFO_DEFAULT)) == GNOME_VFS_OK) { if (finfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS) { if ((finfo->permissions & GNOME_VFS_PERM_USER_WRITE && finfo->uid == uid) || (finfo->permissions & GNOME_VFS_PERM_GROUP_WRITE && finfo->gid == gid) || (finfo->permissions & GNOME_VFS_PERM_OTHER_WRITE)) { can_exist = TRUE; } } } gnome_vfs_file_info_unref (finfo); g_free (path); return (can_exist); } static gboolean check_if_file_is_symlink (gchar * filename) { GnomeVFSResult result; GnomeVFSFileInfo *finfo; gboolean symlink = FALSE; finfo = gnome_vfs_file_info_new (); result = gnome_vfs_get_file_info (filename, finfo, GNOME_VFS_FILE_INFO_DEFAULT); if (result == GNOME_VFS_OK) { if (finfo->type == GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK) { symlink = TRUE; } } gnome_vfs_file_info_unref (finfo); return (symlink); } gboolean check_if_read_only (GdsFile * gds_file, GnomeVFSURI * uri) { GnomeVFSResult result; GnomeVFSFileInfo *finfo; gboolean is_read_only = TRUE; gint uid; gint gid; if (gnome_vfs_uri_is_local (uri)) { uid = getuid (); gid = getgid (); finfo = gnome_vfs_file_info_new (); if ((result = gnome_vfs_get_file_info_uri (uri, finfo, GNOME_VFS_FILE_INFO_DEFAULT)) == GNOME_VFS_OK) { if (finfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS) { if ((finfo->permissions & GNOME_VFS_PERM_USER_WRITE && finfo->uid == uid) || (finfo->permissions & GNOME_VFS_PERM_GROUP_WRITE && finfo->gid == gid) || (finfo->permissions & GNOME_VFS_PERM_OTHER_WRITE)) { is_read_only = FALSE; } } } gnome_vfs_file_info_unref (finfo); } gds_editor_set_editable (GDS_EDITOR (gds_file->text), is_read_only ? FALSE : TRUE); if (is_read_only) read_only (gds_file->filename); return (is_read_only); } // This is used as a callback on various occasions, so we have to accept the widget. // Take in a filename and create the file using gnome-vfs void file_create (GtkWidget * widget, gchar * filename) { create_file (filename); } gboolean create_file (gchar * filename) { GnomeVFSHandle *handle; GnomeVFSResult result; gboolean created = FALSE; if ((result = gnome_vfs_create (&handle, filename, GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE | GNOME_VFS_PERM_OTHER_READ)) == GNOME_VFS_OK) { created = TRUE; gnome_vfs_close (handle); } return (created); } // Get the modification time of a file for keeping track of external modification gint get_modification_time (GnomeVFSURI * uri) { GnomeVFSResult result; GnomeVFSFileInfo *finfo; gint retval = 0; finfo = gnome_vfs_file_info_new (); result = gnome_vfs_get_file_info_uri (uri, finfo, GNOME_VFS_FILE_INFO_FOLLOW_LINKS); if (result == GNOME_VFS_OK) { retval = finfo->mtime; } gnome_vfs_file_info_unref (finfo); return (retval); } gboolean check_path_is_local (gchar * path) { GnomeVFSURI *uri; gboolean local = FALSE; uri = gnome_vfs_uri_new (path); if (uri) { if (gnome_vfs_uri_is_local (uri)) local = TRUE; gnome_vfs_uri_unref (uri); } return (local); } gboolean gds_file_is_untitled (GdsFile * file) { gchar *string; gboolean untitled = FALSE; string = gnome_vfs_uri_extract_short_name (file->uri); if (!strcmp (string, "Untitled")) untitled = TRUE; return (untitled); } gchar * gnome_vfs_uri_get_host_path (GnomeVFSURI * uri) { gchar *path; gchar *str; path = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD); str = gnome_vfs_unescape_string (path, "/"); g_free (path); path = str; str = strrchr (path, '/'); if (str) { str++; *str = '\0'; } str = g_strdup (path); g_free (path); return (str); } /* static gint get_file_read_buffer_size(gchar *filename) { GnomeVFSResult result; GnomeVFSFileInfo *finfo; gint read_size = 64 * 1024; finfo = gnome_vfs_file_info_new(); if((result = gnome_vfs_get_file_info(filename, finfo, GNOME_VFS_FILE_INFO_DEFAULT)) == GNOME_VFS_OK) { gnome_vfs_file_info_ref(finfo); if(finfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE) { read_size = finfo->io_block_size; } gnome_vfs_file_info_unref(finfo); } return(read_size); } */