apple-mail-mcp 2.20.17 → 2.20.19
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/build/index.js +144 -22
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -65193,16 +65193,112 @@ function getHeader(headers, name2) {
|
|
|
65193
65193
|
if (!match) return null;
|
|
65194
65194
|
return match[1].replace(/\r?\n[ \t]+/g, " ").trim();
|
|
65195
65195
|
}
|
|
65196
|
+
function decodeBytes(bytes, charset) {
|
|
65197
|
+
try {
|
|
65198
|
+
return new TextDecoder(charset.trim().toLowerCase()).decode(bytes);
|
|
65199
|
+
} catch {
|
|
65200
|
+
return bytes.toString("utf8");
|
|
65201
|
+
}
|
|
65202
|
+
}
|
|
65203
|
+
function parseParams(value) {
|
|
65204
|
+
const pieces = [];
|
|
65205
|
+
let current = "";
|
|
65206
|
+
let quoted = false;
|
|
65207
|
+
for (let i = 0; i < value.length; i++) {
|
|
65208
|
+
const ch = value[i];
|
|
65209
|
+
if (ch === "\\" && quoted && i + 1 < value.length) {
|
|
65210
|
+
current += ch + value[++i];
|
|
65211
|
+
continue;
|
|
65212
|
+
}
|
|
65213
|
+
if (ch === '"') quoted = !quoted;
|
|
65214
|
+
if (ch === ";" && !quoted) {
|
|
65215
|
+
pieces.push(current);
|
|
65216
|
+
current = "";
|
|
65217
|
+
} else {
|
|
65218
|
+
current += ch;
|
|
65219
|
+
}
|
|
65220
|
+
}
|
|
65221
|
+
pieces.push(current);
|
|
65222
|
+
const params = /* @__PURE__ */ new Map();
|
|
65223
|
+
for (const piece of pieces.slice(1)) {
|
|
65224
|
+
const eq = piece.indexOf("=");
|
|
65225
|
+
if (eq < 0) continue;
|
|
65226
|
+
let val = piece.slice(eq + 1).trim();
|
|
65227
|
+
if (val.length >= 2 && val.startsWith('"') && val.endsWith('"')) {
|
|
65228
|
+
val = val.slice(1, -1).replace(/\\(.)/g, "$1");
|
|
65229
|
+
}
|
|
65230
|
+
params.set(piece.slice(0, eq).trim().toLowerCase(), val);
|
|
65231
|
+
}
|
|
65232
|
+
return params;
|
|
65233
|
+
}
|
|
65234
|
+
function decodeEncodedWords(text) {
|
|
65235
|
+
return text.replace(/(\?=)\s+(?==\?)/g, "$1").replace(
|
|
65236
|
+
/=\?([^?\s]+)\?([bq])\?([^?]*)\?=/gi,
|
|
65237
|
+
(_all, charset, kind, body) => {
|
|
65238
|
+
const bytes = kind.toLowerCase() === "b" ? Buffer.from(body, "base64") : Buffer.from(
|
|
65239
|
+
body.replace(/_/g, " ").replace(
|
|
65240
|
+
/=([0-9a-f]{2})/gi,
|
|
65241
|
+
(_m, hex) => String.fromCharCode(parseInt(hex, 16))
|
|
65242
|
+
),
|
|
65243
|
+
"latin1"
|
|
65244
|
+
);
|
|
65245
|
+
return decodeBytes(bytes, charset.split("*")[0]);
|
|
65246
|
+
}
|
|
65247
|
+
);
|
|
65248
|
+
}
|
|
65249
|
+
function decodeExtendedValue(segments) {
|
|
65250
|
+
let charset = "utf-8";
|
|
65251
|
+
const chunks = [];
|
|
65252
|
+
segments.forEach((segment, index) => {
|
|
65253
|
+
let value = segment.value;
|
|
65254
|
+
if (!segment.encoded) {
|
|
65255
|
+
chunks.push(Buffer.from(value, "utf8"));
|
|
65256
|
+
return;
|
|
65257
|
+
}
|
|
65258
|
+
if (index === 0) {
|
|
65259
|
+
const head = value.match(/^([^']*)'[^']*'([\s\S]*)$/);
|
|
65260
|
+
if (head) {
|
|
65261
|
+
charset = head[1] || charset;
|
|
65262
|
+
value = head[2];
|
|
65263
|
+
}
|
|
65264
|
+
}
|
|
65265
|
+
chunks.push(
|
|
65266
|
+
Buffer.from(
|
|
65267
|
+
value.replace(
|
|
65268
|
+
/%([0-9a-f]{2})/gi,
|
|
65269
|
+
(_m, hex) => String.fromCharCode(parseInt(hex, 16))
|
|
65270
|
+
),
|
|
65271
|
+
"latin1"
|
|
65272
|
+
)
|
|
65273
|
+
);
|
|
65274
|
+
});
|
|
65275
|
+
return decodeBytes(Buffer.concat(chunks), charset);
|
|
65276
|
+
}
|
|
65277
|
+
function paramValue(params, name2) {
|
|
65278
|
+
const extended = params.get(`${name2}*`);
|
|
65279
|
+
if (extended !== void 0) return decodeExtendedValue([{ value: extended, encoded: true }]);
|
|
65280
|
+
const segments = [];
|
|
65281
|
+
for (let i = 0; ; i++) {
|
|
65282
|
+
const encoded = params.get(`${name2}*${i}*`);
|
|
65283
|
+
const plain = params.get(`${name2}*${i}`);
|
|
65284
|
+
if (encoded !== void 0) segments.push({ value: encoded, encoded: true });
|
|
65285
|
+
else if (plain !== void 0) segments.push({ value: plain, encoded: false });
|
|
65286
|
+
else break;
|
|
65287
|
+
}
|
|
65288
|
+
if (segments.length > 0) return decodeExtendedValue(segments);
|
|
65289
|
+
const value = params.get(name2);
|
|
65290
|
+
return value === void 0 ? null : decodeEncodedWords(value);
|
|
65291
|
+
}
|
|
65196
65292
|
function extractFilename(headers) {
|
|
65197
65293
|
const dispHeader = getHeader(headers, "Content-Disposition");
|
|
65198
65294
|
if (dispHeader) {
|
|
65199
|
-
const
|
|
65200
|
-
if (
|
|
65295
|
+
const filename = paramValue(parseParams(dispHeader), "filename")?.trim();
|
|
65296
|
+
if (filename) return filename;
|
|
65201
65297
|
}
|
|
65202
65298
|
const ctHeader = getHeader(headers, "Content-Type");
|
|
65203
65299
|
if (ctHeader) {
|
|
65204
|
-
const
|
|
65205
|
-
if (
|
|
65300
|
+
const name2 = paramValue(parseParams(ctHeader), "name")?.trim();
|
|
65301
|
+
if (name2) return name2;
|
|
65206
65302
|
}
|
|
65207
65303
|
return null;
|
|
65208
65304
|
}
|
|
@@ -65217,23 +65313,33 @@ function extractContentId(headers) {
|
|
|
65217
65313
|
const id = raw.replace(/^<+/, "").replace(/>+$/, "").trim().toLowerCase();
|
|
65218
65314
|
return id || null;
|
|
65219
65315
|
}
|
|
65220
|
-
function isEmbeddedResource(headers,
|
|
65316
|
+
function isEmbeddedResource(headers, referenced) {
|
|
65221
65317
|
if (!isInlineDisposition(headers)) return false;
|
|
65222
65318
|
const cid = extractContentId(headers);
|
|
65223
65319
|
if (!cid) return false;
|
|
65224
|
-
|
|
65225
|
-
|
|
65320
|
+
return referenced().has(cid);
|
|
65321
|
+
}
|
|
65322
|
+
function cidReferences(html) {
|
|
65323
|
+
const refs = /* @__PURE__ */ new Set();
|
|
65324
|
+
for (const match of html.matchAll(/cid:([^\s"'<>()]+)/gi)) {
|
|
65325
|
+
let ref = match[1];
|
|
65326
|
+
try {
|
|
65327
|
+
ref = decodeURIComponent(ref);
|
|
65328
|
+
} catch {
|
|
65329
|
+
}
|
|
65330
|
+
refs.add(ref.trim().toLowerCase());
|
|
65331
|
+
}
|
|
65332
|
+
return refs;
|
|
65226
65333
|
}
|
|
65227
|
-
function
|
|
65228
|
-
const
|
|
65334
|
+
function collectCidReferences(parts) {
|
|
65335
|
+
const refs = /* @__PURE__ */ new Set();
|
|
65229
65336
|
for (const part of parts) {
|
|
65230
65337
|
if (extractMimeType(part.headers) !== "text/html") continue;
|
|
65231
65338
|
const encoding = getHeader(part.headers, "Content-Transfer-Encoding");
|
|
65232
|
-
|
|
65233
|
-
|
|
65234
|
-
);
|
|
65339
|
+
const html = decodePartText(decodeBody(part.body, encoding), extractCharset(part.headers));
|
|
65340
|
+
for (const ref of cidReferences(html)) refs.add(ref);
|
|
65235
65341
|
}
|
|
65236
|
-
return
|
|
65342
|
+
return refs;
|
|
65237
65343
|
}
|
|
65238
65344
|
function extractSize(headers) {
|
|
65239
65345
|
const dispHeader = getHeader(headers, "Content-Disposition");
|
|
@@ -65340,12 +65446,13 @@ function parseMimeAttachments(source) {
|
|
|
65340
65446
|
const boundary = extractBoundary(source);
|
|
65341
65447
|
if (!boundary) return [];
|
|
65342
65448
|
const parts = walkLeafParts(source, boundary);
|
|
65343
|
-
|
|
65449
|
+
let refs;
|
|
65450
|
+
const referenced = () => refs ??= collectCidReferences(parts);
|
|
65344
65451
|
const attachments = [];
|
|
65345
65452
|
for (const part of parts) {
|
|
65346
65453
|
const filename = extractFilename(part.headers);
|
|
65347
65454
|
if (!filename) continue;
|
|
65348
|
-
if (isEmbeddedResource(part.headers,
|
|
65455
|
+
if (isEmbeddedResource(part.headers, referenced)) continue;
|
|
65349
65456
|
const encoding = getHeader(part.headers, "Content-Transfer-Encoding");
|
|
65350
65457
|
attachments.push({
|
|
65351
65458
|
name: filename,
|
|
@@ -65432,7 +65539,7 @@ var init_mimeParse = __esm({
|
|
|
65432
65539
|
});
|
|
65433
65540
|
|
|
65434
65541
|
// src/utils/headers.ts
|
|
65435
|
-
function
|
|
65542
|
+
function decodeEncodedWords2(value) {
|
|
65436
65543
|
if (!value.includes("=?")) return value;
|
|
65437
65544
|
const joined = value.replace(/(\?=)\s+(=\?)/g, "$1$2");
|
|
65438
65545
|
return joined.replace(
|
|
@@ -65522,7 +65629,7 @@ function parseHeaderBlock(input) {
|
|
|
65522
65629
|
const all = (name2) => headers.filter((h) => h.name.toLowerCase() === name2.toLowerCase()).map((h) => h.value);
|
|
65523
65630
|
const decoded = (name2) => {
|
|
65524
65631
|
const v = first(name2);
|
|
65525
|
-
return v === void 0 ? void 0 :
|
|
65632
|
+
return v === void 0 ? void 0 : decodeEncodedWords2(v);
|
|
65526
65633
|
};
|
|
65527
65634
|
const dateHeader = first("Date") || void 0;
|
|
65528
65635
|
let date3;
|
|
@@ -84997,9 +85104,13 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
84997
85104
|
if (scoped.kind === "hit") return scoped.output;
|
|
84998
85105
|
if (scoped.kind === "done") return null;
|
|
84999
85106
|
}
|
|
85000
|
-
const
|
|
85001
|
-
|
|
85002
|
-
|
|
85107
|
+
const account = hint?.account && !hint?.mailbox ? hint.account : void 0;
|
|
85108
|
+
const result = executeAppleScript(
|
|
85109
|
+
this.unscopedByIdScript(id, innerAction, { ...opts, account }),
|
|
85110
|
+
{
|
|
85111
|
+
timeoutMs: READ_ONLY_BYID_TIMEOUT_MS
|
|
85112
|
+
}
|
|
85113
|
+
);
|
|
85003
85114
|
if (!result.success || !result.output.trim()) {
|
|
85004
85115
|
if (!result.success) {
|
|
85005
85116
|
if (result.timedOut) this.lastMessageLookupError = timedOutScanningForId(id);
|
|
@@ -85116,6 +85227,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
85116
85227
|
*/
|
|
85117
85228
|
unscopedByIdScript(id, innerAction, opts = {}) {
|
|
85118
85229
|
const threshold = getByIdScanThreshold();
|
|
85230
|
+
const scopeAcct = escapeForAppleScript(opts.account ?? "");
|
|
85119
85231
|
const stalledKeys = threshold > 0 ? this.stalledMailboxes.keys() : [];
|
|
85120
85232
|
const stalledList = `{${stalledKeys.map((key) => {
|
|
85121
85233
|
const i = key.indexOf(STALLED_KEY_SEP);
|
|
@@ -85175,6 +85287,8 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
85175
85287
|
set _probeStalled to false
|
|
85176
85288
|
set _stopAt to 0
|
|
85177
85289
|
set _stalledKeys to ${stalledList}
|
|
85290
|
+
set _scopeAcct to "${scopeAcct}"
|
|
85291
|
+
set _acctSeen to false
|
|
85178
85292
|
set _startedAt to current date
|
|
85179
85293
|
set _acctNames to {}
|
|
85180
85294
|
try
|
|
@@ -85191,10 +85305,14 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
85191
85305
|
set _acctName to ""
|
|
85192
85306
|
if _ai <= (length of _acctNames) then set _acctName to item _ai of _acctNames
|
|
85193
85307
|
if _acctName is "" then set _acctName to (name of acct)
|
|
85194
|
-
if
|
|
85308
|
+
if _scopeAcct is not "" and _acctName is not _scopeAcct then
|
|
85309
|
+
-- Scoped to one account: leave the others alone.
|
|
85310
|
+
set _ai to _ai + 0
|
|
85311
|
+
else if _budgetHit or _probeStalled then
|
|
85195
85312
|
-- Stopped early: name what is left without asking Mail.app.
|
|
85196
85313
|
set _unreached to _unreached & _acctName & " (every mailbox)${DIAG_ITEM_SEP}"
|
|
85197
85314
|
else
|
|
85315
|
+
set _acctSeen to true
|
|
85198
85316
|
set _mbNames to {}
|
|
85199
85317
|
try
|
|
85200
85318
|
set _mbNames to name of mailboxes of acct
|
|
@@ -85240,7 +85358,11 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
85240
85358
|
-- reach them. Collect into the SAME _hits/_names, which means an id
|
|
85241
85359
|
-- present both in an account and locally is now correctly reported as
|
|
85242
85360
|
-- ambiguous rather than silently resolving to the account copy.
|
|
85243
|
-
if
|
|
85361
|
+
if _scopeAcct is not "" and not _acctSeen then return "${LOOKUP_ERROR_MARKER}Account \\"" & _scopeAcct & "\\" not found \u2014 check the name with list-accounts."
|
|
85362
|
+
if _scopeAcct is not "" then
|
|
85363
|
+
-- Local mailboxes belong to no account.
|
|
85364
|
+
set _ai to _ai + 0
|
|
85365
|
+
else if _budgetHit or _probeStalled then
|
|
85244
85366
|
set _unreached to _unreached & "${LOCAL_STORE_LABEL} (any local mailboxes)${DIAG_ITEM_SEP}"
|
|
85245
85367
|
else if not (${hitFound}) then${localMailboxBindingFragment()}
|
|
85246
85368
|
set _mi to 0
|
package/package.json
CHANGED