From ccfd3f21cf3295babd2c59f5656b298f793754f8 Mon Sep 17 00:00:00 2001 From: Schalli Date: Tue, 30 Jun 2026 08:41:17 +0200 Subject: [PATCH] =?UTF-8?q?fix(dkv):=20fix=20EWS=20attachment=20ID=20extra?= =?UTF-8?q?ction=20=E2=80=94=20FileAttachment=20has=20no=20Id=20attribute?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit extractAttrs(block, 't:FileAttachment', 'Id') always returned empty array because the attachment Id lives in a child , not on the tag itself. This caused all Exchange inbox checks to silently find zero PDF attachments and report "no matching emails". Fixed by iterating FileAttachment blocks individually and extracting t:AttachmentId/@Id from within each block. Also added filename (.pdf) as fallback when ContentType is application/octet-stream. Co-Authored-By: Claude Sonnet 4.6 --- .../dkv/providers/exchange-inbox.provider.ts | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/api/src/dkv/providers/exchange-inbox.provider.ts b/apps/api/src/dkv/providers/exchange-inbox.provider.ts index 9322819..03c6676 100644 --- a/apps/api/src/dkv/providers/exchange-inbox.provider.ts +++ b/apps/api/src/dkv/providers/exchange-inbox.provider.ts @@ -272,12 +272,27 @@ export class ExchangeInboxProvider implements InboxProvider { continue; } - // Collect PDF attachment IDs - const attachmentIds = extractAttrs(block, 't:FileAttachment', 'Id') - .filter((_, idx) => { - const types = extractAll(block, 't:ContentType'); - return (types[idx] ?? '').toLowerCase().includes('pdf'); - }); + // Collect PDF attachment IDs by iterating each FileAttachment block. + // extractAttrs(block, 't:FileAttachment', 'Id') was wrong — the Id lives + // inside a child not on the FileAttachment tag. + const attachmentIds: string[] = []; + const FA_OPEN = ''; + const FA_CLOSE = ''; + let faPos = 0; + while (faPos < block.length) { + const faStart = block.indexOf(FA_OPEN, faPos); + if (faStart === -1) break; + const faEnd = block.indexOf(FA_CLOSE, faStart); + if (faEnd === -1) break; + const faBlock = block.slice(faStart, faEnd); + const attId = extractAttr(faBlock, 't:AttachmentId', 'Id'); + const ct = (extractAll(faBlock, 't:ContentType')[0] ?? '').toLowerCase(); + const nm = (extractAll(faBlock, 't:Name')[0] ?? '').toLowerCase(); + if (attId && (ct.includes('pdf') || nm.endsWith('.pdf'))) { + attachmentIds.push(attId); + } + faPos = faEnd + FA_CLOSE.length; + } if (attachmentIds.length === 0) continue;