New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

wo-imap-handler

Package Overview
Dependencies
Maintainers
3
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

wo-imap-handler - npm Package Compare versions

Comparing version 0.1.13 to 0.1.14

2

package.json
{
"name": "wo-imap-handler",
"main": "src/imap-handler.js",
"version": "0.1.13",
"version": "0.1.14",
"homepage": "https://github.com/whiteout-io/imap-handler",

@@ -6,0 +6,0 @@ "author": "Andris Reinman <andris@kreata.ee>",

@@ -115,2 +115,3 @@ # IMAP Handler

* **asArray** if set to `true` return the value as an array instead of a string where the command is split on LITERAL notions
* **isLogging** if set to true, do not include literals and long strings, useful when logging stuff and do not want to include message bodies etc. Additionally nodes with `sensitive: true` options are also not displayed (useful with logging passwords) if `logging` is used.

@@ -117,0 +118,0 @@ The function returns a string or if `asArray` is set to true, as an array which is split on LITERAL notions, eg. "{4}\r\nabcde" becomes ["{4}\r\n", "abcde"]. This is useful if you need to wait for "+" response from the server before you can transmit the literal data.

@@ -22,8 +22,8 @@ // Copyright (c) 2013 Andris Reinman

(function(root, factory) {
"use strict";
'use strict';
if (typeof define === "function" && define.amd) {
define(["imap-formal-syntax"], factory);
} else if (typeof exports === "object") {
module.exports = factory(require("./imap-formal-syntax"));
if (typeof define === 'function' && define.amd) {
define(['imap-formal-syntax'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('./imap-formal-syntax'));
} else {

@@ -34,3 +34,3 @@ root.imapCompiler = factory(root.imapFormalSyntax);

"use strict";
'use strict';

@@ -40,31 +40,35 @@ /**

*/
return function(response, asArray) {
return function(response, asArray, isLogging) {
var respParts = [],
resp = (response.tag || "") + (response.command ? " " + response.command : ""),
resp = (response.tag || '') + (response.command ? ' ' + response.command : ''),
val, lastType,
walk = function(node) {
if (lastType === "LITERAL" || (["(", "<", "["].indexOf(resp.substr(-1)) < 0 && resp.length)) {
resp += " ";
if (lastType === 'LITERAL' || (['(', '<', '['].indexOf(resp.substr(-1)) < 0 && resp.length)) {
resp += ' ';
}
if (Array.isArray(node)) {
lastType = "LIST";
resp += "(";
lastType = 'LIST';
resp += '(';
node.forEach(walk);
resp += ")";
resp += ')';
return;
}
if (!node && typeof node !== "string" && typeof node !== "number") {
resp += "NIL";
if (!node && typeof node !== 'string' && typeof node !== 'number') {
resp += 'NIL';
return;
}
if (typeof node === "string") {
resp += JSON.stringify(node);
if (typeof node === 'string') {
if (isLogging && node.length > 20) {
resp += '"(* ' + node.length + 'B string *)"';
} else {
resp += JSON.stringify(node);
}
return;
}
if (typeof node === "number") {
if (typeof node === 'number') {
resp += Math.round(node) || 0; // Only integers allowed

@@ -75,31 +79,44 @@ return;

lastType = node.type;
if (isLogging && node.sensitive) {
resp += '"(* value hidden *)"';
return;
}
switch (node.type.toUpperCase()) {
case "LITERAL":
if (!node.value) {
resp += "{0}\r\n";
case 'LITERAL':
if (isLogging) {
resp += '"(* ' + node.value.length + 'B literal *)"';
} else {
resp += "{" + node.value.length + "}\r\n";
if (!node.value) {
resp += '{0}\r\n';
} else {
resp += '{' + node.value.length + '}\r\n';
}
respParts.push(resp);
resp = node.value || '';
}
respParts.push(resp);
resp = node.value || "";
break;
case "STRING":
resp += JSON.stringify(node.value || "");
case 'STRING':
if (isLogging && node.value.length > 20) {
resp += '"(* ' + node.value.length + 'B string *)"';
} else {
resp += JSON.stringify(node.value || '');
}
break;
case "TEXT":
case "SEQUENCE":
resp += node.value || "";
case 'TEXT':
case 'SEQUENCE':
resp += node.value || '';
break;
case "NUMBER":
case 'NUMBER':
resp += (node.value || 0);
break;
case "ATOM":
case "SECTION":
val = node.value || "";
case 'ATOM':
case 'SECTION':
val = node.value || '';
if (imapFormalSyntax.verify(val.charAt(0) === "\\" ? val.substr(1) : val, imapFormalSyntax["ATOM-CHAR"]()) >= 0) {
if (imapFormalSyntax.verify(val.charAt(0) === '\\' ? val.substr(1) : val, imapFormalSyntax['ATOM-CHAR']()) >= 0) {
val = JSON.stringify(val);

@@ -111,8 +128,8 @@ }

if (node.section) {
resp += "[";
resp += '[';
node.section.forEach(walk);
resp += "]";
resp += ']';
}
if (node.partial) {
resp += "<" + node.partial.join(".") + ">";
resp += '<' + node.partial.join('.') + '>';
}

@@ -130,4 +147,4 @@ break;

return asArray ? respParts : respParts.join("");
return asArray ? respParts : respParts.join('');
};
}));

@@ -22,7 +22,7 @@ // Copyright (c) 2013 Andris Reinman

(function(root, factory) {
"use strict";
'use strict';
if (typeof define === "function" && define.amd) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === "object") {
} else if (typeof exports === 'object') {
module.exports = factory();

@@ -34,3 +34,3 @@ } else {

"use strict";
'use strict';

@@ -40,5 +40,5 @@ // IMAP Formal Syntax

function expandRange(start, end){
function expandRange(start, end) {
var chars = [];
for(var i = start; i <= end; i++){
for (var i = start; i <= end; i++) {
chars.push(i);

@@ -49,10 +49,10 @@ }

function excludeChars(source, exclude){
function excludeChars(source, exclude) {
var sourceArr = Array.prototype.slice.call(source);
for(var i = sourceArr.length - 1; i >= 0; i--){
if(exclude.indexOf(sourceArr[i]) >= 0){
for (var i = sourceArr.length - 1; i >= 0; i--) {
if (exclude.indexOf(sourceArr[i]) >= 0) {
sourceArr.splice(i, 1);
}
}
return sourceArr.join("");
return sourceArr.join('');
}

@@ -62,5 +62,5 @@

"CHAR": function(){
CHAR: function() {
var value = expandRange(0x01, 0x7F);
this.CHAR = function(){
this.CHAR = function() {
return value;

@@ -71,5 +71,5 @@ };

"CHAR8": function(){
CHAR8: function() {
var value = expandRange(0x01, 0xFF);
this.CHAR8 = function(){
this.CHAR8 = function() {
return value;

@@ -80,9 +80,9 @@ };

"SP": function(){
return " ";
SP: function() {
return ' ';
},
"CTL": function(){
var value = expandRange(0x00, 0x1F) + "\x7F";
this.CTL = function(){
CTL: function() {
var value = expandRange(0x00, 0x1F) + '\x7F';
this.CTL = function() {
return value;

@@ -93,9 +93,9 @@ };

"DQUOTE": function(){
return "\"";
DQUOTE: function() {
return '"';
},
"ALPHA": function(){
ALPHA: function() {
var value = expandRange(0x41, 0x5A) + expandRange(0x61, 0x7A);
this.ALPHA = function(){
this.ALPHA = function() {
return value;

@@ -106,5 +106,5 @@ };

"DIGIT": function(){
DIGIT: function() {
var value = expandRange(0x30, 0x39) + expandRange(0x61, 0x7A);
this.DIGIT = function(){
this.DIGIT = function() {
return value;

@@ -115,5 +115,5 @@ };

"ATOM-CHAR": function(){
var value = excludeChars(this.CHAR(), this["atom-specials"]());
this["ATOM-CHAR"] = function(){
'ATOM-CHAR': function() {
var value = excludeChars(this.CHAR(), this['atom-specials']());
this['ATOM-CHAR'] = function() {
return value;

@@ -124,5 +124,5 @@ };

"ASTRING-CHAR": function(){
var value = this["ATOM-CHAR"]() + this["resp-specials"]();
this["ASTRING-CHAR"] = function(){
'ASTRING-CHAR': function() {
var value = this['ATOM-CHAR']() + this['resp-specials']();
this['ASTRING-CHAR'] = function() {
return value;

@@ -133,5 +133,5 @@ };

"TEXT-CHAR": function(){
var value = excludeChars(this.CHAR(), "\r\n");
this["TEXT-CHAR"] = function(){
'TEXT-CHAR': function() {
var value = excludeChars(this.CHAR(), '\r\n');
this['TEXT-CHAR'] = function() {
return value;

@@ -142,6 +142,6 @@ };

"atom-specials": function(){
var value = "(" + ")" + "{" + this.SP() + this.CTL() + this["list-wildcards"]() +
this["quoted-specials"]() + this["resp-specials"]();
this["atom-specials"] = function(){
'atom-specials': function() {
var value = '(' + ')' + '{' + this.SP() + this.CTL() + this['list-wildcards']() +
this['quoted-specials']() + this['resp-specials']();
this['atom-specials'] = function() {
return value;

@@ -152,9 +152,9 @@ };

"list-wildcards": function(){
return "%" + "*";
'list-wildcards': function() {
return '%' + '*';
},
"quoted-specials": function(){
var value = this.DQUOTE() + "\\";
this["quoted-specials"] = function(){
'quoted-specials': function() {
var value = this.DQUOTE() + '\\';
this['quoted-specials'] = function() {
return value;

@@ -165,9 +165,9 @@ };

"resp-specials": function(){
return "]";
'resp-specials': function() {
return ']';
},
tag: function(){
var value = excludeChars(this["ASTRING-CHAR"](), "+");
this.tag = function(){
tag: function() {
var value = excludeChars(this['ASTRING-CHAR'](), '+');
this.tag = function() {
return value;

@@ -178,5 +178,5 @@ };

command: function(){
command: function() {
var value = this.ALPHA() + this.DIGIT();
this.command = function(){
this.command = function() {
return value;

@@ -187,5 +187,5 @@ };

verify: function(str, allowedChars){
for(var i=0, len = str.length; i < len; i++){
if(allowedChars.indexOf(str.charAt(i)) < 0){
verify: function(str, allowedChars) {
for (var i = 0, len = str.length; i < len; i++) {
if (allowedChars.indexOf(str.charAt(i)) < 0) {
return i;

@@ -197,2 +197,2 @@ }

};
}));
}));

@@ -23,8 +23,8 @@ // Copyright (c) 2013 Andris Reinman

(function(root, factory) {
"use strict";
'use strict';
if (typeof define === "function" && define.amd) {
define(["./imap-parser", "./imap-compiler"], factory);
if (typeof define === 'function' && define.amd) {
define(['./imap-parser', './imap-compiler'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require("./imap-parser"), require("./imap-compiler"));
module.exports = factory(require('./imap-parser'), require('./imap-compiler'));
} else {

@@ -35,3 +35,3 @@ root.imapHandler = factory(root.imapParser, root.imapCompiler);

"use strict";
'use strict';

@@ -42,2 +42,2 @@ return {

};
}));
}));

@@ -22,7 +22,7 @@ // Copyright (c) 2013 Andris Reinman

(function(root, factory) {
"use strict";
'use strict';
if (typeof define === "function" && define.amd) {
if (typeof define === 'function' && define.amd) {
define(['imap-formal-syntax'], factory);
} else if (typeof exports === "object") {
} else if (typeof exports === 'object') {
module.exports = factory(require('./imap-formal-syntax'));

@@ -34,6 +34,6 @@ } else {

"use strict";
'use strict';
function ParserInstance(input, options) {
this.input = (input || "").toString();
this.input = (input || '').toString();
this.options = options || {};

@@ -46,3 +46,3 @@ this.remainder = this.input;

if (!this.tag) {
this.tag = this.getElement(imapFormalSyntax.tag() + "*+", true);
this.tag = this.getElement(imapFormalSyntax.tag() + '*+', true);
}

@@ -59,8 +59,8 @@ return this.tag;

switch ((this.command || "").toString().toUpperCase()) {
case "OK":
case "NO":
case "BAD":
case "PREAUTH":
case "BYE":
switch ((this.command || '').toString().toUpperCase()) {
case 'OK':
case 'NO':
case 'BAD':
case 'PREAUTH':
case 'BYE':
responseCode = this.remainder.match(/^ \[(?:[^\]]*\])+/);

@@ -72,3 +72,3 @@ if (responseCode) {

this.humanReadable = this.remainder.trim();
this.remainder = "";
this.remainder = '';
}

@@ -84,3 +84,3 @@ break;

if (this.remainder.match(/^\s/)) {
throw new Error("Unexpected whitespace at position " + this.pos);
throw new Error('Unexpected whitespace at position ' + this.pos);
}

@@ -92,6 +92,6 @@

if ((errPos = imapFormalSyntax.verify(element, syntax)) >= 0) {
throw new Error("Unexpected char at position " + (this.pos + errPos));
throw new Error('Unexpected char at position ' + (this.pos + errPos));
}
} else {
throw new Error("Unexpected end of input at position " + this.pos);
throw new Error('Unexpected end of input at position ' + this.pos);
}

@@ -107,7 +107,7 @@

if (!this.remainder.length) {
throw new Error("Unexpected end of input at position " + this.pos);
throw new Error('Unexpected end of input at position ' + this.pos);
}
if (imapFormalSyntax.verify(this.remainder.charAt(0), imapFormalSyntax.SP()) >= 0) {
throw new Error("Unexpected char at position " + this.pos);
throw new Error('Unexpected char at position ' + this.pos);
}

@@ -121,7 +121,7 @@

if (!this.remainder.length) {
throw new Error("Unexpected end of input at position " + this.pos);
throw new Error('Unexpected end of input at position ' + this.pos);
}
if (this.remainder.match(/^\s/)) {
throw new Error("Unexpected whitespace at position " + this.pos);
throw new Error('Unexpected whitespace at position ' + this.pos);
}

@@ -133,3 +133,3 @@

function TokenParser(parent, startPos, str, options) {
this.str = (str || "").toString();
this.str = (str || '').toString();
this.options = options || {};

@@ -141,5 +141,5 @@ this.parent = parent;

this.currentNode.type = "TREE";
this.currentNode.type = 'TREE';
this.state = "NORMAL";
this.state = 'NORMAL';

@@ -157,5 +157,5 @@ this.processString();

if (!node.closed && node.type === "SEQUENCE" && node.value === "*") {
if (!node.closed && node.type === 'SEQUENCE' && node.value === '*') {
node.closed = true;
node.type = "ATOM";
node.type = 'ATOM';
}

@@ -165,9 +165,9 @@

if (!node.closed) {
throw new Error("Unexpected end of input at position " + (this.pos + this.str.length - 1));
throw new Error('Unexpected end of input at position ' + (this.pos + this.str.length - 1));
}
switch (node.type.toUpperCase()) {
case "LITERAL":
case "STRING":
case "SEQUENCE":
case 'LITERAL':
case 'STRING':
case 'SEQUENCE':
elm = {

@@ -179,4 +179,4 @@ type: node.type.toUpperCase(),

break;
case "ATOM":
if (node.value.toUpperCase() === "NIL") {
case 'ATOM':
if (node.value.toUpperCase() === 'NIL') {
branch.push(null);

@@ -191,6 +191,6 @@ break;

break;
case "SECTION":
case 'SECTION':
branch = branch[branch.length - 1].section = [];
break;
case "LIST":
case 'LIST':
elm = [];

@@ -200,6 +200,6 @@ branch.push(elm);

break;
case "PARTIAL":
partial = node.value.split(".").map(Number);
case 'PARTIAL':
partial = node.value.split('.').map(Number);
if (partial.slice(-1)[0] < partial.slice(0, 1)[0]) {
throw new Error("Invalid partial value at position " + node.startPos);
throw new Error('Invalid partial value at position ' + node.startPos);
}

@@ -225,3 +225,3 @@ branch[branch.length - 1].partial = partial;

type: false,
value: "",
value: '',
closed: true

@@ -234,3 +234,3 @@ };

if (typeof startPos === "number") {
if (typeof startPos === 'number') {
node.startPos = startPos;

@@ -250,3 +250,3 @@ }

// jump to the next non whitespace pos
while (this.str.charAt(i + 1) === " ") {
while (this.str.charAt(i + 1) === ' ') {
i++;

@@ -262,3 +262,3 @@ }

case "NORMAL":
case 'NORMAL':

@@ -270,4 +270,4 @@ switch (chr) {

this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "string";
this.state = "STRING";
this.currentNode.type = 'string';
this.state = 'STRING';
this.currentNode.closed = false;

@@ -277,5 +277,5 @@ break;

// ( starts a new list
case "(":
case '(':
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "LIST";
this.currentNode.type = 'LIST';
this.currentNode.closed = false;

@@ -285,5 +285,5 @@ break;

// ) closes a list
case ")":
if (this.currentNode.type !== "LIST") {
throw new Error("Unexpected list terminator ) at position " + (this.pos + i));
case ')':
if (this.currentNode.type !== 'LIST') {
throw new Error('Unexpected list terminator ) at position ' + (this.pos + i));
}

@@ -299,5 +299,5 @@

// ] closes section group
case "]":
if (this.currentNode.type !== "SECTION") {
throw new Error("Unexpected section terminator ] at position " + (this.pos + i));
case ']':
if (this.currentNode.type !== 'SECTION') {
throw new Error('Unexpected section terminator ] at position ' + (this.pos + i));
}

@@ -311,12 +311,12 @@ this.currentNode.closed = true;

// < starts a new partial
case "<":
if (this.str.charAt(i - 1) !== "]") {
case '<':
if (this.str.charAt(i - 1) !== ']') {
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "ATOM";
this.currentNode.type = 'ATOM';
this.currentNode.value = chr;
this.state = "ATOM";
this.state = 'ATOM';
} else {
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "PARTIAL";
this.state = "PARTIAL";
this.currentNode.type = 'PARTIAL';
this.state = 'PARTIAL';
this.currentNode.closed = false;

@@ -327,6 +327,6 @@ }

// { starts a new literal
case "{":
case '{':
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "LITERAL";
this.state = "LITERAL";
this.currentNode.type = 'LITERAL';
this.state = 'LITERAL';
this.currentNode.closed = false;

@@ -336,12 +336,12 @@ break;

// ( starts a new sequence
case "*":
case '*':
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "SEQUENCE";
this.currentNode.type = 'SEQUENCE';
this.currentNode.value = chr;
this.currentNode.closed = false;
this.state = "SEQUENCE";
this.state = 'SEQUENCE';
break;
// normally a space should never occur
case " ":
case ' ':
// just ignore

@@ -351,14 +351,44 @@ break;

// [ starts section
case "[":
case '[':
// If it is the *first* element after response command, then process as a response argument list
if (["OK", "NO", "BAD", "BYE", "PREAUTH"].indexOf(this.parent.command.toUpperCase()) >= 0 && this.currentNode === this.tree) {
if (['OK', 'NO', 'BAD', 'BYE', 'PREAUTH'].indexOf(this.parent.command.toUpperCase()) >= 0 && this.currentNode === this.tree) {
this.currentNode.endPos = this.pos + i;
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "ATOM";
this.currentNode.type = 'ATOM';
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "SECTION";
this.currentNode.type = 'SECTION';
this.currentNode.closed = false;
this.state = "NORMAL";
this.state = 'NORMAL';
// RFC2221 defines a response code REFERRAL whose payload is an
// RFC2192/RFC5092 imapurl that we will try to parse as an ATOM but
// fail quite badly at parsing. Since the imapurl is such a unique
// (and crazy) term, we just specialize that case here.
if (this.str.substr(i + 1, 9).toUpperCase() === 'REFERRAL ') {
// create the REFERRAL atom
this.currentNode = this.createNode(this.currentNode, this.pos + i + 1);
this.currentNode.type = 'ATOM';
this.currentNode.endPos = this.pos + i + 8;
this.currentNode.value = 'REFERRAL';
this.currentNode = this.currentNode.parentNode;
// eat all the way through the ] to be the IMAPURL token.
this.currentNode = this.createNode(this.currentNode, this.pos + i + 10);
// just call this an ATOM, even though IMAPURL might be more correct
this.currentNode.type = 'ATOM';
// jump i to the ']'
i = this.str.indexOf(']', i + 10);
this.currentNode.endPos = this.pos + i - 1;
this.currentNode.value = this.str.substring(this.currentNode.startPos - this.pos,
this.currentNode.endPos - this.pos + 1);
this.currentNode = this.currentNode.parentNode;
// close out the SECTION
this.currentNode.closed = true;
this.currentNode = this.currentNode.parentNode;
checkSP();
}
break;

@@ -370,11 +400,11 @@ }

// Allow \ as the first char for atom to support system flags
// Allow % to support LIST "" %
if (imapFormalSyntax["ATOM-CHAR"]().indexOf(chr) < 0 && chr !== "\\" && chr !== "%") {
throw new Error("Unexpected char at position " + (this.pos + i));
// Allow % to support LIST '' %
if (imapFormalSyntax['ATOM-CHAR']().indexOf(chr) < 0 && chr !== '\\' && chr !== '%') {
throw new Error('Unexpected char at position ' + (this.pos + i));
}
this.currentNode = this.createNode(this.currentNode, this.pos + i);
this.currentNode.type = "ATOM";
this.currentNode.type = 'ATOM';
this.currentNode.value = chr;
this.state = "ATOM";
this.state = 'ATOM';
break;

@@ -384,12 +414,9 @@ }

case "ATOM":
case 'ATOM':
// space finishes an atom
if (chr === " ") {
if ([")", "]"].indexOf(this.str.charAt(i + 1)) >= 0) {
throw new Error("Unexpected whitespace at position " + (this.pos + i + 1));
}
if (chr === ' ') {
this.currentNode.endPos = this.pos + i - 1;
this.currentNode = this.currentNode.parentNode;
this.state = "NORMAL";
this.state = 'NORMAL';
break;

@@ -402,4 +429,4 @@ }

(
(chr === ")" && this.currentNode.parentNode.type === "LIST") ||
(chr === "]" && this.currentNode.parentNode.type === "SECTION")
(chr === ')' && this.currentNode.parentNode.type === 'LIST') ||
(chr === ']' && this.currentNode.parentNode.type === 'SECTION')
)

@@ -413,3 +440,3 @@ ) {

this.currentNode = this.currentNode.parentNode;
this.state = "NORMAL";
this.state = 'NORMAL';

@@ -420,31 +447,31 @@ checkSP();

if ((chr === "," || chr === ":") && this.currentNode.value.match(/^\d+$/)) {
this.currentNode.type = "SEQUENCE";
if ((chr === ',' || chr === ':') && this.currentNode.value.match(/^\d+$/)) {
this.currentNode.type = 'SEQUENCE';
this.currentNode.closed = true;
this.state = "SEQUENCE";
this.state = 'SEQUENCE';
}
// [ starts a section group for this element
if (chr === "[") {
if (chr === '[') {
// allowed only for selected elements
if (["BODY", "BODY.PEEK"].indexOf(this.currentNode.value.toUpperCase()) < 0) {
throw new Error("Unexpected section start char [ at position " + this.pos);
if (['BODY', 'BODY.PEEK'].indexOf(this.currentNode.value.toUpperCase()) < 0) {
throw new Error('Unexpected section start char [ at position ' + this.pos);
}
this.currentNode.endPos = this.pos + i;
this.currentNode = this.createNode(this.currentNode.parentNode, this.pos + i);
this.currentNode.type = "SECTION";
this.currentNode.type = 'SECTION';
this.currentNode.closed = false;
this.state = "NORMAL";
this.state = 'NORMAL';
break;
}
if (chr === "<") {
throw new Error("Unexpected start of partial at position " + this.pos);
if (chr === '<') {
throw new Error('Unexpected start of partial at position ' + this.pos);
}
// if the char is not ATOM compatible, throw. Allow \* as an exception
if (imapFormalSyntax["ATOM-CHAR"]().indexOf(chr) < 0 && chr !== "]" && !(chr === "*" && this.currentNode.value === "\\")) {
throw new Error("Unexpected char at position " + (this.pos + i));
} else if (this.currentNode.value === "\\*") {
throw new Error("Unexpected char at position " + (this.pos + i));
if (imapFormalSyntax['ATOM-CHAR']().indexOf(chr) < 0 && chr !== ']' && !(chr === '*' && this.currentNode.value === '\\')) {
throw new Error('Unexpected char at position ' + (this.pos + i));
} else if (this.currentNode.value === '\\*') {
throw new Error('Unexpected char at position ' + (this.pos + i));
}

@@ -455,3 +482,3 @@

case "STRING":
case 'STRING':

@@ -463,3 +490,3 @@ // DQUOTE ends the string sequence

this.currentNode = this.currentNode.parentNode;
this.state = "NORMAL";
this.state = 'NORMAL';

@@ -471,6 +498,6 @@ checkSP();

// \ Escapes the following char
if (chr === "\\") {
if (chr === '\\') {
i++;
if (i >= len) {
throw new Error("Unexpected end of input at position " + (this.pos + i));
throw new Error('Unexpected end of input at position ' + (this.pos + i));
}

@@ -480,5 +507,7 @@ chr = this.str.charAt(i);

if (imapFormalSyntax["TEXT-CHAR"]().indexOf(chr) < 0) {
throw new Error("Unexpected char at position " + (this.pos + i));
/* // skip this check, otherwise the parser might explode on binary input
if (imapFormalSyntax['TEXT-CHAR']().indexOf(chr) < 0) {
throw new Error('Unexpected char at position ' + (this.pos + i));
}
*/

@@ -488,6 +517,6 @@ this.currentNode.value += chr;

case "PARTIAL":
if (chr === ">") {
if (this.currentNode.value.substr(-1) === ".") {
throw new Error("Unexpected end of partial at position " + this.pos);
case 'PARTIAL':
if (chr === '>') {
if (this.currentNode.value.substr(-1) === '.') {
throw new Error('Unexpected end of partial at position ' + this.pos);
}

@@ -497,3 +526,3 @@ this.currentNode.endPos = this.pos + i;

this.currentNode = this.currentNode.parentNode;
this.state = "NORMAL";
this.state = 'NORMAL';
checkSP();

@@ -503,12 +532,12 @@ break;

if (chr === "." && (!this.currentNode.value.length || this.currentNode.value.match(/\./))) {
throw new Error("Unexpected partial separator . at position " + this.pos);
if (chr === '.' && (!this.currentNode.value.length || this.currentNode.value.match(/\./))) {
throw new Error('Unexpected partial separator . at position ' + this.pos);
}
if (imapFormalSyntax.DIGIT().indexOf(chr) < 0 && chr !== ".") {
throw new Error("Unexpected char at position " + (this.pos + i));
if (imapFormalSyntax.DIGIT().indexOf(chr) < 0 && chr !== '.') {
throw new Error('Unexpected char at position ' + (this.pos + i));
}
if (this.currentNode.value.match(/^0$|\.0$/) && chr !== ".") {
throw new Error("Invalid partial at position " + (this.pos + i));
if (this.currentNode.value.match(/^0$|\.0$/) && chr !== '.') {
throw new Error('Invalid partial at position ' + (this.pos + i));
}

@@ -519,7 +548,7 @@

case "LITERAL":
case 'LITERAL':
if (this.currentNode.started) {
//if(imapFormalSyntax["CHAR8"]().indexOf(chr) < 0){
if (chr === "\u0000") {
throw new Error("Unexpected \\x00 at position " + (this.pos + i));
//if(imapFormalSyntax['CHAR8']().indexOf(chr) < 0){
if (chr === '\u0000') {
throw new Error('Unexpected \\x00 at position ' + (this.pos + i));
}

@@ -532,3 +561,3 @@ this.currentNode.value += chr;

this.currentNode = this.currentNode.parentNode;
this.state = "NORMAL";
this.state = 'NORMAL';
checkSP();

@@ -539,3 +568,3 @@ }

if (chr === "+" && this.options.literalPlus) {
if (chr === '+' && this.options.literalPlus) {
this.currentNode.literalPlus = true;

@@ -545,12 +574,12 @@ break;

if (chr === "}") {
if (!("literalLength" in this.currentNode)) {
throw new Error("Unexpected literal prefix end char } at position " + (this.pos + i));
if (chr === '}') {
if (!('literalLength' in this.currentNode)) {
throw new Error('Unexpected literal prefix end char } at position ' + (this.pos + i));
}
if (this.str.charAt(i + 1) === "\n") {
if (this.str.charAt(i + 1) === '\n') {
i++;
} else if (this.str.charAt(i + 1) === "\r" && this.str.charAt(i + 2) === "\n") {
} else if (this.str.charAt(i + 1) === '\r' && this.str.charAt(i + 2) === '\n') {
i += 2;
} else {
throw new Error("Unexpected char at position " + (this.pos + i));
throw new Error('Unexpected char at position ' + (this.pos + i));
}

@@ -566,3 +595,3 @@ this.currentNode.literalLength = Number(this.currentNode.literalLength);

this.currentNode = this.currentNode.parentNode;
this.state = "NORMAL";
this.state = 'NORMAL';
checkSP();

@@ -573,19 +602,19 @@ }

if (imapFormalSyntax.DIGIT().indexOf(chr) < 0) {
throw new Error("Unexpected char at position " + (this.pos + i));
throw new Error('Unexpected char at position ' + (this.pos + i));
}
if (this.currentNode.literalLength === "0") {
throw new Error("Invalid literal at position " + (this.pos + i));
if (this.currentNode.literalLength === '0') {
throw new Error('Invalid literal at position ' + (this.pos + i));
}
this.currentNode.literalLength = (this.currentNode.literalLength || "") + chr;
this.currentNode.literalLength = (this.currentNode.literalLength || '') + chr;
break;
case "SEQUENCE":
case 'SEQUENCE':
// space finishes the sequence set
if (chr === " ") {
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== "*") {
throw new Error("Unexpected whitespace at position " + (this.pos + i));
if (chr === ' ') {
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
throw new Error('Unexpected whitespace at position ' + (this.pos + i));
}
if (this.currentNode.value.substr(-1) === "*" && this.currentNode.value.substr(-2, 1) !== ":") {
throw new Error("Unexpected whitespace at position " + (this.pos + i));
if (this.currentNode.value.substr(-1) === '*' && this.currentNode.value.substr(-2, 1) !== ':') {
throw new Error('Unexpected whitespace at position ' + (this.pos + i));
}

@@ -596,27 +625,40 @@

this.currentNode = this.currentNode.parentNode;
this.state = "NORMAL";
this.state = 'NORMAL';
break;
} else if (this.currentNode.parentNode &&
chr === ']' &&
this.currentNode.parentNode.type === 'SECTION') {
this.currentNode.endPos = this.pos + i - 1;
this.currentNode = this.currentNode.parentNode;
this.currentNode.closed = true;
this.currentNode.endPos = this.pos + i;
this.currentNode = this.currentNode.parentNode;
this.state = 'NORMAL';
checkSP();
break;
}
if (chr === ":") {
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== "*") {
throw new Error("Unexpected range separator : at position " + (this.pos + i));
if (chr === ':') {
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
throw new Error('Unexpected range separator : at position ' + (this.pos + i));
}
} else if (chr === "*") {
if ([",", ":"].indexOf(this.currentNode.value.substr(-1)) < 0) {
throw new Error("Unexpected range wildcard at position " + (this.pos + i));
} else if (chr === '*') {
if ([',', ':'].indexOf(this.currentNode.value.substr(-1)) < 0) {
throw new Error('Unexpected range wildcard at position ' + (this.pos + i));
}
} else if (chr === ",") {
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== "*") {
throw new Error("Unexpected sequence separator , at position " + (this.pos + i));
} else if (chr === ',') {
if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
throw new Error('Unexpected sequence separator , at position ' + (this.pos + i));
}
if (this.currentNode.value.substr(-1) === "*" && this.currentNode.value.substr(-2, 1) !== ":") {
throw new Error("Unexpected sequence separator , at position " + (this.pos + i));
if (this.currentNode.value.substr(-1) === '*' && this.currentNode.value.substr(-2, 1) !== ':') {
throw new Error('Unexpected sequence separator , at position ' + (this.pos + i));
}
} else if (!chr.match(/\d/)) {
throw new Error("Unexpected char at position " + (this.pos + i));
throw new Error('Unexpected char at position ' + (this.pos + i));
}
if (chr.match(/\d/) && this.currentNode.value.substr(-1) === "*") {
throw new Error("Unexpected number at position " + (this.pos + i));
if (chr.match(/\d/) && this.currentNode.value.substr(-1) === '*') {
throw new Error('Unexpected number at position ' + (this.pos + i));
}

@@ -641,5 +683,5 @@

if (["UID", "AUTHENTICATE"].indexOf((response.command || "").toUpperCase()) >= 0) {
if (['UID', 'AUTHENTICATE'].indexOf((response.command || '').toUpperCase()) >= 0) {
parser.getSpace();
response.command += " " + parser.getElement(imapFormalSyntax.command());
response.command += ' ' + parser.getElement(imapFormalSyntax.command());
}

@@ -654,3 +696,3 @@

response.attributes = (response.attributes || []).concat({
type: "TEXT",
type: 'TEXT',
value: parser.humanReadable

@@ -657,0 +699,0 @@ });

(function(root, factory) {
"use strict";
'use strict';
if (typeof define === "function" && define.amd) {
if (typeof define === 'function' && define.amd) {
define(['chai', 'imap-handler'], factory);

@@ -10,3 +10,3 @@ } else if (typeof exports === 'object') {

}(this, function(chai, imapHandler) {
"use strict";
'use strict';

@@ -16,4 +16,4 @@ var expect = chai.expect;

describe("IMAP Command Compiler", function() {
describe("#compile", function() {
describe('IMAP Command Compiler', function() {
describe('#compile', function() {
it('should compile correctly', function() {

@@ -30,3 +30,3 @@ var command = '* FETCH (ENVELOPE ("Mon, 2 Sep 2013 05:30:13 -0700 (PDT)" NIL ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "tr.ee")) NIL NIL NIL "<-4730417346358914070@unknownmsgid>") BODYSTRUCTURE (("MESSAGE" "RFC822" NIL NIL NIL "7BIT" 105 (NIL NIL ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "pangalink.net")) NIL NIL "<test1>" NIL) ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 12 0 NIL NIL NIL) 5 NIL NIL NIL) ("MESSAGE" "RFC822" NIL NIL NIL "7BIT" 83 (NIL NIL ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "pangalink.net")) NIL NIL "NIL" NIL) ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 12 0 NIL NIL NIL) 4 NIL NIL NIL) ("TEXT" "HTML" ("CHARSET" "utf-8") NIL NIL "QUOTED-PRINTABLE" 19 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----mailcomposer-?=_1-1328088797399") NIL NIL))',

describe("Types", function() {
describe('Types', function() {
var parsed;

@@ -36,63 +36,63 @@

parsed = {
tag: "*",
command: "CMD"
tag: '*',
command: 'CMD'
};
});
describe("No attributes", function() {
describe('No attributes', function() {
it('should compile correctly', function() {
expect(imapHandler.compiler(parsed)).to.equal("* CMD");
expect(imapHandler.compiler(parsed)).to.equal('* CMD');
});
});
describe("TEXT", function() {
describe('TEXT', function() {
it('should compile correctly', function() {
parsed.attributes = [{
type: "TEXT",
value: "Tere tere!"
type: 'TEXT',
value: 'Tere tere!'
}];
expect(imapHandler.compiler(parsed)).to.equal("* CMD Tere tere!");
expect(imapHandler.compiler(parsed)).to.equal('* CMD Tere tere!');
});
});
describe("SECTION", function() {
describe('SECTION', function() {
it('should compile correctly', function() {
parsed.attributes = [{
type: "SECTION",
type: 'SECTION',
section: [{
type: "ATOM",
value: "ALERT"
type: 'ATOM',
value: 'ALERT'
}]
}];
expect(imapHandler.compiler(parsed)).to.equal("* CMD [ALERT]");
expect(imapHandler.compiler(parsed)).to.equal('* CMD [ALERT]');
});
});
describe("ATOM", function() {
describe('ATOM', function() {
it('should compile correctly', function() {
parsed.attributes = [{
type: "ATOM",
value: "ALERT"
type: 'ATOM',
value: 'ALERT'
}, {
type: "ATOM",
value: "\\ALERT"
type: 'ATOM',
value: '\\ALERT'
}, {
type: "ATOM",
value: "NO ALERT"
type: 'ATOM',
value: 'NO ALERT'
}];
expect(imapHandler.compiler(parsed)).to.equal("* CMD ALERT \\ALERT \"NO ALERT\"");
expect(imapHandler.compiler(parsed)).to.equal('* CMD ALERT \\ALERT "NO ALERT"');
});
});
describe("SEQUENCE", function() {
describe('SEQUENCE', function() {
it('should compile correctly', function() {
parsed.attributes = [{
type: "SEQUENCE",
value: "*:4,5,6"
type: 'SEQUENCE',
value: '*:4,5,6'
}];
expect(imapHandler.compiler(parsed)).to.equal("* CMD *:4,5,6");
expect(imapHandler.compiler(parsed)).to.equal('* CMD *:4,5,6');
});
});
describe("NIL", function() {
describe('NIL', function() {
it('should compile correctly', function() {

@@ -104,3 +104,3 @@ parsed.attributes = [

expect(imapHandler.compiler(parsed)).to.equal("* CMD NIL NIL");
expect(imapHandler.compiler(parsed)).to.equal('* CMD NIL NIL');

@@ -110,24 +110,59 @@ });

describe("TEXT", function() {
describe('TEXT', function() {
it('should compile correctly', function() {
parsed.attributes = [{
type: "String",
value: "Tere tere!"
type: 'String',
value: 'Tere tere!',
sensitive: true
},
"Vana kere"
'Vana kere'
];
expect(imapHandler.compiler(parsed)).to.equal("* CMD \"Tere tere!\" \"Vana kere\"");
expect(imapHandler.compiler(parsed)).to.equal('* CMD "Tere tere!" "Vana kere"');
});
it('should keep short strings', function() {
parsed.attributes = [{
type: 'String',
value: 'Tere tere!'
},
'Vana kere'
];
expect(imapHandler.compiler(parsed, false, true)).to.equal('* CMD "Tere tere!" "Vana kere"');
});
it('should hide strings', function() {
parsed.attributes = [{
type: 'String',
value: 'Tere tere!',
sensitive: true
},
'Vana kere'
];
expect(imapHandler.compiler(parsed, false, true)).to.equal('* CMD "(* value hidden *)" "Vana kere"');
});
it('should hide long strings', function() {
parsed.attributes = [{
type: 'String',
value: 'Tere tere! Tere tere! Tere tere! Tere tere! Tere tere!'
},
'Vana kere'
];
expect(imapHandler.compiler(parsed, false, true)).to.equal('* CMD "(* 54B string *)" "Vana kere"');
});
});
describe("No Command", function() {
describe('No Command', function() {
it('should compile correctly', function() {
parsed = {
tag: "*",
tag: '*',
attributes: [
1, {
type: "ATOM",
value: "EXPUNGE"
type: 'ATOM',
value: 'EXPUNGE'
}

@@ -137,19 +172,19 @@ ]

expect(imapHandler.compiler(parsed)).to.equal("* 1 EXPUNGE");
expect(imapHandler.compiler(parsed)).to.equal('* 1 EXPUNGE');
});
});
describe("Literal", function() {
describe('Literal', function() {
it('shoud return as text', function() {
var parsed = {
tag: "*",
command: "CMD",
tag: '*',
command: 'CMD',
attributes: [{
type: "LITERAL",
value: "Tere tere!"
type: 'LITERAL',
value: 'Tere tere!'
},
"Vana kere"
'Vana kere'
]
};
expect(imapHandler.compiler(parsed)).to.equal("* CMD {10}\r\nTere tere! \"Vana kere\"");
expect(imapHandler.compiler(parsed)).to.equal('* CMD {10}\r\nTere tere! "Vana kere"');
});

@@ -159,13 +194,13 @@

var parsed = {
tag: "*",
command: "CMD",
tag: '*',
command: 'CMD',
attributes: [{
type: "LITERAL",
value: "Tere tere!"
type: 'LITERAL',
value: 'Tere tere!'
}, {
type: "LITERAL",
value: "Vana kere"
type: 'LITERAL',
value: 'Vana kere'
}]
};
expect(imapHandler.compiler(parsed, true)).to.deep.equal(["* CMD {10}\r\n", "Tere tere! {9}\r\n", "Vana kere"]);
expect(imapHandler.compiler(parsed, true)).to.deep.equal(['* CMD {10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere']);
});

@@ -175,15 +210,15 @@

var parsed = {
tag: "*",
command: "CMD",
tag: '*',
command: 'CMD',
attributes: [{
type: "LITERAL",
value: "Tere tere!"
type: 'LITERAL',
value: 'Tere tere!'
}, {
type: "LITERAL",
value: "Vana kere"
type: 'LITERAL',
value: 'Vana kere'
},
"zzz"
'zzz'
]
};
expect(imapHandler.compiler(parsed, true)).to.deep.equal(["* CMD {10}\r\n", "Tere tere! {9}\r\n", "Vana kere \"zzz\""]);
expect(imapHandler.compiler(parsed, true)).to.deep.equal(['* CMD {10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere "zzz"']);
});

@@ -194,11 +229,26 @@

attributes: [{
type: "LITERAL",
value: "Tere tere!"
type: 'LITERAL',
value: 'Tere tere!'
}, {
type: "LITERAL",
value: "Vana kere"
type: 'LITERAL',
value: 'Vana kere'
}]
};
expect(imapHandler.compiler(parsed, true)).to.deep.equal(["{10}\r\n", "Tere tere! {9}\r\n", "Vana kere"]);
expect(imapHandler.compiler(parsed, true)).to.deep.equal(['{10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere']);
});
it('shoud return byte length', function() {
var parsed = {
tag: '*',
command: 'CMD',
attributes: [{
type: 'LITERAL',
value: 'Tere tere!'
},
'Vana kere'
]
};
expect(imapHandler.compiler(parsed, false, true)).to.equal('* CMD "(* 10B literal *)" "Vana kere"');
});
});

@@ -205,0 +255,0 @@ });

(function(root, factory) {
"use strict";
'use strict';
if (typeof define === "function" && define.amd) {
if (typeof define === 'function' && define.amd) {
define(['chai', 'imap-handler', './fixtures/mimetorture'], factory);

@@ -10,3 +10,3 @@ } else if (typeof exports === 'object') {

}(this, function(chai, imapHandler, mimetorture) {
"use strict";
'use strict';

@@ -16,45 +16,45 @@ var expect = chai.expect;

describe("IMAP Command Parser", function() {
describe('IMAP Command Parser', function() {
describe('get tag', function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD").tag).to.equal("TAG1");
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD').tag).to.equal('TAG1');
});
it("should fail for unexpected WS", function() {
it('should fail for unexpected WS', function() {
expect(function() {
imapHandler.parser(" TAG CMD");
imapHandler.parser(' TAG CMD');
}).to.throw(Error);
});
it("should * OK ", function() {
it('should * OK ', function() {
expect(function() {
imapHandler.parser(" TAG CMD");
imapHandler.parser(' TAG CMD');
}).to.throw(Error);
});
it("should + OK ", function() {
expect(imapHandler.parser("+ TAG CMD").tag).to.equal("+");
it('should + OK ', function() {
expect(imapHandler.parser('+ TAG CMD').tag).to.equal('+');
});
it("should allow untagged", function() {
it('should allow untagged', function() {
expect(function() {
imapHandler.parser("* CMD");
imapHandler.parser('* CMD');
}).to.not.throw(Error);
});
it("should fail for empty tag", function() {
it('should fail for empty tag', function() {
expect(function() {
imapHandler.parser("");
imapHandler.parser('');
}).to.throw(Error);
});
it("should fail for unexpected end", function() {
it('should fail for unexpected end', function() {
expect(function() {
imapHandler.parser("TAG1");
imapHandler.parser('TAG1');
}).to.throw(Error);
});
it("should fail for invalid char", function() {
it('should fail for invalid char', function() {
expect(function() {
imapHandler.parser("TAG\"1 CMD");
imapHandler.parser('TAG"1 CMD');
}).to.throw(Error);

@@ -64,6 +64,6 @@ });

describe("get arguments", function() {
it("should allow trailing whitespace and empty arguments", function() {
describe('get arguments', function() {
it('should allow trailing whitespace and empty arguments', function() {
expect(function() {
imapHandler.parser("* SEARCH ");
imapHandler.parser('* SEARCH ');
}).to.not.throw(Error);

@@ -73,26 +73,26 @@ });

describe("get command", function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD").command).to.equal("CMD");
describe('get command', function() {
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD').command).to.equal('CMD');
});
it("should work for multi word command", function() {
expect(imapHandler.parser("TAG1 UID FETCH").command).to.equal("UID FETCH");
it('should work for multi word command', function() {
expect(imapHandler.parser('TAG1 UID FETCH').command).to.equal('UID FETCH');
});
it("should fail for unexpected WS", function() {
it('should fail for unexpected WS', function() {
expect(function() {
imapHandler.parser("TAG1 CMD");
imapHandler.parser('TAG1 CMD');
}).to.throw(Error);
});
it("should fail for empty command", function() {
it('should fail for empty command', function() {
expect(function() {
imapHandler.parser("TAG1 ");
imapHandler.parser('TAG1 ');
}).to.throw(Error);
});
it("should fail for invalid char", function() {
it('should fail for invalid char', function() {
expect(function() {
imapHandler.parser("TAG1 CM=D");
imapHandler.parser('TAG1 CM=D');
}).to.throw(Error);

@@ -102,45 +102,45 @@ });

describe("get attribute", function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD FED").attributes).to.deep.equal([{
type: "ATOM",
value: "FED"
describe('get attribute', function() {
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD FED').attributes).to.deep.equal([{
type: 'ATOM',
value: 'FED'
}]);
});
it("should succeed for single whitespace between values", function() {
expect(imapHandler.parser("TAG1 CMD FED TED").attributes).to.deep.equal([{
type: "ATOM",
value: "FED"
it('should succeed for single whitespace between values', function() {
expect(imapHandler.parser('TAG1 CMD FED TED').attributes).to.deep.equal([{
type: 'ATOM',
value: 'FED'
}, {
type: "ATOM",
value: "TED"
type: 'ATOM',
value: 'TED'
}]);
});
it("should succeed for ATOM", function() {
expect(imapHandler.parser("TAG1 CMD ABCDE").attributes).to.deep.equal([{
type: "ATOM",
value: "ABCDE"
it('should succeed for ATOM', function() {
expect(imapHandler.parser('TAG1 CMD ABCDE').attributes).to.deep.equal([{
type: 'ATOM',
value: 'ABCDE'
}]);
expect(imapHandler.parser("TAG1 CMD ABCDE DEFGH").attributes).to.deep.equal([{
type: "ATOM",
value: "ABCDE"
expect(imapHandler.parser('TAG1 CMD ABCDE DEFGH').attributes).to.deep.equal([{
type: 'ATOM',
value: 'ABCDE'
}, {
type: "ATOM",
value: "DEFGH"
type: 'ATOM',
value: 'DEFGH'
}]);
expect(imapHandler.parser("TAG1 CMD %").attributes).to.deep.equal([{
type: "ATOM",
value: "%"
expect(imapHandler.parser('TAG1 CMD %').attributes).to.deep.equal([{
type: 'ATOM',
value: '%'
}]);
expect(imapHandler.parser("TAG1 CMD \\*").attributes).to.deep.equal([{
type: "ATOM",
value: "\\*"
expect(imapHandler.parser('TAG1 CMD \\*').attributes).to.deep.equal([{
type: 'ATOM',
value: '\\*'
}]);
expect(imapHandler.parser("12.82 STATUS [Gmail].Trash (UIDNEXT UNSEEN HIGHESTMODSEQ)").attributes).to.deep.equal([{
expect(imapHandler.parser('12.82 STATUS [Gmail].Trash (UIDNEXT UNSEEN HIGHESTMODSEQ)').attributes).to.deep.equal([{
type: 'ATOM',

@@ -162,5 +162,5 @@ value: '[Gmail].Trash'

it("should not succeed for ATOM", function() {
it('should not succeed for ATOM', function() {
expect(function() {
imapHandler.parser("TAG1 CMD \\*a");
imapHandler.parser('TAG1 CMD \\*a');
}).to.throw(Error);

@@ -171,119 +171,150 @@ });

describe('get string', function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD \"ABCDE\"").attributes).to.deep.equal([{
type: "STRING",
value: "ABCDE"
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD "ABCDE"').attributes).to.deep.equal([{
type: 'STRING',
value: 'ABCDE'
}]);
expect(imapHandler.parser("TAG1 CMD \"ABCDE\" \"DEFGH\"").attributes).to.deep.equal([{
type: "STRING",
value: "ABCDE"
expect(imapHandler.parser('TAG1 CMD "ABCDE" "DEFGH"').attributes).to.deep.equal([{
type: 'STRING',
value: 'ABCDE'
}, {
type: "STRING",
value: "DEFGH"
type: 'STRING',
value: 'DEFGH'
}]);
});
it('should not explode on invalid char', function() {
expect(imapHandler.parser('* 1 FETCH (BODY[] "\xc2")').attributes).to.deep.equal([{
type: 'ATOM',
value: 'FETCH'
},
[{
type: 'ATOM',
value: 'BODY',
section: []
}, {
type: 'STRING',
value: '\xc2'
}]
]);
});
});
describe('get list', function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD (1234)").attributes).to.deep.equal([
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD (1234)').attributes).to.deep.equal([
[{
type: "ATOM",
value: "1234"
type: 'ATOM',
value: '1234'
}]
]);
expect(imapHandler.parser("TAG1 CMD (1234 TERE)").attributes).to.deep.equal([
expect(imapHandler.parser('TAG1 CMD (1234 TERE)').attributes).to.deep.equal([
[{
type: "ATOM",
value: "1234"
type: 'ATOM',
value: '1234'
}, {
type: "ATOM",
value: "TERE"
type: 'ATOM',
value: 'TERE'
}]
]);
expect(imapHandler.parser("TAG1 CMD (1234)(TERE)").attributes).to.deep.equal([
expect(imapHandler.parser('TAG1 CMD (1234)(TERE)').attributes).to.deep.equal([
[{
type: "ATOM",
value: "1234"
type: 'ATOM',
value: '1234'
}],
[{
type: "ATOM",
value: "TERE"
type: 'ATOM',
value: 'TERE'
}]
]);
expect(imapHandler.parser("TAG1 CMD ( 1234)").attributes).to.deep.equal([
expect(imapHandler.parser('TAG1 CMD ( 1234)').attributes).to.deep.equal([
[{
type: "ATOM",
value: "1234"
type: 'ATOM',
value: '1234'
}]
]);
expect(imapHandler.parser("TAG1 CMD (1234) ").attributes).to.deep.equal([
// Trailing whitespace in a BODYSTRUCTURE atom list has been
// observed on yahoo.co.jp's
expect(imapHandler.parser('TAG1 CMD (1234 )').attributes).to.deep.equal([
[{
type: "ATOM",
value: "1234"
type: 'ATOM',
value: '1234'
}]
]);
expect(imapHandler.parser('TAG1 CMD (1234) ').attributes).to.deep.equal([
[{
type: 'ATOM',
value: '1234'
}]
]);
});
it("should fail", function() {
expect(function() {
imapHandler.parser("TAG1 CMD (1234 )");
}).to.throw(Error);
});
});
describe('nested list', function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD (((TERE)) VANA)").attributes).to.deep.equal([
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD (((TERE)) VANA)').attributes).to.deep.equal([
[
[
[{
type: "ATOM",
value: "TERE"
type: 'ATOM',
value: 'TERE'
}]
], {
type: "ATOM",
value: "VANA"
type: 'ATOM',
value: 'VANA'
}
]
]);
expect(imapHandler.parser("TAG1 CMD (( (TERE)) VANA)").attributes).to.deep.equal([
expect(imapHandler.parser('TAG1 CMD (( (TERE)) VANA)').attributes).to.deep.equal([
[
[
[{
type: "ATOM",
value: "TERE"
type: 'ATOM',
value: 'TERE'
}]
], {
type: "ATOM",
value: "VANA"
type: 'ATOM',
value: 'VANA'
}
]
]);
expect(imapHandler.parser('TAG1 CMD (((TERE) ) VANA)').attributes).to.deep.equal([
[
[
[{
type: 'ATOM',
value: 'TERE'
}]
], {
type: 'ATOM',
value: 'VANA'
}
]
]);
});
});
describe("get literal", function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD {4}\r\nabcd").attributes).to.deep.equal([{
type: "LITERAL",
value: "abcd"
describe('get literal', function() {
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD {4}\r\nabcd').attributes).to.deep.equal([{
type: 'LITERAL',
value: 'abcd'
}]);
expect(imapHandler.parser("TAG1 CMD {4}\r\nabcd {4}\r\nkere").attributes).to.deep.equal([{
type: "LITERAL",
value: "abcd"
expect(imapHandler.parser('TAG1 CMD {4}\r\nabcd {4}\r\nkere').attributes).to.deep.equal([{
type: 'LITERAL',
value: 'abcd'
}, {
type: "LITERAL",
value: "kere"
type: 'LITERAL',
value: 'kere'
}]);
expect(imapHandler.parser("TAG1 CMD ({4}\r\nabcd {4}\r\nkere)").attributes).to.deep.equal([
expect(imapHandler.parser('TAG1 CMD ({4}\r\nabcd {4}\r\nkere)').attributes).to.deep.equal([
[{
type: "LITERAL",
value: "abcd"
type: 'LITERAL',
value: 'abcd'
}, {
type: "LITERAL",
value: "kere"
type: 'LITERAL',
value: 'kere'
}]

@@ -293,5 +324,5 @@ ]);

it("should fail", function() {
it('should fail', function() {
expect(function() {
imapHandler.parser("TAG1 CMD {4}\r\nabcd{4} \r\nkere");
imapHandler.parser('TAG1 CMD {4}\r\nabcd{4} \r\nkere');
}).to.throw(Error);

@@ -301,6 +332,6 @@ });

it('should allow zero length literal in the end of a list', function() {
expect(imapHandler.parser("TAG1 CMD ({0}\r\n)").attributes).to.deep.equal([
expect(imapHandler.parser('TAG1 CMD ({0}\r\n)').attributes).to.deep.equal([
[{
type: "LITERAL",
value: ""
type: 'LITERAL',
value: ''
}]

@@ -312,16 +343,16 @@ ]);

describe("ATOM Section", function() {
it("should succeed", function() {
expect(imapHandler.parser("TAG1 CMD BODY[]").attributes).to.deep.equal([{
type: "ATOM",
value: "BODY",
describe('ATOM Section', function() {
it('should succeed', function() {
expect(imapHandler.parser('TAG1 CMD BODY[]').attributes).to.deep.equal([{
type: 'ATOM',
value: 'BODY',
section: []
}]);
expect(imapHandler.parser("TAG1 CMD BODY[(KERE)]").attributes).to.deep.equal([{
type: "ATOM",
value: "BODY",
expect(imapHandler.parser('TAG1 CMD BODY[(KERE)]').attributes).to.deep.equal([{
type: 'ATOM',
value: 'BODY',
section: [
[{
type: "ATOM",
value: "KERE"
type: 'ATOM',
value: 'KERE'
}]

@@ -331,45 +362,112 @@ ]

});
it("should fail where default BODY and BODY.PEEK are allowed to have sections", function() {});
it('will not fail due to trailing whitespace', function() {
// We intentionally have trailing whitespace in the section here
// because we altered the parser to handle this when we made it
// legal for lists and it makes sense to accordingly test it.
// However, we have no recorded incidences of this happening in
// reality (unlike for lists).
expect(imapHandler.parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From) ]').attributes).to.deep.equal([{
type: 'ATOM',
value: 'BODY',
section: [{
type: 'ATOM',
value: 'HEADER.FIELDS'
},
[{
type: 'ATOM',
value: 'Subject'
}, {
type: 'ATOM',
value: 'From'
}]
]
}]);
});
it('should fail where default BODY and BODY.PEEK are allowed to have sections', function() {});
expect(function() {
imapHandler.parser("TAG1 CMD KODY[]");
imapHandler.parser('TAG1 CMD KODY[]');
}).to.throw(Error);
});
describe("Human readable", function() {
describe('Human readable', function() {
it('should succeed', function() {
expect(imapHandler.parser("* OK [CAPABILITY IDLE] Hello world!")).to.deep.equal({
command: "OK",
tag: "*",
expect(imapHandler.parser('* OK [CAPABILITY IDLE] Hello world!')).to.deep.equal({
command: 'OK',
tag: '*',
attributes: [{
section: [{
type: "ATOM",
value: "CAPABILITY"
type: 'ATOM',
value: 'CAPABILITY'
}, {
type: "ATOM",
value: "IDLE"
type: 'ATOM',
value: 'IDLE'
}],
type: "ATOM",
value: ""
type: 'ATOM',
value: ''
}, {
type: "TEXT",
value: "Hello world!"
type: 'TEXT',
value: 'Hello world!'
}]
});
expect(imapHandler.parser("* OK Hello world!")).to.deep.equal({
command: "OK",
tag: "*",
expect(imapHandler.parser('* OK Hello world!')).to.deep.equal({
command: 'OK',
tag: '*',
attributes: [{
type: "TEXT",
value: "Hello world!"
type: 'TEXT',
value: 'Hello world!'
}]
});
expect(imapHandler.parser("* OK")).to.deep.equal({
command: "OK",
tag: "*"
expect(imapHandler.parser('* OK')).to.deep.equal({
command: 'OK',
tag: '*'
});
expect(imapHandler.parser("* OK [PERMANENTFLAGS (de:hacking $label kt-evalution [css3-page] \\*)] Flags permitted.")).to.deep.equal({
// USEATTR is from RFC6154; we are testing that just an ATOM
// on its own will parse successfully here. (All of the
// RFC5530 codes are also single atoms.)
expect(imapHandler.parser('TAG1 OK [USEATTR] \\All not supported')).to.deep.equal({
tag: 'TAG1',
command: 'OK',
attributes: [{
type: 'ATOM',
value: '',
section: [{
type: 'ATOM',
value: 'USEATTR'
}]
}, {
type: 'TEXT',
value: '\\All not supported'
}]
});
// RFC5267 defines the NOUPDATE error. Including for quote /
// string coverage.
expect(imapHandler.parser('* NO [NOUPDATE "B02"] Too many contexts')).to.deep.equal({
tag: '*',
command: 'NO',
attributes: [{
type: 'ATOM',
value: '',
section: [{
type: 'ATOM',
value: 'NOUPDATE'
}, {
type: 'STRING',
value: 'B02'
}]
}, {
type: 'TEXT',
value: 'Too many contexts'
}]
});
// RFC5464 defines the METADATA response code; adding this to
// ensure the transition for when '2199' hits ']' is handled
// safely.
expect(imapHandler.parser('TAG1 OK [METADATA LONGENTRIES 2199] GETMETADATA complete')).to.deep.equal({
tag: 'TAG1',
command: 'OK',

@@ -380,2 +478,78 @@ attributes: [{

section: [{
type: 'ATOM',
value: 'METADATA'
}, {
type: 'ATOM',
value: 'LONGENTRIES'
}, {
type: 'ATOM',
value: '2199'
}]
}, {
type: 'TEXT',
value: 'GETMETADATA complete'
}]
});
// RFC4467 defines URLMECH. Included because of the example
// third atom involves base64-encoding which is somewhat unusual
expect(imapHandler.parser('TAG1 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done')).to.deep.equal({
tag: 'TAG1',
command: 'OK',
attributes: [{
type: 'ATOM',
value: '',
section: [{
type: 'ATOM',
value: 'URLMECH'
}, {
type: 'ATOM',
value: 'INTERNAL'
}, {
type: 'ATOM',
value: 'XSAMPLE=P34OKhO7VEkCbsiYY8rGEg=='
}]
}, {
type: 'TEXT',
value: 'done'
}]
});
// RFC2221 defines REFERRAL where the argument is an imapurl
// (defined by RFC2192 which is obsoleted by RFC5092) which
// is significantly more complicated than the rest of the IMAP
// grammar and which was based on the RFC2060 grammar where
// resp_text_code included:
// atom [SPACE 1*<any TEXT_CHAR except ']'>]
// So this is just a test case of our explicit special-casing
// of REFERRAL.
expect(imapHandler.parser('TAG1 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/] Remote Server')).to.deep.equal({
tag: 'TAG1',
command: 'NO',
attributes: [{
type: 'ATOM',
value: '',
section: [{
type: 'ATOM',
value: 'REFERRAL'
}, {
type: 'ATOM',
value: 'IMAP://user;AUTH=*@SERVER2/'
}]
}, {
type: 'TEXT',
value: 'Remote Server'
}]
});
// PERMANENTFLAGS is from RFC3501. Its syntax is also very
// similar to BADCHARSET, except BADCHARSET has astrings
// inside the list.
expect(imapHandler.parser('* OK [PERMANENTFLAGS (de:hacking $label kt-evalution [css3-page] \\*)] Flags permitted.')).to.deep.equal({
tag: '*',
command: 'OK',
attributes: [{
type: 'ATOM',
value: '',
section: [{
type: 'ATOM',

@@ -406,22 +580,74 @@ value: 'PERMANENTFLAGS'

});
// COPYUID is from RFC4315 and included the previously failing
// parsing situation of a sequence terminated by ']' rather than
// whitespace.
expect(imapHandler.parser('TAG1 OK [COPYUID 4 1417051618:1417051620 1421730687:1421730689] COPY completed')).to.deep.equal({
tag: 'TAG1',
command: 'OK',
attributes: [{
type: 'ATOM',
value: '',
section: [{
type: 'ATOM',
value: 'COPYUID'
}, {
type: 'ATOM',
value: '4'
}, {
type: 'SEQUENCE',
value: '1417051618:1417051620'
}, {
type: 'SEQUENCE',
value: '1421730687:1421730689'
}]
}, {
type: 'TEXT',
value: 'COPY completed'
}]
});
// MODIFIED is from RFC4551 and is basically the same situation
// as the COPYUID case, but in this case our example sequences
// have commas in them. (Note that if there was no comma, the
// '7,9' payload would end up an ATOM.)
expect(imapHandler.parser('TAG1 OK [MODIFIED 7,9] Conditional STORE failed')).to.deep.equal({
tag: 'TAG1',
command: 'OK',
attributes: [{
type: 'ATOM',
value: '',
section: [{
type: 'ATOM',
value: 'MODIFIED'
}, {
type: 'SEQUENCE',
value: '7,9'
}]
}, {
type: 'TEXT',
value: 'Conditional STORE failed'
}]
});
});
});
describe("ATOM Partial", function() {
describe('ATOM Partial', function() {
it('should succeed', function() {
expect(imapHandler.parser("TAG1 CMD BODY[]<0>").attributes).to.deep.equal([{
type: "ATOM",
value: "BODY",
expect(imapHandler.parser('TAG1 CMD BODY[]<0>').attributes).to.deep.equal([{
type: 'ATOM',
value: 'BODY',
section: [],
partial: [0]
}]);
expect(imapHandler.parser("TAG1 CMD BODY[]<12.45>").attributes).to.deep.equal([{
type: "ATOM",
value: "BODY",
expect(imapHandler.parser('TAG1 CMD BODY[]<12.45>').attributes).to.deep.equal([{
type: 'ATOM',
value: 'BODY',
section: [],
partial: [12, 45]
}]);
expect(imapHandler.parser("TAG1 CMD BODY[HEADER.FIELDS (Subject From)]<12.45>").attributes).to.deep.equal([{
type: "ATOM",
value: "BODY",
expect(imapHandler.parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From)]<12.45>').attributes).to.deep.equal([{
type: 'ATOM',
value: 'BODY',
section: [{

@@ -432,7 +658,7 @@ type: 'ATOM',

[{
type: "ATOM",
value: "Subject"
type: 'ATOM',
value: 'Subject'
}, {
type: "ATOM",
value: "From"
type: 'ATOM',
value: 'From'
}]

@@ -446,19 +672,19 @@ ],

expect(function() {
imapHandler.parser("TAG1 CMD KODY<0.123>");
imapHandler.parser('TAG1 CMD KODY<0.123>');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD BODY[]<123.0>");
imapHandler.parser('TAG1 CMD BODY[]<123.0>');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD BODY[]<01>");
imapHandler.parser('TAG1 CMD BODY[]<01>');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD BODY[]<0.01>");
imapHandler.parser('TAG1 CMD BODY[]<0.01>');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD BODY[]<0.1.>");
imapHandler.parser('TAG1 CMD BODY[]<0.1.>');
}).to.throw(Error);

@@ -468,26 +694,26 @@ });

describe("SEQUENCE", function() {
describe('SEQUENCE', function() {
it('should succeed', function() {
expect(imapHandler.parser("TAG1 CMD *:4,5:7 TEST").attributes).to.deep.equal([{
type: "SEQUENCE",
value: "*:4,5:7"
expect(imapHandler.parser('TAG1 CMD *:4,5:7 TEST').attributes).to.deep.equal([{
type: 'SEQUENCE',
value: '*:4,5:7'
}, {
type: "ATOM",
value: "TEST"
type: 'ATOM',
value: 'TEST'
}]);
expect(imapHandler.parser("TAG1 CMD 1:* TEST").attributes).to.deep.equal([{
type: "SEQUENCE",
value: "1:*"
expect(imapHandler.parser('TAG1 CMD 1:* TEST').attributes).to.deep.equal([{
type: 'SEQUENCE',
value: '1:*'
}, {
type: "ATOM",
value: "TEST"
type: 'ATOM',
value: 'TEST'
}]);
expect(imapHandler.parser("TAG1 CMD *:4 TEST").attributes).to.deep.equal([{
type: "SEQUENCE",
value: "*:4"
expect(imapHandler.parser('TAG1 CMD *:4 TEST').attributes).to.deep.equal([{
type: 'SEQUENCE',
value: '*:4'
}, {
type: "ATOM",
value: "TEST"
type: 'ATOM',
value: 'TEST'
}]);

@@ -498,27 +724,27 @@ });

expect(function() {
imapHandler.parser("TAG1 CMD *:4,5:");
imapHandler.parser('TAG1 CMD *:4,5:');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD *:4,5:TEST TEST");
imapHandler.parser('TAG1 CMD *:4,5:TEST TEST');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD *:4,5: TEST");
imapHandler.parser('TAG1 CMD *:4,5: TEST');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD *4,5 TEST");
imapHandler.parser('TAG1 CMD *4,5 TEST');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD *,5 TEST");
imapHandler.parser('TAG1 CMD *,5 TEST');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD 5,* TEST");
imapHandler.parser('TAG1 CMD 5,* TEST');
}).to.throw(Error);
expect(function() {
imapHandler.parser("TAG1 CMD 5, TEST");
imapHandler.parser('TAG1 CMD 5, TEST');
}).to.throw(Error);

@@ -528,15 +754,15 @@ });

describe("Escaped quotes", function() {
describe('Escaped quotes', function() {
it('should succeed', function() {
expect(imapHandler.parser('* 331 FETCH (ENVELOPE ("=?ISO-8859-1?Q?\\"G=FCnter__Hammerl\\"?="))').attributes).to.deep.equal([{
type: "ATOM",
value: "FETCH"
type: 'ATOM',
value: 'FETCH'
},
[{
type: "ATOM",
value: "ENVELOPE"
type: 'ATOM',
value: 'ENVELOPE'
},
[{
type: "STRING",
value: "=?ISO-8859-1?Q?\"G=FCnter__Hammerl\"?="
type: 'STRING',
value: '=?ISO-8859-1?Q?"G=FCnter__Hammerl"?='
}]

@@ -543,0 +769,0 @@ ]

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc