summaryrefslogtreecommitdiffabout
path: root/kmicromail
Side-by-side diff
Diffstat (limited to 'kmicromail') (more/less context) (show whitespace changes)
-rw-r--r--kmicromail/libetpan/maildir/maildir.c25
-rw-r--r--kmicromail/libetpan/mh/mailmh.c12
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
@@ -1,981 +1,985 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2002 - 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 "mailmh.h"
/*
perfs :
/net/home/dinh/Mail/inbox/sylpheed 686
2724 /net/home/dinh/Mail/inbox/sylpheed
bart:~/LibEtPan/libetpan/tests> time ./mhtest >/dev/null
real 0m0.385s
user 0m0.270s
sys 0m0.110s
*/
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libetpan-config.h"
struct mailmh * mailmh_new(const char * foldername)
{
struct mailmh * f;
f = malloc(sizeof(*f));
if (f == NULL)
return NULL;
f->mh_main = mailmh_folder_new(NULL, foldername);
if (f->mh_main == NULL) {
free(f);
return NULL;
}
return f;
}
void mailmh_free(struct mailmh * f)
{
mailmh_folder_free(f->mh_main);
free(f);
}
struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size,
time_t mtime)
{
struct mailmh_msg_info * msg_info;
msg_info = malloc(sizeof(* msg_info));
if (msg_info == NULL)
return NULL;
msg_info->msg_index = index;
msg_info->msg_size = size;
msg_info->msg_mtime = mtime;
msg_info->msg_array_index = 0;
return msg_info;
}
void mailmh_msg_info_free(struct mailmh_msg_info * msg_info)
{
free(msg_info);
}
struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent,
const char * name)
{
char * filename;
char * parent_filename;
struct mailmh_folder * folder;
folder = malloc(sizeof(* folder));
if (folder == NULL)
goto err;
if (parent == NULL) {
filename = strdup(name);
if (filename == NULL)
goto free_folder;
}
else {
parent_filename = parent->fl_filename;
filename = malloc(strlen(parent_filename) + strlen(name) + 2);
if (filename == NULL)
goto free_folder;
strcpy(filename, parent_filename);
strcat(filename, MAIL_DIR_SEPARATOR_S);
strcat(filename, name);
}
folder->fl_filename = filename;
folder->fl_name = strdup(name);
if (folder->fl_name == NULL)
goto free_filename;
folder->fl_msgs_tab = carray_new(128);
if (folder->fl_msgs_tab == NULL)
goto free_name;
#if 0
folder->fl_msgs_hash = cinthash_new(128);
if (folder->fl_msgs_hash == NULL)
goto free_msgs_tab;
#endif
folder->fl_msgs_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
if (folder->fl_msgs_hash == NULL)
goto free_msgs_tab;
folder->fl_subfolders_tab = carray_new(128);
if (folder->fl_subfolders_tab == NULL)
goto free_msgs_hash;
folder->fl_subfolders_hash = chash_new(128, CHASH_COPYNONE);
if (folder->fl_subfolders_hash == NULL)
goto free_subfolders_tab;
folder->fl_mtime = 0;
folder->fl_parent = parent;
folder->fl_max_index = 0;
return folder;
free_subfolders_tab:
carray_free(folder->fl_subfolders_tab);
free_msgs_hash:
#if 0
cinthash_free(folder->fl_msgs_hash);
#endif
chash_free(folder->fl_msgs_hash);
free_msgs_tab:
carray_free(folder->fl_msgs_tab);
free_name:
free(folder->fl_name);
free_filename:
free(folder->fl_filename);
free_folder:
free(folder);
err:
return NULL;
}
void mailmh_folder_free(struct mailmh_folder * folder)
{
unsigned int i;
for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) {
struct mailmh_folder * subfolder;
subfolder = carray_get(folder->fl_subfolders_tab, i);
if (subfolder != NULL)
mailmh_folder_free(subfolder);
}
carray_free(folder->fl_subfolders_tab);
chash_free(folder->fl_subfolders_hash);
for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) {
struct mailmh_msg_info * msg_info;
msg_info = carray_get(folder->fl_msgs_tab, i);
if (msg_info != NULL)
mailmh_msg_info_free(msg_info);
}
carray_free(folder->fl_msgs_tab);
chash_free(folder->fl_msgs_hash);
#if 0
cinthash_free(folder->fl_msgs_hash);
#endif
free(folder->fl_filename);
free(folder->fl_name);
free(folder);
}
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;
}