summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/mh/mailmh.c
authorzautrix <zautrix>2005-03-18 20:17:03 (UTC)
committer zautrix <zautrix>2005-03-18 20:17:03 (UTC)
commit9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf (patch) (unidiff)
tree2528e6cc740225ca0f47d5ac8ff70f7d3bb10621 /libetpan/src/low-level/mh/mailmh.c
parent9319998f20f03dcc217fbb39656755dc65226276 (diff)
downloadkdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.zip
kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.gz
kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.bz2
Initial revision
Diffstat (limited to 'libetpan/src/low-level/mh/mailmh.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/mh/mailmh.c989
1 files changed, 989 insertions, 0 deletions
diff --git a/libetpan/src/low-level/mh/mailmh.c b/libetpan/src/low-level/mh/mailmh.c
new file mode 100644
index 0000000..42cab9d
--- a/dev/null
+++ b/libetpan/src/low-level/mh/mailmh.c
@@ -0,0 +1,989 @@
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 "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 int got_file;
611 int r;
612
613 len = strlen(folder->fl_filename) + 20;
614 new_filename = malloc(len);
615 if (new_filename == NULL)
616 return MAILMH_ERROR_MEMORY;
617
618 max = folder->fl_max_index + 1;
619
620 got_file = 0;
621 k = 0;
622 while (k < MAX_TRY_ALLOC) {
623 snprintf(new_filename, len, "%s%c%lu", folder->fl_filename,
624 MAIL_DIR_SEPARATOR, (unsigned long) (max + k));
625
626 if (link(filename, new_filename) == 0) {
627 unlink(filename);
628 }
629 else if (errno == EXDEV) {
630 free(filename);
631 return MAILMH_ERROR_FOLDER;
632 }
633 else if (errno == EPERM) {
634 rename(filename, new_filename);
635 got_file = 1;
636 }
637
638 if (got_file) {
639 free(new_filename);
640
641 if (k > MAX_TRY_ALLOC / 2) {
642 r = mailmh_folder_update(folder);
643 /* ignore errors */
644 }
645
646 * result = max + k;
647
648 folder->fl_max_index = max + k;
649
650 return MAILMH_NO_ERROR;
651 }
652 k ++;
653 }
654
655 free(new_filename);
656
657 return MAILMH_ERROR_FOLDER;
658}
659
660int mailmh_folder_get_message_filename(struct mailmh_folder * folder,
661 uint32_t index, char ** result)
662{
663 char * filename;
664 int len;
665
666#if 0
667 r = mailmh_folder_update(folder);
668 if (r != MAILMH_NO_ERROR)
669 return r;
670#endif
671
672 len = strlen(folder->fl_filename) + 20;
673 filename = malloc(len);
674 if (filename == NULL)
675 return MAILMH_ERROR_MEMORY;
676
677 snprintf(filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR,
678 (unsigned long) index);
679
680 * result = filename;
681
682 return MAILMH_NO_ERROR;;
683}
684
685
686int mailmh_folder_get_message_fd(struct mailmh_folder * folder,
687 uint32_t index, int flags, int * result)
688{
689 char * filename;
690 int fd;
691 int r;
692
693#if 0
694 r = mailmh_folder_update(folder);
695 if (r != MAILMH_NO_ERROR)
696 return r;
697#endif
698
699 r = mailmh_folder_get_message_filename(folder, index, &filename);
700 if (r != MAILMH_NO_ERROR)
701 return r;
702
703 fd = open(filename, flags);
704 free(filename);
705 if (fd == -1)
706 return MAILMH_ERROR_MSG_NOT_FOUND;
707
708 * result = fd;
709
710 return MAILMH_NO_ERROR;
711}
712
713int mailmh_folder_get_message_size(struct mailmh_folder * folder,
714 uint32_t index, size_t * result)
715{
716 int r;
717 char * filename;
718 struct stat buf;
719
720 r = mailmh_folder_get_message_filename(folder, index, &filename);
721 if (r != MAILMH_NO_ERROR)
722 return r;
723
724 r = stat(filename, &buf);
725 free(filename);
726 if (r < 0)
727 return MAILMH_ERROR_FILE;
728
729 * result = buf.st_size;
730
731 return MAILMH_NO_ERROR;
732}
733
734int mailmh_folder_add_message_uid(struct mailmh_folder * folder,
735 const char * message, size_t size,
736 uint32_t * pindex)
737{
738 char * tmpname;
739 int fd;
740 size_t namesize;
741 size_t left;
742 ssize_t res;
743 struct mailmh_msg_info * msg_info;
744 uint32_t index;
745 int error;
746 int r;
747 unsigned int array_index;
748 struct stat buf;
749 chashdatum key;
750 chashdatum data;
751
752#if 0
753 r = mailmh_folder_update(folder);
754 if (r != MAILMH_NO_ERROR) {
755 error = r;
756 goto err;
757 }
758#endif
759
760 namesize = strlen(folder->fl_filename) + 20;
761 tmpname = malloc(namesize);
762 snprintf(tmpname, namesize, "%s%ctmpXXXXXX",
763 folder->fl_filename, MAIL_DIR_SEPARATOR);
764 fd = mkstemp(tmpname);
765 if (fd < 0) {
766 error = MAILMH_ERROR_FILE;
767 goto free;
768 }
769
770 left = size;
771 while (left > 0) {
772 res = write(fd, message, left);
773 if (res == -1) {
774 close(fd);
775 error = MAILMH_ERROR_FILE;
776 goto free;
777 }
778
779 left -= res;
780 }
781 close(fd);
782
783 r = stat(tmpname, &buf);
784 if (r < 0) {
785 error = MAILMH_ERROR_FILE;
786 goto free;
787 }
788
789 r = mailmh_folder_alloc_msg(folder, tmpname, &index);
790 if (r != MAILMH_NO_ERROR) {
791 unlink(tmpname);
792 error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG;
793 goto free;
794 }
795 free(tmpname);
796
797 msg_info = mailmh_msg_info_new(index, size, buf.st_mtime);
798 if (msg_info == NULL) {
799 mailmh_folder_remove_message(folder, index);
800 error = MAILMH_ERROR_MEMORY;
801 goto err;
802 }
803
804 r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
805 if (r < 0) {
806 mailmh_folder_remove_message(folder, index);
807 mailmh_msg_info_free(msg_info);
808 error = MAILMH_ERROR_MEMORY;
809 goto err;
810 }
811 msg_info->msg_array_index = array_index;
812
813#if 0
814 r = cinthash_add(folder->fl_msgs_hash, index, msg_info);
815#endif
816 key.data = &index;
817 key.len = sizeof(index);
818 data.data = msg_info;
819 data.len = 0;
820
821 if (pindex != NULL)
822 * pindex = index;
823
824 r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
825 if (r < 0) {
826 carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
827 mailmh_msg_info_free(msg_info);
828 error = MAILMH_ERROR_MEMORY;
829 goto err;
830 }
831
832 return MAILMH_NO_ERROR;
833
834 free:
835 free(tmpname);
836 err:
837 return error;
838}
839
840int mailmh_folder_add_message(struct mailmh_folder * folder,
841 const char * message, size_t size)
842{
843 return mailmh_folder_add_message_uid(folder, message, size, NULL);
844}
845
846int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder,
847 int fd, uint32_t * pindex)
848{
849 char * message;
850 struct stat buf;
851 int r;
852
853#if 0
854 r = mailmh_folder_update(folder);
855 if (r != MAILMH_NO_ERROR)
856 return r;
857#endif
858
859 if (fstat(fd, &buf) == -1)
860 return MAILMH_ERROR_FILE;
861
862 message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
863 if (message == MAP_FAILED)
864 return MAILMH_ERROR_FILE;
865
866 r = mailmh_folder_add_message_uid(folder, message, buf.st_size, pindex);
867
868 munmap(message, buf.st_size);
869
870 return r;
871}
872
873int mailmh_folder_add_message_file(struct mailmh_folder * folder,
874 int fd)
875{
876 return mailmh_folder_add_message_file_uid(folder, fd, NULL);
877}
878
879int mailmh_folder_remove_message(struct mailmh_folder * folder,
880 uint32_t index)
881{
882 char * filename;
883 struct mailmh_msg_info * msg_info;
884 int res;
885 int r;
886 chashdatum key;
887 chashdatum data;
888
889#if 0
890 r = mailmh_folder_update(folder);
891 if (r != MAILMH_NO_ERROR) {
892 res = r;
893 goto err;
894 }
895#endif
896
897 r = mailmh_folder_get_message_filename(folder, index, &filename);
898 if (filename == NULL) {
899 res = r;
900 goto err;
901 }
902
903 if (unlink(filename) == -1) {
904 res = MAILMH_ERROR_FILE;
905 goto free;
906 }
907
908 key.data = &index;
909 key.len = sizeof(index);
910 r = chash_get(folder->fl_msgs_hash, &key, &data);
911#if 0
912 msg_info = cinthash_find(folder->fl_msgs_hash, index);
913#endif
914 if (r == 0) {
915 msg_info = data.data;
916
917 carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
918#if 0
919 cinthash_remove(folder->fl_msgs_hash, index);
920#endif
921 chash_delete(folder->fl_msgs_hash, &key, NULL);
922 }
923
924 return MAILMH_NO_ERROR;
925
926 free:
927 free(filename);
928 err:
929 return res;
930}
931
932
933int mailmh_folder_move_message(struct mailmh_folder * dest_folder,
934 struct mailmh_folder * src_folder,
935 uint32_t index)
936{
937 int fd;
938 char * filename;
939 int r;
940
941#if 0
942 r = mailmh_folder_update(dest_folder);
943 if (r != MAILMH_NO_ERROR)
944 return r;
945 r = mailmh_folder_update(src_folder);
946 if (r != MAILMH_NO_ERROR)
947 return r;
948#endif
949
950 /* move on the same filesystem */
951 r = mailmh_folder_get_message_filename(src_folder, index, &filename);
952 if (r != MAILMH_NO_ERROR)
953 return r;
954
955 r = mailmh_folder_alloc_msg(dest_folder, filename, &index);
956 free(filename);
957 if (r == MAILMH_NO_ERROR)
958 return MAILMH_NO_ERROR;
959
960 /* move on the different filesystems */
961 r = mailmh_folder_get_message_fd(src_folder, index, O_RDONLY, &fd);
962 if (r != MAILMH_NO_ERROR)
963 return r;
964
965 r = mailmh_folder_add_message_file(dest_folder, fd);
966 if (r != MAILMH_NO_ERROR) {
967 close(fd);
968 return r;
969 }
970
971 close(fd);
972
973 r = mailmh_folder_remove_message(src_folder, index);
974
975 return MAILMH_NO_ERROR;
976}
977
978unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder)
979{
980 unsigned int i;
981 unsigned int count;
982
983 count = 0;
984 for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++)
985 if (carray_get(folder->fl_msgs_tab, i) != NULL)
986 count ++;
987
988 return count;
989}