~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/lib-mail/istream-qp-decoder.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "buffer.h"
 
5
#include "hex-binary.h"
 
6
#include "istream-private.h"
 
7
#include "quoted-printable.h"
 
8
#include "istream-qp.h"
 
9
 
 
10
struct qp_decoder_istream {
 
11
        struct istream_private istream;
 
12
};
 
13
 
 
14
static int
 
15
i_stream_read_parent(struct istream_private *stream, size_t *prev_size)
 
16
{
 
17
        size_t size;
 
18
        ssize_t ret;
 
19
 
 
20
        size = i_stream_get_data_size(stream->parent);
 
21
        if (size >= 4 && size != *prev_size) {
 
22
                *prev_size = size;
 
23
                return 1;
 
24
        }
 
25
 
 
26
        ret = i_stream_read(stream->parent);
 
27
        if (ret <= 0) {
 
28
                stream->istream.stream_errno = stream->parent->stream_errno;
 
29
                stream->istream.eof = stream->parent->eof;
 
30
                return ret;
 
31
        }
 
32
        *prev_size = i_stream_get_data_size(stream->parent);
 
33
        return 1;
 
34
}
 
35
 
 
36
static int
 
37
i_stream_qp_try_decode_input(struct qp_decoder_istream *bstream, bool eof)
 
38
{
 
39
        struct istream_private *stream = &bstream->istream;
 
40
        const unsigned char *data;
 
41
        size_t size, avail, buffer_avail, pos;
 
42
        buffer_t buf;
 
43
        int ret;
 
44
 
 
45
        data = i_stream_get_data(stream->parent, &size);
 
46
        if (size == 0)
 
47
                return 0;
 
48
 
 
49
        /* normally the decoded quoted-printable content can't be larger than
 
50
           the encoded content, but because we always use CRLFs, it may use
 
51
           twice as much space by only converting LFs to CRLFs. */
 
52
        i_stream_try_alloc(stream, size, &avail);
 
53
        buffer_avail = stream->buffer_size - stream->pos;
 
54
 
 
55
        if (size > buffer_avail/2) {
 
56
                /* can't fit everything to destination buffer.
 
57
                   write as much as we can. */
 
58
                size = buffer_avail/2;
 
59
                if (size == 0)
 
60
                        return -2;
 
61
        }
 
62
 
 
63
        buffer_create_from_data(&buf, stream->w_buffer + stream->pos,
 
64
                                buffer_avail);
 
65
        ret = !eof ? quoted_printable_decode(data, size, &pos, &buf) :
 
66
                quoted_printable_decode_final(data, size, &pos, &buf);
 
67
        if (ret < 0) {
 
68
                io_stream_set_error(&stream->iostream,
 
69
                        "Invalid quoted-printable data: 0x%s",
 
70
                        binary_to_hex(data+pos, I_MAX(size-pos, 8)));
 
71
                stream->istream.stream_errno = EINVAL;
 
72
                return -1;
 
73
        }
 
74
 
 
75
        stream->pos += buf.used;
 
76
        i_stream_skip(stream->parent, pos);
 
77
        return pos > 0 ? 1 : 0;
 
78
}
 
79
 
 
80
static ssize_t i_stream_qp_decoder_read(struct istream_private *stream)
 
81
{
 
82
        struct qp_decoder_istream *bstream =
 
83
                (struct qp_decoder_istream *)stream;
 
84
        const unsigned char *data;
 
85
        size_t pre_count, post_count, size;
 
86
        int ret;
 
87
        size_t prev_size = 0;
 
88
 
 
89
        do {
 
90
                ret = i_stream_read_parent(stream, &prev_size);
 
91
                if (ret <= 0) {
 
92
                        if (ret != -1 || stream->istream.stream_errno != 0)
 
93
                                return 0;
 
94
 
 
95
                        ret = i_stream_qp_try_decode_input(bstream, TRUE);
 
96
                        if (ret == 0) {
 
97
                                /* ended with =[whitespace] but without LF */
 
98
                                stream->istream.eof = TRUE;
 
99
                                return -1;
 
100
                        }
 
101
                        /* partial qp input */
 
102
                        i_assert(ret < 0);
 
103
                        data = i_stream_get_data(stream->parent, &size);
 
104
                        io_stream_set_error(&stream->iostream,
 
105
                                "quoted-printable input ends with a partial block: 0x%s",
 
106
                                binary_to_hex(data, size));
 
107
                        stream->istream.stream_errno = EINVAL;
 
108
                        return -1;
 
109
                }
 
110
 
 
111
                /* encode as much data as fits into destination buffer */
 
112
                pre_count = stream->pos - stream->skip;
 
113
                while ((ret = i_stream_qp_try_decode_input(bstream, FALSE)) > 0) ;
 
114
                post_count = stream->pos - stream->skip;
 
115
        } while (ret == 0 && pre_count == post_count);
 
116
 
 
117
        if (ret < 0)
 
118
                return ret;
 
119
 
 
120
        i_assert(post_count > pre_count);
 
121
        return post_count - pre_count;
 
122
}
 
123
 
 
124
static void
 
125
i_stream_qp_decoder_seek(struct istream_private *stream,
 
126
                             uoff_t v_offset, bool mark)
 
127
{
 
128
        if (v_offset < stream->istream.v_offset) {
 
129
                /* seeking backwards - go back to beginning and seek
 
130
                   forward from there. */
 
131
                stream->parent_expected_offset = stream->parent_start_offset;
 
132
                stream->skip = stream->pos = 0;
 
133
                stream->istream.v_offset = 0;
 
134
                i_stream_seek(stream->parent, 0);
 
135
        }
 
136
        i_stream_default_seek_nonseekable(stream, v_offset, mark);
 
137
}
 
138
 
 
139
struct istream *i_stream_create_qp_decoder(struct istream *input)
 
140
{
 
141
        struct qp_decoder_istream *bstream;
 
142
 
 
143
        bstream = i_new(struct qp_decoder_istream, 1);
 
144
        bstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
 
145
 
 
146
        bstream->istream.read = i_stream_qp_decoder_read;
 
147
        bstream->istream.seek = i_stream_qp_decoder_seek;
 
148
 
 
149
        bstream->istream.istream.readable_fd = FALSE;
 
150
        bstream->istream.istream.blocking = input->blocking;
 
151
        bstream->istream.istream.seekable = input->seekable;
 
152
        return i_stream_create(&bstream->istream, input,
 
153
                               i_stream_get_fd(input));
 
154
}