Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / providers / imapp / camel-imapp-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 /* 
5  * Authors: Michael Zucchi <notzed@ximian.com>
6  *
7  * Copyright (C) 2002 Ximian, Inc. (www.ximian.com)
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 Lesser 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 Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21  * USA
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <libedataserver/md5-utils.h>
33 #include <libedataserver/e-data-server-util.h>
34
35 #include "camel-data-cache.h"
36 #include "camel-exception.h"
37 #include "camel-file-utils.h"
38 #include "camel-mime-message.h"
39 #include "camel-operation.h"
40 #include "camel-session.h"
41 #include "camel-stream-filter.h"
42 #include "camel-stream-mem.h"
43
44 #include "camel-imapp-exception.h"
45 #include "camel-imapp-folder.h"
46 #include "camel-imapp-store.h"
47 #include "camel-imapp-summary.h"
48
49 #define d(x)
50
51 #define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o)))
52 static CamelFolderClass *parent_class;
53
54 static void imap_finalize (CamelObject *object);
55 static void imap_refresh_info (CamelFolder *folder, CamelException *ex);
56 static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex);
57 static CamelMimeMessage *imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex);
58
59 static void
60 imap_folder_class_init (CamelIMAPPFolderClass *camel_imapp_folder_class)
61 {
62         CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_imapp_folder_class);
63         
64         parent_class = CAMEL_FOLDER_CLASS(camel_folder_get_type());
65         
66         /* virtual method overload */
67         camel_folder_class->refresh_info = imap_refresh_info;
68         camel_folder_class->sync = imap_sync;
69         
70         camel_folder_class->get_message = imap_get_message;
71 }
72
73 static void
74 imap_folder_init(CamelObject *o, CamelObjectClass *klass)
75 {
76         CamelFolder *folder = (CamelFolder *)o;
77         CamelIMAPPFolder *ifolder = (CamelIMAPPFolder *)o;
78
79         folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY |
80                                  CAMEL_FOLDER_HAS_SEARCH_CAPABILITY);
81         
82         folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
83                 CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT |
84                 CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_USER;
85
86         /* FIXME: this is just a skeleton */
87
88         ifolder->changes = camel_folder_change_info_new();
89 }
90
91 CamelType
92 camel_imapp_folder_get_type (void)
93 {
94         static CamelType camel_imapp_folder_type = CAMEL_INVALID_TYPE;
95         
96         if (!camel_imapp_folder_type) {
97                 camel_imapp_folder_type = camel_type_register (CAMEL_FOLDER_TYPE, "CamelIMAPPFolder",
98                                                               sizeof (CamelIMAPPFolder),
99                                                               sizeof (CamelIMAPPFolderClass),
100                                                               (CamelObjectClassInitFunc) imap_folder_class_init,
101                                                               NULL,
102                                                               imap_folder_init,
103                                                               (CamelObjectFinalizeFunc) imap_finalize);
104         }
105         
106         return camel_imapp_folder_type;
107 }
108
109 void
110 imap_finalize (CamelObject *object)
111 {
112         CamelIMAPPFolder *folder = (CamelIMAPPFolder *)object;
113
114         camel_folder_change_info_free(folder->changes);
115 }
116
117 CamelFolder *
118 camel_imapp_folder_new(CamelStore *store, const char *path)
119 {
120         CamelFolder *folder;
121         char *root;
122
123         d(printf("opening imap folder '%s'\n", path));
124         
125         folder = CAMEL_FOLDER (camel_object_new (CAMEL_IMAPP_FOLDER_TYPE));
126         camel_folder_construct(folder, store, path, path);
127
128         ((CamelIMAPPFolder *)folder)->raw_name = g_strdup(path);
129
130         folder->summary = camel_imapp_summary_new();
131
132         root = camel_session_get_storage_path(((CamelService *)store)->session, (CamelService *)store, NULL);
133         if (root) {
134                 char *base = g_build_filename(root, path, NULL);
135                 char *file = g_build_filename(base, ".ev-summary", NULL);
136
137                 g_mkdir_with_parents (base, 0777);
138                 g_free(base);
139
140                 camel_folder_summary_set_filename(folder->summary, file);
141                 printf("loading summary from '%s' (root=%s)\n", file, root);
142                 g_free(file);
143                 camel_folder_summary_load(folder->summary);
144                 g_free(root);
145         }
146
147         return folder;
148 }
149
150 #if 0
151 /* experimental interfaces */
152 void
153 camel_imapp_folder_open(CamelIMAPPFolder *folder, CamelException *ex)
154 {
155         /* */
156 }
157
158 void
159 camel_imapp_folder_delete(CamelIMAPPFolder *folder, CamelException *ex)
160 {
161 }
162
163 void
164 camel_imapp_folder_rename(CamelIMAPPFolder *folder, const char *new, CamelException *ex)
165 {
166 }
167
168 void
169 camel_imapp_folder_close(CamelIMAPPFolder *folder, CamelException *ex)
170 {
171 }
172 #endif
173
174 static void 
175 imap_refresh_info (CamelFolder *folder, CamelException *ex)
176 {
177         printf("imapp refresh info?\n");
178 }
179
180 static void
181 imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
182 {
183         camel_imapp_driver_sync(((CamelIMAPPStore *)(folder->parent_store))->driver, expunge, (CamelIMAPPFolder *) folder);
184 }
185
186 static CamelMimeMessage *
187 imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
188 {
189         CamelMimeMessage * volatile msg = NULL;
190         CamelStream * volatile stream = NULL;
191
192         printf("get message '%s'\n", uid);
193
194         CAMEL_TRY {
195                 /* simple implementation, just get whole message in 1 go */
196                 stream = camel_imapp_driver_fetch(((CamelIMAPPStore *)(folder->parent_store))->driver, (CamelIMAPPFolder *)folder, uid, "");
197                 camel_stream_reset(stream);
198                 msg = camel_mime_message_new();
199                 if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) {
200                         /* do we care? */
201                 }
202         } CAMEL_CATCH(e) {
203                 if (msg)
204                         camel_object_unref(msg);
205                 msg = NULL;
206                 camel_exception_xfer(ex, e);
207         } CAMEL_DONE;
208
209         if (stream)
210                 camel_object_unref(stream);
211
212         return msg;
213 }
214
215
216 /* Algorithm for selecting a folder:
217
218   - If uidvalidity == old uidvalidity
219     and exsists == old exists
220     and recent == old recent
221     and unseen == old unseen
222     Assume our summary is correct
223   for each summary item
224     mark the summary item as 'old/not updated'
225   rof
226   fetch flags from 1:*
227   for each fetch response
228     info = summary[index]
229     if info.uid != uid
230       info = summary_by_uid[uid]
231     fi
232     if info == NULL
233       create new info @ index
234     fi
235     if got.flags
236       update flags
237     fi
238     if got.header
239       update based on header
240       mark as retrieved
241     else if got.body
242       update based on imap body
243       mark as retrieved
244     fi
245
246   Async fetch response:
247     info = summary[index]
248     if info == null
249        if uid == null
250           force resync/select?
251        info = empty @ index
252     else if uid && info.uid != uid
253        force a resync?
254        return
255     fi
256
257     if got.flags {
258       info.flags = flags
259     }
260     if got.header {
261       info.init(header)
262       info.empty = false
263     }
264
265 info.state - 2 bit field in flags
266    0 = empty, nothing set
267    1 = uid & flags set
268    2 = update required
269    3 = up to date
270 */
271