iobroker.imap 0.0.4

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.
@@ -0,0 +1,424 @@
1
+ "use strict";
2
+
3
+ const Imap = require("node-imap");
4
+ const EventEmitter = require("events").EventEmitter;
5
+ const simpleParser = require("mailparser").simpleParser;
6
+
7
+ class MailListener extends EventEmitter {
8
+ constructor(options, debug) {
9
+ super();
10
+ this.xoauth2 = null;
11
+ if (options.token) {
12
+ const _build_XOAuth2_token = (user = "", access_token = "") =>
13
+ Buffer.from([`user=${user}`, `auth=Bearer ${access_token}`, "", ""].join("\x01"), "utf-8").toString(
14
+ "base64",
15
+ );
16
+ this.xoauth2 = _build_XOAuth2_token(options.username, options.token);
17
+ }
18
+ try {
19
+ this.flag = JSON.parse(options.flag);
20
+ } catch (e) {
21
+ this.flag = ["ALL"];
22
+ }
23
+ this.seen = { markSeen: false };
24
+ this.mailbox = options.inbox || "INBOX";
25
+ this.dir = `${__dirname}/lib/attachment`;
26
+ this.client = options.user;
27
+ this.max = options.maxi_html > options.maxi ? options.maxi_html : options.maxi;
28
+ let tlsoption = {};
29
+ try {
30
+ if (typeof options.tlsoption === "object") {
31
+ tlsoption = JSON.parse(JSON.stringify(options.tlsoption));
32
+ } else {
33
+ tlsoption = JSON.parse(options.tlsoption);
34
+ }
35
+ } catch (e) {
36
+ this.emit("log", "debug", "TLSOPTION", e, this.client);
37
+ }
38
+ this.all_seqno = [];
39
+ this.folder = [];
40
+ this.imap = new Imap({
41
+ xoauth2: this.xoauth2,
42
+ xoauth: null,
43
+ user: options.username,
44
+ password: options.password,
45
+ host: options.host,
46
+ port: options.port,
47
+ tls: options.tls,
48
+ autotls: options.autotls,
49
+ tlsOptions: tlsoption,
50
+ connTimeout: 10000,
51
+ authTimeout: 5000,
52
+ debug: debug,
53
+ socketTimeout: 0,
54
+ keepalive: {
55
+ interval: 10000,
56
+ idleInterval: 0,
57
+ forceNoop: true,
58
+ },
59
+ });
60
+ this.imap.once("ready", this.onReady.bind(this));
61
+ this.imap.once("close", this.onClose.bind(this));
62
+ this.imap.on("error", this.onError.bind(this));
63
+ this.imap.on("alert", this.onAlert.bind(this));
64
+ this.imap.on("update", this.onUpdate.bind(this));
65
+ this.imap.on("mail", this.onMail.bind(this));
66
+ this.imap.on("uidvalidity", this.onUidvalidity.bind(this));
67
+ this.imap.on("expunge", this.onExpunge.bind(this));
68
+ //this.imap.on("debug", this.onDebug.bind(this));
69
+ }
70
+
71
+ start() {
72
+ this.imap.connect();
73
+ }
74
+
75
+ //onDebug(type, box, state) {
76
+ // this.adapter.log.info("Debug: " + type);
77
+ // this.adapter.log.info("Debug_JSON: " + JSON.stringify(box));
78
+ // if (state) this.adapter.log.info("Debug_State: " + state);
79
+ //}
80
+
81
+ async subscribeBox(mailboxname) {
82
+ this.imap.subscribeBox(mailboxname, (error) => {
83
+ if (error) {
84
+ this.emit("error", error, this.client);
85
+ } else {
86
+ this.emit("log", "debug", "Subscribe", mailboxname, this.client);
87
+ }
88
+ });
89
+ }
90
+
91
+ setFolder() {
92
+ this.imap.getBoxes((error, boxes) => {
93
+ if (error) {
94
+ this.emit("error", error, this.client);
95
+ } else {
96
+ for (const key in boxes) {
97
+ if (key != "[Gmail]" && key != "[Google Mail]") {
98
+ this.folder.push(key);
99
+ }
100
+ if (boxes[key].children) {
101
+ for (const keys in boxes[key].children) {
102
+ const foldername = `${key}${boxes[key].delimiter}${keys}`;
103
+ this.folder.push(foldername);
104
+ this.subscribeBox(foldername);
105
+ }
106
+ }
107
+ }
108
+ this.emit("sub", this.folder, this.client);
109
+ }
110
+ });
111
+ }
112
+
113
+ getFolder() {
114
+ return this.folder;
115
+ }
116
+
117
+ async custom_search(obj) {
118
+ let read_mail = null;
119
+ if (obj.message.fetch.fetch) {
120
+ if (obj.message.fetch.seqno != null) {
121
+ read_mail = obj.message.fetch.seqno;
122
+ this.startReadMails(read_mail, obj, read_mail.length);
123
+ } else if (obj.message.fetch.single != null) {
124
+ read_mail = obj.message.fetch.single;
125
+ this.startReadMails(read_mail, obj, read_mail.split(":")[1]);
126
+ } else {
127
+ this.emit("error", "Missing fetch", this.client);
128
+ return;
129
+ }
130
+ } else {
131
+ let flag;
132
+ try {
133
+ if (typeof obj.message.search === "object") {
134
+ flag = JSON.parse(JSON.stringify(obj.message.search));
135
+ } else {
136
+ flag = JSON.parse(obj.message.search);
137
+ }
138
+ } catch (e) {
139
+ this.emit("error", e, this.client);
140
+ this.emit("sendToError", obj, "Error parse", this.client);
141
+ return;
142
+ }
143
+ await this.imap.search(flag, (error, results) => {
144
+ if (error) {
145
+ this.emit("error", error, this.client);
146
+ this.emit("sendToError", obj, "Error search", this.client);
147
+ } else if (results.length > 0) {
148
+ const new_arr = [];
149
+ results.sort((a, b) => a - b);
150
+ results.reverse();
151
+ if (obj.message.max > 0 && results.length > obj.message.max) {
152
+ for (let i = 0; i < obj.message.max; i++) {
153
+ new_arr.push(results[i]);
154
+ }
155
+ read_mail = new_arr;
156
+ } else {
157
+ read_mail = results;
158
+ }
159
+ this.startReadMails(read_mail, obj, read_mail.length);
160
+ } else {
161
+ this.emit("sendToError", obj, "Mailbox is empty", this.client);
162
+ }
163
+ });
164
+ }
165
+ }
166
+
167
+ async startReadMails(read_mail, obj, count) {
168
+ if (read_mail != null) {
169
+ const result = await this.readAllMails(read_mail, obj, count);
170
+ this.emit("sendTo", obj, result, this.client);
171
+ } else {
172
+ this.emit("sendToError", obj, "Cannot found Mails", this.client);
173
+ }
174
+ }
175
+
176
+ stop() {
177
+ this.imap.end();
178
+ }
179
+
180
+ imap_state() {
181
+ return this.imap.state;
182
+ }
183
+
184
+ imap_delimiter() {
185
+ return this.imap.delimiter;
186
+ }
187
+
188
+ imap_namespaces() {
189
+ return this.imap.namespaces;
190
+ }
191
+
192
+ onNewRead() {
193
+ this.readMails.call(this);
194
+ }
195
+
196
+ onReady(folder) {
197
+ if (folder && folder != "") {
198
+ if (folder == this.mailbox) return;
199
+ this.mailbox = folder;
200
+ this.getStatus(folder);
201
+ this.imap.openBox(folder, false, (error, mailbox) => {
202
+ if (error) {
203
+ this.emit("error", error, this.client);
204
+ } else {
205
+ this.emit("mailbox", mailbox, this.client);
206
+ this.readMails.call(this);
207
+ }
208
+ });
209
+ } else {
210
+ this.getStatus(this.mailbox);
211
+ this.imap.openBox(this.mailbox, false, (error, mailbox) => {
212
+ if (error) {
213
+ this.emit("error", error, this.client);
214
+ } else {
215
+ this.emit("connected", this.client);
216
+ this.emit("mailbox", mailbox, this.client);
217
+ this.readMails.call(this);
218
+ this.setFolder();
219
+ }
220
+ });
221
+ }
222
+ }
223
+
224
+ getStatus(folder) {
225
+ this.imap.status(folder, (err, mailbox) => {
226
+ if (err) {
227
+ this.emit("error", err, this.client);
228
+ } else {
229
+ this.emit("status", mailbox, this.client);
230
+ }
231
+ });
232
+ }
233
+
234
+ onExpunge(seqno) {
235
+ this.emit("expunge", seqno, this.client);
236
+ }
237
+
238
+ onUidvalidity(uidvalidity) {
239
+ this.emit("uidvalidity", uidvalidity, this.client);
240
+ }
241
+
242
+ onAlert(message) {
243
+ this.emit("alert", message, this.client);
244
+ }
245
+
246
+ onUpdate(seqno, info) {
247
+ const isRange = this.all_seqno.findIndex((number) => number == seqno);
248
+ if (isRange != -1 && (isRange < this.max || isRange == this.max)) {
249
+ this.emit("update", "Start Update", seqno, info, this.client);
250
+ this.readMails.call(this);
251
+ } else {
252
+ this.emit("update", "No Update", seqno, info, this.client);
253
+ }
254
+ }
255
+
256
+ onMail(seqno) {
257
+ this.emit("mailevent", seqno, this.client);
258
+ this.readMails.call(this);
259
+ }
260
+
261
+ onClose(hadError) {
262
+ this.emit("disconnected", hadError, this.client);
263
+ }
264
+
265
+ onError(err) {
266
+ if (err) {
267
+ this.emit("error", err, this.client);
268
+ }
269
+ }
270
+
271
+ readMails() {
272
+ this.imap.search(this.flag, async (error, results) => {
273
+ if (error) {
274
+ this.emit("error", error, this.client);
275
+ } else if (results.length > 0) {
276
+ const all = results.length;
277
+ let count = 1;
278
+ this.emit("seqno", results, this.client);
279
+ this.all_seqno = [];
280
+ results.sort((a, b) => a - b);
281
+ results.reverse();
282
+ for (const result of results) {
283
+ if (count > this.max) break;
284
+ this.all_seqno.push(result);
285
+ await this.findmail(result, count, all);
286
+ ++count;
287
+ }
288
+ } else {
289
+ this.emit("info", "Mailbox is empty", this.client);
290
+ }
291
+ });
292
+ }
293
+
294
+ async findmail(result, counter, all) {
295
+ return new Promise((resolve) => {
296
+ try {
297
+ const f = this.imap.fetch(result, {
298
+ bodies: "",
299
+ ...this.seen,
300
+ });
301
+ f.on("message", (msg, seqno) => {
302
+ let attrs;
303
+ msg.on("attributes", (att) => {
304
+ attrs = att;
305
+ });
306
+ msg.on("body", async (stream, info) => {
307
+ const mail = await simpleParser(stream);
308
+ //if (mail.attachments.length > 0) {
309
+ // delete mail.attachments;
310
+ //}
311
+ this.emit("mail", mail, seqno, attrs, info, this.client, counter, all);
312
+ resolve(true);
313
+ });
314
+ });
315
+ f.once("error", (error) => {
316
+ if (error) {
317
+ this.emit("error", error, this.client);
318
+ }
319
+ resolve(false);
320
+ });
321
+ } catch (error) {
322
+ this.emit("error", error, this.client);
323
+ resolve(false);
324
+ }
325
+ });
326
+ }
327
+
328
+ readAllMails(result, obj, count) {
329
+ const all_mails = [];
330
+ const mails = {};
331
+ let counter = 0;
332
+ return new Promise((resolve) => {
333
+ try {
334
+ const f = this.imap.fetch(result, {
335
+ bodies: "",
336
+ ...obj.message.bodie,
337
+ });
338
+ f.on("message", (msg, seqno) => {
339
+ let attrs;
340
+ msg.on("attributes", (att) => {
341
+ attrs = att;
342
+ });
343
+ msg.on("body", async (stream, info) => {
344
+ if (obj.message.parse) {
345
+ mails["body"] = await simpleParser(stream);
346
+ } else {
347
+ mails["body"] = stream;
348
+ }
349
+ mails["seqno"] = seqno;
350
+ mails["attrs"] = attrs;
351
+ mails["info"] = info;
352
+ mails["user"] = this.client;
353
+ ++counter;
354
+ all_mails.push(mails);
355
+ if (count == counter) {
356
+ resolve(all_mails);
357
+ }
358
+ });
359
+ });
360
+ f.once("error", (error) => {
361
+ if (error) {
362
+ this.emit("error", error, this.client);
363
+ }
364
+ resolve(false);
365
+ });
366
+ } catch (error) {
367
+ this.emit("error", error, this.client);
368
+ resolve(false);
369
+ }
370
+ });
371
+ }
372
+
373
+ set_move(seqno, box) {
374
+ this.imap.move(seqno, box, (err) => {
375
+ if (!err) {
376
+ this.emit("log", "info", "SetFlag", `${seqno}: move success`, this.client);
377
+ } else {
378
+ this.emit("error", err, this.client);
379
+ }
380
+ });
381
+ }
382
+
383
+ set_copy(seqno, box) {
384
+ this.imap.copy(seqno, box, (err) => {
385
+ if (!err) {
386
+ this.emit("log", "info", "SetFlag", `${seqno}: copy success`, this.client);
387
+ } else {
388
+ this.emit("error", err, this.client);
389
+ }
390
+ });
391
+ }
392
+
393
+ set_addFlags(seqno, flag) {
394
+ this.imap.addFlags(seqno, flag, (err) => {
395
+ if (!err) {
396
+ this.emit("log", "info", "SetFlag", `${seqno}: addFlags success`, this.client);
397
+ } else {
398
+ this.emit("error", err, this.client);
399
+ }
400
+ });
401
+ }
402
+
403
+ set_delFlags(seqno, flag) {
404
+ this.imap.delFlags(seqno, flag, (err) => {
405
+ if (!err) {
406
+ this.emit("log", "info", "SetFlag", `${seqno}: delFlags success`, this.client);
407
+ } else {
408
+ this.emit("error", err, this.client);
409
+ }
410
+ });
411
+ }
412
+
413
+ set_setFlags(seqno, flag) {
414
+ this.imap.setFlags(seqno, flag, (err) => {
415
+ if (!err) {
416
+ this.emit("log", "info", "SetFlag", `${seqno}: setFlags success`, this.client);
417
+ } else {
418
+ this.emit("error", err, this.client);
419
+ }
420
+ });
421
+ }
422
+ }
423
+
424
+ module.exports.MailListener = MailListener;