/*
** SellaNMS
** $Id: email.cxx,v 1.19 2005/03/31 18:57:12 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software, LLC. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

#ifdef HAVE_CONFIG_H
	#include "config.h"
#endif

#include "email.h"
#include "debug.h"
#include "smtp.h"
#include <pthread.h>

Email::Email() {
	this->name.append(" email");

	has_scheduler = false;
	has_execute = true;
}

Email::~Email() {
}

RESULT Email::execute() {
	RESULT result = SUCCESS;

	if ((result = readOutput("email")) != SUCCESS) {
		LMSG("NOTICE: Email failed to read output from storage.");
		result = FAILURE;
	} else {
		while (!outputEmpty()) {
			/* Default policy_input. */
			polInput = polInputDefault;

			/* Get next policy_input */
			if (policyInputNext(polInput) == ACTION_REJECT) {
				LMSG("NOTICE: Failed to obtain next policy input.");
				result = FAILURE;
				break;
			}

			/* Run policy on input data. */
			if (outputPolicy.evaluate(polOutput, polInput) == ACTION_REJECT) {
				LMSG("NOTICE: Failed to apply policy.");
				result = FAILURE;
				break;
			}

			processPolicyOutput(polOutput);
		}
	}

	return result;
}

RESULT Email::readConfig() {
	RESULT result = SUCCESS;

	vector<string> v;

	/* Add and compile input policy. */
	if (config->assignValues("policy input", v)) {
		LMSG("NOTICE: Input policies are not implemented yet.");
		if (inputPolicy.addPolicies(config, v) == FAILURE) {
			LMSG("NOTICE: Failed to add/compile input policies.");
			result = FAILURE;
		}
	}

	/* Add and compile output policy. */
	if (config->assignValues("policy output", v)) {
		if (outputPolicy.addPolicies(config, v) == FAILURE) {
			LMSG("NOTICE: Failed to add/compile output policies.");
			result = FAILURE;
		}
	}

	/* Verify we have required policies. */
	if (outputPolicy.empty()) {
		LMSG("NOTICE: A output policy is required for this module.");
		result = FAILURE;
	}

	/* Large queue-depth results in increased RAM usage, during high event periods. An overwhelmed system could grow out of control. */
	if (config->assignValue("queue-depth", queueDepth, MODULE_OUTPUT_EMAIL_QUEUEDEPTH_DEFAULT)) {
		if (queueDepth < 1) {
			queueDepth = MODULE_OUTPUT_EMAIL_QUEUEDEPTH_DEFAULT;
		}
	}

   /* Configure Storage */
   storage.setConfig(*config);

	return result;
}

RESULT Email::printConfig() {
	LMSG("queue-depth: %lu", this->queueDepth);

	Output::printConfig();

	return SUCCESS;
}

