mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-01-23 16:27:51 +08:00
Fixed Compress
This commit is contained in:
parent
0c76c38aed
commit
6bc92ab0ff
4 changed files with 57 additions and 30 deletions
58
README.md
58
README.md
|
@ -39,6 +39,7 @@ Wild Duck IMAP server supports the following IMAP standards:
|
|||
- **APPENDLIMIT** (RFC7889) – maximum global allowed message size is advertised in CAPABILITY listing
|
||||
- **UTF8=ACCEPT** (RFC6855) – this also means that Wild Duck natively supports unicode email usernames. For example <андрис@уайлддак.орг> is a valid email address that is hosted by a test instance of Wild Duck
|
||||
- **QUOTA** (RFC2087) – Quota size is global for an account, using a single quota root. Be aware that quota size does not mean actual byte storage in disk, it is calculated as the sum of the rfc822 sources of stored messages. Actual disk usage is larger as there are database overhead per every message.
|
||||
- **COMPRESS=DEFLATE** (RFC4978) – Compress traffic between the client and the server
|
||||
|
||||
Wild Duck more or less passes the [ImapTest](https://www.imapwiki.org/ImapTest/TestFeatures). Common errors that arise in the test are unknown labels (Wild Duck doesn't send unsolicited FLAGS updates) and NO for STORE (messages deleted in one session can not be updated in another).
|
||||
|
||||
|
@ -379,26 +380,29 @@ Parameters
|
|||
|
||||
- **id** is the mailbox ID
|
||||
- **size** is optional number to limit the length of the messages array (defaults to 20)
|
||||
- **before** is an optional paging number (see *next* in response)
|
||||
- **after** is an optional paging number (see *prev* in response)
|
||||
- **before** is an optional paging number (see _next_ in response)
|
||||
- **after** is an optional paging number (see _prev_ in response)
|
||||
|
||||
Response includes the following fields
|
||||
|
||||
* **mailbox** is an object that lists some metadata about the current mailbox
|
||||
* **id** is the mailbox ID
|
||||
* **path** is the folder path
|
||||
* **next** is an URL fragment for retrieving the next page (or false if there are no more pages)
|
||||
* **prev** is an URL fragment for retrieving the previous page (or false if it is the first page)
|
||||
* **messages** is an array of messages in the mailbox
|
||||
* **id** is the message ID
|
||||
* **date** is the date when this message was received
|
||||
* **hasAttachments** is a boolean that indicates if this messages has attachments or not
|
||||
* **intro** includes the first 256 characters from the message
|
||||
* **subject** is the message title
|
||||
* **from** is the From: field
|
||||
* **to** is the To: field
|
||||
* **cc** is the Cc: field
|
||||
* **bcc** is the Bcc: field
|
||||
- **mailbox** is an object that lists some metadata about the current mailbox
|
||||
|
||||
- **id** is the mailbox ID
|
||||
- **path** is the folder path
|
||||
|
||||
- **next** is an URL fragment for retrieving the next page (or false if there are no more pages)
|
||||
- **prev** is an URL fragment for retrieving the previous page (or false if it is the first page)
|
||||
- **messages** is an array of messages in the mailbox
|
||||
|
||||
- **id** is the message ID
|
||||
- **date** is the date when this message was received
|
||||
- **hasAttachments** is a boolean that indicates if this messages has attachments or not
|
||||
- **intro** includes the first 256 characters from the message
|
||||
- **subject** is the message title
|
||||
- **from** is the From: field
|
||||
- **to** is the To: field
|
||||
- **cc** is the Cc: field
|
||||
- **bcc** is the Bcc: field
|
||||
|
||||
The response for successful listing should look like this:
|
||||
|
||||
|
@ -451,6 +455,7 @@ Response message includes the following fields
|
|||
- **date** is the receive date (not header Date: field)
|
||||
|
||||
- **mailbox** is the id of the mailbox this messages belongs to
|
||||
|
||||
- **flags** is an array of IMAP flags for this message
|
||||
- **text** is the plaintext version of the message (derived from html if not present in message source)
|
||||
- **html** is the HTML version of the message (derived from plaintext if not present in message source)
|
||||
|
@ -468,15 +473,21 @@ Response message includes the following fields
|
|||
|
||||
HTML content has embedded images linked with the following URL structure:
|
||||
|
||||
attachment:MESSAGE_ID/ATTACHMENT_ID
|
||||
```
|
||||
attachment:MESSAGE_ID/ATTACHMENT_ID
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
<img src="attachment:aaaaaa/bbbbbb">
|
||||
```
|
||||
<img src="attachment:aaaaaa/bbbbbb">
|
||||
```
|
||||
|
||||
To fetch the actual attachment contents for this image, use the following url:
|
||||
|
||||
http://localhost:8080/message/aaaaaa/attachment/bbbbbb
|
||||
```
|
||||
http://localhost:8080/message/aaaaaa/attachment/bbbbbb
|
||||
```
|
||||
|
||||
#### Example response
|
||||
|
||||
|
@ -588,10 +599,9 @@ Any other differences are most probably real bugs and unintentional.
|
|||
|
||||
Wild Duck does not plan to be the most feature-rich IMAP client in the world. Most IMAP extensions are useless because there aren't too many clients that are able to benefit from these extensions. There are a few extensions though that would make sense to be added to Wild Duck
|
||||
|
||||
1. The IMAP COMPRESS Extension (RFC4978)
|
||||
2. IMAP4 non-synchronizing literals, LITERAL- (RFC7888). Synchronized literals are needed for APPEND to check mailbox quota, small values could go with the non-synchronizing version.
|
||||
3. LIST-STATUS (RFC5819)
|
||||
4. _What else?_ (definitely not NOTIFY nor QRESYNC)
|
||||
1. IMAP4 non-synchronizing literals, LITERAL- (RFC7888). Synchronized literals are needed for APPEND to check mailbox quota, small values could go with the non-synchronizing version.
|
||||
2. LIST-STATUS (RFC5819)
|
||||
3. _What else?_ (definitely not NOTIFY nor QRESYNC)
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
|
@ -32,17 +32,34 @@ module.exports = {
|
|||
setImmediate(() => {
|
||||
this.compression = true;
|
||||
|
||||
this._deflate = zlib.createDeflateRaw();
|
||||
this._deflate = zlib.createDeflateRaw({
|
||||
windowBits: 15
|
||||
});
|
||||
this._inflate = zlib.createInflateRaw();
|
||||
|
||||
this._deflate.once('error', err => {
|
||||
this._socket.emit('error', err);
|
||||
this._server.logger.debug('[%s] Deflate error %s', this.id, err.message);
|
||||
this.close();
|
||||
});
|
||||
|
||||
this._deflate.pipe(this._socket);
|
||||
this._inflate.once('error', err => {
|
||||
this._server.logger.debug('[%s] Inflate error %s', this.id, err.message);
|
||||
this.close();
|
||||
});
|
||||
|
||||
this.writeStream.unpipe(this._socket);
|
||||
this.writeStream.pipe(this._deflate);
|
||||
this._deflate.pipe(this._socket);
|
||||
let readNext = () => {
|
||||
let chunk;
|
||||
while ((chunk = this.writeStream.read()) !== null) {
|
||||
if (this._deflate.write(chunk) === false) {
|
||||
return this._deflate.once('drain', readNext);
|
||||
}
|
||||
}
|
||||
// flush data to socket
|
||||
this._deflate.flush();
|
||||
};
|
||||
this.writeStream.on('readable', readNext);
|
||||
|
||||
this._socket.unpipe(this._parser);
|
||||
this._socket.pipe(this._inflate).pipe(this._parser);
|
||||
|
|
|
@ -21,7 +21,7 @@ class IMAPComposer extends Transform {
|
|||
if (typeof obj.pipe === 'function') {
|
||||
// pipe stream to socket and wait until it finishes before continuing
|
||||
this.connection._server.logger.debug('[%s] S: <pipe message stream to socket>', this.connection.id);
|
||||
obj.pipe(this.connection._socket, {
|
||||
obj.pipe(this.connection[!this.connection.compression ? '_socket' : '_deflate'], {
|
||||
end: false
|
||||
});
|
||||
obj.on('error', err => this.emit('error', err));
|
||||
|
|
|
@ -122,7 +122,7 @@ class IMAPConnection extends EventEmitter {
|
|||
*/
|
||||
send(payload, callback) {
|
||||
if (this._socket && this._socket.writable) {
|
||||
(!this.compression ? this._socket : this._deflate).write(payload + '\r\n', 'binary', callback);
|
||||
this[!this.compression ? '_socket' : '_deflate'].write(payload + '\r\n', 'binary', callback);
|
||||
this._server.logger.debug('[%s] S:', this.id, payload);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue