apple-mail-mcp 2.20.17 → 2.20.18

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.
Files changed (2) hide show
  1. package/build/index.js +124 -17
  2. 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 fnMatch = dispHeader.match(/filename="?([^";\r\n]+)"?/i);
65200
- if (fnMatch) return fnMatch[1].trim();
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 nameMatch = ctHeader.match(/name="?([^";\r\n]+)"?/i);
65205
- if (nameMatch) return nameMatch[1].trim();
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, htmlBodies) {
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
- const needle = `cid:${cid}`;
65225
- return htmlBodies.some((html) => html.includes(needle));
65320
+ return referenced().has(cid);
65226
65321
  }
65227
- function collectHtmlBodies(parts) {
65228
- const bodies = [];
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;
65333
+ }
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
- bodies.push(
65233
- decodePartText(decodeBody(part.body, encoding), extractCharset(part.headers)).toLowerCase()
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 bodies;
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
- const htmlBodies = collectHtmlBodies(parts);
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, htmlBodies)) continue;
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 decodeEncodedWords(value) {
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 : decodeEncodedWords(v);
65632
+ return v === void 0 ? void 0 : decodeEncodedWords2(v);
65526
65633
  };
65527
65634
  const dateHeader = first("Date") || void 0;
65528
65635
  let date3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.20.17",
3
+ "version": "2.20.18",
4
4
  "description": "MCP server for Apple Mail - read, search, send, and manage emails via Claude and other AI assistants",
5
5
  "type": "module",
6
6
  "main": "build/index.js",