This commit is contained in:
Florian Federspiel
2023-11-25 16:53:52 +01:00
commit 677030f712
685 changed files with 148719 additions and 0 deletions

15
test/imaps/node_modules/libqp/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"rules": {
"indent": 0,
"no-await-in-loop": 0,
"require-atomic-updates": 0
},
"globals": {
"BigInt": true
},
"extends": ["nodemailer", "prettier"],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "script"
}
}

8
test/imaps/node_modules/libqp/.prettierrc.js generated vendored Normal file
View File

@@ -0,0 +1,8 @@
module.exports = {
printWidth: 160,
tabWidth: 4,
singleQuote: true,
endOfLine: 'lf',
trailingComma: 'none',
arrowParens: 'avoid'
};

19
test/imaps/node_modules/libqp/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2014-2022 Andris Reinman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

119
test/imaps/node_modules/libqp/README.md generated vendored Normal file
View File

@@ -0,0 +1,119 @@
# libqp
Encode and decode quoted-printable strings according to [RFC2045](http://tools.ietf.org/html/rfc2045#section-6.7).
## Usage
Install with npm
```
npm install libqp
```
Require in your script
```javascript
const libqp = require('libqp');
```
### Encode values
Encode Buffer objects or unicode strings with
```
libqp.encode(val) → String
```
Where
- **val** is a Buffer or an unicode string
**Example**
```javascript
libqp.encode('jõgeva');
// j=C3=B5geva
```
### Wrap encoded values
Quoted-Printable encoded lines are limited to 76 characters but `encode` method might return lines longer than the limit.
To enforce soft line breaks on lines longer than 76 (or any other length) characters, use `wrap`
```
libqp.wrap(str[, lineLength]) → String
```
Where
- **str** is a Quoted-Printable encoded string
- **lineLength** (defaults to 76) is the maximum allowed line length. Any longer line will be soft wrapped
**Example**
```javascript
libqp.wrap('abc j=C3=B5geva', 10);
// abc j=\r\n
// =C3=B5geva
```
### Transform Streams
`libqp` makes it possible to encode and decode streams with `libqp.Encoder` and `libqp.Decoder` constructors.
### Encoder Stream
Create new Encoder Stream with
```
const encoder = new libqp.Encoder([options])
```
Where
- **options** is the optional stream options object with an additional option `lineLength` if you want to use any other line length than the default 76 characters (or set to `false` to turn the soft wrapping off completely)
**Example**
The following example script reads in a file, encodes it to Quoted-Printable and saves the output to a file.
```javascript
var libqp = require('libqp');
var fs = require('fs');
var source = fs.createReadStream('source.txt');
var encoded = fs.createReadStream('encoded.txt');
var encoder = new libqp.Encoder();
source.pipe(encoder).pipe(encoded);
```
### Decoder Stream
Create new Decoder Stream with
```
const decoder = new libqp.Decoder([options])
```
Where
- **options** is the optional stream options object
**Example**
The following example script reads in a file in Quoted-Printable encoding, decodes it and saves the output to a file.
```javascript
const libqp = require('libqp');
const fs = require('fs');
let encoded = fs.createReadStream('encoded.txt');
let dest = fs.createReadStream('dest.txt');
let decoder = new libqp.Decoder();
encoded.pipe(decoder).pipe(dest);
```
## License
**MIT**

319
test/imaps/node_modules/libqp/lib/libqp.js generated vendored Normal file
View File

@@ -0,0 +1,319 @@
/* eslint no-useless-escape: 0 */
'use strict';
const stream = require('stream');
const Transform = stream.Transform;
/**
* Encodes a Buffer into a Quoted-Printable encoded string
*
* @param {Buffer} buffer Buffer to convert
* @returns {String} Quoted-Printable encoded string
*/
function encode(buffer) {
if (typeof buffer === 'string') {
buffer = Buffer.from(buffer, 'utf-8');
}
// usable characters that do not need encoding
let ranges = [
// https://tools.ietf.org/html/rfc2045#section-6.7
[0x09], // <TAB>
[0x0a], // <LF>
[0x0d], // <CR>
[0x20, 0x3c], // <SP>!"#$%&'()*+,-./0123456789:;
[0x3e, 0x7e] // >?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
];
let result = '';
let ord;
for (let i = 0, len = buffer.length; i < len; i++) {
ord = buffer[i];
// if the char is in allowed range, then keep as is, unless it is a ws in the end of a line
if (checkRanges(ord, ranges) && !((ord === 0x20 || ord === 0x09) && (i === len - 1 || buffer[i + 1] === 0x0a || buffer[i + 1] === 0x0d))) {
result += String.fromCharCode(ord);
continue;
}
result += '=' + (ord < 0x10 ? '0' : '') + ord.toString(16).toUpperCase();
}
return result;
}
/**
* Decodes a Quoted-Printable encoded string to a Buffer object
*
* @param {String} str Quoted-Printable encoded string
* @returns {Buffer} Decoded value
*/
function decode(str) {
str = (str || '')
.toString()
// remove invalid whitespace from the end of lines
.replace(/[\t ]+$/gm, '')
// remove soft line breaks
.replace(/\=(?:\r?\n|$)/g, '');
let encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length,
bufferLength = str.length - encodedBytesCount * 2,
chr,
hex,
buffer = Buffer.alloc(bufferLength),
bufferPos = 0;
for (let i = 0, len = str.length; i < len; i++) {
chr = str.charAt(i);
if (chr === '=' && (hex = str.substr(i + 1, 2)) && /[\da-fA-F]{2}/.test(hex)) {
buffer[bufferPos++] = parseInt(hex, 16);
i += 2;
continue;
}
buffer[bufferPos++] = chr.charCodeAt(0);
}
return buffer;
}
/**
* Adds soft line breaks to a Quoted-Printable string
*
* @param {String} str Quoted-Printable encoded string that might need line wrapping
* @param {Number} [lineLength=76] Maximum allowed length for a line
* @returns {String} Soft-wrapped Quoted-Printable encoded string
*/
function wrap(str, lineLength) {
str = (str || '').toString();
lineLength = lineLength || 76;
if (str.length <= lineLength) {
return str;
}
let pos = 0,
len = str.length,
match,
code,
line,
lineMargin = Math.floor(lineLength / 3),
result = '';
// insert soft linebreaks where needed
while (pos < len) {
line = str.substr(pos, lineLength);
if ((match = line.match(/\r\n/))) {
line = line.substr(0, match.index + match[0].length);
result += line;
pos += line.length;
continue;
}
if (line.substr(-1) === '\n') {
// nothing to change here
result += line;
pos += line.length;
continue;
} else if ((match = line.substr(-lineMargin).match(/\n.*?$/))) {
// truncate to nearest line break
line = line.substr(0, line.length - (match[0].length - 1));
result += line;
pos += line.length;
continue;
} else if (line.length > lineLength - lineMargin && (match = line.substr(-lineMargin).match(/[ \t\.,!\?][^ \t\.,!\?]*$/))) {
// truncate to nearest space
line = line.substr(0, line.length - (match[0].length - 1));
} else if (line.match(/\=[\da-f]{0,2}$/i)) {
// push incomplete encoding sequences to the next line
if ((match = line.match(/\=[\da-f]{0,1}$/i))) {
line = line.substr(0, line.length - match[0].length);
}
// ensure that utf-8 sequences are not split
while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/\=[\da-f]{2}$/gi))) {
code = parseInt(match[0].substr(1, 2), 16);
if (code < 128) {
break;
}
line = line.substr(0, line.length - 3);
if (code >= 0xc0) {
break;
}
}
}
if (pos + line.length < len && line.substr(-1) !== '\n') {
if (line.length === lineLength && line.match(/\=[\da-f]{2}$/i)) {
line = line.substr(0, line.length - 3);
} else if (line.length === lineLength) {
line = line.substr(0, line.length - 1);
}
pos += line.length;
line += '=\r\n';
} else {
pos += line.length;
}
result += line;
}
return result;
}
/**
* Helper function to check if a number is inside provided ranges
*
* @param {Number} nr Number to check for
* @param {Array} ranges An Array of allowed values
* @returns {Boolean} True if the value was found inside allowed ranges, false otherwise
*/
function checkRanges(nr, ranges) {
for (let i = ranges.length - 1; i >= 0; i--) {
if (!ranges[i].length) {
continue;
}
if (ranges[i].length === 1 && nr === ranges[i][0]) {
return true;
}
if (ranges[i].length === 2 && nr >= ranges[i][0] && nr <= ranges[i][1]) {
return true;
}
}
return false;
}
/**
* Creates a transform stream for encoding data to Quoted-Printable encoding
*
* @constructor
* @param {Object} options Stream options
* @param {Number} [options.lineLength=76] Maximum lenght for lines, set to false to disable wrapping
*/
class Encoder extends Transform {
constructor(options) {
super();
// init Transform
this.options = options || {};
if (this.options.lineLength !== false) {
this.options.lineLength = this.options.lineLength || 76;
}
this._curLine = '';
this.inputBytes = 0;
this.outputBytes = 0;
Transform.call(this, this.options);
}
_transform(chunk, encoding, done) {
let qp;
if (encoding !== 'buffer') {
chunk = Buffer.from(chunk, encoding);
}
if (!chunk || !chunk.length) {
return done();
}
this.inputBytes += chunk.length;
if (this.options.lineLength) {
qp = this._curLine + encode(chunk);
qp = wrap(qp, this.options.lineLength);
qp = qp.replace(/(^|\n)([^\n]*)$/, (match, lineBreak, lastLine) => {
this._curLine = lastLine;
return lineBreak;
});
if (qp) {
this.outputBytes += qp.length;
this.push(qp);
}
} else {
qp = encode(chunk);
this.outputBytes += qp.length;
this.push(qp, 'ascii');
}
done();
}
_flush(done) {
if (this._curLine) {
this.outputBytes += this._curLine.length;
this.push(this._curLine, 'ascii');
}
done();
}
}
/**
* Creates a transform stream for decoding Quoted-Printable encoded strings
*
* @constructor
* @param {Object} options Stream options
*/
class Decoder extends Transform {
constructor(options) {
options = options || {};
super(options);
// init Transform
this.options = options;
this._curLine = '';
this.inputBytes = 0;
this.outputBytes = 0;
}
_transform(chunk, encoding, done) {
let qp, buf;
chunk = chunk.toString('ascii');
if (!chunk || !chunk.length) {
return done();
}
this.inputBytes += chunk.length;
qp = this._curLine + chunk;
this._curLine = '';
qp = qp.replace(/\=[^\n]?$/, lastLine => {
this._curLine = lastLine;
return '';
});
if (qp) {
buf = decode(qp);
this.outputBytes += buf.length;
this.push(buf);
}
done();
}
_flush(done) {
let buf;
if (this._curLine) {
buf = decode(this._curLine);
this.outputBytes += buf.length;
this.push(buf);
}
done();
}
}
// expose to the world
module.exports = {
encode,
decode,
wrap,
Encoder,
Decoder
};

