Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,10 @@ class EmailUtil {
try {
for (msg in msgs) {
val flags = map[folder.getUID(msg)] ?: ""
if (!flags.equals(msg.flags.toString(), ignoreCase = true)) {
val existingFlags = flags.split(" ").map { it.uppercase() }.toSet()
val receivedFlags = msg.flags.toString().split(" ").map { it.uppercase() }.toSet()

if (existingFlags != receivedFlags) {
updateCandidates.add(msg)
}
}
Expand Down Expand Up @@ -694,7 +697,21 @@ class EmailUtil {
}

return@withContext when (outgoingMsgInfo.messageType) {
MessageType.NEW, MessageType.DRAFT -> {
MessageType.DRAFT -> {
prepareReplyFromDraft(
context = context,
accountEntity = accountEntity,
session = session,
outgoingMsgInfo = outgoingMsgInfo,
pubKeys = pubKeys,
protectedPubKeys = protectedPubKeys,
prvKeys = prvKeys,
protector = ringProtector,
hideArmorMeta = hideArmorMeta
)
}

MessageType.NEW -> {
prepareNewMsg(
session = session,
info = outgoingMsgInfo,
Expand Down Expand Up @@ -1033,6 +1050,42 @@ class EmailUtil {
return@withContext msg
}

suspend fun prepareReplyFromDraft(
context: Context,
accountEntity: AccountEntity,
session: Session,
outgoingMsgInfo: OutgoingMessageInfo,
pubKeys: List<String>? = null,
protectedPubKeys: List<String>? = null,
prvKeys: List<String>? = null,
protector: SecretKeyRingProtector? = null,
hideArmorMeta: Boolean = false,
): MimeMessage = withContext(Dispatchers.IO) {
return@withContext prepareNewMsg(
session = session,
info = outgoingMsgInfo,
pubKeys = pubKeys,
protectedPubKeys = protectedPubKeys,
prvKeys = prvKeys,
protector = protector,
hideArmorMeta = hideArmorMeta
).apply {
//we need to restore 'References' and 'In-Reply-To' headers to support correct conversation
val replyToMimeMessage =
getReplyToMimeMessage(context, accountEntity, session, outgoingMsgInfo)

replyToMimeMessage.getHeader(JavaEmailConstants.HEADER_REFERENCES)?.firstOrNull()
?.let { references ->
setHeader(JavaEmailConstants.HEADER_REFERENCES, references)
}

replyToMimeMessage.getHeader(JavaEmailConstants.HEADER_IN_REPLY_TO)?.firstOrNull()
?.let { inReplyTo ->
setHeader(JavaEmailConstants.HEADER_IN_REPLY_TO, inReplyTo)
}
}
}

private suspend fun prepareForwardedMsg(
context: Context,
accountEntity: AccountEntity,
Expand Down Expand Up @@ -1171,7 +1224,7 @@ class EmailUtil {
val attBodyPart = genBodyPartWithAtt(
context = context,
att = att,
shouldBeEncrypted = msgEntity.isEncrypted ?: false,
shouldBeEncrypted = msgEntity.isEncrypted == true,
publicKeys = publicKeys,
secretKeys = secretKeys,
ringProtector = ringProtector
Expand Down Expand Up @@ -1294,9 +1347,16 @@ class EmailUtil {
protector: SecretKeyRingProtector? = null,
hideArmorMeta: Boolean = false,
): BodyPart {
val finalText = (info.msg + info.quotedTextForReply).takeIf {
info.messageType in arrayOf(
MessageType.REPLY,
MessageType.REPLY_ALL
) && !info.quotedTextForReply.isNullOrEmpty()
} ?: info.msg ?: ""

return if (info.encryptionType == MessageEncryptionType.ENCRYPTED) {
val encryptedContent = PgpEncryptAndOrSign.encryptAndOrSignMsg(
msg = info.msg ?: "",
msg = finalText,
pubKeys = pubKeys ?: emptyList(),
protectedPubKeys = protectedPubKeys,
prvKeys = prvKeys,
Expand All @@ -1319,7 +1379,7 @@ class EmailUtil {
}
} else {
MimeBodyPart().apply {
setText(info.msg ?: "")
setText(finalText)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
* Contributors: DenBond7
* Contributors: denbond7
*/

package com.flowcrypt.email.api.email.model
Expand All @@ -18,7 +18,7 @@ import kotlinx.parcelize.Parcelize
* @author Denys Bondarenko
*/
@Parcelize
data class LocalFolder constructor(
data class LocalFolder(
val account: String,
val fullName: String,
var folderAlias: String? = null,
Expand Down Expand Up @@ -52,6 +52,9 @@ data class LocalFolder constructor(
@IgnoredOnParcel
val isDrafts: Boolean = FoldersManager.FolderType.DRAFTS == getFolderType()

@IgnoredOnParcel
val isTrash: Boolean = FoldersManager.FolderType.TRASH == getFolderType()

fun getFolderType(): FoldersManager.FolderType? {
return FoldersManager.getFolderType(this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ data class MessageEntity(

@IgnoredOnParcel
@Ignore
val isSeen: Boolean = flags?.contains(MessageFlag.SEEN.value) ?: false
val isSeen: Boolean = flags?.contains(MessageFlag.SEEN.value) == true

@IgnoredOnParcel
@Ignore
val isDraft: Boolean = flags?.contains(MessageFlag.DRAFT.value) ?: false
val isDraft: Boolean = flags?.contains(MessageFlag.DRAFT.value) == true

@IgnoredOnParcel
@Ignore
Expand All @@ -168,12 +168,16 @@ data class MessageEntity(

@IgnoredOnParcel
@Ignore
val isPasswordProtected = password?.isNotEmpty() ?: false
val isPasswordProtected = password?.isNotEmpty() == true

@IgnoredOnParcel
@Ignore
val isGmailThread: Boolean = threadMessagesCount != null && threadMessagesCount > 0

@IgnoredOnParcel
@Ignore
val flagsValueSet = flags?.split(" ")?.filter { it.isNotEmpty() }?.map { it.uppercase() }?.toSet()

/**
* Generate a list of the all recipients.
*
Expand Down Expand Up @@ -473,17 +477,21 @@ data class MessageEntity(
fromAddresses = InternetAddress.toString(thread.recipients.toTypedArray()),
hasPgp = thread.hasPgpThings,
flags = if (thread.hasUnreadMessages) {
messageEntity.flags?.replace(MessageFlag.SEEN.value, "")
messageEntity.flagsStringAfterRemoveSome(MessageFlag.SEEN.value)
} else {
if (messageEntity.flags?.contains(MessageFlag.SEEN.value) == true) {
messageEntity.flags
} else {
messageEntity.flags.plus("${MessageFlag.SEEN.value} ")
messageEntity.flags.plus(" ${MessageFlag.SEEN.value}")
}
}
)
}

fun flagsStringAfterRemoveSome(flagValue: String): String? {
return flags?.replace("(\\s)?$flagValue(\\s)?".toRegex(), "")
}

private fun prepareDateHeaderValue(context: Context): String {
val dateInMilliseconds: Long =
if (JavaEmailConstants.FOLDER_OUTBOX.equals(folder, ignoreCase = true)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ fun Message.isTrashed(): Boolean? {
return labelIds.contains(GmailApiHelper.LABEL_TRASH)
}

fun Message.isSent(): Boolean {
return labelIds.contains(GmailApiHelper.LABEL_SENT) == true
}

fun Message.canBeUsed(localFolder: LocalFolder?): Boolean {
return if (localFolder?.getFolderType() == FoldersManager.FolderType.TRASH) {
isTrashed() == true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,10 @@ class DraftViewModel(
accountEntity = activeAccount,
outgoingMsgInfo = outgoingMessageInfo,
signingRequired = false,
hideArmorMeta = activeAccount.clientConfiguration?.shouldHideArmorMeta() ?: false
hideArmorMeta = activeAccount.clientConfiguration?.shouldHideArmorMeta() == true
)
val existingSnapshot = MsgsCacheManager.getMsgSnapshot(draftMessageEntity.id.toString())
if (existingSnapshot != null) {
existingSnapshot.getUri(0)?.let { fileUri ->
MsgsCacheManager.getMsgSnapshot(draftMessageEntity.id.toString())?.getUri(0)
?.let { fileUri ->
(getApplication() as Context).contentResolver?.openInputStream(fileUri)
?.let { inputStream ->
val keys = PGPainless.readKeyRing()
Expand Down Expand Up @@ -239,7 +238,6 @@ class DraftViewModel(
mimeMessage.setHeader(JavaEmailConstants.HEADER_IN_REPLY_TO, inReplyTo)
}
}
}
}
val draftsDir = CacheManager.getDraftDirectory(getApplication())

Expand Down Expand Up @@ -344,6 +342,6 @@ class DraftViewModel(
)

companion object {
val DELAY_TIMEOUT = TimeUnit.SECONDS.toMillis(5)
val DELAY_TIMEOUT = TimeUnit.SECONDS.toMillis(30)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class MessagesViewModel(application: Application) : AccountViewModel(application
MessageState.PENDING_MARK_UNREAD -> {
msgEntity.copy(
state = newMsgState.value,
flags = msgEntity.flags?.replace(MessageFlag.SEEN.value, "")
flags = msgEntity.flagsStringAfterRemoveSome(MessageFlag.SEEN.value)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ class MsgDetailsViewModel(
MessageState.PENDING_MARK_UNREAD -> {
msgEntity.copy(
state = newMsgState.value,
flags = msgEntity.flags?.replace(MessageFlag.SEEN.value, "")
flags = msgEntity.flagsStringAfterRemoveSome(MessageFlag.SEEN.value)
)
}

Expand Down Expand Up @@ -531,7 +531,7 @@ class MsgDetailsViewModel(
}

fun getMessageActionAvailability(messageAction: MessageAction): Boolean {
return messageActionsAvailabilityStateFlow.value[messageAction] ?: false
return messageActionsAvailabilityStateFlow.value[messageAction] == true
}

private suspend fun reVerifySignaturesInternal(): Result<VerificationResult> =
Expand Down Expand Up @@ -839,10 +839,10 @@ class MsgDetailsViewModel(
if (msgEntity.flags?.contains(MessageFlag.SEEN.value) == true) {
msgEntity.flags
} else {
msgEntity.flags?.plus("${MessageFlag.SEEN.value} ")
msgEntity.flags?.plus(" ${MessageFlag.SEEN.value}")
}
} else {
msgEntity.flags?.replace(MessageFlag.SEEN.value, "")
msgEntity.flagsStringAfterRemoveSome(MessageFlag.SEEN.value)
}
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import com.flowcrypt.email.api.retrofit.response.model.PublicKeyMsgBlock
import com.flowcrypt.email.database.MessageState
import com.flowcrypt.email.database.entity.MessageEntity
import com.flowcrypt.email.extensions.com.flowcrypt.email.util.processing
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.containsLabel
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.isDraft
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.isTrashed
import com.flowcrypt.email.extensions.java.lang.printStackTraceIfDebugOnly
import com.flowcrypt.email.jetpack.workmanager.sync.UpdateMsgsSeenStateWorker
import com.flowcrypt.email.model.MessageEncryptionType
Expand Down Expand Up @@ -290,8 +289,8 @@ class ProcessMessageViewModel(
format = GmailApiHelper.RESPONSE_FORMAT_FULL
)

if (!msgFullInfo.isDraft() && msgFullInfo.containsLabel(localFolder) == false) {
throw MessageNotFoundException("Message doesn't contain label = ${localFolder.fullName}")
if (!localFolder.isTrash && msgFullInfo.isTrashed() == true) {
throw MessageNotFoundException("Message was moved to trash")
}

val originalMsg = GmaiAPIMimeMessage(
Expand Down Expand Up @@ -375,10 +374,10 @@ class ProcessMessageViewModel(
if (msgEntity.flags?.contains(MessageFlag.SEEN.value) == true) {
msgEntity.flags
} else {
msgEntity.flags?.plus("${MessageFlag.SEEN.value} ")
msgEntity.flags?.plus(" ${MessageFlag.SEEN.value}")
}
} else {
msgEntity.flags?.replace(MessageFlag.SEEN.value, "")
msgEntity.flagsStringAfterRemoveSome(MessageFlag.SEEN.value)
}
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ class ThreadDetailsViewModel(
MessageState.PENDING_MARK_UNREAD -> {
messageEntity.copy(
state = newMsgState.value,
flags = messageEntity.flags?.replace(MessageFlag.SEEN.value, "")
flags = messageEntity.flagsStringAfterRemoveSome(MessageFlag.SEEN.value)
)
}

Expand Down Expand Up @@ -479,7 +479,7 @@ class ThreadDetailsViewModel(
candidatesToBeInserted.add(entity)
} else if (existingVersion.copy(id = null) != entity) {
candidatesToBeUpdated.add(entity.copy(id = existingVersion.id))
if (existingVersion.flags != entity.flags) {
if (existingVersion.flagsValueSet != entity.flagsValueSet) {
MsgsCacheManager.removeMessage(existingVersion.id.toString())
}
}
Expand Down Expand Up @@ -527,7 +527,7 @@ class ThreadDetailsViewModel(
it.id == messageItemBasedOnDataFromServer.id
}?.let { item ->
val existingMessageItem = item as Message
if (existingMessageItem.messageEntity.flags != messageEntity.flags) {
if (existingMessageItem.messageEntity.flagsValueSet != messageEntity.flagsValueSet) {
messageItemBasedOnDataFromServer
} else {
existingMessageItem.copy(messageEntity = messageEntity)
Expand Down Expand Up @@ -649,10 +649,10 @@ class ThreadDetailsViewModel(
if (messageEntity.flags?.contains(MessageFlag.SEEN.value) == true) {
messageEntity.flags
} else {
messageEntity.flags?.plus("${MessageFlag.SEEN.value} ")
messageEntity.flags?.plus(" ${MessageFlag.SEEN.value}")
}
} else {
messageEntity.flags?.replace(MessageFlag.SEEN.value, "")
messageEntity.flagsStringAfterRemoveSome(MessageFlag.SEEN.value)
}
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ abstract class BaseIdleWorker(context: Context, params: WorkerParameters) :
accountEntity: AccountEntity, folderFullName: String
) = withContext(Dispatchers.IO) {
val updateCandidates = EmailUtil.genUpdateCandidates(mapOfUIDAndMsgFlags, remoteFolder, msgs)
.map { remoteFolder.getUID(it) to it.flags }.toMap()
.associate { remoteFolder.getUID(it) to it.flags }
processUpdatedMsgs(accountEntity, folderFullName, updateCandidates)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
composeMsgViewModel.updateOutgoingMessageInfo(
composeMsgViewModel.outgoingMessageInfoStateFlow.value.copy(
messageType = args.messageType,
replyToMessageEntityId = if (args.incomingMessageInfo?.msgEntity?.isDraft == true) {
null
} else {
args.incomingMessageInfo?.msgEntity?.id
},
replyToMessageEntityId = args.incomingMessageInfo?.msgEntity?.id,
quotedTextForReply = EmailUtil.genReplyContent(args.incomingMessageInfo).takeIf {
args.messageType in arrayOf(
MessageType.REPLY,
Expand Down Expand Up @@ -1076,19 +1072,7 @@ class CreateMessageFragment : BaseFragment<FragmentCreateMessageBinding>(),
CreateMessageFragmentDirections
.actionCreateMessageFragmentToCreateOutgoingMessageDialogFragment(
requestKey = REQUEST_KEY_CREATE_OUTGOING_MESSAGE,
outgoingMessageInfo = outgoingMessageInfo.copy(
msg = if (outgoingMessageInfo.quotedTextForReply?.isNotEmpty() == true &&
args.messageType in arrayOf(
MessageType.REPLY,
MessageType.REPLY_ALL
)
) {
outgoingMessageInfo.msg + EmailUtil.genReplyContent(args.incomingMessageInfo)
} else {
outgoingMessageInfo.msg
},
password = usePasswordIfNeeded(),
)
outgoingMessageInfo = outgoingMessageInfo.copy(password = usePasswordIfNeeded())
)
)
}
Expand Down