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 17 package com.android.email.mail.internet; 18 19 import com.android.email.mail.MessagingException; 20 import com.android.email.mail.Multipart; 21 import com.android.email.mail.Part; 22 import com.android.email.mail.store.LocalStore.LocalAttachmentBodyPart; 23 import com.android.email.provider.AttachmentProvider; 24 import com.android.email.provider.EmailContent; 25 26 import android.content.ContentResolver; 27 import android.net.Uri; 28 29 import java.util.regex.Matcher; 30 import java.util.regex.Pattern; 31 32 public class EmailHtmlUtil { 33 34 // Regex that matches characters that have special meaning in HTML. '<', '>', '&' and 35 // multiple continuous spaces. 36 private static final Pattern PLAIN_TEXT_TO_ESCAPE = Pattern.compile("[<>&]| {2,}|\r?\n"); 37 38 //TODO: make resolveInlineImage() work in the new content provider model. 39 /** 40 * Resolve content-id reference in src attribute of img tag to AttachmentProvider's 41 * content uri. This method calls itself recursively at most the number of 42 * LocalAttachmentPart that mime type is image and has content id. 43 * The attribute src="cid:content_id" is resolved as src="content://...". 44 * This method is package scope for testing purpose. 45 * 46 * @param text html email text 47 * @param part mime part which may contain inline image 48 * @return html text in which src attribute of img tag may be replaced with content uri 49 */ resolveInlineImage( ContentResolver resolver, long accountId, String text, Part part, int depth)50 public static String resolveInlineImage( 51 ContentResolver resolver, long accountId, String text, Part part, int depth) 52 throws MessagingException { 53 // avoid too deep recursive call. 54 if (depth >= 10 || text == null) { 55 return text; 56 } 57 String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); 58 String contentId = part.getContentId(); 59 if (contentType.startsWith("image/") && 60 contentId != null && 61 part instanceof LocalAttachmentBodyPart) { 62 LocalAttachmentBodyPart attachment = (LocalAttachmentBodyPart)part; 63 Uri attachmentUri = 64 AttachmentProvider.getAttachmentUri(accountId, attachment.getAttachmentId()); 65 Uri contentUri = 66 AttachmentProvider.resolveAttachmentIdToContentUri(resolver, attachmentUri); 67 // Regexp which matches ' src="cid:contentId"'. 68 String contentIdRe = "\\s+(?i)src=\"cid(?-i):\\Q" + contentId + "\\E\""; 69 // Replace all occurrences of src attribute with ' src="content://contentUri"'. 70 text = text.replaceAll(contentIdRe, " src=\"" + contentUri + "\""); 71 } 72 73 if (part.getBody() instanceof Multipart) { 74 Multipart mp = (Multipart)part.getBody(); 75 for (int i = 0; i < mp.getCount(); i++) { 76 text = resolveInlineImage(resolver, accountId, text, mp.getBodyPart(i), depth + 1); 77 } 78 } 79 80 return text; 81 } 82 83 /** 84 * Escape some special character as HTML escape sequence. 85 * 86 * @param text Text to be displayed using WebView. 87 * @return Text correctly escaped. 88 */ escapeCharacterToDisplay(String text)89 public static String escapeCharacterToDisplay(String text) { 90 Pattern pattern = PLAIN_TEXT_TO_ESCAPE; 91 Matcher match = pattern.matcher(text); 92 93 if (match.find()) { 94 StringBuilder out = new StringBuilder(); 95 int end = 0; 96 do { 97 int start = match.start(); 98 out.append(text.substring(end, start)); 99 end = match.end(); 100 int c = text.codePointAt(start); 101 if (c == ' ') { 102 // Escape successive spaces into series of " ". 103 for (int i = 1, n = end - start; i < n; ++i) { 104 out.append(" "); 105 } 106 out.append(' '); 107 } else if (c == '\r' || c == '\n') { 108 out.append("<br>"); 109 } else if (c == '<') { 110 out.append("<"); 111 } else if (c == '>') { 112 out.append(">"); 113 } else if (c == '&') { 114 out.append("&"); 115 } 116 } while (match.find()); 117 out.append(text.substring(end)); 118 text = out.toString(); 119 } 120 return text; 121 } 122 } 123