Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-offline-folder.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@novell.com>
4  *
5  *  Copyright 2005 Novell, Inc. (www.novell.com)
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
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
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <glib.h>
29 #include <glib/gi18n-lib.h>
30
31 #include "camel-offline-folder.h"
32 #include "camel-operation.h"
33 #include "camel-service.h"
34 #include "camel-session.h"
35
36 #define CAMEL_OFFLINE_FOLDER_GET_CLASS(f) (CAMEL_OFFLINE_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (f)))
37
38 static void camel_offline_folder_class_init (CamelOfflineFolderClass *klass);
39 static void camel_offline_folder_init (CamelOfflineFolder *folder, CamelOfflineFolderClass *klass);
40 static void camel_offline_folder_finalize (CamelObject *object);
41
42 static int offline_folder_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args);
43 static int offline_folder_setv (CamelObject *object, CamelException *ex, CamelArgV *args);
44
45 static void offline_folder_downsync (CamelOfflineFolder *offline, const char *expression, CamelException *ex);
46
47 static CamelFolderClass *parent_class = NULL;
48
49 static GSList *offline_folder_props = NULL;
50
51 static CamelProperty offline_prop_list[] = {
52         { CAMEL_OFFLINE_FOLDER_SYNC_OFFLINE, "sync_offline", N_("Copy folder content locally for offline operation") },
53 };
54
55
56 CamelType
57 camel_offline_folder_get_type (void)
58 {
59         static CamelType type = 0;
60         
61         if (!type) {
62                 type = camel_type_register (CAMEL_FOLDER_TYPE,
63                                             "CamelOfflineFolder",
64                                             sizeof (CamelOfflineFolder),
65                                             sizeof (CamelOfflineFolderClass),
66                                             (CamelObjectClassInitFunc) camel_offline_folder_class_init,
67                                             NULL,
68                                             (CamelObjectInitFunc) camel_offline_folder_init,
69                                             (CamelObjectFinalizeFunc) camel_offline_folder_finalize);
70         }
71         
72         return type;
73 }
74
75
76 static void
77 camel_offline_folder_class_init (CamelOfflineFolderClass *klass)
78 {
79         int i;
80         
81         parent_class = (CamelFolderClass *) camel_type_get_global_classfuncs (CAMEL_FOLDER_TYPE);
82         
83         if (offline_folder_props == NULL) {
84                 for (i = 0; i < G_N_ELEMENTS (offline_prop_list); i++) {
85                         offline_prop_list[i].description = _(offline_prop_list[i].description);
86                         offline_folder_props = g_slist_prepend (offline_folder_props, &offline_prop_list[i]);
87                 }
88         }
89         
90         ((CamelObjectClass *) klass)->getv = offline_folder_getv;
91         ((CamelObjectClass *) klass)->setv = offline_folder_setv;
92         
93         klass->downsync = offline_folder_downsync;
94 }
95
96
97 struct _offline_downsync_msg {
98         CamelSessionThreadMsg msg;
99         
100         CamelFolder *folder;
101         CamelFolderChangeInfo *changes;
102 };
103
104 static void
105 offline_downsync_sync (CamelSession *session, CamelSessionThreadMsg *mm)
106 {
107         struct _offline_downsync_msg *m = (struct _offline_downsync_msg *) mm;
108         CamelMimeMessage *message;
109         int i;
110         
111         camel_operation_start (NULL, _("Downloading new messages for offline mode"));
112         
113         if (m->changes) {
114                 for (i = 0; i < m->changes->uid_added->len; i++) {
115                         int pc = i * 100 / m->changes->uid_added->len;
116                         
117                         camel_operation_progress (NULL, pc);
118                         if ((message = camel_folder_get_message (m->folder, m->changes->uid_added->pdata[i], &mm->ex)))
119                                 camel_object_unref (message);
120                 }
121         } else {
122                 camel_offline_folder_downsync ((CamelOfflineFolder *) m->folder, "(match-all)", &mm->ex);
123         }
124         
125         camel_operation_end (NULL);
126 }
127
128 static void
129 offline_downsync_free (CamelSession *session, CamelSessionThreadMsg *mm)
130 {
131         struct _offline_downsync_msg *m = (struct _offline_downsync_msg *) mm;
132         
133         if (m->changes)
134                 camel_folder_change_info_free (m->changes);
135         
136         camel_object_unref (m->folder);
137 }
138
139 static CamelSessionThreadOps offline_downsync_ops = {
140         offline_downsync_sync,
141         offline_downsync_free,
142 };
143
144 static void
145 offline_folder_changed (CamelFolder *folder, CamelFolderChangeInfo *changes, void *dummy)
146 {
147         CamelOfflineFolder *offline = (CamelOfflineFolder *) folder;
148         CamelService *service = (CamelService *) folder->parent_store;
149         
150         if (changes->uid_added->len > 0 && (offline->sync_offline || camel_url_get_param (service->url, "sync_offline"))) {
151                 CamelSession *session = service->session;
152                 struct _offline_downsync_msg *m;
153                 
154                 m = camel_session_thread_msg_new (session, &offline_downsync_ops, sizeof (*m));
155                 m->changes = camel_folder_change_info_new ();
156                 camel_folder_change_info_cat (m->changes, changes);
157                 camel_object_ref (folder);
158                 m->folder = folder;
159                 
160                 camel_session_thread_queue (session, &m->msg, 0);
161         }
162 }
163
164 static void
165 camel_offline_folder_init (CamelOfflineFolder *folder, CamelOfflineFolderClass *klass)
166 {       
167         camel_object_hook_event (folder, "folder_changed", (CamelObjectEventHookFunc) offline_folder_changed, NULL);
168 }
169
170 static void
171 camel_offline_folder_finalize (CamelObject *object)
172 {
173         ;
174 }
175
176 static int
177 offline_folder_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args)
178 {
179         CamelArgGetV props;
180         int i, count = 0;
181         guint32 tag;
182         
183         for (i = 0; i < args->argc; i++) {
184                 CamelArgGet *arg = &args->argv[i];
185                 
186                 tag = arg->tag;
187                 
188                 switch (tag & CAMEL_ARG_TAG) {
189                 case CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES:
190                 case CAMEL_FOLDER_ARG_PROPERTIES:
191                         props.argc = 1;
192                         props.argv[0] = *arg;
193                         ((CamelObjectClass *) parent_class)->getv (object, ex, &props);
194                         *arg->ca_ptr = g_slist_concat (*arg->ca_ptr, g_slist_copy (offline_folder_props));
195                         break;
196                 case CAMEL_OFFLINE_FOLDER_ARG_SYNC_OFFLINE:
197                         *arg->ca_int = ((CamelOfflineFolder *) object)->sync_offline;
198                         break;
199                 default:
200                         count++;
201                         continue;
202                 }
203                 
204                 arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
205         }
206         
207         if (count)
208                 return ((CamelObjectClass *) parent_class)->getv (object, ex, args);
209         
210         return 0;
211 }
212
213 static int
214 offline_folder_setv (CamelObject *object, CamelException *ex, CamelArgV *args)
215 {
216         CamelOfflineFolder *folder = (CamelOfflineFolder *) object;
217         gboolean save = FALSE;
218         guint32 tag;
219         int i;
220         
221         for (i = 0; i < args->argc; i++) {
222                 CamelArg *arg = &args->argv[i];
223                 
224                 tag = arg->tag;
225                 
226                 switch (tag & CAMEL_ARG_TAG) {
227                 case CAMEL_OFFLINE_FOLDER_ARG_SYNC_OFFLINE:
228                         if (folder->sync_offline != arg->ca_int) {
229                                 folder->sync_offline = arg->ca_int;
230                                 save = TRUE;
231                         }
232                         break;
233                 default:
234                         continue;
235                 }
236                 
237                 arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
238         }
239         
240         if (save)
241                 camel_object_state_write (object);
242         
243         return ((CamelObjectClass *) parent_class)->setv (object, ex, args);
244 }
245
246 static void
247 offline_folder_downsync (CamelOfflineFolder *offline, const char *expression, CamelException *ex)
248 {
249         CamelFolder *folder = (CamelFolder *) offline;
250         CamelMimeMessage *message;
251         GPtrArray *uids;
252         int i;
253         
254         camel_operation_start (NULL, _("Syncing messages in folder '%s' to disk"), folder->full_name);
255         
256         if (expression)
257                 uids = camel_folder_search_by_expression (folder, expression, ex);
258         else
259                 uids = camel_folder_get_uids (folder);
260         
261         if (!uids) {
262                 camel_operation_end (NULL);
263                 return;
264         }
265         
266         for (i = 0; i < uids->len; i++) {
267                 int pc = i * 100 / uids->len;
268                 
269                 message = camel_folder_get_message (folder, uids->pdata[i], ex);
270                 camel_operation_progress (NULL, pc);
271                 if (message == NULL)
272                         break;
273                 
274                 camel_object_unref (message);
275         }
276         
277         if (expression)
278                 camel_folder_search_free (folder, uids);
279         else
280                 camel_folder_free_uids (folder, uids);
281         
282         camel_operation_end (NULL);
283 }
284
285
286 /**
287  * camel_offline_fodler_downsync:
288  * @offline: a #CamelOfflineFolder object
289  * @expression: search expression describing which set of messages to downsync (%NULL for all)
290  * @ex: a #CamelException
291  *
292  * Syncs messages in @offline described by the search @expression to
293  * the local machine for offline availability.
294  **/
295 void
296 camel_offline_folder_downsync (CamelOfflineFolder *offline, const char *expression, CamelException *ex)
297 {
298         g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline));
299         
300         CAMEL_OFFLINE_FOLDER_GET_CLASS (offline)->downsync (offline, expression, ex);
301 }