@bobfrankston/rmfmail 1.1.69 → 1.1.71

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.
@@ -3647,12 +3647,12 @@ function setupAutocomplete(input) {
3647
3647
  }
3648
3648
  function getLastToken() {
3649
3649
  const val = input.value;
3650
- const lastComma = val.lastIndexOf(",");
3650
+ const lastComma = lastUnquotedComma(val);
3651
3651
  return val.substring(lastComma + 1).trim();
3652
3652
  }
3653
3653
  function replaceLastToken(replacement) {
3654
3654
  const val = input.value;
3655
- const lastComma = val.lastIndexOf(",");
3655
+ const lastComma = lastUnquotedComma(val);
3656
3656
  const prefix = lastComma >= 0 ? val.substring(0, lastComma + 1) + " " : "";
3657
3657
  input.value = prefix + replacement + ", ";
3658
3658
  closeDropdown();
@@ -3729,7 +3729,7 @@ function setupAutocomplete(input) {
3729
3729
  item.addEventListener("mousedown", (e) => {
3730
3730
  e.preventDefault();
3731
3731
  if (e.button !== 0) return;
3732
- const display = r.name ? `${r.name} <${r.email}>` : r.email;
3732
+ const display = formatRecipient(r.name, r.email);
3733
3733
  replaceLastToken(display);
3734
3734
  });
3735
3735
  item.addEventListener("contextmenu", (e) => {
@@ -3786,14 +3786,48 @@ function setupAutocomplete(input) {
3786
3786
  setupAutocomplete(toInput);
3787
3787
  setupAutocomplete(ccInput);
3788
3788
  setupAutocomplete(bccInput);
3789
+ function splitRecipients(s) {
3790
+ const out = [];
3791
+ let cur = "", inQuote = false;
3792
+ for (const c of s) {
3793
+ if (c === '"') {
3794
+ inQuote = !inQuote;
3795
+ cur += c;
3796
+ } else if (c === "," && !inQuote) {
3797
+ out.push(cur);
3798
+ cur = "";
3799
+ } else cur += c;
3800
+ }
3801
+ out.push(cur);
3802
+ return out;
3803
+ }
3804
+ function lastUnquotedComma(s) {
3805
+ let inQuote = false, last = -1;
3806
+ for (let i = 0; i < s.length; i++) {
3807
+ if (s[i] === '"') inQuote = !inQuote;
3808
+ else if (s[i] === "," && !inQuote) last = i;
3809
+ }
3810
+ return last;
3811
+ }
3812
+ function formatRecipient(name, address) {
3813
+ if (!name) return address;
3814
+ const quoted = /[,"]/.test(name) ? `"${name.replace(/"/g, "'")}"` : name;
3815
+ return `${quoted} <${address}>`;
3816
+ }
3789
3817
  function formatAddrs(addrs) {
3790
- return addrs.map((a) => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");
3818
+ return addrs.map((a) => formatRecipient(a.name, a.address)).join(", ");
3791
3819
  }
3792
3820
  function parseAddrs(s) {
3793
3821
  if (!s.trim()) return [];
3794
- return s.split(",").map((p) => p.trim()).filter((p) => p.length > 0).map((part) => {
3822
+ return splitRecipients(s).map((p) => p.trim()).filter((p) => p.length > 0).map((part) => {
3795
3823
  const match = part.match(/^(.+?)\s*<(.+?)>$/);
3796
- if (match) return { name: match[1].trim(), address: match[2].trim() };
3824
+ if (match) {
3825
+ let name = match[1].trim();
3826
+ if (name.length >= 2 && name.startsWith('"') && name.endsWith('"')) {
3827
+ name = name.slice(1, -1);
3828
+ }
3829
+ return { name, address: match[2].trim() };
3830
+ }
3797
3831
  return { name: "", address: part };
3798
3832
  });
3799
3833
  }