Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / providers / groupwise / camel-groupwise-summary.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Copyright (C) 2004 Novell Inc.
4  *
5  *  Authors:
6  *      parthasrathi susarla <sparthasrathi@novell.com>
7  * Based on the IMAP summary class implementation by: 
8  *    Michael Zucchi <notzed@ximian.com>
9  *    Dan Winship <danw@ximian.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of version 2 of the GNU Lesser General Public
13  * License as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this program; if not, write to the
22  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35
36 #include "camel-data-cache.h"
37 #include "camel-file-utils.h"
38 #include "camel-folder.h"
39
40 #include "camel-groupwise-folder.h"
41 #include "camel-groupwise-summary.h"
42
43 #define CAMEL_GW_SUMMARY_VERSION (1)
44
45 /*Prototypes*/
46 static int gw_summary_header_load (CamelFolderSummary *, FILE *);
47 static int gw_summary_header_save (CamelFolderSummary *, FILE *);
48
49 static CamelMessageInfo *gw_message_info_load (CamelFolderSummary *s, FILE *in) ;
50
51 static int gw_message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info) ;
52 static CamelMessageContentInfo * gw_content_info_load (CamelFolderSummary *s, FILE *in) ;
53 static int gw_content_info_save (CamelFolderSummary *s, FILE *out, CamelMessageContentInfo *info) ;
54 static gboolean gw_info_set_flags(CamelMessageInfo *info, guint32 flags, guint32 set);          
55
56 static void camel_groupwise_summary_class_init (CamelGroupwiseSummaryClass *klass);
57 static void camel_groupwise_summary_init       (CamelGroupwiseSummary *obj);
58
59
60 /*End of Prototypes*/
61
62
63 static CamelFolderSummaryClass *camel_groupwise_summary_parent ;
64
65
66 CamelType
67 camel_groupwise_summary_get_type (void)
68 {
69         static CamelType type = CAMEL_INVALID_TYPE;
70
71         if (type == CAMEL_INVALID_TYPE) {
72                 type = camel_type_register(
73                                 camel_folder_summary_get_type(), "CamelGroupwiseSummary",
74                                 sizeof (CamelGroupwiseSummary),
75                                 sizeof (CamelGroupwiseSummaryClass),
76                                 (CamelObjectClassInitFunc) camel_groupwise_summary_class_init,
77                                 NULL,
78                                 (CamelObjectInitFunc) camel_groupwise_summary_init,
79                                 NULL);
80         }
81
82         return type;
83 }
84
85 static CamelMessageInfo *
86 gw_message_info_clone(CamelFolderSummary *s, const CamelMessageInfo *mi)
87 {
88         CamelGroupwiseMessageInfo *to;
89         const CamelGroupwiseMessageInfo *from = (const CamelGroupwiseMessageInfo *)mi;
90
91         to = (CamelGroupwiseMessageInfo *)camel_groupwise_summary_parent->message_info_clone(s, mi);
92         to->server_flags = from->server_flags;
93
94         /* FIXME: parent clone should do this */
95         to->info.content = camel_folder_summary_content_info_new(s);
96
97         return (CamelMessageInfo *)to;
98 }
99
100 static void
101 camel_groupwise_summary_class_init (CamelGroupwiseSummaryClass *klass)
102 {
103         CamelFolderSummaryClass *cfs_class = (CamelFolderSummaryClass *) klass;
104
105         camel_groupwise_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS (camel_type_get_global_classfuncs (camel_folder_summary_get_type()));
106
107         cfs_class->message_info_clone = gw_message_info_clone ;
108         cfs_class->summary_header_load = gw_summary_header_load;
109         cfs_class->summary_header_save = gw_summary_header_save;
110         cfs_class->message_info_load = gw_message_info_load;
111         cfs_class->message_info_save = gw_message_info_save;
112         cfs_class->content_info_load = gw_content_info_load;
113         cfs_class->content_info_save = gw_content_info_save;
114         cfs_class->info_set_flags = gw_info_set_flags;
115 }
116
117
118 static void
119 camel_groupwise_summary_init (CamelGroupwiseSummary *obj)
120 {
121         CamelFolderSummary *s = (CamelFolderSummary *)obj;
122
123         /* subclasses need to set the right instance data sizes */
124         s->message_info_size = sizeof(CamelGroupwiseMessageInfo);
125         s->content_info_size = sizeof(CamelGroupwiseMessageContentInfo);
126         
127         /* Meta-summary - Overriding UID len */
128         s->meta_summary->uid_len = 2048;
129 }
130
131
132 /**
133  * camel_groupwise_summary_new:
134  * @filename: the file to store the summary in.
135  *
136  * This will create a new CamelGroupwiseSummary object and read in the
137  * summary data from disk, if it exists.
138  *
139  * Return value: A new CamelGroupwiseSummary object.
140  **/
141 CamelFolderSummary *
142 camel_groupwise_summary_new (struct _CamelFolder *folder, const char *filename)
143 {
144         CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY (
145                         camel_object_new (camel_groupwise_summary_get_type ()));
146         
147         summary->folder = folder ;
148         camel_folder_summary_set_build_content (summary, TRUE);
149         camel_folder_summary_set_filename (summary, filename);
150
151         if (camel_folder_summary_load (summary) == -1) {
152                 camel_folder_summary_clear (summary);
153                 camel_folder_summary_touch (summary);
154         }
155
156         return summary;
157 }
158
159 static int
160 gw_summary_header_load (CamelFolderSummary *s, FILE *in)
161 {
162         CamelGroupwiseSummary *ims = CAMEL_GROUPWISE_SUMMARY (s);
163
164         if (camel_groupwise_summary_parent->summary_header_load (s, in) == -1)
165                 return -1 ;
166
167         if (camel_file_util_decode_fixed_int32(in, &ims->version) == -1
168                         || camel_file_util_decode_fixed_int32(in, &ims->validity) == -1)
169                 return -1;
170         
171         if (camel_file_util_decode_string (in, &ims->time_string) == -1)
172                 return -1;
173         return 0 ;
174 }
175
176
177 static int
178 gw_summary_header_save (CamelFolderSummary *s, FILE *out)
179 {
180         CamelGroupwiseSummary *ims = CAMEL_GROUPWISE_SUMMARY(s);
181
182         if (camel_groupwise_summary_parent->summary_header_save (s, out) == -1)
183                 return -1;
184
185         camel_file_util_encode_fixed_int32(out, CAMEL_GW_SUMMARY_VERSION);
186         camel_file_util_encode_fixed_int32(out, ims->validity);
187         return camel_file_util_encode_string (out, ims->time_string);
188
189
190 }
191
192 static CamelMessageInfo *
193 gw_message_info_load (CamelFolderSummary *s, FILE *in)
194 {
195         CamelMessageInfo *info ;
196         CamelGroupwiseMessageInfo *gw_info ;
197
198
199         info = camel_groupwise_summary_parent->message_info_load(s,in) ;
200         if (info) {
201                 gw_info = (CamelGroupwiseMessageInfo*) info ;
202                 if (camel_file_util_decode_uint32 (in, &gw_info->server_flags) == -1)
203                         goto error ;
204         }
205
206         return info ;
207 error:
208         camel_message_info_free (info) ;
209         return NULL ;
210 }
211
212
213 static int
214 gw_message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info)
215 {
216         CamelGroupwiseMessageInfo *gw_info = (CamelGroupwiseMessageInfo *)info;
217
218         if (camel_groupwise_summary_parent->message_info_save (s, out, info) == -1)
219                 return -1;
220
221         return camel_file_util_encode_uint32 (out, gw_info->server_flags);
222 }
223
224
225 static CamelMessageContentInfo *
226 gw_content_info_load (CamelFolderSummary *s, FILE *in)
227 {       
228         if (fgetc (in))
229                 return camel_groupwise_summary_parent->content_info_load (s, in);
230         else
231                 return camel_folder_summary_content_info_new (s);
232 }
233
234
235 static int
236 gw_content_info_save (CamelFolderSummary *s, FILE *out,
237                 CamelMessageContentInfo *info)
238 {
239         if (info->type) {
240                 fputc (1, out);
241                 return camel_groupwise_summary_parent->content_info_save (s, out, info);
242         } else
243                 return fputc (0, out);
244 }
245
246 static gboolean
247 gw_info_set_flags (CamelMessageInfo *info, guint32 flags, guint32 set)
248 {
249         guint32 old;
250         CamelMessageInfoBase *mi = (CamelMessageInfoBase *)info;
251
252         /* TODO: locking? */
253
254         old = mi->flags;
255         /* we don't set flags which aren't appropriate for the folder*/
256         if ((set == (CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN|CAMEL_MESSAGE_SEEN)) && (old & CAMEL_GW_MESSAGE_JUNK))
257                 return FALSE;
258         
259         mi->flags = (old & ~flags) | (set & flags);
260         if (old != mi->flags) {
261                 mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
262                 if (mi->summary)
263                         camel_folder_summary_touch(mi->summary);
264         }
265         /* This is a hack, we are using CAMEL_MESSAGE_JUNK justo to hide the item
266          * we make sure this doesn't have any side effects*/
267         
268         if ((set == CAMEL_MESSAGE_JUNK_LEARN) && (old & CAMEL_GW_MESSAGE_JUNK)) {
269                 mi->flags |= CAMEL_GW_MESSAGE_NOJUNK | CAMEL_MESSAGE_JUNK;
270
271                 /* This has ugly side-effects. Evo will never learn unjunk. 
272
273                    We need to create one CAMEL_MESSAGE_HIDDEN flag which must be used for all hiding operations. We must also get rid of the seperate file that is maintained somewhere in evolution/mail/em-folder-browser.c for hidden messages
274                  */
275
276                 if (mi->summary) {
277                         camel_folder_summary_touch(mi->summary);
278                 }
279
280         } else  if ((old & ~CAMEL_MESSAGE_SYSTEM_MASK) == (mi->flags & ~CAMEL_MESSAGE_SYSTEM_MASK)) 
281                 return FALSE;
282
283         if (mi->summary && mi->summary->folder && mi->uid) {
284                 CamelFolderChangeInfo *changes = camel_folder_change_info_new();
285
286                 camel_folder_change_info_change_uid(changes, camel_message_info_uid(info));
287                 camel_object_trigger_event(mi->summary->folder, "folder_changed", changes);
288                 camel_folder_change_info_free(changes);
289         }
290
291         return TRUE;
292
293 }
294
295
296 void
297 camel_gw_summary_add_offline (CamelFolderSummary *summary, const char *uid, CamelMimeMessage *message, const CamelMessageInfo *info)
298 {
299         CamelGroupwiseMessageInfo *mi ; 
300         const CamelFlag *flag ;
301         const CamelTag *tag ;
302
303         /* Create summary entry */
304         mi = (CamelGroupwiseMessageInfo *)camel_folder_summary_info_new_from_message (summary, message) ;
305
306         /* Copy flags 'n' tags */
307         mi->info.flags = camel_message_info_flags(info) ;
308
309         flag = camel_message_info_user_flags(info) ;
310         while (flag) {
311                 camel_message_info_set_user_flag((CamelMessageInfo *)mi, flag->name, TRUE);
312                 flag = flag->next;
313         }
314         tag = camel_message_info_user_tags(info);
315         while (tag) {
316                 camel_message_info_set_user_tag((CamelMessageInfo *)mi, tag->name, tag->value);
317                 tag = tag->next;
318         }
319
320         mi->info.size = camel_message_info_size(info);
321         mi->info.uid = g_strdup (uid);
322
323         camel_folder_summary_add (summary, (CamelMessageInfo *)mi);
324
325 }
326
327 void
328 camel_gw_summary_add_offline_uncached (CamelFolderSummary *summary, const char *uid, const CamelMessageInfo *info)
329 {
330         CamelGroupwiseMessageInfo *mi;
331
332         mi = camel_message_info_clone(info);
333         mi->info.uid = g_strdup(uid);
334         camel_folder_summary_add (summary, (CamelMessageInfo *)mi);
335 }
336
337 void
338 groupwise_summary_clear (CamelFolderSummary *summary, gboolean uncache)
339 {
340         CamelFolderChangeInfo *changes;
341         CamelMessageInfo *info;
342         int i, count;
343         const char *uid;
344
345         changes = camel_folder_change_info_new ();
346         count = camel_folder_summary_count (summary);
347         for (i = 0; i < count; i++) {
348                 if (!(info = camel_folder_summary_index (summary, i)))
349                         continue;
350                 
351                 uid = camel_message_info_uid (info);
352                 camel_folder_change_info_remove_uid (changes, uid);
353                 camel_folder_summary_remove_uid (summary, uid);
354                 camel_message_info_free(info);
355         }
356
357         camel_folder_summary_clear (summary);
358         camel_folder_summary_save (summary);
359
360         if (uncache)
361                 camel_data_cache_clear (((CamelGroupwiseFolder *) summary->folder)->cache, "cache", NULL);
362
363         if (camel_folder_change_info_changed (changes))
364                 camel_object_trigger_event (summary->folder, "folder_changed", changes);
365         camel_folder_change_info_free (changes);
366 }
367