root/msg/entity.cc

Revision 2a665297c7a8b588c97e99f1843a3b75aad25531, 5.5 KB (checked in by Antti-Juhani Kaijanaho <ajk@…>, 16 months ago)

Fix #81: Correct handling of Content- header fields in multiparting entities

Signed-off-by: Antti-Juhani Kaijanaho <ajk@…>

  • Property mode set to 100644
Line 
1/*  This file is part of Alue, the multiprotocol Internet discussion daemon
2
3    Copyright © 2009, 2010 Antti-Juhani Kaijanaho
4
5    Alue is free software: you can redistribute it and/or modify it
6    under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    Alue is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with Alue.  If not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20#include "content_type.hh"
21#include "entity.hh"
22#include "lexutils.hh"
23#include "message_entity.hh"
24#include "multipart.hh"
25#include "text_plain.hh"
26#include "util.hh"
27#include "raw_entity.hh"
28
29#include "../util.hh"
30
31#include <boost/algorithm/string/case_conv.hpp>
32#include <boost/format.hpp>
33#include <boost/nondet_random.hpp>
34
35#include "../assert.hh"
36
37namespace msg
38{
39        size_t entity::get_size() const
40        {
41                std::string body = get_body();
42                size_t n = 0;
43                for (field_iterator it = fields_begin();
44                     it != fields_end(); it++)
45                {
46                        n += it->length();
47                }
48                n += 2;
49                n += body.length();
50                return n;
51        }
52
53        size_t entity::get_body_lines() const
54        {
55                std::string body = get_body();
56                unsigned long lines = -1;
57                size_t inx = std::string::npos;
58                do
59                {
60                        inx++;
61                        lines++;
62                        inx = body.find("\r\n", inx);
63                } while (inx != std::string::npos);
64                return lines;
65        }
66
67        entity::ptr entity::mk(std::string ms, bool validate, std::string dct)
68        {
69                entity_header::ptr hdr(new entity_header(ms, validate, dct));
70
71                entity::ptr rv;
72                content_type ct = hdr->get_content_type();
73                switch (ct.get_type())
74                {
75                case content_type::MESSAGE:
76                        rv.reset(new message_entity(hdr, ms));
77                        break;
78                case content_type::MULTIPART:
79                        rv.reset(new multipart(hdr, ms));
80                        break;
81                case content_type::TEXT:
82                        rv.reset(new text_plain(hdr, ms));
83                        break;
84                default:
85                        rv.reset(new raw_entity(hdr, ms));
86                        break;
87                }
88                return rv;
89        }
90
91        multipart::ptr entity::clone_as_multipart() const
92        {
93                static const char content_[] = "content-";
94                boost::random_device urand;
95
96                entity_header::ptr envh(new entity_header(*hdr));
97                entity_header::ptr subh(new entity_header(DEFAULT_CT));
98
99                for (field_iterator it = hdr->fields_begin();
100                     it != hdr->fields_end(); it++)
101                {
102                        std::string fld = *it;
103                        size_t colon = fld.find(':');
104                        if (colon == std::string::npos) colon = 0;
105                        std::string name = fld.substr(0, colon);
106                        size_t start = colon + 1 < fld.length()
107                                ? (fld[colon+1] == ' ' ? colon + 1 : colon)
108                                : colon;
109                        std::string content = fld.substr(start);
110                        util::strip_crlf(content);
111                        boost::to_lower(name);
112                        if (name.substr(0, sizeof content_ - 1) != content_)
113                                continue;
114                        subh->replace_field(name, content);
115                        envh->delete_field(name);
116                }
117
118                std::string body = get_body();
119
120                std::string boundary;
121        redo:
122                {
123                        std::ostringstream ss;
124                        ss << urand() << urand() << urand() << urand();
125                        if (body.find(ss.str()) != std::string::npos)
126                                goto redo;
127                        boundary = ss.str();
128                }
129
130                bool bit8 = false;
131                for (size_t i = 0; i < body.length(); i++)
132                {
133                        if ((unsigned char)body[i] > 0x7f)
134                        {
135                                bit8 = true;
136                                break;
137                        }
138                }
139
140                envh->replace_field("MIME-Version", "1.0");
141                envh->add_field("Content-Type",
142                                std::string("multipart/mixed; boundary=") +
143                                make_phrase(boundary));
144                envh->add_field("Content-Transfer-Encoding",
145                                bit8 ? "8bit" : "7bit");
146
147                std::ostringstream nbss;
148                nbss << "--" << boundary << "\r\n"
149                     << subh->get_header() << "\r\n"
150                     << body
151                     << "\r\n--" << boundary << "--\r\n";
152               
153                multipart::ptr rv(new multipart(envh, nbss.str()));
154                return rv;
155        }
156
157}
Note: See TracBrowser for help on using the browser.