Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-digest-folder.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright 2001-2003 Ximian, Inc. (www.ximian.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "camel-digest-folder.h"
28 #include "camel-digest-summary.h"
29 #include "camel-exception.h"
30 #include "camel-folder-search.h"
31 #include "camel-mime-message.h"
32 #include "camel-multipart.h"
33
34 #define d(x)
35
36 #define _PRIVATE(o) (((CamelDigestFolder *)(o))->priv)
37
38 struct _CamelDigestFolderPrivate {
39         CamelMimeMessage *message;
40         CamelFolderSearch *search;
41         GMutex *search_lock;
42 };
43
44 #define CAMEL_DIGEST_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelDigestFolder *)f)->priv->l))
45 #define CAMEL_DIGEST_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelDigestFolder *)f)->priv->l))
46
47 static CamelFolderClass *parent_class = NULL;
48
49 static void digest_refresh_info (CamelFolder *folder, CamelException *ex);
50 static void digest_sync (CamelFolder *folder, gboolean expunge, CamelException *ex);
51 static const char *digest_get_full_name (CamelFolder *folder);
52 static void digest_expunge (CamelFolder *folder, CamelException *ex);
53
54 /* message manipulation */
55 static CamelMimeMessage *digest_get_message (CamelFolder *folder, const gchar *uid,
56                                              CamelException *ex);
57 static void digest_append_message (CamelFolder *folder, CamelMimeMessage *message,
58                                    const CamelMessageInfo *info, char **appended_uid, CamelException *ex);
59 static void digest_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
60                                          CamelFolder *dest, GPtrArray **transferred_uids,
61                                          gboolean delete_originals, CamelException *ex);
62
63 static GPtrArray *digest_search_by_expression (CamelFolder *folder, const char *expression,
64                                                CamelException *ex);
65
66 static GPtrArray *digest_search_by_uids (CamelFolder *folder, const char *expression,
67                                          GPtrArray *uids, CamelException *ex);
68
69 static void digest_search_free (CamelFolder *folder, GPtrArray *result);
70
71 static void
72 camel_digest_folder_class_init (CamelDigestFolderClass *camel_digest_folder_class)
73 {
74         CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_digest_folder_class);
75         
76         parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_folder_get_type ()));
77         
78         /* virtual method definition */
79         
80         /* virtual method overload */
81         camel_folder_class->refresh_info = digest_refresh_info;
82         camel_folder_class->sync = digest_sync;
83         camel_folder_class->expunge = digest_expunge;
84         camel_folder_class->get_full_name = digest_get_full_name;
85         
86         camel_folder_class->get_message = digest_get_message;
87         camel_folder_class->append_message = digest_append_message;
88         camel_folder_class->transfer_messages_to = digest_transfer_messages_to;
89         
90         camel_folder_class->search_by_expression = digest_search_by_expression;
91         camel_folder_class->search_by_uids = digest_search_by_uids;
92         camel_folder_class->search_free = digest_search_free;
93 }
94
95 static void
96 camel_digest_folder_init (gpointer object, gpointer klass)
97 {
98         CamelDigestFolder *digest_folder = CAMEL_DIGEST_FOLDER (object);
99         CamelFolder *folder = CAMEL_FOLDER (object);
100         
101         folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY | CAMEL_FOLDER_HAS_SEARCH_CAPABILITY;
102         
103         folder->summary = camel_digest_summary_new ();
104         
105         digest_folder->priv = g_new (struct _CamelDigestFolderPrivate, 1);
106         digest_folder->priv->message = NULL;
107         digest_folder->priv->search = NULL;
108         digest_folder->priv->search_lock = g_mutex_new ();
109 }
110
111 static void
112 digest_finalize (CamelObject *object)
113 {
114         CamelDigestFolder *digest_folder = CAMEL_DIGEST_FOLDER (object);
115         CamelFolder *folder = CAMEL_FOLDER (object);
116         
117         if (folder->summary) {
118                 camel_object_unref (folder->summary);
119                 folder->summary = NULL;
120         }
121         
122         camel_object_unref (digest_folder->priv->message);
123         
124         if (digest_folder->priv->search)
125                 camel_object_unref (digest_folder->priv->search);
126         
127         g_mutex_free (digest_folder->priv->search_lock);
128         
129         g_free (digest_folder->priv);
130 }
131
132 CamelType
133 camel_digest_folder_get_type (void)
134 {
135         static CamelType type = CAMEL_INVALID_TYPE;
136         
137         if (type == CAMEL_INVALID_TYPE) {
138                 type = camel_type_register (CAMEL_FOLDER_TYPE,
139                                             "CamelDigestFolder",
140                                             sizeof (CamelDigestFolder),
141                                             sizeof (CamelDigestFolderClass),
142                                             (CamelObjectClassInitFunc) camel_digest_folder_class_init,
143                                             NULL,
144                                             (CamelObjectInitFunc) camel_digest_folder_init,
145                                             (CamelObjectFinalizeFunc) digest_finalize);
146         }
147         
148         return type;
149 }
150
151 static gboolean
152 multipart_contains_message_parts (CamelMultipart *multipart)
153 {
154         gboolean has_message_parts = FALSE;
155         CamelDataWrapper *wrapper;
156         CamelMimePart *part;
157         int i, parts;
158         
159         parts = camel_multipart_get_number (multipart);
160         for (i = 0; i < parts && !has_message_parts; i++) {
161                 part = camel_multipart_get_part (multipart, i);
162                 wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
163                 if (CAMEL_IS_MULTIPART (wrapper)) {
164                         has_message_parts = multipart_contains_message_parts (CAMEL_MULTIPART (wrapper));
165                 } else if (CAMEL_IS_MIME_MESSAGE (wrapper)) {
166                         has_message_parts = TRUE;
167                 }
168         }
169         
170         return has_message_parts;
171 }
172
173 static void
174 digest_add_multipart (CamelFolder *folder, CamelMultipart *multipart, const char *preuid)
175 {
176         CamelDataWrapper *wrapper;
177         CamelMessageInfo *info;
178         CamelMimePart *part;
179         int parts, i;
180         char *uid;
181         
182         parts = camel_multipart_get_number (multipart);
183         for (i = 0; i < parts; i++) {
184                 part = camel_multipart_get_part (multipart, i);
185                 
186                 wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
187                 
188                 if (CAMEL_IS_MULTIPART (wrapper)) {
189                         uid = g_strdup_printf ("%s%d.", preuid, i);
190                         digest_add_multipart (folder, CAMEL_MULTIPART (wrapper), uid);
191                         g_free (uid);
192                         continue;
193                 } else if (!CAMEL_IS_MIME_MESSAGE (wrapper)) {
194                         continue;
195                 }
196                 
197                 info = camel_folder_summary_info_new_from_message (folder->summary, CAMEL_MIME_MESSAGE (wrapper));
198                 g_free(info->uid);
199                 info->uid = g_strdup_printf ("%s%d", preuid, i);
200                 camel_folder_summary_add (folder->summary, info);
201         }
202 }
203
204 static void
205 construct_summary (CamelFolder *folder, CamelMultipart *multipart)
206 {
207         digest_add_multipart (folder, multipart, "");
208 }
209
210 CamelFolder *
211 camel_digest_folder_new (CamelStore *parent_store, CamelMimeMessage *message)
212 {
213         CamelDigestFolder *digest_folder;
214         CamelDataWrapper *wrapper;
215         CamelFolder *folder;
216         
217         wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (message));
218         if (!wrapper || !CAMEL_IS_MULTIPART (wrapper))
219                 return NULL;
220         
221         /* Make sure we have a multipart/digest subpart or at least some message/rfc822 attachments... */
222         if (!camel_content_type_is (CAMEL_DATA_WRAPPER (message)->mime_type, "multipart", "digest")) {
223                 if (!multipart_contains_message_parts (CAMEL_MULTIPART (wrapper)))
224                         return NULL;
225         }
226         
227         folder = CAMEL_FOLDER (camel_object_new (camel_digest_folder_get_type ()));
228         digest_folder = CAMEL_DIGEST_FOLDER (folder);
229         
230         camel_folder_construct (folder, parent_store, "folder_name", "short_name");
231         
232         camel_object_ref (message);
233         digest_folder->priv->message = message;
234         
235         construct_summary (folder, CAMEL_MULTIPART (wrapper));
236         
237         return folder;
238 }
239
240 static void
241 digest_refresh_info (CamelFolder *folder, CamelException *ex)
242 {
243         
244 }
245
246 static void
247 digest_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
248 {
249         /* no-op */
250 }
251
252 static void
253 digest_expunge (CamelFolder *folder, CamelException *ex)
254 {
255         /* no-op */
256 }
257
258 static const char *
259 digest_get_full_name (CamelFolder *folder)
260 {
261         return folder->full_name;
262 }
263
264 static void
265 digest_append_message (CamelFolder *folder, CamelMimeMessage *message,
266                        const CamelMessageInfo *info, char **appended_uid,
267                        CamelException *ex)
268 {
269         /* no-op */
270         if (appended_uid)
271                 *appended_uid = NULL;
272 }
273
274 static void
275 digest_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
276                              CamelFolder *dest, GPtrArray **transferred_uids,
277                              gboolean delete_originals, CamelException *ex)
278 {
279         /* no-op */
280         if (transferred_uids)
281                 *transferred_uids = NULL;
282 }
283
284 static CamelMimeMessage *
285 digest_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
286 {
287         CamelDigestFolder *digest = CAMEL_DIGEST_FOLDER (folder);
288         CamelDataWrapper *wrapper;
289         CamelMimeMessage *message;
290         CamelMimePart *part;
291         char *subuid;
292         int id;
293         
294         part = CAMEL_MIME_PART (digest->priv->message);
295         wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
296         
297         do {
298                 id = strtoul (uid, &subuid, 10);
299                 if (!CAMEL_IS_MULTIPART (wrapper))
300                         return NULL;
301                 
302                 part = camel_multipart_get_part (CAMEL_MULTIPART (wrapper), id);
303                 wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
304                 uid = subuid + 1;
305         } while (*subuid == '.');
306         
307         if (!CAMEL_IS_MIME_MESSAGE (wrapper))
308                 return NULL;
309         
310         message = CAMEL_MIME_MESSAGE (wrapper);
311         camel_object_ref (message);
312         
313         return message;
314 }
315
316 static GPtrArray *
317 digest_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
318 {
319         CamelDigestFolder *df = (CamelDigestFolder *) folder;
320         GPtrArray *matches;
321         
322         CAMEL_DIGEST_FOLDER_LOCK (folder, search_lock);
323         
324         if (!df->priv->search)
325                 df->priv->search = camel_folder_search_new ();
326         
327         camel_folder_search_set_folder (df->priv->search, folder);
328         matches = camel_folder_search_search(df->priv->search, expression, NULL, ex);
329         
330         CAMEL_DIGEST_FOLDER_UNLOCK (folder, search_lock);
331         
332         return matches;
333 }
334
335 static GPtrArray *
336 digest_search_by_uids (CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
337 {
338         CamelDigestFolder *df = (CamelDigestFolder *) folder;
339         GPtrArray *matches;
340
341         if (uids->len == 0)
342                 return g_ptr_array_new();
343
344         CAMEL_DIGEST_FOLDER_LOCK (folder, search_lock);
345         
346         if (!df->priv->search)
347                 df->priv->search = camel_folder_search_new ();
348         
349         camel_folder_search_set_folder (df->priv->search, folder);
350         matches = camel_folder_search_search(df->priv->search, expression, NULL, ex);
351         
352         CAMEL_DIGEST_FOLDER_UNLOCK (folder, search_lock);
353         
354         return matches;
355 }
356
357 static void
358 digest_search_free (CamelFolder *folder, GPtrArray *result)
359 {
360         CamelDigestFolder *digest_folder = CAMEL_DIGEST_FOLDER (folder);
361         
362         CAMEL_DIGEST_FOLDER_LOCK (folder, search_lock);
363         
364         camel_folder_search_free_result (digest_folder->priv->search, result);
365         
366         CAMEL_DIGEST_FOLDER_UNLOCK (folder, search_lock);
367 }