1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.emailcommon.internet;
18
19import com.android.emailcommon.mail.Body;
20import com.android.emailcommon.mail.BodyPart;
21import com.android.emailcommon.mail.MessagingException;
22
23import java.io.BufferedWriter;
24import java.io.IOException;
25import java.io.OutputStream;
26import java.io.OutputStreamWriter;
27import java.util.regex.Pattern;
28
29/**
30 * TODO this is a close approximation of Message, need to update along with
31 * Message.
32 */
33public class MimeBodyPart extends BodyPart {
34    protected MimeHeader mHeader = new MimeHeader();
35    protected MimeHeader mExtendedHeader;
36    protected Body mBody;
37    protected int mSize;
38
39    // regex that matches content id surrounded by "<>" optionally.
40    private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$");
41    // regex that matches end of line.
42    private static final Pattern END_OF_LINE = Pattern.compile("\r?\n");
43
44    public MimeBodyPart() throws MessagingException {
45        this(null);
46    }
47
48    public MimeBodyPart(Body body) throws MessagingException {
49        this(body, null);
50    }
51
52    public MimeBodyPart(Body body, String mimeType) throws MessagingException {
53        if (mimeType != null) {
54            setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
55        }
56        setBody(body);
57    }
58
59    protected String getFirstHeader(String name) throws MessagingException {
60        return mHeader.getFirstHeader(name);
61    }
62
63    @Override
64    public void addHeader(String name, String value) throws MessagingException {
65        mHeader.addHeader(name, value);
66    }
67
68    @Override
69    public void setHeader(String name, String value) throws MessagingException {
70        mHeader.setHeader(name, value);
71    }
72
73    @Override
74    public String[] getHeader(String name) throws MessagingException {
75        return mHeader.getHeader(name);
76    }
77
78    @Override
79    public void removeHeader(String name) throws MessagingException {
80        mHeader.removeHeader(name);
81    }
82
83    @Override
84    public Body getBody() throws MessagingException {
85        return mBody;
86    }
87
88    @Override
89    public void setBody(Body body) throws MessagingException {
90        this.mBody = body;
91        if (body instanceof com.android.emailcommon.mail.Multipart) {
92            com.android.emailcommon.mail.Multipart multipart =
93                ((com.android.emailcommon.mail.Multipart)body);
94            multipart.setParent(this);
95            setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType());
96        }
97        else if (body instanceof TextBody) {
98            String contentType = String.format("%s;\n charset=utf-8", getMimeType());
99            String name = MimeUtility.getHeaderParameter(getContentType(), "name");
100            if (name != null) {
101                contentType += String.format(";\n name=\"%s\"", name);
102            }
103            setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType);
104            setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
105        }
106    }
107
108    @Override
109    public String getContentType() throws MessagingException {
110        String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
111        if (contentType == null) {
112            return "text/plain";
113        } else {
114            return contentType;
115        }
116    }
117
118    @Override
119    public String getDisposition() throws MessagingException {
120        String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
121        if (contentDisposition == null) {
122            return null;
123        } else {
124            return contentDisposition;
125        }
126    }
127
128    @Override
129    public String getContentId() throws MessagingException {
130        String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID);
131        if (contentId == null) {
132            return null;
133        } else {
134            // remove optionally surrounding brackets.
135            return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1");
136        }
137    }
138
139    @Override
140    public String getMimeType() throws MessagingException {
141        return MimeUtility.getHeaderParameter(getContentType(), null);
142    }
143
144    @Override
145    public boolean isMimeType(String mimeType) throws MessagingException {
146        return getMimeType().equals(mimeType);
147    }
148
149    public void setSize(int size) {
150        this.mSize = size;
151    }
152
153    @Override
154    public int getSize() throws MessagingException {
155        return mSize;
156    }
157
158    /**
159     * Set extended header
160     *
161     * @param name Extended header name
162     * @param value header value - flattened by removing CR-NL if any
163     * remove header if value is null
164     * @throws MessagingException
165     */
166    @Override
167    public void setExtendedHeader(String name, String value) throws MessagingException {
168        if (value == null) {
169            if (mExtendedHeader != null) {
170                mExtendedHeader.removeHeader(name);
171            }
172            return;
173        }
174        if (mExtendedHeader == null) {
175            mExtendedHeader = new MimeHeader();
176        }
177        mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
178    }
179
180    /**
181     * Get extended header
182     *
183     * @param name Extended header name
184     * @return header value - null if header does not exist
185     * @throws MessagingException
186     */
187    @Override
188    public String getExtendedHeader(String name) throws MessagingException {
189        if (mExtendedHeader == null) {
190            return null;
191        }
192        return mExtendedHeader.getFirstHeader(name);
193    }
194
195    /**
196     * Write the MimeMessage out in MIME format.
197     */
198    @Override
199    public void writeTo(OutputStream out) throws IOException, MessagingException {
200        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
201        mHeader.writeTo(out);
202        writer.write("\r\n");
203        writer.flush();
204        if (mBody != null) {
205            mBody.writeTo(out);
206        }
207    }
208}
209