Skip to content

Commit

Permalink
Implement UIDPLUS and MOVE plugins.
Browse files Browse the repository at this point in the history
  • Loading branch information
asutherland committed Jan 28, 2016
1 parent b487340 commit 0fbfbe9
Show file tree
Hide file tree
Showing 10 changed files with 533 additions and 28 deletions.
6 changes: 3 additions & 3 deletions lib/commands/append.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ module.exports = function(connection, parsed, data, callback) {
return callback();
}

connection.server.appendMessage(mailbox, (flags || []).map(function(flag) {
var appendResult = connection.server.appendMessage(mailbox, (flags || []).map(function(flag) {
return flag.value;
}), internaldate && internaldate.value, raw.value, connection);

Expand All @@ -99,6 +99,6 @@ module.exports = function(connection, parsed, data, callback) {
type: "TEXT",
value: "APPEND Completed"
}]
}, "APPEND", parsed, data);
}, "APPEND", parsed, data, appendResult);
callback();
};
};
17 changes: 14 additions & 3 deletions lib/commands/copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,32 @@ module.exports = function(connection, parsed, data, callback) {
return callback();
}

var sourceUids = [],
targetUids = [];
range.forEach(function(rangeMessage) {
var message = rangeMessage[1],
flags = [].concat(message.flags || []),
internaldate = message.internaldate;
sourceUids.push(message.uid);

connection.server.appendMessage(mailbox, flags, internaldate, message.raw, connection);
var appendResult = connection.server.appendMessage(mailbox, flags, internaldate, message.raw, connection);
targetUids.push(appendResult.message.uid);
});

// Create extra context info for UIDPLUS
var extra = {
mailbox: mailbox,
sourceUids: sourceUids,
targetUids: targetUids
};

connection.send({
tag: parsed.tag,
command: "OK",
attributes: [{
type: "TEXT",
value: "COPY Completed"
}]
}, "COPY", parsed, data);
}, "COPY", parsed, data, extra);
callback();
};
};
19 changes: 15 additions & 4 deletions lib/commands/uid copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,36 @@ module.exports = function(connection, parsed, data, callback) {
type: "TEXT",
value: "Target mailbox does not exist"
}]
}, "COPY FAIL", parsed, data);
}, "UID COPY FAIL", parsed, data);
return callback();
}

var sourceUids = [],
targetUids = [];
range.forEach(function(rangeMessage) {
var message = rangeMessage[1],
flags = [].concat(message.flags || []),
internaldate = message.internaldate;
sourceUids.push(message.uid);

connection.server.appendMessage(mailbox, flags, internaldate, message.raw, connection);
var appendResult = connection.server.appendMessage(mailbox, flags, internaldate, message.raw, connection);
targetUids.push(appendResult.message.uid);
});

// Create extra context info for UIDPLUS
var extra = {
mailbox: mailbox,
sourceUids: sourceUids,
targetUids: targetUids
};

connection.send({
tag: parsed.tag,
command: "OK",
attributes: [{
type: "TEXT",
value: "UID COPY Completed"
}]
}, "UID COPY", parsed, data);
}, "UID COPY", parsed, data, extra);
callback();
};
};
2 changes: 1 addition & 1 deletion lib/mock-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,4 @@ function runClientMockup(port, host, commands, debug, callback) {
}
});
});
}
}
2 changes: 1 addition & 1 deletion lib/plugins/condstore.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,4 +257,4 @@ function getCondstoreValue(attributes, name, parent, index) {
}

return condstoreValue;
}
}
112 changes: 112 additions & 0 deletions lib/plugins/move.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"use strict";

