#ifndef SIEVE_H
#define SIEVE_H

struct sieve_script;
struct sieve_binary;

#include "sieve-config.h"
#include "sieve-types.h"
#include "sieve-error.h"

/*
 * Main Sieve library interface
 */

/* sieve_init():
 *   Initializes the sieve engine. Must be called before any sieve functionality
 *   is used.
 */
struct sieve_instance *sieve_init(const struct sieve_environment *env,
				  const struct sieve_callbacks *callbacks,
				  void *context, bool debug);

/* sieve_deinit():
 *   Frees all memory allocated by the sieve engine.
 */
void sieve_deinit(struct sieve_instance **_svinst);

/* sieve_get_capabilities():
 *
 */
const char *sieve_get_capabilities(struct sieve_instance *svinst,
				   const char *name);

/* sieve_set_extensions():
 *
 */
void sieve_set_extensions(struct sieve_instance *svinst,
			  const char *extensions);


/* sieve_get_event():
 *
 */
struct event *sieve_get_event(struct sieve_instance *svinst) ATTR_PURE;

/*
 * Script compilation
 */

/* sieve_compile_script:
 */
struct sieve_binary *sieve_compile_script(struct sieve_script *script,
					  struct sieve_error_handler *ehandler,
					  enum sieve_compile_flags flags,
					  enum sieve_error *error_r)
					  ATTR_NULL(2, 4);

/* sieve_compile:
 *
 *   Compiles the script into a binary.
 */
struct sieve_binary *sieve_compile(struct sieve_instance *svinst,
				   const char *script_location,
				   const char *script_name,
				   struct sieve_error_handler *ehandler,
				   enum sieve_compile_flags flags,
				   enum sieve_error *error_r)
				   ATTR_NULL(3, 4, 6);

/*
 * Reading/writing Sieve binaries
 */

/* sieve_load:
 *
 *  Loads the sieve binary indicated by the provided path.
 */
struct sieve_binary *sieve_load(struct sieve_instance *svinst,
				const char *bin_path,
				enum sieve_error *error_r);

/* sieve_open_script:
 *
 *   First tries to open the binary version of the specified script and if it
 *   does not exist or if it contains errors, the script is (re-)compiled. Note
 *   that errors in the bytecode are caught only at runtime.
 */
struct sieve_binary *sieve_open_script(struct sieve_script *script,
				       struct sieve_error_handler *ehandler,
				       enum sieve_compile_flags flags,
				       enum sieve_error *error_r);

/* sieve_open:
 *
 *   First tries to open the binary version of the specified script and if it
 *   does not exist or if it contains errors, the script is (re-)compiled. Note
 *   that errors in the bytecode are caught only at runtime.
 */
struct sieve_binary *sieve_open(struct sieve_instance *svinst,
				const char *script_location,
				const char *script_name,
				struct sieve_error_handler *ehandler,
				enum sieve_compile_flags flags,
				enum sieve_error *error_r);

/* sieve_save_as:
 *
 *  Saves the binary as the file indicated by the path parameter. This function
 *  will not write the binary to disk when it was loaded from the indicated
 *  bin_path, unless update is TRUE.
 */
int sieve_save_as(struct sieve_binary *sbin, const char *bin_path, bool update,
		  mode_t save_mode, enum sieve_error *error_r);

/* sieve_save:
 *
 *  Saves the binary to the default location. This function will not overwrite
 *  the binary it was loaded earlier from the default location, unless update
 *  is TRUE.
 */
int sieve_save(struct sieve_binary *sbin, bool update,
	       enum sieve_error *error_r);

/* sieve_close:
 *
 *   Closes a compiled/opened sieve binary.
 */
void sieve_close(struct sieve_binary **sbin);

/* sieve_get_source:
 *
 *   Obtains the path the binary was compiled or loaded from
 */
const char *sieve_get_source(struct sieve_binary *sbin);

/*
 * sieve_is_loeded:
 *
 *   Indicates whether the binary was loaded from a pre-compiled file.
 */
bool sieve_is_loaded(struct sieve_binary *sbin);

/*
 * Debugging
 */

/* sieve_dump:
 *
 *   Dumps the byte code in human-readable form to the specified ostream.
 */
