Diffstat (limited to 'kmicromail/libetpan/mh/mailmh.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | kmicromail/libetpan/mh/mailmh.c | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/kmicromail/libetpan/mh/mailmh.c b/kmicromail/libetpan/mh/mailmh.c new file mode 100644 index 0000000..d6ff950 --- a/dev/null +++ b/kmicromail/libetpan/mh/mailmh.c | |||
@@ -0,0 +1,965 @@ | |||
1 | /* | ||
2 | * libEtPan! -- a mail stuff library | ||
3 | * | ||
4 | * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 "mailmh.h" | ||
37 | |||
38 | /* | ||
39 | perfs : | ||
40 | |||
41 | /net/home/dinh/Mail/inbox/sylpheed 686 | ||
42 | |||
43 | 2724 /net/home/dinh/Mail/inbox/sylpheed | ||
44 | |||
45 | bart:~/LibEtPan/libetpan/tests> time ./mhtest >/dev/null | ||
46 | |||
47 | real 0m0.385s | ||
48 | user 0m0.270s | ||
49 | sys 0m0.110s | ||
50 | |||
51 | */ | ||
52 | |||
53 | #include <dirent.h> | ||
54 | #include <sys/stat.h> | ||
55 | #include <errno.h> | ||
56 | #include <unistd.h> | ||
57 | #include <sys/mman.h> | ||
58 | #include <fcntl.h> | ||
59 | #include <stdio.h> | ||
60 | #include <stdlib.h> | ||
61 | #include <string.h> | ||
62 | |||
63 | #include "libetpan-config.h" | ||
64 | |||
65 | struct mailmh * mailmh_new(const char * foldername) | ||
66 | { | ||
67 | struct mailmh * f; | ||
68 | |||
69 | f = malloc(sizeof(*f)); | ||
70 | if (f == NULL) | ||
71 | return NULL; | ||
72 | |||
73 | f->mh_main = mailmh_folder_new(NULL, foldername); | ||
74 | if (f->mh_main == NULL) { | ||
75 | free(f); | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | return f; | ||
80 | } | ||
81 | |||
82 | void mailmh_free(struct mailmh * f) | ||
83 | { | ||
84 | mailmh_folder_free(f->mh_main); | ||
85 | free(f); | ||
86 | } | ||
87 | |||
88 | |||
89 | |||
90 | struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size, | ||
91 | time_t mtime) | ||
92 | { | ||
93 | struct mailmh_msg_info * msg_info; | ||
94 | |||
95 | msg_info = malloc(sizeof(* msg_info)); | ||
96 | if (msg_info == NULL) | ||
97 | return NULL; | ||
98 | msg_info->msg_index = index; | ||
99 | msg_info->msg_size = size; | ||
100 | msg_info->msg_mtime = mtime; | ||
101 | |||
102 | msg_info->msg_array_index = 0; | ||
103 | |||
104 | return msg_info; | ||
105 | } | ||
106 | |||
107 | void mailmh_msg_info_free(struct mailmh_msg_info * msg_info) | ||
108 | { | ||
109 | free(msg_info); | ||
110 | } | ||
111 | |||
112 | struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent, | ||
113 | const char * name) | ||
114 | { | ||
115 | char * filename; | ||
116 | char * parent_filename; | ||
117 | |||
118 | struct mailmh_folder * folder; | ||
119 | |||
120 | folder = malloc(sizeof(* folder)); | ||
121 | if (folder == NULL) | ||
122 | goto err; | ||
123 | |||
124 | if (parent == NULL) { | ||
125 | filename = strdup(name); | ||
126 | if (filename == NULL) | ||
127 | goto free_folder; | ||
128 | } | ||
129 | else { | ||
130 | parent_filename = parent->fl_filename; | ||
131 | filename = malloc(strlen(parent_filename) + strlen(name) + 2); | ||
132 | if (filename == NULL) | ||
133 | goto free_folder; | ||
134 | |||
135 | strcpy(filename, parent_filename); | ||
136 | strcat(filename, MAIL_DIR_SEPARATOR_S); | ||
137 | strcat(filename, name); | ||
138 | } | ||
139 | |||
140 | folder->fl_filename = filename; | ||
141 | |||
142 | folder->fl_name = strdup(name); | ||
143 | if (folder->fl_name == NULL) | ||
144 | goto free_filename; | ||
145 | |||
146 | folder->fl_msgs_tab = carray_new(128); | ||
147 | if (folder->fl_msgs_tab == NULL) | ||
148 | goto free_name; | ||
149 | |||
150 | #if 0 | ||
151 | folder->fl_msgs_hash = cinthash_new(128); | ||
152 | if (folder->fl_msgs_hash == NULL) | ||
153 | goto free_msgs_tab; | ||
154 | #endif | ||
155 | folder->fl_msgs_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); | ||
156 | if (folder->fl_msgs_hash == NULL) | ||
157 | goto free_msgs_tab; | ||
158 | |||
159 | folder->fl_subfolders_tab = carray_new(128); | ||
160 | if (folder->fl_subfolders_tab == NULL) | ||
161 | goto free_msgs_hash; | ||
162 | |||
163 | folder->fl_subfolders_hash = chash_new(128, CHASH_COPYNONE); | ||
164 | if (folder->fl_subfolders_hash == NULL) | ||
165 | goto free_subfolders_tab; | ||
166 | |||
167 | folder->fl_mtime = 0; | ||
168 | folder->fl_parent = parent; | ||
169 | folder->fl_max_index = 0; | ||
170 | |||
171 | return folder; | ||
172 | |||
173 | free_subfolders_tab: | ||
174 | carray_free(folder->fl_subfolders_tab); | ||
175 | free_msgs_hash: | ||
176 | #if 0 | ||
177 | cinthash_free(folder->fl_msgs_hash); | ||
178 | #endif | ||
179 | chash_free(folder->fl_msgs_hash); | ||
180 | free_msgs_tab: | ||
181 | carray_free(folder->fl_msgs_tab); | ||
182 | free_name: | ||
183 | free(folder->fl_name); | ||
184 | free_filename: | ||
185 | free(folder->fl_filename); | ||
186 | free_folder: | ||
187 | free(folder); | ||
188 | err: | ||
189 | return NULL; | ||
190 | } | ||
191 | |||
192 | void mailmh_folder_free(struct mailmh_folder * folder) | ||
193 | { | ||
194 | unsigned int i; | ||
195 | |||
196 | for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) { | ||
197 | struct mailmh_folder * subfolder; | ||
198 | |||
199 | subfolder = carray_get(folder->fl_subfolders_tab, i); | ||
200 | if (subfolder != NULL) | ||
201 | mailmh_folder_free(subfolder); | ||
202 | } | ||
203 | carray_free(folder->fl_subfolders_tab); | ||
204 | chash_free(folder->fl_subfolders_hash); | ||
205 | |||
206 | for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { | ||
207 | struct mailmh_msg_info * msg_info; | ||
208 | |||
209 | msg_info = carray_get(folder->fl_msgs_tab, i); | ||
210 | if (msg_info != NULL) | ||
211 | mailmh_msg_info_free(msg_info); | ||
212 | } | ||
213 | carray_free(folder->fl_msgs_tab); | ||
214 | chash_free(folder->fl_msgs_hash); | ||
215 | #if 0 | ||
216 | cinthash_free(folder->fl_msgs_hash); | ||
217 | #endif | ||
218 | |||
219 | free(folder->fl_filename); | ||
220 | free(folder->fl_name); | ||
221 | |||
222 | free(folder); | ||
223 | } | ||
224 | |||
225 | struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root, | ||
226 | const char * filename) | ||
227 | { | ||
228 | int r; | ||
229 | char pathname[PATH_MAX]; | ||
230 | char * p; | ||
231 | chashdatum key; | ||
232 | chashdatum data; | ||
233 | struct mailmh_folder * folder; | ||
234 | char * start; | ||
235 | |||
236 | if (strcmp(root->fl_filename, filename) == 0) | ||
237 | return root; | ||
238 | |||
239 | #if 0 | ||
240 | r = mailmh_folder_update(root); | ||
241 | if (r != MAILMH_NO_ERROR) | ||
242 | return NULL; | ||
243 | #endif | ||
244 | |||
245 | #if 0 | ||
246 | for(i = 0 ; i < root->fl_subfolders_tab->len ; i++) { | ||
247 | struct mailmh_folder * subfolder; | ||
248 | |||
249 | subfolder = carray_get(root->fl_subfolders_tab, i); | ||
250 | if (subfolder != NULL) | ||
251 | if (strncmp(subfolder->fl_filename, filename, | ||
252 | strlen(subfolder->fl_filename)) == 0) | ||
253 | return mailmh_folder_find(subfolder, filename); | ||
254 | } | ||
255 | #endif | ||
256 | strncpy(pathname, filename, PATH_MAX); | ||
257 | pathname[PATH_MAX - 1] = 0; | ||
258 | start = pathname + strlen(root->fl_filename) + 1; | ||
259 | |||
260 | p = strchr(start, MAIL_DIR_SEPARATOR); | ||
261 | if (p != NULL) { | ||
262 | * p = 0; | ||
263 | |||
264 | root = mailmh_folder_find(root, pathname); | ||
265 | if (root != NULL) { | ||
266 | folder = mailmh_folder_find(root, filename); | ||
267 | if (folder == NULL) | ||
268 | return NULL; | ||
269 | return folder; | ||
270 | } | ||
271 | |||
272 | return NULL; | ||
273 | } | ||
274 | else { | ||
275 | key.data = pathname; | ||
276 | key.len = strlen(pathname); | ||
277 | r = chash_get(root->fl_subfolders_hash, &key, &data); | ||
278 | if (r < 0) | ||
279 | return NULL; | ||
280 | |||
281 | return data.data; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | int mailmh_folder_update(struct mailmh_folder * folder) | ||
286 | { | ||
287 | DIR * d; | ||
288 | struct dirent * ent; | ||
289 | struct stat buf; | ||
290 | char * mh_seq; | ||
291 | char filename[PATH_MAX]; | ||
292 | int res; | ||
293 | int r; | ||
294 | uint32_t max_index; | ||
295 | #if 0 | ||
296 | int add_folder; | ||
297 | #endif | ||
298 | unsigned int i; | ||
299 | |||
300 | if (stat(folder->fl_filename, &buf) == -1) { | ||
301 | res = MAILMH_ERROR_FOLDER; | ||
302 | goto err; | ||
303 | } | ||
304 | |||
305 | if (folder->fl_mtime == buf.st_mtime) { | ||
306 | res = MAILMH_NO_ERROR; | ||
307 | goto err; | ||
308 | } | ||
309 | |||
310 | folder->fl_mtime = buf.st_mtime; | ||
311 | |||
312 | d = opendir(folder->fl_filename); | ||
313 | if (d == NULL) { | ||
314 | res = MAILMH_ERROR_FOLDER; | ||
315 | goto err; | ||
316 | } | ||
317 | |||
318 | max_index = 0; | ||
319 | |||
320 | #if 0 | ||
321 | if (folder->fl_subfolders_tab->len == 0) | ||
322 | add_folder = 1; | ||
323 | else | ||
324 | add_folder = 0; | ||
325 | #endif | ||
326 | |||
327 | /* clear the message list */ | ||
328 | |||
329 | for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) { | ||
330 | struct mailmh_msg_info * msg_info; | ||
331 | chashdatum key; | ||
332 | |||
333 | msg_info = carray_get(folder->fl_msgs_tab, i); | ||
334 | if (msg_info == NULL) | ||
335 | continue; | ||
336 | |||
337 | #if 0 | ||
338 | cinthash_remove(folder->fl_msgs_hash, msg_info->msg_index); | ||
339 | #endif | ||
340 | key.data = &msg_info->msg_index; | ||
341 | key.len = sizeof(msg_info->msg_index); | ||
342 | chash_delete(folder->fl_msgs_hash, &key, NULL); | ||
343 | |||
344 | mailmh_msg_info_free(msg_info); | ||
345 | } | ||
346 | |||
347 | carray_set_size(folder->fl_msgs_tab, 0); | ||
348 | |||
349 | do { | ||
350 | uint32_t index; | ||
351 | |||
352 | ent = readdir(d); | ||
353 | |||
354 | if (ent != NULL) { | ||
355 | |||
356 | snprintf(filename, PATH_MAX, | ||
357 | "%s%c%s", folder->fl_filename, MAIL_DIR_SEPARATOR, ent->d_name); | ||
358 | |||
359 | if (stat(filename, &buf) == -1) | ||
360 | continue; | ||
361 | |||
362 | if (S_ISREG(buf.st_mode)) { | ||
363 | index = strtoul(ent->d_name, NULL, 10); | ||
364 | if (index != 0) { | ||
365 | struct mailmh_msg_info * msg_info; | ||
366 | unsigned int array_index; | ||
367 | chashdatum key; | ||
368 | chashdatum data; | ||
369 | |||
370 | msg_info = mailmh_msg_info_new(index, buf.st_size, buf.st_mtime); | ||
371 | if (msg_info == NULL) { | ||
372 | res = MAILMH_ERROR_MEMORY; | ||
373 | goto closedir; | ||
374 | } | ||
375 | |||
376 | r = carray_add(folder->fl_msgs_tab, msg_info, &array_index); | ||
377 | if (r < 0) { | ||
378 | mailmh_msg_info_free(msg_info); | ||
379 | res = MAILMH_ERROR_MEMORY; | ||
380 | goto closedir; | ||
381 | } | ||
382 | msg_info->msg_array_index = array_index; | ||
383 | |||
384 | if (index > max_index) | ||
385 | max_index = index; | ||
386 | |||
387 | #if 0 | ||
388 | r = cinthash_add(folder->fl_msgs_hash, msg_info->msg_index, msg_info); | ||
389 | #endif | ||
390 | key.data = &msg_info->msg_index; | ||
391 | key.len = sizeof(msg_info->msg_index); | ||
392 | data.data = msg_info; | ||
393 | data.len = 0; | ||
394 | |||
395 | r = chash_set(folder->fl_msgs_hash, &key, &data, NULL); | ||
396 | if (r < 0) { | ||
397 | carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); | ||
398 | mailmh_msg_info_free(msg_info); | ||
399 | res = MAILMH_ERROR_MEMORY; | ||
400 | goto closedir; | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | else if (S_ISDIR(buf.st_mode)) { | ||
405 | struct mailmh_folder * subfolder; | ||
406 | unsigned int array_index; | ||
407 | chashdatum key; | ||
408 | chashdatum data; | ||
409 | |||
410 | if (ent->d_name[0] == '.') { | ||
411 | if (ent->d_name[1] == 0) | ||
412 | continue; | ||
413 | if ((ent->d_name[1] == '.') && (ent->d_name[2] == 0)) | ||
414 | continue; | ||
415 | } | ||
416 | |||
417 | key.data = ent->d_name; | ||
418 | key.len = strlen(ent->d_name); | ||
419 | r = chash_get(folder->fl_subfolders_hash, &key, &data); | ||
420 | if (r < 0) { | ||
421 | subfolder = mailmh_folder_new(folder, ent->d_name); | ||
422 | if (subfolder == NULL) { | ||
423 | res = MAILMH_ERROR_MEMORY; | ||
424 | goto closedir; | ||
425 | } | ||
426 | |||
427 | r = carray_add(folder->fl_subfolders_tab, subfolder, &array_index); | ||
428 | if (r < 0) { | ||
429 | mailmh_folder_free(subfolder); | ||
430 | res = MAILMH_ERROR_MEMORY; | ||
431 | goto closedir; | ||
432 | } | ||
433 | subfolder->fl_array_index = array_index; | ||
434 | |||
435 | key.data = subfolder->fl_filename; | ||
436 | key.len = strlen(subfolder->fl_filename); | ||
437 | data.data = subfolder; | ||
438 | data.len = 0; | ||
439 | r = chash_set(folder->fl_subfolders_hash, &key, &data, NULL); | ||
440 | if (r < 0) { | ||
441 | carray_delete_fast(folder->fl_subfolders_tab, subfolder->fl_array_index); | ||
442 | mailmh_folder_free(subfolder); | ||
443 | res = MAILMH_ERROR_MEMORY; | ||
444 | goto closedir; | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | while (ent != NULL); | ||
451 | |||
452 | folder->fl_max_index = max_index; | ||
453 | |||
454 | mh_seq = malloc(strlen(folder->fl_filename) + 2 + sizeof(".mh_sequences")); | ||
455 | if (mh_seq == NULL) { | ||
456 | res = MAILMH_ERROR_MEMORY; | ||
457 | goto closedir; | ||
458 | } | ||
459 | strcpy(mh_seq, folder->fl_filename); | ||
460 | strcat(mh_seq, MAIL_DIR_SEPARATOR_S); | ||
461 | strcat(mh_seq, ".mh_sequences"); | ||
462 | |||
463 | if (stat(mh_seq, &buf) == -1) { | ||
464 | int fd; | ||
465 | |||
466 | fd = creat(mh_seq, S_IRUSR | S_IWUSR); | ||
467 | if (fd != -1) | ||
468 | close(fd); | ||
469 | } | ||
470 | free(mh_seq); | ||
471 | |||
472 | closedir(d); | ||
473 | |||
474 | return MAILMH_NO_ERROR; | ||
475 | |||
476 | closedir: | ||
477 | closedir(d); | ||
478 | err: | ||
479 | return res; | ||
480 | } | ||
481 | |||
482 | int mailmh_folder_add_subfolder(struct mailmh_folder * parent, | ||
483 | const char * name) | ||
484 | { | ||
485 | char * foldername; | ||
486 | int r; | ||
487 | struct mailmh_folder * folder; | ||
488 | unsigned int array_index; | ||
489 | chashdatum key; | ||
490 | chashdatum data; | ||
491 | |||
492 | foldername = malloc(strlen(parent->fl_filename) + strlen(name) + 2); | ||
493 | if (foldername == NULL) | ||
494 | return MAILMH_ERROR_MEMORY; | ||
495 | strcpy(foldername, parent->fl_filename); | ||
496 | strcat(foldername, MAIL_DIR_SEPARATOR_S); | ||
497 | strcat(foldername, name); | ||
498 | |||
499 | r = mkdir(foldername, 0700); | ||
500 | free(foldername); | ||
501 | |||
502 | if (r < 0) | ||
503 | return MAILMH_ERROR_FOLDER; | ||
504 | |||
505 | folder = mailmh_folder_new(parent, name); | ||
506 | if (folder == NULL) | ||
507 | return MAILMH_ERROR_MEMORY; | ||
508 | |||
509 | r = carray_add(parent->fl_subfolders_tab, folder, &array_index); | ||
510 | if (r < 0) { | ||
511 | mailmh_folder_free(folder); | ||
512 | return MAILMH_ERROR_MEMORY; | ||
513 | } | ||
514 | folder->fl_array_index = array_index; | ||
515 | |||
516 | key.data = folder->fl_filename; | ||
517 | key.len = strlen(folder->fl_filename); | ||
518 | data.data = folder; | ||
519 | data.len = 0; | ||
520 | |||
521 | r = chash_set(parent->fl_subfolders_hash, &key, &data, NULL); | ||
522 | if (r < 0) { | ||
523 | carray_delete_fast(folder->fl_subfolders_tab, folder->fl_array_index); | ||
524 | mailmh_folder_free(folder); | ||
525 | return MAILMH_ERROR_MEMORY; | ||
526 | } | ||
527 | |||
528 | return MAILMH_NO_ERROR; | ||
529 | } | ||
530 | |||
531 | int mailmh_folder_remove_subfolder(struct mailmh_folder * folder) | ||
532 | { | ||
533 | struct mailmh_folder * parent; | ||
534 | chashdatum key; | ||
535 | chashdatum data; | ||
536 | int r; | ||
537 | |||
538 | parent = folder->fl_parent; | ||
539 | |||
540 | key.data = folder->fl_filename; | ||
541 | key.len = strlen(folder->fl_filename); | ||
542 | |||
543 | r = chash_get(parent->fl_subfolders_hash, &key, &data); | ||
544 | if (r < 0) | ||
545 | return MAILMH_ERROR_FOLDER; | ||
546 | |||
547 | chash_delete(parent->fl_subfolders_hash, &key, NULL); | ||
548 | carray_delete_fast(parent->fl_subfolders_tab, folder->fl_array_index); | ||
549 | |||
550 | mailmh_folder_free(folder); | ||
551 | |||
552 | return MAILMH_NO_ERROR; | ||
553 | |||
554 | } | ||
555 | |||
556 | int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder, | ||
557 | struct mailmh_folder * dst_folder, | ||
558 | const char * new_name) | ||
559 | { | ||
560 | int r; | ||
561 | struct mailmh_folder * folder; | ||
562 | struct mailmh_folder * parent; | ||
563 | char * new_foldername; | ||
564 | |||
565 | parent = src_folder->fl_parent; | ||
566 | if (parent == NULL) | ||
567 | return MAILMH_ERROR_RENAME; | ||
568 | |||
569 | new_foldername = malloc(strlen(dst_folder->fl_filename) + 2 + strlen(new_name)); | ||
570 | if (new_foldername == NULL) | ||
571 | return MAILMH_ERROR_MEMORY; | ||
572 | |||
573 | strcpy(new_foldername, dst_folder->fl_filename); | ||
574 | strcat(new_foldername, MAIL_DIR_SEPARATOR_S); | ||
575 | strcat(new_foldername, new_name); | ||
576 | |||
577 | r = rename(src_folder->fl_filename, new_foldername); | ||
578 | free(new_foldername); | ||
579 | if (r < 0) | ||
580 | return MAILMH_ERROR_RENAME; | ||
581 | |||
582 | r = mailmh_folder_remove_subfolder(src_folder); | ||
583 | if (r != MAILMH_NO_ERROR) | ||
584 | return r; | ||
585 | |||
586 | folder = mailmh_folder_new(dst_folder, new_name); | ||
587 | if (folder == NULL) | ||
588 | return MAILMH_ERROR_MEMORY; | ||
589 | |||
590 | r = carray_add(parent->fl_subfolders_tab, folder, NULL); | ||
591 | if (r < 0) { | ||
592 | mailmh_folder_free(folder); | ||
593 | return MAILMH_ERROR_MEMORY; | ||
594 | } | ||
595 | |||
596 | return MAILMH_NO_ERROR; | ||
597 | } | ||
598 | |||
599 | #define MAX_TRY_ALLOC 32 | ||
600 | |||
601 | /* initial file MUST be in the same directory */ | ||
602 | |||
603 | static int mailmh_folder_alloc_msg(struct mailmh_folder * folder, | ||
604 | char * filename, uint32_t * result) | ||
605 | { | ||
606 | uint32_t max; | ||
607 | uint32_t k; | ||
608 | char * new_filename; | ||
609 | size_t len; | ||
610 | |||
611 | len = strlen(folder->fl_filename) + 20; | ||
612 | new_filename = malloc(len); | ||
613 | if (new_filename == NULL) | ||
614 | return MAILMH_ERROR_MEMORY; | ||
615 | |||
616 | max = folder->fl_max_index + 1; | ||
617 | |||
618 | k = 0; | ||
619 | while (k < MAX_TRY_ALLOC) { | ||
620 | snprintf(new_filename, len, "%s%c%lu", folder->fl_filename, | ||
621 | MAIL_DIR_SEPARATOR, (unsigned long) (max + k)); | ||
622 | |||
623 | if (link(filename, new_filename) == 0) { | ||
624 | int r; | ||
625 | |||
626 | free(new_filename); | ||
627 | unlink(filename); | ||
628 | |||
629 | if (k > MAX_TRY_ALLOC / 2) { | ||
630 | r = mailmh_folder_update(folder); | ||
631 | /* ignore errors */ | ||
632 | } | ||
633 | |||
634 | * result = max + k; | ||
635 | |||
636 | folder->fl_max_index = max + k; | ||
637 | |||
638 | return MAILMH_NO_ERROR; | ||
639 | } | ||
640 | else if (errno == EXDEV) { | ||
641 | free(filename); | ||
642 | return MAILMH_ERROR_FOLDER; | ||
643 | } | ||
644 | k ++; | ||
645 | } | ||
646 | |||
647 | free(new_filename); | ||
648 | |||
649 | return MAILMH_ERROR_FOLDER; | ||
650 | } | ||
651 | |||
652 | int mailmh_folder_get_message_filename(struct mailmh_folder * folder, | ||
653 | uint32_t index, char ** result) | ||
654 | { | ||
655 | char * filename; | ||
656 | int len; | ||
657 | |||
658 | #if 0 | ||
659 | r = mailmh_folder_update(folder); | ||
660 | if (r != MAILMH_NO_ERROR) | ||
661 | return r; | ||
662 | #endif | ||
663 | |||
664 | len = strlen(folder->fl_filename) + 20; | ||
665 | filename = malloc(len); | ||
666 | if (filename == NULL) | ||
667 | return MAILMH_ERROR_MEMORY; | ||
668 | |||
669 | snprintf(filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR, | ||
670 | (unsigned long) index); | ||
671 | |||
672 | * result = filename; | ||
673 | |||
674 | return MAILMH_NO_ERROR;; | ||
675 | } | ||
676 | |||
677 | |||
678 | int mailmh_folder_get_message_fd(struct mailmh_folder * folder, | ||
679 | uint32_t index, int flags, int * result) | ||
680 | { | ||
681 | char * filename; | ||
682 | int fd; | ||
683 | int r; | ||
684 | |||
685 | #if 0 | ||
686 | r = mailmh_folder_update(folder); | ||
687 | if (r != MAILMH_NO_ERROR) | ||
688 | return r; | ||
689 | #endif | ||
690 | |||
691 | r = mailmh_folder_get_message_filename(folder, index, &filename); | ||
692 | if (r != MAILMH_NO_ERROR) | ||
693 | return r; | ||
694 | |||
695 | fd = open(filename, flags); | ||
696 | free(filename); | ||
697 | if (fd == -1) | ||
698 | return MAILMH_ERROR_MSG_NOT_FOUND; | ||
699 | |||
700 | * result = fd; | ||
701 | |||
702 | return MAILMH_NO_ERROR; | ||
703 | } | ||
704 | |||
705 | int mailmh_folder_get_message_size(struct mailmh_folder * folder, | ||
706 | uint32_t index, size_t * result) | ||
707 | { | ||
708 | int r; | ||
709 | char * filename; | ||
710 | struct stat buf; | ||
711 | |||
712 | r = mailmh_folder_get_message_filename(folder, index, &filename); | ||
713 | if (r != MAILMH_NO_ERROR) | ||
714 | return r; | ||
715 | |||
716 | r = stat(filename, &buf); | ||
717 | free(filename); | ||
718 | if (r < 0) | ||
719 | return MAILMH_ERROR_FILE; | ||
720 | |||
721 | * result = buf.st_size; | ||
722 | |||
723 | return MAILMH_NO_ERROR; | ||
724 | } | ||
725 | |||
726 | int mailmh_folder_add_message(struct mailmh_folder * folder, | ||
727 | const char * message, size_t size) | ||
728 | { | ||
729 | char * tmpname; | ||
730 | int fd; | ||
731 | size_t namesize; | ||
732 | size_t left; | ||
733 | ssize_t res; | ||
734 | struct mailmh_msg_info * msg_info; | ||
735 | uint32_t index; | ||
736 | int error; | ||
737 | int r; | ||
738 | unsigned int array_index; | ||
739 | struct stat buf; | ||
740 | chashdatum key; | ||
741 | chashdatum data; | ||
742 | |||
743 | #if 0 | ||
744 | r = mailmh_folder_update(folder); | ||
745 | if (r != MAILMH_NO_ERROR) { | ||
746 | error = r; | ||
747 | goto err; | ||
748 | } | ||
749 | #endif | ||
750 | |||
751 | namesize = strlen(folder->fl_filename) + 20; | ||
752 | tmpname = malloc(namesize); | ||
753 | snprintf(tmpname, namesize, "%s%ctmpXXXXXX", | ||
754 | folder->fl_filename, MAIL_DIR_SEPARATOR); | ||
755 | fd = mkstemp(tmpname); | ||
756 | if (fd < 0) { | ||
757 | error = MAILMH_ERROR_FILE; | ||
758 | goto free; | ||
759 | } | ||
760 | |||
761 | left = size; | ||
762 | while (left > 0) { | ||
763 | res = write(fd, message, left); | ||
764 | if (res == -1) { | ||
765 | close(fd); | ||
766 | error = MAILMH_ERROR_FILE; | ||
767 | goto free; | ||
768 | } | ||
769 | |||
770 | left -= res; | ||
771 | } | ||
772 | close(fd); | ||
773 | |||
774 | r = stat(tmpname, &buf); | ||
775 | if (r < 0) { | ||
776 | error = MAILMH_ERROR_FILE; | ||
777 | goto free; | ||
778 | } | ||
779 | |||
780 | r = mailmh_folder_alloc_msg(folder, tmpname, &index); | ||
781 | if (r != MAILMH_NO_ERROR) { | ||
782 | unlink(tmpname); | ||
783 | error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG; | ||
784 | goto free; | ||
785 | } | ||
786 | free(tmpname); | ||
787 | |||
788 | msg_info = mailmh_msg_info_new(index, size, buf.st_mtime); | ||
789 | if (msg_info == NULL) { | ||
790 | mailmh_folder_remove_message(folder, index); | ||
791 | error = MAILMH_ERROR_MEMORY; | ||
792 | goto err; | ||
793 | } | ||
794 | |||
795 | r = carray_add(folder->fl_msgs_tab, msg_info, &array_index); | ||
796 | if (r < 0) { | ||
797 | mailmh_folder_remove_message(folder, index); | ||
798 | mailmh_msg_info_free(msg_info); | ||
799 | error = MAILMH_ERROR_MEMORY; | ||
800 | goto err; | ||
801 | } | ||
802 | msg_info->msg_array_index = array_index; | ||
803 | |||
804 | #if 0 | ||
805 | r = cinthash_add(folder->fl_msgs_hash, index, msg_info); | ||
806 | #endif | ||
807 | key.data = &index; | ||
808 | key.len = sizeof(index); | ||
809 | data.data = msg_info; | ||
810 | data.len = 0; | ||
811 | |||
812 | r = chash_set(folder->fl_msgs_hash, &key, &data, NULL); | ||
813 | if (r < 0) { | ||
814 | carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); | ||
815 | mailmh_msg_info_free(msg_info); | ||
816 | error = MAILMH_ERROR_MEMORY; | ||
817 | goto err; | ||
818 | } | ||
819 | |||
820 | return MAILMH_NO_ERROR; | ||
821 | |||
822 | free: | ||
823 | free(tmpname); | ||
824 | err: | ||
825 | return error; | ||
826 | } | ||
827 | |||
828 | int mailmh_folder_add_message_file(struct mailmh_folder * folder, | ||
829 | int fd) | ||
830 | { | ||
831 | char * message; | ||
832 | struct stat buf; | ||
833 | int r; | ||
834 | |||
835 | #if 0 | ||
836 | r = mailmh_folder_update(folder); | ||
837 | if (r != MAILMH_NO_ERROR) | ||
838 | return r; | ||
839 | #endif | ||
840 | |||
841 | if (fstat(fd, &buf) == -1) | ||
842 | return MAILMH_ERROR_FILE; | ||
843 | |||
844 | message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | ||
845 | if (message == MAP_FAILED) | ||
846 | return MAILMH_ERROR_FILE; | ||
847 | |||
848 | r = mailmh_folder_add_message(folder, message, buf.st_size); | ||
849 | |||
850 | munmap(message, buf.st_size); | ||
851 | |||
852 | return r; | ||
853 | } | ||
854 | |||
855 | int mailmh_folder_remove_message(struct mailmh_folder * folder, | ||
856 | uint32_t index) | ||
857 | { | ||
858 | char * filename; | ||
859 | struct mailmh_msg_info * msg_info; | ||
860 | int res; | ||
861 | int r; | ||
862 | chashdatum key; | ||
863 | chashdatum data; | ||
864 | |||
865 | #if 0 | ||
866 | r = mailmh_folder_update(folder); | ||
867 | if (r != MAILMH_NO_ERROR) { | ||
868 | res = r; | ||
869 | goto err; | ||
870 | } | ||
871 | #endif | ||
872 | |||
873 | r = mailmh_folder_get_message_filename(folder, index, &filename); | ||
874 | if (filename == NULL) { | ||
875 | res = r; | ||
876 | goto err; | ||
877 | } | ||
878 | |||
879 | if (unlink(filename) == -1) { | ||
880 | res = MAILMH_ERROR_FILE; | ||
881 | goto free; | ||
882 | } | ||
883 | |||
884 | key.data = &index; | ||
885 | key.len = sizeof(index); | ||
886 | r = chash_get(folder->fl_msgs_hash, &key, &data); | ||
887 | #if 0 | ||
888 | msg_info = cinthash_find(folder->fl_msgs_hash, index); | ||
889 | #endif | ||
890 | if (r == 0) { | ||
891 | msg_info = data.data; | ||
892 | |||
893 | carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); | ||
894 | #if 0 | ||
895 | cinthash_remove(folder->fl_msgs_hash, index); | ||
896 | #endif | ||
897 | chash_delete(folder->fl_msgs_hash, &key, NULL); | ||
898 | } | ||
899 | |||
900 | return MAILMH_NO_ERROR; | ||
901 | |||
902 | free: | ||
903 | free(filename); | ||
904 | err: | ||
905 | return res; | ||
906 | } | ||
907 | |||
908 | |||
909 | int mailmh_folder_move_message(struct mailmh_folder * dest_folder, | ||
910 | struct mailmh_folder * src_folder, | ||
911 | uint32_t index) | ||
912 | { | ||
913 | int fd; | ||
914 | char * filename; | ||
915 | int r; | ||
916 | |||
917 | #if 0 | ||
918 | r = mailmh_folder_update(dest_folder); | ||
919 | if (r != MAILMH_NO_ERROR) | ||
920 | return r; | ||
921 | r = mailmh_folder_update(src_folder); | ||
922 | if (r != MAILMH_NO_ERROR) | ||
923 | return r; | ||
924 | #endif | ||
925 | |||
926 | /* move on the same filesystem */ | ||
927 | r = mailmh_folder_get_message_filename(src_folder, index, &filename); | ||
928 | if (r != MAILMH_NO_ERROR) | ||
929 | return r; | ||
930 | |||
931 | r = mailmh_folder_alloc_msg(dest_folder, filename, &index); | ||
932 | free(filename); | ||
933 | if (r == MAILMH_NO_ERROR) | ||
934 | return MAILMH_NO_ERROR; | ||
935 | |||
936 | /* move on the different filesystems */ | ||
937 | r = mailmh_folder_get_message_fd(src_folder, index, O_RDONLY, &fd); | ||
938 | if (r != MAILMH_NO_ERROR) | ||
939 | return r; | ||
940 | |||
941 | r = mailmh_folder_add_message_file(dest_folder, fd); | ||
942 | if (r != MAILMH_NO_ERROR) { | ||
943 | close(fd); | ||
944 | return r; | ||
945 | } | ||
946 | |||
947 | close(fd); | ||
948 | |||
949 | r = mailmh_folder_remove_message(src_folder, index); | ||
950 | |||
951 | return MAILMH_NO_ERROR; | ||
952 | } | ||
953 | |||
954 | unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder) | ||
955 | { | ||
956 | unsigned int i; | ||
957 | unsigned int count; | ||
958 | |||
959 | count = 0; | ||
960 | for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) | ||
961 | if (carray_get(folder->fl_msgs_tab, i) != NULL) | ||
962 | count ++; | ||
963 | |||
964 | return count; | ||
965 | } | ||