test-client-custom-summary: Include <config.h>
[platform/upstream/evolution-data-server.git] / camel / camel-vtrash-folder.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *           Michael Zucchi <notzed@ximian.com>
5  *
6  *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <string.h>
29
30 #include <glib/gi18n-lib.h>
31
32 #include "camel-db.h"
33 #include "camel-mime-message.h"
34 #include "camel-store.h"
35 #include "camel-vee-store.h"
36 #include "camel-vtrash-folder.h"
37 #include "camel-string-utils.h"
38
39 static struct {
40         const gchar *full_name;
41         const gchar *name;
42         const gchar *expr;
43         guint32 bit;
44         guint32 flags;
45         const gchar *error_copy;
46         const gchar *db_col;
47 } vdata[] = {
48         { CAMEL_VTRASH_NAME, N_("Trash"), "(match-all (system-flag \"Deleted\"))", CAMEL_MESSAGE_DELETED, CAMEL_FOLDER_IS_TRASH,
49           N_("Cannot copy messages to the Trash folder"), "deleted" },
50         { CAMEL_VJUNK_NAME, N_("Junk"), "(match-all (system-flag \"Junk\"))", CAMEL_MESSAGE_JUNK, CAMEL_FOLDER_IS_JUNK,
51           N_("Cannot copy messages to the Junk folder"), "junk" },
52 };
53
54 struct _transfer_data {
55         GCancellable *cancellable;
56         CamelFolder *folder;
57         CamelFolder *dest;
58         GPtrArray *uids;
59         gboolean delete;
60
61         CamelFolder *source_folder;
62         GPtrArray *source_uids;
63         guint32 sbit;
64 };
65
66 G_DEFINE_TYPE (CamelVTrashFolder, camel_vtrash_folder, CAMEL_TYPE_VEE_FOLDER)
67
68 static void
69 transfer_messages (CamelFolder *folder,
70                    struct _transfer_data *md,
71                    GError **error)
72 {
73         gint i;
74
75         camel_folder_transfer_messages_to_sync (
76                 md->folder, md->uids, md->dest,
77                 md->delete, NULL, md->cancellable, error);
78
79         if (md->cancellable != NULL)
80                 g_object_unref (md->cancellable);
81
82         /* set the bit back */
83         for (i = 0; i < md->source_uids->len; i++) {
84                 CamelMessageInfo *mi = camel_folder_get_message_info (md->source_folder, md->source_uids->pdata[i]);
85                 if (mi) {
86                         camel_message_info_set_flags (mi, md->sbit, md->sbit);
87                         camel_folder_free_message_info (md->source_folder, mi);
88                 }
89         }
90
91         camel_folder_thaw (md->folder);
92
93         for (i = 0; i < md->uids->len; i++)
94                 g_free (md->uids->pdata[i]);
95
96         g_ptr_array_free (md->uids, TRUE);
97         g_ptr_array_free (md->source_uids, TRUE);
98         g_object_unref (md->folder);
99         g_free (md);
100 }
101
102 static gboolean
103 vtrash_folder_append_message_sync (CamelFolder *folder,
104                                    CamelMimeMessage *message,
105                                    CamelMessageInfo *info,
106                                    gchar **appended_uid,
107                                    GCancellable *cancellable,
108                                    GError **error)
109 {
110         g_set_error (
111                 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, "%s",
112                 _(vdata[((CamelVTrashFolder *) folder)->type].error_copy));
113
114         return FALSE;
115 }
116
117 static gboolean
118 vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
119                                          GPtrArray *uids,
120                                          CamelFolder *dest,
121                                          gboolean delete_originals,
122                                          GPtrArray **transferred_uids,
123                                          GCancellable *cancellable,
124                                          GError **error)
125 {
126         CamelVeeMessageInfo *mi;
127         gint i;
128         GHashTable *batch = NULL;
129         const gchar *tuid;
130         struct _transfer_data *md;
131         guint32 sbit = ((CamelVTrashFolder *) source)->bit;
132
133         /* This is a special case of transfer_messages_to: Either the
134          * source or the destination is a vtrash folder (but not both
135          * since a store should never have more than one).
136          */
137
138         if (transferred_uids)
139                 *transferred_uids = NULL;
140
141         if (CAMEL_IS_VTRASH_FOLDER (dest)) {
142                 /* Copy to trash is meaningless. */
143                 if (!delete_originals) {
144                         g_set_error (
145                                 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, "%s",
146                                 _(vdata[((CamelVTrashFolder *) dest)->type].error_copy));
147                         return FALSE;
148                 }
149
150                 /* Move to trash is the same as setting the message flag */
151                 for (i = 0; i < uids->len; i++)
152                         camel_folder_set_message_flags (
153                                 source, uids->pdata[i],
154                                 ((CamelVTrashFolder *) dest)->bit, ~0);
155                 return TRUE;
156         }
157
158         /* Moving/Copying from the trash to the original folder = undelete.
159          * Moving/Copying from the trash to a different folder = move/copy.
160          *
161          * Need to check this uid by uid, but we batch up the copies.
162          */
163
164         camel_folder_freeze (source);
165         camel_folder_freeze (dest);
166
167         for (i = 0; i < uids->len; i++) {
168                 mi = (CamelVeeMessageInfo *) camel_folder_get_message_info (source, uids->pdata[i]);
169                 if (mi == NULL) {
170                         g_warning ("Cannot find uid %s in source folder during transfer", (gchar *) uids->pdata[i]);
171                         continue;
172                 }
173
174                 if (dest == camel_folder_summary_get_folder (mi->orig_summary)) {
175                         /* Just unset the flag on the original message */
176                         camel_folder_set_message_flags (
177                                 source, uids->pdata[i], sbit, 0);
178                 } else {
179                         if (batch == NULL)
180                                 batch = g_hash_table_new (NULL, NULL);
181                         md = g_hash_table_lookup (batch, camel_folder_summary_get_folder (mi->orig_summary));
182                         if (md == NULL) {
183                                 md = g_malloc0 (sizeof (*md));
184                                 md->cancellable = cancellable;
185                                 md->folder = g_object_ref (camel_folder_summary_get_folder (mi->orig_summary));
186                                 md->uids = g_ptr_array_new ();
187                                 md->dest = dest;
188                                 md->delete = delete_originals;
189                                 md->source_folder = source;
190                                 md->source_uids = g_ptr_array_new ();
191                                 md->sbit = sbit;
192                                 if (cancellable != NULL)
193                                         g_object_ref (cancellable);
194                                 camel_folder_freeze (md->folder);
195                                 g_hash_table_insert (batch, camel_folder_summary_get_folder (mi->orig_summary), md);
196                         }
197
198                         /* unset the bit temporarily */
199                         camel_message_info_set_flags ((CamelMessageInfo *) mi, sbit, 0);
200
201                         tuid = uids->pdata[i];
202                         if (strlen (tuid) > 8)
203                                 tuid += 8;
204                         g_ptr_array_add (md->uids, g_strdup (tuid));
205                         g_ptr_array_add (md->source_uids, uids->pdata[i]);
206                 }
207                 camel_folder_free_message_info (source, (CamelMessageInfo *) mi);
208         }
209
210         if (batch) {
211                 g_hash_table_foreach (batch, (GHFunc) transfer_messages, error);
212                 g_hash_table_destroy (batch);
213         }
214
215         camel_folder_thaw (dest);
216         camel_folder_thaw (source);
217
218         return TRUE;
219 }
220
221 static void
222 camel_vtrash_folder_class_init (CamelVTrashFolderClass *class)
223 {
224         CamelFolderClass *folder_class;
225
226         folder_class = CAMEL_FOLDER_CLASS (class);
227         folder_class->append_message_sync = vtrash_folder_append_message_sync;
228         folder_class->transfer_messages_to_sync = vtrash_folder_transfer_messages_to_sync;
229 }
230
231 static void
232 camel_vtrash_folder_init (CamelVTrashFolder *vtrash_folder)
233 {
234 }
235
236 /**
237  * camel_vtrash_folder_new:
238  * @parent_store: the parent #CamelVeeStore object
239  * @type: type of vfolder, #CAMEL_VTRASH_FOLDER_TRASH or
240  * #CAMEL_VTRASH_FOLDER_JUNK currently.
241  *
242  * Create a new CamelVTrashFolder object.
243  *
244  * Returns: a new #CamelVTrashFolder object
245  **/
246 CamelFolder *
247 camel_vtrash_folder_new (CamelStore *parent_store,
248                          camel_vtrash_folder_t type)
249 {
250         CamelVTrashFolder *vtrash;
251
252         g_assert (type < CAMEL_VTRASH_FOLDER_LAST);
253
254         vtrash = g_object_new (
255                 CAMEL_TYPE_VTRASH_FOLDER,
256                 "full-name", vdata[type].full_name,
257                 "display-name", gettext (vdata[type].name),
258                 "parent-store", parent_store, NULL);
259
260         camel_vee_folder_construct (
261                 CAMEL_VEE_FOLDER (vtrash),
262                 CAMEL_STORE_FOLDER_PRIVATE |
263                 CAMEL_STORE_FOLDER_CREATE);
264
265         ((CamelFolder *) vtrash)->folder_flags |= vdata[type].flags;
266         camel_vee_folder_set_expression ((CamelVeeFolder *) vtrash, vdata[type].expr);
267         vtrash->bit = vdata[type].bit;
268         vtrash->type = type;
269
270         return (CamelFolder *) vtrash;
271 }