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.c | 989 |
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 | /* | ||
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 | 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 | |||
660 | int 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 | |||
686 | int 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 | |||
713 | int 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 | |||
734 | int 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 | |||
840 | int 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 | |||
846 | int 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 | |||
873 | int 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 | |||
879 | int 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 | |||
933 | int 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 | |||
978 | unsigned 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 | } | ||