#ifndef MASTER_AUTH_H
#define MASTER_AUTH_H

#include "net.h"

struct master_service;

/* Major version changes are not backwards compatible,
   minor version numbers can be ignored. */
#define AUTH_MASTER_PROTOCOL_MAJOR_VERSION 1
#define AUTH_MASTER_PROTOCOL_MINOR_VERSION 1

/* Authentication client process's cookie size */
#define MASTER_AUTH_COOKIE_SIZE (128/8)

/* LOGIN_MAX_INBUF_SIZE should be based on this. Keep this large enough so that
   LOGIN_MAX_INBUF_SIZE will be 1024+2 bytes. This is because IMAP ID command's
   values may be max. 1024 bytes plus 2 for "" quotes. (Although it could be
   even double of that when value is full of \" quotes, but for now lets not
   make it too easy to waste memory..) */
#define MASTER_AUTH_MAX_DATA_SIZE (1024 + 128 + 64 + 2)

#define MASTER_AUTH_ERRMSG_INTERNAL_FAILURE \
	"Internal error occurred. Refer to server log for more information."

enum mail_auth_request_flags {
	/* Connection has TLS compression enabled */
	MAIL_AUTH_REQUEST_FLAG_TLS_COMPRESSION	= BIT(0),
	/* Connection is secure (SSL or just trusted) */
	MAIL_AUTH_REQUEST_FLAG_CONN_SECURED = BIT(1),
	/* Connection is secured using SSL specifically */
	MAIL_AUTH_REQUEST_FLAG_CONN_SSL_SECURED = BIT(2),
	/* This login is implicit; no command reply is expected */
	MAIL_AUTH_REQUEST_FLAG_IMPLICIT = BIT(3),
};

/* Authentication request. File descriptor may be sent along with the
   request. */
struct master_auth_request {
	/* Request tag. Reply is sent back using same tag. */
	unsigned int tag;

	/* Authentication process, authentication ID and auth cookie. */
	pid_t auth_pid;
	unsigned int auth_id;
	unsigned int client_pid;
	uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];

	/* Properties of the connection. The file descriptor
	   itself may be a local socketpair. */
	struct ip_addr local_ip, remote_ip;
	in_port_t local_port, remote_port;

	uint32_t flags;

	/* request follows this many bytes of client input */
	uint32_t data_size;
	/* inode of the transferred fd. verified just to be sure that the
	   correct fd is mapped to the correct struct. */
	ino_t ino;
};

enum master_auth_status {
	MASTER_AUTH_STATUS_OK,
	MASTER_AUTH_STATUS_INTERNAL_ERROR
};

struct master_auth_reply {
	/* tag=0 are notifications from master */
	unsigned int tag;
	enum master_auth_status status;
	/* PID of the post-login mail process handling this connection */
	pid_t mail_pid;
};

struct master_auth_request_params {
	/* Client fd to transfer to post-login process or -1 if no fd is
	   wanted to be transferred. */
	int client_fd;
	/* Override master_auth->default_path if non-NULL */
	const char *socket_path;

	/* Authentication request that is sent to post-login process.
	   tag is ignored. */
	struct master_auth_request request;
	/* Client input of size request.data_size */
	const unsigned char *data;
};

/* reply=NULL if the auth lookup was cancelled due to some error */
typedef void master_auth_callback_t(const struct master_auth_reply *reply,
				    void *context);

struct master_auth *
master_auth_init(struct master_service *service, const char *path);
void master_auth_deinit(struct master_auth **auth);

/* Send an authentication request. Returns tag which can be used to abort the
   request (ie. ignore the reply from master). */
void master_auth_request_full(struct master_auth *auth,
			      const struct master_auth_request_params *params,
			      master_auth_callback_t *callback, void *context,
			      unsigned int *tag_r);
/* For backwards compatibility: */
void master_auth_request(struct master_auth *auth, int fd,
			 const struct master_auth_request *request,
			 const unsigned char *data,
			 master_auth_callback_t *callback,
			 void *context, unsigned int *tag_r);
void master_auth_request_abort(struct master_auth *auth, unsigned int tag);

#endif
