imapflow 1.0.72 → 1.0.76

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.
package/.eslintrc CHANGED
@@ -10,7 +10,8 @@
10
10
  "extends": ["nodemailer", "prettier"],
11
11
  "parser": "@babel/eslint-parser",
12
12
  "parserOptions": {
13
- "ecmaVersion": 2018
13
+ "ecmaVersion": 2018,
14
+ "sourceType": "script"
14
15
  },
15
16
  "plugins": ["@babel"]
16
17
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # CHANGELOG
2
2
 
3
+ - 1.0.75 - 2021-10-15
4
+
5
+ - Fixed an exception with failing IDLE (ramiroaisen #60)
6
+ - Do not use 1 and 1.MIME for single node messages, fallback to TEXT and HEADERS
7
+
3
8
  - 1.0.71 - 2021-09-28
4
9
 
5
10
  - IDLE precheck changes
@@ -86,7 +86,8 @@ module.exports = async (connection, destination, content, flags, idate) => {
86
86
  EXISTS: async untagged => {
87
87
  map.seq = Number(untagged.command);
88
88
  }
89
- }
89
+ },
90
+ comment: 'Sequence not found from APPEND output'
90
91
  });
91
92
  response.next();
92
93
  } catch (err) {
@@ -13,61 +13,99 @@ module.exports = async connection => {
13
13
  let response;
14
14
 
15
15
  let preCheckWaitQueue = [];
16
-
17
16
  try {
18
17
  connection.idling = true;
19
18
 
20
- let preCheckProcessing = false;
19
+ //let idleSent = false;
20
+ let doneRequested = false;
21
+ let doneSent = false;
22
+ let canEnd = false;
23
+
24
+ let preCheck = () => {
25
+ doneRequested = true;
26
+ if (canEnd && !doneSent) {
27
+ connection.log.debug({
28
+ src: 'c',
29
+ msg: `DONE`,
30
+ comment: `breaking IDLE`,
31
+ lockId: connection.currentLockId,
32
+ path: connection.mailbox && connection.mailbox.path
33
+ });
34
+ connection.write('DONE');
35
+ doneSent = true;
36
+
37
+ connection.idling = false;
38
+ connection.preCheck = false; // unset itself
39
+
40
+ while (preCheckWaitQueue.length) {
41
+ let { resolve } = preCheckWaitQueue.shift();
42
+ resolve();
43
+ }
44
+ }
45
+ };
46
+
21
47
  connection.preCheck = () => {
22
- let processor = new Promise((resolve, reject) => {
48
+ let handler = new Promise((resolve, reject) => {
23
49
  preCheckWaitQueue.push({ resolve, reject });
24
50
  });
25
51
 
26
- if (!preCheckProcessing) {
27
- preCheckProcessing = true;
28
- // small delay to make sure we do not call preCheck before command is actually executed
29
- setImmediate(() => {
30
- if (connection.idling) {
31
- connection.log.debug({ src: 'c', msg: `DONE`, comment: `breaking IDLE` });
32
- connection.write('DONE');
33
- connection.idling = false;
34
- }
35
- connection.preCheck = false; // unset itself
36
- while (preCheckWaitQueue.length) {
37
- console.log('RESOLVING IDLE');
38
- let entry = preCheckWaitQueue.shift();
39
- entry.resolve();
40
- }
41
- });
42
- }
52
+ connection.log.trace({
53
+ msg: 'Requesting IDLE break',
54
+ lockId: connection.currentLockId,
55
+ path: connection.mailbox && connection.mailbox.path,
56
+ queued: preCheckWaitQueue.length,
57
+ doneRequested,
58
+ canEnd,
59
+ doneSent
60
+ });
61
+
62
+ preCheck();
43
63
 
44
- return processor;
64
+ return handler;
45
65
  };
46
66
 
47
67
  response = await connection.exec('IDLE', false, {
48
68
  onPlusTag: async () => {
49
69
  connection.log.debug({ msg: `Initiated IDLE, waiting for server input` });
70
+ canEnd = true;
71
+ if (doneRequested) {
72
+ preCheck();
73
+ }
74
+ },
75
+ onSend: () => {
76
+ //idleSent = true;
50
77
  }
51
78
  });
52
79
 
53
80
  // unset before response.next()
54
- connection.preCheck = false;
55
- while (preCheckWaitQueue.length) {
56
- let entry = preCheckWaitQueue.shift();
57
- let err = new Error('Already processed');
58
- entry.reject(err);
81
+ if (typeof connection.preCheck === 'function') {
82
+ connection.log.trace({
83
+ msg: 'Clearing pre-check function',
84
+ lockId: connection.currentLockId,
85
+ path: connection.mailbox && connection.mailbox.path,
86
+ queued: preCheckWaitQueue.length,
87
+ doneRequested,
88
+ canEnd,
89
+ doneSent
90
+ });
91
+ connection.preCheck = false;
92
+ while (preCheckWaitQueue.length) {
93
+ let { resolve } = preCheckWaitQueue.shift();
94
+ resolve();
95
+ }
59
96
  }
60
97
 
61
98
  response.next();
62
99
  return;
63
100
  } catch (err) {
64
101
  connection.preCheck = false;
65
- while (preCheckWaitQueue.length) {
66
- let entry = preCheckWaitQueue.shift();
67
- entry.reject(err);
68
- }
102
+ connection.idling = false;
69
103
 
70
104
  connection.log.warn({ err, cid: connection.id });
105
+ while (preCheckWaitQueue.length) {
106
+ let { reject } = preCheckWaitQueue.shift();
107
+ reject(err);
108
+ }
71
109
  return false;
72
110
  }
73
111
  }
@@ -85,7 +123,7 @@ module.exports = async connection => {
85
123
  };
86
124
 
87
125
  let idleCheck = async () => {
88
- let response = await connection.exec('NOOP');
126
+ let response = await connection.exec('NOOP', false, { comment: 'IDLE not supported' });
89
127
  response.next();
90
128
  };
91
129
 
@@ -3,7 +3,7 @@
3
3
  // Sends a NO-OP command
4
4
  module.exports = async connection => {
5
5
  try {
6
- let response = await connection.exec('NOOP');
6
+ let response = await connection.exec('NOOP', false, { comment: 'Requested by command' });
7
7
  response.next();
8
8
  return true;
9
9
  } catch (err) {
package/lib/imap-flow.js CHANGED
@@ -331,8 +331,14 @@ class ImapFlow extends EventEmitter {
331
331
  isLogging: true
332
332
  });
333
333
 
334
- this.log.debug({ src: 's', msg: logCompiled.toString(), cid: this.id });
334
+ let options = data.options || {};
335
+
336
+ this.log.debug({ src: 's', msg: logCompiled.toString(), cid: this.id, comment: options.comment });
335
337
  this.write(Buffer.from(this.commandParts.shift()));
338
+
339
+ if (typeof options.onSend === 'function') {
340
+ options.onSend();
341
+ }
336
342
  }
337
343
 
338
344
  async trySend() {
@@ -344,7 +350,8 @@ class ImapFlow extends EventEmitter {
344
350
  await this.send({
345
351
  tag: this.currentRequest.tag,
346
352
  command: this.currentRequest.command,
347
- attributes: this.currentRequest.attributes
353
+ attributes: this.currentRequest.attributes,
354
+ options: this.currentRequest.options
348
355
  });
349
356
  }
350
357
 
@@ -1024,7 +1031,7 @@ class ImapFlow extends EventEmitter {
1024
1031
  * await client.connect();
1025
1032
  */
1026
1033
  async connect() {
1027
- let connector = this.options.secure ? tls : net;
1034
+ let connector = this.secureConnection ? tls : net;
1028
1035
 
1029
1036
  let opts = Object.assign(
1030
1037
  {
@@ -2018,7 +2025,13 @@ class ImapFlow extends EventEmitter {
2018
2025
  return {};
2019
2026
  }
2020
2027
 
2021
- options = options || {};
2028
+ options = Object.assign(
2029
+ {
2030
+ chunkSize: 64 * 1024,
2031
+ maxBytes: Infinity
2032
+ },
2033
+ options || {}
2034
+ );
2022
2035
 
2023
2036
  let hasMore = true;
2024
2037
  let processed = 0;
@@ -2028,6 +2041,28 @@ class ImapFlow extends EventEmitter {
2028
2041
 
2029
2042
  let uid = false;
2030
2043
 
2044
+ if (part === '1') {
2045
+ // First part has special conditions for single node emails as
2046
+ // the mime parts for root node are not 1 and 1.MIME but TEXT and HEADERS
2047
+ let response = await this.fetchOne(range, { uid: true, bodyStructure: true }, options);
2048
+
2049
+ if (!response) {
2050
+ return { response: false, chunk: false };
2051
+ }
2052
+
2053
+ if (!uid && response.uid) {
2054
+ uid = response.uid;
2055
+ // force UID from now on even if first range was a sequence number
2056
+ range = uid;
2057
+ options.uid = true;
2058
+ }
2059
+
2060
+ if (!response.bodyStructure.childNodes) {
2061
+ // single text message
2062
+ part = 'TEXT';
2063
+ }
2064
+ }
2065
+
2031
2066
  let getNextPart = async query => {
2032
2067
  query = query || {};
2033
2068
 
@@ -2045,10 +2080,15 @@ class ImapFlow extends EventEmitter {
2045
2080
  query.bodyParts = [];
2046
2081
  }
2047
2082
 
2048
- if (query.size && /^[\d.]+$/.test(part)) {
2049
- // fetch meta as well
2050
- mimeKey = part + '.mime';
2051
- query.bodyParts.push(mimeKey);
2083
+ if (query.size) {
2084
+ if (/^[\d.]+$/.test(part)) {
2085
+ // fetch meta as well
2086
+ mimeKey = part + '.mime';
2087
+ query.bodyParts.push(mimeKey);
2088
+ } else if (part === 'text') {
2089
+ mimeKey = 'header';
2090
+ query.bodyParts.push(mimeKey);
2091
+ }
2052
2092
  }
2053
2093
 
2054
2094
  query.bodyParts.push({
@@ -2085,15 +2125,10 @@ class ImapFlow extends EventEmitter {
2085
2125
  }
2086
2126
 
2087
2127
  if (query.bodyParts) {
2088
- result.mime = response.bodyParts.get(mimeKey);
2089
-
2090
- if (part === '1' && !result.mime) {
2091
- // Outlook does not support requesting 1.MIME for text/* messages, so we issue an additional command
2092
- let mimeResponse = await this.fetchOne(range, { bodyParts: ['header'] }, options);
2093
- if (!mimeResponse) {
2094
- return { response: false, chunk: false };
2095
- }
2096
- result.mime = mimeResponse.headers;
2128
+ if (mimeKey === 'header') {
2129
+ result.mime = response.headers;
2130
+ } else {
2131
+ result.mime = response.bodyParts.get(mimeKey);
2097
2132
  }
2098
2133
  }
2099
2134
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imapflow",
3
- "version": "1.0.72",
3
+ "version": "1.0.76",
4
4
  "description": "IMAP Client for Node",
5
5
  "main": "./lib/imap-flow.js",
6
6
  "scripts": {
@@ -26,19 +26,19 @@
26
26
  },
27
27
  "homepage": "https://imapflow.com/",
28
28
  "devDependencies": {
29
- "@babel/eslint-parser": "^7.15.7",
30
- "@babel/eslint-plugin": "^7.14.5",
31
- "@babel/plugin-syntax-class-properties": "^7.12.13",
32
- "@babel/preset-env": "^7.15.6",
33
- "@types/node": "16.10.1",
29
+ "@babel/eslint-parser": "7.15.8",
30
+ "@babel/eslint-plugin": "7.14.5",
31
+ "@babel/plugin-syntax-class-properties": "7.12.13",
32
+ "@babel/preset-env": "7.15.8",
33
+ "@types/node": "16.11.1",
34
34
  "braintree-jsdoc-template": "3.3.0",
35
- "eslint": "7.32.0",
35
+ "eslint": "8.0.1",
36
36
  "eslint-config-nodemailer": "1.2.0",
37
37
  "eslint-config-prettier": "8.3.0",
38
38
  "grunt": "1.4.1",
39
39
  "grunt-cli": "1.4.3",
40
- "grunt-contrib-nodeunit": "3.0.0",
41
- "grunt-eslint": "23.0.0",
40
+ "grunt-contrib-nodeunit": "4.0.0",
41
+ "grunt-eslint": "24.0.0",
42
42
  "jsdoc": "3.6.7",
43
43
  "tsd-jsdoc": "2.5.0"
44
44
  },
@@ -48,7 +48,7 @@
48
48
  "libbase64": "1.2.1",
49
49
  "libmime": "5.0.0",
50
50
  "libqp": "1.1.0",
51
- "mailsplit": "5.2.0",
52
- "pino": "6.13.3"
51
+ "mailsplit": "5.3.1",
52
+ "pino": "7.0.2"
53
53
  }
54
54
  }