use of android.content.ContentValues in project k-9 by k9mail.
the class MigrationTo51 method migrateComplexMailContent.
private static MimeStructureState migrateComplexMailContent(SQLiteDatabase db, File attachmentDirOld, File attachmentDirNew, long messageId, String htmlContent, String textContent, MimeHeader mimeHeader, MimeStructureState structureState) throws IOException {
Timber.d("Processing mail with complex data structure as multipart/mixed");
String boundary = MimeUtility.getHeaderParameter(mimeHeader.getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE), "boundary");
if (TextUtils.isEmpty(boundary)) {
boundary = MimeUtil.createUniqueBoundary();
}
mimeHeader.setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("multipart/mixed; boundary=\"%s\";", boundary));
ContentValues cv = new ContentValues();
cv.put("type", MESSAGE_PART_TYPE__UNKNOWN);
cv.put("data_location", DATA_LOCATION__IN_DATABASE);
cv.put("mime_type", "multipart/mixed");
cv.put("header", mimeHeader.toString());
cv.put("boundary", boundary);
structureState.applyValues(cv);
long rootMessagePartId = db.insertOrThrow("message_parts", null, cv);
structureState = structureState.nextMultipartChild(rootMessagePartId);
if (htmlContent != null) {
htmlContent = replaceContentUriWithContentIdInHtmlPart(db, messageId, htmlContent);
}
if (textContent != null && htmlContent != null) {
structureState = insertBodyAsMultipartAlternative(db, structureState, null, textContent, htmlContent);
structureState = structureState.popParent();
} else if (textContent != null) {
structureState = insertTextualPartIntoDatabase(db, structureState, null, textContent, false);
} else if (htmlContent != null) {
structureState = insertTextualPartIntoDatabase(db, structureState, null, htmlContent, true);
}
structureState = insertAttachments(db, attachmentDirOld, attachmentDirNew, messageId, structureState);
return structureState;
}
use of android.content.ContentValues in project k-9 by k9mail.
the class MigrationTo51 method insertMimeAttachmentPart.
private static MimeStructureState insertMimeAttachmentPart(SQLiteDatabase db, File attachmentDirOld, File attachmentDirNew, MimeStructureState structureState, long id, int size, String name, String mimeType, String storeData, String contentUriString, String contentId, String contentDisposition) {
Timber.d("processing attachment %d, %s, %s, %s, %s", id, name, mimeType, storeData, contentUriString);
if (contentDisposition == null) {
contentDisposition = "attachment";
}
MimeHeader mimeHeader = new MimeHeader();
mimeHeader.setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\r\n name=\"%s\"", mimeType, name));
mimeHeader.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, String.format(Locale.US, "%s;\r\n filename=\"%s\";\r\n size=%d", contentDisposition, name, // TODO: Should use encoded word defined in RFC 2231.
size));
if (contentId != null) {
mimeHeader.setHeader(MimeHeader.HEADER_CONTENT_ID, contentId);
}
boolean hasData = contentUriString != null;
File attachmentFileToMove;
if (hasData) {
try {
Uri contentUri = Uri.parse(contentUriString);
List<String> pathSegments = contentUri.getPathSegments();
String attachmentId = pathSegments.get(1);
boolean isMatchingAttachmentId = Long.parseLong(attachmentId) == id;
File attachmentFile = new File(attachmentDirOld, attachmentId);
boolean isExistingAttachmentFile = attachmentFile.exists();
if (!isMatchingAttachmentId) {
Timber.e("mismatched attachment id. mark as missing");
attachmentFileToMove = null;
} else if (!isExistingAttachmentFile) {
Timber.e("attached file doesn't exist. mark as missing");
attachmentFileToMove = null;
} else {
attachmentFileToMove = attachmentFile;
}
} catch (Exception e) {
// anything here fails, conservatively assume the data doesn't exist
attachmentFileToMove = null;
}
} else {
attachmentFileToMove = null;
}
if (attachmentFileToMove == null) {
Timber.d("matching attachment is in local cache");
}
boolean hasContentTypeAndIsInline = !TextUtils.isEmpty(contentId) && "inline".equalsIgnoreCase(contentDisposition);
int messageType = hasContentTypeAndIsInline ? MESSAGE_PART_TYPE__HIDDEN_ATTACHMENT : MESSAGE_PART_TYPE__UNKNOWN;
ContentValues cv = new ContentValues();
cv.put("type", messageType);
cv.put("mime_type", mimeType);
cv.put("decoded_body_size", size);
cv.put("display_name", name);
cv.put("header", mimeHeader.toString());
cv.put("encoding", MimeUtil.ENC_BINARY);
cv.put("data_location", attachmentFileToMove != null ? DATA_LOCATION__ON_DISK : DATA_LOCATION__MISSING);
cv.put("content_id", contentId);
cv.put("server_extra", storeData);
structureState.applyValues(cv);
long partId = db.insertOrThrow("message_parts", null, cv);
structureState = structureState.nextChild(partId);
if (attachmentFileToMove != null) {
boolean moveOk = attachmentFileToMove.renameTo(new File(attachmentDirNew, Long.toString(partId)));
if (!moveOk) {
Timber.e("Moving attachment to new dir failed!");
}
}
return structureState;
}
use of android.content.ContentValues in project k-9 by k9mail.
the class LocalFolder method doMessageThreading.
private ThreadInfo doMessageThreading(SQLiteDatabase db, Message message) throws MessagingException {
long rootId = -1;
long parentId = -1;
String messageId = message.getMessageId();
// If there's already an empty message in the database, update that
ThreadInfo msgThreadInfo = getThreadInfo(db, messageId, true);
// Get the message IDs from the "References" header line
String[] referencesArray = message.getHeader("References");
List<String> messageIds = null;
if (referencesArray.length > 0) {
messageIds = Utility.extractMessageIds(referencesArray[0]);
}
// Append the first message ID from the "In-Reply-To" header line
String[] inReplyToArray = message.getHeader("In-Reply-To");
String inReplyTo;
if (inReplyToArray.length > 0) {
inReplyTo = Utility.extractMessageId(inReplyToArray[0]);
if (inReplyTo != null) {
if (messageIds == null) {
messageIds = new ArrayList<>(1);
messageIds.add(inReplyTo);
} else if (!messageIds.contains(inReplyTo)) {
messageIds.add(inReplyTo);
}
}
}
if (messageIds == null) {
// This is not a reply, nothing to do for us.
return (msgThreadInfo != null) ? msgThreadInfo : new ThreadInfo(-1, -1, messageId, -1, -1);
}
for (String reference : messageIds) {
ThreadInfo threadInfo = getThreadInfo(db, reference, false);
if (threadInfo == null) {
// Create placeholder message in 'messages' table
ContentValues cv = new ContentValues();
cv.put("message_id", reference);
cv.put("folder_id", mFolderId);
cv.put("empty", 1);
long newMsgId = db.insert("messages", null, cv);
// Create entry in 'threads' table
cv.clear();
cv.put("message_id", newMsgId);
if (rootId != -1) {
cv.put("root", rootId);
}
if (parentId != -1) {
cv.put("parent", parentId);
}
parentId = db.insert("threads", null, cv);
if (rootId == -1) {
rootId = parentId;
}
} else {
if (rootId != -1 && threadInfo.rootId == -1 && rootId != threadInfo.threadId) {
// We found an existing root container that is not
// the root of our current path (References).
// Connect it to the current parent.
// Let all children know who's the new root
ContentValues cv = new ContentValues();
cv.put("root", rootId);
db.update("threads", cv, "root = ?", new String[] { Long.toString(threadInfo.threadId) });
// Connect the message to the current parent
cv.put("parent", parentId);
db.update("threads", cv, "id = ?", new String[] { Long.toString(threadInfo.threadId) });
} else {
rootId = (threadInfo.rootId == -1) ? threadInfo.threadId : threadInfo.rootId;
}
parentId = threadInfo.threadId;
}
}
//TODO: set in-reply-to "link" even if one already exists
long threadId;
long msgId;
if (msgThreadInfo != null) {
threadId = msgThreadInfo.threadId;
msgId = msgThreadInfo.msgId;
} else {
threadId = -1;
msgId = -1;
}
return new ThreadInfo(threadId, msgId, messageId, rootId, parentId);
}
use of android.content.ContentValues in project k-9 by k9mail.
the class LocalFolder method saveMessagePart.
private long saveMessagePart(SQLiteDatabase db, PartContainer partContainer, long rootMessagePartId, int order) throws IOException, MessagingException {
Part part = partContainer.part;
ContentValues cv = new ContentValues();
if (rootMessagePartId != -1) {
cv.put("root", rootMessagePartId);
}
cv.put("parent", partContainer.parent);
cv.put("seq", order);
cv.put("server_extra", part.getServerExtra());
return updateOrInsertMessagePart(db, cv, part, INVALID_MESSAGE_PART_ID);
}
use of android.content.ContentValues in project k-9 by k9mail.
the class LocalFolder method moveMessages.
@Override
public Map<String, String> moveMessages(final List<? extends Message> msgs, final Folder destFolder) throws MessagingException {
if (!(destFolder instanceof LocalFolder)) {
throw new MessagingException("moveMessages called with non-LocalFolder");
}
final LocalFolder lDestFolder = (LocalFolder) destFolder;
final Map<String, String> uidMap = new HashMap<>();
try {
this.localStore.database.execute(false, new DbCallback<Void>() {
@Override
public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
try {
lDestFolder.open(OPEN_MODE_RW);
for (Message message : msgs) {
LocalMessage lMessage = (LocalMessage) message;
String oldUID = message.getUid();
Timber.d("Updating folder_id to %s for message with UID %s, " + "id %d currently in folder %s", lDestFolder.getId(), message.getUid(), lMessage.getId(), getName());
String newUid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
message.setUid(newUid);
uidMap.put(oldUID, newUid);
// Message threading in the target folder
ThreadInfo threadInfo = lDestFolder.doMessageThreading(db, message);
/*
* "Move" the message into the new folder
*/
long msgId = lMessage.getId();
String[] idArg = new String[] { Long.toString(msgId) };
ContentValues cv = new ContentValues();
cv.put("folder_id", lDestFolder.getId());
cv.put("uid", newUid);
db.update("messages", cv, "id = ?", idArg);
// Create/update entry in 'threads' table for the message in the
// target folder
cv.clear();
cv.put("message_id", msgId);
if (threadInfo.threadId == -1) {
if (threadInfo.rootId != -1) {
cv.put("root", threadInfo.rootId);
}
if (threadInfo.parentId != -1) {
cv.put("parent", threadInfo.parentId);
}
db.insert("threads", null, cv);
} else {
db.update("threads", cv, "id = ?", new String[] { Long.toString(threadInfo.threadId) });
}
/*
* Add a placeholder message so we won't download the original
* message again if we synchronize before the remote move is
* complete.
*/
// We need to open this folder to get the folder id
open(OPEN_MODE_RW);
cv.clear();
cv.put("uid", oldUID);
cv.putNull("flags");
cv.put("read", 1);
cv.put("deleted", 1);
cv.put("folder_id", mFolderId);
cv.put("empty", 0);
String messageId = message.getMessageId();
if (messageId != null) {
cv.put("message_id", messageId);
}
final long newId;
if (threadInfo.msgId != -1) {
// There already existed an empty message in the target folder.
// Let's use it as placeholder.
newId = threadInfo.msgId;
db.update("messages", cv, "id = ?", new String[] { Long.toString(newId) });
} else {
newId = db.insert("messages", null, cv);
}
/*
* Update old entry in 'threads' table to point to the newly
* created placeholder.
*/
cv.clear();
cv.put("message_id", newId);
db.update("threads", cv, "id = ?", new String[] { Long.toString(lMessage.getThreadId()) });
}
} catch (MessagingException e) {
throw new WrappedException(e);
}
return null;
}
});
this.localStore.notifyChange();
return uidMap;
} catch (WrappedException e) {
throw (MessagingException) e.getCause();
}
}
Aggregations