summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c
Unidiff
Diffstat (limited to 'libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c
new file mode 100644
index 0000000..d2c30cc
--- a/dev/null
+++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c
@@ -0,0 +1,334 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "maildirdriver_message.h"
37
38#include "mailmessage_tools.h"
39#include "maildirdriver.h"
40#include "maildir.h"
41#include "generic_cache.h"
42#include "mail_cache_db.h"
43#include "maildirdriver_tools.h"
44
45#include <unistd.h>
46#include <sys/mman.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <fcntl.h>
50#include <string.h>
51#include <stdlib.h>
52
53static int get_flags(mailmessage * msg_info,
54 struct mail_flags ** result);
55
56static int prefetch(mailmessage * msg_info);
57
58static void prefetch_free(struct generic_message_t * msg);
59
60static int initialize(mailmessage * msg_info);
61
62static void check(mailmessage * msg_info);
63
64static mailmessage_driver local_maildir_cached_message_driver = {
65 .msg_name = "maildir-cached",
66
67 .msg_initialize = initialize,
68 .msg_uninitialize = mailmessage_generic_uninitialize,
69
70 .msg_flush = mailmessage_generic_flush,
71 .msg_check = check,
72
73 .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
74
75 .msg_fetch = mailmessage_generic_fetch,
76 .msg_fetch_header = mailmessage_generic_fetch_header,
77 .msg_fetch_body = mailmessage_generic_fetch_header,
78 .msg_fetch_size = NULL,
79 .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
80 .msg_fetch_section = mailmessage_generic_fetch_section,
81 .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
82 .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
83 .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
84 .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
85
86 .msg_get_flags = get_flags,
87};
88
89mailmessage_driver * maildir_cached_message_driver =
90&local_maildir_cached_message_driver;
91
92struct maildir_msg_data {
93 int fd;
94};
95
96#if 0
97static inline struct maildir_cached_session_state_data *
98get_cached_session_data(mailmessage * msg)
99{
100 return msg->session->data;
101}
102
103static inline mailsession * cached_session_get_ancestor(mailsession * session)
104{
105 return get_data(session)->session;
106}
107
108static inline struct maildir_session_state_data *
109cached_session_get_ancestor_data(mailsession * session)
110{
111 return get_ancestor(session)->data;
112}
113
114static struct maildir * get_maildir_session(mailmessage * msg)
115{
116 return cached_session_get_ancestor_data(msg->session)->session;
117}
118#endif
119static inline struct maildir_cached_session_state_data *
120get_cached_session_data(mailmessage * msg)
121{
122 return msg->msg_session->sess_data;
123}
124
125static inline struct maildir_cached_session_state_data *
126cached_session_get_data(mailsession * s)
127{
128 return s->sess_data;
129}
130
131static inline mailsession * cached_session_get_ancestor(mailsession * s)
132{
133 return cached_session_get_data(s)->md_ancestor;
134}
135
136static inline struct maildir_session_state_data *
137cached_session_get_ancestor_data(mailsession * s)
138{
139 return cached_session_get_ancestor(s)->sess_data;
140}
141
142static inline struct maildir_session_state_data *
143get_session_ancestor_data(mailmessage * msg)
144{
145 return cached_session_get_ancestor_data(msg->msg_session);
146}
147
148static inline struct maildir *
149cached_session_get_maildir_session(mailsession * session)
150{
151 return cached_session_get_ancestor_data(session)->md_session;
152}
153
154static inline struct maildir * get_maildir_session(mailmessage * msg)
155{
156 return cached_session_get_maildir_session(msg->msg_session);
157}
158
159static int prefetch(mailmessage * msg_info)
160{
161 struct generic_message_t * msg;
162 int res;
163 struct maildir_msg_data * data;
164 char * filename;
165 int fd;
166 char * mapping;
167 struct maildir * md;
168
169 md = get_maildir_session(msg_info);
170
171 filename = maildir_message_get(md, msg_info->msg_uid);
172 if (filename == NULL) {
173 res = MAIL_ERROR_MEMORY;
174 goto err;
175 }
176
177 fd = open(filename, O_RDONLY);
178 free(filename);
179 if (fd == -1) {
180 res = MAIL_ERROR_FILE;
181 goto err;
182 }
183
184 mapping = mmap(NULL, msg_info->msg_size, PROT_READ, MAP_PRIVATE, fd, 0);
185 if (mapping == MAP_FAILED) {
186 res = MAIL_ERROR_FILE;
187 goto close;
188 }
189
190 data = malloc(sizeof(* data));
191 if (data == NULL) {
192 res = MAIL_ERROR_MEMORY;
193 goto unmap;
194 }
195
196 data->fd = fd;
197
198 msg = msg_info->msg_data;
199
200 msg->msg_data = data;
201 msg->msg_message = mapping;
202 msg->msg_length = msg_info->msg_size;
203
204 return MAIL_NO_ERROR;
205
206 unmap:
207 munmap(mapping, msg_info->msg_size);
208 close:
209 close(fd);
210 err:
211 return res;
212}
213
214static void prefetch_free(struct generic_message_t * msg)
215{
216 if (msg->msg_message != NULL) {
217 struct maildir_msg_data * data;
218
219 munmap(msg->msg_message, msg->msg_length);
220 msg->msg_message = NULL;
221 data = msg->msg_data;
222 close(data->fd);
223 free(data);
224 }
225}
226
227static int initialize(mailmessage * msg_info)
228{
229 struct generic_message_t * msg;
230 int r;
231
232 r = mailmessage_generic_initialize(msg_info);
233 if (r != MAIL_NO_ERROR)
234 return r;
235
236 msg = msg_info->msg_data;
237 msg->msg_prefetch = prefetch;
238 msg->msg_prefetch_free = prefetch_free;
239
240 return MAIL_NO_ERROR;
241}
242
243static void check(mailmessage * msg_info)
244{
245 int r;
246
247 if (msg_info->msg_flags != NULL) {
248 r = mail_flags_store_set(get_session_ancestor_data(msg_info)->md_flags_store, msg_info);
249
250 r = mail_flags_store_set(get_cached_session_data(msg_info)->md_flags_store, msg_info);
251 /* ignore errors */
252 }
253}
254
255#define FLAGS_NAME "flags.db"
256
257static int get_flags(mailmessage * msg_info,
258 struct mail_flags ** result)
259{
260 struct mail_cache_db * cache_db_flags;
261 chashdatum key;
262 chashdatum value;
263 struct maildir * md;
264 struct mail_flags * flags;
265 struct maildir_cached_session_state_data * data;
266 struct maildir_msg * md_msg;
267 int r;
268 uint32_t driver_flags;
269 char filename_flags[PATH_MAX];
270 char keyname[PATH_MAX];
271 MMAPString * mmapstr;
272
273 if (msg_info->msg_flags != NULL) {
274 * result = msg_info->msg_flags;
275 return MAIL_NO_ERROR;
276 }
277
278 data = get_cached_session_data(msg_info);
279 flags = mail_flags_store_get(data->md_flags_store,
280 msg_info->msg_index);
281 if (flags != NULL) {
282 msg_info->msg_flags = flags;
283 * result = msg_info->msg_flags;
284 return MAIL_NO_ERROR;
285 }
286
287 snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s",
288 data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb,
289 MAIL_DIR_SEPARATOR, FLAGS_NAME);
290
291 r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
292 if (r < 0)
293 return MAIL_ERROR_FILE;
294
295 snprintf(keyname, PATH_MAX, "%s-flags", msg_info->msg_uid);
296
297 mmapstr = mmap_string_new("");
298 if (mmapstr == NULL) {
299 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
300 return MAIL_ERROR_MEMORY;
301 }
302
303 r = generic_cache_flags_read(cache_db_flags, mmapstr, keyname, &flags);
304 mmap_string_free(mmapstr);
305
306 mail_cache_db_close_unlock(filename_flags, cache_db_flags);
307
308 if (r != MAIL_NO_ERROR) {
309 flags = mail_flags_new_empty();
310 if (flags == NULL)
311 return MAIL_ERROR_MEMORY;
312 }
313
314 md = get_maildir_session(msg_info);
315 if (md == NULL)
316 return MAIL_ERROR_BAD_STATE;
317
318 key.data = msg_info->msg_uid;
319 key.len = strlen(msg_info->msg_uid);
320 r = chash_get(md->mdir_msg_hash, &key, &value);
321 if (r < 0)
322 return MAIL_ERROR_MSG_NOT_FOUND;
323
324 md_msg = value.data;
325
326 driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags);
327
328 flags->fl_flags = driver_flags;
329 msg_info->msg_flags = flags;
330
331 * result = msg_info->msg_flags;
332
333 return MAIL_NO_ERROR;
334}