27
test/imaps/node_modules/libqp/package.json generated vendored Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "libqp",
"version": "2.0.1",
"description": "Encode and decode quoted-printable strings according to rfc2045",
"main": "lib/libqp.js",
"scripts": {
"test": "node --test test/"
},
"repository": {
"type": "git",
"url": "git://github.com/andris9/libqp.git"
},
"keywords": [
"quoted-printable",
"mime"
],
"author": "Andris Reinman",
"license": "MIT",
"bugs": {
"url": "https://github.com/andris9/libqp/issues"
},
"homepage": "https://github.com/andris9/libqp",
"devDependencies": {
"eslint-config-nodemailer": "1.2.0",
"eslint-config-prettier": "8.5.0"
}
}

40
test/imaps/node_modules/libqp/test/libqp-test.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
'use strict';
const test = require('node:test');
const assert = require('node:assert').strict;
const libqp = require('../lib/libqp');
test('Encoding tests', async t => {
await t.test('simple string', async () => {
const encoded = libqp.encode('tere jõgeva');
assert.strictEqual(encoded, 'tere j=C3=B5geva');
});
await t.test('stream', async () => {
let input = 'tere jõgeva';
let encoder = new libqp.Encoder();
let encoded = await new Promise((resolve, reject) => {
let chunks = [];
encoder.on('readable', () => {
let chunk;
while ((chunk = encoder.read()) !== null) {
chunks.push(chunk);
}
});
encoder.on('end', () => {
resolve(Buffer.concat(chunks).toString());
});
encoder.on('Error', err => {
reject(err);
});
encoder.end(Buffer.from(input));
});
assert.strictEqual(encoded, 'tere j=C3=B5geva');
});
});