EmailHtmlUtil.java revision 21ace307e07cb4c363c4183f4d62f4049f5d92fd
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.email.mail.internet; 18 19import com.android.email.mail.MessagingException; 20import com.android.email.mail.Multipart; 21import com.android.email.mail.Part; 22import com.android.email.mail.store.LocalStore.LocalAttachmentBodyPart; 23import com.android.email.provider.AttachmentProvider; 24import com.android.email.provider.EmailContent; 25 26import android.content.ContentResolver; 27import android.net.Uri; 28 29import java.util.regex.Matcher; 30import java.util.regex.Pattern; 31 32public 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 */ 50 public static String resolveInlineImage( 51 ContentResolver resolver, EmailContent.Account account, 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 contentUri = AttachmentProvider.resolveAttachmentIdToContentUri( 64 resolver, AttachmentProvider.getAttachmentUri(account, attachment.getAttachmentId())); 65 // Regexp which matches ' src="cid:contentId"'. 66 String contentIdRe = "\\s+(?i)src=\"cid(?-i):\\Q" + contentId + "\\E\""; 67 // Replace all occurrences of src attribute with ' src="content://contentUri"'. 68 text = text.replaceAll(contentIdRe, " src=\"" + contentUri + "\""); 69 } 70 71 if (part.getBody() instanceof Multipart) { 72 Multipart mp = (Multipart)part.getBody(); 73 for (int i = 0; i < mp.getCount(); i++) { 74 text = resolveInlineImage(resolver, account, text, mp.getBodyPart(i), depth + 1); 75 } 76 } 77 78 return text; 79 } 80 81 /** 82 * Escape some special character as HTML escape sequence. 83 * 84 * @param text Text to be displayed using WebView. 85 * @return Text correctly escaped. 86 */ 87 public static String escapeCharacterToDisplay(String text) { 88 Pattern pattern = PLAIN_TEXT_TO_ESCAPE; 89 Matcher match = pattern.matcher(text); 90 91 if (match.find()) { 92 StringBuilder out = new StringBuilder(); 93 int end = 0; 94 do { 95 int start = match.start(); 96 out.append(text.substring(end, start)); 97 end = match.end(); 98 int c = text.codePointAt(start); 99 if (c == ' ') { 100 // Escape successive spaces into series of " ". 101 for (int i = 1, n = end - start; i < n; ++i) { 102 out.append(" "); 103 } 104 out.append(' '); 105 } else if (c == '\r' || c == '\n') { 106 out.append("<br>"); 107 } else if (c == '<') { 108 out.append("<"); 109 } else if (c == '>') { 110 out.append(">"); 111 } else if (c == '&') { 112 out.append("&"); 113 } 114 } while (match.find()); 115 out.append(text.substring(end)); 116 text = out.toString(); 117 } 118 return text; 119 } 120} 121