This commit is contained in:
2026-07-10 20:17:43 +03:00
parent 2f0bfba1cf
commit 07db914ca0
15 changed files with 382 additions and 315 deletions
+101
View File
@@ -0,0 +1,101 @@
export interface Folder {
name: string;
id: string;
totalCount: number;
unreadCount: number;
childFolderCount: number;
}
type SoapRequest = (body: string, soapAction: string) => Promise<any>;
export async function extractFolders(
soapRequest: SoapRequest,
parentFolderId: string,
recursive: boolean = false,
): Promise<Folder[]> {
const DISTINGUISHED_FOLDERS: Record<string, string> = {
inbox: "inbox",
"входящие": "inbox",
sent: "sentitems",
"отправленные": "sentitems",
drafts: "drafts",
"черновики": "drafts",
deleted: "deleteditems",
"удаленные": "deleteditems",
junk: "junkemail",
"нежелательная почта": "junkemail",
outbox: "outbox",
"исходящие": "outbox",
calendar: "calendar",
"календарь": "calendar",
};
function buildSoapEnvelope(body: string): string {
return `<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<s:Body>
${body}
</s:Body>
</s:Envelope>`;
}
function extractResponseMessages(data: any): any[] {
const body = data?.Envelope?.Body;
if (!body) return [];
const firstKey = Object.keys(body).find((k) => k.endsWith("Response"));
if (!firstKey) return [];
const rm = body[firstKey]?.ResponseMessages;
if (!rm) return [];
const msgKey = Object.keys(rm).find((k) => k.endsWith("ResponseMessage"));
if (!msgKey) return [];
const msgs = rm[msgKey];
return Array.isArray(msgs) ? msgs : [msgs];
}
const traversal = recursive ? "Deep" : "Shallow";
const isDistinguished =
DISTINGUISHED_FOLDERS[parentFolderId.toLowerCase()] !== undefined
|| ["msgfolderroot"].includes(parentFolderId.toLowerCase());
const folderIdXml = isDistinguished
? `<t:DistinguishedFolderId Id="${parentFolderId}"/>`
: `<t:FolderId Id="${parentFolderId}"/>`;
const soap = buildSoapEnvelope(`\
<m:FindFolder Traversal="${traversal}">
<m:FolderShape>
<t:BaseShape>Default</t:BaseShape>
</m:FolderShape>
<m:ParentFolderIds>
${folderIdXml}
</m:ParentFolderIds>
<m:IndexedPageFolderView MaxEntriesReturned="200" Offset="0" BasePoint="Beginning"/>
</m:FindFolder>`);
const data = await soapRequest(
soap,
"http://schemas.microsoft.com/exchange/services/2006/messages/FindFolder",
);
const folders: Folder[] = [];
for (const msg of extractResponseMessages(data)) {
const folderList = msg?.RootFolder?.Folders?.Folder;
if (!folderList) continue;
const list = Array.isArray(folderList) ? folderList : [folderList];
for (const f of list) {
folders.push({
name: f.DisplayName ?? "Unknown",
id: f.FolderId?.["@_Id"] ?? "",
totalCount: f.TotalCount ?? 0,
unreadCount: f.UnreadCount ?? 0,
childFolderCount: f.ChildFolderCount ?? 0,
});
}
}
return folders;
}