imapflow 1.0.90 → 1.0.93

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/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ *.js text eol=lf
@@ -0,0 +1,21 @@
1
+ name: Run tests
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ strategy:
10
+ matrix:
11
+ node: [16.x, 18.x]
12
+ os: [ubuntu-latest]
13
+ runs-on: ${{ matrix.os }}
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: Use Node.js ${{ matrix.node }}
17
+ uses: actions/setup-node@v1
18
+ with:
19
+ node-version: ${{ matrix.node }}
20
+ - run: npm install
21
+ - run: npm test
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # CHANGELOG
2
2
 
3
+ - 1.0.93 - 2022-05-03
4
+
5
+ - Fixed missing unicode encoding for APPEND, COPY, MOVE
6
+
7
+ - 1.0.92 - 2022-05-03
8
+
9
+ - Added support for IMAP BINARY extension (rfc3516)
10
+ - Logging improvements
11
+
12
+ - 1.0.91 - 2022-05-02
13
+
14
+ - Do not throw if literal includes a null byte
15
+ - Use UTF8 path names by default
16
+ - Overrides '\*' range query with the EXISTS value
17
+
3
18
  - 1.0.90 - 2022-04-04
4
19
 
5
20
  - Added new configuration option `maxIdleTime`
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { getStatusCode, formatFlag, canUseFlag, formatDateTime, normalizePath, comparePaths, getErrorText } = require('../tools.js');
3
+ const { getStatusCode, formatFlag, canUseFlag, formatDateTime, normalizePath, encodePath, comparePaths, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Appends a message to a mailbox
6
6
  module.exports = async (connection, destination, content, flags, idate) => {
@@ -26,7 +26,7 @@ module.exports = async (connection, destination, content, flags, idate) => {
26
26
  .map(flag => flag && formatFlag(flag.toString()))
27
27
  .filter(flag => flag && canUseFlag(connection.mailbox, flag));
28
28
 
29
- let attributes = [{ type: 'ATOM', value: destination }];
29
+ let attributes = [{ type: 'ATOM', value: encodePath(connection, destination) }];
30
30
 
31
31
  idate = idate ? formatDateTime(idate) : false;
32
32
 
@@ -38,7 +38,17 @@ module.exports = async (connection, destination, content, flags, idate) => {
38
38
  attributes.push({ type: 'STRING', value: idate }); // force quotes as required by date-time
39
39
  }
40
40
 
41
- attributes.push({ type: 'LITERAL', value: content });
41
+ let isLiteral8 = false;
42
+ if (connection.capabilities.has('BINARY') && !connection.disableBinary) {
43
+ if (typeof content === 'string') {
44
+ content = Buffer.from(content);
45
+ }
46
+ // Value is literal8 if it contains NULL bytes. The server must support the BINARY extension
47
+ // and if it does not then send the value as a regular literal and hope for the best
48
+ isLiteral8 = content.indexOf(Buffer.from([0])) >= 0;
49
+ }
50
+
51
+ attributes.push({ type: 'LITERAL', value: content, isLiteral8 });
42
52
 
43
53
  let map = { destination };
44
54
  if (connection.mailbox && connection.mailbox.path) {
@@ -39,7 +39,7 @@ module.exports = async (connection, username, accessToken) => {
39
39
  try {
40
40
  errorResponse = JSON.parse(Buffer.from(resp.attributes[0].value, 'base64').toString());
41
41
  } catch (err) {
42
- connection.log.debug({ data: resp.attributes[0].value, err });
42
+ connection.log.debug({ errorResponse: resp.attributes[0].value, err });
43
43
  }
44
44
  }
45
45
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { getStatusCode, normalizePath, expandRange, getErrorText } = require('../tools.js');
3
+ const { getStatusCode, normalizePath, encodePath, expandRange, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Copies messages from current mailbox to some other mailbox
6
6
  module.exports = async (connection, range, destination, options) => {
@@ -14,7 +14,7 @@ module.exports = async (connection, range, destination, options) => {
14
14
 
15
15
  let attributes = [
16
16
  { type: 'SEQUENCE', value: range },
17
- { type: 'ATOM', value: destination }
17
+ { type: 'ATOM', value: encodePath(connection, destination) }
18
18
  ];
19
19
 
20
20
  let response;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath, getStatusCode, getErrorText } = require('../tools.js');
3
+ const { encodePath, normalizePath, getStatusCode, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Creates a new mailbox
6
6
  module.exports = async (connection, path) => {
@@ -16,7 +16,7 @@ module.exports = async (connection, path) => {
16
16
  let map = {
17
17
  path
18
18
  };
19
- response = await connection.exec('CREATE', [{ type: 'ATOM', value: path }]);
19
+ response = await connection.exec('CREATE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
20
20
 
21
21
  let section =
22
22
  response.response.attributes &&
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath, getStatusCode, getErrorText } = require('../tools.js');
3
+ const { encodePath, normalizePath, getStatusCode, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Deletes an existing mailbox
6
6
  module.exports = async (connection, path) => {
@@ -20,7 +20,7 @@ module.exports = async (connection, path) => {
20
20
  let map = {
21
21
  path
22
22
  };
23
- response = await connection.exec('DELETE', [{ type: 'ATOM', value: path }]);
23
+ response = await connection.exec('DELETE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
24
24
  response.next();
25
25
  return map;
26
26
  } catch (err) {
@@ -18,6 +18,8 @@ module.exports = async (connection, range, query, options) => {
18
18
  list: []
19
19
  };
20
20
 
21
+ const commandKey = connection.capabilities.has('BINARY') && !connection.disableBinary ? 'BINARY' : 'BODY';
22
+
21
23
  let response;
22
24
  try {
23
25
  let attributes = [{ type: 'SEQUENCE', value: (range || '*').toString() }];
@@ -27,7 +29,7 @@ module.exports = async (connection, range, query, options) => {
27
29
  let setBodyPeek = (attributes, partial) => {
28
30
  let bodyPeek = {
29
31
  type: 'ATOM',
30
- value: 'BODY.PEEK',
32
+ value: `${commandKey}.PEEK`,
31
33
  section: [],
32
34
  partial
33
35
  };
@@ -61,7 +63,7 @@ module.exports = async (connection, range, query, options) => {
61
63
  partial.push(Number(query.source.maxLength));
62
64
  }
63
65
  }
64
- queryStructure.push({ type: 'ATOM', value: 'BODY.PEEK', section: [], partial });
66
+ queryStructure.push({ type: 'ATOM', value: `${commandKey}.PEEK`, section: [], partial });
65
67
  }
66
68
 
67
69
  // if possible, always request for unique email id
@@ -1,8 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath } = require('../tools.js');
3
+ const { decodePath, encodePath, normalizePath } = require('../tools.js');
4
4
  const { specialUse } = require('../special-use');
5
- const iconv = require('iconv-lite');
6
5
 
7
6
  // Lists mailboxes from server
8
7
  module.exports = async (connection, reference, mailbox) => {
@@ -14,7 +13,7 @@ module.exports = async (connection, reference, mailbox) => {
14
13
  let entries = [];
15
14
 
16
15
  let runList = async (reference, mailbox) => {
17
- response = await connection.exec(listCommand, [reference, mailbox], {
16
+ response = await connection.exec(listCommand, [encodePath(connection, reference), encodePath(connection, mailbox)], {
18
17
  untagged: {
19
18
  [listCommand]: async untagged => {
20
19
  if (!untagged.attributes || !untagged.attributes.length) {
@@ -22,7 +21,8 @@ module.exports = async (connection, reference, mailbox) => {
22
21
  }
23
22
 
24
23
  let entry = {
25
- path: (untagged.attributes[2] && untagged.attributes[2].value) || '',
24
+ path: normalizePath(connection, decodePath(connection, (untagged.attributes[2] && untagged.attributes[2].value) || '')),
25
+ pathAsListed: (untagged.attributes[2] && untagged.attributes[2].value) || '',
26
26
  flags: new Set(untagged.attributes[0].map(entry => entry.value)),
27
27
  delimiter: untagged.attributes[1] && untagged.attributes[1].value,
28
28
  listed: true
@@ -45,19 +45,8 @@ module.exports = async (connection, reference, mailbox) => {
45
45
  entry.path = entry.path.slice(1);
46
46
  }
47
47
 
48
- entry.parent = (entry.delimiter ? entry.path.split(entry.delimiter) : [entry.path]).map(folder => {
49
- if (!connection.enabled.has('UTF8=ACCEPT')) {
50
- try {
51
- return iconv.decode(Buffer.from(folder), 'utf-7-imap').toString();
52
- } catch (err) {
53
- return folder; // keep as is
54
- }
55
- } else {
56
- return folder; // keep as is
57
- }
58
- });
59
-
60
- entry.path = normalizePath(connection, entry.path);
48
+ entry.parentPath = entry.delimiter && entry.path ? entry.path.substr(0, entry.path.lastIndexOf(entry.delimiter)) : '';
49
+ entry.parent = entry.delimiter ? entry.path.split(entry.delimiter) : [entry.path];
61
50
  entry.name = entry.parent.pop();
62
51
 
63
52
  let specialUseFlag = specialUse(connection.capabilities.has('XLIST') || connection.capabilities.has('SPECIAL-USE'), entry);
@@ -80,59 +69,54 @@ module.exports = async (connection, reference, mailbox) => {
80
69
  await runList('', 'INBOX');
81
70
  }
82
71
 
83
- response = await connection.exec('LSUB', [normalizePath(connection, reference || ''), normalizePath(connection, mailbox || '', true)], {
84
- untagged: {
85
- LSUB: async untagged => {
86
- if (!untagged.attributes || !untagged.attributes.length) {
87
- return;
88
- }
89
-
90
- let entry = {
91
- flags: new Set(untagged.attributes[0].map(entry => entry.value)),
92
- delimiter: untagged.attributes[1] && untagged.attributes[1].value,
93
- path: (untagged.attributes[2] && untagged.attributes[2].value) || '',
94
- subscribed: true
95
- };
72
+ response = await connection.exec(
73
+ 'LSUB',
74
+ [encodePath(connection, normalizePath(connection, reference || '')), encodePath(connection, normalizePath(connection, mailbox || '', true))],
75
+ {
76
+ untagged: {
77
+ LSUB: async untagged => {
78
+ if (!untagged.attributes || !untagged.attributes.length) {
79
+ return;
80
+ }
96
81
 
97
- if (entry.path.toUpperCase() === 'INBOX') {
98
- entry.specialUse = '\\Inbox';
99
- }
82
+ let entry = {
83
+ path: normalizePath(connection, decodePath(connection, (untagged.attributes[2] && untagged.attributes[2].value) || '')),
84
+ pathAsListed: (untagged.attributes[2] && untagged.attributes[2].value) || '',
85
+ flags: new Set(untagged.attributes[0].map(entry => entry.value)),
86
+ delimiter: untagged.attributes[1] && untagged.attributes[1].value,
87
+ subscribed: true
88
+ };
100
89
 
101
- if (entry.delimiter && entry.path.charAt(0) === entry.delimiter) {
102
- entry.path = entry.path.slice(1);
103
- }
90
+ if (entry.path.toUpperCase() === 'INBOX') {
91
+ entry.specialUse = '\\Inbox';
92
+ }
104
93
 
105
- entry.parent = (entry.delimiter ? entry.path.split(entry.delimiter) : [entry.path]).map(folder => {
106
- if (!connection.enabled.has('UTF8=ACCEPT')) {
107
- try {
108
- return iconv.decode(Buffer.from(folder), 'utf-7-imap').toString();
109
- } catch (err) {
110
- return folder; // keep as is
111
- }
112
- } else {
113
- return folder; // keep as is
94
+ if (entry.delimiter && entry.path.charAt(0) === entry.delimiter) {
95
+ entry.path = entry.path.slice(1);
114
96
  }
115
- });
116
97
 
117
- entry.name = entry.parent.pop();
98
+ entry.parentPath = entry.delimiter && entry.path ? entry.path.substr(0, entry.path.lastIndexOf(entry.delimiter)) : '';
99
+ entry.parent = entry.delimiter ? entry.path.split(entry.delimiter) : [entry.path];
100
+ entry.name = entry.parent.pop();
118
101
 
119
- let existing = entries.find(existing => existing.path === entry.path);
120
- if (existing) {
121
- existing.subscribed = true;
122
- entry.flags.forEach(flag => existing.flags.add(flag));
123
- } else {
124
- // ignore non-listed folders
125
- /*
126
- let specialUseFlag = specialUse(connection.capabilities.has('XLIST') || connection.capabilities.has('SPECIAL-USE'), entry);
127
- if (specialUseFlag && !flagsSeen.has(specialUseFlag)) {
128
- entry.specialUse = specialUseFlag;
102
+ let existing = entries.find(existing => existing.path === entry.path);
103
+ if (existing) {
104
+ existing.subscribed = true;
105
+ entry.flags.forEach(flag => existing.flags.add(flag));
106
+ } else {
107
+ // ignore non-listed folders
108
+ /*
109
+ let specialUseFlag = specialUse(connection.capabilities.has('XLIST') || connection.capabilities.has('SPECIAL-USE'), entry);
110
+ if (specialUseFlag && !flagsSeen.has(specialUseFlag)) {
111
+ entry.specialUse = specialUseFlag;
112
+ }
113
+ entries.push(entry);
114
+ */
129
115
  }
130
- entries.push(entry);
131
- */
132
116
  }
133
117
  }
134
118
  }
135
- });
119
+ );
136
120
  response.next();
137
121
 
138
122
  let inboxEntry = entries.find(entry => entry.specialUse === '\\Inbox');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { getStatusCode, normalizePath, expandRange, getErrorText } = require('../tools.js');
3
+ const { getStatusCode, normalizePath, encodePath, expandRange, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Moves messages from current mailbox to some other mailbox
6
6
  module.exports = async (connection, range, destination, options) => {
@@ -14,7 +14,7 @@ module.exports = async (connection, range, destination, options) => {
14
14
 
15
15
  let attributes = [
16
16
  { type: 'SEQUENCE', value: range },
17
- { type: 'ATOM', value: destination }
17
+ { type: 'ATOM', value: encodePath(connection, destination) }
18
18
  ];
19
19
 
20
20
  let map = { path: connection.mailbox.path, destination };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { getStatusCode, normalizePath, getErrorText } = require('../tools.js');
3
+ const { encodePath, getStatusCode, normalizePath, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Requests quota information for a mailbox
6
6
  module.exports = async (connection, path) => {
@@ -63,7 +63,7 @@ module.exports = async (connection, path) => {
63
63
  let quotaFound = false;
64
64
  let response;
65
65
  try {
66
- response = await connection.exec('GETQUOTAROOT', [{ type: 'ATOM', value: path }], {
66
+ response = await connection.exec('GETQUOTAROOT', [{ type: 'ATOM', value: encodePath(connection, path) }], {
67
67
  untagged: {
68
68
  QUOTAROOT: async untagged => {
69
69
  let quotaRoot =
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath, getStatusCode, getErrorText } = require('../tools.js');
3
+ const { encodePath, normalizePath, getStatusCode, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Renames existing mailbox
6
6
  module.exports = async (connection, path, newPath) => {
@@ -23,8 +23,8 @@ module.exports = async (connection, path, newPath) => {
23
23
  newPath
24
24
  };
25
25
  response = await connection.exec('RENAME', [
26
- { type: 'ATOM', value: path },
27
- { type: 'ATOM', value: newPath }
26
+ { type: 'ATOM', value: encodePath(connection, path) },
27
+ { type: 'ATOM', value: encodePath(connection, newPath) }
28
28
  ]);
29
29
  response.next();
30
30
  return map;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath, getStatusCode, getErrorText } = require('../tools.js');
3
+ const { encodePath, normalizePath, getStatusCode, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Selects a mailbox
6
6
  module.exports = async (connection, path, options) => {
@@ -47,101 +47,105 @@ module.exports = async (connection, path, options) => {
47
47
  map.qresync = true;
48
48
  }
49
49
 
50
- response = await connection.exec(!options.readOnly ? 'SELECT' : 'EXAMINE', [{ type: 'ATOM', value: path }].concat(extraArgs || []), {
51
- untagged: {
52
- OK: async untagged => {
53
- if (!untagged.attributes || !untagged.attributes.length) {
54
- return;
55
- }
56
- let section = !untagged.attributes[0].value && untagged.attributes[0].section;
57
- if (section && section.length > 1 && section[0].type === 'ATOM' && typeof section[0].value === 'string') {
58
- let key = section[0].value.toLowerCase();
59
- let value;
60
-
61
- if (typeof section[1].value === 'string') {
62
- value = section[1].value;
63
- } else if (Array.isArray(section[1])) {
64
- value = section[1].map(entry => (typeof entry.value === 'string' ? entry.value : false)).filter(entry => entry);
50
+ response = await connection.exec(
51
+ !options.readOnly ? 'SELECT' : 'EXAMINE',
52
+ [{ type: 'ATOM', value: encodePath(connection, path) }].concat(extraArgs || []),
53
+ {
54
+ untagged: {
55
+ OK: async untagged => {
56
+ if (!untagged.attributes || !untagged.attributes.length) {
57
+ return;
65
58
  }
66
-
67
- switch (key) {
68
- case 'highestmodseq':
69
- key = 'highestModseq';
70
- if (/^[0-9]+$/.test(value)) {
71
- value = BigInt(value);
72
- }
73
- break;
74
-
75
- case 'mailboxid':
76
- key = 'mailboxId';
77
- if (Array.isArray(value) && value.length) {
78
- value = value[0];
79
- }
80
- break;
81
-
82
- case 'permanentflags':
83
- key = 'permanentFlags';
84
- value = new Set(value);
85
- break;
86
-
87
- case 'uidnext':
88
- key = 'uidNext';
89
- value = Number(value);
90
- break;
91
-
92
- case 'uidvalidity':
93
- key = 'uidValidity';
94
- if (/^[0-9]+$/.test(value)) {
95
- value = BigInt(value);
96
- }
97
- break;
59
+ let section = !untagged.attributes[0].value && untagged.attributes[0].section;
60
+ if (section && section.length > 1 && section[0].type === 'ATOM' && typeof section[0].value === 'string') {
61
+ let key = section[0].value.toLowerCase();
62
+ let value;
63
+
64
+ if (typeof section[1].value === 'string') {
65
+ value = section[1].value;
66
+ } else if (Array.isArray(section[1])) {
67
+ value = section[1].map(entry => (typeof entry.value === 'string' ? entry.value : false)).filter(entry => entry);
68
+ }
69
+
70
+ switch (key) {
71
+ case 'highestmodseq':
72
+ key = 'highestModseq';
73
+ if (/^[0-9]+$/.test(value)) {
74
+ value = BigInt(value);
75
+ }
76
+ break;
77
+
78
+ case 'mailboxid':
79
+ key = 'mailboxId';
80
+ if (Array.isArray(value) && value.length) {
81
+ value = value[0];
82
+ }
83
+ break;
84
+
85
+ case 'permanentflags':
86
+ key = 'permanentFlags';
87
+ value = new Set(value);
88
+ break;
89
+
90
+ case 'uidnext':
91
+ key = 'uidNext';
92
+ value = Number(value);
93
+ break;
94
+
95
+ case 'uidvalidity':
96
+ key = 'uidValidity';
97
+ if (/^[0-9]+$/.test(value)) {
98
+ value = BigInt(value);
99
+ }
100
+ break;
101
+ }
102
+
103
+ map[key] = value;
98
104
  }
99
105
 
100
- map[key] = value;
101
- }
102
-
103
- if (section && section.length === 1 && section[0].type === 'ATOM' && typeof section[0].value === 'string') {
104
- let key = section[0].value.toLowerCase();
105
- switch (key) {
106
- case 'nomodseq':
107
- key = 'noModseq';
108
- map[key] = true;
109
- break;
106
+ if (section && section.length === 1 && section[0].type === 'ATOM' && typeof section[0].value === 'string') {
107
+ let key = section[0].value.toLowerCase();
108
+ switch (key) {
109
+ case 'nomodseq':
110
+ key = 'noModseq';
111
+ map[key] = true;
112
+ break;
113
+ }
114
+ }
115
+ },
116
+ FLAGS: async untagged => {
117
+ if (!untagged.attributes || (!untagged.attributes.length && Array.isArray(untagged.attributes[0]))) {
118
+ return;
119
+ }
120
+ let flags = untagged.attributes[0].map(flag => (typeof flag.value === 'string' ? flag.value : false)).filter(flag => flag);
121
+ map.flags = new Set(flags);
122
+ },
123
+ EXISTS: async untagged => {
124
+ let num = Number(untagged.command);
125
+ if (isNaN(num)) {
126
+ return false;
110
127
  }
111
- }
112
- },
113
- FLAGS: async untagged => {
114
- if (!untagged.attributes || (!untagged.attributes.length && Array.isArray(untagged.attributes[0]))) {
115
- return;
116
- }
117
- let flags = untagged.attributes[0].map(flag => (typeof flag.value === 'string' ? flag.value : false)).filter(flag => flag);
118
- map.flags = new Set(flags);
119
- },
120
- EXISTS: async untagged => {
121
- let num = Number(untagged.command);
122
- if (isNaN(num)) {
123
- return false;
124
- }
125
128
 
126
- map.exists = num;
127
- },
128
- VANISHED: async untagged => {
129
- await connection.untaggedVanished(
130
- untagged,
131
- // mailbox is not yet open, so use a dummy mailbox object
132
- { path, uidNext: false, uidValidity: false }
133
- );
134
- },
135
- // we should only get an untagged FETCH for a SELECT/EXAMINE if QRESYNC was asked for
136
- FETCH: async untagged => {
137
- await connection.untaggedFetch(
138
- untagged,
139
- // mailbox is not yet open, so use a dummy mailbox object
140
- { path, uidNext: false, uidValidity: false }
141
- );
129
+ map.exists = num;
130
+ },
131
+ VANISHED: async untagged => {
132
+ await connection.untaggedVanished(
133
+ untagged,
134
+ // mailbox is not yet open, so use a dummy mailbox object
135
+ { path, uidNext: false, uidValidity: false }
136
+ );
137
+ },
138
+ // we should only get an untagged FETCH for a SELECT/EXAMINE if QRESYNC was asked for
139
+ FETCH: async untagged => {
140
+ await connection.untaggedFetch(
141
+ untagged,
142
+ // mailbox is not yet open, so use a dummy mailbox object
143
+ { path, uidNext: false, uidValidity: false }
144
+ );
145
+ }
142
146
  }
143
147
  }
144
- });
148
+ );
145
149
 
146
150
  let section = !response.response.attributes[0].value && response.response.attributes[0].section;
147
151
  if (section && section.length && section[0].type === 'ATOM' && typeof section[0].value === 'string') {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath } = require('../tools.js');
3
+ const { encodePath, normalizePath } = require('../tools.js');
4
4
 
5
5
  // Requests info about a mailbox
6
6
  module.exports = async (connection, path, query) => {
@@ -11,7 +11,7 @@ module.exports = async (connection, path, query) => {
11
11
 
12
12
  path = normalizePath(connection, path);
13
13
 
14
- let attributes = [{ type: 'ATOM', value: path }];
14
+ let attributes = [{ type: 'ATOM', value: encodePath(connection, path) }];
15
15
 
16
16
  let queryAttributes = [];
17
17
  Object.keys(query || {}).forEach(key => {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath, getStatusCode, getErrorText } = require('../tools.js');
3
+ const { encodePath, normalizePath, getStatusCode, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Subscribes to a mailbox
6
6
  module.exports = async (connection, path) => {
@@ -13,7 +13,7 @@ module.exports = async (connection, path) => {
13
13
 
14
14
  let response;
15
15
  try {
16
- response = await connection.exec('SUBSCRIBE', [{ type: 'ATOM', value: path }]);
16
+ response = await connection.exec('SUBSCRIBE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
17
17
  response.next();
18
18
  return true;
19
19
  } catch (err) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { normalizePath, getStatusCode, getErrorText } = require('../tools.js');
3
+ const { encodePath, normalizePath, getStatusCode, getErrorText } = require('../tools.js');
4
4
 
5
5
  // Unsubscribes from a mailbox
6
6
  module.exports = async (connection, path) => {
@@ -13,7 +13,7 @@ module.exports = async (connection, path) => {
13
13
 
14
14
  let response;
15
15
  try {
16
- response = await connection.exec('UNSUBSCRIBE', [{ type: 'ATOM', value: path }]);
16
+ response = await connection.exec('UNSUBSCRIBE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
17
17
  response.next();
18
18
  return true;
19
19
  } catch (err) {
@@ -85,7 +85,7 @@ module.exports = async (response, options) => {
85
85
  let canAppend = !asArray || literalPlus || (literalMinus && literalLength <= 4096);
86
86
  let usePlus = canAppend && (literalMinus || literalPlus);
87
87
 
88
- resp += `{${literalLength}${usePlus ? '+' : ''}}\r\n`;
88
+ resp += `${node.isLiteral8 ? '~' : ''}{${literalLength}${usePlus ? '+' : ''}}\r\n`;
89
89
 
90
90
  if (canAppend) {
91
91
  resp += (node.value || '').toString('binary');