/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
* This library 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 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 .
*
* Authors: Jeffrey Stedfast
* Michael Zucchi
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include "camel-db.h"
#include "camel-mime-message.h"
#include "camel-store.h"
#include "camel-vee-store.h"
#include "camel-vtrash-folder.h"
#include "camel-string-utils.h"
static struct {
const gchar *full_name;
const gchar *name;
const gchar *expr;
guint32 bit;
guint32 flags;
const gchar *error_copy;
const gchar *db_col;
} vdata[] = {
{ CAMEL_VTRASH_NAME, N_("Trash"), "(match-all (system-flag \"Deleted\"))", CAMEL_MESSAGE_DELETED, CAMEL_FOLDER_IS_TRASH,
N_("Cannot copy messages to the Trash folder"), "deleted" },
{ CAMEL_VJUNK_NAME, N_("Junk"), "(match-all (system-flag \"Junk\"))", CAMEL_MESSAGE_JUNK, CAMEL_FOLDER_IS_JUNK,
N_("Cannot copy messages to the Junk folder"), "junk" },
};
struct _transfer_data {
GCancellable *cancellable;
CamelFolder *folder;
CamelFolder *dest;
GPtrArray *uids;
gboolean delete;
CamelFolder *source_folder;
GPtrArray *source_uids;
guint32 sbit;
};
G_DEFINE_TYPE (CamelVTrashFolder, camel_vtrash_folder, CAMEL_TYPE_VEE_FOLDER)
static void
transfer_messages (CamelFolder *folder,
struct _transfer_data *md,
GError **error)
{
gint i;
camel_folder_transfer_messages_to_sync (
md->folder, md->uids, md->dest,
md->delete, NULL, md->cancellable, error);
if (md->cancellable != NULL)
g_object_unref (md->cancellable);
/* set the bit back */
for (i = 0; i < md->source_uids->len; i++) {
CamelMessageInfo *mi = camel_folder_get_message_info (md->source_folder, md->source_uids->pdata[i]);
if (mi) {
camel_message_info_set_flags (mi, md->sbit, md->sbit);
camel_message_info_unref (mi);
}
}
camel_folder_thaw (md->folder);
for (i = 0; i < md->uids->len; i++)
g_free (md->uids->pdata[i]);
g_ptr_array_free (md->uids, TRUE);
g_ptr_array_free (md->source_uids, TRUE);
g_object_unref (md->folder);
g_free (md);
}
static gboolean
vtrash_folder_append_message_sync (CamelFolder *folder,
CamelMimeMessage *message,
CamelMessageInfo *info,
gchar **appended_uid,
GCancellable *cancellable,
GError **error)
{
g_set_error (
error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, "%s",
_(vdata[((CamelVTrashFolder *) folder)->type].error_copy));
return FALSE;
}
static gboolean
vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
GPtrArray *uids,
CamelFolder *dest,
gboolean delete_originals,
GPtrArray **transferred_uids,
GCancellable *cancellable,
GError **error)
{
CamelVeeMessageInfo *mi;
gint i;
GHashTable *batch = NULL;
const gchar *tuid;
struct _transfer_data *md;
guint32 sbit = ((CamelVTrashFolder *) source)->bit;
/* This is a special case of transfer_messages_to: Either the
* source or the destination is a vtrash folder (but not both
* since a store should never have more than one).
*/
if (transferred_uids)
*transferred_uids = NULL;
if (CAMEL_IS_VTRASH_FOLDER (dest)) {
/* Copy to trash is meaningless. */
if (!delete_originals) {
g_set_error (
error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, "%s",
_(vdata[((CamelVTrashFolder *) dest)->type].error_copy));
return FALSE;
}
/* Move to trash is the same as setting the message flag */
for (i = 0; i < uids->len; i++)
camel_folder_set_message_flags (
source, uids->pdata[i],
((CamelVTrashFolder *) dest)->bit, ~0);
return TRUE;
}
/* Moving/Copying from the trash to the original folder = undelete.
* Moving/Copying from the trash to a different folder = move/copy.
*
* Need to check this uid by uid, but we batch up the copies.
*/
camel_folder_freeze (source);
camel_folder_freeze (dest);
for (i = 0; i < uids->len; i++) {
mi = (CamelVeeMessageInfo *) camel_folder_get_message_info (source, uids->pdata[i]);
if (mi == NULL) {
g_warning ("Cannot find uid %s in source folder during transfer", (gchar *) uids->pdata[i]);
continue;
}
if (dest == camel_folder_summary_get_folder (mi->orig_summary)) {
/* Just unset the flag on the original message */
camel_folder_set_message_flags (
source, uids->pdata[i], sbit, 0);
} else {
if (batch == NULL)
batch = g_hash_table_new (NULL, NULL);
md = g_hash_table_lookup (batch, camel_folder_summary_get_folder (mi->orig_summary));
if (md == NULL) {
md = g_malloc0 (sizeof (*md));
md->cancellable = cancellable;
md->folder = g_object_ref (camel_folder_summary_get_folder (mi->orig_summary));
md->uids = g_ptr_array_new ();
md->dest = dest;
md->delete = delete_originals;
md->source_folder = source;
md->source_uids = g_ptr_array_new ();
md->sbit = sbit;
if (cancellable != NULL)
g_object_ref (cancellable);
camel_folder_freeze (md->folder);
g_hash_table_insert (batch, camel_folder_summary_get_folder (mi->orig_summary), md);
}
/* unset the bit temporarily */
camel_message_info_set_flags ((CamelMessageInfo *) mi, sbit, 0);
tuid = uids->pdata[i];
if (strlen (tuid) > 8)
tuid += 8;
g_ptr_array_add (md->uids, g_strdup (tuid));
g_ptr_array_add (md->source_uids, uids->pdata[i]);
}
camel_message_info_unref (mi);
}
if (batch) {
g_hash_table_foreach (batch, (GHFunc) transfer_messages, error);
g_hash_table_destroy (batch);
}
camel_folder_thaw (dest);
camel_folder_thaw (source);
return TRUE;
}
static void
camel_vtrash_folder_class_init (CamelVTrashFolderClass *class)
{
CamelFolderClass *folder_class;
folder_class = CAMEL_FOLDER_CLASS (class);
folder_class->append_message_sync = vtrash_folder_append_message_sync;
folder_class->transfer_messages_to_sync = vtrash_folder_transfer_messages_to_sync;
}
static void
camel_vtrash_folder_init (CamelVTrashFolder *vtrash_folder)
{
}
/**
* camel_vtrash_folder_new:
* @parent_store: the parent #CamelVeeStore object
* @type: type of vfolder, #CAMEL_VTRASH_FOLDER_TRASH or
* #CAMEL_VTRASH_FOLDER_JUNK currently.
*
* Create a new CamelVTrashFolder object.
*
* Returns: a new #CamelVTrashFolder object
**/
CamelFolder *
camel_vtrash_folder_new (CamelStore *parent_store,
camel_vtrash_folder_t type)
{
CamelVTrashFolder *vtrash;
g_return_val_if_fail (type < CAMEL_VTRASH_FOLDER_LAST, NULL);
vtrash = g_object_new (
CAMEL_TYPE_VTRASH_FOLDER,
"full-name", vdata[type].full_name,
"display-name", gettext (vdata[type].name),
"parent-store", parent_store, NULL);
camel_vee_folder_construct (
CAMEL_VEE_FOLDER (vtrash),
CAMEL_STORE_FOLDER_PRIVATE |
CAMEL_STORE_FOLDER_CREATE);
((CamelFolder *) vtrash)->folder_flags |= vdata[type].flags;
camel_vee_folder_set_expression ((CamelVeeFolder *) vtrash, vdata[type].expr);
vtrash->bit = vdata[type].bit;
vtrash->type = type;
return (CamelFolder *) vtrash;
}