1345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein/*
2345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Copyright (C) 2008 The Android Open Source Project
3345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein *
4345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License");
5345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * you may not use this file except in compliance with the License.
6345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * You may obtain a copy of the License at
7345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein *
8345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein *      http://www.apache.org/licenses/LICENSE-2.0
9345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein *
10345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Unless required by applicable law or agreed to in writing, software
11345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS,
12345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * See the License for the specific language governing permissions and
14345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * limitations under the License.
15345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */
16345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
17345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinpackage com.android.emailcommon.internet;
18345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
19345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.Body;
20345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.BodyPart;
21345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.MessagingException;
22345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
23345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.BufferedWriter;
24345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.IOException;
25345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.OutputStream;
26345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.OutputStreamWriter;
27345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.util.regex.Pattern;
28345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
29345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein/**
30345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * TODO this is a close approximation of Message, need to update along with
31345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Message.
32345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */
33345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinpublic class MimeBodyPart extends BodyPart {
34345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    protected MimeHeader mHeader = new MimeHeader();
35345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    protected MimeHeader mExtendedHeader;
36345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    protected Body mBody;
37345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    protected int mSize;
38345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
39345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    // regex that matches content id surrounded by "<>" optionally.
40345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$");
41345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    // regex that matches end of line.
42345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    private static final Pattern END_OF_LINE = Pattern.compile("\r?\n");
43345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
44345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public MimeBodyPart() throws MessagingException {
45345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        this(null);
46345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
47345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
48345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public MimeBodyPart(Body body) throws MessagingException {
49345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        this(body, null);
50345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
51345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
52345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public MimeBodyPart(Body body, String mimeType) throws MessagingException {
53345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (mimeType != null) {
54345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
55345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
56345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        setBody(body);
57345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
58345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
59345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    protected String getFirstHeader(String name) throws MessagingException {
60345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        return mHeader.getFirstHeader(name);
61345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
62345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
63aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
64345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public void addHeader(String name, String value) throws MessagingException {
65345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        mHeader.addHeader(name, value);
66345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
67345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
68aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
69345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public void setHeader(String name, String value) throws MessagingException {
70345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        mHeader.setHeader(name, value);
71345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
72345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
73aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
74345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public String[] getHeader(String name) throws MessagingException {
75345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        return mHeader.getHeader(name);
76345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
77345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
78aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
79345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public void removeHeader(String name) throws MessagingException {
80345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        mHeader.removeHeader(name);
81345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
82345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
83aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
84345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public Body getBody() throws MessagingException {
85345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        return mBody;
86345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
87345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
88aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
89345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public void setBody(Body body) throws MessagingException {
90345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        this.mBody = body;
91345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (body instanceof com.android.emailcommon.mail.Multipart) {
92345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            com.android.emailcommon.mail.Multipart multipart =
93345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein                ((com.android.emailcommon.mail.Multipart)body);
94345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            multipart.setParent(this);
95345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType());
96345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
97345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        else if (body instanceof TextBody) {
98345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            String contentType = String.format("%s;\n charset=utf-8", getMimeType());
99345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            String name = MimeUtility.getHeaderParameter(getContentType(), "name");
100345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            if (name != null) {
101345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein                contentType += String.format(";\n name=\"%s\"", name);
102345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            }
103345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType);
104345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
105345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
106345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
107345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
108aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
109345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public String getContentType() throws MessagingException {
110345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
111345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (contentType == null) {
112345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return "text/plain";
113345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        } else {
114345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return contentType;
115345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
116345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
117345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
118aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
119345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public String getDisposition() throws MessagingException {
120345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
121345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (contentDisposition == null) {
122345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return null;
123345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        } else {
124345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return contentDisposition;
125345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
126345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
127345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
128aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
129345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public String getContentId() throws MessagingException {
130345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID);
131345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (contentId == null) {
132345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return null;
133345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        } else {
134345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            // remove optionally surrounding brackets.
135345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1");
136345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
137345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
138345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
139aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
140345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public String getMimeType() throws MessagingException {
141345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        return MimeUtility.getHeaderParameter(getContentType(), null);
142345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
143345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
144aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
145345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public boolean isMimeType(String mimeType) throws MessagingException {
146345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        return getMimeType().equals(mimeType);
147345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
148345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
149345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public void setSize(int size) {
150345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        this.mSize = size;
151345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
152345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
153aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
154345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public int getSize() throws MessagingException {
155345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        return mSize;
156345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
157345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
158345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    /**
159345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * Set extended header
160aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy     *
161345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * @param name Extended header name
162345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * @param value header value - flattened by removing CR-NL if any
163345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * remove header if value is null
164345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * @throws MessagingException
165345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     */
166aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
167345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public void setExtendedHeader(String name, String value) throws MessagingException {
168345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (value == null) {
169345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            if (mExtendedHeader != null) {
170345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein                mExtendedHeader.removeHeader(name);
171345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            }
172345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return;
173345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
174345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (mExtendedHeader == null) {
175aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy            mExtendedHeader = new MimeHeader();
176345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
177345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
178345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
179345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
180345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    /**
181345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * Get extended header
182aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy     *
183345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * @param name Extended header name
184345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * @return header value - null if header does not exist
185aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy     * @throws MessagingException
186345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     */
187aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
188345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public String getExtendedHeader(String name) throws MessagingException {
189345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (mExtendedHeader == null) {
190345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            return null;
191345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
192345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        return mExtendedHeader.getFirstHeader(name);
193345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
194345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein
195345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    /**
196345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     * Write the MimeMessage out in MIME format.
197345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein     */
198aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy    @Override
199345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    public void writeTo(OutputStream out) throws IOException, MessagingException {
200345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
201345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        mHeader.writeTo(out);
202345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        writer.write("\r\n");
203345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        writer.flush();
204345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        if (mBody != null) {
205345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein            mBody.writeTo(out);
206345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein        }
207345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein    }
208345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein}
209