Rename camel_service_get_settings().
[platform/upstream/evolution-data-server.git] / camel / camel-imapx-folder.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-imap-folder.c : class for a imap folder */
3 /*
4  * Authors: Michael Zucchi <notzed@ximian.com>
5  *
6  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
7  *
8  * This library 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 library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <glib/gi18n-lib.h>
29
30 #include "camel-imapx-utils.h"
31 #include "camel-imapx-store.h"
32 #include "camel-imapx-folder.h"
33 #include "camel-imapx-summary.h"
34 #include "camel-imapx-server.h"
35
36 #include <stdlib.h>
37 #include <string.h>
38
39 #define d(...) camel_imapx_debug(debug, '?', __VA_ARGS__)
40
41 /* The custom property ID is a CamelArg artifact.
42  * It still identifies the property in state files. */
43 enum {
44         PROP_0,
45         PROP_APPLY_FILTERS = 0x2501
46 };
47
48 G_DEFINE_TYPE (CamelIMAPXFolder, camel_imapx_folder, CAMEL_TYPE_OFFLINE_FOLDER)
49
50 static gboolean imapx_folder_get_apply_filters (CamelIMAPXFolder *folder);
51
52 CamelFolder *
53 camel_imapx_folder_new (CamelStore *store,
54                         const gchar *folder_dir,
55                         const gchar *folder_name,
56                         GError **error)
57 {
58         CamelFolder *folder;
59         CamelService *service;
60         CamelSettings *settings;
61         CamelIMAPXFolder *ifolder;
62         const gchar *short_name;
63         gchar *state_file;
64         gboolean filter_all;
65         gboolean filter_inbox;
66         gboolean filter_junk;
67         gboolean filter_junk_inbox;
68
69         d("opening imap folder '%s'\n", folder_dir);
70
71         service = CAMEL_SERVICE (store);
72
73         settings = camel_service_ref_settings (service);
74
75         g_object_get (
76                 settings,
77                 "filter-all", &filter_all,
78                 "filter-inbox", &filter_inbox,
79                 "filter-junk", &filter_junk,
80                 "filter-junk-inbox", &filter_junk_inbox,
81                 NULL);
82
83         g_object_unref (settings);
84
85         short_name = strrchr (folder_name, '/');
86         if (short_name)
87                 short_name++;
88         else
89                 short_name = folder_name;
90
91         folder = g_object_new (
92                 CAMEL_TYPE_IMAPX_FOLDER,
93                 "display-name", short_name,
94                 "full_name", folder_name,
95                 "parent-store", store, NULL);
96         ifolder = (CamelIMAPXFolder *) folder;
97
98         ((CamelIMAPXFolder *) folder)->raw_name = g_strdup (folder_name);
99
100         folder->summary = camel_imapx_summary_new (folder);
101         if (!folder->summary) {
102                 g_set_error (
103                         error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
104                         _("Could not create folder summary for %s"),
105                         short_name);
106                 return NULL;
107         }
108
109         ifolder->cache = camel_data_cache_new (folder_dir, error);
110         if (!ifolder->cache) {
111                 g_prefix_error (
112                         error, _("Could not create cache for %s: "),
113                         short_name);
114                 return NULL;
115         }
116
117         state_file = g_build_filename (folder_dir, "cmeta", NULL);
118         camel_object_set_state_filename (CAMEL_OBJECT (folder), state_file);
119         g_free (state_file);
120         camel_object_state_read (CAMEL_OBJECT (folder));
121
122         ifolder->search = camel_folder_search_new ();
123         ifolder->search_lock = g_mutex_new ();
124         ifolder->stream_lock = g_mutex_new ();
125         ifolder->ignore_recent = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
126         ifolder->exists_on_server = 0;
127         ifolder->unread_on_server = 0;
128         ifolder->modseq_on_server = 0;
129         ifolder->uidnext_on_server = 0;
130
131         if (!g_ascii_strcasecmp (folder_name, "INBOX")) {
132                 if (filter_inbox || filter_all)
133                         folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
134                 if (filter_junk)
135                         folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
136         } else {
137                 if (filter_junk && !filter_junk_inbox)
138                         folder->folder_flags |= CAMEL_FOLDER_FILTER_JUNK;
139
140                 if (filter_all || imapx_folder_get_apply_filters (ifolder))
141                         folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
142         }
143
144         camel_store_summary_connect_folder_summary (
145                 (CamelStoreSummary *) ((CamelIMAPXStore *) store)->summary,
146                 folder_name, folder->summary);
147
148         return folder;
149 }
150
151 static gboolean
152 imapx_folder_get_apply_filters (CamelIMAPXFolder *folder)
153 {
154         g_return_val_if_fail (folder != NULL, FALSE);
155         g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), FALSE);
156
157         return folder->apply_filters;
158 }
159
160 static void
161 imapx_folder_set_apply_filters (CamelIMAPXFolder *folder,
162                                 gboolean apply_filters)
163 {
164         g_return_if_fail (folder != NULL);
165         g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
166
167         if ((folder->apply_filters ? 1 : 0) == (apply_filters ? 1 : 0))
168                 return;
169
170         folder->apply_filters = apply_filters;
171
172         g_object_notify (G_OBJECT (folder), "apply-filters");
173 }
174
175 static void
176 imapx_folder_set_property (GObject *object,
177                            guint property_id,
178                            const GValue *value,
179                            GParamSpec *pspec)
180 {
181         switch (property_id) {
182                 case PROP_APPLY_FILTERS:
183                         imapx_folder_set_apply_filters (
184                                 CAMEL_IMAPX_FOLDER (object),
185                                 g_value_get_boolean (value));
186                         return;
187         }
188
189         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
190 }
191
192 static void
193 imapx_folder_get_property (GObject *object,
194                            guint property_id,
195                            GValue *value,
196                            GParamSpec *pspec)
197 {
198         switch (property_id) {
199                 case PROP_APPLY_FILTERS:
200                         g_value_set_boolean (
201                                 value, imapx_folder_get_apply_filters (
202                                 CAMEL_IMAPX_FOLDER (object)));
203                         return;
204         }
205
206         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
207 }
208
209 static void
210 imapx_folder_dispose (GObject *object)
211 {
212         CamelIMAPXFolder *folder = CAMEL_IMAPX_FOLDER (object);
213         CamelStore *parent_store;
214
215         if (folder->cache != NULL) {
216                 g_object_unref (folder->cache);
217                 folder->cache = NULL;
218         }
219
220         if (folder->search != NULL) {
221                 g_object_unref (folder->search);
222                 folder->search = NULL;
223         }
224
225         parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (folder));
226         if (parent_store) {
227                 camel_store_summary_disconnect_folder_summary (
228                         (CamelStoreSummary *) ((CamelIMAPXStore *) parent_store)->summary,
229                         CAMEL_FOLDER (folder)->summary);
230         }
231
232         /* Chain up to parent's dispose() method. */
233         G_OBJECT_CLASS (camel_imapx_folder_parent_class)->dispose (object);
234 }
235
236 static void
237 imapx_folder_finalize (GObject *object)
238 {
239         CamelIMAPXFolder *folder = CAMEL_IMAPX_FOLDER (object);
240
241         if (folder->ignore_recent != NULL)
242                 g_hash_table_unref (folder->ignore_recent);
243
244         g_mutex_free (folder->search_lock);
245         g_mutex_free (folder->stream_lock);
246
247         /* Chain up to parent's finalize() method. */
248         G_OBJECT_CLASS (camel_imapx_folder_parent_class)->finalize (object);
249 }
250
251 gchar *
252 imapx_get_filename (CamelFolder *folder,
253                     const gchar *uid,
254                     GError **error)
255 {
256         CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
257
258         return camel_data_cache_get_filename (ifolder->cache, "cache", uid);
259 }
260
261 /* Algorithm for selecting a folder:
262  *
263  *  - If uidvalidity == old uidvalidity
264  *    and exsists == old exists
265  *    and recent == old recent
266  *    and unseen == old unseen
267  *    Assume our summary is correct
268  *  for each summary item
269  *    mark the summary item as 'old/not updated'
270  *  rof
271  *  fetch flags from 1:*
272  *  for each fetch response
273  *    info = summary[index]
274  *    if info.uid != uid
275  *      info = summary_by_uid[uid]
276  *    fi
277  *    if info == NULL
278  *      create new info @ index
279  *    fi
280  *    if got.flags
281  *      update flags
282  *    fi
283  *    if got.header
284  *      update based on header
285  *      mark as retrieved
286  *    else if got.body
287  *      update based on imap body
288  *      mark as retrieved
289  *    fi
290  *
291  *  Async fetch response:
292  *    info = summary[index]
293  *    if info == null
294  *       if uid == null
295  *          force resync/select?
296  *       info = empty @ index
297  *    else if uid && info.uid != uid
298  *       force a resync?
299  *       return
300  *    fi
301  *
302  *    if got.flags {
303  *      info.flags = flags
304  *    }
305  *    if got.header {
306  *      info.init (header)
307  *      info.empty = false
308  *    }
309  *
310  * info.state - 2 bit field in flags
311  *   0 = empty, nothing set
312  *   1 = uid & flags set
313  *   2 = update required
314  *   3 = up to date
315  */
316
317 static void
318 imapx_search_free (CamelFolder *folder,
319                    GPtrArray *uids)
320 {
321         CamelIMAPXFolder *ifolder = CAMEL_IMAPX_FOLDER (folder);
322
323         g_return_if_fail (ifolder->search);
324
325         g_mutex_lock (ifolder->search_lock);
326
327         camel_folder_search_free_result (ifolder->search, uids);
328
329         g_mutex_unlock (ifolder->search_lock);
330 }
331
332 static GPtrArray *
333 imapx_search_by_uids (CamelFolder *folder,
334                       const gchar *expression,
335                       GPtrArray *uids,
336                       GCancellable *cancellable,
337                       GError **error)
338 {
339         CamelIMAPXFolder *ifolder = CAMEL_IMAPX_FOLDER (folder);
340         GPtrArray *matches;
341
342         if (uids->len == 0)
343                 return g_ptr_array_new ();
344
345         g_mutex_lock (ifolder->search_lock);
346
347         camel_folder_search_set_folder (ifolder->search, folder);
348         matches = camel_folder_search_search (ifolder->search, expression, uids, cancellable, error);
349
350         g_mutex_unlock (ifolder->search_lock);
351
352         return matches;
353 }
354
355 static guint32
356 imapx_count_by_expression (CamelFolder *folder,
357                            const gchar *expression,
358                            GCancellable *cancellable,
359                            GError **error)
360 {
361         CamelIMAPXFolder *ifolder = CAMEL_IMAPX_FOLDER (folder);
362         guint32 matches;
363
364         g_mutex_lock (ifolder->search_lock);
365
366         camel_folder_search_set_folder (ifolder->search, folder);
367         matches = camel_folder_search_count (ifolder->search, expression, cancellable, error);
368
369         g_mutex_unlock (ifolder->search_lock);
370
371         return matches;
372 }
373
374 static GPtrArray *
375 imapx_search_by_expression (CamelFolder *folder,
376                             const gchar *expression,
377                             GCancellable *cancellable,
378                             GError **error)
379 {
380         CamelIMAPXFolder *ifolder = CAMEL_IMAPX_FOLDER (folder);
381         GPtrArray *matches;
382
383         g_mutex_lock (ifolder->search_lock);
384
385         camel_folder_search_set_folder (ifolder->search, folder);
386         matches = camel_folder_search_search (ifolder->search, expression, NULL, cancellable, error);
387
388         g_mutex_unlock (ifolder->search_lock);
389
390         return matches;
391 }
392
393 static gboolean
394 imapx_append_message_sync (CamelFolder *folder,
395                            CamelMimeMessage *message,
396                            CamelMessageInfo *info,
397                            gchar **appended_uid,
398                            GCancellable *cancellable,
399                            GError **error)
400 {
401         CamelStore *parent_store;
402         CamelIMAPXStore *istore;
403         CamelIMAPXServer *server;
404         gboolean success = FALSE;
405
406         parent_store = camel_folder_get_parent_store (folder);
407         istore = CAMEL_IMAPX_STORE (parent_store);
408
409         if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
410                 g_set_error (
411                         error, CAMEL_SERVICE_ERROR,
412                         CAMEL_SERVICE_ERROR_UNAVAILABLE,
413                         _("You must be working online to complete this operation"));
414                 return FALSE;
415         }
416
417         if (appended_uid)
418                 *appended_uid = NULL;
419
420         server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
421         if (server) {
422                 success = camel_imapx_server_append_message (
423                         server, folder, message, info, appended_uid, cancellable, error);
424                 g_object_unref (server);
425         }
426
427         return success;
428 }
429
430 static gboolean
431 imapx_expunge_sync (CamelFolder *folder,
432                     GCancellable *cancellable,
433                     GError **error)
434 {
435         CamelStore *parent_store;
436         CamelIMAPXStore *istore;
437         CamelIMAPXServer *server;
438
439         parent_store = camel_folder_get_parent_store (folder);
440         istore = CAMEL_IMAPX_STORE (parent_store);
441
442         if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
443                 g_set_error (
444                         error, CAMEL_SERVICE_ERROR,
445                         CAMEL_SERVICE_ERROR_UNAVAILABLE,
446                         _("You must be working online to complete this operation"));
447                 return FALSE;
448         }
449
450         server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (folder), cancellable, error);
451         if (server) {
452                 camel_imapx_server_expunge (server, folder, cancellable, error);
453                 camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (folder));
454                 g_object_unref (server);
455                 return TRUE;
456         }
457
458         return FALSE;
459 }
460
461 static gboolean
462 imapx_fetch_messages_sync (CamelFolder *folder,
463                            CamelFetchType type,
464                            gint limit,
465                            GCancellable *cancellable,
466                            GError **error)
467 {
468         CamelService *service;
469         CamelStore *parent_store;
470         CamelIMAPXStore *istore;
471         CamelIMAPXServer *server;
472         gboolean success = FALSE;
473
474         parent_store = camel_folder_get_parent_store (folder);
475         istore = CAMEL_IMAPX_STORE (parent_store);
476         service = CAMEL_SERVICE (parent_store);
477
478         if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
479                 g_set_error (
480                         error, CAMEL_SERVICE_ERROR,
481                         CAMEL_SERVICE_ERROR_UNAVAILABLE,
482                         _("You must be working online to complete this operation"));
483                 return FALSE;
484         }
485
486         if (!camel_service_connect_sync (service, cancellable, error))
487                 return FALSE;
488
489         server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (folder), cancellable, error);
490         if (server != NULL) {
491                 success = camel_imapx_server_fetch_messages (server, folder, type, limit, cancellable, error);
492                 camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (folder));
493                 g_object_unref (server);
494         }
495
496         return success;
497 }
498
499 static CamelMimeMessage *
500 imapx_get_message_sync (CamelFolder *folder,
501                         const gchar *uid,
502                         GCancellable *cancellable,
503                         GError **error)
504 {
505         CamelMimeMessage *msg = NULL;
506         CamelStream *stream = NULL;
507         CamelStore *parent_store;
508         CamelIMAPXStore *istore;
509         CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
510         CamelIMAPXServer *server;
511         const gchar *path = NULL;
512         gboolean offline_message = FALSE;
513
514         parent_store = camel_folder_get_parent_store (folder);
515         istore = CAMEL_IMAPX_STORE (parent_store);
516
517         if (!strchr (uid, '-'))
518                 path = "cur";
519         else {
520                 path = "new";
521                 offline_message = TRUE;
522         }
523
524         stream = camel_data_cache_get (ifolder->cache, path, uid, NULL);
525         if (!stream) {
526                 if (offline_message) {
527                         g_set_error (
528                                 error, CAMEL_FOLDER_ERROR,
529                                 CAMEL_FOLDER_ERROR_INVALID_UID,
530                                 "Offline message vanished from disk: %s", uid);
531                         return NULL;
532                 }
533
534                 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
535                         g_set_error (
536                                 error, CAMEL_SERVICE_ERROR,
537                                 CAMEL_SERVICE_ERROR_UNAVAILABLE,
538                                 _("You must be working online to complete this operation"));
539                         return NULL;
540                 }
541
542                 server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (folder), cancellable, error);
543                 if (server) {
544                         stream = camel_imapx_server_get_message (server, folder, uid, cancellable, error);
545                         camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (folder));
546                         g_object_unref (server);
547                 } else
548                         return NULL;
549         }
550
551         if (stream != NULL) {
552                 msg = camel_mime_message_new ();
553
554                 g_mutex_lock (ifolder->stream_lock);
555                 if (!camel_data_wrapper_construct_from_stream_sync (
556                         (CamelDataWrapper *) msg, stream, cancellable, error)) {
557                         g_object_unref (msg);
558                         msg = NULL;
559                 }
560                 g_mutex_unlock (ifolder->stream_lock);
561                 g_object_unref (stream);
562
563                 if (msg) {
564                         CamelMessageInfo *mi = camel_folder_summary_get (folder->summary, uid);
565
566                         if (mi) {
567                                 gboolean has_attachment;
568
569                                 has_attachment = camel_mime_message_has_attachment (msg);
570                                 if (((camel_message_info_flags (mi) & CAMEL_MESSAGE_ATTACHMENTS) && !has_attachment) ||
571                                     ((camel_message_info_flags (mi) & CAMEL_MESSAGE_ATTACHMENTS) == 0 && has_attachment)) {
572                                         camel_message_info_set_flags (mi,
573                                                 CAMEL_MESSAGE_ATTACHMENTS, has_attachment ? CAMEL_MESSAGE_ATTACHMENTS : 0);
574                                 }
575
576                                 camel_message_info_free (mi);
577                         }
578                 }
579         }
580
581         return msg;
582 }
583
584 static gboolean
585 imapx_purge_message_cache_sync (CamelFolder *folder,
586                                 gchar *start_uid,
587                                 gchar *end_uid,
588                                 GCancellable *cancellable,
589                                 GError **error)
590 {
591         /* Not Implemented for now. */
592         return TRUE;
593 }
594
595 static gboolean
596 imapx_refresh_info_sync (CamelFolder *folder,
597                          GCancellable *cancellable,
598                          GError **error)
599 {
600         CamelService *service;
601         CamelStore *parent_store;
602         CamelIMAPXStore *istore;
603         CamelIMAPXServer *server;
604         gboolean success = FALSE;
605
606         parent_store = camel_folder_get_parent_store (folder);
607         istore = CAMEL_IMAPX_STORE (parent_store);
608         service = CAMEL_SERVICE (parent_store);
609
610         if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
611                 g_set_error (
612                         error, CAMEL_SERVICE_ERROR,
613                         CAMEL_SERVICE_ERROR_UNAVAILABLE,
614                         _("You must be working online to complete this operation"));
615                 return FALSE;
616         }
617
618         if (!camel_service_connect_sync (service, cancellable, error))
619                 return FALSE;
620
621         server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (folder), cancellable, error);
622         if (server != NULL) {
623                 success = camel_imapx_server_refresh_info (server, folder, cancellable, error);
624                 camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (folder));
625                 g_object_unref (server);
626         }
627
628         return success;
629 }
630
631 static gboolean
632 imapx_synchronize_sync (CamelFolder *folder,
633                         gboolean expunge,
634                         GCancellable *cancellable,
635                         GError **error)
636 {
637         CamelStore *parent_store;
638         CamelIMAPXStore *istore;
639         CamelIMAPXServer *server;
640
641         parent_store = camel_folder_get_parent_store (folder);
642         istore = CAMEL_IMAPX_STORE (parent_store);
643
644         if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
645                 g_set_error (
646                         error, CAMEL_SERVICE_ERROR,
647                         CAMEL_SERVICE_ERROR_UNAVAILABLE,
648                         _("You must be working online to complete this operation"));
649                 return FALSE;
650         }
651
652         server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (folder), cancellable, error);
653         if (!server)
654                 return FALSE;
655
656         camel_imapx_server_sync_changes (server, folder, cancellable, NULL);
657
658         /* Sync twice - make sure deleted flags are written out,
659          * then sync again incase expunge changed anything */
660
661         if (expunge)
662                 camel_imapx_server_expunge (server, folder, cancellable, NULL);
663
664         camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (folder));
665         g_object_unref (server);
666
667         return TRUE;
668 }
669
670 static gboolean
671 imapx_synchronize_message_sync (CamelFolder *folder,
672                                 const gchar *uid,
673                                 GCancellable *cancellable,
674                                 GError **error)
675 {
676         CamelStore *parent_store;
677         CamelIMAPXStore *istore;
678         CamelIMAPXServer *server;
679         gboolean success;
680
681         parent_store = camel_folder_get_parent_store (folder);
682         istore = CAMEL_IMAPX_STORE (parent_store);
683
684         if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
685                 g_set_error (
686                         error, CAMEL_SERVICE_ERROR,
687                         CAMEL_SERVICE_ERROR_UNAVAILABLE,
688                         _("You must be working online to complete this operation"));
689                 return FALSE;
690         }
691
692         server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (folder), cancellable, error);
693         if (server == NULL)
694                 return FALSE;
695
696         success = camel_imapx_server_sync_message (server, folder, uid, cancellable, error);
697         camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (folder));
698         g_object_unref (server);
699
700         return success;
701 }
702
703 static gboolean
704 imapx_transfer_messages_to_sync (CamelFolder *source,
705                                  GPtrArray *uids,
706                                  CamelFolder *dest,
707                                  gboolean delete_originals,
708                                  GPtrArray **transferred_uids,
709                                  GCancellable *cancellable,
710                                  GError **error)
711 {
712         CamelStore *parent_store;
713         CamelIMAPXStore *istore;
714         CamelIMAPXServer *server;
715         gboolean success = FALSE;
716
717         parent_store = camel_folder_get_parent_store (source);
718         istore = CAMEL_IMAPX_STORE (parent_store);
719
720         if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
721                 g_set_error (
722                         error, CAMEL_SERVICE_ERROR,
723                         CAMEL_SERVICE_ERROR_UNAVAILABLE,
724                         _("You must be working online to complete this operation"));
725                 return FALSE;
726         }
727
728         server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (source), cancellable, error);
729         if (server) {
730                 success = camel_imapx_server_copy_message (server, source, dest, uids, delete_originals, cancellable, error);
731                 camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (source));
732                 g_object_unref (server);
733         }
734
735         imapx_refresh_info_sync (dest, cancellable, NULL);
736
737         return success;
738 }
739
740 static void
741 imapx_rename (CamelFolder *folder,
742               const gchar *new_name)
743 {
744         CamelStore *parent_store;
745
746         parent_store = camel_folder_get_parent_store (folder);
747
748         camel_store_summary_disconnect_folder_summary (
749                 (CamelStoreSummary *) ((CamelIMAPXStore *) parent_store)->summary,
750                 folder->summary);
751
752         CAMEL_FOLDER_CLASS (camel_imapx_folder_parent_class)->rename (folder, new_name);
753
754         camel_store_summary_connect_folder_summary (
755                 (CamelStoreSummary *) ((CamelIMAPXStore *) parent_store)->summary,
756                 camel_folder_get_full_name (folder), folder->summary);
757 }
758
759 static void
760 camel_imapx_folder_class_init (CamelIMAPXFolderClass *class)
761 {
762         GObjectClass *object_class;
763         CamelFolderClass *folder_class;
764
765         object_class = G_OBJECT_CLASS (class);
766         object_class->set_property = imapx_folder_set_property;
767         object_class->get_property = imapx_folder_get_property;
768         object_class->dispose = imapx_folder_dispose;
769         object_class->finalize = imapx_folder_finalize;
770
771         folder_class = CAMEL_FOLDER_CLASS (class);
772         folder_class->rename = imapx_rename;
773         folder_class->search_by_expression = imapx_search_by_expression;
774         folder_class->search_by_uids = imapx_search_by_uids;
775         folder_class->count_by_expression = imapx_count_by_expression;
776         folder_class->search_free = imapx_search_free;
777         folder_class->get_filename = imapx_get_filename;
778         folder_class->append_message_sync = imapx_append_message_sync;
779         folder_class->expunge_sync = imapx_expunge_sync;
780         folder_class->fetch_messages_sync = imapx_fetch_messages_sync;
781         folder_class->get_message_sync = imapx_get_message_sync;
782         folder_class->purge_message_cache_sync = imapx_purge_message_cache_sync;
783         folder_class->refresh_info_sync = imapx_refresh_info_sync;
784         folder_class->synchronize_sync = imapx_synchronize_sync;
785         folder_class->synchronize_message_sync = imapx_synchronize_message_sync;
786         folder_class->transfer_messages_to_sync = imapx_transfer_messages_to_sync;
787
788         g_object_class_install_property (
789                 object_class,
790                 PROP_APPLY_FILTERS,
791                 g_param_spec_boolean (
792                         "apply-filters",
793                         "Apply Filters",
794                         _("Apply message _filters to this folder"),
795                         FALSE,
796                         G_PARAM_READWRITE |
797                         CAMEL_PARAM_PERSISTENT));
798 }
799
800 static void
801 camel_imapx_folder_init (CamelIMAPXFolder *imapx_folder)
802 {
803         CamelFolder *folder = CAMEL_FOLDER (imapx_folder);
804
805         folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
806
807         folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
808                 CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT |
809                 CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_USER;
810
811         camel_folder_set_lock_async (folder, TRUE);
812 }
813