public InputStream getAttachmentInputStream(final String attachmentId) throws MessagingException { return database.execute( false, new DbCallback<InputStream>() { @Override public InputStream doDbWork(final SQLiteDatabase db) throws WrappedException { Cursor cursor = db.query( "message_parts", new String[] {"data_location", "data", "encoding"}, "id = ?", new String[] {attachmentId}, null, null, null); try { if (!cursor.moveToFirst()) { return null; } int location = cursor.getInt(0); String encoding = cursor.getString(2); InputStream rawInputStream = getRawAttachmentInputStream(cursor, location, attachmentId); return getDecodingInputStream(rawInputStream, encoding); } finally { cursor.close(); } } }); }
public long getSize() throws MessagingException { final StorageManager storageManager = StorageManager.getInstance(context); final File attachmentDirectory = storageManager.getAttachmentDirectory(uUid, database.getStorageProviderId()); return database.execute( false, new DbCallback<Long>() { @Override public Long doDbWork(final SQLiteDatabase db) { final File[] files = attachmentDirectory.listFiles(); long attachmentLength = 0; if (files != null) { for (File file : files) { if (file.exists()) { attachmentLength += file.length(); } } } final File dbFile = storageManager.getDatabase(uUid, database.getStorageProviderId()); return dbFile.length() + attachmentLength; } }); }
public AttachmentInfo getAttachmentInfo(final String attachmentId) throws MessagingException { return database.execute( false, new DbCallback<AttachmentInfo>() { @Override public AttachmentInfo doDbWork(final SQLiteDatabase db) throws WrappedException { Cursor cursor = db.query( "message_parts", new String[] {"display_name", "decoded_body_size", "mime_type"}, "id = ?", new String[] {attachmentId}, null, null, null); try { if (!cursor.moveToFirst()) { return null; } String name = cursor.getString(0); long size = cursor.getLong(1); String mimeType = cursor.getString(2); final AttachmentInfo attachmentInfo = new AttachmentInfo(); attachmentInfo.name = name; attachmentInfo.size = size; attachmentInfo.type = mimeType; return attachmentInfo; } finally { cursor.close(); } } }); }
/* * Given a query string, actually do the query for the messages and * call the MessageRetrievalListener for each one */ List<LocalMessage> getMessages( final MessageRetrievalListener<LocalMessage> listener, final LocalFolder folder, final String queryString, final String[] placeHolders) throws MessagingException { final List<LocalMessage> messages = new ArrayList<>(); final int j = database.execute( false, new DbCallback<Integer>() { @Override public Integer doDbWork(final SQLiteDatabase db) throws WrappedException { Cursor cursor = null; int i = 0; try { cursor = db.rawQuery(queryString + " LIMIT 10", placeHolders); while (cursor.moveToNext()) { LocalMessage message = new LocalMessage(LocalStore.this, null, folder); message.populateFromGetMessageCursor(cursor); messages.add(message); if (listener != null) { listener.messageFinished(message, i, -1); } i++; } cursor.close(); cursor = db.rawQuery(queryString + " LIMIT -1 OFFSET 10", placeHolders); while (cursor.moveToNext()) { LocalMessage message = new LocalMessage(LocalStore.this, null, folder); message.populateFromGetMessageCursor(cursor); messages.add(message); if (listener != null) { listener.messageFinished(message, i, -1); } i++; } } catch (Exception e) { Log.d(K9.LOG_TAG, "Got an exception", e); } finally { Utility.closeQuietly(cursor); } return i; } }); if (listener != null) { listener.messagesFinished(j); } return Collections.unmodifiableList(messages); }
public void removePendingCommands() throws MessagingException { database.execute( false, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException { db.delete("pending_commands", null, null); return null; } }); }
public void removePendingCommand(final PendingCommand command) throws MessagingException { database.execute( false, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException { db.delete("pending_commands", "id = ?", new String[] {Long.toString(command.mId)}); return null; } }); }
/** * Split database operations with a large set of arguments into multiple SQL statements. * * <p>At the time of this writing (2012-12-06) SQLite only supports around 1000 arguments. That's * why we have to split SQL statements with a large set of arguments into multiple SQL statements * each working on a subset of the arguments. * * @param selectionCallback Supplies the argument set and the code to query/update the database. * @param batchSize The maximum size of the selection set in each SQL statement. * @throws MessagingException */ public void doBatchSetSelection(final BatchSetSelection selectionCallback, final int batchSize) throws MessagingException { final List<String> selectionArgs = new ArrayList<>(); int start = 0; while (start < selectionCallback.getListSize()) { final StringBuilder selection = new StringBuilder(); selection.append(" IN ("); int count = Math.min(selectionCallback.getListSize() - start, batchSize); for (int i = start, end = start + count; i < end; i++) { if (i > start) { selection.append(",?"); } else { selection.append("?"); } selectionArgs.add(selectionCallback.getListItem(i)); } selection.append(")"); try { database.execute( true, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { selectionCallback.doDbWork( db, selection.toString(), selectionArgs.toArray(EMPTY_STRING_ARRAY)); return null; } }); selectionCallback.postDbWork(); } catch (WrappedException e) { throw (MessagingException) e.getCause(); } selectionArgs.clear(); start += count; } }
public void createFolders(final List<LocalFolder> foldersToCreate, final int visibleLimit) throws MessagingException { database.execute( true, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException { for (LocalFolder folder : foldersToCreate) { String name = folder.getName(); final LocalFolder.PreferencesHolder prefHolder = folder.new PreferencesHolder(); // When created, special folders should always be displayed // inbox should be integrated // and the inbox and drafts folders should be syncced by default if (mAccount.isSpecialFolder(name)) { prefHolder.inTopGroup = true; prefHolder.displayClass = LocalFolder.FolderClass.FIRST_CLASS; if (name.equalsIgnoreCase(mAccount.getInboxFolderName())) { prefHolder.integrate = true; prefHolder.notifyClass = LocalFolder.FolderClass.FIRST_CLASS; prefHolder.pushClass = LocalFolder.FolderClass.FIRST_CLASS; } else { prefHolder.pushClass = LocalFolder.FolderClass.INHERITED; } if (name.equalsIgnoreCase(mAccount.getInboxFolderName()) || name.equalsIgnoreCase(mAccount.getDraftsFolderName())) { prefHolder.syncClass = LocalFolder.FolderClass.FIRST_CLASS; } else { prefHolder.syncClass = LocalFolder.FolderClass.NO_CLASS; } } folder.refresh(name, prefHolder); // Recover settings from Preferences db.execSQL( "INSERT INTO folders (name, visible_limit, top_group, display_class, poll_class, notify_class, push_class, integrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", new Object[] { name, visibleLimit, prefHolder.inTopGroup ? 1 : 0, prefHolder.displayClass.name(), prefHolder.syncClass.name(), prefHolder.notifyClass.name(), prefHolder.pushClass.name(), prefHolder.integrate ? 1 : 0, }); } return null; } }); }
public void resetVisibleLimits(int visibleLimit) throws MessagingException { final ContentValues cv = new ContentValues(); cv.put("visible_limit", Integer.toString(visibleLimit)); cv.put("more_messages", MoreMessages.UNKNOWN.getDatabaseName()); database.execute( false, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException { db.update("folders", cv, null, null); return null; } }); }
private void markAllMessagePartsDataAsMissing() throws MessagingException { database.execute( false, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException { ContentValues cv = new ContentValues(); cv.put("data_location", DataLocation.MISSING); db.update("message_parts", cv, null, null); return null; } }); }
public void compact() throws MessagingException { if (K9.DEBUG) Log.i(K9.LOG_TAG, "Before compaction size = " + getSize()); database.execute( false, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException { db.execSQL("VACUUM"); return null; } }); if (K9.DEBUG) Log.i(K9.LOG_TAG, "After compaction size = " + getSize()); }
public void addPendingCommand(PendingCommand command) throws MessagingException { for (int i = 0; i < command.arguments.length; i++) { command.arguments[i] = UrlEncodingHelper.encodeUtf8(command.arguments[i]); } final ContentValues cv = new ContentValues(); cv.put("command", command.command); cv.put("arguments", Utility.combine(command.arguments, ',')); database.execute( false, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException { db.insert("pending_commands", "command", cv); return null; } }); }
public int getFolderCount() throws MessagingException { return database.execute( false, new DbCallback<Integer>() { @Override public Integer doDbWork(final SQLiteDatabase db) { Cursor cursor = null; try { cursor = db.rawQuery("SELECT COUNT(*) FROM folders", null); cursor.moveToFirst(); return cursor.getInt(0); // folder count } finally { Utility.closeQuietly(cursor); } } }); }
// TODO this takes about 260-300ms, seems slow. @Override public List<LocalFolder> getPersonalNamespaces(boolean forceListAll) throws MessagingException { final List<LocalFolder> folders = new LinkedList<>(); try { database.execute( false, new DbCallback<List<? extends Folder>>() { @Override public List<? extends Folder> doDbWork(final SQLiteDatabase db) throws WrappedException { Cursor cursor = null; try { cursor = db.rawQuery( "SELECT " + GET_FOLDER_COLS + " FROM folders " + "ORDER BY name ASC", null); while (cursor.moveToNext()) { if (cursor.isNull(FOLDER_ID_INDEX)) { continue; } String folderName = cursor.getString(FOLDER_NAME_INDEX); LocalFolder folder = new LocalFolder(LocalStore.this, folderName); folder.open(cursor); folders.add(folder); } return folders; } catch (MessagingException e) { throw new WrappedException(e); } finally { Utility.closeQuietly(cursor); } } }); } catch (WrappedException e) { throw (MessagingException) e.getCause(); } return folders; }
public void clear() throws MessagingException { if (K9.DEBUG) Log.i(K9.LOG_TAG, "Before prune size = " + getSize()); deleteAllMessageDataFromDisk(); if (K9.DEBUG) { Log.i(K9.LOG_TAG, "After prune / before compaction size = " + getSize()); Log.i(K9.LOG_TAG, "Before clear folder count = " + getFolderCount()); Log.i(K9.LOG_TAG, "Before clear message count = " + getMessageCount()); Log.i(K9.LOG_TAG, "After prune / before clear size = " + getSize()); } database.execute( false, new DbCallback<Void>() { @Override public Void doDbWork(final SQLiteDatabase db) { // We don't care about threads of deleted messages, so delete the whole table. db.delete("threads", null, null); // Don't delete deleted messages. They are essentially placeholders for UIDs of messages // that have // been deleted locally. db.delete("messages", "deleted = 0", null); return null; } }); compact(); if (K9.DEBUG) { Log.i(K9.LOG_TAG, "After clear message count = " + getMessageCount()); Log.i(K9.LOG_TAG, "After clear size = " + getSize()); } }
public List<PendingCommand> getPendingCommands() throws MessagingException { return database.execute( false, new DbCallback<List<PendingCommand>>() { @Override public List<PendingCommand> doDbWork(final SQLiteDatabase db) throws WrappedException { Cursor cursor = null; try { cursor = db.query( "pending_commands", new String[] {"id", "command", "arguments"}, null, null, null, null, "id ASC"); List<PendingCommand> commands = new ArrayList<>(); while (cursor.moveToNext()) { PendingCommand command = new PendingCommand(); command.mId = cursor.getLong(0); command.command = cursor.getString(1); String arguments = cursor.getString(2); command.arguments = arguments.split(","); for (int i = 0; i < command.arguments.length; i++) { command.arguments[i] = Utility.fastUrlDecode(command.arguments[i]); } commands.add(command); } return commands; } finally { Utility.closeQuietly(cursor); } } }); }