smtp-server.h revision 912e87d5be9dd8895e8cb7c6cb51d8a752edbe8c
#ifndef SMTP_SERVER_H
#define SMTP_SERVER_H
#include "smtp-common.h"
#include "smtp-command.h"
#include "smtp-params.h"
struct smtp_address;
struct smtp_reply;
struct smtp_command;
struct smtp_server_helo_data;
struct smtp_server_esmtp_param;
struct smtp_server_cmd_ehlo;
struct smtp_server_cmd_mail;
struct smtp_server_cmd_ctx;
struct smtp_server_command;
struct smtp_server_reply;
struct smtp_server;
/*
* Types
*/
enum smtp_server_state {
};
extern const char *const smtp_server_state_names[];
struct smtp_server_helo_data {
const char *domain;
};
/*
* Transaction
*/
struct smtp_server_recipient {
struct smtp_address *path;
struct smtp_params_rcpt params;
void *context;
};
struct smtp_server_transaction {
struct smtp_server_connection *conn;
const char *id;
struct smtp_address *mail_from;
struct smtp_params_mail params;
void *context;
};
struct smtp_server_transaction *trans,
struct smtp_server_cmd_ctx *data_cmd,
struct smtp_server_transaction *trans);
/*
* Callbacks
*/
struct smtp_server_cmd_helo {
struct smtp_server_helo_data helo;
different from a previous one */
};
struct smtp_server_cmd_mail {
struct smtp_address *path;
struct smtp_params_mail params;
};
struct smtp_server_cmd_rcpt {
struct smtp_address *path;
struct smtp_params_rcpt params;
/* called once the recipient is definitively added to the transaction */
struct smtp_server_transaction *trans,
struct smtp_server_recipient *rcpt,
unsigned int index);
void *trans_context;
};
struct smtp_server_cmd_auth {
const char *sasl_mech;
const char *initial_response;
};
struct smtp_server_callbacks {
/* Command callbacks:
SMTP commands. Commands are handled asynchronously, which means that
the command is not necessarily finished when the callback ends. A
command is finished either when 1 is returned or a reply is submitted
for it. When a callback returns 0, the command implementation is
waiting for an external event and when it returns -1 an error
occurred. When 1 is returned, a default success reply is set if no
reply was submitted. Not submitting an error reply when -1 is
returned causes an assert fail. Except for RCPT and DATA, all these
callbacks are optional to implement; appropriate default behavior is
provided.
The SMTP server API takes care of transaction state checking.
However, until all previous commands are handled, a transaction
command cannot rely on the transaction state being final. Use
cmd->hook_next to get notified when all previous commands are
finished and the current command is next in line to reply.
If the implementation does not need asynchronous behavior, set
max_pipelined_commands=1 and don't return 0 from any command handler.
*/
int (*conn_cmd_helo)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
/* STARTTLS */
int (*conn_cmd_starttls)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd);
/* AUTH */
int (*conn_cmd_auth)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_auth *data);
int (*conn_cmd_auth_continue)(void *conn_ctx,
/* MAIL */
int (*conn_cmd_mail)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
/* RCPT */
int (*conn_cmd_rcpt)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_rcpt *data);
/* RSET */
int (*conn_cmd_rset)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd);
/* DATA */
int (*conn_cmd_data_begin)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input);
int (*conn_cmd_data_continue)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans);
/* VRFY */
int (*conn_cmd_vrfy)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
const char *param);
/* NOOP */
int (*conn_cmd_noop)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd);
/* QUIT */
int (*conn_cmd_quit)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd);
/* XCLIENT */
void (*conn_cmd_xclient)(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_proxy_data *data);
/* Command input callbacks:
These can be used to do stuff before and after a pipelined group of
commands is read.
*/
void (*conn_cmd_input_pre)(void *context);
void (*conn_cmd_input_post)(void *context);
/* Transaction events */
void (*conn_trans_free)(void *context,
struct smtp_server_transaction *trans);
/* Protocol state events */
void (*conn_state_changed)(void *context,
enum smtp_server_state newstate);
/* Proxy data */
void (*conn_proxy_data_updated)(void *conn_ctx,
const struct smtp_proxy_data *data);
/* Connection */
int (*conn_start_tls)(void *conn_ctx,
void (*conn_destroy)(void *context);
/* Security */
bool (*conn_is_trusted)(void *context);
};
/*
* Server
*/
struct smtp_server_settings {
enum smtp_protocol protocol;
enum smtp_capability capabilities;
const char *hostname;
const char *login_greeting;
const char *rawlog_dir;
/* The maximum time in milliseconds a client is allowed to be idle
before it is disconnected. */
unsigned int max_client_idle_time_msecs;
/* maximum number of commands in pipeline per connection (default = 1)
*/
unsigned int max_pipelined_commands;
/* maximum number of sequential bad commands */
unsigned int max_bad_commands;
/* maximum number of recipients in a transaction
(0 means unlimited, which is the default) */
unsigned int max_recipients;
/* command limits */
struct smtp_command_limits command_limits;
/* accept these additional custom XCLIENT fields */
const char *const *xclient_extensions;
Configuring this is mainly useful for the test suite. The kernel
defaults are used when these settings are 0. */
bool debug:1;
bool auth_optional:1;
bool tls_required:1;
bool rcpt_domain_optional:1;
bool param_extensions:1;
};
struct smtp_server_stats {
unsigned int command_count, reply_count;
};
/*
* Connection
*/
/* Create connection. It is still inactive and needs to be started with
one of the functions below. */
struct smtp_server_connection *
struct smtp_server_connection *
const struct smtp_server_settings *set,
/* Initialize the connection with state and data from login service */
const unsigned char *pdata,
unsigned int pdata_len, bool ssl_secured);
/* Start the connection. Establishes SSL layer immediately if instructed,
and sends the greeting once the connection is ready for commands. */
/* Start the connection, but only establish SSL layer and send greeting;
handling command input is held off until smtp_server_connection_resume() is
called. */
/* Halt connection command input and idle timeout entirely. */
/* Resume connection command input and idle timeout. */
ATTR_NULL(3);
bool client_input);
enum smtp_server_state
const char *
struct smtp_server_transaction *
const char *
const struct smtp_server_stats *
enum smtp_protocol
const char *
struct smtp_server_helo_data *
struct smtp_proxy_data *proxy_data);
/*
* Command
*/
enum smtp_server_command_flags {
};
/* Commands are handled asynchronously, which means that the command is not
necessary finished when the start function ends. A command is finished
when a reply is submitted for it. Several command hooks are available to
get notified about events in the command's life cycle.
*/
const char *params);
struct smtp_server_cmd_ctx {
const char *name;
struct smtp_server *server;
struct smtp_server_connection *conn;
struct smtp_server_command *cmd;
/* public hooks */
/* next: command is next to reply but has not submittted all replies
yet */
/* replied: command has submitted all replies */
/* completed: server is about to send last replies for this command */
/* destroy: command is about to be destroyed */
void *context;
};
/* The core SMTP commands are pre-registered. Special connection callbacks are
provided for the core SMTP commands. Only use this command registration API
*/
enum smtp_server_command_flags);
const char *name);
unsigned int count);
struct smtp_server_reply *
unsigned int idx);
unsigned int status);
/* AUTH */
const char *challenge);
const char *username, const char *success_msg)
ATTR_NULL(3);
/*
* Reply
*/
struct smtp_server_reply *
ATTR_NULL(3);
struct smtp_server_reply *
struct smtp_server_reply *
const char *line);
/* Submit a reply for the command at the specified index (> 0 only if more than
a single reply is expected). */
/* Submit the reply for the specified command. */
/* Forward a reply for the command at the specified index (> 0 only if more
than a single reply is expected). */
/* Forward the reply for the specified command. */
const struct smtp_reply *from);
/* Submit the same message for all expected replies for this command. */
/* Submit and send the same message for all expected replies for this command
early; i.e., no matter whether all command data is received completely. */
/* Reply the command with a 221 bye message */
/* EHLO */
struct smtp_server_reply *
const char *keyword);
#endif