/**
   * Add a single attachment part to the message
   *
   * <p>This will skip adding attachments if they are already found in the attachments table. The
   * heuristic for this will fail (false-positive) if two identical attachments are included in a
   * single POP3 message. TODO: Fix that, by (elsewhere) simulating an mLocation value based on the
   * attachments position within the list of multipart/mixed elements. This would make every POP3
   * attachment unique, and might also simplify the code (since we could just look at the positions,
   * and ignore the filename, etc.)
   *
   * <p>TODO: Take a closer look at encoding and deal with it if necessary.
   *
   * @param context a context for file operations
   * @param localMessage the attachments will be built against this message
   * @param part a single attachment part from POP or IMAP
   */
  public static void addOneAttachment(
      final Context context, final EmailContent.Message localMessage, final Part part)
      throws MessagingException, IOException {
    final Attachment localAttachment = mimePartToAttachment(part);
    localAttachment.mMessageKey = localMessage.mId;
    localAttachment.mAccountKey = localMessage.mAccountKey;

    if (DEBUG_ATTACHMENTS) {
      LogUtils.d(Logging.LOG_TAG, "Add attachment " + localAttachment);
    }

    // To prevent duplication - do we already have a matching attachment?
    // The fields we'll check for equality are:
    //  mFileName, mMimeType, mContentId, mMessageKey, mLocation
    // NOTE:  This will false-positive if you attach the exact same file, twice, to a POP3
    // message.  We can live with that - you'll get one of the copies.
    final Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, localMessage.mId);
    final Cursor cursor =
        context.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION, null, null, null);
    boolean attachmentFoundInDb = false;
    try {
      while (cursor.moveToNext()) {
        final Attachment dbAttachment = new Attachment();
        dbAttachment.restore(cursor);
        // We test each of the fields here (instead of in SQL) because they may be
        // null, or may be strings.
        if (!TextUtils.equals(dbAttachment.mFileName, localAttachment.mFileName)
            || !TextUtils.equals(dbAttachment.mMimeType, localAttachment.mMimeType)
            || !TextUtils.equals(dbAttachment.mContentId, localAttachment.mContentId)
            || !TextUtils.equals(dbAttachment.mLocation, localAttachment.mLocation)) {
          continue;
        }
        // We found a match, so use the existing attachment id, and stop looking/looping
        attachmentFoundInDb = true;
        localAttachment.mId = dbAttachment.mId;
        if (DEBUG_ATTACHMENTS) {
          LogUtils.d(Logging.LOG_TAG, "Skipped, found db attachment " + dbAttachment);
        }
        break;
      }
    } finally {
      cursor.close();
    }

    // Save the attachment (so far) in order to obtain an id
    if (!attachmentFoundInDb) {
      localAttachment.save(context);
    }

    // If an attachment body was actually provided, we need to write the file now
    saveAttachmentBody(context, part, localAttachment, localMessage.mAccountKey);

    if (localMessage.mAttachments == null) {
      localMessage.mAttachments = new ArrayList<Attachment>();
    }
    localMessage.mAttachments.add(localAttachment);
    localMessage.mFlagAttachment = true;
  }
  private void attachmentParser(
      final ArrayList<EmailContent.Attachment> atts,
      final EmailContent.Message msg,
      final int endingTag)
      throws IOException {
    String fileName = null;
    String length = null;
    String location = null;
    boolean isInline = false;
    String contentId = null;

    while (nextTag(endingTag) != END) {
      switch (tag) {
          // We handle both EAS 2.5 and 12.0+ attachments here
        case Tags.EMAIL_DISPLAY_NAME:
        case Tags.BASE_DISPLAY_NAME:
          fileName = getValue();
          break;
        case Tags.EMAIL_ATT_NAME:
        case Tags.BASE_FILE_REFERENCE:
          location = getValue();
          break;
        case Tags.EMAIL_ATT_SIZE:
        case Tags.BASE_ESTIMATED_DATA_SIZE:
          length = getValue();
          break;
        case Tags.BASE_IS_INLINE:
          String isInlineStr = getValue();
          isInline = "true".equalsIgnoreCase(isInlineStr) || "1".equals(isInlineStr);
          break;
        case Tags.BASE_CONTENT_ID:
          contentId = getValue();
          break;
        default:
          skipTag();
      }
    }

    if ((fileName != null) && (length != null) && (location != null)) {
      EmailContent.Attachment att = new EmailContent.Attachment();
      att.mEncoding = "base64";
      att.mSize = Long.parseLong(length);
      att.mFileName = fileName;
      att.mLocation = location;
      att.mMimeType = getMimeTypeFromFileName(fileName);
      att.mAccountKey = mAccount.mId;
      // Save away the contentId, if we've got one (for inline images); note that the
      // EAS docs appear to be wrong about the tags used; inline images come with
      // contentId rather than contentLocation, when sent from Ex03, Ex07, and Ex10
      if (isInline && !TextUtils.isEmpty(contentId)) {
        att.mContentId = contentId;
      }
      // Check if this attachment can't be downloaded due to an account policy
      if (mPolicy != null) {
        if (mPolicy.mDontAllowAttachments
            || (mPolicy.mMaxAttachmentSize > 0 && (att.mSize > mPolicy.mMaxAttachmentSize))) {
          att.mFlags = EmailContent.Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD;
        }
      }
      atts.add(att);
      msg.mFlagAttachment = true;
    }
  }