-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.js
More file actions
143 lines (118 loc) · 3.59 KB
/
Copy pathindex.js
File metadata and controls
143 lines (118 loc) · 3.59 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
const fs = require('fs')
const path = require('path')
const eol = require('eol')
const MsgReader = require('@kenjiuno/msgreader').default
const lang = 'de' // Available options: de, en
const i18n = {
de: {
sender: 'Absender',
receiver: 'Empfänger',
date: 'Datum',
subject: 'Betreff',
message: 'nachricht',
timeZone: 'Europe/Berlin',
},
en: {
sender: 'Sender',
receiver: 'Receiver',
date: 'Date',
subject: 'Subject',
message: 'message',
timeZone: 'UTC',
},
}
function getNumericOffset (zone, now) {
const tzNum = Intl
.DateTimeFormat('en-US', {
timeZone: zone,
timeZoneName: 'short',
})
.format(now)
.split(', ')[1]
.replace('GMT', '')
const timeZoneIsNumeric = /^[0-9:+-]*$/.test(tzNum)
const offset =
(!timeZoneIsNumeric || tzNum.length === 3)
? tzNum
: tzNum.length === 0
? '+00'
: (tzNum.length === 2 || tzNum.length === 5)
? tzNum.replace('+', '+0').replace('-', '-0')
: tzNum.padStart(5, '0')
return offset
.replace('UTC', '+00')
}
// Remove characters that are invalid or problematic in file names.
// Trailing whitespace (and trailing dots) make a name unusable on Windows,
// so they are stripped. See https://github.com/feramhq/msg2txt/issues/2
function sanitizeFilename (name) {
return String(name == null ? '' : name)
.replace(/[/\\]/g, '_') // path separators would escape the target directory
.replace(/[\s.]+$/, '') // trailing whitespace and dots are invalid on Windows
.trim()
|| 'attachment'
}
function main (filename) {
if (!filename.endsWith('.msg')) {
throw new Error('Only .msg files can be converted!')
}
const msgFileBuffer = fs.readFileSync(path.resolve(filename))
const testMsg = new MsgReader(msgFileBuffer)
const testMsgInfo = testMsg.getFileData()
const headers = Object.fromEntries(
(testMsgInfo.headers || '')
.split('\r\n')
.filter(line => line.includes(': '))
.map(line => line.split(': '))
)
const opts = {
timeZone: i18n[lang].timeZone,
hour12: false,
}
const dateFormatted = headers.Date
? (() => {
const date = new Date(Date.parse(headers.Date))
return date.toLocaleDateString('en-CA', opts)
+ ' ' +
date.toLocaleTimeString(lang, opts)
+ ' ' +
getNumericOffset(i18n[lang].timeZone, date)
})()
: ''
let message =
i18n[lang].sender + ': ' + headers.From + '\n' +
i18n[lang].receiver + ': ' + headers.To + '\n' +
i18n[lang].date + ': ' + dateFormatted + '\n' +
i18n[lang].subject + ': ' + testMsgInfo.subject + '\n' +
'\n'
message += testMsgInfo.body + '\n'
message = eol.auto(message)
const directory = path.join(
path.dirname(filename),
path.basename(filename, '.msg')
)
fs.mkdirSync(directory)
fs.writeFileSync(
path.join(directory, `${i18n[lang].message}.txt`),
message,
{encoding: 'utf-8'}
)
;(testMsgInfo.attachments || []).forEach(attachment => {
// Attachments without a `dataId` carry no extractable byte stream
// (e.g. embedded .msg messages, which msgreader does not support).
// Skipping them avoids a crash in `getAttachment`.
if (attachment.dataId == null) {
console.warn(
`Skipping attachment "${attachment.fileName || ''}": ` +
'no extractable content (e.g. an embedded message).'
)
return
}
const attachmentObj = testMsg.getAttachment(attachment)
fs.writeFileSync(
path.join(directory, sanitizeFilename(attachmentObj.fileName)),
attachmentObj.content
)
})
}
module.exports = main