private void onInviteLinkClicked() { if (!isMessageOpen()) return; Message message = getMessage(); String startTime = new PackedString(message.mMeetingInfo).get(MeetingInfo.MEETING_DTSTART); if (startTime != null) { long epochTimeMillis = Utility.parseEmailDateTimeToMillis(startTime); mCallback.onCalendarLinkClicked(epochTimeMillis); } else { Email.log("meetingInfo without DTSTART " + message.mMeetingInfo); } }
/** Send a service message indicating that a meeting invite button has been clicked. */ private void onRespondToInvite(int response, int toastResId) { if (!isMessageOpen()) return; Message message = getMessage(); // do not send twice in a row the same response if (mPreviousMeetingResponse != response) { getController().sendMeetingResponse(message.mId, response); mPreviousMeetingResponse = response; } Utility.showToast(getActivity(), toastResId); mCallback.onRespondedToInvite(response); }
/** * Find the account with the shortest expiration time. This is always assumed to be the account * that forces the password to be refreshed. * * @return -1 if no expirations, or accountId if one is found */ @VisibleForTesting /*package*/ static long findShortestExpiration(Context context) { long policyId = Utility.getFirstRowLong( context, Policy.CONTENT_URI, Policy.ID_PROJECTION, HAS_PASSWORD_EXPIRATION, null, PolicyColumns.PASSWORD_EXPIRATION_DAYS + " ASC", EmailContent.ID_PROJECTION_COLUMN, -1L); if (policyId < 0) return -1L; return Policy.getAccountIdWithPolicyKey(context, policyId); }
@Override public boolean equals(Object o) { if (!(o instanceof HostAuth)) { return false; } HostAuth that = (HostAuth) o; return mPort == that.mPort && mFlags == that.mFlags && Utility.areStringsEqual(mProtocol, that.mProtocol) && Utility.areStringsEqual(mAddress, that.mAddress) && Utility.areStringsEqual(mLogin, that.mLogin) && Utility.areStringsEqual(mPassword, that.mPassword) && Utility.areStringsEqual(mDomain, that.mDomain) && Utility.areStringsEqual(mClientCertAlias, that.mClientCertAlias); }
/** * M: Get the count of the sendable mails of the specified account * * @param accountId the id of the account * @return -1 if error, else the sendable message count */ private static int getSendableMessageCount(Context context, long accountId) { int count = 0; long outboxId = Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_OUTBOX); if (outboxId == Mailbox.NO_MAILBOX) { return -1; } ContentResolver resolver = context.getContentResolver(); Cursor c = resolver.query( EmailContent.Message.CONTENT_URI, EmailContent.Message.ID_COLUMN_PROJECTION, EmailContent.Message.MAILBOX_KEY + "=?", new String[] {Long.toString(outboxId)}, null); try { if (c == null || c.getCount() <= 0) { return -1; } while (c.moveToNext()) { long messageId = c.getLong(0); if (Utility.hasUnloadedAttachments(context, messageId)) { LogUtils.logFeature( LogTag.SENDMAIL_TAG, "Can't send #" + messageId + "; unloaded attachments"); continue; } else { count++; } } } finally { if (c != null) { c.close(); } } return count; }
public void addData(EmailContent.Message msg, int endingTag) throws IOException { ArrayList<EmailContent.Attachment> atts = new ArrayList<EmailContent.Attachment>(); boolean truncated = false; while (nextTag(endingTag) != END) { switch (tag) { case Tags.EMAIL_ATTACHMENTS: case Tags.BASE_ATTACHMENTS: // BASE_ATTACHMENTS is used in EAS 12.0 and up attachmentsParser(atts, msg, tag); break; case Tags.EMAIL_TO: msg.mTo = Address.pack(Address.parse(getValue(), false)); break; case Tags.EMAIL_FROM: Address[] froms = Address.parse(getValue(), false); if (froms != null && froms.length > 0) { msg.mDisplayName = froms[0].toFriendly(); } msg.mFrom = Address.toString(froms); break; case Tags.EMAIL_CC: msg.mCc = Address.pack(Address.parse(getValue(), false)); break; case Tags.EMAIL_REPLY_TO: msg.mReplyTo = Address.pack(Address.parse(getValue(), false)); break; case Tags.EMAIL_DATE_RECEIVED: try { msg.mTimeStamp = Utility.parseEmailDateTimeToMillis(getValue()); } catch (ParseException e) { LogUtils.w(TAG, "Parse error for EMAIL_DATE_RECEIVED tag.", e); } break; case Tags.EMAIL_SUBJECT: msg.mSubject = getValue(); break; case Tags.EMAIL_READ: msg.mFlagRead = getValueInt() == 1; break; case Tags.BASE_BODY: bodyParser(msg); break; case Tags.EMAIL_FLAG: msg.mFlagFavorite = flagParser(); break; case Tags.EMAIL_MIME_TRUNCATED: truncated = getValueInt() == 1; break; case Tags.EMAIL_MIME_DATA: // We get MIME data for EAS 2.5. First we parse it, then we take the // html and/or plain text data and store it in the message if (truncated) { // If the MIME data is truncated, don't bother parsing it, because // it will take time and throw an exception anyway when EOF is reached // In this case, we will load the body separately by tagging the message // "partially loaded". // Get the data (and ignore it) getValue(); userLog("Partially loaded: ", msg.mServerId); msg.mFlagLoaded = EmailContent.Message.FLAG_LOADED_PARTIAL; mFetchNeeded = true; } else { mimeBodyParser(msg, getValue()); } break; case Tags.EMAIL_BODY: String text = getValue(); msg.mText = text; break; case Tags.EMAIL_MESSAGE_CLASS: String messageClass = getValue(); if (messageClass.equals("IPM.Schedule.Meeting.Request")) { msg.mFlags |= EmailContent.Message.FLAG_INCOMING_MEETING_INVITE; } else if (messageClass.equals("IPM.Schedule.Meeting.Canceled")) { msg.mFlags |= EmailContent.Message.FLAG_INCOMING_MEETING_CANCEL; } break; case Tags.EMAIL_MEETING_REQUEST: meetingRequestParser(msg); break; case Tags.EMAIL_THREAD_TOPIC: msg.mThreadTopic = getValue(); break; case Tags.RIGHTS_LICENSE: skipParser(tag); break; case Tags.EMAIL2_CONVERSATION_ID: msg.mServerConversationId = Base64.encodeToString(getValueBytes(), Base64.URL_SAFE); break; case Tags.EMAIL2_CONVERSATION_INDEX: // Ignore this byte array since we're not constructing a tree. getValueBytes(); break; case Tags.EMAIL2_LAST_VERB_EXECUTED: int val = getValueInt(); if (val == LAST_VERB_REPLY || val == LAST_VERB_REPLY_ALL) { // We aren't required to distinguish between reply and reply all here msg.mFlags |= EmailContent.Message.FLAG_REPLIED_TO; } else if (val == LAST_VERB_FORWARD) { msg.mFlags |= EmailContent.Message.FLAG_FORWARDED; } break; default: skipTag(); } } if (atts.size() > 0) { msg.mAttachments = atts; } if ((msg.mFlags & EmailContent.Message.FLAG_INCOMING_MEETING_MASK) != 0) { String text = TextUtilities.makeSnippetFromHtmlText(msg.mText != null ? msg.mText : msg.mHtml); if (TextUtils.isEmpty(text)) { // Create text for this invitation String meetingInfo = msg.mMeetingInfo; if (!TextUtils.isEmpty(meetingInfo)) { PackedString ps = new PackedString(meetingInfo); ContentValues values = new ContentValues(); putFromMeeting( ps, MeetingInfo.MEETING_LOCATION, values, CalendarContract.Events.EVENT_LOCATION); String dtstart = ps.get(MeetingInfo.MEETING_DTSTART); if (!TextUtils.isEmpty(dtstart)) { try { final long startTime = Utility.parseEmailDateTimeToMillis(dtstart); values.put(CalendarContract.Events.DTSTART, startTime); } catch (ParseException e) { LogUtils.w(TAG, "Parse error for MEETING_DTSTART tag.", e); } } putFromMeeting(ps, MeetingInfo.MEETING_ALL_DAY, values, CalendarContract.Events.ALL_DAY); msg.mText = CalendarUtilities.buildMessageTextFromEntityValues(mContext, values, null); msg.mHtml = Html.toHtml(new SpannedString(msg.mText)); } } } }
public static void sendMailImpl(Context context, long accountId) { /// M: We Can't send mail in low storage state @{ if (StorageLowState.checkIfStorageLow(context)) { LogUtils.e(Logging.LOG_TAG, "Can't send mail due to low storage"); return; } /// @} /** M: Get the sendable mails count of the account and notify this sending @{ */ final int count = getSendableMessageCount(context, accountId); LogUtils.logFeature(LogTag.SENDMAIL_TAG, "sendable message count [%d]", count); if (count <= 0) { return; } SendNotificationProxy.getInstance(context) .showSendingNotification(accountId, NotificationController.SEND_MAIL, count); /** @} */ final Account account = Account.restoreAccountWithId(context, accountId); TrafficStats.setThreadStatsTag(TrafficFlags.getSmtpFlags(context, account)); final NotificationController nc = NotificationController.getInstance(context); // 1. Loop through all messages in the account's outbox final long outboxId = Mailbox.findMailboxOfType(context, account.mId, Mailbox.TYPE_OUTBOX); if (outboxId == Mailbox.NO_MAILBOX) { return; } final ContentResolver resolver = context.getContentResolver(); final Cursor c = resolver.query( EmailContent.Message.CONTENT_URI, EmailContent.Message.ID_COLUMN_PROJECTION, EmailContent.Message.MAILBOX_KEY + "=?", new String[] {Long.toString(outboxId)}, null); try { // 2. exit early if (c.getCount() <= 0) { return; } final Sender sender = Sender.getInstance(context, account); final Store remoteStore = Store.getInstance(account, context); final ContentValues moveToSentValues; if (remoteStore.requireCopyMessageToSentFolder()) { Mailbox sentFolder = Mailbox.restoreMailboxOfType(context, accountId, Mailbox.TYPE_SENT); moveToSentValues = new ContentValues(); moveToSentValues.put(MessageColumns.MAILBOX_KEY, sentFolder.mId); } else { moveToSentValues = null; } // 3. loop through the available messages and send them /** M: mark should we cancel the Login Failed Notification. */ boolean shouldCancelNf = false; while (c.moveToNext()) { long messageId = -1; if (moveToSentValues != null) { moveToSentValues.remove(EmailContent.MessageColumns.FLAGS); } try { messageId = c.getLong(0); // Don't send messages with unloaded attachments if (Utility.hasUnloadedAttachments(context, messageId)) { LogUtils.logFeature( LogTag.SENDMAIL_TAG, "Can't send #" + messageId + "; unloaded attachments"); continue; } sender.sendMessage(messageId); } catch (MessagingException me) { LogUtils.logFeature( LogTag.SENDMAIL_TAG, "<<< Smtp send message failed id [%s], exception: %s", messageId, me); // report error for this message, but keep trying others if (me instanceof AuthenticationFailedException) { shouldCancelNf = false; nc.showLoginFailedNotification(account.mId); } /// M: One mail sent failed SendNotificationProxy.getInstance(context) .showSendingNotification(account.mId, NotificationController.SEND_FAILED, 1); continue; } /// M: One mail sent complete SendNotificationProxy.getInstance(context) .showSendingNotification(account.mId, NotificationController.SEND_COMPLETE, 1); // 4. move to sent, or delete final Uri syncedUri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId); // Delete all cached files AttachmentUtilities.deleteAllCachedAttachmentFiles(context, account.mId, messageId); if (moveToSentValues != null) { // If this is a forwarded message and it has attachments, delete them, as they // duplicate information found elsewhere (on the server). This saves storage. final EmailContent.Message msg = EmailContent.Message.restoreMessageWithId(context, messageId); if ((msg.mFlags & EmailContent.Message.FLAG_TYPE_FORWARD) != 0) { AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, messageId); } /// M: un-mark sending status after sending final int flags = msg.mFlags & ~(EmailContent.Message.FLAG_TYPE_REPLY | EmailContent.Message.FLAG_TYPE_FORWARD | EmailContent.Message.FLAG_TYPE_REPLY_ALL | EmailContent.Message.FLAG_TYPE_ORIGINAL | EmailContent.Message.FLAG_STATUS_SENDING); moveToSentValues.put(EmailContent.MessageColumns.FLAGS, flags); resolver.update(syncedUri, moveToSentValues, null, null); } else { AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, messageId); final Uri uri = ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, messageId); resolver.delete(uri, null, null); resolver.delete(syncedUri, null, null); } shouldCancelNf = true; } if (shouldCancelNf) { nc.cancelLoginFailedNotification(account.mId); } } catch (MessagingException me) { if (me instanceof AuthenticationFailedException) { nc.showLoginFailedNotification(account.mId); } /// M: All mails failed to be sent, caused by fail to get instance of store SendNotificationProxy.getInstance(context) .showSendingNotification(account.mId, NotificationController.SEND_FAILED, c.getCount()); } finally { c.close(); } }
@Override public void loadAttachment( final IEmailServiceCallback cb, final long attachmentId, final boolean background) throws RemoteException { /// M: We Can't load attachment in low storage state @{ if (StorageLowState.checkIfStorageLow(mContext)) { LogUtils.e(Logging.LOG_TAG, "Can't load attachment due to low storage"); cb.loadAttachmentStatus(0, attachmentId, EmailServiceStatus.SUCCESS, 0); return; } /// @} Folder remoteFolder = null; try { // 1. Check if the attachment is already here and return early in that case Attachment attachment = Attachment.restoreAttachmentWithId(mContext, attachmentId); if (attachment == null) { cb.loadAttachmentStatus(0, attachmentId, EmailServiceStatus.ATTACHMENT_NOT_FOUND, 0); return; } final long messageId = attachment.mMessageKey; final EmailContent.Message message = EmailContent.Message.restoreMessageWithId(mContext, attachment.mMessageKey); if (message == null) { cb.loadAttachmentStatus(messageId, attachmentId, EmailServiceStatus.MESSAGE_NOT_FOUND, 0); return; } // If the message is loaded, just report that we're finished if (Utility.attachmentExists(mContext, attachment) && attachment.mUiState == UIProvider.AttachmentState.SAVED) { cb.loadAttachmentStatus(messageId, attachmentId, EmailServiceStatus.SUCCESS, 0); return; } // Say we're starting... cb.loadAttachmentStatus(messageId, attachmentId, EmailServiceStatus.IN_PROGRESS, 0); // 2. Open the remote folder. final Account account = Account.restoreAccountWithId(mContext, message.mAccountKey); Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey); if (mailbox.mType == Mailbox.TYPE_OUTBOX /// M: View an attachment which comes from refMessage need sourceKey to identify || mailbox.mType == Mailbox.TYPE_DRAFTS) { long sourceId = Utility.getFirstRowLong( mContext, Body.CONTENT_URI, new String[] {BodyColumns.SOURCE_MESSAGE_KEY}, BodyColumns.MESSAGE_KEY + "=?", new String[] {Long.toString(messageId)}, null, 0, -1L); if (sourceId != -1) { EmailContent.Message sourceMsg = EmailContent.Message.restoreMessageWithId(mContext, sourceId); if (sourceMsg != null) { mailbox = Mailbox.restoreMailboxWithId(mContext, sourceMsg.mMailboxKey); message.mServerId = sourceMsg.mServerId; } } } else if (mailbox.mType == Mailbox.TYPE_SEARCH && message.mMainMailboxKey != 0) { mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMainMailboxKey); } if (account == null || mailbox == null) { // If the account/mailbox are gone, just report success; the UI handles this cb.loadAttachmentStatus(messageId, attachmentId, EmailServiceStatus.SUCCESS, 0); return; } TrafficStats.setThreadStatsTag(TrafficFlags.getAttachmentFlags(mContext, account)); final Store remoteStore = Store.getInstance(account, mContext); remoteFolder = remoteStore.getFolder(mailbox.mServerId); remoteFolder.open(OpenMode.READ_WRITE); // 3. Generate a shell message in which to retrieve the attachment, // and a shell BodyPart for the attachment. Then glue them together. final Message storeMessage = remoteFolder.createMessage(message.mServerId); final MimeBodyPart storePart = new MimeBodyPart(); storePart.setSize((int) attachment.mSize); storePart.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, attachment.mLocation); storePart.setHeader( MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n name=\"%s\"", attachment.mMimeType, attachment.mFileName)); // TODO is this always true for attachments? I think we dropped the // true encoding along the way /// M: set encoding type according to data base record. String encoding = attachment.mEncoding; if (TextUtils.isEmpty(encoding)) { encoding = "base64"; } storePart.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, encoding); final MimeMultipart multipart = new MimeMultipart(); multipart.setSubType("mixed"); multipart.addBodyPart(storePart); storeMessage.setHeader(MimeHeader.HEADER_CONTENT_TYPE, "multipart/mixed"); storeMessage.setBody(multipart); // 4. Now ask for the attachment to be fetched final FetchProfile fp = new FetchProfile(); fp.add(storePart); remoteFolder.fetch( new Message[] {storeMessage}, fp, new MessageRetrievalListenerBridge(messageId, attachmentId, cb)); // If we failed to load the attachment, throw an Exception here, so that // AttachmentDownloadService knows that we failed if (storePart.getBody() == null) { throw new MessagingException("Attachment not loaded."); } // Save the attachment to wherever it's going AttachmentUtilities.saveAttachment( mContext, storePart.getBody().getInputStream(), attachment); // 6. Report success cb.loadAttachmentStatus(messageId, attachmentId, EmailServiceStatus.SUCCESS, 0); } catch (MessagingException me) { LogUtils.i(Logging.LOG_TAG, me, "Error loading attachment"); final ContentValues cv = new ContentValues(1); cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.FAILED); final Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId); mContext.getContentResolver().update(uri, cv, null, null); cb.loadAttachmentStatus(0, attachmentId, EmailServiceStatus.CONNECTION_ERROR, 0); } finally { if (remoteFolder != null) { remoteFolder.close(false); } } }
public void fetchInternal(Message[] messages, FetchProfile fp, MessageRetrievalListener listener) throws MessagingException { if (messages.length == 0) { return; } checkOpen(); HashMap<String, Message> messageMap = new HashMap<String, Message>(); for (Message m : messages) { messageMap.put(m.getUid(), m); } /* * Figure out what command we are going to run: * FLAGS - UID FETCH (FLAGS) * ENVELOPE - UID FETCH (INTERNALDATE UID RFC822.SIZE FLAGS BODY.PEEK[ * HEADER.FIELDS (date subject from content-type to cc)]) * STRUCTURE - UID FETCH (BODYSTRUCTURE) * BODY_SANE - UID FETCH (BODY.PEEK[]<0.N>) where N = max bytes returned * BODY - UID FETCH (BODY.PEEK[]) * Part - UID FETCH (BODY.PEEK[ID]) where ID = mime part ID */ final LinkedHashSet<String> fetchFields = new LinkedHashSet<String>(); fetchFields.add(ImapConstants.UID); if (fp.contains(FetchProfile.Item.FLAGS)) { fetchFields.add(ImapConstants.FLAGS); } if (fp.contains(FetchProfile.Item.ENVELOPE)) { fetchFields.add(ImapConstants.INTERNALDATE); fetchFields.add(ImapConstants.RFC822_SIZE); fetchFields.add(ImapConstants.FETCH_FIELD_HEADERS); } if (fp.contains(FetchProfile.Item.STRUCTURE)) { fetchFields.add(ImapConstants.BODYSTRUCTURE); } if (fp.contains(FetchProfile.Item.BODY_SANE)) { fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK_SANE); } if (fp.contains(FetchProfile.Item.BODY)) { fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK); } final Part fetchPart = fp.getFirstPart(); if (fetchPart != null) { String[] partIds = fetchPart.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); if (partIds != null) { fetchFields.add( ImapConstants.FETCH_FIELD_BODY_PEEK_BARE + "[" + partIds[0] + "]" + (mFetchSize > 0 ? String.format("<0.%d>", mFetchSize) : "")); } } try { mConnection.sendCommand( String.format( ImapConstants.UID_FETCH + " %s (%s)", ImapStore.joinMessageUids(messages), Utility.combine(fetchFields.toArray(new String[fetchFields.size()]), ' ')), false); ImapResponse response; int messageNumber = 0; do { response = null; try { response = mConnection.readResponse(listener); if (!response.isDataResponse(1, ImapConstants.FETCH)) { continue; // Ignore } final ImapList fetchList = response.getListOrEmpty(2); final String uid = fetchList.getKeyedStringOrEmpty(ImapConstants.UID).getString(); if (TextUtils.isEmpty(uid)) continue; ImapMessage message = (ImapMessage) messageMap.get(uid); if (message == null) continue; if (fp.contains(FetchProfile.Item.FLAGS)) { final ImapList flags = fetchList.getKeyedListOrEmpty(ImapConstants.FLAGS); for (int i = 0, count = flags.size(); i < count; i++) { final ImapString flag = flags.getStringOrEmpty(i); if (flag.is(ImapConstants.FLAG_DELETED)) { message.setFlagInternal(Flag.DELETED, true); } else if (flag.is(ImapConstants.FLAG_ANSWERED)) { message.setFlagInternal(Flag.ANSWERED, true); } else if (flag.is(ImapConstants.FLAG_SEEN)) { message.setFlagInternal(Flag.SEEN, true); } else if (flag.is(ImapConstants.FLAG_FLAGGED)) { message.setFlagInternal(Flag.FLAGGED, true); } } } if (fp.contains(FetchProfile.Item.ENVELOPE)) { final Date internalDate = fetchList.getKeyedStringOrEmpty(ImapConstants.INTERNALDATE).getDateOrNull(); final int size = fetchList.getKeyedStringOrEmpty(ImapConstants.RFC822_SIZE).getNumberOrZero(); final InputStream header = fetchList .getKeyedStringOrEmpty(ImapConstants.BODY_BRACKET_HEADER, true) .getAsStream(); message.setInternalDate(internalDate); message.setSize(size); message.parse(header); } if (fp.contains(FetchProfile.Item.STRUCTURE)) { ImapList bs = fetchList.getKeyedListOrEmpty(ImapConstants.BODYSTRUCTURE); if (!bs.isEmpty()) { try { parseBodyStructure(bs, message, ImapConstants.TEXT); } catch (MessagingException e) { if (Logging.LOGD) { Log.v(Logging.LOG_TAG, "Error handling message", e); } message.setBody(null); } } } if (fp.contains(FetchProfile.Item.BODY) || fp.contains(FetchProfile.Item.BODY_SANE)) { // Body is keyed by "BODY[]...". // Previously used "BODY[..." but this can be confused with "BODY[HEADER..." // TODO Should we accept "RFC822" as well?? ImapString body = fetchList.getKeyedStringOrEmpty("BODY[]", true); String bodyText = body.getString(); InputStream bodyStream = body.getAsStream(); message.parse(bodyStream); } if (fetchPart != null && fetchPart.getSize() > 0) { InputStream bodyStream = fetchList.getKeyedStringOrEmpty("BODY[", true).getAsStream(); String contentType = fetchPart.getContentType(); String[] encodingHeader = fetchPart.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING); String contentTransferEncoding = null; if (encodingHeader != null) { contentTransferEncoding = encodingHeader[0]; } // TODO Don't create 2 temp files. // decodeBody creates BinaryTempFileBody, but we could avoid this // if we implement ImapStringBody. // (We'll need to share a temp file. Protect it with a ref-count.) fetchPart.setBody( decodeBody(bodyStream, contentTransferEncoding, fetchPart.getSize(), listener)); } if (listener != null) { listener.messageRetrieved(message); } } finally { destroyResponses(); } } while (!response.isTagged()); } catch (IOException ioe) { throw ioExceptionHandler(mConnection, ioe); } }
@Override public void onClick(View view) { if (!isMessageOpen()) { return; // Ignore. } switch (view.getId()) { case R.id.reply: mCallback.onReply(); return; case R.id.reply_all: mCallback.onReplyAll(); return; case R.id.forward: mCallback.onForward(); return; case R.id.favorite: onClickFavorite(); return; case R.id.invite_link: onInviteLinkClicked(); return; case R.id.accept: onRespondToInvite( EmailServiceConstants.MEETING_REQUEST_ACCEPTED, R.string.message_view_invite_toast_yes); return; case R.id.maybe: onRespondToInvite( EmailServiceConstants.MEETING_REQUEST_TENTATIVE, R.string.message_view_invite_toast_maybe); return; case R.id.decline: onRespondToInvite( EmailServiceConstants.MEETING_REQUEST_DECLINED, R.string.message_view_invite_toast_no); return; case R.id.more: { PopupMenu popup = new PopupMenu(getActivity(), mMoreButton); Menu menu = popup.getMenu(); popup.getMenuInflater().inflate(R.menu.message_header_overflow_menu, menu); // Remove Reply if ReplyAll icon is visible or vice versa menu.removeItem(mDefaultReplyAll ? R.id.reply_all : R.id.reply); if (!FeatureQuery.FEATURE_EMAIL_SET_SYNCSIZE || (Utility.ENTIRE_MAIL == Utility.getAccountSyncSize(mContext, getMessage().mAccountKey)) || (getMessage().mFlagLoaded == Message.FLAG_LOADED_COMPLETE)) { menu.removeItem(R.id.fetch_entire_mail); } popup.setOnMenuItemClickListener(this); popup.show(); break; } } super.onClick(view); }