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