@social-mail/social-mail-client 1.2.310 → 1.2.311

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 (56) hide show
  1. package/dist/admin/AdminAppIndex.pack.js +195 -37
  2. package/dist/admin/AdminAppIndex.pack.js.map +1 -1
  3. package/dist/admin/AdminAppIndex.pack.min.js +6 -5
  4. package/dist/admin/AdminAppIndex.pack.min.js.map +1 -1
  5. package/dist/public/channel/ChannelView.pack.js +1 -0
  6. package/dist/public/channel/ChannelView.pack.js.map +1 -1
  7. package/dist/public/channel/ChannelView.pack.min.js +1 -0
  8. package/dist/public/channel/ChannelView.pack.min.js.map +1 -1
  9. package/dist/public/store/Store.pack.js +1 -0
  10. package/dist/public/store/Store.pack.js.map +1 -1
  11. package/dist/public/store/Store.pack.min.js +1 -0
  12. package/dist/public/store/Store.pack.min.js.map +1 -1
  13. package/dist/public/store/StoreApp.pack.js +1 -0
  14. package/dist/public/store/StoreApp.pack.js.map +1 -1
  15. package/dist/public/store/StoreApp.pack.min.js +1 -0
  16. package/dist/public/store/StoreApp.pack.min.js.map +1 -1
  17. package/dist/services/mime-service/MimeMessage.d.ts +1 -1
  18. package/dist/services/mime-service/MimeMessage.d.ts.map +1 -1
  19. package/dist/services/mime-service/MimeMessage.js +3 -2
  20. package/dist/services/mime-service/MimeMessage.js.map +1 -1
  21. package/dist/services/mime-service/MimeNode.d.ts +6 -1
  22. package/dist/services/mime-service/MimeNode.d.ts.map +1 -1
  23. package/dist/services/mime-service/MimeNode.js +37 -30
  24. package/dist/services/mime-service/MimeNode.js.map +1 -1
  25. package/dist/style/GlobalStyle.js +1 -0
  26. package/dist/style/GlobalStyle.js.map +1 -1
  27. package/dist/tests/services/mime/parse-headers.d.ts +2 -0
  28. package/dist/tests/services/mime/parse-headers.d.ts.map +1 -0
  29. package/dist/tests/services/mime/parse-headers.js +123 -0
  30. package/dist/tests/services/mime/parse-headers.js.map +1 -0
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/dist/web/AppIndex.pack.js +2404 -2246
  33. package/dist/web/AppIndex.pack.js.map +1 -1
  34. package/dist/web/AppIndex.pack.min.js +6 -5
  35. package/dist/web/AppIndex.pack.min.js.map +1 -1
  36. package/dist/web/page/mails/ConversationPage.d.ts +1 -0
  37. package/dist/web/page/mails/ConversationPage.d.ts.map +1 -1
  38. package/dist/web/page/mails/ConversationPage.js +22 -3
  39. package/dist/web/page/mails/ConversationPage.js.map +1 -1
  40. package/dist/web/page/mails/MailboxContacts.d.ts.map +1 -1
  41. package/dist/web/page/mails/MailboxContacts.js +6 -1
  42. package/dist/web/page/mails/MailboxContacts.js.map +1 -1
  43. package/dist/web/page/mails/unsubscribe/UnsubscribeWindow.d.ts +11 -0
  44. package/dist/web/page/mails/unsubscribe/UnsubscribeWindow.d.ts.map +1 -0
  45. package/dist/web/page/mails/unsubscribe/UnsubscribeWindow.js +122 -0
  46. package/dist/web/page/mails/unsubscribe/UnsubscribeWindow.js.map +1 -0
  47. package/node_modules/@web-atoms/data-styles/data-styles.css +8 -1
  48. package/node_modules/@web-atoms/data-styles/package.json +1 -1
  49. package/package.json +2 -2
  50. package/src/services/mime-service/MimeMessage.ts +5 -3
  51. package/src/services/mime-service/MimeNode.ts +53 -30
  52. package/src/style/GlobalStyle.ts +1 -0
  53. package/src/tests/services/mime/parse-headers.ts +111 -0
  54. package/src/web/page/mails/ConversationPage.tsx +18 -0
  55. package/src/web/page/mails/MailboxContacts.tsx +6 -1
  56. package/src/web/page/mails/unsubscribe/UnsubscribeWindow.tsx +108 -0
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-redundant-type-constituents */
1
2
  import QueryIterator from "../../common/QueryIterator";
