Added node-modules

This commit is contained in:
Dobie Wollert
2014-09-14 07:04:16 -04:00
parent 663941bf57
commit 6a92348cf5
4870 changed files with 670395 additions and 0 deletions

416
node_modules/emailjs/smtp/address.js generated vendored Normal file
View File

@ -0,0 +1,416 @@
/*
* Email address parsing code.
* rewritten with python's (2.7) email/_parseaddr.py as the starting point
*/
var SPACE = ' ';
var EMPTYSTRING = '';
var COMMASPACE = ', ';
var quote = function(str)
{
// Add quotes around a string.
return str.replace(/\\\\/g, '\\\\').replace(/"/g, '\\"');
};
/*
* To understand what this class does, it helps to have a copy of RFC 2822 in
* front of you.
*/
var Address = function(field)
{
/*
* Initialize a new instance.
* `field' is an unparsed address header field, containing
* one or more addresses.
*/
this.specials = '()<>@,:;.\"[]';
this.pos = 0;
this.LWS = ' \t';
this.CR = '\r\n';
this.FWS = this.LWS + this.CR;
this.atomends = this.specials + this.LWS + this.CR;
// Note that RFC 2822 now specifies `.' as obs-phrase, meaning that it
// is obsolete syntax. RFC 2822 requires that we recognize obsolete
// syntax, so allow dots in phrases.
this.phraseends = this.atomends.replace(/\./g, '');
this.field = field || "";
this.commentlist = [];
};
Address.prototype =
{
gotonext: function()
{
//Parse up to the start of the next address.
while(this.pos < this.field.length)
{
if((this.LWS + '\n\r').indexOf(this.field[this.pos]) != -1)
this.pos++;
else if(this.field[this.pos] == '(')
this.commentlist.push(this.getcomment());
else
break;
}
},
getlist: function()
{
// Parse all addresses. Returns a list containing all of the addresses
var result = [], ad;
while(this.pos < this.field.length)
{
ad = this.get();
if(ad)
result.push(ad);
else
result.push({label:'', address:''});
}
return result;
},
get: function()
{
// Parse the next address
this.commentlist = [];
this.gotonext();
var oldpos = this.pos, oldcl = this.commentlist, plist = this.getphraselist(), returnlist = [],
addrspec, fieldlen, routeaddr;
this.gotonext();
if(this.pos >= this.field.length)
{
// Bad email address, no domain
if(plist.length)
returnlist = {label:this.commentlist.join(SPACE), address:plist[0]};
}
else if('.@'.indexOf(this.field[this.pos]) != -1)
{
// email address is just an addrspec
// this isn't very efficient since we start over
this.pos = oldpos;
this.commentlist = oldcl;
addrspec = this.getspec();
returnlist = {label:this.commentlist.join(SPACE), address:addrspec};
}
else if(this.field[this.pos] == ':')
{
// address is a group
returnlist = [];
fieldlen = this.field.length;
this.pos++;
while(this.pos < this.field.length)
{
this.gotonext();
if(this.pos < fieldlen && this.field[this.pos] == ';')
{
this.pos += 1;
break;
}
returnlist = returnlist.push(this.get());
}
}
else if(this.field[this.pos] == '<')
{
// Address is a prhase then a route addr
routeaddr = this.getroute();
if(this.commentlist.length)
returnlist = {label:plist.join(SPACE) + ' (' + this.commentlist.join(SPACE) + ')', address:routeaddr};
else
returnlist = {label:plist.join(SPACE), address:routeaddr};
}
else
{
if(plist.length)
returnlist = {label:this.commentlist.join(SPACE), address:plist[0]};
else if(this.specials.indexOf(this.field[this.pos]) != -1)
this.pos++;
}
this.gotonext();
if(this.pos < this.field.length && this.field[this.pos] == ',')
this.pos++;
return returnlist;
},
getroute: function()
{
// Parse a route address. this method skips all route stuff and returns addrspec
if(this.field[this.pos] != '<')
return '';
var expectroute = false, adlist = '';
this.pos++;
this.gotonext();
while(this.pos < this.field.length)
{
if(expectroute)
{
this.getdomain();
expectroute = false;
}
else if(this.field[this.pos] == '>')
{
this.pos += 1;
break;
}
else if(this.field[this.pos] == '@')
{
this.pos += 1;
expectroute = true;
}
else if(this.field[this.pos] == ':')
{
this.pos++;
}
else
{
adlist = this.getspec();
this.pos++;
break;
}
this.gotonext();
}
return adlist;
},
getspec: function()
{
//parse an RFC 2822 addr-spec
var aslist = [];
this.gotonext();
while(this.pos < this.field.length)
{
if(this.field[this.pos] == '.')
{
aslist.push('.');
this.pos++;
}
else if(this.field[this.pos] == '"')
aslist.push('"' + this.getquote() + '"');
else if(this.atomends.indexOf(this.field[this.pos]) != -1)
break;
else
aslist.push(this.getatom());
this.gotonext();
}
if(this.pos >= this.field.length || this.field[this.pos] != '@')
return aslist.join(EMPTYSTRING);
aslist.push('@');
this.pos++;
this.gotonext();
return aslist.join(EMPTYSTRING) + this.getdomain();
},
getdomain: function()
{
// get the complete domain name from an address
var sdlist = [];
while(this.pos < this.field.length)
{
if(this.LWS.indexOf(this.field[this.pos]) != -1)
this.pos++;
else if(this.field[this.pos] == '(')
this.commentlist.push(this.getcomment());
else if(this.field[this.pos] == '[')
sdlist.push(this.getdomainliteral());
else if(this.field[this.pos] == '.')
{
this.pos++;
sdlist.push('.');
}
else if(this.atomends.indexOf(this.field[this.pos]) != -1)
break;
else
sdlist.push(this.getatom());
}
return sdlist.join(EMPTYSTRING);
},
getdelimited: function(beginchar, endchars, allowcomments)
{
/*
* Parse a header fragment delimited by special characters.
*
* `beginchar' is the start character for the fragment.
* If self is not looking at an instance of `beginchar' then
* getdelimited returns the empty string.
*
* `endchars' is a sequence of allowable end-delimiting characters.
* Parsing stops when one of these is encountered.
*
* If `allowcomments' is non-zero, embedded RFC 2822 comments are allowed
* within the parsed fragment.
*/
if(this.field[this.pos] != beginchar)
return '';
allowcomments = (allowcomments === false) ? false : true;
var slist = [''], quote = false;
this.pos++;
while(this.pos < this.field.length)
{
if(quote)
{
slist.push(this.field[this.pos]);
quote = false;
}
else if(endchars.indexOf(this.field[this.pos]) != -1)
{
this.pos++;
break;
}
else if(allowcomments && this.field[this.pos] == '(')
{
slist.push(this.getcomment());
continue;
}
else if(this.field[this.pos] == '\\')
quote = true;
else
slist.push(this.field[this.pos]);
this.pos++;
}
return slist.join(EMPTYSTRING);
},
getquote: function()
{
// get a quote-delimited fragment from self's field
return this.getdelimited('"', '"\r', false);
},
getcomment: function()
{
// Get a parenthesis-delimited fragment from self's field.
return this.getdelimited('(', ')\r', true);
},
getdomainliteral: function()
{
// parse an rfc 2822 domain literal
return '[' + this.getdelimited('[', ']\r', false) + ']';
},
getatom: function(atomends)
{
/*
* Parse an RFC 2822 atom.
*
* Optional atomends specifies a different set of end token delimiters
* (the default is to use this.atomends). This is used e.g. in
* getphraselist() since phrase endings must not include the `.' (which
* is legal in phrases).
*/
var atomlist = [''];
if(atomends === undefined)
atomends = this.atomends;
while(this.pos < this.field.length)
{
if(atomends.indexOf(this.field[this.pos]) != -1)
break;
else
atomlist.push(this.field[this.pos]);
this.pos++;
}
return atomlist.join(EMPTYSTRING);
},
getphraselist: function()
{
/*
* Parse a sequence of RFC 2822 phrases.
*
* A phrase is a sequence of words, which are in turn either RFC 2822
* atoms or quoted-strings. Phrases are canonicalized by squeezing all
* runs of continuous whitespace into one space.
*/
var plist = [];
while(this.pos < this.field.length)
{
if(this.FWS.indexOf(this.field[this.pos]) != -1)
this.pos++;
else if(this.field[this.pos] == '"')
plist.push(this.getquote());
else if(this.field[this.pos] == '(')
this.commentlist.push(this.getcomment());
else if(this.phraseends.indexOf(this.field[this.pos]) != -1)
break;
else
plist.push(this.getatom(this.phraseends));
}
return plist;
}
};
exports.Address = Address;
exports.parse = function(field)
{
var addresses = (new Address(field)).getlist();
return addresses.length ? addresses : [];
};

209
node_modules/emailjs/smtp/client.js generated vendored Normal file
View File

@ -0,0 +1,209 @@
var smtp = require('./smtp');
var smtpError = require('./error');
var message = require('./message');
var address = require('./address');
var Client = function(server)
{
this.smtp = new smtp.SMTP(server);
//this.smtp.debug(1);
this.queue = [];
this.timer = null;
this.sending = false;
this.ready = false;
};
Client.prototype =
{
_poll: function()
{
var self = this;
clearTimeout(self.timer);
if(self.queue.length)
{
if(self.smtp.state() == smtp.state.NOTCONNECTED)
self._connect(self.queue[0]);
else if(self.smtp.state() == smtp.state.CONNECTED && !self.sending && self.ready)
self._sendmail(self.queue.shift());
}
// wait around 1 seconds in case something does come in, otherwise close out SMTP connection if still open
else if(self.smtp.state() == smtp.state.CONNECTED)
self.timer = setTimeout(function() { self.smtp.quit(); }, 1000);
},
_connect: function(stack)
{
var self = this,
connect = function(err)
{
if(!err)
{
var begin = function(err)
{
if(!err)
{
self.ready = true;
self._poll();
}
else {
stack.callback(err, stack.message);
// clear out the queue so all callbacks can be called with the same error message
self.queue.shift();
self._poll();
}
};
if(!self.smtp.authorized())
self.smtp.login(begin);
else
self.smtp.ehlo_or_helo_if_needed(begin);
}
else {
stack.callback(err, stack.message);
// clear out the queue so all callbacks can be called with the same error message
self.queue.shift();
self._poll();
}
};
self.ready = false;
self.smtp.connect(connect);
},
send: function(msg, callback)
{
var self = this;
if(!(msg instanceof message.Message)
&& msg.from
&& (msg.to || msg.cc || msg.bcc)
&& (msg.text || this._containsInlinedHtml(msg.attachment)))
msg = message.create(msg);
if(msg instanceof message.Message)
{
msg.valid(function(valid, why)
{
if(valid)
{
var stack =
{
message: msg,
to: address.parse(msg.header.to),
from: address.parse(msg.header.from)[0].address,
callback: callback || function() {}
};
if(msg.header.cc)
stack.to = stack.to.concat(address.parse(msg.header.cc));
if(msg.header.bcc)
stack.to = stack.to.concat(address.parse(msg.header.bcc));
if(msg.header['return-path'] && address.parse(msg.header['return-path']).length)
stack.returnPath = address.parse(msg.header['return-path'])[0].address;
self.queue.push(stack);
self._poll();
}
else
callback(new Error(why), msg);
});
}
else
callback(new Error("message is not a valid Message instance"), msg);
},
_containsInlinedHtml: function(attachment) {
if (Array.isArray(attachment)) {
return attachment.some((function(ctx) {
return function(att) {
return ctx._isAttachmentInlinedHtml(att);
};
})(this));
} else {
return this._isAttachmentInlinedHtml(attachment);
}
},
_isAttachmentInlinedHtml: function(attachment) {
return attachment &&
(attachment.data || attachment.path) &&
attachment.alternative === true;
},
_sendsmtp: function(stack, next)
{
var self = this;
var check= function(err)
{
if(!err && next)
{
next.apply(self, [stack]);
}
else
{
// if we snag on SMTP commands, call done, passing the error
// but first reset SMTP state so queue can continue polling
self.smtp.rset(function() { self._senddone(err, stack); });
}
};
return check;
},
_sendmail: function(stack)
{
var self = this;
var from = stack.returnPath || stack.from;
self.sending = true;
self.smtp.mail(self._sendsmtp(stack, self._sendrcpt), '<' + from + '>');
},
_sendrcpt: function(stack)
{
var self = this, to = stack.to.shift().address;
self.smtp.rcpt(self._sendsmtp(stack, stack.to.length ? self._sendrcpt : self._senddata), '<'+ to +'>');
},
_senddata: function(stack)
{
var self = this;
self.smtp.data(self._sendsmtp(stack, self._sendmessage));
},
_sendmessage: function(stack)
{
var self = this, stream = stack.message.stream();
stream.on('data', function(data) { self.smtp.message(data); });
stream.on('end', function() { self.smtp.data_end(self._sendsmtp(stack, function() { self._senddone(null, stack) })); });
// there is no way to cancel a message while in the DATA portion, so we have to close the socket to prevent
// a bad email from going out
stream.on('error', function(err) { self.smtp.close(); self._senddone(err, stack); });
},
_senddone: function(err, stack)
{
var self = this;
self.sending = false;
stack.callback(err, stack.message);
self._poll();
}
};
exports.Client = Client;
exports.connect = function(server)
{
return new Client(server);
};

21
node_modules/emailjs/smtp/error.js generated vendored Normal file
View File

@ -0,0 +1,21 @@
module.exports = function(message, code, error, smtp)
{
var err = new Error(message);
err.code = code;
if(error)
err.previous = error;
err.smtp = smtp;
return err;
};
module.exports.COULDNOTCONNECT = 1;
module.exports.BADRESPONSE = 2;
module.exports.AUTHFAILED = 3;
module.exports.TIMEDOUT = 4;
module.exports.ERROR = 5;
module.exports.NOCONNECTION = 6;
module.exports.AUTHNOTSUPPORTED = 7;
module.exports.CONNECTIONCLOSED = 8;
module.exports.CONNECTIONENDED = 9;
module.exports.CONNECTIONAUTH = 10;

622
node_modules/emailjs/smtp/message.js generated vendored Normal file
View File

@ -0,0 +1,622 @@
var stream = require('stream');
var util = require('util');
var fs = require('fs');
var os = require('os');
var path = require('path');
var moment = require('moment');
var mimelib = require('mimelib');
var CRLF = "\r\n";
var MIMECHUNK = 76; // MIME standard wants 76 char chunks when sending out.
var BASE64CHUNK= 24; // BASE64 bits needed before padding is used
var MIME64CHUNK= MIMECHUNK * 6; // meets both base64 and mime divisibility
var BUFFERSIZE = MIMECHUNK*24*7; // size of the message stream buffer
var counter = 0;
// support for nodejs without Buffer.concat native function
if(!Buffer.concat)
{
require("bufferjs/concat");
}
var generate_boundary = function()
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+_,-./:=?";
for(var i=0; i < 69; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
};
function person2address(l)
{
// an array of emails or name+emails
if (Array.isArray(l)) {
l = l.join(', ');
}
// a string of comma separated emails or comma separated name+<emails>
if(typeof l == 'string') {
return l.replace(/([^<]+[^\s])(\s*)(<[^>]+>)/g, function(full, name, space, email) { return mimelib.encodeMimeWord(name, 'Q', 'utf-8') + space + email; });
}
return null;
}
var fix_header_name_case = function(header_name) {
return header_name.toLowerCase().replace(/^(.)|-(.)/g, function(match) {
return match.toUpperCase();
});
};
var Message = function(headers)
{
this.attachments = [];
this.alternative = null;
var now = new Date();
this.header = {
"message-id":"<" + now.getTime() + "." + (counter++) + "." + process.pid + "@" + os.hostname() +">",
"date":moment().format("ddd, DD MMM YYYY HH:mm:ss ") + moment().format("Z").replace(/:/, '')
};
this.content = "text/plain; charset=utf-8";
for(var header in headers)
{
// allow user to override default content-type to override charset or send a single non-text message
if(/^content-type$/i.test(header))
{
this.content = headers[header];
}
else if(header == 'text')
{
this.text = headers[header];
}
else if(header == "attachment" && typeof (headers[header]) == "object")
{
if(Array.isArray(headers[header])) {
var that = this;
for (var i = 0, l = headers[header].length; i < l; i++) {
this.attach(headers[header][i]);
}
} else {
this.attach(headers[header]);
}
}
else if(header == 'subject')
{
this.header.subject = mimelib.encodeMimeWord(headers.subject, 'Q', 'utf-8');
}
else if(/cc|bcc|to|from/i.test(header))
{
this.header[header.toLowerCase()] = person2address(headers[header]);
}
else
{
// allow any headers the user wants to set??
// if(/cc|bcc|to|from|reply-to|sender|subject|date|message-id/i.test(header))
this.header[header.toLowerCase()] = headers[header];
}
}
};
Message.prototype =
{
attach: function(options)
{
/*
legacy support, will remove eventually...
arguments -> (path, type, name, headers)
*/
if (arguments.length > 1)
options = {path:options, type:arguments[1], name:arguments[2]};
// sender can specify an attachment as an alternative
if(options.alternative)
{
this.alternative = options;
this.alternative.charset = options.charset || "utf-8";
this.alternative.type = options.type || "text/html";
this.alternative.inline = true;
}
else
this.attachments.push(options);
return this;
},
/*
legacy support, will remove eventually...
should use Message.attach() instead
*/
attach_alternative: function(html, charset)
{
this.alternative =
{
data: html,
charset: charset || "utf-8",
type: "text/html",
inline: true
};
return this;
},
valid: function(callback)
{
var self = this;
if(!self.header.from)
{
callback(false, "message does not have a valid sender");
}
if(!(self.header.to || self.header.cc || self.header.bcc))
{
callback(false, "message does not have a valid recipient");
}
else if(self.attachments.length === 0)
{
callback(true);
}
else
{
var check = [];
var failed = [];
self.attachments.forEach(function(attachment, index)
{
if(attachment.path)
{
// migrating path->fs for existsSync)
if(!(fs.existsSync || path.existsSync)(attachment.path))
failed.push(attachment.path + " does not exist");
}
else if(attachment.stream)
{
if(!attachment.stream.readable)
failed.push("attachment stream is not readable");
}
else if(!attachment.data)
{
failed.push("attachment has no data associated with it");
}
});
callback(failed.length === 0, failed.join(", "));
}
},
stream: function()
{
return new MessageStream(this);
},
read: function(callback)
{
var buffer = "";
var capture = function(data)
{
buffer += data;
};
var output = function(err)
{
callback(err, buffer);
};
var str = this.stream();
str.on('data', capture);
str.on('end', output);
str.on('error', output);
}
};
var MessageStream = function(message)
{
var self = this;
stream.Stream.call(self);
self.message = message;
self.readable = true;
self.paused = false;
self.buffer = new Buffer(MIMECHUNK*24*7);
self.bufferIndex = 0;
var output_process = function(next, args)
{
if(self.paused)
{
self.resumed = function() { next.apply(null, args); };
}
else
{
next.apply(null, args);
}
next.apply(null, args);
};
var output_mixed = function()
{
var boundary = generate_boundary();
var data = ["Content-Type: multipart/mixed; boundary=\"", boundary, "\"", CRLF, CRLF, "--", boundary, CRLF];
output(data.join(''));
if(!self.message.alternative)
{
output_text(self.message);
output_message(boundary, self.message.attachments, 0, close);
}
else
{
output_alternative(self.message, function() { output_message(boundary, self.message.attachments, 0, close); });
}
};
var output_message = function(boundary, list, index, callback)
{
if(index < list.length)
{
output(["--", boundary, CRLF].join(''));
if(list[index].related)
{
output_related(list[index], function() { output_message(boundary, list, index + 1, callback); });
}
else
{
output_attachment(list[index], function() { output_message(boundary, list, index + 1, callback); });
}
}
else
{
output([CRLF, "--", boundary, "--", CRLF, CRLF].join(''));
callback();
}
};
var output_attachment_headers = function(attachment)
{
var data = [],
header,
headers =
{
'content-type': attachment.type + (attachment.charset ? "; charset=" + attachment.charset : ""),
'content-transfer-encoding': 'base64',
'content-disposition': attachment.inline ? 'inline' : 'attachment; filename="' + mimelib.encodeMimeWord(attachment.name, 'Q', 'utf-8') + '"'
};
for(header in (attachment.headers || {}))
{
// allow sender to override default headers
headers[header.toLowerCase()] = attachment.headers[header];
}
for(header in headers)
{
data = data.concat([fix_header_name_case(header), ': ', headers[header], CRLF]);
}
output(data.concat([CRLF]).join(''));
};
var output_attachment = function(attachment, callback)
{
var build = attachment.path ? output_file : attachment.stream ? output_stream : output_data;
output_attachment_headers(attachment);
build(attachment, callback);
};
var output_data = function(attachment, callback)
{
output_base64(attachment.encoded ? attachment.data : new Buffer(attachment.data).toString("base64"), callback);
};
var output_file = function(attachment, next)
{
var chunk = MIME64CHUNK*16;
var buffer = new Buffer(chunk);
var closed = function(fd) { fs.close(fd); };
var opened = function(err, fd)
{
if(!err)
{
var read = function(err, bytes)
{
if(!err && self.readable)
{
// guaranteed to be encoded without padding unless it is our last read
output_base64(buffer.toString("base64", 0, bytes), function()
{
if(bytes == chunk) // we read a full chunk, there might be more
{
fs.read(fd, buffer, 0, chunk, null, read);
}
else // that was the last chunk, we are done reading the file
{
self.removeListener("error", closed);
fs.close(fd, next);
}
});
}
else
{
self.emit('error', err || {message:"message stream was interrupted somehow!"});
}
};
fs.read(fd, buffer, 0, chunk, null, read);
self.once("error", closed);
}
else
self.emit('error', err);
};
fs.open(attachment.path, 'r', opened);
};
var output_stream = function(attachment, callback)
{
if(attachment.stream.readable)
{
var previous = null;
attachment.stream.resume();
attachment.stream.on('end', function()
{
output_base64((previous || new Buffer(0)).toString("base64"), callback);
self.removeListener('pause', attachment.stream.pause);
self.removeListener('resume', attachment.stream.resume);
self.removeListener('error', attachment.stream.resume);
});
attachment.stream.on('data', function(buffer)
{
// do we have bytes from a previous stream data event?
if(previous)
{
var buffer2 = Buffer.concat([previous, buffer]);
previous = null; // free up the buffer
buffer = null; // free up the buffer
buffer = buffer2;
}
var padded = buffer.length % (MIME64CHUNK);
// encode as much of the buffer to base64 without empty bytes
if(padded)
{
previous = new Buffer(padded);
// copy dangling bytes into previous buffer
buffer.copy(previous, 0, buffer.length - padded);
}
output_base64(buffer.toString("base64", 0, buffer.length - padded));
});
self.on('pause', attachment.stream.pause);
self.on('resume', attachment.stream.resume);
self.on('error', attachment.stream.resume);
}
else
self.emit('error', {message:"stream not readable"});
};
var output_base64 = function(data, callback)
{
var loops = Math.ceil(data.length / MIMECHUNK);
var loop = 0;
while(loop < loops)
{
output(data.substring(MIMECHUNK * loop, MIMECHUNK * (loop + 1)) + CRLF);
loop++;
}
if(callback)
callback();
};
var output_text = function(message)
{
var data = [];
data = data.concat(["Content-Type:", message.content, CRLF, "Content-Transfer-Encoding: 7bit", CRLF]);
data = data.concat(["Content-Disposition: inline", CRLF, CRLF]);
data = data.concat([message.text || "", CRLF, CRLF]);
output(data.join(''));
};
var output_alternative = function(message, callback)
{
var data = [], boundary = generate_boundary();
data = data.concat(["Content-Type: multipart/alternative; boundary=\"", boundary, "\"", CRLF, CRLF]);
data = data.concat(["--", boundary, CRLF]);
output(data.join(''));
output_text(message);
output(["--", boundary, CRLF].join(''));
var finish = function()
{
output([CRLF, "--", boundary, "--", CRLF, CRLF].join(''));
callback();
};
if(message.alternative.related)
{
output_related(message.alternative, finish);
}
else
{
output_attachment(message.alternative, finish);
}
};
var output_related = function(message, callback)
{
var data = [], boundary = generate_boundary();
data = data.concat(["Content-Type: multipart/related; boundary=\"", boundary, "\"", CRLF, CRLF]);
data = data.concat(["--", boundary, CRLF]);
output(data.join(''));
output_attachment(message, function()
{
output_message(boundary, message.related, 0, function()
{
output([CRLF, "--", boundary, "--", CRLF, CRLF].join(''));
callback();
});
});
};
var output_header_data = function()
{
if(self.message.attachments.length || self.message.alternative)
{
output("MIME-Version: 1.0" + CRLF);
output_mixed();
}
else // you only have a text message!
{
output_text(self.message);
close();
}
};
var output_header = function()
{
var data = [];
for(var header in self.message.header)
{
// do not output BCC in the headers...
if(!(/bcc/i.test(header)))
data = data.concat([fix_header_name_case(header), ": ", self.message.header[header], CRLF]);
}
output(data.join(''));
output_header_data();
};
var output = function(data, callback, args)
{
var bytes = Buffer.byteLength(data);
// can we buffer the data?
if(bytes + self.bufferIndex < self.buffer.length)
{
self.buffer.write(data, self.bufferIndex);
self.bufferIndex += bytes;
if(callback)
callback.apply(null, args);
}
// we can't buffer the data, so ship it out!
else if(bytes > self.buffer.length)
{
if(self.bufferIndex)
{
self.emit('data', self.buffer.toString("utf-8", 0, self.bufferIndex));
self.bufferIndex = 0;
}
var loops = Math.ceil(data.length / self.buffer.length);
var loop = 0;
while(loop < loops)
{
self.emit('data', data.substring(self.buffer.length*loop, self.buffer.length*(loop + 1)));
loop++;
}
}
else // we need to clean out the buffer, it is getting full
{
if(!self.paused)
{
self.emit('data', self.buffer.toString("utf-8", 0, self.bufferIndex));
self.buffer.write(data, 0);
self.bufferIndex = bytes;
// we could get paused after emitting data...
if(self.paused)
{
self.once("resume", function() { callback.apply(null, args); });
}
else if(callback)
{
callback.apply(null, args);
}
}
else // we can't empty out the buffer, so let's wait till we resume before adding to it
{
self.once("resume", function() { output(data, callback, args); });
}
}
};
var close = function(err)
{
if(err)
{
self.emit("error", err);
}
else
{
self.emit('data', self.buffer.toString("utf-8", 0, self.bufferIndex));
self.emit('end');
}
self.buffer = null;
self.bufferIndex = 0;
self.readable = false;
self.removeAllListeners("resume");
self.removeAllListeners("pause");
self.removeAllListeners("error");
self.removeAllListeners("data");
self.removeAllListeners("end");
};
self.once("destroy", close);
process.nextTick(output_header);
};
util.inherits(MessageStream, stream.Stream);
MessageStream.prototype.pause = function()
{
this.paused = true;
this.emit('pause');
};
MessageStream.prototype.resume = function()
{
this.paused = false;
this.emit('resume');
};
MessageStream.prototype.destroy = function()
{
this.emit("destroy", self.bufferIndex > 0 ? {message:"message stream destroyed"} : null);
};
MessageStream.prototype.destroySoon = function()
{
this.emit("destroy");
};
exports.Message = Message;
exports.BUFFERSIZE = BUFFERSIZE;
exports.create = function(headers)
{
return new Message(headers);
};

75
node_modules/emailjs/smtp/response.js generated vendored Normal file
View File

@ -0,0 +1,75 @@
var SMTPError = require('./error');
var SMTPResponse = function(stream, timeout, onerror)
{
var buffer = '',
notify = function()
{
if(buffer.length)
{
// parse buffer for response codes
var line = buffer.replace("\r", '');
var match = line ? line.match(/(\d+)\s?(.*)/) : null;
stream.emit('response', null, match ? {code:match[1], message:match[2], data:line} : {code:-1, data:line});
buffer = '';
}
},
error = function(err)
{
stream.emit('response', SMTPError('connection encountered an error', SMTPError.ERROR, err));
},
timedout = function(err)
{
stream.emit('response', SMTPError('timedout while connecting to smtp server', SMTPError.TIMEDOUT, err));
},
watch = function()
{
var data = stream.read();
if (data !== null) {
var decoded = data.toString();
var emit = false;
var code = 0;
buffer += decoded;
notify();
}
},
close = function(err)
{
stream.emit('response', SMTPError('connection has closed', SMTPError.CONNECTIONCLOSED, err));
},
end = function(err)
{
stream.emit('response', SMTPError('connection has ended', SMTPError.CONNECTIONENDED, err));
};
this.stop = function(err) {
stream.removeAllListeners('response');
stream.removeListener('readable', watch);
stream.removeListener('end', end);
stream.removeListener('close', close);
stream.removeListener('error', error);
if(err && typeof(onerror) == "function")
onerror(err);
};
stream.on('readable', watch);
stream.on('end', end);
stream.on('close', close);
stream.on('error', error);
stream.setTimeout(timeout, timedout);
};
exports.monitor = function(stream, timeout, onerror)
{
return new SMTPResponse(stream, timeout, onerror);
};

537
node_modules/emailjs/smtp/smtp.js generated vendored Normal file
View File

@ -0,0 +1,537 @@
/*
* SMTP class written using python's (2.7) smtplib.py as a base
*/
var net = require('net');
var crypto = require('crypto');
var os = require('os');
var tls = require('tls');
var util = require('util');
var events = require('events');
var starttls = require('./tls');
var SMTPResponse = require('./response');
var SMTPError = require('./error');
var SMTP_PORT = 25;
var SMTP_SSL_PORT = 465;
var SMTP_TLS_PORT = 587;
var CRLF = "\r\n";
var AUTH_METHODS = {
PLAIN: 'PLAIN',
CRAM_MD5: 'CRAM-MD5',
LOGIN: 'LOGIN',
XOAUTH2: 'XOAUTH2'
};
var TIMEOUT = 5000;
var DEBUG = 0;
var log = function() {
if (DEBUG) {
Array.prototype.slice.call(arguments).forEach(function(d) {
console.log(d);
});
}
};
var quotedata = function(data) {
// Quote data for email.
// Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
// Internet CRLF end-of-line.
return data.replace(/(?:\r\n|\n|\r(?!\n))/g, CRLF).replace(/^\./gm, '..');
};
var caller = function(callback) {
if (typeof(callback) == 'function') {
var args = Array.prototype.slice.call(arguments);
args.shift();
callback.apply(null, args);
}
};
var SMTPState = {
NOTCONNECTED: 0,
CONNECTING: 1,
CONNECTED: 2
};
var SMTP = function(options) {
events.EventEmitter.call(this);
options = options || {};
this.sock = null;
this.timeout = options.timeout || TIMEOUT;
this.features = null;
this._state = SMTPState.NOTCONNECTED;
this._secure = false;
this.loggedin = (options.user && options.password) ? false : true;
this.domain = options.domain || os.hostname();
this.host = options.host || 'localhost';
this.port = options.port || (options.ssl ? SMTP_SSL_PORT : options.tls ? SMTP_TLS_PORT : SMTP_PORT);
this.ssl = options.ssl || false;
this.tls = options.tls || false;
this.monitor = null;
// keep these strings hidden when quicky debugging/logging
this.user = function() {
return options.user;
};
this.password = function() {
return options.password;
};
};
SMTP.prototype = {
debug: function(level) {
DEBUG = level;
},
state: function() {
return this._state;
},
authorized: function() {
return this.loggedin;
},
connect: function(callback, port, host, options) {
options = options || {};
var self = this;
self.host = host || self.host;
self.port = port || self.port;
self.ssl = options.ssl || self.ssl;
if (self._state != SMTPState.NOTCONNECTED) {
self.quit(function() {
self.connect(callback, port, host, options);
});
return;
}
var connected = function(err) {
if (!err) {
log("connected: " + self.host + ":" + self.port);
if (self.ssl && !self.tls) {
// if key/ca/cert was passed in, check if connection is authorized
if (typeof(self.ssl) != 'boolean' && !self.sock.authorized) {
self.close(true);
caller(callback, SMTPError('could not establish an ssl connection', SMTPError.CONNECTIONAUTH, err));
} else self._secure = true;
}
} else {
self.close(true);
caller(callback, SMTPError("could not connect", SMTPError.COULDNOTCONNECT, err));
}
};
var response = function(err, msg) {
if (err) {
self.close(true);
caller(callback, err);
} else if (msg.code == '220') {
log(msg.data);
// might happen first, so no need to wait on connected()
self._state = SMTPState.CONNECTED;
caller(callback, null, msg.data);
} else {
log("response (data): " + msg.data);
self.quit(function() {
caller(callback, SMTPError("bad response on connection", SMTPError.BADRESPONSE, err, msg.data));
});
}
};
self._state = SMTPState.CONNECTING;
log("connecting: " + self.host + ":" + self.port);
if (self.ssl) {
self.sock = tls.connect(self.port, self.host, self.ssl, connected);
} else {
self.sock = new net.Socket();
self.sock.connect(self.port, self.host, connected);
}
self.monitor = SMTPResponse.monitor(self.sock, self.timeout, function() {
self.close(true);
});
self.sock.once('response', response);
self.sock.once('error', response); // the socket could reset or throw, so let's handle it and let the user know
},
send: function(str, callback) {
var self = this;
if (self.sock && self._state == SMTPState.CONNECTED) {
log(str);
var response = function(err, msg) {
if (err) {
caller(callback, err);
} else {
log(msg.data);
caller(callback, null, msg);
}
};
self.sock.once('response', response);
self.sock.write(str);
} else {
self.close(true);
caller(callback, SMTPError('no connection has been established', SMTPError.NOCONNECTION));
}
},
command: function(cmd, callback, codes, failed) {
codes = Array.isArray(codes) ? codes : typeof(codes) == 'number' ? [codes] : [250];
var response = function(err, msg) {
if (err) {
caller(callback, err);
} else {
if (codes.indexOf(Number(msg.code)) != -1) caller(callback, err, msg.data, msg.message);
else caller(callback, SMTPError("bad response on command '" + cmd.split(' ')[0] + "'", SMTPError.BADRESPONSE, null, msg.data));
}
};
this.send(cmd + CRLF, response);
},
helo: function(callback, domain) {
/*
* SMTP 'helo' command.
* Hostname to send for self command defaults to the FQDN of the local
* host.
*/
var self = this,
response = function(err, data) {
if (err) {
caller(callback, err);
} else {
self.parse_smtp_features(data);
caller(callback, err, data);
}
};
this.command("helo " + (domain || this.domain), response);
},
starttls: function(callback) {
var self = this,
response = function(err, msg) {
if (err) {
err.message += " while establishing a starttls session";
caller(callback, err);
} else {
var secured_socket = null;
var secured = function() {
self._secure = true;
self.sock = secured_socket;
var error = function(err) {
self.close(true);
caller(callback, err);
};
SMTPResponse.monitor(self.sock, self.timeout, function() {
self.close(true);
});
caller(callback, msg.data);
};
secured_socket = starttls.secure(self.sock, self.tls, secured);
}
};
this.command("starttls", response, [220]);
},
parse_smtp_features: function(data) {
var self = this;
// According to RFC1869 some (badly written)
// MTA's will disconnect on an ehlo. Toss an exception if
// that happens -ddm
data.split("\n").forEach(function(ext) {
var parse = ext.match(/^(?:\d+[\-=]?)\s*?([^\s]+)(?:\s+(.*)\s*?)?$/);
// To be able to communicate with as many SMTP servers as possible,
// we have to take the old-style auth advertisement into account,
// because:
// 1) Else our SMTP feature parser gets confused.
// 2) There are some servers that only advertise the auth methods we
// support using the old style.
if (parse) {
// RFC 1869 requires a space between ehlo keyword and parameters.
// It's actually stricter, in that only spaces are allowed between
// parameters, but were not going to check for that here. Note
// that the space isn't present if there are no parameters.
self.features[parse[1].toLowerCase()] = parse[2] || true;
}
});
return;
},
ehlo: function(callback, domain) {
var self = this,
response = function(err, data) {
if (err) {
caller(callback, err);
} else {
self.parse_smtp_features(data);
if (self.tls && !self._secure) {
self.starttls(function() {
self.ehlo(callback, domain);
});
} else {
caller(callback, err, data);
}
}
};
this.features = {};
this.command("ehlo " + (domain || this.domain), response);
},
has_extn: function(opt) {
return this.features[opt.toLowerCase()] === undefined;
},
help: function(callback, args) {
// SMTP 'help' command, returns text from the server
this.command(args ? "help " + args : "help", callback, [211, 214]);
},
rset: function(callback) {
this.command("rset", callback);
},
noop: function(callback) {
this.send("noop", callback);
},
mail: function(callback, from) {
this.command("mail FROM:" + from, callback);
},
rcpt: function(callback, to) {
this.command("RCPT TO:" + to, callback, [250, 251]);
},
data: function(callback) {
this.command("data", callback, [354]);
},
data_end: function(callback) {
this.command(CRLF + ".", callback);
},
message: function(data) {
log(data);
this.sock.write(data);
},
verify: function(address, callback) {
// SMTP 'verify' command -- checks for address validity."""
this.command("vrfy " + address, callback, [250, 251, 252]);
},
expn: function(address, callback) {
// SMTP 'expn' command -- expands a mailing list.
this.command("expn " + address, callback);
},
ehlo_or_helo_if_needed: function(callback, domain) {
// Call self.ehlo() and/or self.helo() if needed.
// If there has been no previous EHLO or HELO command self session, self
// method tries ESMTP EHLO first.
var self = this;
if (!this.features) {
var response = function(err, data) {
caller(callback, err, data);
};
var attempt = function(err, data) {
if (err) self.helo(response, domain);
else caller(callback, err, data);
};
self.ehlo(attempt, domain);
}
},
login: function(callback, user, password, options) {
var self = this,
login = {
user: user ? function() {
return user;
} : self.user,
password: password ? function() {
return password;
} : self.password,
method: options && options.method ? options.method.toUpperCase() : ''
},
domain = options && options.domain ? options.domain : this.domain,
initiate = function(err, data) {
if (err) {
caller(callback, err);
return;
}
/*
* Log in on an SMTP server that requires authentication.
*
* The arguments are:
* - user: The user name to authenticate with.
* - password: The password for the authentication.
*
* If there has been no previous EHLO or HELO command self session, self
* method tries ESMTP EHLO first.
*
* This method will return normally if the authentication was successful.
*/
var method = null,
encode_cram_md5 = function(challenge) {
challenge = (new Buffer(challenge, "base64")).toString("ascii");
var hmac = crypto.createHmac('md5', login.password());
hmac.update(challenge);
return (new Buffer(login.user() + " " + hmac.digest('hex')).toString("base64"));
},
encode_plain = function() {
return (new Buffer("\0" + login.user() + "\0" + login.password())).toString("base64");
},
encode_xoauth2 = function() {
// console.log("user=" + login.user() + "\1auth=Bearer " + login.password()+"\1\1");
// see: https://developers.google.com/gmail/xoauth2_protocol
return (new Buffer("user=" + login.user() + "\1auth=Bearer " + login.password() + "\1\1")).toString("base64");
};
// List of authentication methods we support: from preferred to
// less preferred methods.
if (!method) {
var preferred = [AUTH_METHODS.CRAM_MD5, AUTH_METHODS.LOGIN, AUTH_METHODS.PLAIN, AUTH_METHODS.XOAUTH2];
for (var i = 0; i < preferred.length; i++) {
if ((self.features.auth || "").indexOf(preferred[i]) != -1) {
method = preferred[i];
break;
}
}
}
// handle bad responses from command differently
var failed = function(err, data) {
self.loggedin = false;
self.close(); // if auth is bad, close the connection, it won't get better by itself
caller(callback, SMTPError('authorization.failed', SMTPError.AUTHFAILED, err, data));
};
var response = function(err, data) {
if (err) {
failed(err, data);
} else {
self.loggedin = true;
caller(callback, err, data);
}
};
var attempt = function(err, data, msg) {
if (err) {
failed(err, data);
} else {
if (method == AUTH_METHODS.CRAM_MD5) {
self.command(encode_cram_md5(msg), response, [235, 503]);
} else if (method == AUTH_METHODS.LOGIN) {
self.command((new Buffer(login.password())).toString("base64"), response, [235, 503]);
}
}
};
var attempt_user = function(err, data, msg) {
if (err) {
failed(err, data);
} else {
if (method == AUTH_METHODS.LOGIN) {
self.command((new Buffer(login.user())).toString("base64"), attempt, [334]);
}
}
};
if (method == AUTH_METHODS.CRAM_MD5) self.command("AUTH " + AUTH_METHODS.CRAM_MD5, attempt, [334]);
else if (method == AUTH_METHODS.LOGIN) self.command("AUTH " + AUTH_METHODS.LOGIN, attempt_user, [334]);
else if (method == AUTH_METHODS.PLAIN) self.command("AUTH " + AUTH_METHODS.PLAIN + " " + encode_plain(login.user(), login.password()), response, [235, 503]);
else if (method == AUTH_METHODS.XOAUTH2) self.command("AUTH " + AUTH_METHODS.XOAUTH2 + " " + encode_xoauth2(login.user(), login.password()), response, [235, 503]);
else if (!method) caller(callback, SMTPError('no form of authorization supported', SMTPError.AUTHNOTSUPPORTED, null, data));
};
self.ehlo_or_helo_if_needed(initiate, domain);
},
close: function(force) {
if (this.sock) {
if (force) {
log("smtp connection destroyed!");
this.sock.destroy();
} else {
log("smtp connection closed.");
this.sock.end();
}
}
if (this.monitor) {
this.monitor.stop();
this.monitor = null;
}
this._state = SMTPState.NOTCONNECTED;
this._secure = false;
this.sock = null;
this.features = null;
this.loggedin = !(this.user() && this.password());
},
quit: function(callback) {
var self = this,
response = function(err, data) {
caller(callback, err, data);
self.close();
};
this.command("quit", response, [221, 250]);
}
};
for (var each in events.EventEmitter.prototype) {
SMTP.prototype[each] = events.EventEmitter.prototype[each];
}
exports.SMTP = SMTP;
exports.state = SMTPState;

64
node_modules/emailjs/smtp/tls.js generated vendored Normal file
View File

@ -0,0 +1,64 @@
var crypto = require('crypto');
var tls = require('tls');
var secure = function(socket, options, cb)
{
var sslcontext = crypto.createCredentials(options);
//sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
var pair = tls.createSecurePair(sslcontext, false);
var cleartext = pipe(pair, socket);
pair.on('secure', function()
{
var verifyError = (pair.ssl || pair._ssl).verifyError();
if(verifyError)
{
cleartext.authorized = false;
cleartext.authorizationError = verifyError;
}
else
{
cleartext.authorized = true;
}
if (cb) cb();
});
cleartext._controlReleased = true;
return cleartext;
};
var pipe = function(pair, socket)
{
pair.encrypted.pipe(socket);
socket.pipe(pair.encrypted);
var cleartext = pair.cleartext;
cleartext.socket = socket;
cleartext.encrypted = pair.encrypted;
cleartext.authorized = false;
function onerror(e)
{
if (cleartext._controlReleased)
{
cleartext.emit('error', e);
}
}
function onclose()
{
socket.removeListener('error', onerror);
socket.removeListener('close', onclose);
}
socket.on('error', onerror);
socket.on('close', onclose);
return cleartext;
};
exports.secure = secure;