Skip to content
Snippets Groups Projects
sieve-test.c 9.81 KiB
Newer Older
/* Copyright (c) 2002-2011 Pigeonhole authors, see the included COPYING file
Stephan Bosch's avatar
Stephan Bosch committed
 */
#include "lib-signals.h"
#include "ioloop.h"
#include "env-util.h"
#include "str.h"
#include "mail-namespace.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "mail-storage-service.h"
#include "sieve-extensions.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <sysexits.h>

Stephan Bosch's avatar
Stephan Bosch committed
/* 
 * Configuration
 */

#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail"
#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"

Stephan Bosch's avatar
Stephan Bosch committed
/*
 * Print help
 */

"Usage: sieve-test [-a <orig-recipient-address] [-c <config-file>]\n"
"                  [-C] [-D] [-d <dump-filename>] [-e]\n"
"                  [-f <envelope-sender>] [-l <mail-location>]\n"
"                  [-m <default-mailbox>] [-P <plugin>]\n"
"                  [-r <recipient-address>] [-s <script-file>]\n"
"                  [-t <trace-file>] [-T <trace-option>] [-x <extensions>]\n"
/*
 * Dummy SMTP session
 */

static void *sieve_smtp_open
(void *script_ctx ATTR_UNUSED, const char *destination,
	const char *return_path, FILE **file_r)
{
	i_info("sending message from <%s> to <%s>:",
		( return_path == NULL ? "" : return_path ), destination);
	printf("\nSTART MESSAGE:\n");
	
	*file_r = stdout;
	
	return NULL;	
}

static bool sieve_smtp_close
(void *script_ctx ATTR_UNUSED, void *handle ATTR_UNUSED)
{
	printf("END MESSAGE\n\n");
	return TRUE;
}

/*
 * Dummy duplicate check implementation
 */

static int duplicate_check
(void *script_context ATTR_UNUSED, const void *id ATTR_UNUSED, 
	size_t id_size ATTR_UNUSED, const char *user)
{
	i_info("checked duplicate for user %s.\n", user);
	return 0;
}

static void duplicate_mark
(void *script_context ATTR_UNUSED, const void *id ATTR_UNUSED, 
	size_t id_size ATTR_UNUSED, const char *user, 
	time_t time ATTR_UNUSED)
{
	i_info("marked duplicate for user %s.\n", user);
}

