/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2015 Red Hat Inc. (www.redhat.com)
*
* This library is free software: you can redistribute it and/or modify it
* under the terms of version 2.1. of the GNU Lesser General Public License
* as published by the Free Software Foundation.
*
* This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "evolution-config.h"
#include <stdio.h>
#include <string.h>
#include <camel/camel.h>
#include <sqlite3.h>
#include <libemail-engine/libemail-engine.h>
#include "e-mail-properties.h"
#define CURRENT_VERSION 1
struct _EMailPropertiesPrivate {
CamelDB *db;
};
G_DEFINE_TYPE (EMailProperties, e_mail_properties, G_TYPE_OBJECT)
static gint
e_mail_properties_get_value_cb (gpointer data,
gint ncol,
gchar **colvalues,
gchar **colnames)
{
gchar **value = data;
if (value && colvalues && colvalues[0]) {
g_return_val_if_fail (*value == NULL, 0);
*value = g_strdup (colvalues[0]);
}
return 0;
}
static gchar *
e_mail_properties_get (EMailProperties *properties,
const gchar *table,
const gchar *id,
const gchar *key)
{
gchar *value = NULL;
gchar *stmt;
g_return_val_if_fail (E_IS_MAIL_PROPERTIES (properties), NULL);
g_return_val_if_fail (table != NULL, NULL);
g_return_val_if_fail (id != NULL, NULL);
g_return_val_if_fail (key != NULL, NULL);
g_return_val_if_fail (properties->priv->db != NULL, NULL);
stmt = sqlite3_mprintf ("SELECT value FROM %Q WHERE id=%Q AND key=%Q", table, id, key);
camel_db_select (properties->priv->db, stmt, e_mail_properties_get_value_cb, &value, NULL);
sqlite3_free (stmt);
return value;
}
static void
e_mail_properties_add (EMailProperties *properties,
const gchar *table,
const gchar *id,
const gchar *key,
const gchar *value)
{
gchar *stmt, *stored;
GError *error = NULL;
g_return_if_fail (E_IS_MAIL_PROPERTIES (properties));
g_return_if_fail (table != NULL);
g_return_if_fail (id != NULL);
g_return_if_fail (key != NULL);
g_return_if_fail (value != NULL);
g_return_if_fail (properties->priv->db != NULL);
stored = e_mail_properties_get (properties, table, id, key);
if (stored)
stmt = sqlite3_mprintf ("UPDATE %Q SET id=%Q,key=%Q,value=%Q WHERE id=%Q AND key=%Q", table, id, key, value, id, key);
else
stmt = sqlite3_mprintf ("INSERT INTO %Q (id,key,value) VALUES (%Q,%Q,%Q)", table, id, key, value, id, key);
camel_db_command (properties->priv->db, stmt, &error);
sqlite3_free (stmt);
g_free (stored);
if (error) {
g_warning ("%s: Failed to add to '%s' for '%s|%s|%s': %s", G_STRFUNC, table, id, key, value, error->message);
g_clear_error (&error);
}
}
static void
e_mail_properties_remove (EMailProperties *properties,
const gchar *table,
const gchar *id,
const gchar *key)
{
gchar *stmt;
GError *error = NULL;
g_return_if_fail (E_IS_MAIL_PROPERTIES (properties));
g_return_if_fail (table != NULL);
g_return_if_fail (id != NULL);
g_return_if_fail (key != NULL);
g_return_if_fail (properties->priv->db != NULL);
stmt = sqlite3_mprintf ("DELETE FROM %Q WHERE id=%Q AND key=%Q", table, id, key);
camel_db_command (properties->priv->db, stmt, &error);
sqlite3_free (stmt);
if (error) {
g_warning ("%s: Failed to remove from '%s' value '%s|%s': %s", G_STRFUNC, table, id, key, error->message);
g_clear_error (&error);
}
}
static gint
e_mail_properties_get_version_cb (gpointer data,
gint ncol,
gchar **colvalues,
gchar **colnames)
{
gint *pversion = data;
if (pversion && ncol == 1 && colvalues && colvalues[0])
*pversion = (gint) g_ascii_strtoll (colvalues[0], NULL, 10);
return 0;
}
static void
e_mail_properties_set_config_filename (EMailProperties *properties,
const gchar *config_filename)
{
GError *error = NULL;
g_return_if_fail (E_IS_MAIL_PROPERTIES (properties));
g_return_if_fail (config_filename != NULL);
g_return_if_fail (properties->priv->db == NULL);
properties->priv->db = camel_db_new (config_filename, &error);
if (error) {
g_warning ("%s: Failed to open '%s': %s", G_STRFUNC, config_filename, error->message);
g_clear_error (&error);
}
if (properties->priv->db) {
#define ctb(stmt) G_STMT_START { \
if (properties->priv->db) { \
camel_db_command (properties->priv->db, stmt, &error); \
if (error) { \
g_warning ("%s: Failed to execute '%s' on '%s': %s", \
G_STRFUNC, stmt, config_filename, error->message); \
g_clear_error (&error); \
} \
} \
} G_STMT_END
ctb ("CREATE TABLE IF NOT EXISTS version (current INT)");
ctb ("CREATE TABLE IF NOT EXISTS folders ('id' TEXT, 'key' TEXT, 'value' TEXT)");
ctb ("CREATE INDEX IF NOT EXISTS 'folders_index' ON 'folders' (id,key)");
#undef ctb
}
if (properties->priv->db) {
gint version = -1;
gchar *stmt;
camel_db_select (properties->priv->db, "SELECT 'current' FROM 'version'", e_mail_properties_get_version_cb, &version, NULL);
if (version != -1 && version < CURRENT_VERSION) {
/* Here will be added migration code, if needed in the future */
}
if (version < CURRENT_VERSION) {
stmt = sqlite3_mprintf ("DELETE FROM %Q", "version");
camel_db_command (properties->priv->db, stmt, NULL);
sqlite3_free (stmt);
stmt = sqlite3_mprintf ("INSERT INTO %Q (current) VALUES (%d);", "version", CURRENT_VERSION);
camel_db_command (properties->priv->db, stmt, NULL);
sqlite3_free (stmt);
}
}
}
static void
mail_properties_finalize (GObject *object)
{
EMailProperties *properties;
properties = E_MAIL_PROPERTIES (object);
if (properties->priv->db) {
GError *error = NULL;
camel_db_maybe_run_maintenance (properties->priv->db, &error);
if (error) {
g_warning ("%s: Failed to run maintenance: %s", G_STRFUNC, error->message);
g_clear_error (&error);
}
g_clear_object (&properties->priv->db);
}
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_mail_properties_parent_class)->finalize (object);
}
static void
e_mail_properties_class_init (EMailPropertiesClass *class)
{
GObjectClass *object_class;
g_type_class_add_private (class, sizeof (EMailPropertiesPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->finalize = mail_properties_finalize;
}
static void
e_mail_properties_init (EMailProperties *properties)
{
properties->priv = G_TYPE_INSTANCE_GET_PRIVATE (properties, E_TYPE_MAIL_PROPERTIES, EMailPropertiesPrivate);
}
EMailProperties *
e_mail_properties_new (const gchar *config_filename)
{
EMailProperties *properties;
properties = g_object_new (E_TYPE_MAIL_PROPERTIES, NULL);
if (config_filename != NULL)
e_mail_properties_set_config_filename (properties, config_filename);
return properties;
}
void
e_mail_properties_set_for_folder (EMailProperties *properties,
CamelFolder *folder,
const gchar *key,
const gchar *value)
{
gchar *folder_uri;
g_return_if_fail (E_IS_MAIL_PROPERTIES (properties));
g_return_if_fail (CAMEL_IS_FOLDER (folder));
g_return_if_fail (key != NULL);
folder_uri = e_mail_folder_uri_build (
camel_folder_get_parent_store (folder),
camel_folder_get_full_name (folder));
g_return_if_fail (folder_uri != NULL);
e_mail_properties_set_for_folder_uri (properties, folder_uri, key, value);
g_free (folder_uri);
}
void
e_mail_properties_set_for_folder_uri (EMailProperties *properties,
const gchar *folder_uri,
const gchar *key,
const gchar *value)
{
g_return_if_fail (E_IS_MAIL_PROPERTIES (properties));
g_return_if_fail (folder_uri != NULL);
g_return_if_fail (key != NULL);
if (value)
e_mail_properties_add (properties, "folders", folder_uri, key, value);
else
e_mail_properties_remove (properties, "folders", folder_uri, key);
}
/* Free returned pointer with g_free() */
gchar *
e_mail_properties_get_for_folder (EMailProperties *properties,
CamelFolder *folder,
const gchar *key)
{
gchar *folder_uri, *value;
g_return_val_if_fail (E_IS_MAIL_PROPERTIES (properties), NULL);
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
g_return_val_if_fail (key != NULL, NULL);
folder_uri = e_mail_folder_uri_build (
camel_folder_get_parent_store (folder),
camel_folder_get_full_name (folder));
g_return_val_if_fail (folder_uri != NULL, NULL);
value = e_mail_properties_get_for_folder_uri (properties, folder_uri, key);
g_free (folder_uri);
return value;
}
/* Free returned pointer with g_free() */
gchar *
e_mail_properties_get_for_folder_uri (EMailProperties *properties,
const gchar *folder_uri,
const gchar *key)
{
g_return_val_if_fail (E_IS_MAIL_PROPERTIES (properties), NULL);
g_return_val_if_fail (folder_uri != NULL, NULL);
g_return_val_if_fail (key != NULL, NULL);
return e_mail_properties_get (properties, "folders", folder_uri, key);
}