Implemented extracting media type from content type; made check for Attachment disposition case-insensitive

This commit is contained in:
dankito 2024-11-21 17:35:34 +01:00
parent b09b7cf69b
commit da84aaedf6
2 changed files with 31 additions and 14 deletions

View File

@ -5,7 +5,12 @@ import java.io.File
class MailAttachmentWithEInvoice( class MailAttachmentWithEInvoice(
val filename: String, val filename: String,
val contentType: String, /**
* Attachment's media type like "application/xml", "application/pdf", ...
*
* Should always be non-null, but can theoretically be null.
*/
val mediaType: String?,
val invoice: Invoice, val invoice: Invoice,
val file: File val file: File
) { ) {

View File

@ -116,21 +116,17 @@ class MailReader(
private fun findEInvoice(part: BodyPart): MailAttachmentWithEInvoice? { private fun findEInvoice(part: BodyPart): MailAttachmentWithEInvoice? {
try { try {
if (part.disposition == Part.ATTACHMENT) { if (Part.ATTACHMENT.equals(part.disposition, true)) { // TODO: what about Part.INLINE?
val invoice = tryToReadEInvoice(part) val mediaType = getMediaType(part)?.lowercase()
if (invoice != null) { val invoice = tryToReadEInvoice(part, mediaType)
var contentType = part.contentType
val indexOfSeparator = contentType.indexOf(';')
if (indexOfSeparator > -1) {
contentType = contentType.substring(0, indexOfSeparator)
}
if (invoice != null) {
val filename = File(part.fileName) val filename = File(part.fileName)
val file = File.createTempFile(filename.nameWithoutExtension, filename.extension).also { file -> val file = File.createTempFile(filename.nameWithoutExtension, filename.extension).also { file ->
part.inputStream.use { it.copyTo(file.outputStream()) } part.inputStream.use { it.copyTo(file.outputStream()) }
} }
return MailAttachmentWithEInvoice(part.fileName, contentType, invoice, file) return MailAttachmentWithEInvoice(part.fileName, mediaType, invoice, file)
} }
} }
} catch (e: Throwable) { } catch (e: Throwable) {
@ -140,13 +136,12 @@ class MailReader(
return null return null
} }
private fun tryToReadEInvoice(part: BodyPart): Invoice? = try { private fun tryToReadEInvoice(part: BodyPart, mediaType: String?): Invoice? = try {
val filename = part.fileName.lowercase() val filename = part.fileName.lowercase()
val contentType = part.contentType.lowercase()
if (filename.endsWith(".pdf") || contentType.startsWith("application/pdf") || contentType.startsWith("application/octet-stream")) { if (filename.endsWith(".pdf") || mediaType == "application/pdf" || mediaType == "application/octet-stream") {
eInvoiceReader.extractFromPdf(part.inputStream) eInvoiceReader.extractFromPdf(part.inputStream)
} else if (filename.endsWith(".xml") || contentType.startsWith("application/xml") || contentType.startsWith("text/xml")) { } else if (filename.endsWith(".xml") || mediaType == "application/xml" || mediaType == "text/xml") {
eInvoiceReader.extractFromXml(part.inputStream) eInvoiceReader.extractFromXml(part.inputStream)
} else { } else {
null null
@ -156,6 +151,23 @@ class MailReader(
null null
} }
/**
* In most cases parameters are added to content-type's media type, e.g.
* - text/html; charset=utf-8
* - multipart/related; boundary="boundary-related"; type="text/html"
*
* -> This method removes parameters and return media type (first part) only
*/
private fun getMediaType(part: BodyPart): String? = part.contentType?.let { contentType ->
val indexOfSeparator = contentType.indexOf(';')
if (indexOfSeparator > -1) {
contentType.substring(0, indexOfSeparator)
} else {
contentType
}
}
private fun map(date: Date): Instant = private fun map(date: Date): Instant =
date.toInstant() date.toInstant()