Stephan Bosch's avatar
Stephan Bosch committed
/*
 * Tool implementation
 */

	const char *scriptfile, *recipient, *final_recipient, *sender, *mailbox,
		*dumpfile, *tracefile, *mailfile, *mailloc;
	struct sieve_binary *main_sbin, *sbin = NULL;
	struct sieve_message_data msgdata;
	struct sieve_script_env scriptenv;
	struct sieve_error_handler *ehandler;
	struct ostream *teststream = NULL;
	bool force_compile = FALSE, execute = FALSE;
	int exit_status = EXIT_SUCCESS;
		("sieve-test", &argc, &argv, "r:a:f:m:d:l:s:eCt:T:DP:x:u:", FALSE);
	scriptfile = recipient = final_recipient = sender = mailbox = dumpfile =
		tracefile = mailfile = mailloc = NULL;
	memset(&tr_config, 0, sizeof(tr_config));
	while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
		switch (c) {
		case 'r':
		case 'a':
			/* original recipient address */
			recipient = optarg;
			break;
		case 'f':
			/* envelope sender address */
			sender = optarg;
			break;
		case 'm':
			mailbox = optarg;
			break;
Stephan Bosch's avatar
Stephan Bosch committed
		case 'l':
			/* mail location */
			mailloc = optarg;
			break;
			/* trace options */
		case 'T':
			sieve_tool_parse_trace_option(&tr_config, optarg);
		case 'd':
			/* dump file */
			dumpfile = optarg;
			break;
Stephan Bosch's avatar
Stephan Bosch committed
		case 's': 
			/* scriptfile executed before main script */
			{
				const char *file;			

				file = t_strdup(optarg);
				array_append(&scriptfiles, &file, 1);
			}
Stephan Bosch's avatar
Stephan Bosch committed
			break;
			/* execution mode */
Stephan Bosch's avatar
Stephan Bosch committed
		case 'e':
			execute = TRUE;
			break;
			/* force script compile */
Stephan Bosch's avatar
Stephan Bosch committed
			force_compile = TRUE;
			break;
		default:
			/* unrecognized option */
			print_help();
			i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
Stephan Bosch's avatar
Stephan Bosch committed
			break;
		}
	}

	if ( optind < argc ) {
		scriptfile = argv[optind++];
	} else { 
		print_help();
		i_fatal_status(EX_USAGE, "Missing <script-file> argument");
	if ( optind < argc ) {
		mailfile = argv[optind++];
		i_fatal_status(EX_USAGE, "Missing <mail-file> argument");
	if (optind != argc) {
		i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
	svinst = sieve_tool_init_finish(sieve_tool, execute && mailloc == NULL);
	/* Enable debug extension */
	sieve_enable_debug_extension(svinst);
	ehandler = sieve_stderr_ehandler_create(svinst, 0);
	sieve_system_ehandler_set(ehandler);
	sieve_error_handler_accept_infolog(ehandler, TRUE);

	if ( force_compile ) {
		main_sbin = sieve_tool_script_compile(svinst, scriptfile, NULL);
		if ( main_sbin != NULL )
			(void) sieve_save(main_sbin, NULL, TRUE, NULL);
		main_sbin = sieve_tool_script_open(svinst, scriptfile);
	if ( main_sbin == NULL ) {
		exit_status = EXIT_FAILURE;
	} else {
		sieve_tool_dump_binary_to(main_sbin, dumpfile, FALSE);
		/* Obtain mail namespaces from -l argument */
		if ( mailloc != NULL ) {
			sieve_tool_init_mail_user(sieve_tool, mailloc);
		/* Initialize raw mail object */
		mail = sieve_tool_open_file_as_mail(sieve_tool, mailfile);
		sieve_tool_get_envelope_data(mail, &recipient, &sender);
		if ( mailbox == NULL )
			mailbox = "INBOX";
		/* Collect necessary message data */
		memset(&msgdata, 0, sizeof(msgdata));
		msgdata.return_path = sender;
		msgdata.orig_envelope_to = recipient;
		msgdata.final_envelope_to =
			( final_recipient == NULL ? recipient : final_recipient );
		msgdata.auth_user = sieve_tool_get_username(sieve_tool);
		(void)mail_get_first_header(mail, "Message-ID", &msgdata.id);
		/* Create streams for test and trace output */

		if ( !execute )
			teststream = o_stream_create_fd(1, 0, FALSE);

		if ( tracefile != NULL )
			tracestream = sieve_tool_open_output_stream(tracefile);
		/* Compose script environment */
		memset(&scriptenv, 0, sizeof(scriptenv));
		scriptenv.default_mailbox = "INBOX";
		scriptenv.user = sieve_tool_get_mail_user(sieve_tool);
		scriptenv.username = sieve_tool_get_username(sieve_tool);
		scriptenv.hostname = "host.example.com";
		scriptenv.postmaster_address = "postmaster@example.com";
		scriptenv.smtp_open = sieve_smtp_open;
		scriptenv.smtp_close = sieve_smtp_close;
		scriptenv.duplicate_mark = duplicate_mark;
		scriptenv.duplicate_check = duplicate_check;
		scriptenv.trace_stream = tracestream;
		scriptenv.exec_status = &estatus;
		if ( array_count(&scriptfiles) == 0 ) {
			/* Single script */
			sbin = main_sbin;
			main_sbin = NULL;
Stephan Bosch's avatar
Stephan Bosch committed
	
			/* Execute/Test script */
			if ( execute )
				ret = sieve_execute
					(sbin, &msgdata, &scriptenv, ehandler, NULL);
				ret = sieve_test
					(sbin, &msgdata, &scriptenv, ehandler, teststream, NULL);				
		} else {
			/* Multiple scripts */
			const char *const *sfiles;
			unsigned int i, count;
			struct sieve_multiscript *mscript;
			bool more = TRUE;
			int result;

			if ( execute )
				mscript = sieve_multiscript_start_execute
			else
				mscript = sieve_multiscript_start_test
					(svinst, &msgdata, &scriptenv, teststream);
			/* Execute scripts sequentially */
			sfiles = array_get(&scriptfiles, &count); 
			for ( i = 0; i < count && more; i++ ) {
				if ( teststream != NULL ) 
					o_stream_send_str(teststream, 
						t_strdup_printf("\n## Executing script: %s\n", sfiles[i]));
				/* Close previous script */
				if ( sbin != NULL )						
					sieve_close(&sbin);
				/* Compile sieve script */
				if ( force_compile ) {
					sbin = sieve_tool_script_compile(svinst, sfiles[i], sfiles[i]);
					if ( sbin != NULL )
						(void) sieve_save(sbin, NULL, FALSE, NULL);
					sbin = sieve_tool_script_open(svinst, sfiles[i]);
				more = sieve_multiscript_run(mscript, sbin, ehandler, FALSE);
			/* Execute/Test main script */
				if ( teststream != NULL ) 
					o_stream_send_str(teststream, 
						t_strdup_printf("## Executing script: %s\n", scriptfile));
				/* Close previous script */
				if ( sbin != NULL )						
					sieve_close(&sbin);	
Stephan Bosch's avatar
Stephan Bosch committed
				
				sbin = main_sbin;
				main_sbin = NULL;
				sieve_multiscript_run(mscript, sbin, ehandler, TRUE);
			result = sieve_multiscript_finish(&mscript, ehandler, NULL);
		/* Run */
		switch ( ret ) {
		case SIEVE_EXEC_OK:
			i_info("final result: success");
			break;
		case SIEVE_EXEC_BIN_CORRUPT:
			i_info("corrupt binary deleted.");
			(void) unlink(sieve_binary_path(sbin));
		case SIEVE_EXEC_FAILURE:
			i_info("final result: failed; resolved with successful implicit keep");
			break;
		case SIEVE_EXEC_KEEP_FAILED:
			i_info("final result: utter failure");
			break;
		default:
			i_info("final result: unrecognized return value?!");	
		if ( teststream != NULL )
			o_stream_destroy(&teststream);
		/* Cleanup remaining binaries */
		if ( sbin != NULL )
			sieve_close(&sbin);
		if ( main_sbin != NULL ) 
			sieve_close(&main_sbin);
	/* Cleanup error handler */
	sieve_error_handler_unref(&ehandler);

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.