@dawnlit/outlook-bridge 1.1.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -183
- package/dist/backend.d.ts +151 -0
- package/dist/backend.js +3 -0
- package/dist/backend.js.map +1 -0
- package/dist/bridge.d.ts +56 -0
- package/dist/bridge.js +507 -0
- package/dist/bridge.js.map +1 -0
- package/dist/errors.d.ts +79 -43
- package/dist/errors.js +93 -52
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +25 -52
- package/dist/index.js.map +1 -1
- package/dist/mac/accounts.d.ts +7 -2
- package/dist/mac/accounts.js +23 -6
- package/dist/mac/accounts.js.map +1 -1
- package/dist/mac/attachments.d.ts +5 -25
- package/dist/mac/attachments.js +40 -99
- package/dist/mac/attachments.js.map +1 -1
- package/dist/mac/bounces.d.ts +12 -27
- package/dist/mac/bounces.js +96 -117
- package/dist/mac/bounces.js.map +1 -1
- package/dist/mac/cleanup.d.ts +11 -25
- package/dist/mac/cleanup.js +44 -107
- package/dist/mac/cleanup.js.map +1 -1
- package/dist/mac/drafts.d.ts +15 -34
- package/dist/mac/drafts.js +113 -186
- package/dist/mac/drafts.js.map +1 -1
- package/dist/mac/folders.d.ts +12 -21
- package/dist/mac/folders.js +44 -59
- package/dist/mac/folders.js.map +1 -1
- package/dist/mac/index.d.ts +2 -22
- package/dist/mac/index.js +19 -81
- package/dist/mac/index.js.map +1 -1
- package/dist/mac/profile.d.ts +13 -0
- package/dist/mac/profile.js +149 -0
- package/dist/mac/profile.js.map +1 -0
- package/dist/mac/read.d.ts +21 -37
- package/dist/mac/read.js +198 -216
- package/dist/mac/read.js.map +1 -1
- package/dist/mac/run.d.ts +51 -38
- package/dist/mac/run.js +138 -103
- package/dist/mac/run.js.map +1 -1
- package/dist/mac/scripts.d.ts +90 -91
- package/dist/mac/scripts.js +167 -126
- package/dist/mac/scripts.js.map +1 -1
- package/dist/mac/send.d.ts +10 -20
- package/dist/mac/send.js +99 -89
- package/dist/mac/send.js.map +1 -1
- package/dist/mac/signatures.d.ts +2 -2
- package/dist/mac/signatures.js +9 -11
- package/dist/mac/signatures.js.map +1 -1
- package/dist/mac/templates.d.ts +14 -26
- package/dist/mac/templates.js +79 -120
- package/dist/mac/templates.js.map +1 -1
- package/dist/mail.d.ts +80 -46
- package/dist/mail.js +179 -73
- package/dist/mail.js.map +1 -1
- package/dist/runtime.d.ts +76 -43
- package/dist/runtime.js +103 -48
- package/dist/runtime.js.map +1 -1
- package/dist/shared/args.d.ts +48 -0
- package/dist/shared/args.js +216 -0
- package/dist/shared/args.js.map +1 -0
- package/dist/shared/attachmentMatch.d.ts +26 -20
- package/dist/shared/attachmentMatch.js +60 -23
- package/dist/shared/attachmentMatch.js.map +1 -1
- package/dist/shared/bounceReport.d.ts +11 -0
- package/dist/shared/bounceReport.js +45 -0
- package/dist/shared/bounceReport.js.map +1 -0
- package/dist/shared/bounceRules.d.ts +38 -10
- package/dist/shared/bounceRules.js +50 -32
- package/dist/shared/bounceRules.js.map +1 -1
- package/dist/shared/exec.d.ts +21 -0
- package/dist/shared/exec.js +47 -0
- package/dist/shared/exec.js.map +1 -0
- package/dist/shared/json.d.ts +17 -6
- package/dist/shared/json.js +35 -24
- package/dist/shared/json.js.map +1 -1
- package/dist/shared/locate.d.ts +31 -0
- package/dist/shared/locate.js +128 -0
- package/dist/shared/locate.js.map +1 -0
- package/dist/shared/replyBody.d.ts +31 -36
- package/dist/shared/replyBody.js +83 -72
- package/dist/shared/replyBody.js.map +1 -1
- package/dist/shared/templateLimits.d.ts +14 -0
- package/dist/shared/templateLimits.js +21 -0
- package/dist/shared/templateLimits.js.map +1 -0
- package/dist/templateBody.d.ts +69 -0
- package/dist/{outlookTemplateSections.js → templateBody.js} +80 -73
- package/dist/templateBody.js.map +1 -0
- package/dist/types.d.ts +381 -168
- package/dist/types.js +8 -9
- package/dist/types.js.map +1 -1
- package/dist/windows/accounts.d.ts +7 -12
- package/dist/windows/accounts.js +19 -34
- package/dist/windows/accounts.js.map +1 -1
- package/dist/windows/attachments.d.ts +9 -24
- package/dist/windows/attachments.js +94 -119
- package/dist/windows/attachments.js.map +1 -1
- package/dist/windows/bounces.d.ts +13 -26
- package/dist/windows/bounces.js +168 -200
- package/dist/windows/bounces.js.map +1 -1
- package/dist/windows/cleanup.d.ts +23 -23
- package/dist/windows/cleanup.js +99 -113
- package/dist/windows/cleanup.js.map +1 -1
- package/dist/windows/drafts.d.ts +16 -35
- package/dist/windows/drafts.js +156 -253
- package/dist/windows/drafts.js.map +1 -1
- package/dist/windows/folders.d.ts +8 -13
- package/dist/windows/folders.js +44 -52
- package/dist/windows/folders.js.map +1 -1
- package/dist/windows/index.d.ts +2 -27
- package/dist/windows/index.js +11 -66
- package/dist/windows/index.js.map +1 -1
- package/dist/windows/read.d.ts +24 -60
- package/dist/windows/read.js +265 -306
- package/dist/windows/read.js.map +1 -1
- package/dist/windows/run.d.ts +38 -40
- package/dist/windows/run.js +151 -112
- package/dist/windows/run.js.map +1 -1
- package/dist/windows/scripts.d.ts +65 -55
- package/dist/windows/scripts.js +109 -85
- package/dist/windows/scripts.js.map +1 -1
- package/dist/windows/send.d.ts +9 -9
- package/dist/windows/send.js +76 -88
- package/dist/windows/send.js.map +1 -1
- package/dist/windows/signatures.d.ts +4 -10
- package/dist/windows/signatures.js +30 -37
- package/dist/windows/signatures.js.map +1 -1
- package/dist/windows/templates.d.ts +12 -18
- package/dist/windows/templates.js +117 -150
- package/dist/windows/templates.js.map +1 -1
- package/package.json +5 -4
- package/dist/OutlookService.d.ts +0 -43
- package/dist/OutlookService.js +0 -137
- package/dist/OutlookService.js.map +0 -1
- package/dist/outlookTemplateSections.d.ts +0 -62
- package/dist/outlookTemplateSections.js.map +0 -1
- package/dist/shared/capabilities.d.ts +0 -3
- package/dist/shared/capabilities.js +0 -9
- package/dist/shared/capabilities.js.map +0 -1
package/dist/windows/cleanup.js
CHANGED
|
@@ -7,160 +7,146 @@ const run_1 = require("./run");
|
|
|
7
7
|
const scripts_1 = require("./scripts");
|
|
8
8
|
const json_1 = require("../shared/json");
|
|
9
9
|
const mail_1 = require("../mail");
|
|
10
|
-
/** Folders whose contents are received or
|
|
11
|
-
const PROTECTED_FOLDER_IDS = [
|
|
12
|
-
/** Walks an item's parent chain, so Inbox/Sent protection covers their subfolders too. */
|
|
13
|
-
const FOLDER_CHAIN_PS = `
|
|
14
|
-
function Get-FolderChainIds($folder) {
|
|
15
|
-
$ids = @()
|
|
16
|
-
$cur = $folder
|
|
17
|
-
$guard = 0
|
|
18
|
-
while ($cur -ne $null -and $guard -lt 25) {
|
|
19
|
-
$cid = $null
|
|
20
|
-
try { $cid = $cur.EntryID } catch { $cid = $null }
|
|
21
|
-
if (-not $cid) { break }
|
|
22
|
-
$ids += $cid
|
|
23
|
-
$parent = $null
|
|
24
|
-
try { $parent = $cur.Parent } catch { $parent = $null }
|
|
25
|
-
if ($parent -eq $null) { break }
|
|
26
|
-
$cur = $parent
|
|
27
|
-
$guard++
|
|
28
|
-
}
|
|
29
|
-
return $ids
|
|
30
|
-
}
|
|
31
|
-
`;
|
|
10
|
+
/** Folders whose contents are received or sent mail rather than working state. */
|
|
11
|
+
const PROTECTED_FOLDER_IDS = [mail_1.FolderId.Inbox, mail_1.FolderId.SentMail];
|
|
32
12
|
/**
|
|
33
|
-
* Delete mail by
|
|
34
|
-
* Deleted Items, so this is recoverable — purgeDeletedItems is what destroys.
|
|
13
|
+
* Delete mail by entry id from anywhere in the account. Delete() moves each item
|
|
14
|
+
* to Deleted Items, so this is recoverable — purgeDeletedItems is what destroys.
|
|
35
15
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
16
|
+
* This is the one operation that can reach received mail, and an entry id is an
|
|
17
|
+
* unsafe key for it: a stale or wrong id can resolve to a DIFFERENT message.
|
|
18
|
+
* Four things hold the line:
|
|
19
|
+
* - An id that resolves outside this account's store is refused. The bare
|
|
20
|
+
* lookup falls back to the default store, and the Inbox/Sent check below
|
|
21
|
+
* only knows this account's folders, so another mailbox's received mail
|
|
22
|
+
* would otherwise pass it.
|
|
23
|
+
* - Inbox and Sent Items are refused, INCLUDING their subfolders (a filed
|
|
24
|
+
* folder is still received mail), unless `allowProtected`.
|
|
25
|
+
* - `dryRun` resolves and reports without deleting, so the exact subjects and
|
|
26
|
+
* folders can be checked before anything happens.
|
|
27
|
+
* - Every outcome echoes the subject and folder of the item actually resolved.
|
|
48
28
|
*/
|
|
49
|
-
async function deleteOutlookEmails(
|
|
50
|
-
(0, run_1.
|
|
51
|
-
const { allowProtected = false, dryRun = false } = options;
|
|
52
|
-
if (entryIds.length === 0) {
|
|
53
|
-
return { dryRun, deleted: 0, refused: 0, failed: 0, items: [] };
|
|
54
|
-
}
|
|
55
|
-
const script = `${(0, scripts_1.accountScript)(emailAccount)}
|
|
29
|
+
async function deleteOutlookEmails(request) {
|
|
30
|
+
const output = await (0, run_1.runPowerShellJson)(`${(0, scripts_1.accountScript)(request.account)}
|
|
56
31
|
${scripts_1.DELIVERY_STORE_PS}
|
|
57
|
-
${
|
|
32
|
+
$allowProtected = ${(0, run_1.psBool)(request.allowProtected)}
|
|
33
|
+
$dryRun = ${(0, run_1.psBool)(request.dryRun)}
|
|
34
|
+
$protectedReason = ${(0, run_1.psString)(mail_1.PROTECTED_MAIL_REASON)}
|
|
58
35
|
$protectedIds = @{}
|
|
59
|
-
foreach ($
|
|
60
|
-
try { $protectedIds[$store.GetDefaultFolder($
|
|
36
|
+
foreach ($role in @(${PROTECTED_FOLDER_IDS.map(run_1.psInt).join(', ')})) {
|
|
37
|
+
try { $protectedIds[[string]$store.GetDefaultFolder($role).EntryID] = $true } catch {}
|
|
38
|
+
}
|
|
39
|
+
function Test-UnderProtectedFolder($folder) {
|
|
40
|
+
$current = $folder
|
|
41
|
+
for ($guard = 0; $current -ne $null -and $guard -lt 25; $guard++) {
|
|
42
|
+
$folderId = $null
|
|
43
|
+
try { $folderId = [string]$current.EntryID } catch {}
|
|
44
|
+
if (-not $folderId) { return $false }
|
|
45
|
+
if ($protectedIds.ContainsKey($folderId)) { return $true }
|
|
46
|
+
$parent = $null
|
|
47
|
+
try { $parent = $current.Parent } catch {}
|
|
48
|
+
$current = $parent
|
|
49
|
+
}
|
|
50
|
+
return $false
|
|
51
|
+
}
|
|
52
|
+
function Test-InAccountStore($folder) {
|
|
53
|
+
$folderStoreId = $null
|
|
54
|
+
try { $folderStoreId = [string]$folder.StoreID } catch {}
|
|
55
|
+
if (-not $folderStoreId) { return $false }
|
|
56
|
+
if ($folderStoreId -ieq $storeId) { return $true }
|
|
57
|
+
# One store can be named by two id strings; MAPI decides whether they match.
|
|
58
|
+
try { return [bool]$ns.CompareEntryIDs($folderStoreId, $storeId) } catch { return $false }
|
|
61
59
|
}
|
|
62
|
-
|
|
63
60
|
$items = @()
|
|
64
|
-
$
|
|
65
|
-
$refused = 0
|
|
66
|
-
$failed = 0
|
|
67
|
-
foreach ($id in @(${(0, run_1.psList)(entryIds)})) {
|
|
61
|
+
foreach ($id in ${(0, run_1.psArray)(request.entryIds)}) {
|
|
68
62
|
$subject = ''
|
|
69
63
|
$folderPath = ''
|
|
70
64
|
try {
|
|
71
65
|
$it = $null
|
|
72
66
|
try { $it = $ns.GetItemFromID($id, $store.StoreID) } catch { $it = $null }
|
|
73
67
|
if ($it -eq $null) { try { $it = $ns.GetItemFromID($id) } catch { $it = $null } }
|
|
74
|
-
if ($it -eq $null) { throw "no item with that
|
|
75
|
-
try { $subject = $it.Subject } catch {}
|
|
68
|
+
if ($it -eq $null) { throw "no item with that entry id in this account" }
|
|
69
|
+
try { $subject = [string]$it.Subject } catch {}
|
|
76
70
|
$parent = $null
|
|
77
71
|
try { $parent = $it.Parent } catch {}
|
|
78
72
|
if ($parent -eq $null) { throw "item has no parent folder - refusing to delete" }
|
|
79
|
-
try { $folderPath = $parent.FolderPath } catch {}
|
|
80
|
-
|
|
81
|
-
$
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if ($isProtected -and -not ${(0, run_1.psBool)(allowProtected)}) {
|
|
86
|
-
$refused++
|
|
87
|
-
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'refused'; reason = '${(0, run_1.psEscape)(mail_1.PROTECTED_MAIL_REASON)}' }
|
|
88
|
-
} elseif (${(0, run_1.psBool)(dryRun)}) {
|
|
89
|
-
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'would-delete'; reason = '' }
|
|
73
|
+
try { $folderPath = [string]$parent.FolderPath } catch {}
|
|
74
|
+
if (-not (Test-InAccountStore $parent)) { throw "item is in another mailbox, not this account - refusing to delete" }
|
|
75
|
+
if ((Test-UnderProtectedFolder $parent) -and -not $allowProtected) {
|
|
76
|
+
$items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'refused'; reason = $protectedReason }
|
|
77
|
+
} elseif ($dryRun) {
|
|
78
|
+
$items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'would-delete'; reason = '' }
|
|
90
79
|
} else {
|
|
91
80
|
$it.Delete()
|
|
92
|
-
$deleted
|
|
93
|
-
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'deleted'; reason = '' }
|
|
81
|
+
$items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'deleted'; reason = '' }
|
|
94
82
|
}
|
|
95
83
|
} catch {
|
|
96
|
-
$failed
|
|
97
|
-
$items += [pscustomobject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'failed'; reason = $_.Exception.Message }
|
|
84
|
+
$items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'failed'; reason = $_.Exception.Message }
|
|
98
85
|
}
|
|
99
86
|
}
|
|
100
|
-
ConvertTo-Json
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
folderPath: (0, json_1.str)(e.folderPath),
|
|
114
|
-
status: ((0, json_1.str)(e.status) || 'failed'),
|
|
115
|
-
reason: (0, json_1.str)(e.reason),
|
|
116
|
-
};
|
|
117
|
-
}),
|
|
118
|
-
};
|
|
87
|
+
ConvertTo-Json -Depth 3 -InputObject @($items)
|
|
88
|
+
`, 'scan');
|
|
89
|
+
const items = (0, json_1.toArray)(output).map(row => {
|
|
90
|
+
const e = (0, json_1.record)(row);
|
|
91
|
+
return {
|
|
92
|
+
entryId: (0, json_1.str)(e.entryId),
|
|
93
|
+
subject: (0, json_1.str)(e.subject),
|
|
94
|
+
folderPath: (0, json_1.str)(e.folderPath),
|
|
95
|
+
status: (0, mail_1.deleteStatus)((0, json_1.str)(e.status)),
|
|
96
|
+
reason: (0, json_1.str)(e.reason),
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
return (0, mail_1.deleteMailResult)(request.dryRun, items);
|
|
119
100
|
}
|
|
120
101
|
/**
|
|
121
|
-
* Permanently remove items from the account's Deleted Items
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* user already threw away.
|
|
102
|
+
* Permanently remove items from the account's Deleted Items. The ONE irreversible
|
|
103
|
+
* operation here, which is why it is folder-scoped rather than keyed on ids: it
|
|
104
|
+
* can only ever destroy what was already thrown away.
|
|
125
105
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
106
|
+
* Walks backwards, since deleting shifts the collection and a forward walk would
|
|
107
|
+
* skip every other item.
|
|
128
108
|
*/
|
|
129
|
-
async function purgeDeletedItems(
|
|
130
|
-
(0, run_1.
|
|
131
|
-
const script = `${(0, scripts_1.accountScript)(emailAccount)}
|
|
109
|
+
async function purgeDeletedItems(request) {
|
|
110
|
+
const output = await (0, run_1.runPowerShellJson)(`${(0, scripts_1.accountScript)(request.account)}
|
|
132
111
|
${scripts_1.DELIVERY_STORE_PS}
|
|
133
|
-
$folder = $store.GetDefaultFolder(
|
|
134
|
-
$
|
|
112
|
+
$folder = $store.GetDefaultFolder(${(0, run_1.psInt)(mail_1.FolderId.DeletedItems)})
|
|
113
|
+
$olderThanDays = ${(0, run_1.psInt)(request.olderThanDays)}
|
|
114
|
+
$dryRun = ${(0, run_1.psBool)(request.dryRun)}
|
|
115
|
+
${(0, scripts_1.cutoffScript)(request.olderThanDays)}
|
|
135
116
|
$matched = 0
|
|
136
117
|
$purged = 0
|
|
137
118
|
$kept = 0
|
|
138
119
|
$failed = 0
|
|
139
|
-
# Bound once:
|
|
140
|
-
# fresh collection object, and this loop runs once per message in Deleted Items.
|
|
120
|
+
# Bound once: each $folder.Items is a COM call that builds a fresh collection.
|
|
141
121
|
$folderItems = $folder.Items
|
|
142
122
|
for ($i = $folderItems.Count; $i -ge 1; $i--) {
|
|
143
123
|
$it = $null
|
|
144
124
|
try { $it = $folderItems.Item($i) } catch { continue }
|
|
145
125
|
$stamp = $null
|
|
146
|
-
foreach ($
|
|
147
|
-
try { $stamp = $it.$
|
|
126
|
+
foreach ($property in @('ReceivedTime', 'LastModificationTime', 'CreationTime')) {
|
|
127
|
+
try { $stamp = $it.$property; if ($stamp -ne $null) { break } } catch {}
|
|
148
128
|
}
|
|
149
|
-
if ($
|
|
129
|
+
if ($olderThanDays -gt 0 -and $stamp -ne $null -and $stamp -gt $cutoff) { $kept++; continue }
|
|
150
130
|
$matched++
|
|
151
|
-
if ($
|
|
131
|
+
if ($dryRun) { continue }
|
|
152
132
|
try { $it.Delete(); $purged++ } catch { $failed++ }
|
|
153
133
|
}
|
|
154
|
-
ConvertTo-Json
|
|
155
|
-
|
|
156
|
-
|
|
134
|
+
ConvertTo-Json -Compress -InputObject ([PSCustomObject]@{
|
|
135
|
+
folderPath = [string]$folder.FolderPath
|
|
136
|
+
matched = $matched
|
|
137
|
+
purged = $purged
|
|
138
|
+
kept = $kept
|
|
139
|
+
failed = $failed
|
|
140
|
+
})
|
|
141
|
+
`, 'purge');
|
|
142
|
+
const e = (0, json_1.record)(output);
|
|
157
143
|
return {
|
|
158
|
-
folderPath: (0, json_1.str)(
|
|
159
|
-
dryRun,
|
|
160
|
-
matched: (0, json_1.num)(
|
|
161
|
-
purged: (0, json_1.num)(
|
|
162
|
-
kept: (0, json_1.num)(
|
|
163
|
-
failed: (0, json_1.num)(
|
|
144
|
+
folderPath: (0, json_1.str)(e.folderPath),
|
|
145
|
+
dryRun: request.dryRun,
|
|
146
|
+
matched: (0, json_1.num)(e.matched),
|
|
147
|
+
purged: (0, json_1.num)(e.purged),
|
|
148
|
+
kept: (0, json_1.num)(e.kept),
|
|
149
|
+
failed: (0, json_1.num)(e.failed),
|
|
164
150
|
};
|
|
165
151
|
}
|
|
166
152
|
//# sourceMappingURL=cleanup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/windows/cleanup.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/windows/cleanup.ts"],"names":[],"mappings":";;AA4BA,kDAuEC;AAUD,8CA0CC;AAvJD,wDAAwD;AACxD,+BAA4E;AAC5E,uCAA2E;AAC3E,yCAA2D;AAC3D,kCAA0F;AAI1F,kFAAkF;AAClF,MAAM,oBAAoB,GAAG,CAAC,eAAQ,CAAC,KAAK,EAAE,eAAQ,CAAC,QAAQ,CAAC,CAAC;AAEjE;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,UAAU,mBAAmB,CAAC,OAA4B;IAClE,MAAM,MAAM,GAAG,MAAM,IAAA,uBAAiB,EAAC,GAAG,IAAA,uBAAa,EAAC,OAAO,CAAC,OAAO,CAAC;EAC1E,2BAAiB;oBACC,IAAA,YAAM,EAAC,OAAO,CAAC,cAAc,CAAC;YACtC,IAAA,YAAM,EAAC,OAAO,CAAC,MAAM,CAAC;qBACb,IAAA,cAAQ,EAAC,4BAAqB,CAAC;;sBAE9B,oBAAoB,CAAC,GAAG,CAAC,WAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;kBAyB9C,IAAA,aAAO,EAAC,OAAO,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2B1C,EAAE,MAAM,CAAC,CAAC;IACP,MAAM,KAAK,GAAwB,IAAA,cAAO,EAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QACzD,MAAM,CAAC,GAAG,IAAA,aAAM,EAAC,GAAG,CAAC,CAAC;QACtB,OAAO;YACH,OAAO,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,OAAO,CAAC;YACvB,OAAO,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,OAAO,CAAC;YACvB,UAAU,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,UAAU,CAAC;YAC7B,MAAM,EAAE,IAAA,mBAAY,EAAC,IAAA,UAAG,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,MAAM,CAAC;SACxB,CAAC;IACN,CAAC,CAAC,CAAC;IACH,OAAO,IAAA,uBAAgB,EAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,iBAAiB,CAAC,OAAqB;IACzD,MAAM,MAAM,GAAG,MAAM,IAAA,uBAAiB,EAAC,GAAG,IAAA,uBAAa,EAAC,OAAO,CAAC,OAAO,CAAC;EAC1E,2BAAiB;oCACiB,IAAA,WAAK,EAAC,eAAQ,CAAC,YAAY,CAAC;mBAC7C,IAAA,WAAK,EAAC,OAAO,CAAC,aAAa,CAAC;YACnC,IAAA,YAAM,EAAC,OAAO,CAAC,MAAM,CAAC;EAChC,IAAA,sBAAY,EAAC,OAAO,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BpC,EAAE,OAAO,CAAC,CAAC;IACR,MAAM,CAAC,GAAG,IAAA,aAAM,EAAC,MAAM,CAAC,CAAC;IACzB,OAAO;QACH,UAAU,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,UAAU,CAAC;QAC7B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,OAAO,CAAC;QACvB,MAAM,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,MAAM,CAAC;QACrB,IAAI,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,IAAI,CAAC;QACjB,MAAM,EAAE,IAAA,UAAG,EAAC,CAAC,CAAC,MAAM,CAAC;KACxB,CAAC;AACN,CAAC","sourcesContent":["// Deleting mail, and emptying what was already deleted.\nimport { psArray, psBool, psInt, psString, runPowerShellJson } from './run';\nimport { accountScript, cutoffScript, DELIVERY_STORE_PS } from './scripts';\nimport { num, record, str, toArray } from '../shared/json';\nimport { deleteMailResult, deleteStatus, FolderId, PROTECTED_MAIL_REASON } from '../mail';\nimport type { DeleteEmailsRequest, PurgeRequest } from '../backend';\nimport type { DeleteMailOutcome, DeleteMailResult, PurgeDeletedItemsResult } from '../types';\n\n/** Folders whose contents are received or sent mail rather than working state. */\nconst PROTECTED_FOLDER_IDS = [FolderId.Inbox, FolderId.SentMail];\n\n/**\n * Delete mail by entry id from anywhere in the account. Delete() moves each item\n * to Deleted Items, so this is recoverable — purgeDeletedItems is what destroys.\n *\n * This is the one operation that can reach received mail, and an entry id is an\n * unsafe key for it: a stale or wrong id can resolve to a DIFFERENT message.\n * Four things hold the line:\n * - An id that resolves outside this account's store is refused. The bare\n * lookup falls back to the default store, and the Inbox/Sent check below\n * only knows this account's folders, so another mailbox's received mail\n * would otherwise pass it.\n * - Inbox and Sent Items are refused, INCLUDING their subfolders (a filed\n * folder is still received mail), unless `allowProtected`.\n * - `dryRun` resolves and reports without deleting, so the exact subjects and\n * folders can be checked before anything happens.\n * - Every outcome echoes the subject and folder of the item actually resolved.\n */\nexport async function deleteOutlookEmails(request: DeleteEmailsRequest): Promise<DeleteMailResult> {\n const output = await runPowerShellJson(`${accountScript(request.account)}\n${DELIVERY_STORE_PS}\n$allowProtected = ${psBool(request.allowProtected)}\n$dryRun = ${psBool(request.dryRun)}\n$protectedReason = ${psString(PROTECTED_MAIL_REASON)}\n$protectedIds = @{}\nforeach ($role in @(${PROTECTED_FOLDER_IDS.map(psInt).join(', ')})) {\n try { $protectedIds[[string]$store.GetDefaultFolder($role).EntryID] = $true } catch {}\n}\nfunction Test-UnderProtectedFolder($folder) {\n $current = $folder\n for ($guard = 0; $current -ne $null -and $guard -lt 25; $guard++) {\n $folderId = $null\n try { $folderId = [string]$current.EntryID } catch {}\n if (-not $folderId) { return $false }\n if ($protectedIds.ContainsKey($folderId)) { return $true }\n $parent = $null\n try { $parent = $current.Parent } catch {}\n $current = $parent\n }\n return $false\n}\nfunction Test-InAccountStore($folder) {\n $folderStoreId = $null\n try { $folderStoreId = [string]$folder.StoreID } catch {}\n if (-not $folderStoreId) { return $false }\n if ($folderStoreId -ieq $storeId) { return $true }\n # One store can be named by two id strings; MAPI decides whether they match.\n try { return [bool]$ns.CompareEntryIDs($folderStoreId, $storeId) } catch { return $false }\n}\n$items = @()\nforeach ($id in ${psArray(request.entryIds)}) {\n $subject = ''\n $folderPath = ''\n try {\n $it = $null\n try { $it = $ns.GetItemFromID($id, $store.StoreID) } catch { $it = $null }\n if ($it -eq $null) { try { $it = $ns.GetItemFromID($id) } catch { $it = $null } }\n if ($it -eq $null) { throw \"no item with that entry id in this account\" }\n try { $subject = [string]$it.Subject } catch {}\n $parent = $null\n try { $parent = $it.Parent } catch {}\n if ($parent -eq $null) { throw \"item has no parent folder - refusing to delete\" }\n try { $folderPath = [string]$parent.FolderPath } catch {}\n if (-not (Test-InAccountStore $parent)) { throw \"item is in another mailbox, not this account - refusing to delete\" }\n if ((Test-UnderProtectedFolder $parent) -and -not $allowProtected) {\n $items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'refused'; reason = $protectedReason }\n } elseif ($dryRun) {\n $items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'would-delete'; reason = '' }\n } else {\n $it.Delete()\n $items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'deleted'; reason = '' }\n }\n } catch {\n $items += [PSCustomObject]@{ entryId = $id; subject = $subject; folderPath = $folderPath; status = 'failed'; reason = $_.Exception.Message }\n }\n}\nConvertTo-Json -Depth 3 -InputObject @($items)\n`, 'scan');\n const items: DeleteMailOutcome[] = toArray(output).map(row => {\n const e = record(row);\n return {\n entryId: str(e.entryId),\n subject: str(e.subject),\n folderPath: str(e.folderPath),\n status: deleteStatus(str(e.status)),\n reason: str(e.reason),\n };\n });\n return deleteMailResult(request.dryRun, items);\n}\n\n/**\n * Permanently remove items from the account's Deleted Items. The ONE irreversible\n * operation here, which is why it is folder-scoped rather than keyed on ids: it\n * can only ever destroy what was already thrown away.\n *\n * Walks backwards, since deleting shifts the collection and a forward walk would\n * skip every other item.\n */\nexport async function purgeDeletedItems(request: PurgeRequest): Promise<PurgeDeletedItemsResult> {\n const output = await runPowerShellJson(`${accountScript(request.account)}\n${DELIVERY_STORE_PS}\n$folder = $store.GetDefaultFolder(${psInt(FolderId.DeletedItems)})\n$olderThanDays = ${psInt(request.olderThanDays)}\n$dryRun = ${psBool(request.dryRun)}\n${cutoffScript(request.olderThanDays)}\n$matched = 0\n$purged = 0\n$kept = 0\n$failed = 0\n# Bound once: each $folder.Items is a COM call that builds a fresh collection.\n$folderItems = $folder.Items\nfor ($i = $folderItems.Count; $i -ge 1; $i--) {\n $it = $null\n try { $it = $folderItems.Item($i) } catch { continue }\n $stamp = $null\n foreach ($property in @('ReceivedTime', 'LastModificationTime', 'CreationTime')) {\n try { $stamp = $it.$property; if ($stamp -ne $null) { break } } catch {}\n }\n if ($olderThanDays -gt 0 -and $stamp -ne $null -and $stamp -gt $cutoff) { $kept++; continue }\n $matched++\n if ($dryRun) { continue }\n try { $it.Delete(); $purged++ } catch { $failed++ }\n}\nConvertTo-Json -Compress -InputObject ([PSCustomObject]@{\n folderPath = [string]$folder.FolderPath\n matched = $matched\n purged = $purged\n kept = $kept\n failed = $failed\n})\n`, 'purge');\n const e = record(output);\n return {\n folderPath: str(e.folderPath),\n dryRun: request.dryRun,\n matched: num(e.matched),\n purged: num(e.purged),\n kept: num(e.kept),\n failed: num(e.failed),\n };\n}\n"]}
|
package/dist/windows/drafts.d.ts
CHANGED
|
@@ -1,40 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AccountRequest, EntryIdsRequest, ListDraftsRequest } from '../backend';
|
|
2
|
+
import type { DeleteDraftsResult, ListDraftsResult, SendDraftsResult } from '../types';
|
|
3
|
+
/** The account's drafts, newest first. Bodies are previewed, never returned whole. */
|
|
4
|
+
export declare function listOutlookDrafts(request: ListDraftsRequest): Promise<ListDraftsResult>;
|
|
5
|
+
/** Send the named drafts. */
|
|
6
|
+
export declare function sendDrafts(request: EntryIdsRequest): Promise<SendDraftsResult>;
|
|
2
7
|
/**
|
|
3
|
-
* Send
|
|
4
|
-
* Which drafts those are is DRAFTS_SCAN_PS's rule, not this function's.
|
|
8
|
+
* Send every draft belonging to the account.
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
* of Drafts, and
|
|
10
|
+
* The matching items are snapshotted before the first send: sending moves an
|
|
11
|
+
* item out of Drafts, and sending during a live enumeration would skip every
|
|
12
|
+
* other one.
|
|
8
13
|
*/
|
|
9
|
-
export declare function sendAllDrafts(
|
|
14
|
+
export declare function sendAllDrafts(request: AccountRequest): Promise<SendDraftsResult>;
|
|
10
15
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* against the same folders, so repeating a ~700-char store id on every row would be
|
|
16
|
-
* pure payload. Bodies are previewed, never returned whole — a templated reply body
|
|
17
|
-
* runs to tens of thousands of characters and a folder's worth would blow the cap.
|
|
18
|
-
*/
|
|
19
|
-
export declare function listOutlookDrafts(emailAccount: string, limit?: number, previewChars?: number): Promise<ListDraftsResult>;
|
|
20
|
-
/**
|
|
21
|
-
* Delete mail drafts by EntryID. Outlook's Delete() moves the item to Deleted Items
|
|
22
|
-
* rather than destroying it, so a mistaken call stays recoverable from there.
|
|
23
|
-
*
|
|
24
|
-
* Every id must resolve to a mail item sitting in one of THIS account's Drafts
|
|
25
|
-
* folders before anything is deleted; an id pointing at ordinary mail, or at another
|
|
26
|
-
* account's draft, is refused and reported. Without that gate this would be a
|
|
27
|
-
* general-purpose "delete any email by id" tool, which is not what it is for.
|
|
28
|
-
*/
|
|
29
|
-
export declare function deleteOutlookDrafts(emailAccount: string, entryIds: string[]): Promise<DeleteDraftsResult>;
|
|
30
|
-
/**
|
|
31
|
-
* Send a chosen subset of `emailAccount`'s drafts by EntryID — e.g. after
|
|
32
|
-
* `listOutlookDrafts` and a user review pass — instead of `sendAllDrafts`'s
|
|
33
|
-
* account-wide sweep.
|
|
34
|
-
*
|
|
35
|
-
* Same ownership gate as `deleteOutlookDrafts`: every id must resolve to a mail
|
|
36
|
-
* item sitting in one of THIS account's Drafts folders before anything is sent.
|
|
37
|
-
* An id pointing at ordinary inbox mail, or at another account's draft, is
|
|
38
|
-
* refused and reported rather than sent.
|
|
16
|
+
* Delete the named drafts. Outlook's Delete() moves an item to Deleted Items,
|
|
17
|
+
* so a mistake stays recoverable. Without the proof that each is this
|
|
18
|
+
* account's draft, this would be a general "delete any email by id" call,
|
|
19
|
+
* which is not what it is for.
|
|
39
20
|
*/
|
|
40
|
-
export declare function
|
|
21
|
+
export declare function deleteOutlookDrafts(request: EntryIdsRequest): Promise<DeleteDraftsResult>;
|