1345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein/* 2345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Copyright (C) 2008 The Android Open Source Project 3345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 4345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License"); 5345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * you may not use this file except in compliance with the License. 6345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * You may obtain a copy of the License at 7345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 8345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * http://www.apache.org/licenses/LICENSE-2.0 9345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 10345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Unless required by applicable law or agreed to in writing, software 11345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS, 12345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * See the License for the specific language governing permissions and 14345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * limitations under the License. 15345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 16345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 17345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinpackage com.android.emailcommon.internet; 18345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 19345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.Body; 20345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.BodyPart; 21345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.MessagingException; 22345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 23345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.BufferedWriter; 24345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.IOException; 25345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.OutputStream; 26345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.OutputStreamWriter; 27345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.util.regex.Pattern; 28345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 29345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein/** 30345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * TODO this is a close approximation of Message, need to update along with 31345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Message. 32345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 33345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinpublic class MimeBodyPart extends BodyPart { 34345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected MimeHeader mHeader = new MimeHeader(); 35345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected MimeHeader mExtendedHeader; 36345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected Body mBody; 37345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected int mSize; 38345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 39345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // regex that matches content id surrounded by "<>" optionally. 40345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$"); 41345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // regex that matches end of line. 42345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private static final Pattern END_OF_LINE = Pattern.compile("\r?\n"); 43345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 44345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public MimeBodyPart() throws MessagingException { 45345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this(null); 46345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 47345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 48345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public MimeBodyPart(Body body) throws MessagingException { 49345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this(body, null); 50345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 51345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 52345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public MimeBodyPart(Body body, String mimeType) throws MessagingException { 53345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mimeType != null) { 54345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType); 55345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 56345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setBody(body); 57345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 58345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 59345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected String getFirstHeader(String name) throws MessagingException { 60345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mHeader.getFirstHeader(name); 61345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 62345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 63aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 64345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void addHeader(String name, String value) throws MessagingException { 65345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mHeader.addHeader(name, value); 66345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 67345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 68aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 69345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setHeader(String name, String value) throws MessagingException { 70345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mHeader.setHeader(name, value); 71345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 72345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 73aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 74345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String[] getHeader(String name) throws MessagingException { 75345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mHeader.getHeader(name); 76345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 77345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 78aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 79345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void removeHeader(String name) throws MessagingException { 80345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mHeader.removeHeader(name); 81345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 82345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 83aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 84345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public Body getBody() throws MessagingException { 85345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mBody; 86345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 87345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 88aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 89345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setBody(Body body) throws MessagingException { 90345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mBody = body; 91345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (body instanceof com.android.emailcommon.mail.Multipart) { 92345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein com.android.emailcommon.mail.Multipart multipart = 93345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein ((com.android.emailcommon.mail.Multipart)body); 94345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein multipart.setParent(this); 95345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType()); 96345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 97345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein else if (body instanceof TextBody) { 98345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein String contentType = String.format("%s;\n charset=utf-8", getMimeType()); 99345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein String name = MimeUtility.getHeaderParameter(getContentType(), "name"); 100345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (name != null) { 101345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein contentType += String.format(";\n name=\"%s\"", name); 102345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 103345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType); 104345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 105345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 106345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 107345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 108aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 109345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getContentType() throws MessagingException { 110345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE); 111345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (contentType == null) { 112345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return "text/plain"; 113345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 114345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return contentType; 115345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 116345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 117345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 118aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 119345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getDisposition() throws MessagingException { 120345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION); 121345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (contentDisposition == null) { 122345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 123345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 124345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return contentDisposition; 125345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 126345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 127345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 128aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 129345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getContentId() throws MessagingException { 130345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID); 131345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (contentId == null) { 132345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 133345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 134345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // remove optionally surrounding brackets. 135345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1"); 136345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 137345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 138345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 139aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 140345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getMimeType() throws MessagingException { 141345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return MimeUtility.getHeaderParameter(getContentType(), null); 142345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 143345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 144aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 145345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public boolean isMimeType(String mimeType) throws MessagingException { 146345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return getMimeType().equals(mimeType); 147345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 148345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 149345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setSize(int size) { 150345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mSize = size; 151345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 152345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 153aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 154345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public int getSize() throws MessagingException { 155345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mSize; 156345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 157345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 158345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 159345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Set extended header 160aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy * 161345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param name Extended header name 162345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param value header value - flattened by removing CR-NL if any 163345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * remove header if value is null 164345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @throws MessagingException 165345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 166aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 167345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setExtendedHeader(String name, String value) throws MessagingException { 168345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (value == null) { 169345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mExtendedHeader != null) { 170345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader.removeHeader(name); 171345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 172345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return; 173345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 174345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mExtendedHeader == null) { 175aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy mExtendedHeader = new MimeHeader(); 176345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 177345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll("")); 178345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 179345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 180345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 181345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Get extended header 182aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy * 183345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param name Extended header name 184345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @return header value - null if header does not exist 185aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy * @throws MessagingException 186345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 187aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 188345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getExtendedHeader(String name) throws MessagingException { 189345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mExtendedHeader == null) { 190345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 191345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 192345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mExtendedHeader.getFirstHeader(name); 193345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 194345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 195345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 196345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Write the MimeMessage out in MIME format. 197345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 198aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 199345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void writeTo(OutputStream out) throws IOException, MessagingException { 200345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); 201345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mHeader.writeTo(out); 202345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein writer.write("\r\n"); 203345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein writer.flush(); 204345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mBody != null) { 205345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mBody.writeTo(out); 206345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 207345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 208345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein} 209