/*
* e-mail-send-account-override.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.
*
* 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 Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*
* Copyright (C) 2013 Red Hat, Inc. (www.redhat.com)
*
*/
#include "e-mail-send-account-override.h"
#include <config.h>
#include <string.h>
#include <libedataserver/libedataserver.h>
#define E_MAIL_SEND_ACCOUNT_OVERRIDE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_MAIL_SEND_ACCOUNT_OVERRIDE, EMailSendAccountOverridePrivate))
#define FOLDERS_SECTION "Folders"
#define RECIPIENTS_SECTION "Recipients"
#define OPTIONS_SECTION "Options"
#define OPTION_PREFER_FOLDER "PreferFolder"
struct _EMailSendAccountOverridePrivate {
GKeyFile *key_file;
gchar *config_filename;
gboolean prefer_folder;
gboolean need_save;
guint save_frozen;
GMutex property_lock;
};
enum {
PROP_0,
PROP_PREFER_FOLDER
};
enum {
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE (
EMailSendAccountOverride,
e_mail_send_account_override,
G_TYPE_OBJECT)
static gboolean
e_mail_send_account_override_save_locked (EMailSendAccountOverride *override)
{
gchar *contents;
GError *error = NULL;
g_return_val_if_fail (override->priv->key_file != NULL, FALSE);
override->priv->need_save = FALSE;
if (override->priv->config_filename == NULL)
return FALSE;
contents = g_key_file_to_data (override->priv->key_file, NULL, NULL);
if (contents == NULL)
return FALSE;
g_file_set_contents (
override->priv->config_filename, contents, -1, &error);
if (error != NULL) {
g_warning ("%s: %s", G_STRFUNC, error->message);
g_clear_error (&error);
}
g_free (contents);
return TRUE;
}
static gboolean
e_mail_send_account_override_maybe_save_locked (EMailSendAccountOverride *override)
{
if (override->priv->save_frozen > 0) {
override->priv->need_save = TRUE;
return FALSE;
}
return e_mail_send_account_override_save_locked (override);
}
static gchar *
get_override_for_folder_uri_locked (EMailSendAccountOverride *override,
const gchar *folder_uri)
{
gchar *account_uid;
if (folder_uri == NULL || *folder_uri == '\0')
return NULL;
account_uid = g_key_file_get_string (
override->priv->key_file, FOLDERS_SECTION, folder_uri, NULL);
if (account_uid != NULL)
g_strchomp (account_uid);
if (account_uid != NULL && *account_uid == '\0') {
g_free (account_uid);
account_uid = NULL;
}
return account_uid;
}
static gchar *
test_one_recipient (gchar **keys,
GPtrArray *values,
const gchar *name,
const gchar *address)
{
gint ii;
g_return_val_if_fail (keys != NULL, NULL);
g_return_val_if_fail (values != NULL, NULL);
if (name != NULL && *name == '\0')
name = NULL;
if (address != NULL && *address == '\0')
address = NULL;
if (name == NULL && address == NULL)
return NULL;
for (ii = 0; keys[ii] && ii < values->len; ii++) {
if (name != NULL && e_util_utf8_strstrcase (name, keys[ii]) != NULL) {
return g_strdup (values->pdata[ii]);
}
if (address != NULL && e_util_utf8_strstrcase (address, keys[ii]) != NULL) {
return g_strdup (values->pdata[ii]);
}
}
return NULL;
}
static gchar *
get_override_for_recipients_locked (EMailSendAccountOverride *override,
CamelAddress *recipients)
{
CamelInternetAddress *iaddress;
gchar *account_uid = NULL;
GPtrArray *values;
gchar **keys;
gint ii, len;
if (!CAMEL_IS_INTERNET_ADDRESS (recipients))
return NULL;
keys = g_key_file_get_keys (
override->priv->key_file, RECIPIENTS_SECTION, NULL, NULL);
if (keys == NULL)
return NULL;
values = g_ptr_array_new_full (g_strv_length (keys), g_free);
for (ii = 0; keys[ii]; ii++) {
g_ptr_array_add (
values,
g_key_file_get_string (
override->priv->key_file,
RECIPIENTS_SECTION, keys[ii], NULL));
}
iaddress = CAMEL_INTERNET_ADDRESS (recipients);
len = camel_address_length (recipients);
for (ii = 0; ii < len; ii++) {
const gchar *name, *address;
if (camel_internet_address_get (iaddress, ii, &name, &address)) {
account_uid = test_one_recipient (keys, values, name, address);
if (account_uid != NULL)
g_strchomp (account_uid);
if (account_uid != NULL && *account_uid == '\0') {
g_free (account_uid);
account_uid = NULL;
}
if (account_uid != NULL)
break;
}
}
g_ptr_array_free (values, TRUE);
g_strfreev (keys);
return account_uid;
}
static void
list_overrides_section_for_account_locked (EMailSendAccountOverride *override,
const gchar *account_uid,
const gchar *section,
GList **overrides)
{
gchar **keys;
g_return_if_fail (account_uid != NULL);
g_return_if_fail (section != NULL);
if (overrides == NULL)
return;
*overrides = NULL;
keys = g_key_file_get_keys (
override->priv->key_file, section, NULL, NULL);
if (keys != NULL) {
gint ii;
for (ii = 0; keys[ii]; ii++) {
const gchar *key = keys[ii];
gchar *value;
value = g_key_file_get_string (
override->priv->key_file, section, key, NULL);
if (g_strcmp0 (value, account_uid) == 0)
*overrides = g_list_prepend (*overrides, g_strdup (key));
g_free (value);
}
}
g_strfreev (keys);
*overrides = g_list_reverse (*overrides);
}
static void
list_overrides_for_account_locked (EMailSendAccountOverride *override,
const gchar *account_uid,
GList **folder_overrides,
GList **recipient_overrides)
{
if (account_uid == NULL)
return;
list_overrides_section_for_account_locked (
override, account_uid, FOLDERS_SECTION, folder_overrides);
list_overrides_section_for_account_locked (
override, account_uid, RECIPIENTS_SECTION, recipient_overrides);
}
static void
mail_send_account_override_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_PREFER_FOLDER:
e_mail_send_account_override_set_prefer_folder (
E_MAIL_SEND_ACCOUNT_OVERRIDE (object),
g_value_get_boolean (value));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
mail_send_account_override_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_PREFER_FOLDER:
g_value_set_boolean (
value,
e_mail_send_account_override_get_prefer_folder (
E_MAIL_SEND_ACCOUNT_OVERRIDE (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
mail_send_account_override_finalize (GObject *object)
{
EMailSendAccountOverridePrivate *priv;
priv = E_MAIL_SEND_ACCOUNT_OVERRIDE_GET_PRIVATE (object);
g_key_file_free (priv->key_file);
g_free (priv->config_filename);
g_mutex_clear (&priv->property_lock);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_mail_send_account_override_parent_class)->
finalize (object);
}
static void
e_mail_send_account_override_class_init (EMailSendAccountOverrideClass *class)
{
GObjectClass *object_class;
g_type_class_add_private (
class, sizeof (EMailSendAccountOverridePrivate));
object_class = G_OBJECT_CLASS (class);
object_class->set_property = mail_send_account_override_set_property;
object_class->get_property = mail_send_account_override_get_property;
object_class->finalize = mail_send_account_override_finalize;
g_object_class_install_property (
object_class,
PROP_PREFER_FOLDER,
g_param_spec_boolean (
"prefer-folder",
"Prefer Folder",
NULL,
TRUE,
G_PARAM_READWRITE));
signals[CHANGED] = g_signal_new (
"changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (EMailSendAccountOverrideClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
e_mail_send_account_override_init (EMailSendAccountOverride *override)
{
override->priv = E_MAIL_SEND_ACCOUNT_OVERRIDE_GET_PRIVATE (override);
g_mutex_init (&override->priv->property_lock);
override->priv->key_file = g_key_file_new ();
override->priv->prefer_folder = TRUE;
}
EMailSendAccountOverride *
e_mail_send_account_override_new (const gchar *config_filename)
{
EMailSendAccountOverride *override;
override = g_object_new (E_TYPE_MAIL_SEND_ACCOUNT_OVERRIDE, NULL);
if (config_filename != NULL)
e_mail_send_account_override_set_config_filename (
override, config_filename);
return override;
}
void
e_mail_send_account_override_set_config_filename (EMailSendAccountOverride *override,
const gchar *config_filename)
{
GError *error = NULL;
gboolean old_prefer_folder, prefer_folder_changed;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_return_if_fail (config_filename != NULL);
g_return_if_fail (*config_filename != '\0');
g_mutex_lock (&override->priv->property_lock);
if (g_strcmp0 (config_filename, override->priv->config_filename) == 0) {
g_mutex_unlock (&override->priv->property_lock);
return;
}
g_free (override->priv->config_filename);
override->priv->config_filename = g_strdup (config_filename);
g_key_file_load_from_file (
override->priv->key_file,
override->priv->config_filename, G_KEY_FILE_NONE, NULL);
old_prefer_folder = override->priv->prefer_folder;
override->priv->prefer_folder = g_key_file_get_boolean (
override->priv->key_file,
OPTIONS_SECTION, OPTION_PREFER_FOLDER, &error);
if (error != NULL) {
/* default value is to prefer the folder override over the recipients */
override->priv->prefer_folder = TRUE;
g_clear_error (&error);
}
prefer_folder_changed =
(override->priv->prefer_folder != old_prefer_folder);
g_mutex_unlock (&override->priv->property_lock);
if (prefer_folder_changed)
g_object_notify (G_OBJECT (override), "prefer-folder");
}
gchar *
e_mail_send_account_override_dup_config_filename (EMailSendAccountOverride *override)
{
gchar *config_filename;
g_return_val_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override), NULL);
g_mutex_lock (&override->priv->property_lock);
config_filename = g_strdup (override->priv->config_filename);
g_mutex_unlock (&override->priv->property_lock);
return config_filename;
}
void
e_mail_send_account_override_set_prefer_folder (EMailSendAccountOverride *override,
gboolean prefer_folder)
{
gboolean changed, saved = FALSE;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_mutex_lock (&override->priv->property_lock);
changed = (prefer_folder != override->priv->prefer_folder);
if (changed) {
override->priv->prefer_folder = prefer_folder;
g_key_file_set_boolean (
override->priv->key_file,
OPTIONS_SECTION, OPTION_PREFER_FOLDER, prefer_folder);
saved = e_mail_send_account_override_maybe_save_locked (override);
}
g_mutex_unlock (&override->priv->property_lock);
if (changed)
g_object_notify (G_OBJECT (override), "prefer-folder");
if (saved)
g_signal_emit (override, signals[CHANGED], 0);
}
gboolean
e_mail_send_account_override_get_prefer_folder (EMailSendAccountOverride *override)
{
g_return_val_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override), FALSE);
return override->priv->prefer_folder;
}
/* free returned pointer with g_free() */
gchar *
e_mail_send_account_override_get_account_uid (EMailSendAccountOverride *override,
const gchar *folder_uri,
CamelInternetAddress *recipients_to,
CamelInternetAddress *recipients_cc,
CamelInternetAddress *recipients_bcc)
{
gchar *account_uid = NULL;
g_return_val_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override), NULL);
g_return_val_if_fail (override->priv->config_filename != NULL, NULL);
g_mutex_lock (&override->priv->property_lock);
if (override->priv->prefer_folder)
account_uid = get_override_for_folder_uri_locked (
override, folder_uri);
if (account_uid == NULL)
account_uid = get_override_for_recipients_locked (
override, CAMEL_ADDRESS (recipients_to));
if (account_uid == NULL)
account_uid = get_override_for_recipients_locked (
override, CAMEL_ADDRESS (recipients_cc));
if (account_uid == NULL)
account_uid = get_override_for_recipients_locked (
override, CAMEL_ADDRESS (recipients_bcc));
if (account_uid == NULL && !override->priv->prefer_folder)
account_uid = get_override_for_folder_uri_locked (
override, folder_uri);
g_mutex_unlock (&override->priv->property_lock);
return account_uid;
}
void
e_mail_send_account_override_remove_for_account_uid (EMailSendAccountOverride *override,
const gchar *account_uid)
{
GList *folders = NULL, *recipients = NULL;
gboolean saved = FALSE;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_return_if_fail (account_uid != NULL);
g_mutex_lock (&override->priv->property_lock);
list_overrides_for_account_locked (
override, account_uid, &folders, &recipients);
if (folders != NULL || recipients != NULL) {
GList *link;
for (link = folders; link != NULL; link = g_list_next (link)) {
const gchar *key = link->data;
g_key_file_remove_key (
override->priv->key_file,
FOLDERS_SECTION, key, NULL);
}
for (link = recipients; link != NULL; link = g_list_next (link)) {
const gchar *key = link->data;
g_key_file_remove_key (
override->priv->key_file,
RECIPIENTS_SECTION, key, NULL);
}
saved = e_mail_send_account_override_maybe_save_locked (override);
}
g_list_free_full (folders, g_free);
g_list_free_full (recipients, g_free);
g_mutex_unlock (&override->priv->property_lock);
if (saved)
g_signal_emit (override, signals[CHANGED], 0);
}
gchar *
e_mail_send_account_override_get_for_folder (EMailSendAccountOverride *override,
const gchar *folder_uri)
{
gchar *account_uid = NULL;
g_return_val_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override), NULL);
g_mutex_lock (&override->priv->property_lock);
account_uid = get_override_for_folder_uri_locked (override, folder_uri);
g_mutex_unlock (&override->priv->property_lock);
return account_uid;
}
void
e_mail_send_account_override_set_for_folder (EMailSendAccountOverride *override,
const gchar *folder_uri,
const gchar *account_uid)
{
gboolean saved;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_return_if_fail (folder_uri != NULL);
g_return_if_fail (account_uid != NULL);
g_mutex_lock (&override->priv->property_lock);
g_key_file_set_string (
override->priv->key_file,
FOLDERS_SECTION, folder_uri, account_uid);
saved = e_mail_send_account_override_maybe_save_locked (override);
g_mutex_unlock (&override->priv->property_lock);
if (saved)
g_signal_emit (override, signals[CHANGED], 0);
}
void
e_mail_send_account_override_remove_for_folder (EMailSendAccountOverride *override,
const gchar *folder_uri)
{
gboolean saved;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_return_if_fail (folder_uri != NULL);
g_mutex_lock (&override->priv->property_lock);
g_key_file_remove_key (
override->priv->key_file, FOLDERS_SECTION, folder_uri, NULL);
saved = e_mail_send_account_override_maybe_save_locked (override);
g_mutex_unlock (&override->priv->property_lock);
if (saved)
g_signal_emit (override, signals[CHANGED], 0);
}
gchar *
e_mail_send_account_override_get_for_recipient (EMailSendAccountOverride *override,
CamelInternetAddress *recipients)
{
gchar *account_uid;
g_return_val_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override), NULL);
g_return_val_if_fail (recipients != NULL, NULL);
g_mutex_lock (&override->priv->property_lock);
account_uid = get_override_for_recipients_locked (
override, CAMEL_ADDRESS (recipients));
g_mutex_unlock (&override->priv->property_lock);
return account_uid;
}
void
e_mail_send_account_override_set_for_recipient (EMailSendAccountOverride *override,
const gchar *recipient,
const gchar *account_uid)
{
gboolean saved;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_return_if_fail (recipient != NULL);
g_return_if_fail (account_uid != NULL);
g_mutex_lock (&override->priv->property_lock);
g_key_file_set_string (
override->priv->key_file,
RECIPIENTS_SECTION, recipient, account_uid);
saved = e_mail_send_account_override_maybe_save_locked (override);
g_mutex_unlock (&override->priv->property_lock);
if (saved)
g_signal_emit (override, signals[CHANGED], 0);
}
void
e_mail_send_account_override_remove_for_recipient (EMailSendAccountOverride *override,
const gchar *recipient)
{
gboolean saved;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_return_if_fail (recipient != NULL);
g_mutex_lock (&override->priv->property_lock);
g_key_file_remove_key (
override->priv->key_file, RECIPIENTS_SECTION, recipient, NULL);
saved = e_mail_send_account_override_maybe_save_locked (override);
g_mutex_unlock (&override->priv->property_lock);
if (saved)
g_signal_emit (override, signals[CHANGED], 0);
}
void
e_mail_send_account_override_list_for_account (EMailSendAccountOverride *override,
const gchar *account_uid,
GList **folder_overrides,
GList **recipient_overrides)
{
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_return_if_fail (account_uid != NULL);
g_mutex_lock (&override->priv->property_lock);
list_overrides_for_account_locked (
override, account_uid, folder_overrides, recipient_overrides);
g_mutex_unlock (&override->priv->property_lock);
}
void
e_mail_send_account_override_freeze_save (EMailSendAccountOverride *override)
{
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_mutex_lock (&override->priv->property_lock);
override->priv->save_frozen++;
if (!override->priv->save_frozen) {
g_warn_if_reached ();
}
g_mutex_unlock (&override->priv->property_lock);
}
void
e_mail_send_account_override_thaw_save (EMailSendAccountOverride *override)
{
gboolean saved = FALSE;
g_return_if_fail (E_IS_MAIL_SEND_ACCOUNT_OVERRIDE (override));
g_mutex_lock (&override->priv->property_lock);
if (!override->priv->save_frozen) {
g_warn_if_reached ();
} else {
override->priv->save_frozen--;
if (!override->priv->save_frozen && override->priv->need_save)
saved = e_mail_send_account_override_save_locked (override);
}
g_mutex_unlock (&override->priv->property_lock);
if (saved)
g_signal_emit (override, signals[CHANGED], 0);
}