Added mail account username to attachments download directory

This commit is contained in:
dankito 2024-11-26 04:32:49 +01:00
parent 4aefa86ab9
commit ccf48f7cb4
3 changed files with 30 additions and 13 deletions

View File

@ -42,7 +42,7 @@ open class EmailsFetcher(
val folder = store.getFolder(options.emailFolderName) as IMAPFolder val folder = store.getFolder(options.emailFolderName) as IMAPFolder
folder.open(Folder.READ_ONLY) folder.open(Folder.READ_ONLY)
val status = FetchEmailsStatus(options) val status = FetchEmailsStatus(account, options)
folder.addMessageCountListener(object : MessageCountAdapter() { folder.addMessageCountListener(object : MessageCountAdapter() {
override fun messagesAdded(event: MessageCountEvent) { override fun messagesAdded(event: MessageCountEvent) {
@ -53,7 +53,7 @@ open class EmailsFetcher(
}) })
launch(coroutineDispatcher) { launch(coroutineDispatcher) {
keepConnectionOpen(account, folder, options) keepConnectionOpen(status, folder, options)
} }
} }
} catch (e: Throwable) { } catch (e: Throwable) {
@ -62,13 +62,14 @@ open class EmailsFetcher(
} }
} }
protected open suspend fun keepConnectionOpen(account: EmailAccount, folder: IMAPFolder, options: ListenForNewMailsOptions) { protected open suspend fun keepConnectionOpen(status: FetchEmailsStatus, folder: IMAPFolder, options: ListenForNewMailsOptions) {
log.info { "Listening to new emails of ${account.username}" } val account = status.account
log.info { "Listening to new emails of $account" }
// Use IMAP IDLE to keep the connection alive // Use IMAP IDLE to keep the connection alive
while (options.stopListening.get() == false) { while (options.stopListening.get() == false) {
if (!folder.isOpen) { if (!folder.isOpen) {
log.info { "Reopening inbox of ${account.username} ..." } log.info { "Reopening inbox of $account ..." }
folder.open(Folder.READ_ONLY) folder.open(Folder.READ_ONLY)
} }
@ -77,7 +78,7 @@ open class EmailsFetcher(
delay(250) delay(250)
} }
log.info { "Stopped listening to new emails of '${account.username}'" } log.info { "Stopped listening to new emails of '$account}'" }
} }
@ -87,7 +88,7 @@ open class EmailsFetcher(
val inbox = store.getFolder(options.emailFolderName) val inbox = store.getFolder(options.emailFolderName)
inbox.open(Folder.READ_ONLY) inbox.open(Folder.READ_ONLY)
val status = FetchEmailsStatus(options) val status = FetchEmailsStatus(account, options)
val emails = fetchAllEmailsInFolder(inbox, status).also { val emails = fetchAllEmailsInFolder(inbox, status).also {
inbox.close(false) inbox.close(false)
@ -146,6 +147,10 @@ open class EmailsFetcher(
protected open fun findAttachment(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachment? { protected open fun findAttachment(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachment? {
try { try {
val part = messagePart.part val part = messagePart.part
if (part.fileName == null) { // not an attachment
return null
}
val filename = File(part.fileName) val filename = File(part.fileName)
val extension = filename.extension val extension = filename.extension
@ -166,11 +171,6 @@ open class EmailsFetcher(
return null return null
} }
private fun downloadAttachment(part: Part, status: FetchEmailsStatus) =
File(status.options.attachmentsDownloadDirectory, part.fileName).also { file ->
part.inputStream.use { it.copyTo(file.outputStream()) }
}
protected open fun tryToReadEInvoice(part: Part, extension: String, mediaType: String?, status: FetchEmailsStatus): Pair<Invoice, File>? = try { protected open fun tryToReadEInvoice(part: Part, extension: String, mediaType: String?, status: FetchEmailsStatus): Pair<Invoice, File>? = try {
if (extension == "pdf" || mediaType == "application/pdf" || mediaType == "application/octet-stream") { if (extension == "pdf" || mediaType == "application/pdf" || mediaType == "application/octet-stream") {
val file = downloadAttachment(part, status) val file = downloadAttachment(part, status)
@ -187,6 +187,11 @@ open class EmailsFetcher(
null null
} }
private fun downloadAttachment(part: Part, status: FetchEmailsStatus) =
File(status.userAttachmentsDownloadDirectory, part.fileName).also { file ->
part.inputStream.use { it.copyTo(file.outputStream()) }
}
protected open fun getAllMessageParts(part: Part): List<MessagePart> { protected open fun getAllMessageParts(part: Part): List<MessagePart> {
return if (part.isMimeType("multipart/*")) { return if (part.isMimeType("multipart/*")) {

View File

@ -19,7 +19,9 @@ open class FetchEmailsOptions(
companion object { companion object {
val DefaultDownloadedAttachmentsWithExtensions = listOf("pdf", "xml") val DefaultDownloadedAttachmentsWithExtensions = listOf("pdf", "xml")
val DefaultAttachmentsDownloadDirectory: File = Files.createTempDirectory("eInvoices").toFile() val DefaultAttachmentsDownloadDirectory: File = File(System.getProperty("java.io.tmpdir"), "eInvoices").also { it.mkdirs() }
val IllegalFileCharacters = listOf('\\', '/', ':', '*', '?', '"', '<', '>', '|', '\u0000')
} }
fun emailReceived(email: Email) { fun emailReceived(email: Email) {

View File

@ -3,12 +3,22 @@ package net.codinux.invoicing.email
import jakarta.mail.BodyPart import jakarta.mail.BodyPart
import jakarta.mail.Message import jakarta.mail.Message
import jakarta.mail.Part import jakarta.mail.Part
import net.codinux.invoicing.email.model.EmailAccount
import java.io.File
data class FetchEmailsStatus( data class FetchEmailsStatus(
val account: EmailAccount,
val options: FetchEmailsOptions, val options: FetchEmailsOptions,
val messageSpecificErrors: MutableList<FetchEmailsError> = mutableListOf() val messageSpecificErrors: MutableList<FetchEmailsError> = mutableListOf()
) { ) {
val userAttachmentsDownloadDirectory: File by lazy {
val userDirName = account.username.map { if (it in FetchEmailsOptions.IllegalFileCharacters || it.code < 32) '_' else it }.joinToString("")
File(options.attachmentsDownloadDirectory, userDirName).also { it.mkdirs() }
}
fun addError(type: FetchEmailsErrorType, parts: Collection<Part>, error: Throwable) = fun addError(type: FetchEmailsErrorType, parts: Collection<Part>, error: Throwable) =
addError(FetchEmailsError(type, parts.firstNotNullOfOrNull { getMessage(it) }?.messageNumber, error)) addError(FetchEmailsError(type, parts.firstNotNullOfOrNull { getMessage(it) }?.messageNumber, error))