/**
* MOVE: http://tools.ietf.org/html/rfc6851
*
* Additional commands:
* - MOVE
* - UID MOVE
*/
module.exports = function(server) {
server.registerCapability("MOVE");

var moveHandler = function(uidMode, connection, parsed, data, callback) {
function uidify(str) {
if (uidMode) {
return "UID " + str;
}
return str;
}

if (!parsed.attributes ||
parsed.attributes.length !== 2 ||
!parsed.attributes[0] ||
["ATOM", "SEQUENCE"].indexOf(parsed.attributes[0].type) < 0 ||
!parsed.attributes[1] ||
["ATOM", "STRING"].indexOf(parsed.attributes[1].type) < 0
) {
connection.send({
tag: parsed.tag,
command: "BAD",
attributes: [{
type: "TEXT",
value: uidify("MOVE expects sequence set and a mailbox name")
}]
}, "INVALID COMMAND", parsed, data);
return callback();
}

if (["Selected"].indexOf(connection.state) < 0) {
connection.send({
tag: parsed.tag,
command: "BAD",
attributes: [{
type: "TEXT",
value: "Select mailbox first"
}]
}, uidify("MOVE FAILED"), parsed, data);
return callback();
}

var sequence = parsed.attributes[0].value,
path = parsed.attributes[1].value,
mailbox = connection.server.getMailbox(path),
range = connection.server.getMessageRange(connection.selectedMailbox, sequence, uidMode);

if (!mailbox) {
connection.send({
tag: parsed.tag,
command: "NO",
attributes: [{
type: "TEXT",
value: "Target mailbox does not exist"
}]
}, uidify("MOVE FAIL"), parsed, data);
return callback();
}

var rangeMessages = range.map(function(x) { return x[1]; });

var sourceUids = [],
targetUids = [];
rangeMessages.forEach(function(message) {
var flags = [].concat(message.flags || []),
internaldate = message.internaldate;
sourceUids.push(message.uid);

var appendResult = connection.server.appendMessage(mailbox, flags, internaldate, message.raw, connection);
targetUids.push(appendResult.message.uid);
});

// Hook for UIDPLUS to generate the untagged COPYUID response (that wants
// to happen prior to the EXPUNGEs). If the UIDPLUS extension is not
// active, this ill not happen.
var extra = {
mailbox: mailbox,
sourceUids: sourceUids,
targetUids: targetUids
};
connection.send({
tag: "*",
command: "OK",
attributes: [],
skipResponse: true
}, uidify("MOVE COPYUID"), parsed, data, extra);

// Expunge the messages from the source folder.
connection.expungeSpecificMessages(connection.selectedMailbox, rangeMessages, false, true);

connection.send({
tag: parsed.tag,
command: "OK",
attributes: [{
type: "TEXT",
value: "Done"
}]
}, uidify("MOVE OK"), parsed, data);
callback();
};

server.setCommandHandler("MOVE", moveHandler.bind(null, false));
server.setCommandHandler("UID MOVE", moveHandler.bind(null, true));
};
110 changes: 110 additions & 0 deletions lib/plugins/uidplus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"use strict";

/**
* UIDPLUS: http://tools.ietf.org/html/rfc4315
*
* Additional commands:
* - UID EXPUNGE
*
* Additional response codes:
* - APPENDUID
* - COPYUID
* - Not implemented: UIDNOTSTICKY
*/
module.exports = function(server) {
server.registerCapability("UIDPLUS");

server.setCommandHandler("UID EXPUNGE", function(connection, parsed, data, callback) {
if (!parsed.attributes ||
parsed.attributes.length !== 1 ||
!parsed.attributes[0] ||
["ATOM", "SEQUENCE"].indexOf(parsed.attributes[0].type) < 0
) {
connection.send({
tag: parsed.tag,
command: "BAD",
attributes: [{
type: "TEXT",
value: "UID EXPUNGE expects uid sequence set"
}]
}, "INVALID COMMAND", parsed, data);
return callback();
}

if (["Selected"].indexOf(connection.state) < 0) {
connection.send({
tag: parsed.tag,
command: "BAD",
attributes: [{
type: "TEXT",
value: "Select mailbox first"
}]
}, "COPY FAILED", parsed, data);
return callback();
}

var sequence = parsed.attributes[0].value,
range = connection.server.getMessageRange(connection.selectedMailbox, sequence, true),
rangeMessages = range.map(function(x) { return x[1]; });

connection.expungeSpecificMessages(connection.selectedMailbox, rangeMessages, false, true);

connection.send({
tag: parsed.tag,
command: "OK",
attributes: [{
type: "TEXT",
value: "UID EXPUNGE completed"
}]
}, "UID EXPUNGE", parsed, data);
callback();
});

server.outputHandlers.push(function(connection, response, description, parsed, data, extra) {
if (description === "APPEND") {
// The final response should be of the form:
// OK [APPENDUID <target-mailbox-uidvalidity> <uid>] APPEND Completed
response.attributes = [
{
type: "SECTION",
section: [
{
type: "ATOM",
value: "APPENDUID"
},
extra.mailbox.uidvalidity,
extra.message.uid
]
}
].concat(response.attributes);
return;
}

if (description === "COPY" || description === "UID COPY" ||
description === "MOVE COPYUID" || description === "UID MOVE COPYUID") {
response.attributes = [
{
type: "SECTION",
section: [
{
type: "ATOM",
value: "COPYUID"
},
extra.mailbox.uidvalidity,
// The range was interpreted in ascending order so these
// values are already in the right order.
{
type: "SEQUENCE",
value: extra.sourceUids.join(",")
}, {
type: "SEQUENCE",
value: extra.targetUids.join(",")
}
]
}
].concat(response.attributes);
response.skipResponse = false;
return;
}
});
};
Loading

0 comments on commit 0fbfbe9

Please sign in to comment.