/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "base64.h"
#include "hostpid.h"
#include "randgen.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "write-full.h"
#include "istream-header-filter.h"
#include "istream-crlf.h"
#include "istream-concat.h"
#include "message-parser.h"
#include "mail-user.h"
#include "index-mail.h"
#include "mbox-storage.h"
#include "mbox-file.h"
#include "mbox-from.h"
#include "mbox-lock.h"
#include "mbox-md5.h"
#include "mbox-sync-private.h"
#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <utime.h>
struct mbox_save_context {
char last_char;
char *x_delivery_id_header;
};
{
}
{
char ch;
int fd;
*offset = 0;
return 0;
}
return -1;
}
return 0;
return -1;
}
return -1;
}
if (ch != '\n') {
return -1;
}
*offset += 1;
}
return 0;
}
{
return -1;
}
return 0;
}
const char *from_envelope)
{
int ret;
T_BEGIN {
const char *line;
if (from_envelope == NULL) {
} else if (*from_envelope == '\0') {
/* can't write empty envelope */
from_envelope = "MAILER-DAEMON";
}
/* save in local timezone, no matter what it was given with */
} T_END;
return ret;
}
{
const char *str;
/* we can't seek, don't set Content-Length */
return 0;
}
/* write Content-Length headers */
/* flush manually here so that we don't confuse seek() errors with
buffer flushing errors */
return -1;
}
return -1;
}
return -1;
}
return -1;
}
return 0;
}
{
/* open a new view to get the header. this is required if we just
synced the mailbox so we can get updated next_uid. */
}
const struct mbox_flag_type *flags_list)
{
int i;
for (i = 0; flags_list[i].chr != 0; i++) {
}
}
{
/* write the Status: header always. It always gets added soon anyway. */
if ((flags & XSTATUS_FLAGS_MASK) != 0) {
}
}
static void
struct mail_keywords *keywords)
{
const char *const *keyword_names;
for (i = 0; i < count; i++) {
}
}
static int
struct mbox_transaction_context *t)
{
int ret;
"Read-only mbox");
return -1;
}
/* first appended mail in this transaction */
if (t->write_lock_id == 0) {
return -1;
}
if (mbox_file_open(mbox) < 0)
return -1;
}
/* update mbox_sync_dirty state */
if (ret < 0)
return -1;
}
/* we'll need to assign UID for the mail immediately. */
return -1;
}
/* the syncing above could have changed the append offset */
return -1;
FALSE);
}
return 0;
}
static void
struct message_header_line *hdr,
{
/* we can't allow From_-lines in headers. there's no
legitimate reason for allowing them in any case,
so just drop them. */
return;
}
}
}
{
void *randbuf;
sizeof(ioloop_timeval.tv_usec));
}
static struct istream *
{
/* filter out unwanted headers and keep track of headers' MD5 sum */
MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) != 0) {
/* we're using MD5 sums to generate POP3 UIDLs.
clients don't like it much if there are duplicates,
so make sure that there can't be any by appending
our own X-Delivery-ID header. */
const char *hdr;
T_BEGIN {
} T_END;
}
/* convert linefeeds to wanted format */
/* caching creates a tee stream */
ret = cache_input;
return ret;
}
struct mail_save_context *
{
}
return t->save_ctx;
}
{
/* FIXME: we could write timezone_offset to From-line.. */
if (mbox_save_init_file(ctx, t) < 0) {
return -1;
}
/* we can use the wanted UID */
}
/* writing the first mail. Insert X-IMAPbase as well. */
}
save_flags & ~MAIL_RECENT);
}
if (mdata->min_modseq != 0) {
mdata->min_modseq);
}
/* parse and cache the mail headers as we read it */
}
else
}
{
const unsigned char *data;
if (size > 0) {
return -1;
}
}
return 0;
}
{
if (mbox_save_body_input(ctx) < 0)
return -1;
/* i_stream_read() may have returned 0 at EOF
because of this parser */
if (ret == 0)
return 0;
}
return 0;
}
{
/* append our own headers and ending empty line */
return -1;
}
return 0;
}
{
const unsigned char *data;
return -1;
/* writing body */
return mbox_save_body(ctx);
}
for (i = 0; i < size; i++) {
if (data[i] == '\n' &&
/* end of headers. we don't need to worry about
CRs because they're dropped */
break;
}
}
if (i != size) {
/* found end of headers. write the rest of them
(not including the finishing empty line) */
return -1;
}
break;
}
return -1;
}
}
if (ret == 0)
return 0;
return -1;
}
}
hdr_md5_sum, NULL);
}
if (mbox_save_finish_headers(ctx) < 0)
return -1;
/* write body */
if (mbox_save_body_input(ctx) < 0)
return -1;
}
{
(void)mbox_save_finish_headers(ctx);
/* make sure everything is written */
}
T_BEGIN {
if (mbox_write_content_length(ctx) < 0 ||
mbox_append_lf(ctx) < 0)
} T_END;
}
/* saving this mail failed - truncate back to beginning of it */
}
}
}
{
(void)mbox_save_finish(_ctx);
}
{
}
{
return;
/* failed, truncate file back to original size. output stream needs to
be flushed before truncating so unref() won't write anything. */
}
{
int ret = 0;
ret = -1;
}
if (ret == 0) {
}
}
/* try to set atime back to its original value.
(it'll fail with EPERM for shared mailboxes where we aren't
the file's owner) */
}
/* flush the final LF */
}
ret = -1;
}
}
if (ret < 0)
return ret;
}
{
/* after saving mails with UIDs we need to update
the last-uid */
}
}
{
}