Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/mail-save.c @ 1848:8222937d4434 HEAD
Fixes to make copying mail inside same mbox working.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 29 Oct 2003 15:37:33 +0200 |
parents | 280e6d3772c9 |
children | e19d3d8632b7 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "istream.h" #include "ostream.h" #include "message-parser.h" #include "mail-storage.h" #include "mail-save.h" static int write_with_crlf(struct ostream *output, const void *v_data, size_t size) { const unsigned char *data = v_data; size_t i, start; i_assert(size <= SSIZE_T_MAX); if (size == 0) return 0; start = 0; for (i = 0; i < size; i++) { if (data[i] == '\n' && (i == 0 || data[i-1] != '\r')) { /* missing CR */ if (o_stream_send(output, data + start, i - start) < 0) return -1; if (o_stream_send(output, "\r", 1) < 0) return -1; /* \n is written next time */ start = i; } } /* if last char is \r, leave it to buffer */ if (data[size-1] == '\r') size--; if (o_stream_send(output, data + start, size - start) < 0) return -1; return size; } static int write_with_lf(struct ostream *output, const void *v_data, size_t size) { const unsigned char *data = v_data; size_t i, start; i_assert(size <= SSIZE_T_MAX); if (size == 0) return 0; start = 0; for (i = 0; i < size; i++) { if (data[i] == '\n' && i > 0 && data[i-1] == '\r') { /* \r\n - skip \r */ if (o_stream_send(output, data + start, i - start - 1) < 0) return -1; /* \n is written next time */ start = i; } } /* if last char is \r, leave it to buffer */ if (data[size-1] == '\r') size--; if (o_stream_send(output, data + start, size - start) < 0) return -1; return size; } static void set_write_error(struct mail_storage *storage, struct ostream *output, const char *path) { errno = output->stream_errno; if (ENOSPACE(errno)) mail_storage_set_error(storage, "Not enough disk space"); else { mail_storage_set_critical(storage, "Can't write to file %s: %m", path); } } static int save_headers(struct istream *input, struct ostream *output, header_callback_t *header_callback, void *context, write_func_t *write_func) { struct message_header_parser_ctx *hdr_ctx; struct message_header_line *hdr; int ret, failed = FALSE; hdr_ctx = message_parse_header_init(input, NULL); while ((hdr = message_parse_header_next(hdr_ctx)) != NULL) { ret = header_callback(hdr->name, write_func, context); if (ret <= 0) { if (ret < 0) { failed = TRUE; break; } continue; } if (!hdr->eoh) { if (!hdr->continued) { (void)o_stream_send(output, hdr->name, hdr->name_len); (void)o_stream_send(output, ": ", 2); } (void)o_stream_send(output, hdr->value, hdr->value_len); if (!hdr->no_newline) write_func(output, "\n", 1); } } if (!failed) { if (header_callback(NULL, write_func, context) < 0) failed = TRUE; /* end of headers */ write_func(output, "\n", 1); } message_parse_header_deinit(hdr_ctx); return !failed; } int mail_storage_save(struct mail_storage *storage, const char *path, struct istream *input, struct ostream *output, int crlf, header_callback_t *header_callback, void *context) { write_func_t *write_func; const unsigned char *data; size_t size; ssize_t ret; int failed; write_func = crlf ? write_with_crlf : write_with_lf; if (header_callback != NULL) { if (!save_headers(input, output, header_callback, context, write_func)) return FALSE; } failed = FALSE; for (;;) { data = i_stream_get_data(input, &size); if (!failed) { ret = write_func(output, data, size); if (ret < 0) { set_write_error(storage, output, path); failed = TRUE; } else { size = ret; } } i_stream_skip(input, size); ret = i_stream_read(input); if (ret < 0) { errno = input->stream_errno; if (errno == 0) { /* EOF */ i_warning("%lld vs %lld\n", input->v_offset, input->v_limit); if (input->v_offset != input->v_limit && input->v_limit != 0) { /* too early */ mail_storage_set_error(storage, "Unexpected EOF"); failed = TRUE; } break; } else if (errno == EAGAIN) { mail_storage_set_error(storage, "Timeout while waiting for input"); } else { mail_storage_set_critical(storage, "Error reading mail from client: %m"); } failed = TRUE; break; } } return !failed; }