/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* e-setup.c
*
* Copyright (C) 2000, 2001 Ximian, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* 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.
*
*/
/* This needs to be a lot better. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "e-setup.h"
#include "e-local-folder.h"
#include "e-shell-config.h"
#include "e-shell-constants.h"
#include "e-util/e-path.h"
#include <gconf/gconf-client.h>
#include <gtk/gtklabel.h>
#include <gal/widgets/e-gui-utils.h>
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-util.h>
#include <libgnomeui/gnome-messagebox.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define DEFAULT_USER_PATH EVOLUTION_DATADIR "/evolution-" BASE_VERSION "/default_user"
static GList *
check_dir_recur (const char *evolution_directory,
const char *current_directory)
{
DIR *def;
GList *newfiles = NULL;
struct dirent *current;
def = opendir (current_directory);
if (def == NULL)
return NULL;
current = readdir (def);
while (current != NULL) {
struct stat buf;
char *fullname, *fulldefaultname;
if (current->d_name[0] == '.' &&
(current->d_name[1] == '\0' ||
(current->d_name[1] == '.' && current->d_name[2] == '\0'))) {
current = readdir (def);
continue;
}
/* Hack to not copy the old Executive-Summary dir */
if (strcmp (current->d_name, "Executive-Summary") == 0) {
current = readdir (def);
continue;
}
fullname = g_concat_dir_and_file (evolution_directory,
current->d_name);
fulldefaultname = g_concat_dir_and_file (current_directory,
current->d_name);
if (stat (fullname, &buf) == -1) {
char *name;
name = g_strdup (fulldefaultname);
newfiles = g_list_append (newfiles, name);
} else {
if (S_ISDIR (buf.st_mode)) {
newfiles = g_list_concat (newfiles,
check_dir_recur (fullname,
fulldefaultname));
}
}
g_free (fulldefaultname);
g_free (fullname);
current = readdir (def);
}
closedir (def);
return newfiles;
}
static gboolean
check_evolution_directory (const char *evolution_directory)
{
GtkWidget *dialog;
GtkWidget *label1, *label2;
gboolean retval;
GList *newfiles, *l;
int result;
newfiles = g_list_concat (NULL, check_dir_recur (evolution_directory, DEFAULT_USER_PATH));
if (newfiles == NULL) {
retval = TRUE;
goto out;
}
dialog = gnome_dialog_new (_("Evolution installation"),
GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL,
NULL);
label1 = gtk_label_new (_("This new version of Evolution needs to install additional files\ninto your personal Evolution directory"));
label2 = gtk_label_new (_("Please click \"OK\" to install the files, or \"Cancel\" to exit."));
gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), label1, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), label2, TRUE, TRUE, 0);
gtk_widget_show (label1);
gtk_widget_show (label2);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
result = gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
if (result != 0) {
retval = FALSE;
goto out;
}
retval = TRUE;
for (l = newfiles; l; l = l->next) {
char *command;
char *shortpath;
shortpath = l->data + strlen (DEFAULT_USER_PATH);
command = g_strconcat ("cp -r ",
l->data, " ",
evolution_directory, "/",
shortpath,
NULL);
if (system (command) != 0) {
retval = FALSE;
} else {
retval = (retval && TRUE);
}
g_free (command);
}
if (retval == FALSE)
e_notice (NULL, GTK_MESSAGE_ERROR,
_("Could not update files correctly"));
out:
for (l = newfiles; l; l = l->next)
g_free (l->data);
g_list_free (newfiles);
return retval;
}
static gboolean
copy_default_stuff (const char *evolution_directory)
{
gboolean retval;
char *command;
if (mkdir (evolution_directory, 0700)) {
e_notice (NULL, GTK_MESSAGE_ERROR,
_("Cannot create the directory\n%s\nError: %s"),
evolution_directory,
g_strerror (errno));
return FALSE;
}
command = g_strconcat ("cp -r " DEFAULT_USER_PATH " ", evolution_directory, NULL);
if (system (command) != 0) {
/* FIXME: Give more help. */
e_notice (NULL, GTK_MESSAGE_ERROR,
_("An error occurred in copying files into\n`%s'."), evolution_directory);
retval = FALSE;
} else {
retval = TRUE;
}
g_free (command);
return retval;
}
static void
e_shell_rm_dir (const char *path)
{
DIR *base;
struct stat statbuf;
struct dirent *contents;
stat (path, &statbuf);
if (!S_ISDIR (statbuf.st_mode)) {
/* Not a directory */
g_message ("Removing: %s", path);
unlink (path);
return;
} else {
g_message ("Opening: %s", path);
base = opendir (path);
if (base == NULL)
return;
contents = readdir (base);
while (contents != NULL) {
char *fullpath;
if (strcmp (contents->d_name, ".") == 0||
strcmp (contents->d_name, "..") ==0) {
contents = readdir (base);
continue;
}
fullpath = g_concat_dir_and_file (path, contents->d_name);
e_shell_rm_dir (fullpath);
g_free (fullpath);
contents = readdir (base);
}
closedir (base);
rmdir (path);
}
}
/* FIXME: This is a workaround for bonobo-conf breakage. */
static gboolean
setup_bonobo_conf_private_directory (const char *evolution_directory)
{
char *name;
struct stat buf;
name = g_concat_dir_and_file (evolution_directory, "private");
if (stat (name, &buf) == -1) {
if (mkdir (name, 0700) != 0) {
e_notice (NULL, GTK_MESSAGE_ERROR,
_("Evolution could not create directory\n"
"%s:\n%s"),
name, strerror (errno));
g_free (name);
return FALSE;
}
g_free (name);
return TRUE;
}
if (S_ISDIR (buf.st_mode) && access (name, R_OK | W_OK | X_OK) == 0) {
g_free (name);
return TRUE;
}
if (S_ISDIR (buf.st_mode)) {
e_notice (NULL, GTK_MESSAGE_ERROR,
_("Directory %s\n"
"does not have the right permissions. Please make it\n"
"readable and executable and restart Evolution."),
name);
} else {
e_notice (NULL, GTK_MESSAGE_ERROR,
_("File %s\n"
"should be removed to allow Evolution to work correctly.\n"
"Please remove this file and restart Evolution."),
name, strerror (errno));
}
g_free (name);
return FALSE;
}
gboolean
e_setup (const char *evolution_directory)
{
struct stat statinfo;
char *file;
if (stat (evolution_directory, &statinfo) != 0) {
return copy_default_stuff (evolution_directory);
}
if (! S_ISDIR (statinfo.st_mode)) {
e_notice (NULL, GTK_MESSAGE_ERROR,
_("The file `%s' is not a directory.\n"
"Please move it in order to allow installation\n"
"of the Evolution user files."));
return FALSE;
}
/* Make sure this is really our directory, not an Evolution
* build tree or something like that.
*/
file = g_strdup_printf ("%s/local/Executive-Summary", evolution_directory);
if (stat (file, &statinfo) == 0) {
if (S_ISDIR (statinfo.st_mode)) {
GtkWidget *dialog;
dialog = gnome_message_box_new (_("Evolution has detected an old\n"
"Executive-Summary directory.\n"
"This needs to be removed before\n"
"Evolution will run.\n"
"Do you want me to remove this directory?"),
GNOME_MESSAGE_BOX_INFO,
GNOME_STOCK_BUTTON_YES,
GNOME_STOCK_BUTTON_NO,
NULL);
switch (gnome_dialog_run_and_close (GNOME_DIALOG (dialog))) {
case 0:
e_shell_rm_dir (file);
break;
default:
return FALSE;
}
}
}
g_free (file);
file = g_strdup_printf ("%s/searches.xml", evolution_directory);
if (stat (file, &statinfo) != 0) {
e_notice (NULL, GTK_MESSAGE_ERROR,
_("The directory `%s' exists but is not the\n"
"Evolution directory. Please move it in order\n"
"to allow installation of the Evolution user "
"files."), evolution_directory);
g_free (file);
return FALSE;
}
g_free (file);
/* If the user has an old-style config file, replace it with
* the new-style config directory. FIXME: This should be
* temporary.
*/
file = g_strdup_printf ("%s/config", evolution_directory);
if (stat (file, &statinfo) == 0 && ! S_ISDIR (statinfo.st_mode)) {
char *old = g_strdup_printf ("%s.old", file);
rename (file, old);
mkdir (file, 0700);
g_free (old);
}
g_free (file);
/* If the user has an old style trash folder, remove it so it gets
* replaced by the new vfolder-based trash folder. FIXME: This should
* go away at some point. */
file = g_strdup_printf ("%s/local/Trash", evolution_directory);
if (stat (file, &statinfo) == 0 && S_ISDIR (statinfo.st_mode)) {
EFolder *local_folder;
local_folder = e_local_folder_new_from_path (file);
if (local_folder != NULL
&& strcmp (e_folder_get_type_string (local_folder), "mail") == 0) {
char *old = g_strdup_printf ("%s.old", file);
rename (file, old);
g_free (old);
}
if (local_folder != NULL)
g_object_unref (local_folder);
}
g_free (file);
if (! setup_bonobo_conf_private_directory (evolution_directory))
return FALSE;
/* User has evolution directory...
Check if it is up to date. */
return check_evolution_directory (evolution_directory);
}
static void
set_default_folder_physical_uri_from_path (GConfClient *client,
const char *evolution_directory,
const char *path_key_name)
{
char *gconf_path;
char *path_value;
gconf_path = g_strconcat ("/apps/evolution/shell/default_folders/", path_key_name, NULL);
path_value = gconf_client_get_string (client, gconf_path, NULL);
g_free (gconf_path);
if (path_value != NULL
&& strncmp (path_value, E_SHELL_URI_PREFIX, E_SHELL_URI_PREFIX_LEN) == 0
&& strncmp (path_value + E_SHELL_URI_PREFIX_LEN, "/local/", 7) == 0) {
char *key_prefix;
char *local_physical_uri;
char *file_uri_prefix;
key_prefix = g_strndup (path_key_name, strchr (path_key_name, '_') - path_key_name);
gconf_path = g_strconcat ("/apps/evolution/shell/default_folders/", key_prefix, "_uri", NULL);
file_uri_prefix = g_strconcat ("file://", evolution_directory, "/local", NULL);
local_physical_uri = e_path_to_physical (file_uri_prefix, path_value + E_SHELL_URI_PREFIX_LEN + 6);
gconf_client_set_string (client, gconf_path, local_physical_uri, NULL);
g_free (gconf_path);
g_free (key_prefix);
g_free (local_physical_uri);
g_free (file_uri_prefix);
}
}
void
e_setup_check_config (const char *evolution_directory)
{
GConfClient *client;
char *tmp;
client = gconf_client_get_default ();
tmp = gconf_client_get_string (client, "/apps/evolution/shell/default_folders/mail_uri", NULL);
if (tmp != NULL && *tmp != 0) {
g_object_unref (client);
return;
}
/* The following ugliness is to initially set up the physical URIs
based on the default path values (which come from GConf). Of
course, this way of configuring the default folders is a bit of a
mess and needs to be cleaned up... */
set_default_folder_physical_uri_from_path (client, evolution_directory, "mail_path");
set_default_folder_physical_uri_from_path (client, evolution_directory, "contacts_path");
set_default_folder_physical_uri_from_path (client, evolution_directory, "calendar_path");
set_default_folder_physical_uri_from_path (client, evolution_directory, "tasks_path");
g_object_unref (client);
}