accessing mboxes fails..
Also some cleanups to index-storage and maildir code.
--HG--
branch : HEAD
AC_INIT(src)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(dovecot, 1.0-test3)
+AM_INIT_AUTOMAKE(dovecot, 1.0-test6)
AM_MAINTAINER_MODE
AC_ARG_WITH(storages,
[ --with-storages Build specified mail storage formats (maildir,mbox)], [
mail_storages=`echo "$withval"|sed 's/,/ /g'` ],
- mail_storages="maildir")
+ mail_storages="maildir mbox")
dnl * gcc specific options
if test "x$ac_cv_prog_gcc" = "xyes"; then
return data->parts;
}
+time_t index_mail_get_received_date(struct mail *_mail)
+{
+ struct index_mail *mail = (struct index_mail *) _mail;
+ struct index_mail_data *data = &mail->data;
+
+ if (data->received_date == (time_t)-1 &&
+ (mail->wanted_fields & MAIL_FETCH_RECEIVED_DATE) == 0) {
+ data->received_date = index_mail_get_cached_received_date(mail);
+ if (data->received_date != (time_t)-1)
+ return data->received_date;
+ }
+
+ return data->received_date;
+}
+
time_t index_mail_get_date(struct mail *_mail, int *timezone)
{
struct index_mail *mail = (struct index_mail *) _mail;
const struct mail_full_flags *index_mail_get_flags(struct mail *_mail);
const struct message_part *index_mail_get_parts(struct mail *_mail);
+time_t index_mail_get_received_date(struct mail *_mail);
time_t index_mail_get_date(struct mail *_mail, int *timezone);
uoff_t index_mail_get_size(struct mail *_mail);
struct istream *index_mail_init_stream(struct index_mail *mail,
index_storage_refcount++;
}
-void index_storage_deinit(struct index_storage *storage __attr_unused__)
+void index_storage_deinit(struct index_storage *storage)
{
+ i_free(storage->storage.namespace);
+ i_free(storage->storage.error);
+
if (--index_storage_refcount > 0)
return;
return ret;
}
-static void lock_notify(enum mailbox_lock_notify_type notify_type,
- unsigned int secs_left, void *context)
+void index_storage_lock_notify(struct index_mailbox *ibox,
+ enum mailbox_lock_notify_type notify_type,
+ unsigned int secs_left)
{
- struct index_mailbox *ibox = context;
struct index_storage *storage = ibox->storage;
const char *str;
time_t now;
}
}
-void index_storage_reset_lock_notify(struct index_mailbox *ibox)
+void index_storage_lock_notify_reset(struct index_mailbox *ibox)
{
ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
ibox->last_notify_type = MAILBOX_LOCK_NOTIFY_NONE;
#ifndef __INDEX_STORAGE_H
#define __INDEX_STORAGE_H
+#include "file-dotlock.h"
#include "mail-storage-private.h"
#include "mail-index.h"
#include "index-mail.h"
uint32_t commit_log_file_seq;
uoff_t commit_log_file_offset;
- /* sync: */
+ /* mbox: */
+ int mbox_fd;
+ struct istream *mbox_stream, *mbox_file_stream;
+ int mbox_lock_type;
+ dev_t mbox_dev;
+ ino_t mbox_ino;
+ unsigned int mbox_locks;
+ struct dotlock mbox_dotlock;
+ unsigned int mbox_lock_id;
+
+ buffer_t *mbox_data_buf;
+ const uoff_t *mbox_data;
+ uint32_t mbox_data_count;
+
+ /* maildir sync: */
struct maildir_uidlist *uidlist;
time_t last_new_mtime, last_cur_mtime, last_new_sync_time;
time_t dirty_cur_time;
};
int mail_storage_set_index_error(struct index_mailbox *ibox);
-void index_storage_reset_lock_notify(struct index_mailbox *ibox);
+
+void index_storage_lock_notify(struct index_mailbox *ibox,
+ enum mailbox_lock_notify_type notify_type,
+ unsigned int secs_left);
+void index_storage_lock_notify_reset(struct index_mailbox *ibox);
struct mail_index *
index_storage_alloc(const char *index_dir,
struct mailbox_list_context mailbox_ctx;
pool_t pool;
- struct mail_storage *storage;
const char *dir, *prefix;
enum mailbox_list_flags flags;
dirp = opendir(ctx->dir);
if (dirp == NULL) {
if (errno != ENOENT) {
- mail_storage_set_critical(ctx->storage,
+ mail_storage_set_critical(ctx->mailbox_ctx.storage,
"opendir(%s) failed: %m", ctx->dir);
return FALSE;
}
}
if (closedir(dirp) < 0) {
- mail_storage_set_critical(ctx->storage,
+ mail_storage_set_critical(ctx->mailbox_ctx.storage,
"readdir(%s) failed: %m", ctx->dir);
return FALSE;
}
static int maildir_fill_subscribed(struct maildir_list_context *ctx,
struct imap_match_glob *glob)
{
- struct index_storage *istorage = (struct index_storage *)ctx->storage;
+ struct index_storage *istorage =
+ (struct index_storage *)ctx->mailbox_ctx.storage;
struct subsfile_list_context *subsfile_ctx;
const char *path, *name, *p;
struct mailbox_node *node;
path = t_strconcat(istorage->control_dir != NULL ?
istorage->control_dir : istorage->dir,
"/" SUBSCRIPTION_FILE_NAME, NULL);
- subsfile_ctx = subsfile_list_init(ctx->storage, path);
+ subsfile_ctx = subsfile_list_init(ctx->mailbox_ctx.storage, path);
if (subsfile_ctx == NULL)
return FALSE;
pool = pool_alloconly_create("maildir_list", 1024);
ctx = p_new(pool, struct maildir_list_context, 1);
+ ctx->mailbox_ctx.storage = storage;
ctx->pool = pool;
- ctx->storage = storage;
ctx->flags = flags;
ctx->tree_ctx = mailbox_tree_init(MAILDIR_FS_SEP);
str_truncate(ctx->node_path, 0);
node = find_next(&ctx->root, ctx->node_path,
- ctx->storage->hierarchy_sep);
+ ctx->mailbox_ctx.storage->hierarchy_sep);
ctx->parent_pos = str_len(ctx->node_path);
if (node == NULL)
node->flags &= ~MAILBOX_FLAG_MATCHED;
str_truncate(ctx->node_path, ctx->parent_pos);
- if (ctx->parent_pos != 0)
- str_append_c(ctx->node_path, ctx->storage->hierarchy_sep);
+ if (ctx->parent_pos != 0) {
+ str_append_c(ctx->node_path,
+ ctx->mailbox_ctx.storage->hierarchy_sep);
+ }
str_append(ctx->node_path, node->name);
ctx->list.name = str_c(ctx->node_path);
{
struct index_mail *mail = (struct index_mail *)_mail;
struct index_mail_data *data = &mail->data;
- const struct mail_full_flags *flags;
- flags = index_mail_get_flags(_mail);
+ (void)index_mail_get_flags(_mail);
if (maildir_uidlist_is_recent(mail->ibox->uidlist, _mail->uid))
data->flags.flags |= MAIL_RECENT;
struct stat st;
int fd;
+ (void)index_mail_get_received_date(_mail);
if (data->received_date != (time_t)-1)
return data->received_date;
- if ((mail->wanted_fields & MAIL_FETCH_RECEIVED_DATE) == 0) {
- data->received_date = index_mail_get_cached_received_date(mail);
- if (data->received_date != (time_t)-1)
- return data->received_date;
- }
-
if (data->stream != NULL) {
fd = i_stream_get_fd(data->stream);
i_assert(fd != -1);
index_storage_deinit(storage);
- i_free(storage->storage.namespace);
- i_free(storage->storage.error);
-
i_free(storage->dir);
i_free(storage->inbox_path);
i_free(storage->index_dir);
int maildir_copy_commit(struct maildir_copy_context *ctx);
void maildir_copy_rollback(struct maildir_copy_context *ctx);
-int maildir_storage_expunge(struct mail *mail,
- struct mailbox_transaction_context *t);
-
const char *maildir_fix_mailbox_name(struct index_storage *storage,
const char *name, int remove_namespace);
const char *maildir_get_path(struct index_storage *storage, const char *name);
if (dp->d_name[0] == '.')
continue;
+ ret = maildir_uidlist_sync_next_pre(ctx->uidlist_sync_ctx,
+ dp->d_name);
+ if (ret == 0)
+ continue;
+ if (ret < 0)
+ break;
+
flags = 0;
if (move_new) {
str_truncate(src, 0);
unsigned int partial:1;
unsigned int synced:1;
+ unsigned int locked:1;
unsigned int failed:1;
};
/* lock and update uidlist to see if it's just been added */
ret = maildir_uidlist_try_lock(ctx->uidlist);
if (ret <= 0) {
- if (ret == 0)
- return 1; // FIXME: does it work right?
+ if (ret == 0) {
+ ctx->locked = TRUE;
+ return -1;
+ }
ctx->failed = TRUE;
return -1;
}
{
struct maildir_uidlist *uidlist = ctx->uidlist;
struct maildir_uidlist_rec *rec;
- int ret;
/* we'll update uidlist directly */
rec = hash_lookup(uidlist->files, filename);
- if (rec == NULL && !ctx->synced) {
- ret = maildir_uidlist_sync_uidlist(ctx);
- if (ret < 0)
- return -1;
- if (ret == 0) {
- return maildir_uidlist_sync_next_partial(ctx, filename,
- flags);
- }
-
- rec = hash_lookup(uidlist->files, filename);
- }
+ i_assert(rec != NULL || ctx->synced);
if (rec == NULL) {
if (ctx->new_files_count == 0) {
return 1;
}
+int maildir_uidlist_sync_next_pre(struct maildir_uidlist_sync_ctx *ctx,
+ const char *filename)
+{
+ int ret;
+
+ if (!ctx->synced &&
+ hash_lookup(ctx->uidlist->files, filename) == NULL &&
+ (ctx->partial || hash_lookup(ctx->files, filename) == NULL)) {
+ if (ctx->locked)
+ return 0;
+
+ ret = maildir_uidlist_sync_uidlist(ctx);
+ if (ret < 0)
+ return ctx->locked ? 0 : -1;
+ if (ret == 0)
+ return maildir_uidlist_sync_next_pre(ctx, filename);
+ }
+
+ return 1;
+}
+
int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
const char *filename,
enum maildir_uidlist_rec_flag flags)
{
struct maildir_uidlist *uidlist = ctx->uidlist;
struct maildir_uidlist_rec *rec, *old_rec;
- int ret;
if (ctx->failed)
return -1;
MAILDIR_UIDLIST_REC_FLAG_MOVED);
} else {
old_rec = hash_lookup(uidlist->files, filename);
- if (old_rec == NULL && !ctx->synced) {
- ret = maildir_uidlist_sync_uidlist(ctx);
- if (ret < 0)
- return -1;
- if (ret == 0) {
- return maildir_uidlist_sync_next(ctx, filename,
- flags);
- }
- old_rec = hash_lookup(uidlist->files, filename);
- }
+ i_assert(old_rec != NULL || ctx->synced);
rec = p_new(ctx->record_pool, struct maildir_uidlist_rec, 1);
{
int ret = ctx->failed ? -1 : 0;
- // FIXME: we most likely don't handle ctx->failed well enough
- if (!ctx->partial)
- maildir_uidlist_swap(ctx);
- else {
+ if (!ctx->partial) {
+ if (!ctx->failed && !ctx->locked)
+ maildir_uidlist_swap(ctx);
+ } else {
if (ctx->new_files_count != 0) {
maildir_uidlist_assign_uids(ctx->uidlist,
ctx->first_new_pos);
maildir_uidlist_mark_all(ctx->uidlist, FALSE);
}
- if (ctx->new_files_count != 0 && ret == 0)
+ if (ctx->new_files_count != 0 && !ctx->failed && !ctx->locked)
ret = maildir_uidlist_rewrite(ctx->uidlist);
if (UIDLIST_IS_LOCKED(ctx->uidlist))
/* Sync uidlist with what's actually on maildir. */
struct maildir_uidlist_sync_ctx *
maildir_uidlist_sync_init(struct maildir_uidlist *uidlist, int partial);
+/* Returns 1 = ok, -1 = error, 0 = new file and dovecot-uidlist is locked */
+int maildir_uidlist_sync_next_pre(struct maildir_uidlist_sync_ctx *ctx,
+ const char *filename);
int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
const char *filename,
enum maildir_uidlist_rec_flag flags);
libstorage_mbox_a_SOURCES = \
istream-raw-mbox.c \
- mbox-expunge.c \
+ mbox-file.c \
mbox-from.c \
mbox-list.c \
+ mbox-lock.c \
+ mbox-mail.c \
mbox-save.c \
mbox-sync-parse.c \
mbox-sync-rewrite.c \
mbox-sync-update.c \
- mbox-sync.c
- mbox-storage.c
+ mbox-sync.c \
+ mbox-storage.c \
+ mbox-transaction.c
noinst_HEADERS = \
istream-raw-mbox.h \
+ mbox-file.h \
mbox-from.h \
+ mbox-lock.h \
mbox-storage.h \
mbox-sync-private.h
struct _istream istream;
time_t received_time, next_received_time;
- uoff_t from_offset, body_size;
+ char *sender, *next_sender;
+
+ uoff_t from_offset, hdr_offset, next_from_offset, body_size;
struct istream *input;
};
timeout_cb, context);
}
+static int mbox_read_from_line(struct raw_mbox_istream *rstream)
+{
+ const unsigned char *buf, *p;
+ char *sender;
+ time_t received_time;
+ size_t pos, line_pos;
+ int skip;
+
+ buf = i_stream_get_data(rstream->input, &pos);
+ i_assert(pos > 0);
+
+ /* from_offset points to "\nFrom ", so unless we're at the beginning
+ of the file, skip the initial \n */
+ skip = rstream->from_offset != 0;
+
+ while ((p = memchr(buf+skip, '\n', pos-skip)) == NULL) {
+ if (i_stream_read(rstream->input) < 0) {
+ /* EOF - shouldn't happen */
+ return -1;
+ }
+ buf = i_stream_get_data(rstream->input, &pos);
+ }
+ line_pos = (size_t)(p - buf);
+
+ if (rstream->from_offset != 0) {
+ buf++;
+ pos--;
+ }
+
+ /* beginning of mbox */
+ if (memcmp(buf, "From ", 5) != 0 ||
+ mbox_from_parse(buf+5, pos-5, &received_time, &sender) < 0) {
+ /* broken From - should happen only at beginning of
+ file if this isn't a mbox.. */
+ return -1;
+ }
+
+ if (rstream->istream.istream.v_offset == rstream->from_offset) {
+ rstream->received_time = received_time;
+ i_free(rstream->sender);
+ rstream->sender = sender;
+ } else {
+ rstream->next_received_time = received_time;
+ i_free(rstream->next_sender);
+ rstream->next_sender = sender;
+ }
+
+ /* we'll skip over From-line */
+ rstream->istream.istream.v_offset += line_pos+1;
+ rstream->hdr_offset = rstream->istream.istream.v_offset;
+ return 0;
+}
+
static ssize_t _read(struct _istream *stream)
{
static const char *mbox_from = "\nFrom ";
struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
- const unsigned char *buf, *p;
+ const unsigned char *buf;
const char *fromp;
+ char *sender;
time_t received_time;
size_t i, pos;
ssize_t ret;
}
if (stream->istream.v_offset == rstream->from_offset) {
- /* read the full From-line */
- int skip = rstream->from_offset != 0;
- size_t line_pos;
-
- while ((p = memchr(buf+skip, '\n', pos-skip)) == NULL) {
- if (i_stream_read(rstream->input) < 0) {
- /* EOF - shouldn't happen */
- stream->pos = 0;
- stream->istream.eof = TRUE;
- return -1;
- }
- buf = i_stream_get_data(rstream->input, &pos);
- }
- line_pos = (size_t)(p - buf);
-
- if (rstream->from_offset != 0) {
- buf++;
- pos--;
- }
-
- /* beginning of mbox */
- if (memcmp(buf, "From ", 5) != 0)
- received_time = (time_t)-1;
- else
- received_time = mbox_from_parse_date(buf+5, pos-5);
-
- if (received_time == (time_t)-1) {
- /* broken From - should happen only at beginning of
- file if this isn't a mbox.. */
+ if (mbox_read_from_line(rstream) < 0) {
stream->pos = 0;
stream->istream.eof = TRUE;
return -1;
}
-
- if (rstream->from_offset == 0)
- rstream->received_time = received_time;
- else
- rstream->next_received_time = received_time;
-
- /* we'll skip over From-line and try again */
- stream->istream.v_offset += line_pos+1;
return _read(stream);
}
if (pos >= 31) {
- if (memcmp(buf, "\nFrom ", 6) == 0) {
- received_time = mbox_from_parse_date(buf+6, pos-6);
- if (received_time != (time_t)-1) {
- rstream->next_received_time = received_time;
- i_assert(stream->pos == 0);
- return -1;
- }
+ if (memcmp(buf, "\nFrom ", 6) == 0 &&
+ mbox_from_parse(buf+6, pos-6,
+ &received_time, &sender) == 0) {
+ rstream->next_received_time = received_time;
+
+ i_free(rstream->next_sender);
+ rstream->next_sender = sender;
+ i_assert(stream->pos == 0);
+ return -1;
}
} else if (ret == -1) {
/* last few bytes, can't contain From-line */
const unsigned char *data;
size_t size;
time_t received_time;
+ char *sender;
/* minimal: "From x Thu Nov 29 22:33:52 2001" = 31 chars */
if (i_stream_read_data(rstream->input, &data, &size, 30) == -1)
break;
}
- received_time = mbox_from_parse_date(data+6, size-6);
- if (received_time == (time_t)-1)
+ if (mbox_from_parse(data+6, size-6, &received_time, &sender) < 0)
return FALSE;
rstream->next_received_time = received_time;
+ i_free(rstream->next_sender);
+ rstream->next_sender = sender;
return TRUE;
}
return rstream->body_size;
}
+time_t istream_raw_mbox_get_received_time(struct istream *stream)
+{
+ struct raw_mbox_istream *rstream =
+ (struct raw_mbox_istream *)stream->real_stream;
+
+ (void)_read(&rstream->istream);
+ return rstream->received_time;
+}
+
+const char *istream_raw_mbox_get_sender(struct istream *stream)
+{
+ struct raw_mbox_istream *rstream =
+ (struct raw_mbox_istream *)stream->real_stream;
+
+ (void)_read(&rstream->istream);
+ return rstream->sender == NULL ? "" : rstream->sender;
+}
+
void istream_raw_mbox_next(struct istream *stream, uoff_t body_size)
{
struct raw_mbox_istream *rstream =
rstream->received_time = rstream->next_received_time;
rstream->next_received_time = (time_t)-1;
+ i_free(rstream->sender);
+ rstream->sender = rstream->next_sender;
+ rstream->next_sender = NULL;
+
rstream->from_offset = stream->v_offset + body_size;
+ rstream->hdr_offset = rstream->from_offset;
+
+ /* don't clear stream->eof if we don't have to */
+ if (stream->v_offset != rstream->from_offset)
+ i_stream_seek(stream, rstream->from_offset);
i_stream_seek(rstream->input, rstream->from_offset);
}
+void istream_raw_mbox_seek(struct istream *stream, uoff_t offset)
+{
+ struct raw_mbox_istream *rstream =
+ (struct raw_mbox_istream *)stream->real_stream;
+
+ if (offset == rstream->next_from_offset) {
+ istream_raw_mbox_next(stream, (uoff_t)-1);
+ return;
+ }
+
+ if (offset == rstream->from_offset) {
+ /* back to beginning of current message */
+ offset = rstream->hdr_offset;
+ } else {
+ rstream->body_size = (uoff_t)-1;
+ rstream->received_time = (time_t)-1;
+ rstream->next_received_time = (time_t)-1;
+
+ i_free(rstream->sender);
+ rstream->sender = NULL;
+ i_free(rstream->next_sender);
+ rstream->next_sender = NULL;
+ }
+
+ rstream->from_offset = rstream->hdr_offset = offset;
+ i_stream_seek(stream, offset);
+ i_stream_seek(rstream->input, offset);
+}
+
void istream_raw_mbox_flush(struct istream *stream)
{
struct raw_mbox_istream *rstream =
to avoid actually reading through the whole message. */
uoff_t istream_raw_mbox_get_size(struct istream *stream, uoff_t body_size);
+/* Return received time of current message, or (time_t)-1 if the timestamp is
+ broken. */
+time_t istream_raw_mbox_get_received_time(struct istream *stream);
+
+/* Return sender of current message. */
+const char *istream_raw_mbox_get_sender(struct istream *stream);
+
/* Jump to next message. If body_size isn't (uoff_t)-1, we'll use it as
potentially valid body size. */
void istream_raw_mbox_next(struct istream *stream, uoff_t body_size);
+/* Seek to message at given offset. offset must point to beginning of
+ "\nFrom ", or 0 for beginning of file. */
+void istream_raw_mbox_seek(struct istream *stream, uoff_t offset);
+
/* Flush all buffering. Call if you modify the mbox. */
void istream_raw_mbox_flush(struct istream *stream);
+++ /dev/null
-/* Copyright (C) 2002-2003 Timo Sirainen */
-
-#if 0
-#include "lib.h"
-#include "istream.h"
-#include "ostream.h"
-#include "mbox-index.h"
-#include "mbox-storage.h"
-#include "mbox-lock.h"
-#include "index-expunge.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-
-struct mbox_expunge_context {
- struct mail_expunge_context *ctx;
-
- struct index_mailbox *ibox;
- struct istream *input;
- struct ostream *output;
- int failed, expunges;
-
- uoff_t from_offset, move_offset;
-};
-
-struct mail_expunge_context *
-mbox_storage_expunge_init(struct mailbox *box,
- enum mail_fetch_field wanted_fields, int expunge_all)
-{
- struct index_mailbox *ibox = (struct index_mailbox *) box;
- struct mbox_expunge_context *ctx;
- struct mail_expunge_context *mctx;
- struct istream *input;
-
- mctx = index_storage_expunge_init(box, wanted_fields, expunge_all);
- if (mctx == NULL)
- return NULL;
-
- /* mbox must be already opened, synced and locked at this point.
- we just want the istream. */
- input = mbox_get_stream(ibox->index, MAIL_LOCK_EXCLUSIVE);
- if (input == NULL)
- return NULL;
-
- i_assert(ibox->index->mbox_sync_counter ==
- ibox->index->mbox_lock_counter);
-
- ctx = i_new(struct mbox_expunge_context, 1);
- ctx->ctx = mctx;
- ctx->ibox = ibox;
- ctx->input = input;
- ctx->output = o_stream_create_file(ibox->index->mbox_fd, default_pool,
- 4096, FALSE);
- ctx->from_offset = (uoff_t)-1;
- ctx->move_offset = (uoff_t)-1;
- o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
- return (struct mail_expunge_context *) ctx;
-}
-
-static int mbox_move_data(struct mbox_expunge_context *ctx)
-{
- struct istream *input;
- const unsigned char *data;
- size_t size;
- int failed;
-
- i_stream_seek(ctx->input, ctx->move_offset);
-
- if (ctx->output->offset == 0) {
- /* we're writing to beginning of mbox, so we
- don't want the [\r]\n there */
- (void)i_stream_read_data(ctx->input, &data, &size, 1);
- if (size > 0 && data[0] == '\n')
- i_stream_skip(ctx->input, 1);
- else if (size > 1 && data[0] == '\r' &&
- data[1] == '\n')
- i_stream_skip(ctx->input, 2);
- }
-
- if (ctx->from_offset == 0)
- failed = o_stream_send_istream(ctx->output, ctx->input) < 0;
- else {
- input = i_stream_create_limit(default_pool, ctx->input,
- 0, ctx->from_offset);
- failed = o_stream_send_istream(ctx->output, ctx->input) < 0;
- i_stream_unref(input);
- }
-
- return !failed;
-}
-
-int mbox_storage_expunge_deinit(struct mail_expunge_context *_ctx)
-{
- struct mbox_expunge_context *ctx = (struct mbox_expunge_context *) _ctx;
- int failed = ctx->failed;
-
- if (ctx->expunges) {
- if (!failed && ctx->move_offset != (uoff_t)-1) {
- ctx->from_offset = 0;
- if (!mbox_move_data(ctx))
- failed = TRUE;
- } else if (failed && ctx->output->offset > 0) {
- /* we moved some of the data. move the rest as well
- so there won't be invalid holes in mbox file */
- (void)o_stream_send_istream(ctx->output, ctx->input);
- }
-
- if (ftruncate(ctx->ibox->index->mbox_fd,
- (off_t)ctx->output->offset) < 0) {
- mail_storage_set_error(ctx->ibox->box.storage,
- "ftruncate() failed for mbox file %s: %m",
- ctx->ibox->index->mailbox_path);
- failed = TRUE;
- }
- }
-
- if (!index_storage_expunge_deinit(ctx->ctx))
- failed = TRUE;
-
- o_stream_unref(ctx->output);
- i_free(ctx);
- return !failed;
-}
-
-static int get_from_offset(struct mbox_expunge_context *ctx,
- struct mail_index_record *rec, uoff_t *offset_r)
-{
- struct message_size hdr_size;
- uoff_t offset, body_size;
-
- if (!mbox_mail_get_location(ctx->ibox->index, rec, &offset, &body_size))
- return FALSE;
-
- i_stream_seek(ctx->input, offset);
- message_get_header_size(ctx->input, &hdr_size, NULL);
-
- *offset_r = offset + hdr_size.physical_size + body_size;
- return TRUE;
-}
-
-struct mail *mbox_storage_expunge_fetch_next(struct mail_expunge_context *_ctx)
-{
- struct mbox_expunge_context *ctx =
- (struct mbox_expunge_context *) _ctx;
- struct mail_expunge_context *mctx = ctx->ctx;
- struct mail_index *index = ctx->ibox->index;
-
- if (mctx->rec == NULL)
- return NULL;
-
- if (mctx->fetch_next) {
- mctx->fetch_next = FALSE;
- do {
- if (!get_from_offset(ctx, mctx->rec,
- &ctx->from_offset)) {
- ctx->failed = TRUE;
- return NULL;
- }
-
- mctx->seq++;
- mctx->rec = index->next(index, mctx->rec);
- if (mctx->rec == NULL)
- return NULL;
- } while ((mctx->rec->msg_flags & MAIL_DELETED) == 0 &&
- !mctx->expunge_all);
- }
-
- return index_storage_expunge_fetch_next(ctx->ctx);
-}
-
-static int get_prev_from_offset(struct mbox_expunge_context *ctx,
- unsigned int seq)
-{
- struct mail_index_record *rec;
-
- if (seq == 1)
- ctx->from_offset = 0;
- else {
- rec = ctx->ibox->index->lookup(ctx->ibox->index, seq-1);
-
- if (!get_from_offset(ctx, rec, &ctx->from_offset))
- return FALSE;
- }
-
- return TRUE;
-}
-
-int mbox_storage_expunge(struct mail *mail, struct mail_expunge_context *_ctx,
- unsigned int *seq_r, int notify)
-{
- struct mbox_expunge_context *ctx = (struct mbox_expunge_context *) _ctx;
- struct index_mail *imail = (struct index_mail *) mail;
-
- if (ctx->from_offset == (uoff_t)-1) {
- if (!get_prev_from_offset(ctx, imail->data.idx_seq))
- return FALSE;
- }
-
- if (!ctx->expunges) {
- /* first expunged message */
- if (o_stream_seek(ctx->output, ctx->from_offset) < 0)
- return FALSE;
- ctx->expunges = TRUE;
- } else if (ctx->move_offset != ctx->from_offset) {
- if (!mbox_move_data(ctx))
- return FALSE;
- }
-
- if (!get_from_offset(ctx, imail->data.rec, &ctx->move_offset))
- return FALSE;
-
- return index_storage_expunge(mail, ctx->ctx, seq_r, notify);
-}
-#endif
--- /dev/null
+/* Copyright (C) 2002-2003 Timo Sirainen */
+
+#include "lib.h"
+#include "istream.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
+#include "istream-raw-mbox.h"
+
+#include <sys/stat.h>
+
+int mbox_file_open(struct index_mailbox *ibox)
+{
+ struct stat st;
+ int fd;
+
+ i_assert(ibox->mbox_fd == -1);
+
+ fd = open(ibox->path, ibox->readonly ? O_RDONLY : O_RDWR);
+ if (fd == -1) {
+ mbox_set_syscall_error(ibox, "open()");
+ return -1;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ mbox_set_syscall_error(ibox, "fstat()");
+ (void)close(fd);
+ return -1;
+ }
+
+ ibox->mbox_fd = fd;
+ ibox->mbox_dev = st.st_dev;
+ ibox->mbox_ino = st.st_ino;
+ return 0;
+}
+
+void mbox_file_close(struct index_mailbox *ibox)
+{
+ mbox_file_close_stream(ibox);
+
+ if (ibox->mbox_fd != -1) {
+ if (close(ibox->mbox_fd) < 0)
+ i_error("close(mbox) failed: %m");
+ ibox->mbox_fd = -1;
+ }
+}
+
+int mbox_file_open_stream(struct index_mailbox *ibox)
+{
+ if (ibox->mbox_stream != NULL)
+ return 0;
+
+ i_assert(ibox->mbox_file_stream == NULL);
+
+ if (ibox->mbox_fd == -1) {
+ if (mbox_file_open(ibox) < 0)
+ return -1;
+ }
+
+ if (ibox->mail_read_mmaped) {
+ ibox->mbox_file_stream =
+ i_stream_create_mmap(ibox->mbox_fd, default_pool,
+ MAIL_MMAP_BLOCK_SIZE,
+ 0, 0, FALSE);
+ } else {
+ ibox->mbox_file_stream =
+ i_stream_create_file(ibox->mbox_fd, default_pool,
+ MAIL_READ_BLOCK_SIZE, FALSE);
+ }
+
+ ibox->mbox_stream =
+ i_stream_create_raw_mbox(default_pool, ibox->mbox_file_stream);
+ return 0;
+}
+
+void mbox_file_close_stream(struct index_mailbox *ibox)
+{
+ if (ibox->mbox_stream != NULL) {
+ i_stream_close(ibox->mbox_file_stream);
+ i_stream_unref(ibox->mbox_file_stream);
+ ibox->mbox_file_stream = NULL;
+
+ i_stream_unref(ibox->mbox_stream);
+ ibox->mbox_stream = NULL;
+ }
+}
--- /dev/null
+#ifndef __MBOX_FILE_H
+#define __MBOX_FILE_H
+
+int mbox_file_open(struct index_mailbox *ibox);
+void mbox_file_close(struct index_mailbox *ibox);
+
+int mbox_file_open_stream(struct index_mailbox *ibox);
+void mbox_file_close_stream(struct index_mailbox *ibox);
+
+#endif
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
-time_t mbox_from_parse_date(const unsigned char *msg, size_t size)
+int mbox_from_parse(const unsigned char *msg, size_t size,
+ time_t *time_r, char **sender_r)
{
- const unsigned char *msg_end;
+ const unsigned char *msg_start, *sender_end, *msg_end;
struct tm tm;
int i, timezone;
time_t t;
+ *time_r = (time_t)-1;
+ *sender_r = NULL;
+
/* <sender> <date> <moreinfo> */
+ msg_start = msg;
msg_end = msg + size;
- /* skip sender */
+ /* get sender */
while (msg < msg_end && *msg != ' ') {
if (*msg == '\r' || *msg == '\n')
- return (time_t)-1;
+ return -1;
msg++;
}
+ sender_end = msg;
while (msg < msg_end && *msg == ' ') msg++;
/* next 24 chars should be in the date in asctime() format, eg.
"Thu Nov 29 22:33:52 EEST 2001"
*/
if (msg+24 > msg_end)
- return (time_t)-1;
+ return -1;
memset(&tm, 0, sizeof(tm));
}
if (i == 12 || msg[3] != ' ')
- return (time_t)-1;
+ return -1;
msg += 4;
/* day */
if (msg[0] == ' ') {
if (!i_isdigit(msg[1]) || msg[2] != ' ')
- return (time_t)-1;
+ return -1;
tm.tm_mday = msg[1]-'0';
} else {
if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
- return (time_t)-1;
+ return -1;
tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0');
}
if (tm.tm_mday == 0)
/* hour */
if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
- return (time_t)-1;
+ return -1;
tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0');
msg += 3;
/* minute */
if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
- return (time_t)-1;
+ return -1;
tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0');
msg += 3;
/* second */
if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
- return (time_t)-1;
+ return -1;
tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0');
msg += 3;
/* skip to next space */
while (msg < msg_end && *msg != ' ') {
if (*msg == '\r' || *msg == '\n')
- return (time_t)-1;
+ return -1;
msg++;
}
if (msg+5 > msg_end)
- return (time_t)-1;
+ return -1;
msg++;
}
/* year */
if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
!i_isdigit(msg[2]) || !i_isdigit(msg[3]))
- return (time_t)-1;
+ return -1;
tm.tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 +
(msg[2]-'0') * 10 + (msg[3]-'0') - 1900;
t = utc_mktime(&tm);
if (t == (time_t)-1)
- return (time_t)-1;
+ return -1;
t -= timezone * 60;
- return t;
+ *time_r = t;
} else {
/* assume local timezone */
- return mktime(&tm);
+ *time_r = mktime(&tm);
}
+
+ *sender_r = i_strdup_until(msg_start, sender_end);
+ return 0;
}
const char *mbox_from_create(const char *sender, time_t time)
#ifndef __MBOX_FROM_H
#define __MBOX_FROM_H
-time_t mbox_from_parse_date(const unsigned char *msg, size_t size);
+int mbox_from_parse(const unsigned char *msg, size_t size,
+ time_t *time_r, char **sender_r);
const char *mbox_from_create(const char *sender, time_t time);
#endif
/* Copyright (C) 2002-2003 Timo Sirainen */
-#if 0
#include "lib.h"
#include "unlink-directory.h"
#include "imap-match.h"
#include "subscription-file/subscription-file.h"
-#include "mbox-index.h"
#include "mbox-storage.h"
#include "home-expand.h"
char *real_path, *virtual_path;
};
-struct mailbox_list_context {
- struct mail_storage *storage;
+struct mbox_list_context {
+ struct mailbox_list_context mailbox_ctx;
+ struct index_storage *istorage;
+
enum mailbox_list_flags flags;
const char *prefix;
int failed;
- struct mailbox_list *(*next)(struct mailbox_list_context *ctx);
+ struct mailbox_list *(*next)(struct mbox_list_context *ctx);
pool_t list_pool;
struct mailbox_list list;
struct list_dir_context *dir;
};
-static struct mailbox_list *mbox_list_subs(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_inbox(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_path(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_next(struct mailbox_list_context *ctx);
-static struct mailbox_list *mbox_list_none(struct mailbox_list_context *ctx);
+static struct mailbox_list *mbox_list_subs(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_inbox(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_path(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_next(struct mbox_list_context *ctx);
+static struct mailbox_list *mbox_list_none(struct mbox_list_context *ctx);
static const char *mask_get_dir(struct mail_storage *storage, const char *mask)
{
return last_dir == NULL ? NULL : t_strdup_until(mask, last_dir);
}
-static const char *mbox_get_path(struct mail_storage *storage, const char *name)
+static const char *
+mbox_get_path(struct index_storage *storage, const char *name)
{
if (!full_filesystem_access || name == NULL ||
(*name != '/' && *name != '~' && *name != '\0'))
}
struct mailbox_list_context *
-mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
+mbox_mailbox_list_init(struct mail_storage *storage, const char *mask,
enum mailbox_list_flags flags)
{
- struct mailbox_list_context *ctx;
+ struct index_storage *istorage = (struct index_storage *)storage;
+ struct mbox_list_context *ctx;
const char *path, *virtual_path;
DIR *dirp;
if (storage->hierarchy_sep != '/' && strchr(mask, '/') != NULL) {
/* this will never match, return nothing */
- ctx = i_new(struct mailbox_list_context, 1);
- ctx->storage = storage;
+ ctx = i_new(struct mbox_list_context, 1);
+ ctx->mailbox_ctx.storage = storage;
ctx->next = mbox_list_none;
- return ctx;
+ return &ctx->mailbox_ctx;
}
- mask = mbox_fix_mailbox_name(storage, mask, FALSE);
+ mask = mbox_fix_mailbox_name(istorage, mask, FALSE);
/* check that we're not trying to do any "../../" lists */
if (!mbox_is_valid_mask(mask)) {
}
if ((flags & MAILBOX_LIST_SUBSCRIBED) != 0) {
- ctx = i_new(struct mailbox_list_context, 1);
- ctx->storage = storage;
+ ctx = i_new(struct mbox_list_context, 1);
+ ctx->mailbox_ctx.storage = storage;
+ ctx->istorage = istorage;
ctx->flags = flags;
ctx->next = mbox_list_subs;
- ctx->subsfile_ctx = subsfile_list_init(storage);
+ ctx->subsfile_ctx =
+ subsfile_list_init(storage, SUBSCRIPTION_FILE_NAME);
if (ctx->subsfile_ctx == NULL) {
i_free(ctx);
return NULL;
}
ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
ctx->list_pool = pool_alloconly_create("mbox_list", 1024);
- return ctx;
+ return &ctx->mailbox_ctx;
}
/* if we're matching only subdirectories, don't bother scanning the
parent directories */
virtual_path = mask_get_dir(storage, mask);
- path = mbox_get_path(storage, virtual_path);
+ path = mbox_get_path(istorage, virtual_path);
if (list_opendir(storage, path, TRUE, &dirp) < 0)
return NULL;
/* if user gave invalid directory, we just don't show any results. */
- ctx = i_new(struct mailbox_list_context, 1);
- ctx->storage = storage;
+ ctx = i_new(struct mbox_list_context, 1);
+ ctx->mailbox_ctx.storage = storage;
+ ctx->istorage = istorage;
ctx->flags = flags;
ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
ctx->list_pool = pool_alloconly_create("mbox_list", 1024);
ctx->prefix = storage->namespace == NULL ? "" :
- mbox_fix_mailbox_name(storage, storage->namespace, FALSE);
+ mbox_fix_mailbox_name(istorage, storage->namespace, FALSE);
if (virtual_path == NULL && imap_match(ctx->glob, "INBOX") > 0)
ctx->next = mbox_list_inbox;
ctx->dir->virtual_path = virtual_path == NULL ? NULL :
i_strconcat(ctx->prefix, virtual_path, NULL);
}
- return ctx;
+ return &ctx->mailbox_ctx;
}
static void list_dir_context_free(struct list_dir_context *dir)
i_free(dir);
}
-int mbox_list_mailbox_deinit(struct mailbox_list_context *ctx)
+int mbox_mailbox_list_deinit(struct mailbox_list_context *_ctx)
{
- int failed = ctx->failed;
+ struct mbox_list_context *ctx = (struct mbox_list_context *)_ctx;
+ int ret = ctx->failed ? -1 : 0;
if (ctx->subsfile_ctx != NULL) {
- if (!subsfile_list_deinit(ctx->subsfile_ctx))
- failed = TRUE;
+ if (subsfile_list_deinit(ctx->subsfile_ctx) < 0)
+ ret = -1;
}
while (ctx->dir != NULL) {
imap_match_deinit(ctx->glob);
i_free(ctx);
- return !failed;
+ return ret;
}
-struct mailbox_list *mbox_list_mailbox_next(struct mailbox_list_context *ctx)
+struct mailbox_list *mbox_mailbox_list_next(struct mailbox_list_context *_ctx)
{
+ struct mbox_list_context *ctx = (struct mbox_list_context *)_ctx;
+
return ctx->next(ctx);
}
-static int list_file(struct mailbox_list_context *ctx, const char *fname)
+static int list_file(struct mbox_list_context *ctx, const char *fname)
{
struct list_dir_context *dir;
const char *list_path, *real_path, *path;
else {
if (ENOTFOUND(errno))
return 0;
- mail_storage_set_critical(ctx->storage, "stat(%s) failed: %m",
- real_path);
+ mail_storage_set_critical(ctx->mailbox_ctx.storage,
+ "stat(%s) failed: %m", real_path);
return -1;
}
ctx->list.name = NULL;
ret = match2 < 0 ? 0 :
- list_opendir(ctx->storage, real_path, FALSE, &dirp);
+ list_opendir(ctx->mailbox_ctx.storage,
+ real_path, FALSE, &dirp);
if (ret > 0) {
dir = i_new(struct list_dir_context, 1);
dir->dirp = dirp;
return -1;
return match > 0 || match2 > 0;
} else if (match > 0 &&
- strcmp(real_path, ctx->storage->inbox_file) != 0 &&
+ strcmp(real_path, ctx->istorage->inbox_path) != 0 &&
strcasecmp(list_path, "INBOX") != 0) {
/* don't match any INBOX here, it's added separately.
we might also have ~/mail/inbox, ~/mail/Inbox etc.
return 0;
}
-static struct mailbox_list *list_fix_name(struct mailbox_list_context *ctx)
+static struct mailbox_list *list_fix_name(struct mbox_list_context *ctx)
{
char *p, *str, sep;
str = p_strdup(ctx->list_pool, ctx->list.name);
ctx->list.name = str;
- sep = ctx->storage->hierarchy_sep;
+ sep = ctx->mailbox_ctx.storage->hierarchy_sep;
for (p = str; *p != '\0'; p++) {
if (*p == '/')
*p = sep;
return &ctx->list;
}
-static struct mailbox_list *mbox_list_subs(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_subs(struct mbox_list_context *ctx)
{
struct stat st;
const char *name, *path, *p;
return &ctx->list;
t_push();
- name = mbox_fix_mailbox_name(ctx->storage, ctx->list.name, TRUE);
- path = mbox_get_path(ctx->storage, name);
+ name = mbox_fix_mailbox_name(ctx->istorage, ctx->list.name, TRUE);
+ path = mbox_get_path(ctx->istorage, name);
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode))
ctx->list.flags = MAILBOX_NOSELECT | MAILBOX_CHILDREN;
return &ctx->list;
}
-static struct mailbox_list *mbox_list_inbox(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_inbox(struct mbox_list_context *ctx)
{
struct stat st;
ctx->list.flags = strncmp(ctx->prefix, "INBOX/", 6) == 0 ?
MAILBOX_CHILDREN : MAILBOX_NOINFERIORS;
if ((ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0) {
- if (stat(ctx->storage->inbox_file, &st) < 0)
+ if (stat(ctx->istorage->inbox_path, &st) < 0)
ctx->list.flags |= MAILBOX_UNMARKED;
else
ctx->list.flags |= STAT_GET_MARKED(st);
return &ctx->list;
}
-static struct mailbox_list *mbox_list_path(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_path(struct mbox_list_context *ctx)
{
ctx->next = mbox_list_next;
return ctx->next(ctx);
}
-static struct mailbox_list *mbox_list_next(struct mailbox_list_context *ctx)
+static struct mailbox_list *mbox_list_next(struct mbox_list_context *ctx)
{
struct list_dir_context *dir;
struct dirent *d;
}
static struct mailbox_list *
-mbox_list_none(struct mailbox_list_context *ctx __attr_unused__)
+mbox_list_none(struct mbox_list_context *ctx __attr_unused__)
{
return NULL;
}
-#endif
--- /dev/null
+/* Copyright (C) 2002 Timo Sirainen */
+
+#include "lib.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
+#include "mbox-lock.h"
+
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_FLOCK
+# include <sys/file.h>
+#endif
+
+/* 0.1 .. 0.2msec */
+#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
+
+/* lock methods to use in wanted order */
+#define DEFAULT_LOCK_METHODS "dotlock fcntl"
+/* lock timeout */
+#define DEFAULT_LOCK_TIMEOUT 300
+/* assume stale dotlock if mbox file hasn't changed for n seconds */
+#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT 30
+
+struct dotlock_context {
+ struct index_mailbox *ibox;
+ int lock_type;
+ int last_stale;
+};
+
+static int lock_settings_initialized = FALSE;
+static int use_dotlock, use_fcntl_lock, use_flock, fcntl_before_flock;
+static int use_read_dotlock, lock_timeout, dotlock_change_timeout;
+
+static int mbox_unlock_files(struct index_mailbox *ibox);
+
+static void mbox_init_lock_settings(void)
+{
+ const char *str;
+ const char *const *lock;
+
+ use_dotlock = use_fcntl_lock = use_flock = fcntl_before_flock = FALSE;
+
+ str = getenv("MBOX_LOCKS");
+ if (str == NULL) str = DEFAULT_LOCK_METHODS;
+ for (lock = t_strsplit(str, " "); *lock != NULL; lock++) {
+ if (strcasecmp(*lock, "dotlock") == 0)
+ use_dotlock = TRUE;
+ else if (strcasecmp(*lock, "fcntl") == 0) {
+ use_fcntl_lock = TRUE;
+ fcntl_before_flock = use_flock == FALSE;
+ } else if (strcasecmp(*lock, "flock") == 0)
+ use_flock = TRUE;
+ else
+ i_fatal("MBOX_LOCKS: Invalid value %s", *lock);
+ }
+
+ use_read_dotlock = getenv("MBOX_READ_DOTLOCK") != NULL;
+
+ str = getenv("MBOX_LOCK_TIMEOUT");
+ lock_timeout = str == NULL ? DEFAULT_LOCK_TIMEOUT : atoi(str);
+
+ str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
+ dotlock_change_timeout = str == NULL ?
+ DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
+
+ lock_settings_initialized = TRUE;
+}
+
+#ifdef HAVE_FLOCK
+static int mbox_lock_flock(struct index_mailbox *ibox, int lock_type,
+ time_t max_wait_time)
+{
+ time_t now, last_notify;
+
+ if (lock_type == F_WRLCK)
+ lock_type = LOCK_EX;
+ else if (lock_type == F_RDLCK)
+ lock_type = LOCK_SH;
+ else
+ lock_type = LOCK_UN;
+
+ last_notify = 0;
+ while (flock(ibox->mbox_fd, lock_type | LOCK_NB) < 0) {
+ if (errno != EWOULDBLOCK) {
+ mbox_set_syscall_error(ibox, "flock()");
+ return -1;
+ }
+
+ if (max_wait_time == 0)
+ return 0;
+
+ now = time(NULL);
+ if (now >= max_wait_time)
+ return 0;
+
+ if (now != last_notify) {
+ index_storage_lock_notify(ibox,
+ MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
+ max_wait_time - now);
+ }
+
+ usleep(LOCK_RANDOM_USLEEP_TIME);
+ }
+
+ return 1;
+}
+#endif
+
+static int mbox_lock_fcntl(struct index_mailbox *ibox, int lock_type,
+ time_t max_wait_time)
+{
+ struct flock fl;
+ time_t now;
+ int wait_type;
+
+ fl.l_type = lock_type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+
+ wait_type = max_wait_time == 0 ? F_SETLK : F_SETLKW;
+ while (fcntl(ibox->mbox_fd, wait_type, &fl) < 0) {
+ if (errno != EINTR) {
+ if (errno != EAGAIN && errno != EACCES)
+ mbox_set_syscall_error(ibox, "fcntl()");
+ return -1;
+ }
+
+ now = time(NULL);
+ if (max_wait_time != 0 && now >= max_wait_time)
+ return 0;
+
+ index_storage_lock_notify(ibox,
+ MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
+ max_wait_time - now);
+ }
+
+ return 1;
+}
+
+static int mbox_file_locks(struct index_mailbox *ibox, int lock_type,
+ time_t max_wait_time)
+{
+ struct stat st;
+ int ret;
+
+ /* now we need to have the file itself locked. open it if needed. */
+ if (stat(ibox->path, &st) < 0) {
+ mbox_set_syscall_error(ibox, "stat()");
+ return -1;
+ }
+
+ if (st.st_dev != ibox->mbox_dev || st.st_ino != ibox->mbox_ino)
+ mbox_file_close(ibox);
+
+ if (ibox->mbox_fd == -1) {
+ if (mbox_file_open(ibox) < 0) {
+ (void)mbox_unlock_files(ibox);
+ return -1;
+ }
+ }
+
+ if (use_fcntl_lock && fcntl_before_flock) {
+ ret = mbox_lock_fcntl(ibox, lock_type, max_wait_time);
+ if (ret <= 0)
+ return ret;
+ }
+#ifdef HAVE_FLOCK
+ if (use_flock) {
+ ret = mbox_lock_flock(ibox, lock_type, max_wait_time);
+ if (ret <= 0)
+ return ret;
+ }
+#endif
+ if (use_fcntl_lock && !fcntl_before_flock) {
+ ret = mbox_lock_fcntl(ibox, lock_type, max_wait_time);
+ if (ret <= 0)
+ return ret;
+ }
+ return 1;
+}
+
+static int mbox_file_unlock(struct index_mailbox *ibox)
+{
+ int ret = 0;
+
+#ifdef HAVE_FLOCK
+ if (use_flock && mbox_lock_flock(ibox, F_UNLCK, 0) < 0)
+ ret = -1;
+#endif
+ if (use_fcntl_lock && mbox_lock_fcntl(ibox, F_UNLCK, 0) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int dotlock_callback(unsigned int secs_left, int stale, void *context)
+{
+ struct dotlock_context *ctx = context;
+
+ if (stale && !ctx->last_stale) {
+ if (mbox_file_locks(ctx->ibox, ctx->lock_type, 0) <= 0) {
+ /* we couldn't get fcntl/flock - it's really locked */
+ ctx->last_stale = TRUE;
+ return FALSE;
+ }
+ (void)mbox_file_unlock(ctx->ibox);
+ }
+ ctx->last_stale = stale;
+
+ index_storage_lock_notify(ctx->ibox, stale ?
+ MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
+ MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
+ secs_left);
+ return TRUE;
+}
+
+int mbox_lock(struct index_mailbox *ibox, int lock_type,
+ unsigned int *lock_id_r)
+{
+ time_t max_wait_time;
+ int ret;
+
+ /* allow only unlock -> shared/exclusive or exclusive -> shared */
+ i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
+ i_assert(lock_type == F_RDLCK || ibox->mbox_lock_type != F_RDLCK);
+
+ if (ibox->mbox_lock_type == lock_type) {
+ ibox->mbox_locks++;
+ return 1;
+ }
+
+ index_storage_lock_notify_reset(ibox);
+
+ if (!lock_settings_initialized)
+ mbox_init_lock_settings();
+
+ max_wait_time = time(NULL) + lock_timeout;
+
+ /* make .lock file first to protect overwriting the file */
+ if (use_dotlock && ibox->mbox_dotlock.ino == 0) {
+ struct dotlock_context ctx;
+
+ ctx.ibox = ibox;
+ ctx.lock_type = lock_type;
+ ctx.last_stale = -1;
+
+ ret = file_lock_dotlock(ibox->path, NULL,
+ lock_type == F_RDLCK &&
+ !use_read_dotlock, lock_timeout,
+ dotlock_change_timeout, 0,
+ dotlock_callback, &ctx,
+ &ibox->mbox_dotlock);
+
+ if (ret < 0) {
+ mbox_set_syscall_error(ibox, "file_lock_dotlock()");
+ return -1;
+ }
+ if (ret == 0) {
+ mail_storage_set_error(ibox->box.storage,
+ "Timeout while waiting for lock");
+ return 0;
+ }
+ }
+
+ ibox->mbox_lock_type = lock_type;
+ ret = mbox_file_locks(ibox, ibox->mbox_lock_type, max_wait_time);
+ if (ret <= 0) {
+ (void)mbox_unlock_files(ibox);
+ if (ret == 0) {
+ mail_storage_set_error(ibox->box.storage,
+ "Timeout while waiting for lock");
+ }
+ return ret;
+ }
+
+ *lock_id_r = ++ibox->mbox_lock_id;
+ return 1;
+}
+
+static int mbox_unlock_files(struct index_mailbox *ibox)
+{
+ int ret = 0;
+
+ if (ibox->mbox_fd != -1) {
+ if (mbox_file_unlock(ibox) < 0)
+ ret = -1;
+ }
+
+ if (ibox->mbox_dotlock.ino != 0) {
+ if (file_unlock_dotlock(ibox->path, &ibox->mbox_dotlock) <= 0) {
+ mbox_set_syscall_error(ibox, "file_unlock_dotlock()");
+ ret = -1;
+ }
+ ibox->mbox_dotlock.ino = 0;
+ }
+
+ /* make sure we don't keep mmap() between locks */
+ mbox_file_close_stream(ibox);
+
+ ibox->mbox_lock_id++;
+ ibox->mbox_lock_type = F_UNLCK;
+ return ret;
+}
+
+int mbox_unlock(struct index_mailbox *ibox, unsigned int lock_id)
+{
+ i_assert(ibox->mbox_lock_id == lock_id);
+
+ if (--ibox->mbox_locks > 0)
+ return 0;
+
+ return mbox_unlock_files(ibox);
+}
--- /dev/null
+#ifndef __MBOX_LOCK_H
+#define __MBOX_LOCK_H
+
+/* NOTE: if mbox file is not open, it's opened. if it is open but file has
+ been overwritten (ie. inode has changed), it's reopened. */
+int mbox_lock(struct index_mailbox *ibox, int lock_type,
+ unsigned int *lock_id_r);
+int mbox_unlock(struct index_mailbox *ibox, unsigned int lock_id);
+
+#endif
--- /dev/null
+/* Copyright (C) 2003 Timo Sirainen */
+
+#include "lib.h"
+#include "istream.h"
+#include "index-mail.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
+#include "istream-raw-mbox.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int mbox_mail_seek(struct index_mail *mail)
+{
+ i_assert(mail->mail.seq <= mail->ibox->mbox_data_count);
+
+ // FIXME: lock the file
+
+ if (mbox_file_open_stream(mail->ibox) < 0)
+ return -1;
+
+ i_stream_seek(mail->ibox->mbox_stream,
+ mail->ibox->mbox_data[mail->mail.seq-1] >> 1);
+ return 0;
+}
+
+static const struct mail_full_flags *mbox_mail_get_flags(struct mail *_mail)
+{
+ struct index_mail *mail = (struct index_mail *)_mail;
+ struct index_mail_data *data = &mail->data;
+
+ i_assert(_mail->seq <= mail->ibox->mbox_data_count);
+
+ (void)index_mail_get_flags(_mail);
+ if ((mail->ibox->mbox_data[_mail->seq-1] & 1) != 0)
+ data->flags.flags |= MAIL_RECENT;
+
+ return &data->flags;
+}
+
+static time_t mbox_mail_get_received_date(struct mail *_mail)
+{
+ struct index_mail *mail = (struct index_mail *)_mail;
+ struct index_mail_data *data = &mail->data;
+
+ (void)index_mail_get_received_date(_mail);
+ if (data->received_date != (time_t)-1)
+ return data->received_date;
+
+ if (mbox_mail_seek(mail) < 0)
+ return (time_t)-1;
+ data->received_date =
+ istream_raw_mbox_get_received_time(mail->ibox->mbox_stream);
+
+ if (data->received_date != (time_t)-1) {
+ index_mail_cache_add(mail, MAIL_CACHE_RECEIVED_DATE,
+ &data->received_date,
+ sizeof(data->received_date));
+ }
+ return data->received_date;
+}
+
+static const char *
+mbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field)
+{
+ struct index_mail *mail = (struct index_mail *)_mail;
+
+ if (field == MAIL_FETCH_FROM_ENVELOPE) {
+ if (mbox_mail_seek(mail) < 0)
+ return NULL;
+
+ return istream_raw_mbox_get_sender(mail->ibox->mbox_stream);
+
+ }
+
+ return index_mail_get_special(_mail, field);
+}
+
+static struct istream *mbox_mail_get_stream(struct mail *_mail,
+ struct message_size *hdr_size,
+ struct message_size *body_size)
+{
+ struct index_mail *mail = (struct index_mail *)_mail;
+ struct index_mail_data *data = &mail->data;
+
+ if (data->stream == NULL) {
+ if (mbox_mail_seek(mail) < 0)
+ return NULL;
+
+ data->stream = mail->ibox->mbox_stream;
+ }
+
+ return index_mail_init_stream(mail, hdr_size, body_size);
+}
+
+struct mail mbox_mail = {
+ 0, 0, 0, 0, 0, 0,
+
+ mbox_mail_get_flags,
+ index_mail_get_parts,
+ mbox_mail_get_received_date,
+ index_mail_get_date,
+ index_mail_get_size,
+ index_mail_get_header,
+ index_mail_get_headers,
+ mbox_mail_get_stream,
+ mbox_mail_get_special,
+ index_mail_update_flags,
+ index_mail_expunge
+};
/* Copyright (C) 2002 Timo Sirainen */
-#if 0
#include "lib.h"
#include "hostpid.h"
#include "ostream.h"
#include "str.h"
#include "write-full.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
#include "mbox-storage.h"
+#include "mbox-file.h"
+#include "mbox-from.h"
+#include "mbox-lock.h"
#include "mail-save.h"
#include <stdlib.h>
#include <sys/stat.h>
#include <netdb.h>
-struct mail_save_context {
+struct mbox_save_context {
struct index_mailbox *ibox;
- int transaction;
+ uoff_t append_offset;
struct ostream *output;
uoff_t sync_offset, content_length_offset, eoh_offset;
static char my_hostdomain[256] = "";
-static int syscall_error(struct mail_save_context *ctx, const char *function)
-{
- mail_storage_set_critical(ctx->ibox->box.storage,
- "%s failed for mbox file %s: %m",
- function, ctx->ibox->index->mailbox_path);
- return FALSE;
-}
-
-static int write_error(struct mail_save_context *ctx)
+static int write_error(struct mbox_save_context *ctx)
{
if (ENOSPACE(errno)) {
mail_storage_set_error(ctx->ibox->box.storage,
"Not enough disk space");
} else {
- syscall_error(ctx, "write()");
+ mbox_set_syscall_error(ctx->ibox, "write()");
}
- return FALSE;
+ return -1;
}
-static int mbox_seek_to_end(struct mail_save_context *ctx, uoff_t *offset)
+static int mbox_seek_to_end(struct mbox_save_context *ctx, uoff_t *offset)
{
struct stat st;
char ch;
int fd;
- fd = ctx->ibox->index->mbox_fd;
+ fd = ctx->ibox->mbox_fd;
if (fstat(fd, &st) < 0)
- return syscall_error(ctx, "fstat()");
+ return mbox_set_syscall_error(ctx->ibox, "fstat()");
*offset = (uoff_t)st.st_size;
if (st.st_size == 0)
- return TRUE;
+ return 0;
if (lseek(fd, st.st_size-1, SEEK_SET) < 0)
- return syscall_error(ctx, "lseek()");
+ return mbox_set_syscall_error(ctx->ibox, "lseek()");
if (read(fd, &ch, 1) != 1)
- return syscall_error(ctx, "read()");
+ return mbox_set_syscall_error(ctx->ibox, "read()");
if (ch != '\n') {
if (write_full(fd, "\n", 1) < 0)
*offset += 1;
}
- return TRUE;
+ return 0;
}
-static int mbox_append_lf(struct mail_save_context *ctx)
+static int mbox_append_lf(struct mbox_save_context *ctx)
{
if (o_stream_send(ctx->output, "\n", 1) < 0)
return write_error(ctx);
return TRUE;
}
-static int write_from_line(struct mail_save_context *ctx, time_t received_date)
+static int write_from_line(struct mbox_save_context *ctx, time_t received_date,
+ const char *from_envelope)
{
- const char *sender, *line, *name;
+ const char *line, *name;
if (*my_hostdomain == '\0') {
struct hostent *hent;
strocpy(my_hostdomain, name, sizeof(my_hostdomain));
}
- sender = t_strconcat(ctx->ibox->box.storage->user, "@",
- my_hostdomain, NULL);
+ if (from_envelope == NULL) {
+ from_envelope = t_strconcat(ctx->ibox->storage->user, "@",
+ my_hostdomain, NULL);
+ }
/* save in local timezone, no matter what it was given with */
- line = mbox_from_create(sender, received_date);
+ line = mbox_from_create(from_envelope, received_date);
if (o_stream_send_str(ctx->output, line) < 0)
return write_error(ctx);
- return TRUE;
+ return 0;
}
static const char *get_system_flags(enum mail_flags flags)
static const char *get_keywords(const struct mail_full_flags *flags)
{
string_t *str;
- unsigned int field;
unsigned int i;
- if ((flags->flags & MAIL_KEYWORDS_MASK) == 0)
+ if (flags->keywords_count == 0)
return "";
str = t_str_new(256);
- field = 1 << MAIL_KEYWORD_1_BIT;
for (i = 0; i < flags->keywords_count; i++) {
- const char *keyword = flags->keywords[i];
-
- if ((flags->flags & field) && keyword != NULL) {
+ if (str_len(str) > 0)
str_append_c(str, ' ');
- str_append(str, keyword);
- }
-
- field <<= 1;
+ str_append(str, flags->keywords[i]);
}
-
return str_c(str);
}
void *context)
{
static const char *content_length = "Content-Length: ";
- struct mail_save_context *ctx = context;
+ struct mbox_save_context *ctx = context;
const char *str;
char *buf;
size_t space;
return 1;
}
-static int mbox_fix_header(struct mail_save_context *ctx)
+static int mbox_fix_header(struct mbox_save_context *ctx)
{
uoff_t old_offset;
const char *str;
old_offset = ctx->output->offset;
if (o_stream_seek(ctx->output, ctx->content_length_offset) < 0)
- return syscall_error(ctx, "o_stream_seek()");
+ return mbox_set_syscall_error(ctx->ibox, "o_stream_seek()");
/* write value for Content-Length */
str = dec2str(old_offset - (ctx->eoh_offset + 1 + crlf));
return write_error(ctx);
if (o_stream_seek(ctx->output, old_offset) < 0)
- return syscall_error(ctx, "o_stream_seek()");
- return TRUE;
+ return mbox_set_syscall_error(ctx->ibox, "o_stream_seek()");
+ return 0;
}
-int mbox_storage_save_next(struct mail_save_context *ctx,
- const struct mail_full_flags *flags,
- time_t received_date,
- int timezone_offset __attr_unused__,
- struct istream *data)
+int mbox_save(struct mailbox_transaction_context *_t,
+ const struct mail_full_flags *flags,
+ time_t received_date, int timezone_offset __attr_unused__,
+ const char *from_envelope, struct istream *data)
{
- enum mail_flags real_flags;
- int failed;
+ struct mbox_transaction_context *t =
+ (struct mbox_transaction_context *)_t;
+ struct index_mailbox *ibox = t->ictx.ibox;
+ struct mbox_save_context *ctx = t->save_ctx;
+ int ret;
- /* we don't need the real flag positions, easier to keep using our own.
- they need to be checked/added though. */
ctx->flags = flags;
- real_flags = flags->flags;
- if (!index_mailbox_fix_keywords(ctx->ibox, &real_flags,
- flags->keywords,
- flags->keywords_count))
- return FALSE;
- t_push();
- if (!write_from_line(ctx, received_date) ||
- !mail_storage_save(ctx->ibox->box.storage,
- ctx->ibox->index->mailbox_path,
- data, ctx->output,
- getenv("MAIL_SAVE_CRLF") != NULL,
- save_header_callback, ctx) ||
- !mbox_fix_header(ctx) ||
- !mbox_append_lf(ctx)) {
- /* failed, truncate file back to original size.
- output stream needs to be flushed before truncating
- so unref() won't write anything. */
- o_stream_flush(ctx->output);
- if (ctx->sync_offset != (uoff_t)-1) {
- (void)ftruncate(ctx->ibox->index->mbox_fd,
- ctx->sync_offset);
- ctx->sync_offset = (uoff_t)-1;
+ if (ctx == NULL) {
+ ctx = t->save_ctx = i_new(struct mbox_save_context, 1);
+ ctx->ibox = ibox;
+ ctx->append_offset = (uoff_t)-1;
+ }
+
+ if (ctx->append_offset == (uoff_t)-1) {
+ if (ibox->mbox_lock_type != F_WRLCK) {
+ if (mbox_lock(ibox, F_WRLCK, &t->mbox_lock_id) <= 0)
+ return -1;
}
- failed = TRUE;
+
+ if (ibox->mbox_fd == -1) {
+ if (mbox_file_open(ibox) < 0)
+ return -1;
+ }
+
+ if (mbox_seek_to_end(ctx, &ctx->append_offset) < 0)
+ return -1;
+
+ ctx->output = o_stream_create_file(ibox->mbox_fd, default_pool,
+ 4096, FALSE);
+ o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
+ }
+
+ i_assert(ibox->mbox_lock_type == F_WRLCK);
+
+ t_push();
+ if (write_from_line(ctx, received_date, from_envelope) < 0 ||
+ mail_storage_save(ibox->box.storage, ibox->path, data, ctx->output,
+ getenv("MAIL_SAVE_CRLF") != NULL,
+ save_header_callback, ctx) < 0 ||
+ mbox_fix_header(ctx) < 0 ||
+ mbox_append_lf(ctx) < 0) {
+ ret = -1;
} else {
- if (!ctx->transaction)
- ctx->sync_offset = ctx->output->offset;
- failed = FALSE;
+ ret = 0;
}
t_pop();
-
- return !failed;
+ return ret;
}
-struct mail_save_context *
-mbox_storage_save_init(struct mailbox *box, int transaction)
+static void mbox_save_deinit(struct mbox_save_context *ctx)
{
- struct index_mailbox *ibox = (struct index_mailbox *) box;
- struct mail_save_context *ctx;
-
- if (box->is_readonly(box)) {
- mail_storage_set_error(box->storage, "Mailbox is read-only");
- return NULL;
- }
-
- if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
- MAIL_LOCK_EXCLUSIVE))
- return NULL;
+ if (ctx->output != NULL)
+ o_stream_unref(ctx->output);
+ i_free(ctx);
+}
- ctx = i_new(struct mail_save_context, 1);
- ctx->ibox = ibox;
- ctx->transaction = transaction;
+int mbox_save_commit(struct mbox_save_context *ctx)
+{
+ int ret = 0;
- if (!mbox_seek_to_end(ctx, &ctx->sync_offset)) {
- i_free(ctx);
- return NULL;
+ if (ctx->ibox->mbox_fd != -1) {
+ if (fdatasync(ctx->ibox->mbox_fd) < 0) {
+ mbox_set_syscall_error(ctx->ibox, "fsync()");
+ ret = -1;
+ }
}
- ctx->output = o_stream_create_file(ibox->index->mbox_fd,
- default_pool, 4096, FALSE);
- o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
- return ctx;
+ mbox_save_deinit(ctx);
+ return ret;
}
-int mbox_storage_save_deinit(struct mail_save_context *ctx, int rollback)
+void mbox_save_rollback(struct mbox_save_context *ctx)
{
- int failed = FALSE;
+ struct index_mailbox *ibox = ctx->ibox;
- if (!index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK))
- failed = TRUE;
+ if (ctx->append_offset != (uoff_t)-1 && ibox->mbox_fd != -1) {
+ i_assert(ibox->mbox_lock_type == F_WRLCK);
- if (o_stream_flush(ctx->output) < 0)
- failed = TRUE;
- o_stream_unref(ctx->output);
+ /* failed, truncate file back to original size.
+ output stream needs to be flushed before truncating
+ so unref() won't write anything. */
+ o_stream_flush(ctx->output);
- if (rollback && ctx->sync_offset != (uoff_t)-1) {
- if (ftruncate(ctx->ibox->index->mbox_fd,
- ctx->sync_offset) < 0) {
- syscall_error(ctx, "ftruncate()");
- failed = TRUE;
- }
- } else {
- if (fdatasync(ctx->ibox->index->mbox_fd) < 0) {
- syscall_error(ctx, "fsync()");
- failed = TRUE;
- }
+ if (ftruncate(ibox->mbox_fd, (off_t)ctx->append_offset) < 0)
+ mbox_set_syscall_error(ibox, "ftruncate()");
}
- i_free(ctx);
- return !failed;
+ mbox_save_deinit(ctx);
}
-#endif
/* Copyright (C) 2002-2003 Timo Sirainen */
#include "lib.h"
+#include "buffer.h"
#include "home-expand.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "subscription-file/subscription-file.h"
-#include "mail-keywords.h"
-#include "mbox-index.h"
-#include "mbox-lock.h"
#include "mbox-storage.h"
+#include "mbox-lock.h"
+#include "mail-save.h"
#include <stdio.h>
#include <stdlib.h>
extern struct mail_storage mbox_storage;
extern struct mailbox mbox_mailbox;
-static int mbox_handle_errors(struct mail_storage *storage)
+int mbox_set_syscall_error(struct index_mailbox *ibox, const char *function)
+{
+ i_assert(function != NULL);
+
+ mail_storage_set_critical(ibox->box.storage,
+ "%s failed with mbox file %s: %m", function, ibox->path);
+ return -1;
+}
+
+static int mbox_handle_errors(struct index_storage *istorage)
{
+ struct mail_storage *storage = &istorage->storage;
+
if (ENOACCESS(errno))
mail_storage_set_error(storage, "Permission denied");
else if (ENOSPACE(errno))
mbox_create(const char *data, const char *user,
const char *namespace, char hierarchy_sep)
{
- struct mail_storage *storage;
+ struct index_storage *storage;
const char *root_dir, *inbox_file, *index_dir, *p;
struct stat st;
int autodetect;
else if (strcmp(index_dir, "MEMORY") == 0)
index_dir = NULL;
- storage = i_new(struct mail_storage, 1);
- memcpy(storage, &mbox_storage, sizeof(struct mail_storage));
+ storage = i_new(struct index_storage, 1);
+ storage->storage = mbox_storage;
if (hierarchy_sep != '\0')
- storage->hierarchy_sep = hierarchy_sep;
- storage->namespace = i_strdup(namespace);
+ storage->storage.hierarchy_sep = hierarchy_sep;
+ storage->storage.namespace = i_strdup(namespace);
storage->dir = i_strdup(home_expand(root_dir));
- storage->inbox_file = i_strdup(home_expand(inbox_file));
+ storage->inbox_path = i_strdup(home_expand(inbox_file));
storage->index_dir = i_strdup(home_expand(index_dir));
storage->user = i_strdup(user);
storage->callbacks = i_new(struct mail_storage_callbacks, 1);
index_storage_init(storage);
- return storage;
+ return &storage->storage;
}
-static void mbox_free(struct mail_storage *storage)
+static void mbox_free(struct mail_storage *_storage)
{
+ struct index_storage *storage = (struct index_storage *)_storage;
+
index_storage_deinit(storage);
- i_free(storage->namespace);
i_free(storage->dir);
- i_free(storage->inbox_file);
+ i_free(storage->inbox_path);
i_free(storage->index_dir);
i_free(storage->user);
- i_free(storage->error);
i_free(storage->callbacks);
i_free(storage);
}
-const char *mbox_fix_mailbox_name(struct mail_storage *storage,
+const char *mbox_fix_mailbox_name(struct index_storage *istorage,
const char *name, int remove_namespace)
{
+ struct mail_storage *storage = &istorage->storage;
char *dup, *p, sep;
size_t len;
return mbox_is_valid_mask(name);
}
-static const char *mbox_get_index_dir(struct mail_storage *storage,
+static const char *mbox_get_index_dir(struct index_storage *storage,
const char *name)
{
const char *p;
}
}
-static int create_mbox_index_dirs(struct mail_storage *storage,
+static int create_mbox_index_dirs(struct index_storage *storage,
const char *name)
{
const char *index_dir;
index_dir = mbox_get_index_dir(storage, name);
if (index_dir == NULL)
- return TRUE;
+ return 0;
if (mkdir_parents(index_dir, CREATE_MODE) < 0) {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(&storage->storage,
"mkdir_parents(%s) failed: %m", index_dir);
- return FALSE;
+ return -1;
}
- return TRUE;
+ return 0;
}
-static int verify_inbox(struct mail_storage *storage)
+static int verify_inbox(struct index_storage *storage)
{
int fd;
/* make sure inbox file itself exists */
- fd = open(storage->inbox_file, O_RDWR | O_CREAT | O_EXCL, 0660);
+ fd = open(storage->inbox_path, O_RDWR | O_CREAT | O_EXCL, 0660);
if (fd != -1)
(void)close(fd);
/* make sure the index directories exist */
- if (!create_mbox_index_dirs(storage, "INBOX"))
- return FALSE;
+ if (create_mbox_index_dirs(storage, "INBOX") < 0)
+ return -1;
- return TRUE;
+ return 0;
}
-static const char *mbox_get_path(struct mail_storage *storage, const char *name)
+static const char *
+mbox_get_path(struct index_storage *storage, const char *name)
{
if (strcasecmp(name, "INBOX") == 0)
- return storage->inbox_file;
+ return storage->inbox_path;
if (full_filesystem_access && (*name == '/' || *name == '~'))
return home_expand(name);
return t_strconcat(storage->dir, "/", name, NULL);
}
-static void mbox_mail_init(struct index_mail *mail)
+static uint32_t mbox_get_recent_count(struct index_mailbox *ibox)
{
- mail->mail.expunge = mbox_storage_expunge;
+ return 0; // FIXME
}
-static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
- enum mailbox_open_flags flags)
+static struct mailbox *
+mbox_open(struct index_storage *storage, const char *name,
+ enum mailbox_open_flags flags)
{
struct index_mailbox *ibox;
struct mail_index *index;
/* name = "INBOX"
path = "<inbox_file>/INBOX"
index_dir = "/mail/.imap/INBOX" */
- path = storage->inbox_file;
+ path = storage->inbox_path;
index_dir = mbox_get_index_dir(storage, "INBOX");
} else {
/* name = "foo/bar"
index_dir = mbox_get_index_dir(storage, name);
}
- index = index_storage_lookup_ref(index_dir, path);
- if (index == NULL) {
- index = mbox_index_alloc(path, index_dir, index_dir);
- index_storage_add(index);
- }
+ index = index_storage_alloc(index_dir, path, MBOX_INDEX_PREFIX);
+ ibox = index_storage_mailbox_init(storage, &mbox_mailbox,
+ index, name, flags);
+ if (ibox == NULL)
+ return NULL;
+
+ ibox->path = i_strdup(path);
+ ibox->mbox_fd = -1;
- ibox = index_storage_mailbox_init(storage, &mbox_mailbox, index,
- name, flags);
- if (ibox != NULL)
- ibox->mail_init = mbox_mail_init;
- return (struct mailbox *) ibox;
+ ibox->get_recent_count = mbox_get_recent_count;
+ ibox->mail_interface = &mbox_mail;
+
+ return &ibox->box;
}
static struct mailbox *
-mbox_open_mailbox(struct mail_storage *storage,
+mbox_mailbox_open(struct mail_storage *_storage,
const char *name, enum mailbox_open_flags flags)
{
+ struct index_storage *storage = (struct index_storage *)_storage;
const char *path;
struct stat st;
- mail_storage_clear_error(storage);
+ mail_storage_clear_error(_storage);
name = mbox_fix_mailbox_name(storage, name, TRUE);
/* INBOX is always case-insensitive */
if (strcasecmp(name, "INBOX") == 0) {
/* make sure inbox exists */
- if (!verify_inbox(storage))
- return FALSE;
+ if (verify_inbox(storage) < 0)
+ return NULL;
return mbox_open(storage, "INBOX", flags);
}
if (!mbox_is_valid_existing_name(name)) {
- mail_storage_set_error(storage, "Invalid mailbox name");
- return FALSE;
+ mail_storage_set_error(_storage, "Invalid mailbox name");
+ return NULL;
}
path = mbox_get_path(storage, name);
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Mailbox isn't selectable: %s", name);
return NULL;
}
/* exists - make sure the required directories are also there */
- if (!create_mbox_index_dirs(storage, name))
+ if (create_mbox_index_dirs(storage, name) < 0)
return NULL;
return mbox_open(storage, name, flags);
}
if (ENOTFOUND(errno)) {
- mail_storage_set_error(storage, "Mailbox doesn't exist: %s",
+ mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
name);
- } else if (!mbox_handle_errors(storage))
- mail_storage_set_critical(storage, "stat(%s) failed: %m", path);
+ } else if (!mbox_handle_errors(storage)) {
+ mail_storage_set_critical(_storage, "stat(%s) failed: %m",
+ path);
+ }
return NULL;
}
-static int mbox_create_mailbox(struct mail_storage *storage, const char *name,
+static int mbox_mailbox_create(struct mail_storage *_storage, const char *name,
int directory)
{
+ struct index_storage *storage = (struct index_storage *)_storage;
const char *path, *p;
struct stat st;
int fd;
- mail_storage_clear_error(storage);
+ mail_storage_clear_error(_storage);
name = mbox_fix_mailbox_name(storage, name, TRUE);
if (!mbox_is_valid_create_name(name)) {
- mail_storage_set_error(storage, "Invalid mailbox name");
- return FALSE;
+ mail_storage_set_error(_storage, "Invalid mailbox name");
+ return -1;
}
/* make sure it doesn't exist already */
path = mbox_get_path(storage, name);
if (stat(path, &st) == 0) {
- mail_storage_set_error(storage, "Mailbox already exists");
- return FALSE;
+ mail_storage_set_error(_storage, "Mailbox already exists");
+ return -1;
}
if (errno != ENOENT && errno != ELOOP && errno != EACCES) {
if (errno == ENOTDIR) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Mailbox doesn't allow inferior mailboxes");
} else {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"stat() failed for mbox file %s: %m", path);
}
- return FALSE;
+ return -1;
}
/* create the hierarchy if needed */
p = t_strdup_until(path, p);
if (mkdir_parents(p, CREATE_MODE) < 0) {
if (mbox_handle_errors(storage))
- return FALSE;
+ return -1;
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"mkdir_parents(%s) failed: %m", p);
- return FALSE;
+ return -1;
}
if (directory) {
/* wanted to create only the directory */
- return TRUE;
+ return 0;
}
}
fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660);
if (fd != -1) {
(void)close(fd);
- return TRUE;
+ return 0;
}
if (errno == EEXIST) {
/* mailbox was just created between stat() and open() call.. */
- mail_storage_set_error(storage, "Mailbox already exists");
+ mail_storage_set_error(_storage, "Mailbox already exists");
} else if (!mbox_handle_errors(storage)) {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"Can't create mailbox %s: %m", name);
}
- return FALSE;
+ return -1;
}
-static int mbox_delete_mailbox(struct mail_storage *storage, const char *name)
+static int mbox_mailbox_delete(struct mail_storage *_storage, const char *name)
{
+ struct index_storage *storage = (struct index_storage *)_storage;
const char *index_dir, *path;
struct stat st;
- mail_storage_clear_error(storage);
+ mail_storage_clear_error(_storage);
name = mbox_fix_mailbox_name(storage, name, TRUE);
if (strcasecmp(name, "INBOX") == 0) {
- mail_storage_set_error(storage, "INBOX can't be deleted.");
- return FALSE;
+ mail_storage_set_error(_storage, "INBOX can't be deleted.");
+ return -1;
}
if (!mbox_is_valid_existing_name(name)) {
- mail_storage_set_error(storage, "Invalid mailbox name");
- return FALSE;
+ mail_storage_set_error(_storage, "Invalid mailbox name");
+ return -1;
}
path = mbox_get_path(storage, name);
if (lstat(path, &st) < 0) {
if (ENOTFOUND(errno)) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Mailbox doesn't exist: %s", name);
} else if (!mbox_handle_errors(storage)) {
- mail_storage_set_critical(storage, "lstat() failed for "
- "%s: %m", path);
+ mail_storage_set_critical(_storage,
+ "lstat() failed for %s: %m", path);
}
- return FALSE;
+ return -1;
}
if (S_ISDIR(st.st_mode)) {
if (index_dir != NULL && rmdir(index_dir) < 0 &&
!ENOTFOUND(errno) && errno != ENOTEMPTY) {
- if (!mbox_handle_errors(storage)) {
- mail_storage_set_critical(storage,
+ if (!mbox_handle_errors(storage) < 0) {
+ mail_storage_set_critical(_storage,
"rmdir() failed for %s: %m", index_dir);
- return FALSE;
+ return -1;
}
}
if (rmdir(path) == 0)
- return TRUE;
+ return 0;
if (ENOTFOUND(errno)) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Mailbox doesn't exist: %s", name);
} else if (errno == ENOTEMPTY) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Folder %s isn't empty, can't delete it.",
name);
} else if (!mbox_handle_errors(storage)) {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"rmdir() failed for %s: %m", path);
}
- return FALSE;
+ return -1;
}
/* first unlink the mbox file */
if (unlink(path) < 0) {
if (ENOTFOUND(errno)) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Mailbox doesn't exist: %s", name);
} else if (!mbox_handle_errors(storage)) {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"unlink() failed for %s: %m", path);
}
- return FALSE;
+ return -1;
}
/* next delete the index directory */
index_storage_destroy_unrefed();
if (unlink_directory(index_dir, TRUE) < 0 && errno != ENOENT) {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"unlink_directory(%s) failed: %m", index_dir);
/* mailbox itself is deleted, so return success
}
}
- return TRUE;
+ return 0;
}
-static int mbox_rename_mailbox(struct mail_storage *storage,
+static int mbox_mailbox_rename(struct mail_storage *_storage,
const char *oldname, const char *newname)
{
+ struct index_storage *storage = (struct index_storage *)_storage;
const char *oldpath, *newpath, *old_indexdir, *new_indexdir, *p;
struct stat st;
- mail_storage_clear_error(storage);
+ mail_storage_clear_error(_storage);
oldname = mbox_fix_mailbox_name(storage, oldname, TRUE);
newname = mbox_fix_mailbox_name(storage, newname, TRUE);
if (!mbox_is_valid_existing_name(oldname) ||
!mbox_is_valid_create_name(newname)) {
- mail_storage_set_error(storage, "Invalid mailbox name");
- return FALSE;
+ mail_storage_set_error(_storage, "Invalid mailbox name");
+ return -1;
}
oldpath = mbox_get_path(storage, oldname);
p = t_strdup_until(newpath, p);
if (mkdir_parents(p, CREATE_MODE) < 0) {
if (mbox_handle_errors(storage))
- return FALSE;
+ return -1;
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"mkdir_parents(%s) failed: %m", p);
- return FALSE;
+ return -1;
}
}
possibility that someone actually tries to rename two mailboxes
to same new one */
if (lstat(newpath, &st) == 0) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Target mailbox already exists");
- return FALSE;
+ return -1;
} else if (!ENOTFOUND(errno) && errno != EACCES) {
- mail_storage_set_critical(storage, "lstat(%s) failed: %m",
+ mail_storage_set_critical(_storage, "lstat(%s) failed: %m",
newpath);
- return FALSE;
+ return -1;
}
/* NOTE: renaming INBOX works just fine with us, it's simply recreated
the next time it's needed. */
if (rename(oldpath, newpath) < 0) {
if (ENOTFOUND(errno)) {
- mail_storage_set_error(storage,
+ mail_storage_set_error(_storage,
"Mailbox doesn't exist: %s", oldname);
} else if (!mbox_handle_errors(storage)) {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"rename(%s, %s) failed: %m", oldpath, newpath);
}
- return FALSE;
+ return -1;
}
/* we need to rename the index directory as well */
if (old_indexdir != NULL) {
if (rename(old_indexdir, new_indexdir) < 0 &&
errno != ENOENT) {
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(_storage,
"rename(%s, %s) failed: %m",
old_indexdir, new_indexdir);
}
}
- return TRUE;
+ return 0;
}
-static int mbox_set_subscribed(struct mail_storage *storage,
+static int mbox_set_subscribed(struct mail_storage *_storage,
const char *name, int set)
{
+ struct index_storage *storage = (struct index_storage *)_storage;
+ const char *path;
+
+ path = t_strconcat(storage->dir, "/" SUBSCRIPTION_FILE_NAME, NULL);
name = mbox_fix_mailbox_name(storage, name, FALSE);
- return subsfile_set_subscribed(storage, name, set);
+ return subsfile_set_subscribed(_storage, path, name, set);
}
-static int mbox_get_mailbox_name_status(struct mail_storage *storage,
+static int mbox_get_mailbox_name_status(struct mail_storage *_storage,
const char *name,
enum mailbox_name_status *status)
{
+ struct index_storage *storage = (struct index_storage *)_storage;
struct stat st;
const char *path;
- mail_storage_clear_error(storage);
+ mail_storage_clear_error(_storage);
name = mbox_fix_mailbox_name(storage, name, TRUE);
if (!mbox_is_valid_existing_name(name)) {
*status = MAILBOX_NAME_INVALID;
- return TRUE;
+ return 0;
}
path = mbox_get_path(storage, name);
if (stat(path, &st) == 0) {
*status = MAILBOX_NAME_EXISTS;
- return TRUE;
+ return 0;
}
if (!mbox_is_valid_create_name(name)) {
*status = MAILBOX_NAME_INVALID;
- return TRUE;
+ return 0;
}
if (ENOTFOUND(errno) || errno == EACCES) {
*status = MAILBOX_NAME_VALID;
- return TRUE;
+ return 0;
} else if (errno == ENOTDIR) {
*status = MAILBOX_NAME_NOINFERIORS;
- return TRUE;
+ return 0;
} else {
- mail_storage_set_critical(storage, "mailbox name status: "
+ mail_storage_set_critical(_storage, "mailbox name status: "
"stat(%s) failed: %m", path);
- return FALSE;
+ return -1;
}
}
static int mbox_storage_close(struct mailbox *box)
{
- struct index_mailbox *ibox = (struct index_mailbox *) box;
- int failed = FALSE;
-
- /* update flags by rewrite mbox file */
- index_storage_init_lock_notify(ibox);
- if (!ibox->index->mailbox_readonly) {
- if (!mbox_index_rewrite(ibox->index)) {
- mail_storage_set_index_error(ibox);
- failed = TRUE;
- }
- }
- ibox->index->set_lock_notify_callback(ibox->index, NULL, NULL);
+ struct index_mailbox *ibox = (struct index_mailbox *)box;
- return index_storage_mailbox_free(box) && !failed;
+ if (ibox->mbox_data_buf != NULL)
+ buffer_free(ibox->mbox_data_buf);
+ index_storage_mailbox_free(box);
+ return 0;
}
static void mbox_storage_auto_sync(struct mailbox *box,
enum mailbox_sync_flags flags,
unsigned int min_newmail_notify_interval)
{
- struct index_mailbox *ibox = (struct index_mailbox *) box;
+ struct index_mailbox *ibox = (struct index_mailbox *)box;
ibox->min_newmail_notify_interval = min_newmail_notify_interval;
if (flags == 0)
index_mailbox_check_remove_all(ibox);
else
- index_mailbox_check_add(ibox, ibox->index->mailbox_path, FALSE);
-}
-
-static int mbox_storage_lock(struct mailbox *box,
- enum mailbox_lock_type lock_type)
-{
- struct index_mailbox *ibox = (struct index_mailbox *) box;
-
- if (lock_type == MAIL_LOCK_UNLOCK) {
- ibox->lock_type = MAIL_LOCK_UNLOCK;
- if (!index_storage_lock(ibox, MAIL_LOCK_UNLOCK))
- return FALSE;
- return TRUE;
- }
-
- i_assert(ibox->lock_type == MAIL_LOCK_UNLOCK);
-
- if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_FLAGS)) != 0) {
- if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE))
- return FALSE;
- } else if ((lock_type & MAILBOX_LOCK_READ) != 0) {
- if (!index_storage_lock(ibox, MAIL_LOCK_SHARED))
- return FALSE;
- }
-
- if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_SAVE)) != 0) {
- /* FIXME: saving doesn't have to sync it, just lock it */
- if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
- MAIL_LOCK_EXCLUSIVE))
- return FALSE;
- }
-
- ibox->lock_type = lock_type;
- return TRUE;
+ index_mailbox_check_add(ibox, ibox->path, FALSE);
}
struct mail_storage mbox_storage = {
mbox_free,
mbox_autodetect,
index_storage_set_callbacks,
- mbox_open_mailbox,
- mbox_create_mailbox,
- mbox_delete_mailbox,
- mbox_rename_mailbox,
- mbox_list_mailbox_init,
- mbox_list_mailbox_deinit,
- mbox_list_mailbox_next,
+ mbox_mailbox_open,
+ mbox_mailbox_create,
+ mbox_mailbox_delete,
+ mbox_mailbox_rename,
+ mbox_mailbox_list_init,
+ mbox_mailbox_list_next,
+ mbox_mailbox_list_deinit,
mbox_set_subscribed,
mbox_get_mailbox_name_status,
mail_storage_get_last_error,
NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL, NULL, NULL,
-
0
};
index_storage_is_readonly,
index_storage_allow_new_keywords,
mbox_storage_close,
- mbox_storage_lock,
index_storage_get_status,
- index_storage_sync,
+ mbox_storage_sync,
mbox_storage_auto_sync,
- index_storage_fetch_uid,
- index_storage_fetch_seq,
+ mbox_transaction_begin,
+ mbox_transaction_commit,
+ mbox_transaction_rollback,
+ index_storage_fetch,
+ index_storage_get_uids,
index_storage_search_get_sorting,
index_storage_search_init,
index_storage_search_deinit,
index_storage_search_next,
- mbox_storage_save_init,
- mbox_storage_save_deinit,
- mbox_storage_save_next,
- index_storage_copy_init,
- index_storage_copy_deinit,
- index_storage_copy,
- mbox_storage_expunge_init,
- mbox_storage_expunge_deinit,
- mbox_storage_expunge_fetch_next,
- index_storage_is_inconsistency_error
+ mbox_save,
+ mail_storage_copy,
+ index_storage_is_inconsistent
};
#ifndef __MBOX_STORAGE_H
#define __MBOX_STORAGE_H
+/* Extra space to leave in X-Keywords header when rewriting mbox */
+#define MBOX_HEADER_EXTRA_SPACE 100
+
+#define SUBSCRIPTION_FILE_NAME "subscriptions"
+#define MBOX_INDEX_PREFIX "dovecot.index"
+
#include "index-storage.h"
-int mbox_storage_copy(struct mailbox *box, struct mailbox *destbox,
- const char *messageset, int uidset);
+struct mbox_transaction_context {
+ struct index_transaction_context ictx;
+
+ struct mbox_save_context *save_ctx;
+ unsigned int mbox_lock_id;
+};
+
+extern struct mail mbox_mail;
-struct mail_save_context *
-mbox_storage_save_init(struct mailbox *box, int transaction);
-int mbox_storage_save_deinit(struct mail_save_context *ctx, int rollback);
-int mbox_storage_save_next(struct mail_save_context *ctx,
- const struct mail_full_flags *flags,
- time_t received_date, int timezone_offset,
- struct istream *data);
+int mbox_set_syscall_error(struct index_mailbox *ibox, const char *function);
struct mailbox_list_context *
-mbox_list_mailbox_init(struct mail_storage *storage, const char *mask,
+mbox_mailbox_list_init(struct mail_storage *storage, const char *mask,
enum mailbox_list_flags flags);
-int mbox_list_mailbox_deinit(struct mailbox_list_context *ctx);
-struct mailbox_list *mbox_list_mailbox_next(struct mailbox_list_context *ctx);
-
-struct mail_expunge_context *
-mbox_storage_expunge_init(struct mailbox *box,
- enum mail_fetch_field wanted_fields, int expunge_all);
-int mbox_storage_expunge_deinit(struct mail_expunge_context *ctx);
-struct mail *mbox_storage_expunge_fetch_next(struct mail_expunge_context *ctx);
-int mbox_storage_expunge(struct mail *mail, struct mail_expunge_context *ctx,
- unsigned int *seq_r, int notify);
-
-const char *mbox_fix_mailbox_name(struct mail_storage *storage,
+int mbox_mailbox_list_deinit(struct mailbox_list_context *ctx);
+struct mailbox_list *mbox_mailbox_list_next(struct mailbox_list_context *ctx);
+
+struct mailbox_transaction_context *
+mbox_transaction_begin(struct mailbox *box, int hide);
+int mbox_transaction_commit(struct mailbox_transaction_context *t);
+void mbox_transaction_rollback(struct mailbox_transaction_context *t);
+
+int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+
+int mbox_save(struct mailbox_transaction_context *t,
+ const struct mail_full_flags *flags,
+ time_t received_date, int timezone_offset,
+ const char *from_envelope, struct istream *data);
+int mbox_save_commit(struct mbox_save_context *ctx);
+void mbox_save_rollback(struct mbox_save_context *ctx);
+
+const char *mbox_fix_mailbox_name(struct index_storage *istorage,
const char *name, int remove_namespace);
int mbox_is_valid_mask(const char *mask);
return FALSE;
}
- t_push();
-
/* <uid validity> <last uid> */
+ t_push();
str = t_strndup(hdr->full_value, hdr->full_value_len);
ctx->base_uid_validity = strtoul(str, &end, 10);
ctx->base_uid_last = strtoul(end, &end, 10);
pos = end - str;
+ t_pop();
while (pos < hdr->full_value_len && IS_LWSP_LF(hdr->full_value[pos]))
pos++;
if (ctx->base_uid_validity == 0) {
/* broken */
- t_pop();
return FALSE;
}
- if (pos == hdr->full_value_len) {
- t_pop();
+ if (pos == hdr->full_value_len)
return TRUE;
- }
// FIXME: save keywords
extern struct mbox_flag_type mbox_status_flags[];
extern struct mbox_flag_type mbox_xstatus_flags[];
-struct mbox_mail {
+struct mbox_sync_mail {
uint32_t uid;
uint8_t flags;
keywords_mask_t keywords;
struct mbox_sync_mail_context {
struct mbox_sync_context *sync_ctx;
- struct mbox_mail *mail;
+ struct mbox_sync_mail *mail;
uint32_t seq;
uoff_t hdr_offset, body_offset;
};
struct mbox_sync_context {
- struct istream *file_input;
- struct istream *input;
+ struct index_mailbox *ibox;
+ struct istream *input, *file_input;
int fd;
const struct mail_index_header *hdr;
uint32_t prev_msg_uid, next_uid;
};
+int mbox_sync(struct index_mailbox *ibox, int last_commit);
void mbox_sync_parse_next_mail(struct istream *input,
struct mbox_sync_mail_context *ctx);
void mbox_sync_update_header(struct mbox_sync_mail_context *ctx,
i_stream_seek(sync_ctx->file_input, source);
o_stream_seek(output, dest);
- istream_raw_mbox_flush(sync_ctx->input);
+ istream_raw_mbox_flush(sync_ctx->file_input);
if (size == (uoff_t)-1) {
input = sync_ctx->file_input;
int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, buffer_t *mails_buf,
uint32_t first_seq, uint32_t last_seq, off_t extra_space)
{
- struct mbox_mail *mails;
+ struct mbox_sync_mail *mails;
size_t size;
uint32_t first_idx, last_idx, extra_per_mail;
*/
#include "lib.h"
+#include "ioloop.h"
#include "buffer.h"
#include "istream.h"
#include "file-set-size.h"
#include "str.h"
#include "write-full.h"
#include "istream-raw-mbox.h"
+#include "mbox-storage.h"
+#include "mbox-file.h"
#include "mbox-sync-private.h"
+#include <sys/stat.h>
+
static int mbox_sync_grow_file(struct mbox_sync_context *sync_ctx,
- struct mbox_mail *mail, uoff_t body_offset,
+ struct mbox_sync_mail *mail, uoff_t body_offset,
uoff_t grow_size)
{
char spaces[1024];
return 0;
}
-int mbox_sync(struct istream *input)
+int mbox_sync(struct index_mailbox *ibox, int last_commit)
{
struct mbox_sync_context sync_ctx;
struct mbox_sync_mail_context mail_ctx;
- struct mbox_mail mail;
+ struct mbox_sync_mail mail;
+ struct mail_index_sync_ctx *index_sync_ctx;
+ struct mail_index_view *sync_view;
+ const struct mail_index_header *hdr;
+ struct istream *input;
uint32_t seq, need_space_seq;
off_t space_diff;
+ uoff_t from_offset, offset;
buffer_t *mails;
- int ret = 0;
+ string_t *header;
+ struct stat st;
+ int readonly, ret = 0;
+
+ if (last_commit) {
+ seq = ibox->commit_log_file_seq;
+ offset = ibox->commit_log_file_offset;
+ } else {
+ seq = 0;
+ offset = 0;
+ }
+
+ ret = mail_index_sync_begin(ibox->index, &index_sync_ctx, &sync_view,
+ seq, offset);
+ if (ret <= 0)
+ return ret;
+
+ if (mbox_file_open_stream(ibox) < 0)
+ return -1;
+
+ if (mail_index_get_header(sync_view, &hdr) < 0)
+ return -1;
+
+ if (ibox->mbox_data_buf == NULL) {
+ ibox->mbox_data_buf =
+ buffer_create_dynamic(default_pool, 512, (size_t)-1);
+ } else {
+ buffer_set_used_size(ibox->mbox_data_buf, 0);
+ }
+
+ readonly = TRUE; // FIXME
+
+ // FIXME: lock the file
mails = buffer_create_dynamic(default_pool, 4096, (size_t)-1);
memset(&sync_ctx, 0, sizeof(sync_ctx));
- sync_ctx.file_input = input;
- sync_ctx.input = i_stream_create_raw_mbox(default_pool, input);
- sync_ctx.fd = i_stream_get_fd(input);
- //sync_ctx.hdr = ;
+ sync_ctx.file_input = ibox->mbox_file_stream;
+ sync_ctx.input = ibox->mbox_stream;
+ sync_ctx.fd = ibox->mbox_fd;
+ sync_ctx.hdr = hdr;
input = sync_ctx.input;
+ header = str_new(default_pool, 4096);
space_diff = 0; need_space_seq = 0; seq = 1;
for (seq = 1; !input->eof; seq++) {
+ from_offset = input->v_offset;
+
memset(&mail, 0, sizeof(mail));
memset(&mail_ctx, 0, sizeof(mail_ctx));
mail_ctx.sync_ctx = &sync_ctx;
mail_ctx.mail = &mail;
mail_ctx.seq = seq;
+ mail_ctx.header = header;
mbox_sync_parse_next_mail(input, &mail_ctx);
+ if (input->v_offset == from_offset) {
+ /* this was the last mail */
+ break;
+ }
+
mail.body_size =
istream_raw_mbox_get_size(input,
mail_ctx.content_length);
buffer_append(mails, &mail, sizeof(mail));
- if (mail_ctx.need_rewrite) {
+ /* save the offset permanently with recent flag state */
+ from_offset <<= 1;
+ if ((mail.flags & MBOX_NONRECENT) != 0)
+ from_offset |= 1;
+ buffer_append(ibox->mbox_data_buf,
+ &from_offset, sizeof(from_offset));
+
+ if (mail_ctx.need_rewrite && !readonly) {
mbox_sync_update_header(&mail_ctx, NULL);
if ((ret = mbox_sync_try_rewrite(&mail_ctx)) < 0)
break;
ret = -1;
}
- i_stream_unref(input);
- return ret < 0 ? -1 : 0;
-}
-
-#if 0
-int mbox_sync(void)
-{
- struct mail_index_view *sync_view;
- struct mail_index_sync_ctx *sync_ctx;
- struct mail_index_sync_rec sync_rec;
- struct mbox_sync_context ctx;
- struct mbox_sync_mail_context mail_ctx;
- struct mbox_mail mail;
- string_t *header;
- uint32_t seq;
- unsigned int need_space_seq;
- uoff_t missing_space;
- buffer_t *mails;
- int ret;
-
- memset(&ctx, 0, sizeof(ctx));
- /*ctx.index = storage->index;
- ctx.input = storage->input;*/
- ctx.fd = i_stream_get_fd(ctx.input);
-
- header = str_new(default_pool, 4096);
-
- if (mail_index_sync_begin(ctx.index, &sync_ctx, &sync_view, 0, 0) < 0)
- return -1;
-
- ctx.hdr = mail_index_get_header(sync_view);
- ctx.next_uid = ctx.hdr->next_uid;
-
- seq = 1;
- while ((ret = mail_index_sync_next(sync_ctx, &sync_rec)) > 0) {
- while (seq < sync_rec.seq1) {
- seq++;
- }
- switch (sync_rec.type) {
- case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
- break;
- case MAIL_INDEX_SYNC_TYPE_FLAGS:
- break;
- }
+ if (fstat(ibox->mbox_fd, &st) < 0) {
+ mbox_set_syscall_error(ibox, "fstat()");
+ ret = -1;
}
- while (!ctx.input->eof) {
- memset(&mail_ctx, 0, sizeof(mail_ctx));
- mail_ctx.parent = &ctx;
- mail_ctx.header = header;
- mail_ctx.seq = seq;
+ if (ret < 0) {
+ st.st_mtime = 0;
+ st.st_size = 0;
+ }
- mail_ctx.hdr_offset = ctx.input->v_offset;
- mbox_sync_mail_parse_headers(&mail_ctx);
- mail_ctx.body_offset = ctx.input->v_offset;
- mail_ctx.body_size =
- istream_raw_mbox_get_size(ctx.input,
- mail_ctx.content_length);
+ if (mail_index_sync_end(index_sync_ctx, st.st_mtime, st.st_size) < 0)
+ ret = -1;
- mbox_sync_mail_add_missing_headers(&mail_ctx);
+ str_free(header);
+ return ret < 0 ? -1 : 0;
+}
- ret = mbox_sync_try_rewrite_headers(&mail_ctx, &missing_space);
- if (ret < 0)
- break;
- if (missing_space != 0) {
- ctx.space_diff -= missing_space;
- } else {
- ctx.space_diff += mail_ctx.extra_space;
- }
+int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+{
+ struct index_mailbox *ibox = (struct index_mailbox *)box;
- if (ctx.first_spacy_msg_offset == 0)
- ctx.first_spacy_msg_offset = mail_ctx.hdr_offset;
+ if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
+ ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) {
+ ibox->sync_last_check = ioloop_time;
- ctx.prev_msg_uid = mail_ctx.uid;
- istream_raw_mbox_next(ctx.input, mail_ctx.content_length);
+ if (mbox_sync(ibox, FALSE) < 0)
+ return -1;
}
- str_free(header);
- return 0;
+
+ return index_storage_sync(box, flags);
}
-#endif
--- /dev/null
+/* Copyright (C) 2004 Timo Sirainen */
+
+#include "lib.h"
+#include "mbox-storage.h"
+#include "mbox-lock.h"
+#include "mbox-sync-private.h"
+
+struct mailbox_transaction_context *
+mbox_transaction_begin(struct mailbox *box, int hide)
+{
+ struct index_mailbox *ibox = (struct index_mailbox *)box;
+ struct mbox_transaction_context *t;
+
+ t = i_new(struct mbox_transaction_context, 1);
+ t->ictx.mailbox_ctx.box = box;
+ t->ictx.ibox = ibox;
+ t->ictx.trans = mail_index_transaction_begin(ibox->view, hide);
+ return &t->ictx.mailbox_ctx;
+}
+
+int mbox_transaction_commit(struct mailbox_transaction_context *_t)
+{
+ struct mbox_transaction_context *t =
+ (struct mbox_transaction_context *)_t;
+ struct index_mailbox *ibox = t->ictx.ibox;
+ unsigned int lock_id = t->mbox_lock_id;
+ int ret = 0;
+
+ if (t->save_ctx != NULL)
+ ret = mbox_save_commit(t->save_ctx);
+
+ if (ret == 0) {
+ if (index_transaction_commit(_t) < 0)
+ ret = -1;
+ } else {
+ index_transaction_rollback(_t);
+ }
+
+ if (ret == 0) {
+ if (mbox_sync(ibox, TRUE) < 0)
+ ret = -1;
+ }
+
+ if (lock_id != 0) {
+ if (mbox_unlock(ibox, lock_id) < 0)
+ ret = -1;
+ }
+ return ret;
+}
+
+void mbox_transaction_rollback(struct mailbox_transaction_context *_t)
+{
+ struct mbox_transaction_context *t =
+ (struct mbox_transaction_context *)_t;
+ struct index_mailbox *ibox = t->ictx.ibox;
+
+ if (t->save_ctx != NULL)
+ mbox_save_rollback(t->save_ctx);
+
+ if (t->mbox_lock_id != 0)
+ (void)mbox_unlock(ibox, t->mbox_lock_id);
+ index_transaction_rollback(_t);
+}