summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/mh/mailmh.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/mh/mailmh.c') (more/less context) (ignore whitespace changes)
-rw-r--r--kmicromail/libetpan/mh/mailmh.c965
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/*
39perfs :
40
41/net/home/dinh/Mail/inbox/sylpheed 686
42
432724 /net/home/dinh/Mail/inbox/sylpheed
44
45bart:~/LibEtPan/libetpan/tests> time ./mhtest >/dev/null
46
47real 0m0.385s
48user 0m0.270s
49sys 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
65struct 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
82void mailmh_free(struct mailmh * f)
83{
84 mailmh_folder_free(f->mh_main);
85 free(f);
86}
87
88
89
90struct 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
107void mailmh_msg_info_free(struct mailmh_msg_info * msg_info)
108{
109 free(msg_info);
110}
111
112struct 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
192void 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
225struct 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
285int 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
482int 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
531int 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
556int 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
603static 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
652int 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
678int 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
705int 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
726int 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
828int 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
855int 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
909int 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
954unsigned 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}