Permalink
Browse files

Merge branch 'master' of github.com:baudehlo/Haraka

  • Loading branch information...
2 parents 05f3517 + 85d0078 commit 4e989baa7f9e0134d9bcd6ec432d5f703f84a6a6 @baudehlo committed Nov 21, 2012
Showing with 222 additions and 66 deletions.
  1. +13 −0 connection.js
  2. +48 −17 docs/Transaction.md
  3. +79 −0 docs/tutorials/Migrating_from_v1_to_v2.md
  4. +14 −0 haraka.js
  5. +4 −0 mailbody.js
  6. +51 −42 messagestream.js
  7. +2 −2 package.json
  8. +9 −4 smtp_client.js
  9. +2 −1 transaction.js
View
@@ -122,12 +122,22 @@ function setupClient(self) {
function Connection(client, server) {
this.client = client;
this.server = server;
+ this.remote_ip = null;
+ this.remote_host = null
+ this.remote_port = null;
+ this.remote_info = null;
this.current_data = null;
this.current_line = null;
+ this.greeting = null;
+ this.hello_host = null;
this.state = STATE_PAUSE;
+ this.loop_code = null;
+ this.loop_msg = null;
this.uuid = uuid();
this.notes = {};
+ this.transaction = null;
this.tran_count = 0;
+ this.capabilities = null;
this.early_talker_delay = config.get('early_talker_delay') || 1000;
this.banner_includes_uuid = config.get('banner_includes_uuid') ? true : false;
this.deny_includes_uuid = config.get('deny_includes_uuid') ? true : false;
@@ -141,6 +151,7 @@ function Connection(client, server) {
this.hooks_to_run = [];
this.start_time = Date.now();
this.last_reject = '';
+ this.max_bytes = null;
this.totalbytes = 0;
this.rcpt_count = {
accept: 0,
@@ -152,6 +163,7 @@ function Connection(client, server) {
tempfail: 0,
reject: 0,
};
+ this.data_post_start = null;
this.proxy = false;
this.proxy_timer = false;
setupClient(this);
@@ -400,6 +412,7 @@ Connection.prototype.fail = function (err) {
Connection.prototype.disconnect = function() {
if (this.disconnected) return;
+ this.reset_transaction();
plugins.run_hooks('disconnect', this);
};
View
@@ -89,23 +89,54 @@ hook_data or before.
The body of the email if you set `parse_body` above. See `Body Object`.
-* transaction.attachment_hooks(start, data, end)
-
-Sets event emitter hooks for attachments if you set `parse_body` above.
-
-The `start` event will receive `(content_type, filename, body)` as parameters.
-
-The `data` event will receive a `Buffer` object containing some of the
-attachment data.
-
-The `end` event will be called with no parameters when an attachment ends.
-
-Both the `data` and `end` params are optional.
-
-Note that in the `start` event, you can set per-attachment events via:
-
- body.on('attachment_data', cb)
- body.on('attachment_end', cb)
+* transaction.attachment_hooks(start)
+
+Sets a callback for when we see an attachment if `parse_body` has been set.
+
+The `start` event will receive `(content_type, filename, body, stream)` as
+parameters.
+
+The stream is a `ReadableStream` - see http://nodejs.org/api/stream.html for
+details on how this works.
+
+If you set stream.connection then the stream will apply backpressure to the
+connection, allowing you to process attachments before the connection has
+ended. Here is an example which stores attachments in temporary files using
+the `tmp` library from npm and tells us the size of the file:
+
+ exports.hook_data = function (next, connection) {
+ // enable mail body parsing
+ connection.transaction.parse_body = 1;
+ connection.transaction.attachment_hooks(
+ function (ct, fn, body, stream) {
+ start_att(connection, ct, fn, body, stream)
+ }
+ );
+ next();
+ }
+
+ function start_att (connection, ct, fn, body, stream) {
+ connection.loginfo("Got attachment: " + ct + ", " + fn + " for user id: " + connection.transaction.notes.hubdoc_user.email);
+ connection.transaction.notes.attachment_count++;
+
+ stream.connection = connection; // Allow backpressure
+ stream.pause();
+
+ var tmp = require('tmp');
+
+ tmp.file(function (err, path, fd) {
+ connection.loginfo("Got tempfile: " + path + " (" + fd + ")");
+ var ws = fs.createWriteStream(path);
+ stream.pipe(ws);
+ stream.resume();
+ ws.on('close', function () {
+ connection.loginfo("End of stream reached");
+ fs.fstat(fd, function (err, stats) {
+ connection.loginfo("Got data of length: " + stats.size);
+ });
+ });
+ });
+ }
* transaction.set_banner(text, html)
@@ -0,0 +1,79 @@
+Migrating from Haraka v1.x to v2.x
+==================================
+
+Haraka v2.x contains two significant changes to the v1.x API related to
+streams.
+
+Streams are an abstraction over a data flow that is provided by Node core
+and is used throughout node to "pipe" data between two places or more. This
+makes programming very easy, and is hence why we started using them in Haraka
+starting with version 2.0.0.
+
+For more information about the Stream API, see
+http://nodejs.org/api/stream.html
+
+It's important to note that if you are using standard Haraka plugins then
+it's very unlikely you will need to change anything. Though you may want
+to configure `spool_dir` and `spool_after` in `config/smtp.ini`. However if
+you have written custom plugins, continue reading.
+
+Changes To Look For
+-------------------
+
+Firstly, the incoming data in an email (the email body) is now stored in an
+object which you can treat as a ReadableStream. To find if this is relevant
+for you, look for instances of `data_lines` in your plugins.
+
+Secondly, if you parse the mail body, attachments are now provided as a
+stream, rather than custom start/data/end events. To find if this is relevant
+for you, look for instances of `attachment_hooks` in your plugins.
+
+Fixing data_lines plugins
+-------------------------
+
+Any plugins now working on each line of data will need to change to using a
+stream. The stream is called `transaction.message_stream`.
+
+These changes may be complicated if you are iterating over each line and
+doing something with the strings therein. However if you are piping the data
+to an application or over a network, your code will become significantly
+simpler.
+
+...
+
+Fixing attachment_hooks plugins
+-------------------------------
+
+For v1.x you passed in functions to `transaction.attachment_hooks()` as
+follows:
+
+ transaction.attachment_hooks(
+ function (ctype, filename, body) {...}, // start
+ function (buf) {...}, // data
+ function () {...} // end
+ );
+
+That has now changed to:
+
+ transaction.attachment_hooks(
+ function (ctype, filename, body, stream) {...}, // start
+ );
+
+This allows you to attach the stream to other streams via `stream.pipe(dest)`.
+
+Sometimes destination streams will apply backpressure on the sending stream,
+for example if you are sending attachments to a remote service. In order
+for this backpressure to apply to the connection itself (so that we don't
+have to buffer up data in memory), we need to provide the connection object
+to the stream:
+
+ var transaction = connection.transaction;
+ transaction.attachment_hooks(
+ function (ctype, filename, body, stream) {
+ stream.connection = connection;
+ ...
+ }
+ );
+
+For a full example of using attachment streams, see the Transaction.md
+documentation file.
View
@@ -38,6 +38,20 @@ process.on('uncaughtException', function (err) {
process.exit(1);
});
+['SIGTERM', 'SIGINT'].forEach(function (sig) {
+ process.on(sig, function () {
+ process.title = path.basename(process.argv[1], '.js');
+ logger.loginfo(sig + ' received');
+ logger.dump_logs(1);
+ });
+});
+
+process.on('exit', function() {
+ process.title = path.basename(process.argv[1], '.js');
+ logger.loginfo('Shutting down');
+ logger.dump_logs();
+});
+
logger.log("INFO", "Starting up Haraka version " + exports.version);
server.createServer();
View
@@ -17,6 +17,10 @@ function Body (header, options) {
this.options = options || {};
this.bodytext = '';
this.body_text_encoded = '';
+ this.body_encoding = null;
+ this.boundary = null;
+ this.ct = null;
+ this.decode_function = null;
this.children = []; // if multipart
this.state = 'start';
this.buf = new Buffer(buf_siz);
Oops, something went wrong.

0 comments on commit 4e989ba

Please sign in to comment.