~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002101901

« back to all changes in this revision

Viewing changes to src/lib-mail/message-header-encode.c

  • Committer: Chuck Short
  • Date: 2010-01-21 20:21:25 UTC
  • mfrom: (4.1.11 squeeze)
  • Revision ID: zulcss@ubuntu.com-20100121202125-pme73o491kfwj5nc
* Merge from debian testing, remaining changes:
  + Add new binary pkg dovecot-postfix that integrates postfix and dovecot
    automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restriction
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
  + debian/dovecot-postfix.dirs: create backup directory for postfix's config
    configuration
  + restart postfix and dovecot.
  + debian/dovecot-postfix.postrm:
    - remove all dovecot related configuration from postfix.
    - restart postfix and dovecot.
  + debian/dovecot-common.init:
    - check if /etc/dovecot/dovecot-postfix.conf exists and use it
      as the configuration file if so.
  + debian/patches/warning-ubuntu-postfix.dpatch
    - add warning about dovecot-postfix.conf in dovecot default
      configuration file
  + debian/patches/dovecot-postfix.conf.diff:
    - Ubuntu server custom changes to the default dovecot configuration for
      better interfation with postfix.
    - enable sieve plugin.
    - Ubuntu server custom changes to the default dovecot configuration for
      better integration with postfix:
      - enable imap, pop3, imaps, pop3s and managesieve by default.
      - enable dovecot LDA (deliver).
      - enable SASL auth socket in postfix private directory
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules: install profile.
     - debian/control: suggest ufw.
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). (LP: #254721)
   + debian/control: Update Vcs-* headers.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
* New upstream release.
* debian/patches/gold-fix.patch: Removed. Fixed upstream.
* Moved libexec to lib corrections in dovecot-managesieve.patch and
  dovecot-managesieve-dist.patch to dovecot-example.patch
* debian/patches/dovecot-mboxlocking.patch: Regenerated to avoid FTBFS
  when quilt isn't installed.
* debian/patches/quota-mountpoint.patch: Removed. Not needed anymore.
* debian/patches/dovecot-quota.patch: Removed. Quotas aren't properly
  enabled unless mail_plugins = quota imap_quota.
* debian/patches/gold-fix.patch: Fixed configure script to build even
  with binutils-gold or --no-add-needed linker flag (Closes: #554306)
* debian/dovecot-common.init: fixed LSB headers. Thanks to Pascal Volk.
  (Closes: #558040)
* debian/changelog: added CVE references to previous changelog entry.
* debian/rules: checked up the build system. It's not fragile anymore.
  (Closes: 493803)
* debian/dovecot-common.postinst: Now invoking dpkg-reconfigure
  on dovecot-common is enough to generate new certificates
  if the previous ones were removed. (Closes: #545582)
* debian/rules: No longer install convert-tool in /usr/bin.
  It isn't an user utility and it should stay in /usr/lib/dovecot
  like all other similar tool.
* New upstream release. (Closes: #557601)
* [SECURITY] Fixes local information disclosure and denial of service.
  (see: http://www.dovecot.org/list/dovecot-news/2009-November/000143.html
  and CVE-2009-3897)
* Added myself to uploaders.
* Switched to the new source format "3.0 (quilt)":
  - removed dpatch from build-depends
  - removed debian/README.source because now we use only standard
    dpkg features
  - regenerated all patches
* Prepared to switch to multi-origin source:
  - recreated dovecot-libsieve.patch and dovecot-managesieve-dist.patch
    starting from the upstream tarball
  - removed all autotools related build-depends and build-conflict
  - renamed dovecot-libsieve and dovecot-managesieve directories
    to libsieve and managesieve.
* debian/rules: Moved the configuration of libsieve and managesieve from
  the build phase to the configuration phase
* Added dovecot-dbg package  with debugging symbols.  Thanks Stephan Bosch.
  (Closes: #554710)
* Fixed some stray libexec'isms in the default configuration.
* New upstream release.
* debian/dovecot-common.init:
  - use $CONF when starting the daemon. (Closes: #549944)
  - always output start/stop messages. (Closes: #523810)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "str.h"
 
5
#include "base64.h"
 
6
#include "message-header-encode.h"
 
7
 
 
8
#define MIME_WRAPPER_LEN (strlen("=?utf-8?q?""?="))
 
9
#define MIME_MAX_LINE_LEN 76
 
10
 
 
11
#define IS_LWSP(c) \
 
12
        ((c) == ' ' || (c) == '\t' || (c) == '\n')
 
13
 
 
14
static bool input_idx_need_encoding(const unsigned char *input, unsigned int i)
 
15
{
 
16
        if ((input[i] & 0x80) != 0)
 
17
                return TRUE;
 
18
 
 
19
        if (input[i] == '=' && input[i+1] == '?' &&
 
20
            (i == 0 || IS_LWSP(input[i-1])))
 
21
                return TRUE;
 
22
        return FALSE;
 
23
}
 
24
 
 
25
static unsigned int str_last_line_len(string_t *str)
 
26
{
 
27
        const unsigned char *data = str_data(str);
 
28
        unsigned int i = str_len(str);
 
29
 
 
30
        while (i > 0 && data[i-1] != '\n')
 
31
                i--;
 
32
        return str_len(str) - i;
 
33
}
 
34
 
 
35
void message_header_encode_q(const unsigned char *input, unsigned int len,
 
36
                             string_t *output)
 
37
{
 
38
        unsigned int i, line_len, line_len_left;
 
39
 
 
40
        line_len = str_last_line_len(output);
 
41
        if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - 3) {
 
42
                str_append(output, "\n\t");
 
43
                line_len = 1;
 
44
        }
 
45
 
 
46
        str_append(output, "=?utf-8?q?");
 
47
        line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
 
48
        for (i = 0; i < len; i++) {
 
49
                if (line_len_left < 3) {
 
50
                        /* if we're not at the beginning of a character,
 
51
                           go backwards until we are */
 
52
                        while ((input[i] & 0xc0) == 0x80) {
 
53
                                str_truncate(output, str_len(output)-3);
 
54
                                i--;
 
55
                        }
 
56
                        str_append(output, "?=\n\t=?utf-8?q?");
 
57
                        line_len_left = MIME_MAX_LINE_LEN -
 
58
                                MIME_WRAPPER_LEN - 1;
 
59
                }
 
60
                switch (input[i]) {
 
61
                case ' ':
 
62
                        str_append_c(output, '_');
 
63
                        break;
 
64
                case '=':
 
65
                case '?':
 
66
                case '_':
 
67
                        line_len_left -= 2;
 
68
                        str_printfa(output, "=%2X", input[i]);
 
69
                        break;
 
70
                default:
 
71
                        if (input[i] < 32 || (input[i] & 0x80) != 0) {
 
72
                                line_len_left -= 2;
 
73
                                str_printfa(output, "=%2X", input[i]);
 
74
                        } else {
 
75
                                str_append_c(output, input[i]);
 
76
                        }
 
77
                        break;
 
78
                }
 
79
                line_len_left--;
 
80
        }
 
81
        str_append(output, "?=");
 
82
}
 
83
 
 
84
void message_header_encode_b(const unsigned char *input, unsigned int len,
 
85
                             string_t *output)
 
86
{
 
87
        unsigned int line_len, line_len_left, max;
 
88
 
 
89
        line_len = str_last_line_len(output);
 
90
        if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN) {
 
91
                str_append(output, "\n\t");
 
92
                line_len = 1;
 
93
        }
 
94
 
 
95
        for (;;) {
 
96
                line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
 
97
                max = MAX_BASE64_DECODED_SIZE(line_len_left);
 
98
                do {
 
99
                        max--;
 
100
                        if (max > len)
 
101
                                max = len;
 
102
                        else {
 
103
                                /* all of it doesn't fit. find a character where we
 
104
                                   can split it from. */
 
105
                                while (max > 0 && (input[max] & 0xc0) == 0x80)
 
106
                                        max--;
 
107
                        }
 
108
                } while (MAX_BASE64_ENCODED_SIZE(max) > line_len_left &&
 
109
                         max > 0);
 
110
 
 
111
                if (max > 0) {
 
112
                        str_append(output, "=?utf-8?b?");
 
113
                        base64_encode(input, max, output);
 
114
                        str_append(output, "?=");
 
115
                }
 
116
 
 
117
                input += max;
 
118
                len -= max;
 
119
 
 
120
                if (len == 0)
 
121
                        break;
 
122
 
 
123
                str_append(output, "\n\t");
 
124
                line_len = 1;
 
125
        }
 
126
}
 
127
 
 
128
void message_header_encode(const char *_input, string_t *output)
 
129
{
 
130
        const unsigned char *input = (const unsigned char *)_input;
 
131
        unsigned int i, first_idx, last_idx;
 
132
        unsigned int enc_chars, enc_len, base64_len, q_len;
 
133
        bool use_q;
 
134
 
 
135
        /* find the first word that needs encoding */
 
136
        for (i = 0; input[i] != '\0'; i++) {
 
137
                if (input_idx_need_encoding(input, i))
 
138
                        break;
 
139
        }
 
140
        if (input[i] == '\0') {
 
141
                /* no encoding necessary */
 
142
                str_append(output, _input);
 
143
                return;
 
144
        }
 
145
        first_idx = i;
 
146
        while (first_idx > 0 && !IS_LWSP(input[first_idx-1]))
 
147
                first_idx--;
 
148
 
 
149
        /* find the last word that needs encoding */
 
150
        last_idx = ++i; enc_chars = 1;
 
151
        for (; input[i] != '\0'; i++) {
 
152
                if (input_idx_need_encoding(input, i)) {
 
153
                        last_idx = i + 1;
 
154
                        enc_chars++;
 
155
                }
 
156
        }
 
157
        while (input[last_idx] != '\0' && !IS_LWSP(input[last_idx]))
 
158
                last_idx++;
 
159
 
 
160
        /* figure out if we should use Q or B encoding. Prefer Q if it's not
 
161
           too much larger. */
 
162
        enc_len = last_idx - first_idx;
 
163
        base64_len = MAX_BASE64_ENCODED_SIZE(enc_len);
 
164
        q_len = enc_len + enc_chars*3;
 
165
        use_q = q_len*2/3 <= base64_len;
 
166
 
 
167
        /* and do it */
 
168
        str_append_n(output, input, first_idx);
 
169
        if (use_q)
 
170
                message_header_encode_q(input + first_idx, enc_len, output);
 
171
        else
 
172
                message_header_encode_b(input + first_idx, enc_len, output);
 
173
        str_append(output, _input + last_idx);
 
174
}