-rw-r--r-- | kmicromail/libetpan/maildir/maildir.c | 25 | ||||
-rw-r--r-- | kmicromail/libetpan/mh/mailmh.c | 12 |
2 files changed, 26 insertions, 11 deletions
diff --git a/kmicromail/libetpan/maildir/maildir.c b/kmicromail/libetpan/maildir/maildir.c index 0e038b1..1ef0b7a 100644 --- a/kmicromail/libetpan/maildir/maildir.c +++ b/kmicromail/libetpan/maildir/maildir.c @@ -1,729 +1,740 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001 - 2003 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildir.h" #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <dirent.h> #include <time.h> #include <sys/stat.h> #include <sys/mman.h> #ifdef LIBETPAN_SYSTEM_BASENAME #include <libgen.h> #endif /* We suppose the maildir mailbox remains on one unique filesystem. */ struct maildir * maildir_new(const char * path) { struct maildir * md; md = malloc(sizeof(* md)); if (md == NULL) goto err; md->mdir_counter = 0; md->mdir_mtime_new = (time_t) -1; md->mdir_mtime_cur = (time_t) -1; md->mdir_pid = getpid(); gethostname(md->mdir_hostname, sizeof(md->mdir_hostname)); strncpy(md->mdir_path, path, sizeof(md->mdir_path)); md->mdir_path[PATH_MAX - 1] = '\0'; md->mdir_msg_list = carray_new(128); if (md->mdir_msg_list == NULL) goto free; md->mdir_msg_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYNONE); if (md->mdir_msg_hash == NULL) goto free_msg_list; return md; free_msg_list: carray_free(md->mdir_msg_list); free: free(md); err: return NULL; } static void maildir_flush(struct maildir * md, int msg_new); void maildir_free(struct maildir * md) { maildir_flush(md, 0); maildir_flush(md, 1); chash_free(md->mdir_msg_hash); carray_free(md->mdir_msg_list); free(md); } #define MAX_TRY_ALLOC 32 static char * maildir_get_new_message_filename(struct maildir * md, char * tmpfile) { char filename[PATH_MAX]; char basename[PATH_MAX]; int k; time_t now; - + struct stat f_stat; now = time(NULL); k = 0; + + fprintf(stderr,"maildir_get_new_message_filename: %s \n", tmpfile); while (k < MAX_TRY_ALLOC) { snprintf(basename, sizeof(basename), "%lu.%u_%u.%s", (unsigned long) now, md->mdir_pid, md->mdir_counter, md->mdir_hostname); snprintf(filename, sizeof(filename), "%s/tmp/%s", md->mdir_path, basename); - - if (link(tmpfile, filename) == 0) { + fprintf(stderr,"filename %s \n", filename); + // LR changed following lines + if ( stat( filename, &f_stat ) == -1 ) { + //if (link(tmpfile, filename) == 0) { char * dup_filename; dup_filename = strdup(filename); if (dup_filename == NULL) { - unlink(filename); + //unlink(filename); return NULL; } - - unlink(tmpfile); + fprintf(stderr,"filename %s %s \n", tmpfile,dup_filename); + //unlink(tmpfile); + rename (tmpfile,dup_filename ); md->mdir_counter ++; return dup_filename; } md->mdir_counter ++; k ++; } return NULL; } static void msg_free(struct maildir_msg * msg) { free(msg->msg_uid); free(msg->msg_filename); free(msg); } /* msg_new() filename is given without path */ static struct maildir_msg * msg_new(char * filename, int new_msg) { struct maildir_msg * msg; char * p; int flags; size_t uid_len; char * begin_uid; /* name of file : xxx-xxx_xxx-xxx:2,SRFT */ msg = malloc(sizeof(* msg)); if (msg == NULL) goto err; msg->msg_filename = strdup(filename); if (msg->msg_filename == NULL) goto free; begin_uid = filename; uid_len = strlen(begin_uid); flags = 0; p = strstr(filename, ":2,"); if (p != NULL) { uid_len = p - begin_uid; p += 3; /* parse flags */ while (* p != '\0') { switch (* p) { case 'S': flags |= MAILDIR_FLAG_SEEN; break; case 'R': flags |= MAILDIR_FLAG_REPLIED; break; case 'F': flags |= MAILDIR_FLAG_FLAGGED; break; case 'T': flags |= MAILDIR_FLAG_TRASHED; break; } p ++; } } if (new_msg) flags |= MAILDIR_FLAG_NEW; msg->msg_flags = flags; msg->msg_uid = malloc(uid_len + 1); if (msg->msg_uid == NULL) goto free_filename; strncpy(msg->msg_uid, begin_uid, uid_len); msg->msg_uid[uid_len] = '\0'; return msg; free_filename: free(msg->msg_filename); free: free(msg); err: return NULL; } static void maildir_flush(struct maildir * md, int msg_new) { unsigned int i; i = 0; while (i < carray_count(md->mdir_msg_list)) { struct maildir_msg * msg; int delete; msg = carray_get(md->mdir_msg_list, i); if (msg_new) { delete = 0; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) delete = 1; } else { delete = 1; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) delete = 0; } if (delete) { chashdatum key; key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); chash_delete(md->mdir_msg_hash, &key, NULL); carray_delete(md->mdir_msg_list, i); msg_free(msg); } else { i ++; } } } static int add_message(struct maildir * md, char * filename, int is_new) { struct maildir_msg * msg; chashdatum key; chashdatum value; unsigned int i; int res; int r; + fprintf(stderr,"add_message filename: %s \n", filename); msg = msg_new(filename, is_new); if (msg == NULL) { res = MAILDIR_ERROR_MEMORY; goto err; } r = carray_add(md->mdir_msg_list, msg, &i); if (r < 0) { res = MAILDIR_ERROR_MEMORY; goto free_msg; } key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); value.data = msg; value.len = 0; r = chash_set(md->mdir_msg_hash, &key, &value, NULL); if (r < 0) { res = MAILDIR_ERROR_MEMORY; goto delete; } return MAILDIR_NO_ERROR; delete: carray_delete(md->mdir_msg_list, i); free_msg: msg_free(msg); err: return res; } static int add_directory(struct maildir * md, char * path, int is_new) { DIR * d; struct dirent * entry; int res; int r; char filename[PATH_MAX]; d = opendir(path); if (d == NULL) { res = MAILDIR_ERROR_DIRECTORY; goto err; } while ((entry = readdir(d)) != NULL) { struct stat stat_info; snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name); r = stat(filename, &stat_info); if (r < 0) continue; if (S_ISDIR(stat_info.st_mode)) continue; r = add_message(md, entry->d_name, is_new); if (r != MAILDIR_NO_ERROR) { /* ignore errors */ } } closedir(d); return MAILDIR_NO_ERROR; err: return res; } int maildir_update(struct maildir * md) { struct stat stat_info; char path_new[PATH_MAX]; char path_cur[PATH_MAX]; int r; int res; snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path); snprintf(path_cur, sizeof(path_cur), "%s/cur", md->mdir_path); /* did new/ changed ? */ r = stat(path_new, &stat_info); if (r < 0) { res = MAILDIR_ERROR_DIRECTORY; goto free; } if (md->mdir_mtime_new != stat_info.st_mtime) { md->mdir_mtime_new = stat_info.st_mtime; maildir_flush(md, 1); /* messages in new */ r = add_directory(md, path_new, 1); if (r != MAILDIR_NO_ERROR) { res = r; goto free; } } /* did cur/ changed ? */ r = stat(path_cur, &stat_info); if (r < 0) { res = MAILDIR_ERROR_DIRECTORY; goto free; } if (md->mdir_mtime_cur != stat_info.st_mtime) { md->mdir_mtime_cur = stat_info.st_mtime; maildir_flush(md, 0); /* messages in cur */ r = add_directory(md, path_cur, 0); if (r != MAILDIR_NO_ERROR) { res = r; goto free; } } return MAILDIR_NO_ERROR; free: maildir_flush(md, 0); maildir_flush(md, 1); md->mdir_mtime_cur = (time_t) -1; md->mdir_mtime_new = (time_t) -1; return res; } #ifndef LIBETPAN_SYSTEM_BASENAME static char * libetpan_basename(char * filename) { char * next; char * p; p = filename; next = strchr(p, '/'); while (next != NULL) { p = next; next = strchr(p + 1, '/'); } if (p == filename) return filename; else return p + 1; } #else #define libetpan_basename(a) basename(a) #endif int maildir_message_add_uid(struct maildir * md, const char * message, size_t size, char * uid, size_t max_uid_len) { char path_new[PATH_MAX]; char tmpname[PATH_MAX]; int fd; int r; char * mapping; char * delivery_tmp_name; char * delivery_tmp_basename; char delivery_new_name[PATH_MAX]; char * delivery_new_basename; int res; struct stat stat_info; + fprintf(stderr,"maildir_message_add_uid for uid: %s \n", uid); r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = r; goto err; } /* write to tmp/ with a classic temporary file */ snprintf(tmpname, sizeof(tmpname), "%s/tmp/etpan-maildir-XXXXXX", md->mdir_path); fd = mkstemp(tmpname); if (fd < 0) { res = MAILDIR_ERROR_FILE; goto err; } r = ftruncate(fd, size); if (r < 0) { res = MAILDIR_ERROR_FILE; goto close; } mapping = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mapping == MAP_FAILED) { res = MAILDIR_ERROR_FILE; goto close; } memcpy(mapping, message, size); msync(mapping, size, MS_SYNC); munmap(mapping, size); close(fd); /* write to tmp/ with maildir standard name */ delivery_tmp_name = maildir_get_new_message_filename(md, tmpname); if (delivery_tmp_name == NULL) { res = MAILDIR_ERROR_FILE; goto unlink; } /* write to new/ with maildir standard name */ strncpy(tmpname, delivery_tmp_name, sizeof(tmpname)); tmpname[sizeof(tmpname) - 1] = '\0'; delivery_tmp_basename = libetpan_basename(tmpname); snprintf(delivery_new_name, sizeof(delivery_new_name), "%s/new/%s", md->mdir_path, delivery_tmp_basename); r = link(delivery_tmp_name, delivery_new_name); if (r < 0) { res = MAILDIR_ERROR_FILE; goto unlink_tmp; } snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path); r = stat(path_new, &stat_info); if (r < 0) { unlink(delivery_new_name); res = MAILDIR_ERROR_FILE; goto unlink_tmp; } md->mdir_mtime_new = stat_info.st_mtime; delivery_new_basename = libetpan_basename(delivery_new_name); r = add_message(md, delivery_new_basename, 1); if (r != MAILDIR_NO_ERROR) { unlink(delivery_new_name); res = MAILDIR_ERROR_FILE; goto unlink_tmp; } if (uid != NULL) strncpy(uid, delivery_new_basename, max_uid_len); unlink(delivery_tmp_name); free(delivery_tmp_name); return MAILDIR_NO_ERROR; unlink_tmp: unlink(delivery_tmp_name); free(delivery_tmp_name); goto err; close: close(fd); unlink: unlink(tmpname); err: return res; } int maildir_message_add(struct maildir * md, const char * message, size_t size) { return maildir_message_add_uid(md, message, size, NULL, 0); } int maildir_message_add_file_uid(struct maildir * md, int fd, char * uid, size_t max_uid_len) { char * message; struct stat buf; int r; + fprintf(stderr,"maildir_message_add_file_uid: %s \n", uid); if (fstat(fd, &buf) == -1) return MAILDIR_ERROR_FILE; message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (message == MAP_FAILED) return MAILDIR_ERROR_FILE; r = maildir_message_add_uid(md, message, buf.st_size, uid, max_uid_len); munmap(message, buf.st_size); return r; } int maildir_message_add_file(struct maildir * md, int fd) { + fprintf(stderr,"maildir_message_add_file \n"); return maildir_message_add_file_uid(md, fd, NULL, 0); } char * maildir_message_get(struct maildir * md, const char * uid) { chashdatum key; chashdatum value; char filename[PATH_MAX]; char * dup_filename; struct maildir_msg * msg; char * dir; int r; + fprintf(stderr,"maildir_message_get for uid: %s \n", uid); key.data = (void *) uid; key.len = strlen(uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) return NULL; msg = value.data; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; snprintf(filename, sizeof(filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_filename); dup_filename = strdup(filename); if (dup_filename == NULL) return NULL; return dup_filename; } int maildir_message_remove(struct maildir * md, const char * uid) { chashdatum key; chashdatum value; char filename[PATH_MAX]; struct maildir_msg * msg; char * dir; int r; int res; + fprintf(stderr,"maildir_message_remove for uid: %s \n", uid); key.data = (void *) uid; key.len = strlen(uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) { res = MAILDIR_ERROR_NOT_FOUND; goto err; } msg = value.data; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; snprintf(filename, sizeof(filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_filename); r = unlink(filename); if (r < 0) { res = MAILDIR_ERROR_FILE; goto err; } return MAILDIR_NO_ERROR; err: return res; } int maildir_message_change_flags(struct maildir * md, const char * uid, int new_flags) { chashdatum key; chashdatum value; char filename[PATH_MAX]; struct maildir_msg * msg; char * dir; int r; char new_filename[PATH_MAX]; char flag_str[5]; size_t i; int res; - + fprintf(stderr,"maildir_message_change_flags for uid: %s \n", uid); key.data = (void *) uid; key.len = strlen(uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) { res = MAILDIR_ERROR_NOT_FOUND; goto err; } msg = value.data; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; snprintf(filename, sizeof(filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_filename); if ((new_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; i = 0; if ((new_flags & MAILDIR_FLAG_SEEN) != 0) { flag_str[i] = 'S'; i ++; } if ((new_flags & MAILDIR_FLAG_REPLIED) != 0) { flag_str[i] = 'R'; i ++; } if ((new_flags & MAILDIR_FLAG_FLAGGED) != 0) { flag_str[i] = 'F'; i ++; } if ((new_flags & MAILDIR_FLAG_TRASHED) != 0) { flag_str[i] = 'T'; i ++; } flag_str[i] = 0; if (flag_str[0] == '\0') snprintf(new_filename, sizeof(new_filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_uid); else snprintf(new_filename, sizeof(new_filename), "%s/%s/%s:2,%s", md->mdir_path, dir, msg->msg_uid, flag_str); if (strcmp(filename, new_filename) == 0) return MAILDIR_NO_ERROR; r = link(filename, new_filename); if (r < 0) { res = MAILDIR_ERROR_FILE; goto err; } unlink(filename); return MAILDIR_NO_ERROR; err: return res; } diff --git a/kmicromail/libetpan/mh/mailmh.c b/kmicromail/libetpan/mh/mailmh.c index 119f217..5e2b4cc 100644 --- a/kmicromail/libetpan/mh/mailmh.c +++ b/kmicromail/libetpan/mh/mailmh.c @@ -226,756 +226,760 @@ struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root, const char * filename) { int r; char pathname[PATH_MAX]; char * p; chashdatum key; chashdatum data; struct mailmh_folder * folder; char * start; if (strcmp(root->fl_filename, filename) == 0) return root; #if 0 r = mailmh_folder_update(root); if (r != MAILMH_NO_ERROR) return NULL; #endif #if 0 for(i = 0 ; i < root->fl_subfolders_tab->len ; i++) { struct mailmh_folder * subfolder; subfolder = carray_get(root->fl_subfolders_tab, i); if (subfolder != NULL) if (strncmp(subfolder->fl_filename, filename, strlen(subfolder->fl_filename)) == 0) return mailmh_folder_find(subfolder, filename); } #endif strncpy(pathname, filename, PATH_MAX); pathname[PATH_MAX - 1] = 0; start = pathname + strlen(root->fl_filename) + 1; p = strchr(start, MAIL_DIR_SEPARATOR); if (p != NULL) { * p = 0; root = mailmh_folder_find(root, pathname); if (root != NULL) { folder = mailmh_folder_find(root, filename); if (folder == NULL) return NULL; return folder; } return NULL; } else { key.data = pathname; key.len = strlen(pathname); r = chash_get(root->fl_subfolders_hash, &key, &data); if (r < 0) return NULL; return data.data; } } int mailmh_folder_update(struct mailmh_folder * folder) { DIR * d; struct dirent * ent; struct stat buf; char * mh_seq; char filename[PATH_MAX]; int res; int r; uint32_t max_index; #if 0 int add_folder; #endif unsigned int i; if (stat(folder->fl_filename, &buf) == -1) { res = MAILMH_ERROR_FOLDER; goto err; } if (folder->fl_mtime == buf.st_mtime) { res = MAILMH_NO_ERROR; goto err; } folder->fl_mtime = buf.st_mtime; d = opendir(folder->fl_filename); if (d == NULL) { res = MAILMH_ERROR_FOLDER; goto err; } max_index = 0; #if 0 if (folder->fl_subfolders_tab->len == 0) add_folder = 1; else add_folder = 0; #endif /* clear the message list */ for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) { struct mailmh_msg_info * msg_info; chashdatum key; msg_info = carray_get(folder->fl_msgs_tab, i); if (msg_info == NULL) continue; #if 0 cinthash_remove(folder->fl_msgs_hash, msg_info->msg_index); #endif key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); chash_delete(folder->fl_msgs_hash, &key, NULL); mailmh_msg_info_free(msg_info); } carray_set_size(folder->fl_msgs_tab, 0); do { uint32_t index; ent = readdir(d); if (ent != NULL) { snprintf(filename, PATH_MAX, "%s%c%s", folder->fl_filename, MAIL_DIR_SEPARATOR, ent->d_name); if (stat(filename, &buf) == -1) continue; if (S_ISREG(buf.st_mode)) { index = strtoul(ent->d_name, NULL, 10); if (index != 0) { struct mailmh_msg_info * msg_info; unsigned int array_index; chashdatum key; chashdatum data; msg_info = mailmh_msg_info_new(index, buf.st_size, buf.st_mtime); if (msg_info == NULL) { res = MAILMH_ERROR_MEMORY; goto closedir; } r = carray_add(folder->fl_msgs_tab, msg_info, &array_index); if (r < 0) { mailmh_msg_info_free(msg_info); res = MAILMH_ERROR_MEMORY; goto closedir; } msg_info->msg_array_index = array_index; if (index > max_index) max_index = index; #if 0 r = cinthash_add(folder->fl_msgs_hash, msg_info->msg_index, msg_info); #endif key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); data.data = msg_info; data.len = 0; r = chash_set(folder->fl_msgs_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); mailmh_msg_info_free(msg_info); res = MAILMH_ERROR_MEMORY; goto closedir; } } } else if (S_ISDIR(buf.st_mode)) { struct mailmh_folder * subfolder; unsigned int array_index; chashdatum key; chashdatum data; if (ent->d_name[0] == '.') { if (ent->d_name[1] == 0) continue; if ((ent->d_name[1] == '.') && (ent->d_name[2] == 0)) continue; } key.data = ent->d_name; key.len = strlen(ent->d_name); r = chash_get(folder->fl_subfolders_hash, &key, &data); if (r < 0) { subfolder = mailmh_folder_new(folder, ent->d_name); if (subfolder == NULL) { res = MAILMH_ERROR_MEMORY; goto closedir; } r = carray_add(folder->fl_subfolders_tab, subfolder, &array_index); if (r < 0) { mailmh_folder_free(subfolder); res = MAILMH_ERROR_MEMORY; goto closedir; } subfolder->fl_array_index = array_index; key.data = subfolder->fl_filename; key.len = strlen(subfolder->fl_filename); data.data = subfolder; data.len = 0; r = chash_set(folder->fl_subfolders_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_subfolders_tab, subfolder->fl_array_index); mailmh_folder_free(subfolder); res = MAILMH_ERROR_MEMORY; goto closedir; } } } } } while (ent != NULL); folder->fl_max_index = max_index; mh_seq = malloc(strlen(folder->fl_filename) + 2 + sizeof(".mh_sequences")); if (mh_seq == NULL) { res = MAILMH_ERROR_MEMORY; goto closedir; } strcpy(mh_seq, folder->fl_filename); strcat(mh_seq, MAIL_DIR_SEPARATOR_S); strcat(mh_seq, ".mh_sequences"); if (stat(mh_seq, &buf) == -1) { int fd; fd = creat(mh_seq, S_IRUSR | S_IWUSR); if (fd != -1) close(fd); } free(mh_seq); closedir(d); return MAILMH_NO_ERROR; closedir: closedir(d); err: return res; } int mailmh_folder_add_subfolder(struct mailmh_folder * parent, const char * name) { char * foldername; int r; struct mailmh_folder * folder; unsigned int array_index; chashdatum key; chashdatum data; foldername = malloc(strlen(parent->fl_filename) + strlen(name) + 2); if (foldername == NULL) return MAILMH_ERROR_MEMORY; strcpy(foldername, parent->fl_filename); strcat(foldername, MAIL_DIR_SEPARATOR_S); strcat(foldername, name); r = mkdir(foldername, 0700); free(foldername); if (r < 0) return MAILMH_ERROR_FOLDER; folder = mailmh_folder_new(parent, name); if (folder == NULL) return MAILMH_ERROR_MEMORY; r = carray_add(parent->fl_subfolders_tab, folder, &array_index); if (r < 0) { mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } folder->fl_array_index = array_index; key.data = folder->fl_filename; key.len = strlen(folder->fl_filename); data.data = folder; data.len = 0; r = chash_set(parent->fl_subfolders_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_subfolders_tab, folder->fl_array_index); mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } return MAILMH_NO_ERROR; } int mailmh_folder_remove_subfolder(struct mailmh_folder * folder) { struct mailmh_folder * parent; chashdatum key; chashdatum data; int r; parent = folder->fl_parent; key.data = folder->fl_filename; key.len = strlen(folder->fl_filename); r = chash_get(parent->fl_subfolders_hash, &key, &data); if (r < 0) return MAILMH_ERROR_FOLDER; chash_delete(parent->fl_subfolders_hash, &key, NULL); carray_delete_fast(parent->fl_subfolders_tab, folder->fl_array_index); mailmh_folder_free(folder); return MAILMH_NO_ERROR; } int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder, struct mailmh_folder * dst_folder, const char * new_name) { int r; struct mailmh_folder * folder; struct mailmh_folder * parent; char * new_foldername; parent = src_folder->fl_parent; if (parent == NULL) return MAILMH_ERROR_RENAME; new_foldername = malloc(strlen(dst_folder->fl_filename) + 2 + strlen(new_name)); if (new_foldername == NULL) return MAILMH_ERROR_MEMORY; strcpy(new_foldername, dst_folder->fl_filename); strcat(new_foldername, MAIL_DIR_SEPARATOR_S); strcat(new_foldername, new_name); r = rename(src_folder->fl_filename, new_foldername); free(new_foldername); if (r < 0) return MAILMH_ERROR_RENAME; r = mailmh_folder_remove_subfolder(src_folder); if (r != MAILMH_NO_ERROR) return r; folder = mailmh_folder_new(dst_folder, new_name); if (folder == NULL) return MAILMH_ERROR_MEMORY; r = carray_add(parent->fl_subfolders_tab, folder, NULL); if (r < 0) { mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } return MAILMH_NO_ERROR; } #define MAX_TRY_ALLOC 32 /* initial file MUST be in the same directory */ static int mailmh_folder_alloc_msg(struct mailmh_folder * folder, char * filename, uint32_t * result) { uint32_t max; uint32_t k; char * new_filename; size_t len; + struct stat f_stat; len = strlen(folder->fl_filename) + 20; new_filename = malloc(len); if (new_filename == NULL) return MAILMH_ERROR_MEMORY; max = folder->fl_max_index + 1; + //fprintf(stderr,"mailmh_folder_alloc_msg filename: %s \n", filename); k = 0; while (k < MAX_TRY_ALLOC) { snprintf(new_filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR, (unsigned long) (max + k)); - - if (link(filename, new_filename) == 0) { + //fprintf(stderr,"mailmh_folder_alloc_msg new_filename: %s \n", new_filename); + if ( stat( new_filename, &f_stat ) == -1 ) { + // if (link(filename, new_filename) == 0) { int r; - + //fprintf(stderr,"filename found \n"); + //unlink(filename); + rename (filename,new_filename ); free(new_filename); - unlink(filename); if (k > MAX_TRY_ALLOC / 2) { r = mailmh_folder_update(folder); /* ignore errors */ } * result = max + k; folder->fl_max_index = max + k; return MAILMH_NO_ERROR; } else if (errno == EXDEV) { free(filename); return MAILMH_ERROR_FOLDER; } k ++; } free(new_filename); return MAILMH_ERROR_FOLDER; } int mailmh_folder_get_message_filename(struct mailmh_folder * folder, uint32_t index, char ** result) { char * filename; int len; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif len = strlen(folder->fl_filename) + 20; filename = malloc(len); if (filename == NULL) return MAILMH_ERROR_MEMORY; snprintf(filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR, (unsigned long) index); * result = filename; return MAILMH_NO_ERROR;; } int mailmh_folder_get_message_fd(struct mailmh_folder * folder, uint32_t index, int flags, int * result) { char * filename; int fd; int r; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif r = mailmh_folder_get_message_filename(folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; fd = open(filename, flags); free(filename); if (fd == -1) return MAILMH_ERROR_MSG_NOT_FOUND; * result = fd; return MAILMH_NO_ERROR; } int mailmh_folder_get_message_size(struct mailmh_folder * folder, uint32_t index, size_t * result) { int r; char * filename; struct stat buf; r = mailmh_folder_get_message_filename(folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; r = stat(filename, &buf); free(filename); if (r < 0) return MAILMH_ERROR_FILE; * result = buf.st_size; return MAILMH_NO_ERROR; } int mailmh_folder_add_message_uid(struct mailmh_folder * folder, const char * message, size_t size, uint32_t * pindex) { char * tmpname; int fd; size_t namesize; size_t left; ssize_t res; struct mailmh_msg_info * msg_info; uint32_t index; int error; int r; unsigned int array_index; struct stat buf; chashdatum key; chashdatum data; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) { error = r; goto err; } #endif namesize = strlen(folder->fl_filename) + 20; tmpname = malloc(namesize); snprintf(tmpname, namesize, "%s%ctmpXXXXXX", folder->fl_filename, MAIL_DIR_SEPARATOR); fd = mkstemp(tmpname); if (fd < 0) { error = MAILMH_ERROR_FILE; goto free; } left = size; while (left > 0) { res = write(fd, message, left); if (res == -1) { close(fd); error = MAILMH_ERROR_FILE; goto free; } left -= res; } close(fd); r = stat(tmpname, &buf); if (r < 0) { error = MAILMH_ERROR_FILE; goto free; } r = mailmh_folder_alloc_msg(folder, tmpname, &index); if (r != MAILMH_NO_ERROR) { unlink(tmpname); error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG; goto free; } free(tmpname); msg_info = mailmh_msg_info_new(index, size, buf.st_mtime); if (msg_info == NULL) { mailmh_folder_remove_message(folder, index); error = MAILMH_ERROR_MEMORY; goto err; } r = carray_add(folder->fl_msgs_tab, msg_info, &array_index); if (r < 0) { mailmh_folder_remove_message(folder, index); mailmh_msg_info_free(msg_info); error = MAILMH_ERROR_MEMORY; goto err; } msg_info->msg_array_index = array_index; #if 0 r = cinthash_add(folder->fl_msgs_hash, index, msg_info); #endif key.data = &index; key.len = sizeof(index); data.data = msg_info; data.len = 0; if (pindex != NULL) * pindex = index; r = chash_set(folder->fl_msgs_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); mailmh_msg_info_free(msg_info); error = MAILMH_ERROR_MEMORY; goto err; } return MAILMH_NO_ERROR; free: free(tmpname); err: return error; } int mailmh_folder_add_message(struct mailmh_folder * folder, const char * message, size_t size) { return mailmh_folder_add_message_uid(folder, message, size, NULL); } int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder, int fd, uint32_t * pindex) { char * message; struct stat buf; int r; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif if (fstat(fd, &buf) == -1) return MAILMH_ERROR_FILE; message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (message == MAP_FAILED) return MAILMH_ERROR_FILE; r = mailmh_folder_add_message_uid(folder, message, buf.st_size, pindex); munmap(message, buf.st_size); return r; } int mailmh_folder_add_message_file(struct mailmh_folder * folder, int fd) { return mailmh_folder_add_message_file_uid(folder, fd, NULL); } int mailmh_folder_remove_message(struct mailmh_folder * folder, uint32_t index) { char * filename; struct mailmh_msg_info * msg_info; int res; int r; chashdatum key; chashdatum data; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) { res = r; goto err; } #endif r = mailmh_folder_get_message_filename(folder, index, &filename); if (filename == NULL) { res = r; goto err; } if (unlink(filename) == -1) { res = MAILMH_ERROR_FILE; goto free; } key.data = &index; key.len = sizeof(index); r = chash_get(folder->fl_msgs_hash, &key, &data); #if 0 msg_info = cinthash_find(folder->fl_msgs_hash, index); #endif if (r == 0) { msg_info = data.data; carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); #if 0 cinthash_remove(folder->fl_msgs_hash, index); #endif chash_delete(folder->fl_msgs_hash, &key, NULL); } return MAILMH_NO_ERROR; free: free(filename); err: return res; } int mailmh_folder_move_message(struct mailmh_folder * dest_folder, struct mailmh_folder * src_folder, uint32_t index) { int fd; char * filename; int r; #if 0 r = mailmh_folder_update(dest_folder); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_update(src_folder); if (r != MAILMH_NO_ERROR) return r; #endif /* move on the same filesystem */ r = mailmh_folder_get_message_filename(src_folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_alloc_msg(dest_folder, filename, &index); free(filename); if (r == MAILMH_NO_ERROR) return MAILMH_NO_ERROR; /* move on the different filesystems */ r = mailmh_folder_get_message_fd(src_folder, index, O_RDONLY, &fd); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_add_message_file(dest_folder, fd); if (r != MAILMH_NO_ERROR) { close(fd); return r; } close(fd); r = mailmh_folder_remove_message(src_folder, index); return MAILMH_NO_ERROR; } unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder) { unsigned int i; unsigned int count; count = 0; for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) if (carray_get(folder->fl_msgs_tab, i) != NULL) count ++; return count; } |