void sieve_dump(struct sieve_binary *sbin,
		struct ostream *stream, bool verbose);

/* sieve_hexdump:
 *
 *   Dumps the byte code in hexdump form to the specified ostream.
 */

void sieve_hexdump(struct sieve_binary *sbin, struct ostream *stream);

/* sieve_test:
 *
 *   Executes the bytecode, but only prints the result to the given stream.
 */
int sieve_test(struct sieve_binary *sbin,
	       const struct sieve_message_data *msgdata,
	       const struct sieve_script_env *senv,
	       struct sieve_error_handler *ehandler, struct ostream *stream,
	       enum sieve_execute_flags flags, bool *keep);

/*
 * Script execution
 */

/* sieve_script_env_init:
 *
 *   Initializes the scirpt environment from the given mail_user.
 */
int sieve_script_env_init(struct sieve_script_env *senv, struct mail_user *user,
			  const char **error_r);

/* sieve_execute:
 *
 *   Executes the binary, including the result.
 */
int sieve_execute(struct sieve_binary *sbin,
		  const struct sieve_message_data *msgdata,
		  const struct sieve_script_env *senv,
		  struct sieve_error_handler *exec_ehandler,
		  struct sieve_error_handler *action_ehandler,
		  enum sieve_execute_flags flags, bool *keep);

/*
 * Multiscript support
 */

struct sieve_multiscript;

struct sieve_multiscript *
sieve_multiscript_start_execute(struct sieve_instance *svinst,
				const struct sieve_message_data *msgdata,
				const struct sieve_script_env *senv);
struct sieve_multiscript *
sieve_multiscript_start_test(struct sieve_instance *svinst,
			     const struct sieve_message_data *msgdata,
			     const struct sieve_script_env *senv,
			     struct ostream *stream);

bool sieve_multiscript_run(struct sieve_multiscript *mscript,
			   struct sieve_binary *sbin,
			   struct sieve_error_handler *exec_ehandler,
			   struct sieve_error_handler *action_ehandler,
			   enum sieve_execute_flags flags);

bool sieve_multiscript_will_discard(struct sieve_multiscript *mscript);
void sieve_multiscript_run_discard(struct sieve_multiscript *mscript,
				   struct sieve_binary *sbin,
				   struct sieve_error_handler *exec_ehandler,
				   struct sieve_error_handler *action_ehandler,
				   enum sieve_execute_flags flags);

int sieve_multiscript_status(struct sieve_multiscript *mscript);

int sieve_multiscript_tempfail(struct sieve_multiscript **_mscript,
			       struct sieve_error_handler *action_ehandler,
			       enum sieve_execute_flags flags);
int sieve_multiscript_finish(struct sieve_multiscript **_mscript,
			     struct sieve_error_handler *action_ehandler,
			     enum sieve_execute_flags flags, bool *keep);

/*
 * Configured limits
 */

unsigned int sieve_max_redirects(struct sieve_instance *svinst);
unsigned int sieve_max_actions(struct sieve_instance *svinst);
size_t sieve_max_script_size(struct sieve_instance *svinst);

/*
 * User log
 */

const char *sieve_user_get_log_path(struct sieve_instance *svinst,
				    struct sieve_script *user_script)
				    ATTR_NULL(2);

/*
 * Script trace log
 */

struct sieve_trace_log;

int sieve_trace_log_create(struct sieve_instance *svinst, const char *path,
			   struct sieve_trace_log **trace_log_r) ATTR_NULL(2);
int sieve_trace_log_create_dir(struct sieve_instance *svinst, const char *dir,
			       struct sieve_trace_log **trace_log_r)
			       ATTR_NULL(3);

int sieve_trace_log_open(struct sieve_instance *svinst,
			 struct sieve_trace_log **trace_log_r) ATTR_NULL(2);

void sieve_trace_log_printf(struct sieve_trace_log *trace_log,
			    const char *fmt, ...) ATTR_FORMAT(2, 3);

void sieve_trace_log_free(struct sieve_trace_log **_trace_log);

int sieve_trace_config_get(struct sieve_instance *svinst,
			   struct sieve_trace_config *tr_config);

#endif
