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