evolution-3.6.4/modules/backup-restore/evolution-backup-restore.c

No issues found

  1 /*
  2  * evolution-backup-restore.c
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  */
 18 
 19 #include <config.h>
 20 #include <unistd.h>
 21 #include <sys/types.h>
 22 #ifdef HAVE_SYS_WAIT_H
 23 #  include <sys/wait.h>
 24 #endif
 25 #include <stdlib.h>
 26 
 27 #include <gtk/gtk.h>
 28 #include <glib/gi18n.h>
 29 #include <glib/gstdio.h>
 30 
 31 #include <libebackend/libebackend.h>
 32 
 33 #include <mail/e-mail-config-assistant.h>
 34 #include <libevolution-utils/e-alert-dialog.h>
 35 #include <e-util/e-util.h>
 36 #include <e-util/e-dialog-utils.h>
 37 #include <shell/e-shell-utils.h>
 38 #include <shell/e-shell-window.h>
 39 
 40 #include "e-mail-config-restore-page.h"
 41 #include "e-mail-config-restore-ready-page.h"
 42 
 43 #ifdef G_OS_WIN32
 44 #ifdef localtime_r
 45 #undef localtime_r
 46 #endif
 47 /* The localtime() in Microsoft's C library *is* thread-safe */
 48 #define localtime_r(timep, result) \
 49 	(localtime (timep) ? memcpy ( \
 50 	(result), localtime (timep), sizeof (*(result))) : 0)
 51 #endif
 52 
 53 typedef EExtension EvolutionBackupRestoreAssistant;
 54 typedef EExtensionClass EvolutionBackupRestoreAssistantClass;
 55 
 56 typedef EExtension EvolutionBackupRestoreMenuItems;
 57 typedef EExtensionClass EvolutionBackupRestoreMenuItemsClass;
 58 
 59 /* Module Entry Points */
 60 void e_module_load (GTypeModule *type_module);
 61 void e_module_unload (GTypeModule *type_module);
 62 
 63 /* Forward Declarations */
 64 GType evolution_backup_restore_assistant_get_type (void);
 65 GType evolution_backup_restore_menu_items_get_type (void);
 66 
 67 static const gchar *ui =
 68 "<ui>"
 69 "  <menubar name='main-menu'>"
 70 "    <menu action='file-menu'>"
 71 "      <placeholder name='file-actions'>"
 72 "        <menuitem action='settings-backup'/>"
 73 "        <menuitem action='settings-restore'/>"
 74 "      </placeholder>"
 75 "    </menu>"
 76 "  </menubar>"
 77 "</ui>";
 78 
 79 G_DEFINE_DYNAMIC_TYPE (
 80 	EvolutionBackupRestoreAssistant,
 81 	evolution_backup_restore_assistant,
 82 	E_TYPE_EXTENSION)
 83 
 84 G_DEFINE_DYNAMIC_TYPE (
 85 	EvolutionBackupRestoreMenuItems,
 86 	evolution_backup_restore_menu_items,
 87 	E_TYPE_EXTENSION)
 88 
 89 enum {
 90 	BR_OK    = 1 << 0,
 91 	BR_START = 1 << 1
 92 };
 93 
 94 static void
 95 backup (const gchar *filename,
 96         gboolean restart)
 97 {
 98 	if (restart)
 99 		execl (
100 			EVOLUTION_TOOLSDIR "/evolution-backup",
101 			"evolution-backup",
102 			"--gui",
103 			"--backup",
104 			"--restart",
105 			filename,
106 			NULL);
107 	else
108 		execl (
109 			EVOLUTION_TOOLSDIR "/evolution-backup",
110 			"evolution-backup",
111 			"--gui",
112 			"--backup",
113 			filename,
114 			NULL);
115 }
116 
117 static void
118 restore (const gchar *filename,
119          gboolean restart)
120 {
121 	if (restart)
122 		execl (
123 			EVOLUTION_TOOLSDIR "/evolution-backup",
124 			"evolution-backup",
125 			"--gui",
126 			"--restore",
127 			"--restart",
128 			filename,
129 			NULL);
130 	else
131 		execl (
132 			EVOLUTION_TOOLSDIR "/evolution-backup",
133 			"evolution-backup",
134 			"--gui",
135 			"--restore",
136 			filename,
137 			NULL);
138 }
139 
140 static guint32
141 dialog_prompt_user (GtkWindow *parent,
142                     const gchar *string,
143                     const gchar *tag,
144                     ...)
145 {
146 	GtkWidget *dialog;
147 	GtkWidget *check = NULL;
148 	GtkWidget *container;
149 	va_list ap;
150 	gint button;
151 	guint32 mask = 0;
152 	EAlert *alert = NULL;
153 
154 	va_start (ap, tag);
155 	alert = e_alert_new_valist (tag, ap);
156 	va_end (ap);
157 
158 	dialog = e_alert_dialog_new (parent, alert);
159 	g_object_unref (alert);
160 
161 	container = e_alert_dialog_get_content_area (E_ALERT_DIALOG (dialog));
162 
163 	check = gtk_check_button_new_with_mnemonic (string);
164 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
165 	gtk_box_pack_start (GTK_BOX (container), check, FALSE, FALSE, 0);
166 	gtk_widget_show (check);
167 
168 	button = gtk_dialog_run (GTK_DIALOG (dialog));
169 
170 	if (button == GTK_RESPONSE_YES)
171 		mask |= BR_OK;
172 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)))
173 		mask |= BR_START;
174 
175 	gtk_widget_destroy (dialog);
176 
177 	return mask;
178 }
179 
180 static void
181 set_local_only (GtkFileChooser *file_chooser)
182 {
183 	/* XXX Has to be a local file, since the backup utility
184 	 *     takes a filename argument, not a URI. */
185 	gtk_file_chooser_set_local_only (file_chooser, TRUE);
186 }
187 
188 static gchar *
189 suggest_file_name (void)
190 {
191 	time_t t;
192 	struct tm tm;
193 
194 	t = time (NULL);
195 	localtime_r (&t, &tm);
196 
197 	return g_strdup_printf (
198 		"evolution-backup-%04d%02d%02d.tar.gz",
199 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
200 }
201 
202 static void
203 action_settings_backup_cb (GtkAction *action,
204                            EShellWindow *shell_window)
205 {
206 	GFile *file;
207 	GFile *parent;
208 	GFileInfo *file_info;
209 	const gchar *attribute;
210 	GError *error = NULL;
211 	gchar *suggest;
212 
213 	suggest = suggest_file_name ();
214 
215 	file = e_shell_run_save_dialog (
216 		e_shell_window_get_shell (shell_window),
217 		_("Select name of the Evolution backup file"),
218 		suggest, "*.tar.gz", (GtkCallback)
219 		set_local_only, NULL);
220 
221 	g_free (suggest);
222 
223 	if (file == NULL)
224 		return;
225 
226 	/* Make sure the parent directory can be written to. */
227 
228 	parent = g_file_get_parent (file);
229 	attribute = G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE;
230 
231 	/* XXX The query operation blocks the main loop but we
232 	 *     know it's a local file, so let it slide for now. */
233 	file_info = g_file_query_info (
234 		parent, attribute, G_FILE_QUERY_INFO_NONE, NULL, &error);
235 
236 	g_object_unref (parent);
237 
238 	if (error != NULL) {
239 		g_warning ("%s", error->message);
240 		g_error_free (error);
241 		return;
242 	}
243 
244 	if (g_file_info_get_attribute_boolean (file_info, attribute)) {
245 		guint32 mask;
246 		gchar *path;
247 
248 		mask = dialog_prompt_user (
249 			GTK_WINDOW (shell_window),
250 			_("_Restart Evolution after backup"),
251 			"org.gnome.backup-restore:backup-confirm", NULL);
252 		if (mask & BR_OK) {
253 			path = g_file_get_path (file);
254 			backup (path, (mask & BR_START) ? TRUE: FALSE);
255 			g_free (path);
256 		}
257 	} else {
258 		e_alert_run_dialog_for_args (
259 			GTK_WINDOW (shell_window),
260 			"org.gnome.backup-restore:insufficient-permissions",
261 			NULL);
262 	}
263 
264 	g_object_unref (file_info);
265 	g_object_unref (file);
266 }
267 
268 static void
269 action_settings_restore_cb (GtkAction *action,
270                             EShellWindow *shell_window)
271 {
272 	GFile *file;
273 	gchar *path;
274 
275 	file = e_shell_run_open_dialog (
276 		e_shell_window_get_shell (shell_window),
277 		_("Select name of the Evolution backup file to restore"),
278 		(GtkCallback) set_local_only, NULL);
279 
280 	if (file == NULL)
281 		return;
282 
283 	path = g_file_get_path (file);
284 
285 	if (evolution_backup_restore_validate_backup_file (path)) {
286 		guint32 mask;
287 
288 		mask = dialog_prompt_user (
289 			GTK_WINDOW (shell_window),
290 			_("_Restart Evolution after restore"),
291 			"org.gnome.backup-restore:restore-confirm", NULL);
292 		if (mask & BR_OK)
293 			restore (path, mask & BR_START);
294 	} else {
295 		e_alert_run_dialog_for_args (
296 			GTK_WINDOW (shell_window),
297 			"org.gnome.backup-restore:invalid-backup", NULL);
298 	}
299 
300 	g_object_unref (file);
301 	g_free (path);
302 }
303 
304 static GtkActionEntry entries[] = {
305 
306 	{ "settings-backup",
307 	  NULL,
308 	  N_("_Back up Evolution Data..."),
309 	  NULL,
310 	  N_("Back up Evolution data and settings to an archive file"),
311 	  G_CALLBACK (action_settings_backup_cb) },
312 
313 	{ "settings-restore",
314 	  NULL,
315 	  N_("R_estore Evolution Data..."),
316 	  NULL,
317 	  N_("Restore Evolution data and settings from an archive file"),
318 	  G_CALLBACK (action_settings_restore_cb) }
319 };
320 
321 static gboolean
322 evolution_backup_restore_filename_to_visible (GBinding *binding,
323                                               const GValue *source_value,
324                                               GValue *target_value,
325                                               gpointer unused)
326 {
327 	const gchar *filename;
328 	gboolean visible;
329 
330 	filename = g_value_get_string (source_value);
331 	visible = (filename != NULL && *filename != '\0');
332 	g_value_set_boolean (target_value, visible);
333 
334 	return TRUE;
335 }
336 
337 static void
338 evolution_backup_restore_prepare_cb (GtkAssistant *assistant,
339                                      GtkWidget *page,
340                                      EMailConfigRestorePage *restore_page)
341 {
342 	const gchar *filename;
343 
344 	/* If we've landed on the EMailConfigRestoreReadyPage, that
345 	 * means the user has chosen a valid backup file to restore
346 	 * so start the "evolution-backup" tool immediately. */
347 
348 	filename = e_mail_config_restore_page_get_filename (restore_page);
349 
350 	if (E_IS_MAIL_CONFIG_RESTORE_READY_PAGE (page))
351 		restore (filename, TRUE);
352 }
353 
354 static void
355 evolution_backup_restore_assistant_constructed (GObject *object)
356 {
357 	EExtension *extension;
358 	EExtensible *extensible;
359 	EMailConfigAssistant *assistant;
360 	const gchar *type_name;
361 
362 	extension = E_EXTENSION (object);
363 	extensible = e_extension_get_extensible (extension);
364 
365 	/* Chain up to parent's constructed() method. */
366 	G_OBJECT_CLASS (evolution_backup_restore_assistant_parent_class)->
367 		constructed (object);
368 
369 	assistant = E_MAIL_CONFIG_ASSISTANT (extensible);
370 
371 	/* XXX We only want to add the EMailConfigRestorePage to an
372 	 *     EStartupAssistant instance, not a normal EMailConfigAssistant.
373 	 *     But EStartupAssistant is defined in the "startup-wizard" module
374 	 *     and we can't access its GType without knowing its type name, so
375 	 *     just hard-code the type name. */
376 	type_name = G_OBJECT_TYPE_NAME (assistant);
377 	if (g_strcmp0 (type_name, "EStartupAssistant") == 0) {
378 		EMailConfigPage *restore_page;
379 		EMailConfigPage *ready_page;
380 
381 		restore_page = e_mail_config_restore_page_new ();
382 		e_mail_config_assistant_add_page (assistant, restore_page);
383 
384 		ready_page = e_mail_config_restore_ready_page_new ();
385 		e_mail_config_assistant_add_page (assistant, ready_page);
386 
387 		g_object_bind_property_full (
388 			restore_page, "filename",
389 			ready_page, "visible",
390 			G_BINDING_SYNC_CREATE,
391 			evolution_backup_restore_filename_to_visible,
392 			NULL,
393 			NULL, (GDestroyNotify) NULL);
394 
395 		g_signal_connect (
396 			assistant, "prepare",
397 			G_CALLBACK (evolution_backup_restore_prepare_cb),
398 			restore_page);
399 	}
400 }
401 
402 static void
403 evolution_backup_restore_assistant_class_init (EExtensionClass *class)
404 {
405 	GObjectClass *object_class;
406 
407 	object_class = G_OBJECT_CLASS (class);
408 	object_class->constructed = evolution_backup_restore_assistant_constructed;
409 
410 	class->extensible_type = E_TYPE_MAIL_CONFIG_ASSISTANT;
411 }
412 
413 static void
414 evolution_backup_restore_assistant_class_finalize (EExtensionClass *class)
415 {
416 }
417 
418 static void
419 evolution_backup_restore_assistant_init (EExtension *extension)
420 {
421 }
422 
423 static void
424 evolution_backup_restore_menu_items_constructed (GObject *object)
425 {
426 	EExtension *extension;
427 	EExtensible *extensible;
428 	EShellWindow *shell_window;
429 	GtkActionGroup *action_group;
430 	GtkUIManager *ui_manager;
431 	GError *error = NULL;
432 
433 	extension = E_EXTENSION (object);
434 	extensible = e_extension_get_extensible (extension);
435 
436 	/* Chain up to parent's constructed() method. */
437 	G_OBJECT_CLASS (evolution_backup_restore_menu_items_parent_class)->
438 		constructed (object);
439 
440 	shell_window = E_SHELL_WINDOW (extensible);
441 	action_group = e_shell_window_get_action_group (shell_window, "shell");
442 
443 	/* Add actions to the "shell" action group. */
444 	gtk_action_group_add_actions (
445 		action_group, entries,
446 		G_N_ELEMENTS (entries), shell_window);
447 
448 	/* Because we are loading from a hard-coded string, there is
449 	 * no chance of I/O errors.  Failure here implies a malformed
450 	 * UI definition.  Full stop. */
451 	ui_manager = e_shell_window_get_ui_manager (shell_window);
452 	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
453 	if (error != NULL)
454 		g_error ("%s", error->message);
455 }
456 
457 static void
458 evolution_backup_restore_menu_items_class_init (EExtensionClass *class)
459 {
460 	GObjectClass *object_class;
461 	EExtensionClass *extension_class;
462 
463 	object_class = G_OBJECT_CLASS (class);
464 	object_class->constructed = evolution_backup_restore_menu_items_constructed;
465 
466 	extension_class = E_EXTENSION_CLASS (class);
467 	extension_class->extensible_type = E_TYPE_SHELL_WINDOW;
468 }
469 
470 static void
471 evolution_backup_restore_menu_items_class_finalize (EExtensionClass *class)
472 {
473 }
474 
475 static void
476 evolution_backup_restore_menu_items_init (EExtension *extension)
477 {
478 }
479 
480 G_MODULE_EXPORT void
481 e_module_load (GTypeModule *type_module)
482 {
483 	evolution_backup_restore_assistant_register_type (type_module);
484 	evolution_backup_restore_menu_items_register_type (type_module);
485 
486 	e_mail_config_restore_page_type_register (type_module);
487 	e_mail_config_restore_ready_page_type_register (type_module);
488 }
489 
490 G_MODULE_EXPORT void
491 e_module_unload (GTypeModule *type_module)
492 {
493 }