#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "callbacks.h" #include "interface.h" #include "support.h" gchar **argv; GPid rsync_pid; gchar **groups = NULL; gint session_last = -1; // gint height_expander; gsize session_number = 0; gboolean had_error, paused, channel_closed, first_load_groups = TRUE; gchar *argv_session, *error_list; gboolean cmdline_session = FALSE, cmdline_execute = FALSE, dryrunning = FALSE; GtkWidget *main_window, *rsync = NULL; gchar config_command[MAXPATH]; gboolean config_output = FALSE, config_remember = TRUE, config_errorlist = TRUE, config_log = FALSE; GTimeVal startime, pausedtime; gchar *grsync_dir, *rsync_help = NULL, *rsync_man = NULL; FILE *log_file = NULL; gboolean get_checkbox(void* main, gchar* name) { return gtk_toggle_button_get_active((GtkToggleButton*) lookup_widget((GtkWidget*) main, name)); } void set_checkbox(void* main, gchar* name, gboolean val) { gtk_toggle_button_set_active((GtkToggleButton*) lookup_widget((GtkWidget*) main, name), val); } void set_main_title(gchar* session, gchar* extra) { gchar *stmp; stmp = g_strconcat("Grsync: ", session, " ", extra, NULL); gtk_window_set_title((GtkWindow*) main_window, stmp); g_free(stmp); } void load_settings(GtkWidget* main, gchar* session, gchar *filename) { gchar settings_file_path[MAXPATH]; GError *error_handler = NULL; GKeyFile *settings_file; gchar *stmp; gboolean btmp; gint root_x, root_y, width, height; if (filename == NULL) g_sprintf(settings_file_path, "%s/%s", grsync_dir, "grsync.ini"); else strncpy(settings_file_path, filename, MAXPATH-1); // initializes config_command before other functions which may use it if (filename == NULL) strcpy(config_command, "rsync"); if (!g_file_test(settings_file_path, G_FILE_TEST_EXISTS)) { g_printf (_("(ERROR) Can't open config file! Maybe this is the first run?\n")); if (session != NULL) { save_settings(main, session, NULL); load_groups(main, session); } } settings_file = g_key_file_new(); g_key_file_load_from_file(settings_file, settings_file_path, G_KEY_FILE_NONE, NULL); if (session == NULL) { session = g_key_file_get_start_group(settings_file); save_settings(main, session, NULL); load_groups(main, session); } set_main_title(session, NULL); if (filename == NULL) { // load configuration (preferences) stmp = g_key_file_get_string(settings_file, CONFIG_GROUP, "command", NULL); if (stmp != NULL) strncpy(config_command, stmp, MAXPATH - 1); btmp = g_key_file_get_boolean(settings_file, CONFIG_GROUP, "output", &error_handler); if (error_handler != NULL) g_clear_error (&error_handler); else config_output = btmp; btmp = g_key_file_get_boolean(settings_file, CONFIG_GROUP, "remember", &error_handler); if (error_handler != NULL) g_clear_error (&error_handler); else config_remember = btmp; btmp = g_key_file_get_boolean(settings_file, CONFIG_GROUP, "errorlist", &error_handler); if (error_handler != NULL) g_clear_error (&error_handler); else config_errorlist = btmp; btmp = g_key_file_get_boolean(settings_file, CONFIG_GROUP, "logging", &error_handler); if (error_handler != NULL) g_clear_error (&error_handler); else config_log = btmp; // load window position and size root_x = g_key_file_get_integer(settings_file, CONFIG_GROUP, "root_x", NULL); root_y = g_key_file_get_integer(settings_file, CONFIG_GROUP, "root_y", NULL); width = g_key_file_get_integer(settings_file, CONFIG_GROUP, "width", NULL); height = g_key_file_get_integer(settings_file, CONFIG_GROUP, "height", NULL); gtk_window_move((GtkWindow*) main_window, root_x, root_y); if (width > 0 && height > 0) gtk_window_resize((GtkWindow*) main_window, width, height); } // load specific session stmp = g_key_file_get_string(settings_file, session, "text_source", NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) main, "text_source"), stmp); g_free(stmp); stmp = g_key_file_get_string(settings_file, session, "text_dest", NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) main, "text_dest"), stmp); g_free(stmp); stmp = g_key_file_get_string(settings_file, session, "text_addit", NULL); if (stmp == NULL) stmp = g_strconcat("", NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) main, "entry_additional"), stmp); g_free(stmp); stmp = g_key_file_get_string(settings_file, session, "text_com_before", NULL); if (stmp == NULL) stmp = g_strconcat("", NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) main, "entry_com_before"), stmp); g_free(stmp); stmp = g_key_file_get_string(settings_file, session, "text_com_after", NULL); if (stmp == NULL) stmp = g_strconcat("", NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) main, "entry_com_after"), stmp); g_free(stmp); set_checkbox(main, "check_time", g_key_file_get_boolean(settings_file, session, "check_time", NULL)); set_checkbox(main, "check_perm", g_key_file_get_boolean(settings_file, session, "check_perm", NULL)); set_checkbox(main, "check_owner", g_key_file_get_boolean(settings_file, session, "check_owner", NULL)); set_checkbox(main, "check_group", g_key_file_get_boolean(settings_file, session, "check_group", NULL)); set_checkbox(main, "check_onefs", g_key_file_get_boolean(settings_file, session, "check_onefs", NULL)); set_checkbox(main, "check_verbose", g_key_file_get_boolean(settings_file, session, "check_verbose", NULL)); set_checkbox(main, "check_progr", g_key_file_get_boolean(settings_file, session, "check_progr", NULL)); set_checkbox(main, "check_delete", g_key_file_get_boolean(settings_file, session, "check_delete", NULL)); set_checkbox(main, "check_exist", g_key_file_get_boolean(settings_file, session, "check_exist", NULL)); set_checkbox(main, "check_size", g_key_file_get_boolean(settings_file, session, "check_size", NULL)); set_checkbox(main, "check_skipnew", g_key_file_get_boolean(settings_file, session, "check_skipnew", NULL)); set_checkbox(main, "check_windows", g_key_file_get_boolean(settings_file, session, "check_windows", NULL)); set_checkbox(main, "check_sum", g_key_file_get_boolean(settings_file, session, "check_sum", NULL)); set_checkbox(main, "check_symlink", g_key_file_get_boolean(settings_file, session, "check_symlink", NULL)); set_checkbox(main, "check_dev", g_key_file_get_boolean(settings_file, session, "check_dev", NULL)); set_checkbox(main, "check_update", g_key_file_get_boolean(settings_file, session, "check_update", NULL)); set_checkbox(main, "check_keepart", g_key_file_get_boolean(settings_file, session, "check_keepart", NULL)); set_checkbox(main, "check_mapuser", g_key_file_get_boolean(settings_file, session, "check_mapuser", NULL)); set_checkbox(main, "check_compr", g_key_file_get_boolean(settings_file, session, "check_compr", NULL)); set_checkbox(main, "check_backup", g_key_file_get_boolean(settings_file, session, "check_backup", NULL)); set_checkbox(main, "check_com_before", g_key_file_get_boolean(settings_file, session, "check_com_before", NULL)); set_checkbox(main, "check_com_after", g_key_file_get_boolean(settings_file, session, "check_com_after", NULL)); set_checkbox(main, "check_browse_files", g_key_file_get_boolean(settings_file, session, "check_browse_files", NULL)); g_key_file_free (settings_file); } void save_settings(GtkWidget* main, gchar *session, gchar *filename) { gchar settings_file_name[MAXPATH]; gchar *key_data; FILE *key_file; GError *error_handler = NULL; GKeyFile *settings_file; const gchar *stmp; gint root_x, root_y, width, height; if (filename == NULL) g_sprintf(settings_file_name, "%s/%s", grsync_dir, "grsync.ini"); else strncpy(settings_file_name, filename, MAXPATH-1); // g_printf(_("Saving settings to %s...\n"), settings_file_name); g_mkdir(grsync_dir, 0700); settings_file = g_key_file_new(); if (filename == NULL) { g_key_file_load_from_file(settings_file, settings_file_name, G_KEY_FILE_NONE, NULL); // save configuration (preferences) g_key_file_set_string(settings_file, CONFIG_GROUP, "command", config_command); g_key_file_set_boolean(settings_file, CONFIG_GROUP, "output", config_output); g_key_file_set_boolean(settings_file, CONFIG_GROUP, "remember", config_remember); g_key_file_set_boolean(settings_file, CONFIG_GROUP, "errorlist", config_errorlist); g_key_file_set_boolean(settings_file, CONFIG_GROUP, "logging", config_log); if (session_last != -1) g_key_file_set_string(settings_file, CONFIG_GROUP, "last_session", groups[session_last]); // window position and size gtk_window_get_position((GtkWindow*) main_window, &root_x, &root_y); gtk_window_get_size((GtkWindow*) main_window, &width, &height); g_key_file_set_integer(settings_file, CONFIG_GROUP, "root_x", root_x); g_key_file_set_integer(settings_file, CONFIG_GROUP, "root_y", root_y); g_key_file_set_integer(settings_file, CONFIG_GROUP, "width", width); g_key_file_set_integer(settings_file, CONFIG_GROUP, "height", height); } // save specific session stmp = gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) main, "text_source")); g_key_file_set_string(settings_file, session, "text_source", stmp); stmp = gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) main, "text_dest")); g_key_file_set_string(settings_file, session, "text_dest", stmp); stmp = gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) main, "entry_additional")); g_key_file_set_string(settings_file, session, "text_addit", stmp); stmp = gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) main, "entry_com_before")); g_key_file_set_string(settings_file, session, "text_com_before", stmp); stmp = gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) main, "entry_com_after")); g_key_file_set_string(settings_file, session, "text_com_after", stmp); g_key_file_set_boolean(settings_file, session, "check_time", get_checkbox(main, "check_time")); g_key_file_set_boolean(settings_file, session, "check_perm", get_checkbox(main, "check_perm")); g_key_file_set_boolean(settings_file, session, "check_owner", get_checkbox(main, "check_owner")); g_key_file_set_boolean(settings_file, session, "check_group", get_checkbox(main, "check_group")); g_key_file_set_boolean(settings_file, session, "check_onefs", get_checkbox(main, "check_onefs")); g_key_file_set_boolean(settings_file, session, "check_verbose", get_checkbox(main, "check_verbose")); g_key_file_set_boolean(settings_file, session, "check_progr", get_checkbox(main, "check_progr")); g_key_file_set_boolean(settings_file, session, "check_delete", get_checkbox(main, "check_delete")); g_key_file_set_boolean(settings_file, session, "check_exist", get_checkbox(main, "check_exist")); g_key_file_set_boolean(settings_file, session, "check_size", get_checkbox(main, "check_size")); g_key_file_set_boolean(settings_file, session, "check_skipnew", get_checkbox(main, "check_skipnew")); g_key_file_set_boolean(settings_file, session, "check_windows", get_checkbox(main, "check_windows")); g_key_file_set_boolean(settings_file, session, "check_sum", get_checkbox(main, "check_sum")); g_key_file_set_boolean(settings_file, session, "check_symlink", get_checkbox(main, "check_symlink")); g_key_file_set_boolean(settings_file, session, "check_dev", get_checkbox(main, "check_dev")); g_key_file_set_boolean(settings_file, session, "check_update", get_checkbox(main, "check_update")); g_key_file_set_boolean(settings_file, session, "check_keepart", get_checkbox(main, "check_keepart")); g_key_file_set_boolean(settings_file, session, "check_mapuser", get_checkbox(main, "check_mapuser")); g_key_file_set_boolean(settings_file, session, "check_compr", get_checkbox(main, "check_compr")); g_key_file_set_boolean(settings_file, session, "check_backup", get_checkbox(main, "check_backup")); g_key_file_set_boolean(settings_file, session, "check_com_before", get_checkbox(main, "check_com_before")); g_key_file_set_boolean(settings_file, session, "check_com_after", get_checkbox(main, "check_com_after")); g_key_file_set_boolean(settings_file, session, "check_browse_files", get_checkbox(main, "check_browse_files")); key_data = g_key_file_to_data(settings_file, NULL, &error_handler); key_file = fopen(settings_file_name, "w"); if (key_file != NULL) { fputs(key_data, key_file); fclose(key_file); } else { g_printf(_("\tUnable to save settings!\n")); } g_key_file_free(settings_file); g_clear_error(&error_handler); } int compare_strings (char **p1, char **p2) { return strcoll (*p1, *p2); } gboolean load_groups(GtkWidget* main, gchar *session) { gchar settings_file_path[MAXPATH], *stmp; g_sprintf(settings_file_path, "%s/%s", grsync_dir, "grsync.ini"); if (g_file_test(settings_file_path, G_FILE_TEST_EXISTS)) { GError *error_handler = NULL; GKeyFile *settings_file; GtkComboBox *combo; gint i; gboolean flag = FALSE; combo = (GtkComboBox*) lookup_widget(main, "combo_session"); // while (i = gtk_combo_box_get_active(combo) != -1) gtk_combo_box_remove_text(combo, i); for (i = 0; i < session_number; i++) gtk_combo_box_remove_text(combo, 0); settings_file = g_key_file_new(); g_key_file_load_from_file(settings_file, settings_file_path, G_KEY_FILE_NONE, &error_handler); groups = g_key_file_get_groups(settings_file, &session_number); if (!cmdline_session && first_load_groups && g_key_file_get_boolean(settings_file, CONFIG_GROUP, "remember", NULL)) { stmp = g_key_file_get_string(settings_file, CONFIG_GROUP, "last_session", NULL); if (stmp != NULL) { session = stmp; g_free(argv_session); argv_session = g_strconcat(session, NULL); } first_load_groups = FALSE; } i = 0; while (groups[i] != NULL) { if (strcmp(groups[i], CONFIG_GROUP) == 0) { session_number--; g_free(groups[i]); flag = TRUE; } else { if (i > 0 && flag) groups[i - 1] = groups[i]; } i++; } groups[session_number] = NULL; qsort(groups, session_number, sizeof(gchar*), compare_strings); i = 0; while (groups[i] != NULL) { gtk_combo_box_insert_text(combo, i, groups[i]); if (strcmp(groups[i], session) == 0) { gtk_combo_box_set_active(combo, i); session_last = i; } i++; } g_key_file_free (settings_file); g_clear_error (&error_handler); if (session_last == -1) return FALSE; } /* else { g_printf (_("(ERROR) Can't open config file! Maybe this is the first run?\n")); // return FALSE; } */ return TRUE; } void show_browse_source(GtkButton *button, gpointer user_data) { GtkWidget *dialog; gint retval; gboolean browse_files = get_checkbox((GtkWidget*) main_window, "check_browse_files"); GtkFileChooserAction action = browse_files ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; gchar *curr_path = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_source")); gchar *curr_folder = g_path_get_dirname(curr_path); dialog = gtk_file_chooser_dialog_new (_("Browse"), (GtkWindow*) main_window, action, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), curr_folder); if (browse_files) gtk_file_chooser_select_filename(GTK_FILE_CHOOSER (dialog), curr_path); retval = gtk_dialog_run (GTK_DIALOG (dialog)); if (retval == GTK_RESPONSE_ACCEPT || retval == GTK_RESPONSE_OK) { gchar *filename, *tmp; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); tmp = g_strconcat(filename, browse_files ? "" : "/", NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_source"), tmp); g_free(filename); g_free(tmp); } gtk_widget_destroy (dialog); g_free(curr_folder); } void show_browse_dest(GtkButton *button, gpointer user_data) { GtkWidget *dialog; gint retval; gboolean browse_files = get_checkbox((GtkWidget*) main_window, "check_browse_files"); GtkFileChooserAction action = browse_files ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; gchar *curr_path = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_dest")); gchar *curr_folder = g_path_get_dirname(curr_path); dialog = gtk_file_chooser_dialog_new (_("Browse"), (GtkWindow*) main_window, action, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), curr_folder); if (browse_files) gtk_file_chooser_select_filename(GTK_FILE_CHOOSER (dialog), curr_path); retval = gtk_dialog_run (GTK_DIALOG (dialog)); if (retval == GTK_RESPONSE_ACCEPT || retval == GTK_RESPONSE_OK) { gchar *filename, *tmp; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); tmp = g_strconcat(filename, browse_files ? "" : "/", NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_dest"), tmp); g_free (filename); g_free(tmp); } gtk_widget_destroy (dialog); g_free(curr_folder); } void on_play_clicked(GtkButton *button, gpointer user_data) { gint i = 0, j, argc_tmp; gchar **argv_tmp, *gtmp; argv = g_new(gchar *, MAXOPT); argv_tmp = g_new(gchar *, MAXOPT); argv[i++] = config_command; argv[i++] = "-r"; if (dryrunning) argv[i++] = "-n"; if (get_checkbox(button, "check_time")) argv[i++] = "-t"; if (get_checkbox(button, "check_perm")) argv[i++] = "-p"; if (get_checkbox(button, "check_owner")) argv[i++] = "-o"; if (get_checkbox(button, "check_group")) argv[i++] = "-g"; if (get_checkbox(button, "check_onefs")) argv[i++] = "-x"; if (get_checkbox(button, "check_verbose")) argv[i++] = "-v"; if (get_checkbox(button, "check_progr")) argv[i++] = "--progress"; if (get_checkbox(button, "check_delete")) argv[i++] = "--delete"; if (get_checkbox(button, "check_exist")) argv[i++] = "--ignore-existing"; if (get_checkbox(button, "check_size")) argv[i++] = "--size-only"; if (get_checkbox(button, "check_skipnew")) argv[i++] = "-u"; if (get_checkbox(button, "check_windows")) argv[i++] = "--modify-window=1"; if (get_checkbox(button, "check_sum")) argv[i++] = "-c"; if (get_checkbox(button, "check_symlink")) argv[i++] = "-l"; if (get_checkbox(button, "check_dev")) argv[i++] = "-D"; if (get_checkbox(button, "check_update")) argv[i++] = "--existing"; if (get_checkbox(button, "check_keepart")) argv[i++] = "--partial"; if (get_checkbox(button, "check_mapuser")) argv[i++] = "--numeric-ids"; if (get_checkbox(button, "check_compr")) argv[i++] = "-z"; if (get_checkbox(button, "check_backup")) argv[i++] = "-b"; gtmp = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) button, "entry_additional")); if (gtmp[0]) { g_shell_parse_argv(gtmp, &argc_tmp, &argv_tmp, NULL); for (j = 0; j < argc_tmp && i + 3 < MAXOPT; j++) argv[i++] = g_strconcat(argv_tmp[j], NULL); g_strfreev(argv_tmp); } // source, dest and NULL must follow only, or change the previous for cicle ending condition. argv[i++] = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_source")); argv[i++] = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_dest")); argv[i++] = NULL; paused = FALSE; rsync = create_dialog_rsync(); gtk_window_set_transient_for((GtkWindow*) rsync, (GtkWindow*) main_window); if (config_output || dryrunning) { gtk_expander_set_expanded((GtkExpander*) lookup_widget((GtkWidget*) rsync, "expander_rsync"), TRUE); } if (config_errorlist) error_list = g_strconcat("", NULL); if (config_log) { gtmp = g_strconcat(grsync_dir, "/", groups[session_last], ".log", NULL); log_file = fopen(gtmp, "w"); g_free(gtmp); } gtk_widget_show(rsync); gtk_window_set_title((GtkWindow*)rsync, "rsync: running"); if (dryrunning) gtk_label_set_text((GtkLabel*)lookup_widget((GtkWidget*) rsync, "label_file"), _("Simulation in progress")); } void on_dryrun_clicked (GtkButton *button, gpointer user_data) { dryrunning = TRUE; on_play_clicked(button, NULL); } void set_tooltip(GtkTooltips *tooltips, gchar *long_opt, gchar *widget_str) { gchar *tmpc, *tmpc2, *out, *opt; GtkWidget *widget; GtkTooltipsData *oldtip; opt = rsync_man != NULL ? g_strconcat(long_opt, "\n", NULL) : g_strconcat(long_opt, " ", NULL); out = rsync_man != NULL ? g_strconcat(rsync_man, NULL) : g_strconcat(rsync_help, NULL); tmpc = g_strrstr(out, opt); // tmpc = g_strstr_len(out, strlen(out), opt); if (tmpc != NULL && *tmpc) { while (*tmpc != '\n') tmpc--; tmpc++; tmpc2 = rsync_man != NULL ? strstr(tmpc, "\n\n\n") : strchr(tmpc, '\n'); *tmpc2 = '\0'; g_strstrip(tmpc); widget = (GtkWidget*) lookup_widget((GtkWidget*) main_window, widget_str); oldtip = gtk_tooltips_data_get(widget); if (oldtip != NULL) tmpc2 = g_strconcat(tmpc, "\n\n", oldtip->tip_text, NULL); else tmpc2 = g_strconcat(tmpc, NULL); gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), widget, tmpc2, ""); g_free(tmpc2); } g_free(opt); g_free(out); } void on_main_create(GtkWindow *window, gpointer user_data) { GtkWidget *error; gchar *stmp, *tmpc; GtkTooltips *rsync_tips; grsync_dir = g_strconcat(g_get_home_dir(), "/.grsync", NULL); if (!load_groups((GtkWidget*) window, argv_session)) { error = gtk_message_dialog_new(window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, _("The session you specified on the command line doesn't exists")); gtk_dialog_run(GTK_DIALOG(error)); gtk_widget_destroy(error); g_free(argv_session); argv_session = g_strconcat("default", NULL); load_groups((GtkWidget*) window, argv_session); } load_settings((GtkWidget*) window, argv_session, NULL); stmp = g_strconcat(config_command, " --help", NULL); if (!g_spawn_command_line_sync(stmp, &rsync_help, NULL, NULL, NULL)) { error = gtk_message_dialog_new(window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, _("Unable to execute the rsync command line tool. It is needed by this program. You may need to install the rsync package or make it available in the default executable search PATH. See file/preferences to change the default rsync executable command.")); gtk_dialog_run(GTK_DIALOG(error)); gtk_widget_destroy(error); } else { // g_spawn_command_line_sync("man rsync", &rsync_man, NULL, NULL, NULL); rsync_tips = gtk_tooltips_new(); set_tooltip(rsync_tips, "--times", "check_time"); set_tooltip(rsync_tips, "--perms", "check_perm"); set_tooltip(rsync_tips, "--owner", "check_owner"); set_tooltip(rsync_tips, "--group", "check_group"); set_tooltip(rsync_tips, "--one-file-system", "check_onefs"); set_tooltip(rsync_tips, "--verbose", "check_verbose"); set_tooltip(rsync_tips, "--progress", "check_progr"); set_tooltip(rsync_tips, "--delete", "check_delete"); set_tooltip(rsync_tips, "--ignore-existing", "check_exist"); set_tooltip(rsync_tips, "--size-only", "check_size"); set_tooltip(rsync_tips, "--update", "check_skipnew"); set_tooltip(rsync_tips, "--modify-window=NUM", "check_windows"); set_tooltip(rsync_tips, "--checksum", "check_sum"); set_tooltip(rsync_tips, "--links", "check_symlink"); set_tooltip(rsync_tips, "-D", "check_dev"); set_tooltip(rsync_tips, "--existing", "check_update"); set_tooltip(rsync_tips, "--partial", "check_keepart"); set_tooltip(rsync_tips, "--numeric-ids", "check_mapuser"); set_tooltip(rsync_tips, "--compress", "check_compr"); set_tooltip(rsync_tips, "--backup", "check_backup"); } g_free(stmp); if (cmdline_execute) on_play_clicked((GtkButton*) window, NULL); } void on_main_destroy(GtkObject *object, gpointer user_data) { gint sel = gtk_combo_box_get_active((GtkComboBox*) lookup_widget((GtkWidget*) object, "combo_session")); save_settings((GtkWidget*) object, groups[sel], NULL); g_strfreev(groups); if (rsync_help != NULL) g_free(rsync_help); if (rsync_man != NULL) g_free(rsync_man); gtk_main_quit(); } void on_close_clicked(GtkButton *button, gpointer user_data) { if (rsync_pid) { if (paused) kill(rsync_pid, SIGCONT); kill(rsync_pid, SIGTERM); gtk_widget_set_sensitive(lookup_widget((GtkWidget*) button, "button_pause"), FALSE); } else { gtk_widget_destroy(rsync); set_main_title(groups[session_last], NULL); rsync = NULL; } if (cmdline_execute) on_main_destroy((GtkObject*) main_window, NULL); } void set_global_progress(GtkProgressBar* progr, gdouble fraction) { GTimeVal curtime; glong elapsed, remaining; gchar tmps[50]; gtk_progress_bar_set_fraction(progr, fraction); g_get_current_time(&curtime); elapsed = curtime.tv_sec - startime.tv_sec; remaining = elapsed / fraction - elapsed; snprintf(tmps, 49, _("%.f%% (%li:%02li elapsed, %li:%02li remaining)"), round(fraction * 100), elapsed / 60, elapsed % 60, remaining / 60, remaining % 60); gtk_progress_bar_set_text(progr, tmps); set_main_title(groups[session_last], tmps); } void scroll_to_end(GtkTextView* view) { GtkTextBuffer *buffer; GtkTextIter iter; GtkTextMark *mark; buffer = gtk_text_view_get_buffer(view); gtk_text_buffer_get_end_iter(buffer, &iter); mark = gtk_text_buffer_create_mark(buffer, "end_mark", &iter, TRUE); gtk_text_view_scroll_mark_onscreen(view, mark); gtk_text_buffer_delete_mark(buffer, mark); } void rsync_cleanup(gpointer data) { gchar tmps[50]; GTimeVal curtime; glong elapsed; GtkWidget *errors; GtkTextBuffer *buffer; GtkTextView *view; GtkTextIter iter; GtkTextTag *tag; gchar *comm_str, *comm_out, *comm_err, *comm_after; if (channel_closed) { view = (GtkTextView*) lookup_widget((GtkWidget*) data, "textview_output"); if (get_checkbox((GtkWidget*) main_window, "check_com_after")) { comm_str = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) main_window, "entry_com_after")); if (!g_spawn_command_line_sync(comm_str, &comm_out, &comm_err, NULL, NULL)) { comm_out = g_strconcat("", NULL); comm_err = g_strconcat("Error launching command!\n", NULL); } comm_after = g_strconcat("\n", _("*** Launching AFTER command:\n"), comm_str, "\n", comm_out, comm_err, NULL); g_free(comm_out); g_free(comm_err); buffer = gtk_text_view_get_buffer(view); gtk_text_buffer_insert_at_cursor(buffer, comm_after, -1); scroll_to_end(view); if (config_log) fputs(comm_after, log_file); g_free(comm_after); } gtk_button_set_label((GtkButton*) lookup_widget((GtkWidget*) data, "close"), "gtk-close"); GtkLabel *tmpl = (GtkLabel*) lookup_widget((GtkWidget*) data, "label_file"); if (had_error) { gtk_label_set_markup(tmpl, _("Completed with errors!")); } else { gtk_label_set_markup(tmpl, _("Completed successfully!")); set_global_progress((GtkProgressBar*) lookup_widget((GtkWidget*) data, "progress_global"), 1); } gtk_widget_set_sensitive(lookup_widget((GtkWidget*) data, "button_pause"), FALSE); gtk_widget_set_sensitive((GtkWidget*) view, TRUE); gtk_window_set_title((GtkWindow*) rsync, "rsync: stopped"); g_spawn_close_pid(rsync_pid); rsync_pid = 0; g_free(argv); if (config_errorlist && had_error) { errors = create_dialog_errors(); gtk_window_set_transient_for((GtkWindow*) errors, (GtkWindow*) rsync); buffer = gtk_text_view_get_buffer((GtkTextView*) lookup_widget(errors, "textview_errors")); tag = gtk_text_buffer_create_tag(buffer, "fore-red", "foreground", "red", NULL); gtk_text_buffer_get_start_iter(buffer, &iter); gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, error_list, -1, "fore-red", NULL); gtk_widget_show(errors); g_free(error_list); } dryrunning = FALSE; if (cmdline_execute) on_close_clicked((GtkButton*) data, NULL); } else { channel_closed = TRUE; } } gboolean out_watch(GIOChannel *source, GIOCondition condition, gpointer data) { GtkTextBuffer *buffer; GtkTextIter iter, iter2; GString *str; GtkProgressBar *tmpp; static gchar *carriage = NULL, *oldfile = NULL; gchar *file, tmps[50]; gdouble fraction, done, total; if (condition & G_IO_IN) { buffer = gtk_text_view_get_buffer((GtkTextView*)data); if (carriage != NULL) { gtk_text_buffer_get_iter_at_line(buffer, &iter, gtk_text_buffer_get_line_count(buffer) - 2); gtk_text_buffer_get_end_iter(buffer, &iter2); gtk_text_buffer_delete(buffer, &iter, &iter2); } str = g_string_new(""); g_io_channel_read_line_string(source, str, NULL, NULL); carriage = strchr(str->str, '\r'); gtk_text_buffer_insert_at_cursor(buffer, (gchar*)str->str, -1); scroll_to_end((GtkTextView*)data); if (config_log) fputs((gchar*)str->str, log_file); if (!dryrunning) { if (strchr(str->str, '%') && str->str[0] == ' ') { if (oldfile != NULL) file = g_strconcat(oldfile, NULL); else file = g_strconcat(str->str, NULL); fraction = g_ascii_strtod(strchr(strchr(str->str, '%') - 4, ' '), NULL) / 100; tmpp = (GtkProgressBar*)lookup_widget((GtkWidget*) data, "progress_file"); gtk_progress_bar_set_fraction(tmpp, fraction); snprintf(tmps, 5, "%.f%%", round(fraction * 100)); gtk_progress_bar_set_text(tmpp, tmps); fraction = 0; if (strchr(str->str, '%') != strrchr(str->str, '%')) fraction = g_ascii_strtod(strchr(strrchr(str->str, '%') - 6, ' '), NULL) / 100; else if (strchr(str->str, '=')) { total = g_ascii_strtod(strrchr(str->str, '/') + 1, NULL); done = total - g_ascii_strtod(strrchr(str->str, '=') + 1, NULL); fraction = done / total; } if (fraction) set_global_progress((GtkProgressBar*)lookup_widget((GtkWidget*) data, "progress_global"), fraction); } else { file = g_strconcat(str->str, NULL); if (oldfile != NULL) g_free(oldfile); oldfile = g_strconcat(str->str, NULL); } g_strchomp(file); if (file[0] != 0) gtk_label_set_text((GtkLabel*)lookup_widget((GtkWidget*) data, "label_file"), file); g_free(file); } g_string_free(str, TRUE); } else { // if (condition & G_IO_HUP || condition & G_IO_ERR) { g_io_channel_shutdown (source, FALSE, NULL); g_io_channel_unref (source); rsync_cleanup(data); if (oldfile != NULL) g_free(oldfile); oldfile = NULL; return FALSE; } return TRUE; } gboolean err_watch(GIOChannel *source, GIOCondition condition, gpointer data) { GtkTextBuffer *buffer; GtkTextIter iter; // GIOStatus status; GString *str; gchar *tmpc; if (condition & G_IO_IN) { buffer = gtk_text_view_get_buffer((GtkTextView*)data); str = g_string_new(""); g_io_channel_read_line_string(source, str, NULL, NULL); if (str->len > 2) had_error = TRUE; // if (status == G_IO_STATUS_NORMAL) { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, (gchar*)str->str, -1, "fore-red", NULL); scroll_to_end((GtkTextView*)data); // } if (config_log) { // fputs("*ERROR* ", log_file); fputs((gchar*)str->str, log_file); } tmpc = g_strconcat(error_list, str->str, NULL); g_free(error_list); error_list = tmpc; g_string_free(str, TRUE); } else { // if (condition & G_IO_HUP || condition & G_IO_ERR) { g_io_channel_shutdown (source, FALSE, NULL); g_io_channel_unref (source); rsync_cleanup(data); return FALSE; } return TRUE; } void on_rsync_show(GtkWidget *widget, gpointer user_data) { gint out, err, i; // gint bogus; GtkTextBuffer *buffer; GtkTextView *view; GIOChannel *chout, *cherr; GtkTextTag *tag; GtkWidget *error; gchar *comm_str, *comm_text, *comm_out, *comm_err, *comm_before, *tmpc; rsync_pid = 0; had_error = FALSE; gtk_label_set_ellipsize((GtkLabel*)lookup_widget(widget, "label_file"), PANGO_ELLIPSIZE_MIDDLE); if (get_checkbox((GtkWidget*) main_window, "check_com_before")) { comm_str = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) main_window, "entry_com_before")); if (!g_spawn_command_line_sync(comm_str, &comm_out, &comm_err, NULL, NULL)) { comm_out = g_strconcat("", NULL); comm_err = g_strconcat("Error launching command!\n", NULL); } comm_before = g_strconcat(_("*** Launching BEFORE command:\n"), comm_str, "\n", comm_out, comm_err, "\n", NULL); g_free(comm_out); g_free(comm_err); } else { comm_before = g_strconcat("", NULL); } comm_str = g_strjoinv(" ", argv); if (dryrunning) tmpc =_("*** Launching RSYNC command (simulation mode):\n"); else tmpc = _("*** Launching RSYNC command:\n"); comm_text = g_strconcat(comm_before, tmpc, comm_str, "\n\n", NULL); g_free(comm_before); g_free(comm_str); view = (GtkTextView*)lookup_widget(widget, "textview_output"); buffer = gtk_text_view_get_buffer(view); gtk_text_buffer_insert_at_cursor(buffer, comm_text, -1); if (config_log) fputs(comm_text, log_file); g_free(comm_text); // gtk_widget_get_size_request((GtkWidget*) lookup_widget(widget, "scrolled1"), &bogus, &height_expander); g_get_current_time(&startime); if (g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &rsync_pid, NULL, &out, &err, NULL)) { chout = g_io_channel_unix_new (out); cherr = g_io_channel_unix_new (err); g_io_channel_set_flags(chout, G_IO_FLAG_NONBLOCK, NULL); g_io_channel_set_flags(cherr, G_IO_FLAG_NONBLOCK, NULL); // g_io_channel_set_buffer_size(chout, 32); // g_io_channel_set_encoding(chout, NULL, NULL); g_io_channel_set_buffered(chout, FALSE); tag = gtk_text_buffer_create_tag(buffer, "fore-red", "foreground", "red", NULL); channel_closed = FALSE; g_io_add_watch_full(chout, G_PRIORITY_DEFAULT_IDLE, G_IO_IN | G_IO_HUP | G_IO_ERR, out_watch, view, NULL); g_io_add_watch_full(cherr, G_PRIORITY_DEFAULT_IDLE, G_IO_IN | G_IO_HUP | G_IO_ERR, err_watch, view, NULL); } else { gtk_button_set_label((GtkButton*)lookup_widget(widget, "close"), "gtk-close"); gtk_widget_set_sensitive(lookup_widget(widget, "button_pause"), FALSE); error = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, _("Cannot execute rsync")); gtk_dialog_run(GTK_DIALOG(error)); gtk_widget_destroy(error); } } void on_rsync_destroy(GtkObject *object, gpointer user_data) { if (rsync_pid) { if (paused) kill(rsync_pid, SIGCONT); kill(rsync_pid, SIGTERM); } if (log_file != NULL) { fclose(log_file); log_file = NULL; } } void on_combo_session_changed (GtkComboBox *combobox, gpointer user_data) { gint sel = gtk_combo_box_get_active((GtkComboBox*) lookup_widget((GtkWidget*) combobox, "combo_session")); if (session_last != -1 && sel != session_last) { save_settings((GtkWidget*) combobox, groups[session_last], NULL); session_last = sel; load_settings((GtkWidget*) combobox, groups[session_last], NULL); } } void on_session_add_clicked(GtkButton *button, gpointer user_data) { GtkWidget *add, *confirm; gint result, i = 0; add = create_dialog_new_session(); gtk_window_set_transient_for((GtkWindow*) add, (GtkWindow*) main_window); result = gtk_dialog_run ((GtkDialog*) add); if (result == GTK_RESPONSE_OK) { gchar *newses; newses = (gchar*) gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) add, "entry_session_name")); if (strcmp(CONFIG_GROUP, newses) == 0) { confirm = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, _("This session name is reserved, you cannot call it like this")); gtk_dialog_run(GTK_DIALOG(confirm)); gtk_widget_destroy(confirm); gtk_widget_destroy(add); return; } while (groups[i] != NULL && strcmp(groups[i], newses)) i++; if (groups[i] != NULL) { confirm = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, _("A session named like this already exists")); gtk_dialog_run(GTK_DIALOG(confirm)); gtk_widget_destroy(confirm); gtk_widget_destroy(add); return; } save_settings((GtkWidget*) button, newses, NULL); session_number++; load_groups((GtkWidget*) button, newses); } gtk_widget_destroy(add); } void on_session_del_clicked(GtkButton *button, gpointer user_data) { gchar settings_file_name[MAXPATH]; gchar *key_data; FILE *key_file; GError *error_handler = NULL; GKeyFile *settings_file; gint i, result; GtkWidget *confirm; i = gtk_combo_box_get_active((GtkComboBox*) lookup_widget((GtkWidget*) button, "combo_session")); if (strcmp(groups[i], "default") == 0) { confirm = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, _("You cannot delete the default session")); gtk_dialog_run(GTK_DIALOG(confirm)); gtk_widget_destroy(confirm); return; } confirm = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, _("Are you sure you want to delete the '%s' session?"), groups[i]); result = gtk_dialog_run(GTK_DIALOG(confirm)); gtk_widget_destroy(confirm); if (result == GTK_RESPONSE_OK) { g_sprintf(settings_file_name, "%s/%s", grsync_dir, "grsync.ini"); settings_file = g_key_file_new(); g_key_file_load_from_file(settings_file, settings_file_name, G_KEY_FILE_NONE, NULL); g_key_file_remove_group(settings_file, groups[i], &error_handler); key_data = g_key_file_to_data(settings_file, NULL, &error_handler); key_file = fopen(settings_file_name, "w"); if (key_file != NULL) { fputs(key_data, key_file); fclose(key_file); } else { g_printf(_("\tUnable to save settings!\n")); } g_key_file_free(settings_file); g_clear_error(&error_handler); session_last = -1; load_groups((GtkWidget*) button, "default"); load_settings((GtkWidget*) button, "default", NULL); } } void on_button_about_clicked(GtkButton *button, gpointer user_data) { // GtkWidget *about = gtk_about_dialog_new(); GdkPixbuf *pixbuf; pixbuf = create_pixbuf("grsync.png"); gtk_show_about_dialog((GtkWindow*) main_window, "name", PACKAGE, "version", VERSION, "logo", pixbuf, "comments", _("A GTK GUI for rsync"), "copyright", _("(C) Piero Orsoni and others. Released under the GPL.\nSee AUTHORS and COPYING for details"), "website", "http://www.opbyte.it/grsync/", NULL); gdk_pixbuf_unref(pixbuf); } void on_button_switch_clicked (GtkButton *button, gpointer user_data) { const gchar *tmps, *tmpd; gchar *tmp; tmps = gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_source")); tmpd = gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_dest")); tmp = g_strconcat(tmps, NULL); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_source"), tmpd); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) button, "text_dest"), tmp); g_free(tmp); } void on_button_pause_clicked(GtkButton *button, gpointer user_data) { GtkButton *tmpbutt = (GtkButton*)lookup_widget((GtkWidget*) button, "button_pause"); GTimeVal tmptime; if (paused) { if (rsync_pid) kill(rsync_pid, SIGCONT); gtk_button_set_label(tmpbutt, "gtk-media-pause"); gtk_window_set_title((GtkWindow*)rsync, "rsync: running"); g_get_current_time(&tmptime); startime.tv_sec += tmptime.tv_sec - pausedtime.tv_sec; startime.tv_usec += tmptime.tv_usec - pausedtime.tv_usec; } else { if (rsync_pid) kill(rsync_pid, SIGSTOP); gtk_button_set_label(tmpbutt, "gtk-media-play"); gtk_window_set_title((GtkWindow*)rsync, "rsync: paused"); g_get_current_time(&pausedtime); } paused = !paused; } void on_preferences1_activate(GtkMenuItem *menuitem, gpointer user_data) { GtkWidget *config; gint result; config = create_dialog_config(); gtk_window_set_transient_for((GtkWindow*) config, (GtkWindow*) main_window); gtk_entry_set_text((GtkEntry*) lookup_widget((GtkWidget*) config, "entry_command"), config_command); set_checkbox(config, "check_output", config_output); set_checkbox(config, "check_remember", config_remember); set_checkbox(config, "check_errorlist", config_errorlist); set_checkbox(config, "check_log", config_log); result = gtk_dialog_run((GtkDialog*) config); if (result == GTK_RESPONSE_OK) { strncpy(config_command, gtk_entry_get_text((GtkEntry*) lookup_widget((GtkWidget*) config, "entry_command")), MAXPATH - 1); config_output = get_checkbox(config, "check_output"); config_remember = get_checkbox(config, "check_remember"); config_errorlist = get_checkbox(config, "check_errorlist"); config_log = get_checkbox(config, "check_log"); } gtk_widget_destroy(config); } void on_rsync_info_activate(GtkMenuItem *menuitem, gpointer user_data) { GtkWidget *dialog; gchar *tmps, *result; tmps = g_strconcat(config_command, " --version", NULL); g_spawn_command_line_sync(tmps, &result, NULL, NULL, NULL); dialog = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, result); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); g_free(tmps); g_free(result); } void on_import1_activate(GtkMenuItem *menuitem, gpointer user_data) { GtkWidget *dialog, *dialog2; gint retval, i; dialog = gtk_file_chooser_dialog_new (_("Browse"), (GtkWindow*) main_window, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); retval = gtk_dialog_run (GTK_DIALOG (dialog)); if (retval == GTK_RESPONSE_ACCEPT || retval == GTK_RESPONSE_OK) { gchar *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); load_settings((GtkWidget*) menuitem, NULL, filename); dialog2 = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _("Session imported")); gtk_dialog_run(GTK_DIALOG(dialog2)); gtk_widget_destroy(dialog2); g_free(filename); } gtk_widget_destroy (dialog); } void on_export1_activate (GtkMenuItem *menuitem, gpointer user_data) { GtkWidget *dialog, *dialog2; gchar *filename; gint retval, i; i = gtk_combo_box_get_active((GtkComboBox*) lookup_widget((GtkWidget*) menuitem, "combo_session")); dialog = gtk_file_chooser_dialog_new (_("Browse"), (GtkWindow*) main_window, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); filename = g_strconcat(groups[i], ".grsync", NULL); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename); g_free(filename); retval = gtk_dialog_run (GTK_DIALOG (dialog)); if (retval == GTK_RESPONSE_ACCEPT || retval == GTK_RESPONSE_OK) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); save_settings((GtkWidget*) menuitem, groups[i], filename); dialog2 = gtk_message_dialog_new((GtkWindow*) main_window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, _("Session exported")); gtk_dialog_run(GTK_DIALOG(dialog2)); gtk_widget_destroy(dialog2); g_free(filename); } gtk_widget_destroy (dialog); }