]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: server: Add hooks API for recipient.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 7 Oct 2018 18:42:20 +0000 (20:42 +0200)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 12 Feb 2019 13:41:00 +0000 (15:41 +0200)
src/lib-smtp/smtp-server-private.h
src/lib-smtp/smtp-server-recipient.c
src/lib-smtp/smtp-server.h

index 3d78040e33cb6c994d73a2bef723faec654a1c4a..f537a9bbea9e9e381b2a78c44079c645d0b6d6f8 100644 (file)
@@ -54,6 +54,14 @@ struct smtp_server_command_hook {
        void *context;
 };
 
+struct smtp_server_recipient_hook {
+       enum smtp_server_recipient_hook_type type;
+       struct smtp_server_recipient_hook *prev, *next;
+
+       smtp_server_rcpt_func_t *func;
+       void *context;
+};
+
 struct smtp_server_reply_content {
        unsigned int status;
        const char *status_prefix;
@@ -102,6 +110,12 @@ struct smtp_server_command {
        bool reply_early:1;
 };
 
+struct smtp_server_recipient_private {
+       struct smtp_server_recipient rcpt;
+
+       struct smtp_server_recipient_hook *hooks_head, *hooks_tail;
+};
+
 struct smtp_server_state_data {
        enum smtp_server_state state;
        time_t timestamp;
index 9589b71de619dbd3bea82aec5fbf1d464636bea9..8e384c4cec9a842fdd6ad01895ef836a64f3e558 100644 (file)
@@ -1,24 +1,29 @@
 /* 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)
@@ -30,6 +35,9 @@ 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);
 }
 
@@ -40,4 +48,83 @@ void smtp_server_recipient_approved(struct smtp_server_recipient *rcpt)
        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;
+       }
 }
index ff4c61b56d37c804b188d29c81d03dbb9dcf3c80..5e85786b940d730187cb59483130ef00eee16181 100644 (file)
@@ -17,6 +17,8 @@ struct smtp_server_cmd_mail;
 struct smtp_server_cmd_ctx;
 struct smtp_server_command;
 struct smtp_server_reply;
+struct smtp_server_recipient;
+struct smtp_server_transaction;
 
 struct smtp_server;
 
@@ -48,6 +50,17 @@ struct smtp_server_helo_data {
  * 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;
@@ -60,6 +73,25 @@ struct smtp_server_recipient {
 };
 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
  */