removed. (imap_store_refresh_folders): Copy the folders first, then
[platform/upstream/evolution-data-server.git] / camel / camel-disco-folder.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-disco-folder.c: abstract class for a disconnectable folder */
3
4 /* 
5  * Authors: Dan Winship <danw@ximian.com>
6  *
7  * Copyright (C) 2001 Ximian, Inc.
8  *
9  * This program is free software; you can redistribute it and/or 
10  * modify it under the terms of version 2 of the GNU General Public 
11  * License as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21  * USA
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "camel-disco-folder.h"
29 #include "camel-disco-store.h"
30 #include "camel-exception.h"
31
32 #define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (o)))
33 #define CDF_CLASS(o) (CAMEL_DISCO_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (o)))
34
35 static CamelFolderClass *parent_class = NULL;
36
37 static void disco_refresh_info (CamelFolder *folder, CamelException *ex);
38 static void disco_sync (CamelFolder *folder, gboolean expunge, CamelException *ex);
39 static void disco_expunge (CamelFolder *folder, CamelException *ex);
40
41 static void disco_append_message (CamelFolder *folder, CamelMimeMessage *message,
42                                   const CamelMessageInfo *info, char **appended_uid, CamelException *ex);
43 static void disco_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
44                                         CamelFolder *destination,
45                                         GPtrArray **transferred_uids,
46                                         gboolean delete_originals,
47                                         CamelException *ex);
48
49 static void disco_cache_message       (CamelDiscoFolder *disco_folder,
50                                        const char *uid, CamelException *ex);
51 static void disco_prepare_for_offline (CamelDiscoFolder *disco_folder,
52                                        const char *expression,
53                                        CamelException *ex);
54
55 static void
56 camel_disco_folder_class_init (CamelDiscoFolderClass *camel_disco_folder_class)
57 {
58         CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_disco_folder_class);
59
60         parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_folder_get_type ()));
61
62         /* virtual method definition */
63         camel_disco_folder_class->cache_message = disco_cache_message;
64         camel_disco_folder_class->prepare_for_offline = disco_prepare_for_offline;
65
66         /* virtual method overload */
67         camel_folder_class->refresh_info = disco_refresh_info;
68         camel_folder_class->sync = disco_sync;
69         camel_folder_class->expunge = disco_expunge;
70
71         camel_folder_class->append_message = disco_append_message;
72         camel_folder_class->transfer_messages_to = disco_transfer_messages_to;
73 }
74
75 CamelType
76 camel_disco_folder_get_type (void)
77 {
78         static CamelType camel_disco_folder_type = CAMEL_INVALID_TYPE;
79
80         if (camel_disco_folder_type == CAMEL_INVALID_TYPE) {
81                 camel_disco_folder_type = camel_type_register (
82                         CAMEL_FOLDER_TYPE, "CamelDiscoFolder",
83                         sizeof (CamelDiscoFolder),
84                         sizeof (CamelDiscoFolderClass),
85                         (CamelObjectClassInitFunc) camel_disco_folder_class_init,
86                         NULL, NULL, NULL);
87         }
88
89         return camel_disco_folder_type;
90 }
91
92
93 static void
94 disco_refresh_info (CamelFolder *folder, CamelException *ex)
95 {
96         if (camel_disco_store_status (CAMEL_DISCO_STORE (folder->parent_store)) != CAMEL_DISCO_STORE_ONLINE)
97                 return;
98         CDF_CLASS (folder)->refresh_info_online (folder, ex);
99 }
100
101 static void
102 disco_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
103 {
104         if (expunge) {
105                 disco_expunge (folder, ex);
106                 if (camel_exception_is_set (ex))
107                         return;
108         }
109
110         switch (camel_disco_store_status (CAMEL_DISCO_STORE (folder->parent_store))) {
111         case CAMEL_DISCO_STORE_ONLINE:
112                 CDF_CLASS (folder)->sync_online (folder, ex);
113                 break;
114
115         case CAMEL_DISCO_STORE_OFFLINE:
116                 CDF_CLASS (folder)->sync_offline (folder, ex);
117                 break;
118
119         case CAMEL_DISCO_STORE_RESYNCING:
120                 CDF_CLASS (folder)->sync_resyncing (folder, ex);
121                 break;
122         }
123 }
124
125 static void
126 disco_expunge_uids (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
127 {
128         CamelDiscoStore *disco = CAMEL_DISCO_STORE (folder->parent_store);
129
130         if (uids->len == 0)
131                 return;
132
133         switch (camel_disco_store_status (disco)) {
134         case CAMEL_DISCO_STORE_ONLINE:
135                 CDF_CLASS (folder)->expunge_uids_online (folder, uids, ex);
136                 break;
137
138         case CAMEL_DISCO_STORE_OFFLINE:
139                 CDF_CLASS (folder)->expunge_uids_offline (folder, uids, ex);
140                 break;
141
142         case CAMEL_DISCO_STORE_RESYNCING:
143                 CDF_CLASS (folder)->expunge_uids_resyncing (folder, uids, ex);
144                 break;
145         }
146 }
147
148 static void
149 disco_expunge (CamelFolder *folder, CamelException *ex)
150 {
151         GPtrArray *uids;
152         int i, count;
153         CamelMessageInfo *info;
154
155         uids = g_ptr_array_new ();
156         count = camel_folder_summary_count (folder->summary);
157         for (i = 0; i < count; i++) {
158                 info = camel_folder_summary_index (folder->summary, i);
159                 if (info->flags & CAMEL_MESSAGE_DELETED)
160                         g_ptr_array_add (uids, g_strdup (camel_message_info_uid (info)));
161                 camel_folder_summary_info_free (folder->summary, info);
162         }
163
164         disco_expunge_uids (folder, uids, ex);
165
166         for (i = 0; i < uids->len; i++)
167                 g_free (uids->pdata[i]);
168         g_ptr_array_free (uids, TRUE);
169 }
170
171 static void
172 disco_append_message (CamelFolder *folder, CamelMimeMessage *message,
173                       const CamelMessageInfo *info, char **appended_uid,
174                       CamelException *ex)
175 {
176         CamelDiscoStore *disco = CAMEL_DISCO_STORE (folder->parent_store);
177
178         switch (camel_disco_store_status (disco)) {
179         case CAMEL_DISCO_STORE_ONLINE:
180                 CDF_CLASS (folder)->append_online (folder, message, info,
181                                                    appended_uid, ex);
182                 break;
183
184         case CAMEL_DISCO_STORE_OFFLINE:
185                 CDF_CLASS (folder)->append_offline (folder, message, info,
186                                                     appended_uid, ex);
187                 break;
188
189         case CAMEL_DISCO_STORE_RESYNCING:
190                 CDF_CLASS (folder)->append_resyncing (folder, message, info,
191                                                       appended_uid, ex);
192                 break;
193         }
194 }
195
196 static void
197 disco_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
198                             CamelFolder *dest, GPtrArray **transferred_uids,
199                             gboolean delete_originals, CamelException *ex)
200 {
201         CamelDiscoStore *disco = CAMEL_DISCO_STORE (source->parent_store);
202
203         switch (camel_disco_store_status (disco)) {
204         case CAMEL_DISCO_STORE_ONLINE:
205                 CDF_CLASS (source)->transfer_online (source, uids,
206                                                      dest, transferred_uids,
207                                                      delete_originals, ex);
208                 break;
209
210         case CAMEL_DISCO_STORE_OFFLINE:
211                 CDF_CLASS (source)->transfer_offline (source, uids,
212                                                       dest, transferred_uids,
213                                                       delete_originals, ex);
214                 break;
215
216         case CAMEL_DISCO_STORE_RESYNCING:
217                 CDF_CLASS (source)->transfer_resyncing (source, uids,
218                                                         dest, transferred_uids,
219                                                         delete_originals, ex);
220                 break;
221         }
222 }
223
224
225 /**
226  * camel_disco_folder_expunge_uids:
227  * @folder: a (disconnectable) folder
228  * @uids: array of UIDs to expunge
229  * @ex: a CamelException
230  *
231  * This expunges the messages in @uids from @folder. It should take
232  * whatever steps are needed to avoid expunging any other messages,
233  * although in some cases it may not be possible to avoid expunging
234  * messages that are marked deleted by another client at the same time
235  * as the expunge_uids call is running.
236  **/
237 void
238 camel_disco_folder_expunge_uids (CamelFolder *folder, GPtrArray *uids,
239                                  CamelException *ex)
240 {
241         disco_expunge_uids (folder, uids, ex);
242 }
243
244
245 static void
246 disco_cache_message (CamelDiscoFolder *disco_folder, const char *uid,
247                      CamelException *ex)
248 {
249         g_warning ("CamelDiscoFolder::cache_message not implemented for `%s'",
250                    camel_type_to_name (CAMEL_OBJECT_GET_TYPE (disco_folder)));
251 }
252
253 /**
254  * camel_disco_folder_cache_message:
255  * @disco_folder: the folder
256  * @uid: the UID of the message to cache
257  * @ex: a CamelException
258  *
259  * Requests that @disco_folder cache message @uid to disk.
260  **/
261 void
262 camel_disco_folder_cache_message (CamelDiscoFolder *disco_folder,
263                                   const char *uid, CamelException *ex)
264 {
265         CDF_CLASS (disco_folder)->cache_message (disco_folder, uid, ex);
266 }
267
268
269 static void
270 disco_prepare_for_offline (CamelDiscoFolder *disco_folder,
271                            const char *expression,
272                            CamelException *ex)
273 {
274         CamelFolder *folder = CAMEL_FOLDER (disco_folder);
275         GPtrArray *uids;
276         int i;
277
278         camel_operation_start(NULL, _("Preparing folder '%s' for offline"), folder->full_name);
279
280         if (expression)
281                 uids = camel_folder_search_by_expression (folder, expression, ex);
282         else
283                 uids = camel_folder_get_uids (folder);
284
285         if (!uids) {
286                 camel_operation_end(NULL);
287                 return;
288         }
289
290         for (i = 0; i < uids->len; i++) {
291                 int pc = i * 100 / uids->len;
292
293                 camel_disco_folder_cache_message (disco_folder, uids->pdata[i], ex);
294                 camel_operation_progress(NULL, pc);
295                 if (camel_exception_is_set (ex))
296                         break;
297         }
298
299         if (expression)
300                 camel_folder_search_free (folder, uids);
301         else
302                 camel_folder_free_uids (folder, uids);
303
304         camel_operation_end(NULL);
305 }
306
307 /**
308  * camel_disco_folder_prepare_for_offline:
309  * @disco_folder: the folder
310  * @expression: an expression describing messages to synchronize, or %NULL
311  * if all messages should be sync'ed.
312  * @ex: a CamelException
313  *
314  * This prepares @disco_folder for offline operation, by downloading
315  * the bodies of all messages described by @expression (using the
316  * same syntax as camel_folder_search_by_expression() ).
317  **/
318 void 
319 camel_disco_folder_prepare_for_offline (CamelDiscoFolder *disco_folder,
320                                         const char *expression,
321                                         CamelException *ex)
322 {
323         g_return_if_fail (CAMEL_IS_DISCO_FOLDER (disco_folder));
324
325         CDF_CLASS (disco_folder)->prepare_for_offline (disco_folder, expression, ex);
326 }