]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: server: Add support for adding (non-standard) extra capabilities.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sat, 3 Nov 2018 10:18:46 +0000 (11:18 +0100)
committerStephan Bosch <stephan.bosch@dovecot.fi>
Wed, 12 Dec 2018 00:27:32 +0000 (01:27 +0100)
src/lib-smtp/smtp-server-cmd-helo.c
src/lib-smtp/smtp-server-connection.c
src/lib-smtp/smtp-server-private.h
src/lib-smtp/smtp-server.h

index c5e734615cc35bf8fc86f684a5a3954199f06a85..4b0584c1b0de176208e6e1fd13a4869c7e4d9811 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "str.h"
+#include "array.h"
 #include "smtp-syntax.h"
 
 #include "smtp-server-private.h"
@@ -129,8 +130,29 @@ void smtp_server_cmd_helo(struct smtp_server_cmd_ctx *cmd,
 struct smtp_server_reply *
 smtp_server_cmd_ehlo_reply_create(struct smtp_server_cmd_ctx *cmd)
 {
+       static struct {
+               const char *name;
+               void (*add)(struct smtp_server_reply *reply);
+       } standard_caps[] = {
+               /* Sorted alphabetically */
+               { "8BITMIME", smtp_server_reply_ehlo_add_8bitmime },
+               { "BINARYMIME", smtp_server_reply_ehlo_add_binarymime },
+               { "CHUNKING", smtp_server_reply_ehlo_add_chunking },
+               { "DSN", smtp_server_reply_ehlo_add_dsn },
+               { "ENHANCEDSTATUSCODES",
+                 smtp_server_reply_ehlo_add_enhancedstatuscodes },
+               { "PIPELINING", smtp_server_reply_ehlo_add_pipelining },
+               { "SIZE", smtp_server_reply_ehlo_add_size },
+               { "STARTTLS", smtp_server_reply_ehlo_add_starttls },
+               { "VRFY", smtp_server_reply_ehlo_add_vrfy },
+               { "XCLIENT", smtp_server_reply_ehlo_add_xclient }
+       };
+       const unsigned int standard_caps_count = N_ELEMENTS(standard_caps);
+       struct smtp_server_connection *conn = cmd->conn;
        struct smtp_server_command *command = cmd->cmd;
        struct smtp_server_cmd_helo *helo_data = command->data;
+       const struct smtp_capability_extra *extra_caps = NULL;
+       unsigned int extra_caps_count, i, j;
        struct smtp_server_reply *reply;
 
        i_assert(cmd->cmd->reg->func == smtp_server_cmd_ehlo);
@@ -139,17 +161,27 @@ smtp_server_cmd_ehlo_reply_create(struct smtp_server_cmd_ctx *cmd)
        if (helo_data->helo.old_smtp)
                return reply;
 
-       smtp_server_reply_ehlo_add_8bitmime(reply);
-       smtp_server_reply_ehlo_add_binarymime(reply);
-       smtp_server_reply_ehlo_add_chunking(reply);
-       smtp_server_reply_ehlo_add_dsn(reply);
-       smtp_server_reply_ehlo_add_enhancedstatuscodes(reply);
-       smtp_server_reply_ehlo_add_pipelining(reply);
-       smtp_server_reply_ehlo_add_size(reply);
-       smtp_server_reply_ehlo_add_starttls(reply);
-       smtp_server_reply_ehlo_add_vrfy(reply);
-       smtp_server_reply_ehlo_add_xclient(reply);
+       extra_caps_count = 0;
+       if (array_is_created(&conn->extra_capabilities)) {
+               extra_caps = array_get(&conn->extra_capabilities,
+                                      &extra_caps_count);
+       }
 
+       i = j = 0;
+       while (i < standard_caps_count || j < extra_caps_count) {
+               if (i < standard_caps_count && 
+                   (j >= extra_caps_count ||
+                    strcasecmp(standard_caps[i].name,
+                               extra_caps[j].name) < 0)) {
+                       standard_caps[i].add(reply);
+                       i++;
+               } else {
+                       smtp_server_reply_ehlo_add_params(
+                               reply, extra_caps[j].name,
+                               extra_caps[j].params);
+                       j++;
+               }
+       }
        return reply;
 }
 
index a2b3f81dfcfff61e68770e8eb662c1f8362f14ec..131e390f221239c7d86e2053d8a0f840ac592c6f 100644 (file)
@@ -14,6 +14,7 @@
 #include "master-service.h"
 #include "master-service-ssl.h"
 
+#include "smtp-syntax.h"
 #include "smtp-reply-parser.h"
 #include "smtp-command-parser.h"
 #include "smtp-server-private.h"
@@ -1436,6 +1437,49 @@ void smtp_server_connection_set_capabilities(
        conn->set.capabilities = capabilities;
 }
 
+void smtp_server_connection_add_extra_capability(
+       struct smtp_server_connection *conn,
+       const struct smtp_capability_extra *cap)
+{
+       const struct smtp_capability_extra *cap_idx;
+       struct smtp_capability_extra cap_new;
+       unsigned int insert_idx;
+       pool_t pool = conn->pool;
+
+       /* Avoid committing protocol errors */
+       i_assert(smtp_ehlo_keyword_is_valid(cap->name));
+       i_assert(smtp_ehlo_params_are_valid(cap->params));
+
+       /* Cannot override standard capabiltiies */
+       i_assert(smtp_capability_find_by_name(cap->name)
+                == SMTP_CAPABILITY_NONE);
+
+       if (!array_is_created(&conn->extra_capabilities))
+               p_array_init(&conn->extra_capabilities, pool, 4);
+
+       /* Keep array sorted */
+       insert_idx = array_count(&conn->extra_capabilities);
+       array_foreach(&conn->extra_capabilities, cap_idx) {
+               int cmp = strcasecmp(cap_idx->name, cap->name);
+
+               /* Prohibit duplicates */
+               i_assert(cmp != 0);
+
+               if (cmp > 0) {
+                       insert_idx = array_foreach_idx(
+                               &conn->extra_capabilities, cap_idx);
+                       break;
+               }
+       }
+
+       i_zero(&cap_new);
+       cap_new.name = p_strdup(pool, cap->name);
+       if (cap->params != NULL)
+               cap_new.params = p_strarray_dup(pool, cap->params);
+
+       array_insert(&conn->extra_capabilities, insert_idx, &cap_new, 1);
+}
+
 void *smtp_server_connection_get_context(struct smtp_server_connection *conn)
 {
        return conn->context;
index 70f8762797eab7100487e2260f5b3e1d7fb0f10b..746c29f619a1e9bbb346e0f86066a91c75601949 100644 (file)
@@ -144,6 +144,7 @@ struct smtp_server_connection {
 
        struct smtp_server_settings set;
 
+       ARRAY(struct smtp_capability_extra) extra_capabilities;
        ARRAY_TYPE(const_string) mail_param_extensions; /* NULL-terminated */
        ARRAY_TYPE(const_string) rcpt_param_extensions; /* NULL-terminated */
 
index ff9ee92f5e90d0fe1f67082a11c5fc10f3cf0248..1c6ff697dfda4394545c1098c5f1a90b07273ef3 100644 (file)
@@ -427,6 +427,9 @@ void smtp_server_connection_get_proxy_data(struct smtp_server_connection *conn,
 
 void smtp_server_connection_set_capabilities(
        struct smtp_server_connection *conn, enum smtp_capability capabilities);
+void smtp_server_connection_add_extra_capability(
+       struct smtp_server_connection *conn,
+       const struct smtp_capability_extra *cap);
 
 void smtp_server_connection_register_mail_param(
        struct smtp_server_connection *conn, const char *param);