Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/mbox/mbox-save.c @ 1039:793f05a7e50e HEAD
signed/unsigned/const pointer fixes
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 27 Jan 2003 04:05:32 +0200 |
parents | 4bcebdcf052b |
children | 539b7336b68a |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "hostpid.h" #include "ostream.h" #include "write-full.h" #include "mbox-index.h" #include "mbox-lock.h" #include "mbox-storage.h" #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <netdb.h> struct mail_save_context { struct index_mailbox *ibox; int transaction; struct ostream *output; uoff_t sync_offset; }; static char my_hostdomain[256] = ""; static int write_error(struct mail_save_context *ctx) { if (errno == ENOSPC) { mail_storage_set_error(ctx->ibox->box.storage, "Not enough disk space"); } else { mail_storage_set_critical(ctx->ibox->box.storage, "Error writing to mbox file %s: %m", ctx->ibox->index->mailbox_path); } return FALSE; } static int mbox_seek_to_end(struct mail_save_context *ctx, uoff_t *offset) { struct stat st; char ch; int fd; fd = ctx->ibox->index->mbox_fd; if (fstat(fd, &st) < 0) { mail_storage_set_critical(ctx->ibox->box.storage, "fstat() failed for mbox file %s: %m", ctx->ibox->index->mailbox_path); return FALSE; } *offset = (uoff_t)st.st_size; if (st.st_size == 0) return TRUE; if (lseek(fd, st.st_size-1, SEEK_SET) < 0) { mail_storage_set_critical(ctx->ibox->box.storage, "lseek() failed for mbox file %s: %m", ctx->ibox->index->mailbox_path); return FALSE; } if (read(fd, &ch, 1) != 1) { mail_storage_set_critical(ctx->ibox->box.storage, "read() failed for mbox file %s: %m", ctx->ibox->index->mailbox_path); return FALSE; } if (ch != '\n') { if (write_full(fd, "\n", 1) < 0) return write_error(ctx); *offset += 1; } return TRUE; } static int mbox_append_lf(struct mail_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) { const char *sender, *line, *name; if (*my_hostdomain == '\0') { struct hostent *hent; hostpid_init(); hent = gethostbyname(my_hostname); name = hent != NULL ? hent->h_name : NULL; if (name == NULL) { /* failed, use just the hostname */ name = my_hostname; } strocpy(my_hostdomain, name, sizeof(my_hostdomain)); } sender = t_strconcat(ctx->ibox->box.storage->user, "@", my_hostdomain, NULL); /* save in local timezone, no matter what it was given with */ line = mbox_from_create(sender, received_date); if (o_stream_send_str(ctx->output, line) < 0) return write_error(ctx); return TRUE; } static int write_flags(struct mail_save_context *ctx, const struct mail_full_flags *full_flags) { enum mail_flags flags = full_flags->flags; const char *str; unsigned int field; unsigned int i; if (flags == 0) return TRUE; if (flags & MAIL_SEEN) { if (o_stream_send_str(ctx->output, "Status: R\n") < 0) return write_error(ctx); } if (flags & (MAIL_ANSWERED|MAIL_DRAFT|MAIL_FLAGGED|MAIL_DELETED)) { str = t_strconcat("X-Status: ", (flags & MAIL_ANSWERED) ? "A" : "", (flags & MAIL_DRAFT) ? "D" : "", (flags & MAIL_FLAGGED) ? "F" : "", (flags & MAIL_DELETED) ? "T" : "", "\n", NULL); if (o_stream_send_str(ctx->output, str) < 0) return write_error(ctx); } if (flags & MAIL_CUSTOM_FLAGS_MASK) { if (o_stream_send_str(ctx->output, "X-Keywords:") < 0) return write_error(ctx); field = 1 << MAIL_CUSTOM_FLAG_1_BIT; for (i = 0; i < full_flags->custom_flags_count; i++) { const char *custom_flag = full_flags->custom_flags[i]; if ((flags & field) && custom_flag != NULL) { if (o_stream_send(ctx->output, " ", 1) < 0) return write_error(ctx); if (o_stream_send_str(ctx->output, custom_flag) < 0) return write_error(ctx); } field <<= 1; } if (o_stream_send(ctx->output, "\n", 1) < 0) return write_error(ctx); } return TRUE; } 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) { enum mail_flags real_flags; int failed; /* we don't need the real flag positions, easier to keep using our own. they need to be checked/added though. */ real_flags = flags->flags; if (!index_mailbox_fix_custom_flags(ctx->ibox, &real_flags, flags->custom_flags, flags->custom_flags_count)) return FALSE; t_push(); if (!write_from_line(ctx, received_date) || !write_flags(ctx, flags) || !index_storage_save(ctx->ibox->box.storage, ctx->ibox->index->mailbox_path, data, ctx->output) || !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; } failed = TRUE; } else { if (!ctx->transaction) ctx->sync_offset = ctx->output->offset; failed = FALSE; } t_pop(); return !failed; } struct mail_save_context * mbox_storage_save_init(struct mailbox *box, int transaction) { struct index_mailbox *ibox = (struct index_mailbox *) box; struct mail_save_context *ctx; if (box->readonly) { mail_storage_set_error(box->storage, "Mailbox is read-only"); return NULL; } if (!index_storage_sync_and_lock(ibox, FALSE, MAIL_LOCK_EXCLUSIVE)) return NULL; ctx = i_new(struct mail_save_context, 1); ctx->ibox = ibox; ctx->transaction = transaction; if (!mbox_seek_to_end(ctx, &ctx->sync_offset)) { i_free(ctx); return NULL; } ctx->output = o_stream_create_file(ibox->index->mbox_fd, default_pool, 4096, 0, FALSE); o_stream_set_blocking(ctx->output, 60000, NULL, NULL); return ctx; } int mbox_storage_save_deinit(struct mail_save_context *ctx, int rollback) { int failed = FALSE; if (!index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK)) failed = TRUE; if (o_stream_flush(ctx->output) < 0) failed = TRUE; o_stream_unref(ctx->output); if (rollback && ctx->sync_offset != (uoff_t)-1) { if (ftruncate(ctx->ibox->index->mbox_fd, ctx->sync_offset) < 0) { mail_storage_set_critical(ctx->ibox->box.storage, "ftruncate(%s) failed: %m", ctx->ibox->index->mailbox_path); failed = TRUE; } } i_free(ctx); return !failed; }