// We populate Message using the ImapList parsed by BODYSTRUCTURE returned from server. private static void parseBodyStructure(ImapList bs, Part part, String id) throws MessagingException { if (bs.getElementOrNone(0).isList()) { /* * This is a multipart/* */ MimeMultipart mp = new MimeMultipart(); for (int i = 0, count = bs.size(); i < count; i++) { ImapElement e = bs.getElementOrNone(i); if (e.isList()) { /* * For each part in the message we're going to add a new BodyPart and parse * into it. */ MimeBodyPart bp = new MimeBodyPart(); if (id.equals(ImapConstants.TEXT)) { parseBodyStructure(bs.getListOrEmpty(i), bp, Integer.toString(i + 1)); } else { parseBodyStructure(bs.getListOrEmpty(i), bp, id + "." + (i + 1)); } mp.addBodyPart(bp); } else { if (e.isString()) { mp.setSubType(bs.getStringOrEmpty(i).getString().toLowerCase()); } break; // Ignore the rest of the list. } } part.setBody(mp); } else { /* * This is a body. We need to add as much information as we can find out about * it to the Part. */ /* body type body subtype body parameter parenthesized list body id body description body encoding body size */ final ImapString type = bs.getStringOrEmpty(0); final ImapString subType = bs.getStringOrEmpty(1); final String mimeType = (type.getString() + "/" + subType.getString()).toLowerCase(); final ImapList bodyParams = bs.getListOrEmpty(2); final ImapString cid = bs.getStringOrEmpty(3); final ImapString encoding = bs.getStringOrEmpty(5); final int size = bs.getStringOrEmpty(6).getNumberOrZero(); if (MimeUtility.mimeTypeMatches(mimeType, MimeUtility.MIME_TYPE_RFC822)) { // A body type of type MESSAGE and subtype RFC822 // contains, immediately after the basic fields, the // envelope structure, body structure, and size in // text lines of the encapsulated message. // [MESSAGE, RFC822, [NAME, filename.eml], NIL, NIL, 7BIT, 5974, NIL, // [INLINE, [FILENAME*0, Fwd: Xxx..., FILENAME*1, filename.eml]], NIL] /* * This will be caught by fetch and handled appropriately. */ // throw new MessagingException("BODYSTRUCTURE " + // MimeUtility.MIME_TYPE_RFC822 // + " not yet supported."); Logging.w("BODYSTRUCTURE " + MimeUtility.MIME_TYPE_RFC822 + " not yet supported."); return; } /* * Set the content type with as much information as we know right now. */ final StringBuilder contentType = new StringBuilder(mimeType); /* * If there are body params we might be able to get some more information out * of them. */ for (int i = 1, count = bodyParams.size(); i < count; i += 2) { // TODO We need to convert " into %22, but // because MimeUtility.getHeaderParameter doesn't recognize it, // we can't fix it for now. contentType.append( String.format( ";\n %s=\"%s\"", bodyParams.getStringOrEmpty(i - 1).getString(), bodyParams.getStringOrEmpty(i).getString())); } part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType.toString()); // Extension items final ImapList bodyDisposition; if (type.is(ImapConstants.TEXT) && bs.getElementOrNone(9).isList()) { // If media-type is TEXT, 9th element might be: [body-fld-lines] := number // So, if it's not a list, use 10th element. // (Couldn't find evidence in the RFC if it's ALWAYS 10th element.) bodyDisposition = bs.getListOrEmpty(9); } else { bodyDisposition = bs.getListOrEmpty(8); } final StringBuilder contentDisposition = new StringBuilder(); if (bodyDisposition.size() > 0) { final String bodyDisposition0Str = bodyDisposition.getStringOrEmpty(0).getString().toLowerCase(); if (!TextUtils.isEmpty(bodyDisposition0Str)) { contentDisposition.append(bodyDisposition0Str); } final ImapList bodyDispositionParams = bodyDisposition.getListOrEmpty(1); if (!bodyDispositionParams.isEmpty()) { /* * If there is body disposition information we can pull some more * information about the attachment out. */ for (int i = 1, count = bodyDispositionParams.size(); i < count; i += 2) { // TODO We need to convert " into %22. See above. contentDisposition.append( String.format( ";\n %s=\"%s\"", bodyDispositionParams.getStringOrEmpty(i - 1).getString().toLowerCase(), bodyDispositionParams.getStringOrEmpty(i).getString())); } } } if ((size > 0) && (MimeUtility.getHeaderParameter(contentDisposition.toString(), "size") == null)) { // If the encoding is base64 and no Content-Disposition size fetched, then recounting the // actual size: the encoded size multiplied by a fixed ratio if (ENC_BASE64.equals(encoding.getString())) { contentDisposition.append(String.format(";\n size=%d", (int) (size * BASE64_RATIO))); } else { contentDisposition.append(String.format(";\n size=%d", size)); } } if (contentDisposition.length() > 0) { /* * Set the content disposition containing at least the size. Attachment * handling code will use this down the road. */ part.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, contentDisposition.toString()); } /* * Set the Content-Transfer-Encoding header. Attachment code will use this * to parse the body. */ if (!encoding.isEmpty()) { part.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, encoding.getString()); } /* * Set the Content-ID header. */ if (!cid.isEmpty()) { part.setHeader(MimeHeader.HEADER_CONTENT_ID, cid.getString()); } if (size > 0) { if (part instanceof ImapMessage) { ((ImapMessage) part).setSize(size); } else if (part instanceof MimeBodyPart) { ((MimeBodyPart) part).setSize(size); } else { throw new MessagingException("Unknown part type " + part.toString()); } } part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id); } }
public void sendMessage() throws IOException { Logging.d(TAG, "Start send message ... for Uri " + mUri); // Initialize return value int resultType = EmailExternalConstants.TYPE_SEND; int result = EmailExternalConstants.RESULT_SUCCESS; mInputStream = mContentResolver.openInputStream(mUri); if (null == mInputStream) { Logging.w( TAG, "Send Message Failed in sendMessage() method , " + "Can't get InputStream from the given uri: " + mUri); result = EmailExternalConstants.RESULT_FAIL; sendCallback(result, resultType); return; } // Write the output to a temporary file File cacheDir = mContext.getCacheDir(); File tmpFile = File.createTempFile("eas_", "tmp", cacheDir); writToFile(mInputStream, tmpFile); try { mInputStream.close(); } catch (Exception e) { Logging.e(TAG, "Closes inputstream fail.", e); } try { // Get an input stream to our temporary file and create an entity with it FileInputStream fileInputStream = new FileInputStream(tmpFile); InputStreamEntity inputEntity = new InputStreamEntity(fileInputStream, tmpFile.length()); // Create the appropriate command and POST it to the server String cmd = "SendMail&SaveInSent=F"; if (mSaveInSent) { cmd = "SendMail&SaveInSent=T"; } // if (smartSend) { // cmd = reply ? "SmartReply" : "SmartForward"; // cmd += "&ItemId=" + itemId + "&CollectionId=" + collectionId + // "&SaveInSent=T"; // } Logging.d(TAG, "Send cmd: " + cmd); EasResponse resp = sendHttpClientPost(cmd, inputEntity, EasOutboxService.SEND_MAIL_TIMEOUT); fileInputStream.close(); // Send feedback // sendCallback(result, resultType); // TODO:How to define the Deliver complete. // resultType = EmailExternalConstants.TYPE_DELIVER; int code = resp.getStatus(); if (code == HttpStatus.SC_OK) { Logging.d(TAG, "EAS Message sending success, code:" + code); result = EmailExternalConstants.RESULT_SUCCESS; sendCallback(result, resultType); return; } else { Logging.d(TAG, "EAS Message sending failed, code:" + code); result = EmailExternalConstants.RESULT_FAIL; } } catch (FileNotFoundException e) { Logging.e(TAG, "EAS SendMessage FileNotFoundException " + e.getMessage()); result = EmailExternalConstants.RESULT_FAIL; } catch (IOException e) { Logging.e(TAG, "EAS SendMessage Exception " + e.getMessage()); result = EmailExternalConstants.RESULT_FAIL; } finally { // Clean up the temporary file if (tmpFile.exists()) { tmpFile.delete(); } } Logging.d(TAG, "EAS send Message feedback result = " + result + " resultType = " + resultType); sendCallback(result, resultType); }