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