1 /*
2  * Copyright (C) 2009 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 
17 package com.android.emailcommon.mail;
18 
19 import com.android.emailcommon.internet.MimeBodyPart;
20 import com.android.emailcommon.internet.MimeHeader;
21 import com.android.emailcommon.internet.MimeMessage;
22 import com.android.emailcommon.internet.MimeMultipart;
23 import com.android.emailcommon.internet.TextBody;
24 import com.android.emailcommon.provider.Account;
25 import com.android.emailcommon.utility.AttachmentUtilities;
26 
27 import android.net.Uri;
28 
29 import java.util.ArrayList;
30 
31 /**
32  * Utility class makes it easier for developer to build mail message objects.
33  * <p>
34  * Typical usage of these helper functions and builder objects are as follows.
35  * <p>
36  * <pre>
37  * String text2 = new TextBuilder("<html>").text("<head></head>")
38  *     .text("<body>").cidImg("contetid@domain").text("</body>").build("</html");
39  * String text2 = new TextBuilder("<html>").text("<head></head>")
40  *     .text("<body>").uriImg(contentUri).text("</body>").build("</html");
41  * Message msg = new MessageBuilder()
42  *     .setBody(new MultipartBuilder("multipart/mixed")
43  *         .addBodyPart(MessageTestUtils.imagePart("image/jpeg", null, 30, store))
44  *         .addBodyPart(MessageTestUtils.imagePart("application/pdf", cid1, aid1, store))
45  *         .addBodyPart(new MultipartBuilder("multipart/related")
46  *             .addBodyPart(MessageTestUtils.textPart("text/html", text2 + text1))
47  *             .addBodyPart(MessageTestUtils.imagePart("image/jpg", cid1, aid1, store))
48  *             .addBodyPart(MessageTestUtils.imagePart("image/gif", cid2, aid2, store))
49  *             .buildBodyPart())
50  *         .addBodyPart(MessageTestUtils.imagePart("application/pdf", cid2, aid2, store))
51  *         .build())
52  *     .build();
53  * </pre>
54  */
55 
56 public class MessageTestUtils {
57 
58     /**
59      * Generate AttachmentProvider content URI from attachment ID and Account.
60      *
61      * @param attachmentId attachment id
62      * @param account Account object
63      * @return AttachmentProvider content URI
64      */
contentUri(long attachmentId, Account account)65     public static Uri contentUri(long attachmentId, Account account) {
66         return AttachmentUtilities.getAttachmentUri(account.mId, attachmentId);
67     }
68 
69     /**
70      * Create simple MimeBodyPart.
71      *
72      * @param mimeType MIME type of body part
73      * @param contentId content-id header value (optional - null for no header)
74      * @return MimeBodyPart object which body is null.
75      * @throws MessagingException
76      */
bodyPart(String mimeType, String contentId)77     public static BodyPart bodyPart(String mimeType, String contentId) throws MessagingException {
78         final MimeBodyPart bp = new MimeBodyPart(null, mimeType);
79         if (contentId != null) {
80             bp.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId);
81         }
82         return bp;
83     }
84 
85     /**
86      * Create MimeBodyPart with TextBody.
87      *
88      * @param mimeType MIME type of text
89      * @param text body text string
90      * @return MimeBodyPart object whose body is TextBody
91      * @throws MessagingException
92      */
textPart(String mimeType, String text)93     public static BodyPart textPart(String mimeType, String text) throws MessagingException {
94         final TextBody textBody = new TextBody(text);
95         final MimeBodyPart textPart = new MimeBodyPart(textBody);
96         textPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
97         return textPart;
98     }
99 
100     /**
101      * Builder class for Multipart.
102      *
103      * This builder object accepts any number of BodyParts and then can produce
104      * Multipart or BodyPart which contains accepted BodyParts. Usually combined with other
105      * builder object and helper method.
106      */
107     public static class MultipartBuilder {
108         private final String mContentType;
109         private final ArrayList<BodyPart> mParts = new ArrayList<BodyPart>();
110 
111         /**
112          * Create builder object with MIME type and dummy boundary string.
113          *
114          * @param mimeType MIME type of this Multipart
115          */
MultipartBuilder(String mimeType)116         public MultipartBuilder(String mimeType) {
117             this(mimeType, "this_is_boundary");
118         }
119 
120         /**
121          * Create builder object with MIME type and boundary string.
122          *
123          * @param mimeType MIME type of this Multipart
124          * @param boundary boundary string
125          */
MultipartBuilder(String mimeType, String boundary)126         public MultipartBuilder(String mimeType, String boundary) {
127             mContentType = mimeType + "; boundary=" + boundary;
128         }
129 
130         /**
131          * Modifier method to add BodyPart to intended Multipart.
132          *
133          * @param bodyPart BodyPart to be added
134          * @return builder object itself
135          */
addBodyPart(final BodyPart bodyPart)136         public MultipartBuilder addBodyPart(final BodyPart bodyPart) {
137             mParts.add(bodyPart);
138             return this;
139         }
140 
141         /**
142          * Build method to create Multipart.
143          *
144          * @return intended Multipart object
145          * @throws MessagingException
146          */
build()147         public Multipart build() throws MessagingException {
148             final MimeMultipart mp = new MimeMultipart(mContentType);
149             for (BodyPart p : mParts) {
150                 mp.addBodyPart(p);
151             }
152             return mp;
153         }
154 
155         /**
156          * Build method to create BodyPart that contains this "Multipart"
157          * @return BodyPart whose body is intended Multipart.
158          * @throws MessagingException
159          */
buildBodyPart()160         public BodyPart buildBodyPart() throws MessagingException {
161             final BodyPart bp = new MimeBodyPart();
162             bp.setBody(this.build());
163             return bp;
164         }
165     }
166 
167     /**
168      * Builder class for Message
169      *
170      * This builder object accepts Body and then can produce Message object.
171      * Usually combined with other builder object and helper method.
172      */
173     public static class MessageBuilder {
174         private Body mBody;
175 
176         /**
177          * Create Builder object.
178          */
MessageBuilder()179         public MessageBuilder() {
180         }
181 
182         /**
183          * Modifier method to set Body.
184          *
185          * @param body Body of intended Message
186          * @return builder object itself
187          */
setBody(final Body body)188         public MessageBuilder setBody(final Body body) {
189             mBody = body;
190             return this;
191         }
192 
193         /**
194          * Build method to create Message.
195          *
196          * @return intended Message object
197          * @throws MessagingException
198          */
build()199         public Message build() throws MessagingException {
200             final MimeMessage msg = new MimeMessage();
201             if (mBody == null) {
202                 throw new MessagingException("body is not specified");
203             }
204             msg.setBody(mBody);
205             return msg;
206         }
207     }
208 
209     /**
210      * Builder class for simple HTML String.
211      * This builder object accepts some type of object or and string and then create String object.
212      * Usually combined with other builder object and helper method.
213      */
214     public static class TextBuilder {
215         final StringBuilder mBuilder = new StringBuilder();
216 
217         /**
218          * Create builder with preamble string
219          * @param preamble
220          */
TextBuilder(String preamble)221         public TextBuilder(String preamble) {
222             mBuilder.append(preamble);
223         }
224 
225         /**
226          * Modifier method to add img tag that has cid: src attribute.
227          * @param contentId content id string
228          * @return builder object itself
229          */
addCidImg(String contentId)230         public TextBuilder addCidImg(String contentId) {
231             return addTag("img", "SRC", "cid:" + contentId);
232         }
233 
234         /**
235          * Modifier method to add img tag that has content:// src attribute.
236          * @param contentUri content uri object
237          * @return builder object itself
238          */
addUidImg(Uri contentUri)239         public TextBuilder addUidImg(Uri contentUri) {
240             return addTag("img", "src", contentUri.toString());
241         }
242 
243         /**
244          * Modifier method to add tag with specified attribute and value.
245          *
246          * @param tag tag name
247          * @param attribute attribute name
248          * @param value attribute value
249          * @return builder object itself
250          */
addTag(String tag, String attribute, String value)251         public TextBuilder addTag(String tag, String attribute, String value) {
252             return addText(String.format("<%s %s=\"%s\">", tag, attribute, value));
253         }
254 
255         /**
256          * Modifier method to add simple string.
257          * @param text string to add
258          * @return builder object itself
259          */
addText(String text)260         public TextBuilder addText(String text) {
261             mBuilder.append(text);
262             return this;
263         }
264 
265         /**
266          * Build method to create intended String
267          * @param epilogue string to add to the end
268          * @return intended String
269          */
build(String epilogue)270         public String build(String epilogue) {
271             mBuilder.append(epilogue);
272             return mBuilder.toString();
273         }
274     }
275 
276 }
277