/** Save the body part of a single attachment, to a file in the attachments directory. */
  public static void saveAttachmentBody(
      final Context context, final Part part, final Attachment localAttachment, long accountId)
      throws MessagingException, IOException {
    if (part.getBody() != null) {
      final long attachmentId = localAttachment.mId;

      final File saveIn = AttachmentUtilities.getAttachmentDirectory(context, accountId);

      if (!saveIn.isDirectory() && !saveIn.mkdirs()) {
        throw new IOException("Could not create attachment directory");
      }
      final File saveAs =
          AttachmentUtilities.getAttachmentFilename(context, accountId, attachmentId);

      InputStream in = null;
      FileOutputStream out = null;
      final long copySize;
      try {
        in = part.getBody().getInputStream();
        out = new FileOutputStream(saveAs);
        copySize = IOUtils.copyLarge(in, out);
      } finally {
        if (in != null) {
          in.close();
        }
        if (out != null) {
          out.close();
        }
      }

      // update the attachment with the extra information we now know
      final String contentUriString =
          AttachmentUtilities.getAttachmentUri(accountId, attachmentId).toString();

      localAttachment.mSize = copySize;
      localAttachment.setContentUri(contentUriString);

      // update the attachment in the database as well
      final ContentValues cv = new ContentValues(3);
      cv.put(AttachmentColumns.SIZE, copySize);
      cv.put(AttachmentColumns.CONTENT_URI, contentUriString);
      cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.SAVED);
      final Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId);
      context.getContentResolver().update(uri, cv, null, null);
    }
  }
 /**
  * Open an attachment file. There are two "formats" - "raw", which returns an actual file, and
  * "thumbnail", which attempts to generate a thumbnail image.
  *
  * <p>Thumbnails are cached for easy space recovery and cleanup.
  *
  * <p>TODO: The thumbnail format returns null for its failure cases, instead of throwing
  * FileNotFoundException, and should be fixed for consistency.
  *
  * @throws FileNotFoundException
  */
 @Override
 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
   int match = sURIMatcher.match(uri);
   if (match == ATTACHMENTS_CACHED_FILE_ACCESS) {
     long callingId = Binder.clearCallingIdentity();
     try {
       return getContext().getContentResolver().openFileDescriptor(rebuildUri(uri), "r");
     } finally {
       Binder.restoreCallingIdentity(callingId);
     }
   }
   // If this is a write, the caller must have the EmailProvider permission, which is
   // based on signature only
   if (mode.equals("w")) {
     Context context = getContext();
     if (context.checkCallingOrSelfPermission(EmailContent.PROVIDER_PERMISSION)
         != PackageManager.PERMISSION_GRANTED) {
       throw new FileNotFoundException();
     }
     List<String> segments = uri.getPathSegments();
     String accountId = segments.get(0);
     String id = segments.get(1);
     File saveIn = AttachmentUtilities.getAttachmentDirectory(context, Long.parseLong(accountId));
     if (!saveIn.exists()) {
       saveIn.mkdirs();
     }
     File newFile = new File(saveIn, id);
     return ParcelFileDescriptor.open(
         newFile,
         ParcelFileDescriptor.MODE_READ_WRITE
             | ParcelFileDescriptor.MODE_CREATE
             | ParcelFileDescriptor.MODE_TRUNCATE);
   }
   long callingId = Binder.clearCallingIdentity();
   try {
     List<String> segments = uri.getPathSegments();
     String accountId = segments.get(0);
     String id = segments.get(1);
     String format = segments.get(2);
     if (AttachmentUtilities.FORMAT_THUMBNAIL.equals(format)) {
       int width = Integer.parseInt(segments.get(3));
       int height = Integer.parseInt(segments.get(4));
       String filename = "thmb_" + accountId + "_" + id;
       File dir = getContext().getCacheDir();
       File file = new File(dir, filename);
       if (!file.exists()) {
         Uri attachmentUri =
             AttachmentUtilities.getAttachmentUri(Long.parseLong(accountId), Long.parseLong(id));
         Cursor c = query(attachmentUri, new String[] {Columns.DATA}, null, null, null);
         if (c != null) {
           try {
             if (c.moveToFirst()) {
               attachmentUri = Uri.parse(c.getString(0));
             } else {
               return null;
             }
           } finally {
             c.close();
           }
         }
         String type = getContext().getContentResolver().getType(attachmentUri);
         try {
           InputStream in = getContext().getContentResolver().openInputStream(attachmentUri);
           Bitmap thumbnail = createThumbnail(type, in);
           if (thumbnail == null) {
             return null;
           }
           thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true);
           FileOutputStream out = new FileOutputStream(file);
           thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out);
           out.close();
           in.close();
         } catch (IOException ioe) {
           LogUtils.d(Logging.LOG_TAG, "openFile/thumbnail failed with " + ioe.getMessage());
           return null;
         } catch (OutOfMemoryError oome) {
           LogUtils.d(Logging.LOG_TAG, "openFile/thumbnail failed with " + oome.getMessage());
           return null;
         }
       }
       return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
     } else {
       return ParcelFileDescriptor.open(
           new File(getContext().getDatabasePath(accountId + ".db_att"), id),
           ParcelFileDescriptor.MODE_READ_ONLY);
     }
   } finally {
     Binder.restoreCallingIdentity(callingId);
   }
 }