/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "llist.h"
#include "smtp-address.h"
#include "smtp-server-private.h"
+static void
+smtp_server_recipient_call_hooks(struct smtp_server_recipient *rcpt,
+ enum smtp_server_recipient_hook_type type);
+
struct smtp_server_recipient *
smtp_server_recipient_create(struct smtp_server_connection *conn,
const struct smtp_address *rcpt_to)
{
- struct smtp_server_recipient *rcpt;
+ struct smtp_server_recipient_private *prcpt;
pool_t pool;
pool = pool_alloconly_create("smtp server recipient", 512);
- rcpt = p_new(pool, struct smtp_server_recipient, 1);
- rcpt->pool = pool;
- rcpt->conn = conn;
- rcpt->path = smtp_address_clone(pool, rcpt_to);
+ prcpt = p_new(pool, struct smtp_server_recipient_private, 1);
+ prcpt->rcpt.pool = pool;
+ prcpt->rcpt.conn = conn;
+ prcpt->rcpt.path = smtp_address_clone(pool, rcpt_to);
- return rcpt;
+ return &prcpt->rcpt;
}
void smtp_server_recipient_destroy(struct smtp_server_recipient **_rcpt)
if (rcpt == NULL)
return;
+ smtp_server_recipient_call_hooks(
+ rcpt, SMTP_SERVER_RECIPIENT_HOOK_DESTROY);
+
pool_unref(&rcpt->pool);
}
i_assert(trans != NULL);
smtp_server_transaction_add_rcpt(trans, rcpt);
+
+ smtp_server_recipient_call_hooks(
+ rcpt, SMTP_SERVER_RECIPIENT_HOOK_APPROVED);
+}
+
+#undef smtp_server_recipient_add_hook
+void smtp_server_recipient_add_hook(struct smtp_server_recipient *rcpt,
+ enum smtp_server_recipient_hook_type type,
+ smtp_server_rcpt_func_t func, void *context)
+{
+ struct smtp_server_recipient_private *prcpt =
+ (struct smtp_server_recipient_private *)rcpt;
+ struct smtp_server_recipient_hook *hook;
+
+ i_assert(func != NULL);
+
+ hook = prcpt->hooks_head;
+ while (hook != NULL) {
+ /* no double registrations */
+ i_assert(hook->type != type || hook->func != func);
+
+ hook = hook->next;
+ }
+
+ hook = p_new(rcpt->pool, struct smtp_server_recipient_hook, 1);
+ hook->type = type;
+ hook->func = func;
+ hook->context = context;
+
+ DLLIST2_APPEND(&prcpt->hooks_head, &prcpt->hooks_tail, hook);
+}
+
+#undef smtp_server_recipient_remove_hook
+void smtp_server_recipient_remove_hook(
+ struct smtp_server_recipient *rcpt,
+ enum smtp_server_recipient_hook_type type,
+ smtp_server_rcpt_func_t *func)
+{
+ struct smtp_server_recipient_private *prcpt =
+ (struct smtp_server_recipient_private *)rcpt;
+ struct smtp_server_recipient_hook *hook;
+ bool found = FALSE;
+
+ hook = prcpt->hooks_head;
+ while (hook != NULL) {
+ struct smtp_server_recipient_hook *hook_next = hook->next;
+
+ if (hook->type == type && hook->func == func) {
+ DLLIST2_REMOVE(&prcpt->hooks_head, &prcpt->hooks_tail,
+ hook);
+ found = TRUE;
+ break;
+ }
+
+ hook = hook_next;
+ }
+ i_assert(found);
+}
+
+static void
+smtp_server_recipient_call_hooks(struct smtp_server_recipient *rcpt,
+ enum smtp_server_recipient_hook_type type)
+{
+ struct smtp_server_recipient_private *prcpt =
+ (struct smtp_server_recipient_private *)rcpt;
+ struct smtp_server_recipient_hook *hook;
+
+ hook = prcpt->hooks_head;
+ while (hook != NULL) {
+ struct smtp_server_recipient_hook *hook_next = hook->next;
+
+ if (hook->type == type) {
+ DLLIST2_REMOVE(&prcpt->hooks_head, &prcpt->hooks_tail,
+ hook);
+ hook->func(rcpt, hook->context);
+ }
+
+ hook = hook_next;
+ }
}
struct smtp_server_cmd_ctx;
struct smtp_server_command;
struct smtp_server_reply;
+struct smtp_server_recipient;
+struct smtp_server_transaction;
struct smtp_server;
* Recipient
*/
+enum smtp_server_recipient_hook_type {
+ /* approved: the server is about to approve this recipient by sending
+ a success reply to the RCPT command. */
+ SMTP_SERVER_RECIPIENT_HOOK_APPROVED,
+ /* destroy: recipient is about to be destroyed. */
+ SMTP_SERVER_RECIPIENT_HOOK_DESTROY
+};
+
+typedef void smtp_server_rcpt_func_t(struct smtp_server_recipient *rcpt,
+ void *context);
+
struct smtp_server_recipient {
pool_t pool;
struct smtp_server_connection *conn;
};
ARRAY_DEFINE_TYPE(smtp_server_recipient, struct smtp_server_recipient *);
+/* Hooks */
+
+void smtp_server_recipient_add_hook(struct smtp_server_recipient *rcpt,
+ enum smtp_server_recipient_hook_type type,
+ smtp_server_rcpt_func_t func,
+ void *context);
+#define smtp_server_recipient_add_hook(_rcpt, _type, _func, _context) \
+ smtp_server_recipient_add_hook((_rcpt), (_type) + \
+ CALLBACK_TYPECHECK(_func, void (*)( \
+ struct smtp_server_recipient *, typeof(_context))), \
+ (smtp_server_rcpt_func_t *)(_func), (_context))
+void smtp_server_recipient_remove_hook(
+ struct smtp_server_recipient *rcpt,
+ enum smtp_server_recipient_hook_type type,
+ smtp_server_rcpt_func_t *func);
+#define smtp_server_recipient_remove_hook(_rcpt, _type, _func) \
+ smtp_server_recipient_remove_hook((_rcpt), (_type), \
+ (smtp_server_rcpt_func_t *)(_func));
+
/*
* Transaction
*/