-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 @@ -15,715 +15,726 @@ * 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 @@ -514,210 +514,214 @@ int mailmh_folder_add_subfolder(struct mailmh_folder * parent, 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; |