RESULT Email::processPolicyOutput(variable_binding_t &policy_output) {
	RESULT result = SUCCESS;

	unsigned int tmp;
	SMTP smtp;
	vector<string> values;
	vector<string>::iterator it;
	ConfigNode *alias_node = NULL, *default_node = NULL;
	bool delivered;

	if (trace.internal) {
		smtp.setDebug(true);
	}

	/* Determine if we have a default. */
	config->assignNode("default", default_node);

	/* Determine if we have an alias. */
	if (policy_output.find("alias") != policy_output.end()) {
		config->assignNode("alias " + policy_output["alias"], alias_node);

		if (trace.debug) {
			LMSG("set alias: %s", policy_output["alias"].c_str());
		}
	} else {
		alias_node = NULL;
	}

	/* Set our From field(s). */
	if (assignValues("from", policy_output, alias_node, default_node, values)) {
		for (it = values.begin(); it != values.end(); ++it) {
			smtp.setFrom(*it);

			if (trace.debug) {
				LMSG("set from: %s", it->c_str());
			}
		}
	}

	/* Set our ReplyTo field(s). */
	if (assignValues("reply-to", policy_output, alias_node, default_node, values)) {
		for (it = values.begin(); it != values.end(); ++it) {
			smtp.setReplyTo(*it);

			if (trace.debug) {
				LMSG("set reply-to: %s", it->c_str());
			}
		}
	}

	/* Set our To field(s). */
	if (assignValues("to", policy_output, alias_node, default_node, values)) {
		for (it = values.begin(); it != values.end(); ++it) {
			smtp.setTo(*it);

			if (trace.debug) {
				LMSG("set to: %s", it->c_str());
			}
		}
	}

	/* Set our Cc field(s). */
	if (assignValues("cc", policy_output, alias_node, default_node, values)) {
		for (it = values.begin(); it != values.end(); ++it) {
			smtp.setCc(*it);

			if (trace.debug) {
				LMSG("set cc: %s", it->c_str());
			}
		}
	}

	/* Set our Bcc field(s). */
	if (assignValues("bcc", policy_output, alias_node, default_node, values)) {
		for (it = values.begin(); it != values.end(); ++it) {
			smtp.setBcc(*it);

			if (trace.debug) {
				LMSG("set bcc: %s", it->c_str());
			}
		}
	}

	/* Set our Subject field. */
	if (assignValues("subject", policy_output, alias_node, default_node, values)) {
		smtp.setSubject(values[0]);

		if (trace.debug) {
			LMSG("set subject: %s", values[0].c_str());
		}
	} else {
		if (policy_output.find("brief") != policy_output.end()) {
			smtp.setSubject(policy_output["brief"]);

			if (trace.debug) {
				LMSG("set subject: %s", policy_output["brief"].c_str());
			}
		} else {
			smtp.setSubject("Not Available");
		}
	}

	/* Set our Body field(s). */
	if (assignValues("body", policy_output, alias_node, default_node, values)) {
		for (it = values.begin(); it != values.end(); ++it) {
			smtp.setBody(*it);

			if (trace.debug) {
				LMSG("set body: %s", it->c_str());
			}
		}
	} else {
		if (policy_output.find("detail") != policy_output.end()) {
			smtp.setBody(policy_output["detail"]);

			if (trace.debug) {
				LMSG("set body: %s", policy_output["detail"].c_str());
			}
		} else {
			smtp.setBody("Not Available");
		}
	}
	
	/* Set our Priority field. */
	if (assignValues("priority", policy_output, alias_node, default_node, values)) {
		tmp = strtoul(values[0].c_str(), NULL, 10);
		smtp.setPriority(tmp);

		if (trace.debug) {
			LMSG("set priority: %lu", tmp);
		}
	}

	/* Set our Length. */
	if (assignValues("length", policy_output, alias_node, default_node, values)) {
		tmp = strtoul(values[0].c_str(), NULL, 10);
		smtp.setLength(tmp);

		if (trace.debug) {
			LMSG("set length: %lu", tmp);
		}
	}

	/* Set our Timeout. */
	if (assignValues("timeout", policy_output, alias_node, default_node, values)) {
		tmp = strtoul(values[0].c_str(), NULL, 10);
		smtp.setTimeout(tmp);

		if (trace.debug) {
			LMSG("set timeout: %lu", tmp);
		}
	}

	/* Set our Port field. */
	if (assignValues("port", policy_output, alias_node, default_node, values)) {
		tmp = strtoul(values[0].c_str(), NULL, 10);
		smtp.setPort(tmp);

		if (trace.debug) {
			LMSG("set port: %lu", tmp);
		}
	}

	/* Set the desired server(s). */
	assignValues("server", policy_output, alias_node, default_node, values);
	if (values.size() < 1) {
		values.push_back("127.0.0.1");
	}

	/* Cleanup, since we don't need these anymore. */
	SAFE_DELETE(alias_node);
	SAFE_DELETE(default_node);

	/* Loop thru each server, until one succeeds. */
	for (it = values.begin(), delivered = false; it != values.end(); ++it) {
		/* Overwrite the last server. */
		smtp.setServer(*it);

		if (trace.debug) {
			LMSG("set server: %s", it->c_str());
		}

		/* Try to send. */
		if (smtp.send() == SUCCESS) {
			delivered = true;
			break;
		} else if (trace.debug) {
			LMSG("Failed to deliver email to server: %s", it->c_str());
		}
	}

	if (!delivered) {
		LMSG("WARNING: Failed to deliver email. Email has been discarded.");

		result = FAILURE;
	}

	return result;
}

bool Email::assignValues(const string &req, variable_binding_t &policy_output, ConfigNode *alias_node, ConfigNode *default_node, vector<string> &values) {
	values.clear();

	/* Try settings from policy_output. */
	if (policy_output.find(req) != policy_output.end()) {
		values.push_back(policy_output[req]);
		return true;
	}
	
	/* Try settings from alias. */
	if (values.size() == 0 && alias_node) {
		if (alias_node->assignValues(req, values)) {
			return true;
		}
	}
	
	/* Try default settings. */
	if (values.size() == 0 && default_node) {
		if (default_node->assignValues(req, values)) {
			return true;
		}
	}

	return false;
}

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim600: fdm=marker
** vim: noet ts=3 sw=3
*/
