Files
evolution/modules/backup-restore/evolution-backup-tool.c
Matthew Barnes 6f7c3dd230 backup-restore: Add version info to evolution.dirs file.
Store the Evolution version used to create the backup file in the
evolution.dir file which is part of the tarball.

After restoring the backup file we need to reset the last-used-version
key in GSettings to the version listed in the evolution.dir file so the
proper migration routines run when Evolution is restarted.
2012-08-10 08:40:25 -04:00

1021 lines
25 KiB
C

/*
* evolution-backup-tool.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) version 3.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <libedataserver/libedataserver.h>
#ifdef G_OS_WIN32
#ifdef DATADIR
#undef DATADIR
#endif
#include <windows.h>
#include <conio.h>
#ifndef PROCESS_DEP_ENABLE
#define PROCESS_DEP_ENABLE 0x00000001
#endif
#ifndef PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION
#define PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION 0x00000002
#endif
#endif
#include "e-util/e-util-private.h"
#include "e-util/e-util.h"
#define EVOUSERDATADIR_MAGIC "#EVO_USERDATADIR#"
#define EVOLUTION "evolution"
#define EVOLUTION_DIR "$DATADIR/"
#define EVOLUTION_DIR_FILE EVOLUTION ".dir"
#define ANCIENT_GCONF_DUMP_FILE "backup-restore-gconf.xml"
#define DCONF_DUMP_FILE_EDS "backup-restore-dconf-eds.ini"
#define DCONF_DUMP_FILE_EVO "backup-restore-dconf-evo.ini"
#define DCONF_PATH_EDS "/org/gnome/evolution-data-server/"
#define DCONF_PATH_EVO "/org/gnome/evolution/"
#define KEY_FILE_GROUP "Evolution Backup"
static gboolean backup_op = FALSE;
static gchar *bk_file = NULL;
static gboolean restore_op = FALSE;
static gchar *res_file = NULL;
static gboolean check_op = FALSE;
static gchar *chk_file = NULL;
static gboolean restart_arg = FALSE;
static gboolean gui_arg = FALSE;
static gchar **opt_remaining = NULL;
static gint result = 0;
static GtkWidget *progress_dialog;
static GtkWidget *pbar;
static gchar *txt = NULL;
static GOptionEntry options[] = {
{ "backup", '\0', 0, G_OPTION_ARG_NONE, &backup_op,
N_("Back up Evolution directory"), NULL },
{ "restore", '\0', 0, G_OPTION_ARG_NONE, &restore_op,
N_("Restore Evolution directory"), NULL },
{ "check", '\0', 0, G_OPTION_ARG_NONE, &check_op,
N_("Check Evolution Back up"), NULL },
{ "restart", '\0', 0, G_OPTION_ARG_NONE, &restart_arg,
N_("Restart Evolution"), NULL },
{ "gui", '\0', 0, G_OPTION_ARG_NONE, &gui_arg,
N_("With Graphical User Interface"), NULL },
{ G_OPTION_REMAINING, '\0', 0,
G_OPTION_ARG_STRING_ARRAY, &opt_remaining },
{ NULL }
};
#define d(x)
#define print_and_run(x) \
G_STMT_START { g_message ("%s", x); system (x); } G_STMT_END
static gboolean check (const gchar *filename, gboolean *is_new_format);
static GString *
replace_string (const gchar *text,
const gchar *find,
const gchar *replace)
{
const gchar *p, *next;
GString *str;
gint find_len;
g_return_val_if_fail (text != NULL, NULL);
g_return_val_if_fail (find != NULL, NULL);
g_return_val_if_fail (*find, NULL);
find_len = strlen (find);
str = g_string_new ("");
p = text;
while (next = strstr (p, find), next) {
if (p < next)
g_string_append_len (str, p, next - p);
if (replace && *replace)
g_string_append (str, replace);
p = next + find_len;
}
g_string_append (str, p);
return str;
}
static const gchar *
strip_home_dir (const gchar *dir)
{
const gchar *home_dir, *res;
g_return_val_if_fail (dir != NULL, NULL);
home_dir = g_get_home_dir ();
g_return_val_if_fail (home_dir != NULL, dir);
g_return_val_if_fail (*home_dir != '\0', dir);
res = dir;
if (g_str_has_prefix (res, home_dir))
res += strlen (home_dir);
if (*res == G_DIR_SEPARATOR)
res++;
return res;
}
static GString *
replace_variables (const gchar *str)
{
GString *res = NULL, *use;
const gchar *strip_datadir, *strip_configdir;
g_return_val_if_fail (str != NULL, NULL);
strip_datadir = strip_home_dir (e_get_user_data_dir ());
strip_configdir = strip_home_dir (e_get_user_config_dir ());
#define repl(_find, _replace) \
use = replace_string (res ? res->str : str, _find, _replace); \
g_return_val_if_fail (use != NULL, NULL); \
if (res) \
g_string_free (res, TRUE); \
res = use;
repl ("$HOME", g_get_home_dir ());
repl ("$TMP", g_get_tmp_dir ());
repl ("$DATADIR", e_get_user_data_dir ());
repl ("$CONFIGDIR", e_get_user_config_dir ());
repl ("$STRIPDATADIR", strip_datadir);
repl ("$STRIPCONFIGDIR", strip_configdir);
#undef repl
g_return_val_if_fail (res != NULL, NULL);
/* remove trailing dir separator */
while (res->len > 0 && res->str[res->len - 1] == G_DIR_SEPARATOR) {
g_string_truncate (res, res->len - 1);
}
return res;
}
static void
replace_in_file (const gchar *filename,
const gchar *find,
const gchar *replace)
{
gchar *content = NULL;
GError *error = NULL;
GString *filenamestr = NULL;
g_return_if_fail (filename != NULL);
g_return_if_fail (find != NULL);
g_return_if_fail (*find);
g_return_if_fail (replace != NULL);
if (strstr (filename, "$")) {
filenamestr = replace_variables (filename);
if (!filenamestr) {
g_warning (
"%s: Replace variables in '%s' failed!",
G_STRFUNC, filename);
return;
}
filename = filenamestr->str;
}
if (g_file_get_contents (filename, &content, NULL, &error)) {
GString *str = replace_string (content, find, replace);
if (str) {
if (!g_file_set_contents (filename, str->str, -1, &error) && error) {
g_warning (
"%s: cannot write file content, "
"error: %s", G_STRFUNC, error->message);
g_error_free (error);
}
g_string_free (str, TRUE);
} else {
g_warning (
"%s: Replace of '%s' to '%s' failed!",
G_STRFUNC, find, replace);
}
g_free (content);
} else if (error) {
g_warning (
"%s: Cannot read file content, error: %s",
G_STRFUNC, error->message);
g_error_free (error);
}
if (filenamestr)
g_string_free (filenamestr, TRUE);
}
static void
run_cmd (const gchar *cmd)
{
if (!cmd)
return;
if (strstr (cmd, "$") != NULL) {
/* read the doc for g_get_home_dir to know why replacing it here */
GString *str = replace_variables (cmd);
if (str) {
print_and_run (str->str);
g_string_free (str, TRUE);
}
} else
print_and_run (cmd);
}
static void
run_evolution_no_wait (void)
{
g_spawn_command_line_async (EVOLUTION, NULL);
}
static void
write_dir_file (void)
{
GString *content, *filename;
GError *error = NULL;
filename = replace_variables ("$HOME/" EVOLUTION_DIR_FILE);
g_return_if_fail (filename != NULL);
content = replace_variables (
"[" KEY_FILE_GROUP "]\n"
"Version=" VERSION "\n"
"UserDataDir=$STRIPDATADIR\n"
"UserConfigDir=$STRIPCONFIGDIR\n");
g_return_if_fail (content != NULL);
g_file_set_contents (filename->str, content->str, content->len, &error);
if (error) {
g_warning ("Failed to write file '%s': %s\n", filename->str, error->message);
g_error_free (error);
}
g_string_free (filename, TRUE);
g_string_free (content, TRUE);
}
static void
backup (const gchar *filename,
GCancellable *cancellable)
{
gchar *command;
gchar *quotedfname;
g_return_if_fail (filename && *filename);
quotedfname = g_shell_quote (filename);
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Shutting down Evolution");
/* FIXME Will the versioned setting always work? */
run_cmd (EVOLUTION " --quit");
run_cmd ("rm $DATADIR/.running");
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Backing Evolution accounts and settings");
run_cmd ("dconf dump " DCONF_PATH_EDS " >" EVOLUTION_DIR DCONF_DUMP_FILE_EDS);
run_cmd ("dconf dump " DCONF_PATH_EVO " >" EVOLUTION_DIR DCONF_DUMP_FILE_EVO);
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EDS,
e_get_user_data_dir (), EVOUSERDATADIR_MAGIC);
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EVO,
e_get_user_data_dir (), EVOUSERDATADIR_MAGIC);
write_dir_file ();
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Backing Evolution data (Mails, Contacts, Calendar, Tasks, Memos)");
/* FIXME stay on this file system ,other options?" */
/* FIXME compression type?" */
/* FIXME date/time stamp?" */
/* FIXME backup location?" */
command = g_strdup_printf (
"cd $HOME && tar chf - $STRIPDATADIR "
"$STRIPCONFIGDIR .camel_certs " EVOLUTION_DIR_FILE " | "
"gzip > %s", quotedfname);
run_cmd (command);
g_free (command);
g_free (quotedfname);
run_cmd ("rm $HOME/" EVOLUTION_DIR_FILE);
txt = _("Back up complete");
if (restart_arg) {
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Restarting Evolution");
run_evolution_no_wait ();
}
}
static void
extract_backup_data (const gchar *filename,
gchar **restored_version,
gchar **data_dir,
gchar **config_dir)
{
GKeyFile *key_file;
GError *error = NULL;
g_return_if_fail (filename != NULL);
g_return_if_fail (data_dir != NULL);
g_return_if_fail (config_dir != NULL);
key_file = g_key_file_new ();
g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &error);
if (error) {
g_warning ("Failed to read '%s': %s", filename, error->message);
g_error_free (error);
/* This is the current format as of Evolution 3.6. */
} else if (g_key_file_has_group (key_file, KEY_FILE_GROUP)) {
gchar *tmp;
tmp = g_key_file_get_value (
key_file, KEY_FILE_GROUP, "Version", NULL);
if (tmp != NULL)
*restored_version = g_strstrip (g_strdup (tmp));
g_free (tmp);
tmp = g_key_file_get_value (
key_file, KEY_FILE_GROUP, "UserDataDir", NULL);
if (tmp != NULL)
*data_dir = g_shell_quote (tmp);
g_free (tmp);
tmp = g_key_file_get_value (
key_file, KEY_FILE_GROUP, "UserConfigDir", NULL);
if (tmp != NULL)
*config_dir = g_shell_quote (tmp);
g_free (tmp);
/* This is the legacy format with no version information. */
} else if (g_key_file_has_group (key_file, "dirs")) {
gchar *tmp;
tmp = g_key_file_get_value (key_file, "dirs", "data", NULL);
if (tmp)
*data_dir = g_shell_quote (tmp);
g_free (tmp);
tmp = g_key_file_get_value (key_file, "dirs", "config", NULL);
if (tmp)
*config_dir = g_shell_quote (tmp);
g_free (tmp);
}
g_key_file_free (key_file);
}
static gint
get_dir_level (const gchar *dir)
{
gint res = 0, i;
g_return_val_if_fail (dir != NULL, -1);
for (i = 0; dir[i]; i++) {
if (dir[i] == '/' || dir[i] == '\\')
res++;
}
if (i > 0)
res++;
return res;
}
static void
restore (const gchar *filename,
GCancellable *cancellable)
{
gchar *command;
gchar *quotedfname;
gboolean is_new_format = FALSE;
g_return_if_fail (filename && *filename);
if (!check (filename, &is_new_format)) {
g_message ("Cannot restore from an incorrect archive '%s'.", filename);
goto end;
}
quotedfname = g_shell_quote (filename);
if (g_cancellable_is_cancelled (cancellable))
return;
/* FIXME Will the versioned setting always work? */
txt = _("Shutting down Evolution");
run_cmd (EVOLUTION " --quit");
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Back up current Evolution data");
run_cmd ("mv $DATADIR $DATADIR_old");
run_cmd ("mv $CONFIGDIR $CONFIGDIR_old");
run_cmd ("mv $HOME/.camel_certs $HOME/.camel_certs_old");
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Extracting files from back up");
if (is_new_format) {
GString *dir_fn;
gchar *data_dir = NULL;
gchar *config_dir = NULL;
gchar *restored_version = NULL;
command = g_strdup_printf (
"cd $TMP && tar xzf %s "
EVOLUTION_DIR_FILE, quotedfname);
run_cmd (command);
g_free (command);
dir_fn = replace_variables ("$TMP" G_DIR_SEPARATOR_S EVOLUTION_DIR_FILE);
if (!dir_fn) {
g_warning ("Failed to create evolution's dir filename");
goto end;
}
/* data_dir and config_dir are quoted inside extract_backup_data */
extract_backup_data (
dir_fn->str,
&restored_version,
&data_dir,
&config_dir);
g_unlink (dir_fn->str);
g_string_free (dir_fn, TRUE);
if (!data_dir || !config_dir) {
g_warning (
"Failed to get old data_dir (%p)/"
"config_dir (%p)", data_dir, config_dir);
g_free (data_dir);
g_free (config_dir);
goto end;
}
g_mkdir_with_parents (e_get_user_data_dir (), 0700);
g_mkdir_with_parents (e_get_user_config_dir (), 0700);
command = g_strdup_printf (
"cd $DATADIR && tar xzf %s %s --strip-components=%d",
quotedfname, data_dir, get_dir_level (data_dir));
run_cmd (command);
g_free (command);
command = g_strdup_printf (
"cd $CONFIGDIR && tar xzf %s %s --strip-components=%d",
quotedfname, config_dir, get_dir_level (config_dir));
run_cmd (command);
g_free (command);
command = g_strdup_printf (
"cd $HOME && tar xzf %s .camel_certs", quotedfname);
run_cmd (command);
g_free (command);
/* If the back file had version information, set the last
* used version in GSettings before restarting Evolution. */
if (restored_version != NULL && *restored_version != '\0') {
GSettings *settings;
settings = g_settings_new ("org.gnome.evolution");
g_settings_set_string (
settings, "version", restored_version);
g_object_unref (settings);
}
g_free (data_dir);
g_free (config_dir);
g_free (restored_version);
} else {
run_cmd ("mv $HOME/.evolution $HOME/.evolution_old");
command = g_strdup_printf (
"cd $HOME && gzip -cd %s | tar xf -", quotedfname);
run_cmd (command);
g_free (command);
}
g_free (quotedfname);
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Loading Evolution settings");
if (is_new_format) {
/* new format has it in DATADIR... */
GString *file = replace_variables (EVOLUTION_DIR ANCIENT_GCONF_DUMP_FILE);
if (file && g_file_test (file->str, G_FILE_TEST_EXISTS)) {
/* ancient backup */
replace_in_file (
EVOLUTION_DIR ANCIENT_GCONF_DUMP_FILE,
EVOUSERDATADIR_MAGIC, e_get_user_data_dir ());
run_cmd ("gconftool-2 --load " EVOLUTION_DIR ANCIENT_GCONF_DUMP_FILE);
run_cmd ("rm " EVOLUTION_DIR ANCIENT_GCONF_DUMP_FILE);
} else {
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EDS,
EVOUSERDATADIR_MAGIC, e_get_user_data_dir ());
run_cmd ("cat " EVOLUTION_DIR DCONF_DUMP_FILE_EDS " | dconf load " DCONF_PATH_EDS);
run_cmd ("rm " EVOLUTION_DIR DCONF_DUMP_FILE_EDS);
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EVO,
EVOUSERDATADIR_MAGIC, e_get_user_data_dir ());
run_cmd ("cat " EVOLUTION_DIR DCONF_DUMP_FILE_EVO " | dconf load " DCONF_PATH_EVO);
run_cmd ("rm " EVOLUTION_DIR DCONF_DUMP_FILE_EVO);
}
g_string_free (file, TRUE);
} else {
gchar *gconf_dump_file;
/* ... old format in ~/.evolution */
gconf_dump_file = g_build_filename (
"$HOME", ".evolution", ANCIENT_GCONF_DUMP_FILE, NULL);
replace_in_file (
gconf_dump_file,
EVOUSERDATADIR_MAGIC,
e_get_user_data_dir ());
command = g_strconcat (
"gconftool-2 --load ", gconf_dump_file, NULL);
run_cmd (command);
g_free (command);
command = g_strconcat ("rm ", gconf_dump_file, NULL);
run_cmd (command);
g_free (command);
g_free (gconf_dump_file);
}
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Removing temporary back up files");
run_cmd ("rm -rf $DATADIR_old");
run_cmd ("rm -rf $CONFIGDIR_old");
run_cmd ("rm -rf $HOME/.camel_certs_old");
run_cmd ("rm $DATADIR/.running");
if (!is_new_format)
run_cmd ("rm -rf $HOME/.evolution_old");
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Reloading registry service");
/* This runs migration routines on the newly-restored data.
*
* XXX Hard-coding the whole command like this is not ideal
* because the "SourcesX" interface name will occasionally
* change and I guarantee we'll forget to update this. */
run_cmd (
"gdbus call --session "
"--dest org.gnome.evolution.dataserver.Sources0 "
"--object-path /org/gnome/evolution/dataserver/SourceManager "
"--method org.gnome.evolution.dataserver.SourceManager.Reload");
end:
if (restart_arg) {
if (g_cancellable_is_cancelled (cancellable))
return;
txt = _("Restarting Evolution");
run_evolution_no_wait ();
}
}
static gboolean
check (const gchar *filename,
gboolean *is_new_format)
{
gchar *command;
gchar *quotedfname;
gboolean is_new = TRUE;
g_return_val_if_fail (filename && *filename, FALSE);
quotedfname = g_shell_quote (filename);
if (is_new_format)
*is_new_format = FALSE;
command = g_strdup_printf ("tar ztf %s 1>/dev/null", quotedfname);
result = system (command);
g_free (command);
g_message ("First result %d", result);
if (result) {
g_free (quotedfname);
return FALSE;
}
command = g_strdup_printf (
"tar ztf %s | grep -e \"%s$\"",
quotedfname, EVOLUTION_DIR_FILE);
result = system (command);
g_free (command);
if (result) {
command = g_strdup_printf (
"tar ztf %s | grep -e \"^\\.evolution/$\"",
quotedfname);
result = system (command);
g_free (command);
is_new = FALSE;
}
g_message ("Second result %d", result);
if (result) {
g_free (quotedfname);
return FALSE;
}
if (is_new) {
if (is_new_format)
*is_new_format = TRUE;
g_free (quotedfname);
return TRUE;
}
command = g_strdup_printf (
"tar ztf %s | grep -e \"^\\.evolution/%s$\"",
quotedfname, ANCIENT_GCONF_DUMP_FILE);
result = system (command);
g_free (command);
if (result != 0) {
/* maybe it's an ancient backup */
command = g_strdup_printf (
"tar ztf %s | grep -e \"^\\.evolution/%s$\"",
quotedfname, ANCIENT_GCONF_DUMP_FILE);
result = system (command);
g_free (command);
}
g_free (quotedfname);
g_message ("Third result %d", result);
return result == 0;
}
static gboolean
pbar_update (GCancellable *cancellable)
{
gtk_progress_bar_pulse ((GtkProgressBar *) pbar);
gtk_progress_bar_set_text ((GtkProgressBar *) pbar, txt);
/* Return TRUE to reschedule the timeout. */
return !g_cancellable_is_cancelled (cancellable);
}
static gboolean
finish_job (gpointer user_data)
{
gtk_main_quit ();
return FALSE;
}
static gboolean
start_job (GIOSchedulerJob *job,
GCancellable *cancellable,
gpointer user_data)
{
if (backup_op)
backup (bk_file, cancellable);
else if (restore_op)
restore (res_file, cancellable);
else if (check_op)
check (chk_file, NULL); /* not cancellable */
g_io_scheduler_job_send_to_mainloop_async (
job, finish_job, NULL, (GDestroyNotify) NULL);
return FALSE;
}
static void
dlg_response (GtkWidget *dlg,
gint response,
GCancellable *cancellable)
{
/* We will cancel only backup/restore
* operations and not the check operation. */
g_cancellable_cancel (cancellable);
/* If the response is not of delete_event then destroy the event. */
if (response != GTK_RESPONSE_NONE)
gtk_widget_destroy (dlg);
/* We will kill just the tar operation. Rest of
* them will be just a second of microseconds.*/
run_cmd ("pkill tar");
if (bk_file && backup_op && response == GTK_RESPONSE_REJECT) {
/* Backup was canceled, delete the
* backup file as it is not needed now. */
gchar *cmd, *filename;
g_message ("Back up canceled, removing partial back up file.");
filename = g_shell_quote (bk_file);
cmd = g_strconcat ("rm ", filename, NULL);
run_cmd (cmd);
g_free (cmd);
g_free (filename);
}
gtk_main_quit ();
}
gint
main (gint argc,
gchar **argv)
{
GCancellable *cancellable;
gchar *file = NULL, *oper = NULL;
const gchar *title = NULL;
gint ii;
GError *error = NULL;
#ifdef G_OS_WIN32
/* Reduce risks */
{
typedef BOOL (WINAPI *t_SetDllDirectoryA) (LPCSTR lpPathName);
t_SetDllDirectoryA p_SetDllDirectoryA;
p_SetDllDirectoryA = GetProcAddress (
GetModuleHandle ("kernel32.dll"),
"SetDllDirectoryA");
if (p_SetDllDirectoryA != NULL)
p_SetDllDirectoryA ("");
}
#ifndef _WIN64
{
typedef BOOL (WINAPI *t_SetProcessDEPPolicy) (DWORD dwFlags);
t_SetProcessDEPPolicy p_SetProcessDEPPolicy;
p_SetProcessDEPPolicy = GetProcAddress (
GetModuleHandle ("kernel32.dll"),
"SetProcessDEPPolicy");
if (p_SetProcessDEPPolicy)
p_SetProcessDEPPolicy (
PROCESS_DEP_ENABLE |
PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION);
}
#endif
#endif
bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
gtk_init_with_args (
&argc, &argv, NULL, options, GETTEXT_PACKAGE, &error);
if (error != NULL) {
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (EXIT_FAILURE);
}
if (opt_remaining != NULL) {
for (ii = 0; ii < g_strv_length (opt_remaining); ii++) {
if (backup_op) {
title = _("Evolution Back Up");
oper = _("Backing up to the folder %s");
bk_file = g_strdup ((gchar *) opt_remaining[ii]);
file = bk_file;
} else if (restore_op) {
title = _("Evolution Restore");
oper = _("Restoring from the folder %s");
res_file = g_strdup ((gchar *) opt_remaining[ii]);
file = res_file;
} else if (check_op) {
d(g_message ("Checking %s", (gchar *) opt_remaining[ii]));
chk_file = g_strdup ((gchar *) opt_remaining[ii]);
}
}
}
cancellable = g_cancellable_new ();
if (gui_arg && !check_op) {
GtkWidget *widget, *container;
GtkWidget *action_area;
GtkWidget *content_area;
const gchar *txt, *txt2;
gchar *str = NULL;
gchar *markup;
gtk_window_set_default_icon_name ("evolution");
/* Backup / Restore only can have GUI.
* We should restrict the rest. */
progress_dialog = gtk_dialog_new_with_buttons (
title, NULL,
GTK_DIALOG_MODAL,
GTK_STOCK_CANCEL,
GTK_RESPONSE_REJECT,
NULL);
gtk_container_set_border_width (
GTK_CONTAINER (progress_dialog), 12);
gtk_window_set_default_size (
GTK_WINDOW (progress_dialog), 450, 120);
action_area = gtk_dialog_get_action_area (
GTK_DIALOG (progress_dialog));
content_area = gtk_dialog_get_content_area (
GTK_DIALOG (progress_dialog));
/* Override GtkDialog defaults */
gtk_box_set_spacing (GTK_BOX (content_area), 12);
gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
gtk_box_set_spacing (GTK_BOX (action_area), 12);
gtk_container_set_border_width (GTK_CONTAINER (action_area), 0);
if (oper && file)
str = g_strdup_printf (oper, file);
container = gtk_table_new (2, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (container), 12);
gtk_table_set_row_spacings (GTK_TABLE (container), 12);
gtk_widget_show (container);
gtk_box_pack_start (
GTK_BOX (content_area), container, FALSE, TRUE, 0);
widget = gtk_image_new_from_stock (
GTK_STOCK_COPY, GTK_ICON_SIZE_DIALOG);
gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
gtk_widget_show (widget);
gtk_table_attach (
GTK_TABLE (container), widget, 0, 1, 0, 3,
GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
if (backup_op) {
txt = _("Backing up Evolution Data");
txt2 = _("Please wait while Evolution is backing up your data.");
} else if (restore_op) {
txt = _("Restoring Evolution Data");
txt2 = _("Please wait while Evolution is restoring your data.");
} else {
g_return_val_if_reached (EXIT_FAILURE);
}
markup = g_markup_printf_escaped ("<b><big>%s</big></b>", txt);
widget = gtk_label_new (markup);
gtk_label_set_line_wrap (GTK_LABEL (widget), FALSE);
gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
gtk_widget_show (widget);
g_free (markup);
gtk_table_attach (
GTK_TABLE (container), widget, 1, 2, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
markup = g_strconcat (
txt2, " ", _("This may take a while depending "
"on the amount of data in your account."), NULL);
widget = gtk_label_new (markup);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
gtk_widget_show (widget);
g_free (markup);
gtk_table_attach (
GTK_TABLE (container), widget, 1, 2, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
pbar = gtk_progress_bar_new ();
if (str != NULL) {
markup = g_markup_printf_escaped ("<i>%s</i>", str);
widget = gtk_label_new (markup);
gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
g_free (markup);
g_free (str);
gtk_table_attach (
GTK_TABLE (container), widget, 1, 2, 2, 3,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
gtk_table_set_row_spacing (GTK_TABLE (container), 2, 6);
gtk_table_attach (
GTK_TABLE (container), pbar, 1, 2, 3, 4,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
} else
gtk_table_attach (
GTK_TABLE (container), pbar, 1, 2, 2, 3,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
g_signal_connect (
progress_dialog, "response",
G_CALLBACK (dlg_response), cancellable);
gtk_widget_show_all (progress_dialog);
} else if (check_op) {
/* For sanity we don't need gui */
check (chk_file, NULL);
exit (result == 0 ? 0 : 1);
}
if (gui_arg)
g_timeout_add_full (
G_PRIORITY_DEFAULT, 50,
(GSourceFunc) pbar_update,
g_object_ref (cancellable),
(GDestroyNotify) g_object_unref);
g_io_scheduler_push_job (
start_job, NULL,
(GDestroyNotify) NULL,
G_PRIORITY_DEFAULT, cancellable);
gtk_main ();
g_object_unref (cancellable);
return result;
}