-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbackground.js
99 lines (88 loc) · 3.08 KB
/
background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
function base64ToText(base64String) {
const binaryString = atob(base64String);
const codePoints = Array(binaryString.length);
for (let index = 0; index < binaryString.length; index++)
codePoints[index] = binaryString.codePointAt(index);
const uint8CodePoints = Uint8Array.from(codePoints);
return new TextDecoder().decode(uint8CodePoints);
}
async function getBase64invite(message_id) {
let raw = await browser.messages.getRaw(message_id);
raw = raw.replace(/\r/g, "");
let matches = raw.match(/(?=Content-Type: text\/calendar;)(?:[\s\S]*?\n\n)(?<base64>[\s\S]*?)\n\n/);
if (matches === null) {
return false;
}
return matches['groups'].base64;
}
async function isDarkmode() {
let theme = await browser.theme.getCurrent();
return theme.colors?.icons == '#fbfbfe' || theme.colors?.icons == 'rgb(249, 249, 250, 0.7)';
}
async function updateIcon() {
if (await isDarkmode()) {
browser.messageDisplayAction.setIcon({path: 'images/calendar_white.png'});
} else {
browser.messageDisplayAction.setIcon({path: 'images/calendar_black.png'});
}
}
function replaceLocationByUrl(ics) {
// Replace default location by url
// Another option could be to use X-MICROSOFT-SKYPETEAMSMEETINGURL
// But it is not used by every system
const conference_url = ics.match(/<(https:\/\/teams\.microsoft\.com.*?)>/s);
if (conference_url !== null) {
return ics.replace(/LOCATION.*/, `LOCATION:${conference_url[1].replace(/\s+/g, '')}`);
}
return ics;
}
browser.messageDisplay.onMessageDisplayed.addListener(async (tab, message) => {
if (await getBase64invite(message.id) === false) {
browser.messageDisplayAction.disable(tab.id);
} else {
updateIcon();
browser.messageDisplayAction.enable(tab.id);
}
});
let downloading = null;
let url = null;
browser.messageDisplayAction.onClicked.addListener(async (tab) => {
const message = await browser.messageDisplay.getDisplayedMessage(tab.id);
let base64invite = await getBase64invite(message.id);
if (base64invite === false) {
browser.notifications.create(
"no-appointment",
{
type: "basic",
message: "No appointment was found.",
title: "Outlook/Teams Appointments"
}
);
setTimeout(() => {
browser.notifications.clear("no-appointment");
}, 5000);
return;
}
let ics = base64ToText(base64invite);
// Remove everything that is not beween "BEGIN:VCALENDAR" and "END:VCALENDAR"
const ics_matched = ics.match(/(?:[\s\S]*?)(?<VCALENDAR>BEGIN:VCALENDAR(?:[\s\S]*?)END:VCALENDAR)/);
if (ics_matched !== null) {
ics = ics_matched['groups'].VCALENDAR;
}
ics = replaceLocationByUrl(ics);
const blob = new Blob([ics]);
url = URL.createObjectURL(blob);
const escapedSubject = message.subject.replaceAll(/[/\\:*?"<>|]/g, " ")
downloading = await browser.downloads.download(
{
"filename": `${escapedSubject}.ics`,
"saveAs": true,
"url": url
}
);
});
browser.downloads.onChanged.addListener((downloadDelta) => {
if (downloadDelta.id === downloading && downloadDelta.state.current === "complete") {
URL.revokeObjectURL(url);
}
});