2
3
  import { AttachmentFile } from "./AttachmentFile";
3
4
  import { HeaderContentType } from "./HeaderContentType";
@@ -26,7 +27,32 @@ export type IContentDisposition = string | IContentDispositionObject;
26
27
 
27
28
 
28
29
 
30
+ export class CIMap extends Map {
29
31
 
32
+ ci = new Map();
33
+
34
+ set(key: any, value: any): this {
35
+ if (typeof key === "string") {
36
+ let ck = this.ci.get(key);
37
+ if (ck === void 0) {
38
+ ck = key.toLocaleLowerCase();
39
+ this.ci.set(ck, key);
40
+ } else {
41
+ key = ck;
42
+ }
43
+ }
44
+ return super.set(key, value);
45
+ }
46
+
47
+ get(key) {
48
+ if (typeof key === "string") {
49
+ const ck = key.toLocaleLowerCase();
50
+ key = this.ci.get(ck);
51
+ }
52
+ return super.get(key);
53
+ }
54
+
55
+ }
30
56
 
31
57
 
32
58
  export class MimeNode {
@@ -132,7 +158,7 @@ export class MimeNode {
132
158
  return this.contentType.boundary;
133
159
  }
134
160
 
135
- get descendents() {
161
+ get descendent() {
136
162
  return this.enumerate();
137
163
  }
138
164
 
@@ -142,14 +168,14 @@ export class MimeNode {
142
168
  private headers: Map<string, string | any>;
143
169
 
144
170
  constructor(type?: string) {
145
- this.headers = new Map();
171
+ this.headers = new CIMap();
146
172
  this.contentType = new HeaderContentType(type);
147
173
  this.headers.set("Content-Type", this.contentType);
148
174
  }
149
175
 
150
176
  getFirstChild(contentType: string, create = false) {
151
177
  contentType = contentType.toLocaleLowerCase();
152
- let child = QueryIterator.first(this.descendents, (x) => x.contentType.type === contentType);
178
+ let child = QueryIterator.first(this.descendent, (x) => x.contentType.type === contentType);
153
179
  if (!child && create) {
154
180
  child = new MimeNode(contentType);
155
181
  (this.children ??= []).push(child);
@@ -158,33 +184,30 @@ export class MimeNode {
158
184
  }
159
185
 
160
186
  header(name: string) {
161
- for (const [key, value] of this.headers.entries()) {
162
- if (key.toLocaleLowerCase() === name.toLocaleLowerCase()) {
163
- return value;
164
- }
165
- }
187
+ return this.headers.get(name);
166
188
  }
167
189
 
168
190
  setHeader(name: string, value: string) {
169
- for (const [key] of this.headers.keys()) {
170
- if (key.toLocaleLowerCase() === name.toLocaleLowerCase()) {
171
- this.headers.set(key, value);
172
- return;
173
- }
174
- }
175
-
176
- // change name...
177
- switch(name.toLocaleLowerCase()) {
178
- case "content-type":
179
- name = "Content-Type";
180
- break;
181
- case "content-transfer-encoding":
182
- name = "Content-Transfer-Encoding";
183
- break;
184
- case "content-disposition":
185
- name = "Content-Disposition";
186
- break;
187
- }
191
+ // name = name.toLocaleLowerCase();
192
+ // for (const [key] of this.headers.keys()) {
193
+ // if (key.toLocaleLowerCase() === name) {
194
+ // this.headers.set(key, value);
195
+ // return;
196
+ // }
197
+ // }
198
+
199
+ // // change name...
200
+ // switch(name.toLocaleLowerCase()) {
201
+ // case "content-type":
202
+ // name = "Content-Type";
203
+ // break;
204
+ // case "content-transfer-encoding":
205
+ // name = "Content-Transfer-Encoding";
206
+ // break;
207
+ // case "content-disposition":
208
+ // name = "Content-Disposition";
209
+ // break;
210
+ // }
188
211
 
189
212
  this.headers.set(name, value);
190
213
  }
@@ -287,9 +310,9 @@ export class MimeNode {
287
310
  if (headerValue) {
288
311
  this.setHeader(headerName, headerValue);
289
312
  }
290
- const [k, v] = value.split(":", 2);
291
- headerName = k;
292
- headerValue = wordEncoding.decode(v.trim());
313
+ const index = value.indexOf(":");
314
+ headerName = value.substring(0, index);
315
+ headerValue = wordEncoding.decode(value.substring(index+1).trim());
293
316
  }
294
317
 
295
318
  if (headerValue) {
@@ -49,6 +49,7 @@ addLinkTag("https://cdn.jsdelivr.net/npm/file-icon-vectors@1.0.0/dist/file-icon-
49
49
  --font-size-small: 0.8125em;
50
50
 
51
51
  --hover-color: #b8b88b20;
52
+ --command-bg-color: #50505025;
52
53
  --hover-text-color: CanvasText;
53
54
  --selection-color: #b8b88b60;
54
55
  --selection-text-color: CanvasText;
@@ -0,0 +1,111 @@
1
+ import { CIMap, MimeNode } from "../../../services/mime-service/MimeNode";
2
+ import { StringLineStream } from "../../../services/mime-service/stream/LineStream";
3
+ import { Assert } from "../../Assert";
4
+
5
+
6
+ export default async function() {
7
+
8
+ const ci = new CIMap();
9
+
10
+ ci.set("A1", "a1");
11
+ Assert.equal(ci.get("a1"), "a1");
12
+ ci.set("a1", "a2");
13
+ Assert.equal(ci.get("A1"), "a2");
14
+
15
+ const root = new MimeNode();
16
+ await root.parse(new StringLineStream(data));
17
+
18
+ const line = root.header("list-unsubscribe");
19
+ console.log(line);
20
+ }
21
+
22
+ const data = `Delivered-To: ackava@gmail.com
23
+ Received: by 2002:ab3:fb12:0:b0:55d:606f:316e with SMTP id n18csp92417qnc;
24
+ Mon, 15 Jul 2024 23:31:52 -0700 (PDT)
25
+ X-Google-Smtp-Source: AGHT+IH6CExL3W27oPGLMruurtcQA5CkW5wqoDtPj4M6JjXMJc0nbBOuUbMU5Q8akO/F+0WOnqce
26
+ X-Received: by 2002:a05:6102:14a1:b0:48f:ea45:4887 with SMTP id ada2fe7eead31-4914c4edf1amr1746703137.11.1721111511897;
27
+ Mon, 15 Jul 2024 23:31:51 -0700 (PDT)
28
+ ARC-Seal: i=1; a=rsa-sha256; t=1721111511; cv=none;
29
+ d=google.com; s=arc-20160816;
30
+ b=N0GPNVoa8Da4t9jg6uBYFBvzxKd5i1zYqcy55LVZhzJMJRvsMmCieWIYH/4wBPY2C7
31
+ oLF0lDPZQ6wp3M5hCQpYA6/yBizdWPlympG8cmuA1D7MDUSMcDZ/FKc7vwKKHMa2LEsN
32
+ tPSS1qwY836b9wKmOpYZ8IVG0eI7Qi/9NqICCBmW8Uyur/ZEK+eZyAMDLK3zpDjg8BOw
33
+ fOxqfPjmrDV+xyYMFl+QSdhGAFCSjG+Lh00BsO8uoGmBmxTAvHqGtQ8+i86jX+fn55dW
34
+ Bj7+hGNHE/w9JC60wbGY7A/BZBxr5NJuUbS6lf50AWx8r+KS0+piIbsCiZD1x0cL8aZ+
35
+ lnBg==
36
+ ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
37
+ h=mime-version:list-unsubscribe:list-owner:list-subscribe
38
+ :list-unsubscribe-post:list-help:precedence:message-id:from:date
39
+ :subject:to:dkim-signature;
40
+ bh=f6Rq15fNlqiCZ7WKqPaNobIXI+0TpZUM+Nj4isITnpI=;
41
+ fh=hmlPyZWPDmkzfTC20X6uYeCWPkl43Yxy6ifyYfZzmrU=;
42
+ b=hYVMCCcZ2ypLkmeRqGFl5tSMhfIGs9r5Gq/SztqXKJ+BqzaguMzcVpvRKTK8CJBpgq
43
+ KkL0620XPMiBUsUFivvuJHS5nHrsBDOye0fTisTCa+S/QJZVVVTbKCNrV1IbRzfbDoZd
44
+ 2BsmLm0mjVQZQhO0W9eZXjlulmw8a9TvFEz/2z9/8/kMAGC22ugTkTQZSwmoSFHjT+EU
45
+ bs8uV8qLLtp1PiKDj4Br4kwJQtc6D8IsZHkIxbnmRts1wylrxr88u1CHZ9/RHScBa6Ga
46
+ ua56Ajf8wuPjnS6RaZD0apIDPyF28DWBNVqcSGH3x4K0W8Rndf0NgXWjGVT1bcB9oVm7
47
+ cr5w==;
48
+ dara=google.com
49
+ ARC-Authentication-Results: i=1; mx.google.com;
50
+ dkim=pass header.i=@bypeople.com header.s=default header.b=QU8Ngf8L;
51
+ spf=pass (google.com: domain of listbounces@bypeople.com designates 64.64.7.193 as permitted sender) smtp.mailfrom=listbounces@bypeople.com
52
+ Return-Path: <listbounces@bypeople.com>
53
+ Received: from bypeople.com (mail.bypeople.com. [64.64.7.193])
54
+ by mx.google.com with ESMTPS id 6a1803df08f44-6b761a03be8si67454336d6.214.2024.07.15.23.31.51
55
+ for <ackava@gmail.com>
56
+ (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
57
+ Mon, 15 Jul 2024 23:31:51 -0700 (PDT)
58
+ Received-SPF: pass (google.com: domain of listbounces@bypeople.com designates 64.64.7.193 as permitted sender) client-ip=64.64.7.193;
59
+ Authentication-Results: mx.google.com;
60
+ dkim=pass header.i=@bypeople.com header.s=default header.b=QU8Ngf8L;
61
+ spf=pass (google.com: domain of listbounces@bypeople.com designates 64.64.7.193 as permitted sender) smtp.mailfrom=listbounces@bypeople.com
62
+ DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
63
+ d=bypeople.com; s=default; h=Content-Type:MIME-Version:List-Unsubscribe:
64
+ List-Owner:List-Subscribe:List-Help:Message-ID:From:Date:Subject:To:Sender:
65
+ Reply-To:Cc:Content-Transfer-Encoding:Content-ID:Content-Description:
66
+ Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:
67
+ In-Reply-To:References:List-Id:List-Post:List-Archive;
68
+ bh=f6Rq15fNlqiCZ7WKqPaNobIXI+0TpZUM+Nj4isITnpI=; b=QU8Ngf8LVkZ5Txf/iicBVbrz02
69
+ hltmvhYW8uniAlLZCOaFAM6pI4rA9D3X5GwJQF1VCmu+a/Tt8uijaXJxQGu+cEX/ePY2s/ZuIoZuO
70
+ tFvD7t4yW2E2//EHG2igbD++G+f7xWg3CX5j2TN1lGC0sVU071Ivo2j9RdH81IDEsuTTKP7nmTpgd
71
+ MWtodz14xW/F6IRG+eUEqZkFnuxJtIkh3GFfcWq0yDFpsYn+FwfdcyCJdB+UaMvbKhO1XbrjEYEHc
72
+ gNM3Ad74pg4zZBWsUKMkM0UjhI8v77nOe6KEauvRflHH8Q+pAPdJ/ijS3K+jFl3+fkK77IX9tix55
73
+ jyVGzMyg==;
74
+ Received: from peopleby by new.designshock.com with local (Exim 4.97.1)
75
+ (envelope-from <listbounces@bypeople.com>)
76
+ id 1sTbj5-0000000Blo5-2iZm
77
+ for ackava@gmail.com;
78
+ Tue, 16 Jul 2024 01:31:51 -0500
79
+ To: ackava@gmail.com
80
+ Subject: =?us-ascii?Q?Meet_TshirtDesigns.com_|_3000+_Designs_POD_Read?= =?us-ascii?Q?y,__Lifetime_License!?=
81
+ X-PHP-Originating-Script: 1009:PHPMailer.php
82
+ Date: Tue, 16 Jul 2024 01:31:51 -0500
83
+ From: ByPeople New Project <bp@bypeople.com>
84
+ Message-ID: <wciuWaefXt7RVB1dAEpGxJGiLnRjMH5qpwluY3d6RTE@bypeople.com>
85
+ X-phpList-version: 3.6.7
86
+ X-MessageID: 2601
87
+ X-ListMember: ackava@gmail.com
88
+ Precedence: bulk
89
+ List-Help: =?us-ascii?Q?<http://www.bypeople.com/lists/=3Fp=3Dpreferenc?=
90
+ =?us-ascii?Q?es&uid=3Ddc741e7eb965aacaece6aa3b8e538383>?=
91
+ List-Unsubscribe-Post: List-Unsubscribe=One-Click
92
+ List-Subscribe: <http://www.bypeople.com/lists/?p=subscribe>
93
+ List-Owner: <mailto:listreports@bypeople.com>
94
+ List-Unsubscribe: =?us-ascii?Q?<mailto:abuse@bypeople.com=3Fsubject=3Ddc741e7e?=
95
+ =?us-ascii?Q?b965aacaece6aa3b8e538383>,<http://www.bypeople.?=
96
+ =?us-ascii?Q?com/lists/=3Fp=3Dunsubscribe&uid=3Ddc741e7eb965?=
97
+ =?us-ascii?Q?aacaece6aa3b8e538383>?=
98
+ MIME-Version: 1.0
99
+ Content-Type: multipart/alternative;
100
+ boundary="b1_wciuWaefXt7RVB1dAEpGxJGiLnRjMH5qpwluY3d6RTE"
101
+ X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
102
+ X-AntiAbuse: Primary Hostname - new.designshock.com
103
+ X-AntiAbuse: Original Domain - gmail.com
104
+ X-AntiAbuse: Originator/Caller UID/GID - [1009 978] / [47 12]
105
+ X-AntiAbuse: Sender Address Domain - bypeople.com
106
+ X-Get-Message-Sender-Via: new.designshock.com: authenticated_id: peopleby/from_h
107
+ X-Authenticated-Sender: new.designshock.com: bp@bypeople.com
108
+ X-Source:
109
+ X-Source-Args: phpList:PHPlistPB:core-processqueue
110
+ X-Source-Dir: bypeople.com:/public_html/lists/admin
111
+ `;
@@ -33,6 +33,7 @@ import EngagementDetails from "./engagements/EngagementDetails";
33
33
  import { apiPath } from "../../../common/apiPath";
34
34
  import { AddIconTextButton, DeleteIconTextButton, EditIconTextButton } from "../../../common/controls/buttons/IconButton";
35
35
  import sleep from "@web-atoms/core/dist/core/sleep";
36
+ import UnsubscribeWindow from "./unsubscribe/UnsubscribeWindow";
36
37
 
37
38
  const itemCss = styled.css `
38
39
  border: solid 1px lightgray;
@@ -290,6 +291,11 @@ export default class ConversationPage extends ContentPage {
290
291
  class="fa-solid fa-share-all"
291
292
  title="Forward"
292
293
  />
294
+ { item.hasUnsubscribe && <button
295
+ data-layout="link"
296
+ data-margin-left="auto"
297
+ data-click-event="unsubscribe-email"
298
+ >Unsubscribe</button>}
293
299
  </div> }
294
300
  {isSending && <div data-layout="command-row" style-padding-left="20px">
295
301
  <span text={`Sending in (${ Math.ceil(remaining.totalSeconds)} sec) `}/>
@@ -677,4 +683,16 @@ export default class ConversationPage extends ContentPage {
677
683
  this.mails.remove(mce);
678
684
  }
679
685
 
686
+ @Action({
687
+ onEvent: "unsubscribe-email"
688
+ })
689
+ async unsubscribeEmail(mce: IMailboxContactEmail) {
690
+ const result = await PageNavigator.pushPageForResult(UnsubscribeWindow, mce);
691
+ switch(result) {
692
+ case "blocked":
693
+ this.parameters.blocked = true;
694
+ break;
695
+ }
696
+ }
697
+
680
698
  }
@@ -312,7 +312,12 @@ export default class MailsPage extends MasterDetailPage {
312
312
 
313
313
  @Action({ onEvent: MailAppEvents.mailboxContactUpdated})
314
314
  updateMailboxContact(mc: IMailboxContact) {
315
- this.threadsRepeater.refreshItem(mc);
315
+ const { mailboxID , emailAddressID } = mc;
316
+ const item = this.threadsRepeater.items.find((x: IMailboxContact) =>
317
+ x.mailboxID === mailboxID
318
+ && x.emailAddressID === emailAddressID
319
+ );
320
+ this.threadsRepeater.refreshItem(item);
316
321
  }
317
322
 
318
323
  @Action({ onEvent: "compose-template"})
@@ -0,0 +1,108 @@
1
+ import PopupWindow from "@web-atoms/core/dist/web/services/PopupWindow";
2
+ import BottomPopup from "@web-atoms/web-controls/dist/mobile-app/BottomPopup";
3
+ import { PopupWindowPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
4
+ import { IMailboxContactEmail, MailboxContact } from "../../../../model/model";
5
+ import XNode from "@web-atoms/core/dist/core/XNode";
6
+ import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
7
+ import EntityService from "../../../../services/EntityService";
8
+ import Action from "@web-atoms/core/dist/view-model/Action";
9
+ import FetchBuilder from "@web-atoms/core/dist/services/FetchBuilder";
10
+ import MimeMessage from "../../../../services/mime-service/MimeMessage";
11
+ import { MimeNode } from "../../../../services/mime-service/MimeNode";
12
+ import { StringLineStream } from "../../../../services/mime-service/stream/LineStream";
13
+ import sleep from "@web-atoms/core/dist/core/sleep";
14
+ import { MailAppEvents } from "../../../commands/MailAppEvents";
15
+
16
+ export default class UnsubscribeWindow extends PopupWindowPage<IMailboxContactEmail> {
17
+
18
+ @InjectProperty
19
+ entityService: EntityService;
20
+
21
+ async init() {
22
+
23
+ this.title = "Are you sure?";
24
+
25
+ this.renderer = <div>
26
+ <div>
27
+ <div text={`From: ${this.parameters.email.senderName}`}/>
28
+ <div text={this.parameters.email.senderEmail.emailAddress}/>
29
+ </div>
30
+ <div data-layout="command-row">
31
+ <button
32
+ data-click-event="unsubscribe-post"
33
+ >Unsubscribe</button>
34
+ <button
35
+ data-click-event="block-sender"
36
+ data-margin-left="auto"
37
+ >Block</button>
38
+ </div>
39
+ </div>;
40
+ }
41
+
42
+ @Action({ onEvent: "unsubscribe-post"})
43
+ async unsubscribePost() {
44
+ await this.doUnsubscribe();
45
+
46
+ await sleep(2000);
47
+ this.close("unsubscribed");
48
+ const { mailboxID, emailAddressID } = this.parameters;
49
+ const entity = MailboxContact.create({
50
+ mailboxID,
51
+ emailAddressID,
52
+ closeAllConversations: true
53
+ });
54
+ await this.entityService.save(entity, (e) => e);
55
+ MailAppEvents.mailboxContactUpdated.dispatchEvent(entity);
56
+ }
57
+
58
+ @Action({ onEvent: "block-sender"})
59
+ async blockSender() {
60
+ await this.unsubscribePost();
61
+ const { mailboxID, emailAddressID } = this.parameters;
62
+ const entity = MailboxContact.create({
63
+ mailboxID,
64
+ emailAddressID,
65
+ blocked: true
66
+ });
67
+ await this.entityService.save(entity, (e) => e);
68
+ MailAppEvents.mailboxContactUpdated.dispatchEvent(entity);
69
+ this.close("blocked");
70
+ }
71
+
72
+ private async doUnsubscribe() {
73
+ this.renderer = <div>
74
+ <div>
75
+ Unsubscribing....
76
+ </div>
77
+ </div>;
78
+ const mce = this.parameters;
79
+ // download headers...
80
+ const headers = await FetchBuilder.get(`/api/emails/headers/${mce.emailID}/1`)
81
+ .responseAsText();
82
+
83
+ const root = new MimeNode();
84
+ await root.parse(new StringLineStream(headers));
85
+ let unsubscribe = (root.header("List-Unsubscribe") as string)
86
+ .split(",")
87
+ .find((x) => /\<http/i.test(x));
88
+ if (unsubscribe.startsWith("<")) {
89
+ unsubscribe = unsubscribe.substring(1);
90
+ }
91
+ if (unsubscribe.endsWith(">")) {
92
+ unsubscribe = unsubscribe.substring(0, unsubscribe.length - 1);
93
+ }
94
+
95
+ const unsubscribePost = root.header("List-Unsubscribe-Post");
96
+ if (unsubscribePost) {
97
+ await FetchBuilder.post(unsubscribe).responseAsText();
98
+ } else {
99
+ await FetchBuilder.get(unsubscribe).responseAsText();
100
+ }
101
+ this.renderer = <div>
102
+ <div>
103
+ Unsubscribed Successfully.
104
+ </div>
105
+ </div>;
106
+ }
107
+
108
+ }