]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: client: Add support for recording extra (non-standard) capabilities from...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Tue, 16 Oct 2018 22:59:02 +0000 (00:59 +0200)
committerStephan Bosch <stephan.bosch@dovecot.fi>
Mon, 29 Oct 2018 16:39:05 +0000 (17:39 +0100)
src/lib-smtp/smtp-client-connection.c
src/lib-smtp/smtp-client-connection.h
src/lib-smtp/smtp-client-private.h
src/lib-smtp/smtp-client.c
src/lib-smtp/smtp-client.h
src/lib-smtp/smtp-common.h

index 6b299aba617c58c276f6eee3a1cf483d2e6aba6f..c1e548890cacf80dec656e3bb9b6bb760281de60 100644 (file)
@@ -56,6 +56,33 @@ uoff_t smtp_client_connection_get_size_capability(
        return conn->caps.size;
 }
 
+void smtp_client_connection_accept_extra_capability(
+       struct smtp_client_connection *conn, const char *cap_name)
+{
+       cap_name = p_strdup(conn->pool, cap_name);
+
+       if (!array_is_created(&conn->extra_capabilities))
+               p_array_init(&conn->extra_capabilities, conn->pool, 8);
+       array_append(&conn->extra_capabilities, &cap_name, 1);
+}
+
+const struct smtp_capability_extra *
+smtp_client_connection_get_extra_capability(struct smtp_client_connection *conn,
+                                           const char *name)
+{
+       const struct smtp_capability_extra *cap;
+
+       if (!array_is_created(&conn->caps.extra))
+               return NULL;
+
+       array_foreach(&conn->caps.extra, cap) {
+               if (strcasecmp(cap->name, name) == 0)
+                       return cap;
+       }
+
+       return NULL;
+}
+
 /*
  * Logging
  */
@@ -872,6 +899,42 @@ smtp_client_connection_starttls(struct smtp_client_connection *conn)
        return smtp_client_connection_init_xclient(conn);
 }
 
+static bool
+smtp_client_connection_has_extra_capability(struct smtp_client_connection *conn,
+                                          const char *cap_name)
+{
+       const char *const *cap_idx;
+
+       if (!array_is_created(&conn->extra_capabilities))
+               return FALSE;
+       array_foreach(&conn->extra_capabilities, cap_idx) {
+               if (strcasecmp(*cap_idx, cap_name) == 0)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static void
+smtp_client_connection_record_exta_capability(
+       struct smtp_client_connection *conn, const char *cap_name,
+       const char *const *params)
+{
+       struct smtp_capability_extra cap_extra;
+       pool_t pool = conn->cap_pool;
+
+       if (!smtp_client_connection_has_extra_capability(conn, cap_name))
+               return;
+
+       if (!array_is_created(&conn->caps.extra))
+               p_array_init(&conn->caps.extra, pool, 4);
+
+       i_zero(&cap_extra);
+       cap_extra.name = p_strdup(pool, cap_name);
+       cap_extra.params = p_strarray_dup(pool, params);
+
+       array_append(&conn->caps.extra, &cap_extra, 1);
+}
+
 static void
 smtp_client_connection_handshake_cb(const struct smtp_reply *reply,
                                    struct smtp_client_connection *conn)
@@ -949,6 +1012,10 @@ smtp_client_connection_handshake_cb(const struct smtp_reply *reply,
                        conn->caps.xclient_args =
                                p_strarray_dup(conn->cap_pool, params);
                        break;
+               case SMTP_CAPABILITY_NONE:
+                       smtp_client_connection_record_exta_capability(
+                               conn, cap_name, params);
+                       break;
                default:
                        break;
                }
@@ -1769,6 +1836,10 @@ smtp_client_connection_do_create(struct smtp_client *client, const char *name,
                        conn->set.my_hostname = p_strdup(pool, set->my_hostname);
 
                conn->set.forced_capabilities |= set->forced_capabilities;
+               if (set->extra_capabilities != NULL) {
+                       conn->set.extra_capabilities =
+                               p_strarray_dup(pool, set->extra_capabilities);
+               }
 
                if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0')
                        conn->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir);
@@ -1823,6 +1894,18 @@ smtp_client_connection_do_create(struct smtp_client *client, const char *name,
                conn->set.peer_trusted = set->peer_trusted;
        }
 
+
+       if (set != NULL && set->extra_capabilities != NULL) {
+               const char *const *extp;
+
+               p_array_init(&conn->extra_capabilities, pool,
+                            str_array_length(set->extra_capabilities) + 8);
+               for (extp = set->extra_capabilities; *extp != NULL; extp++) {
+                       const char *ext = p_strdup(pool, *extp);
+                       array_append(&conn->extra_capabilities, &ext, 1);
+               }
+       }
+
        i_assert(conn->set.my_hostname != NULL &&
                *conn->set.my_hostname != '\0');
 
index 08eb3d30f90c1b4231d841400ffbced5cf197d28..dc0d8861380740d11611fa139d0fc4c866730c62 100644 (file)
@@ -73,6 +73,12 @@ enum smtp_capability
 smtp_client_connection_get_capabilities(struct smtp_client_connection *conn);
 uoff_t smtp_client_connection_get_size_capability(
        struct smtp_client_connection *conn);
+void smtp_client_connection_accept_extra_capability(
+       struct smtp_client_connection *conn, const char *cap_name);
+const struct smtp_capability_extra *
+smtp_client_connection_get_extra_capability(struct smtp_client_connection *conn,
+                                           const char *name);
+
 enum smtp_client_connection_state
 smtp_client_connection_get_state(struct smtp_client_connection *conn);
 
index d144b5e63d27096b1a9cac7860c72d541a57851e..5f5da079673eee65abb33e196b06ca6fefd028cd 100644 (file)
@@ -152,10 +152,12 @@ struct smtp_client_connection {
 
        struct smtp_client_settings set;
        char *password;
+       ARRAY_TYPE(const_string) extra_capabilities;
 
        pool_t cap_pool;
        struct {
                enum smtp_capability standard;
+               ARRAY(struct smtp_capability_extra) extra;
                const char **auth_mechanisms;
                const char **xclient_args;
                uoff_t size;
index 6e5049133391ca99dcf3c438eb287d883d0f49e4..f1e5abb72e127c0b694cf84e99b82f04eea16c9b 100644 (file)
@@ -35,6 +35,10 @@ struct smtp_client *smtp_client_init(const struct smtp_client_settings *set)
        client->set.my_hostname = p_strdup(pool, set->my_hostname);
 
        client->set.forced_capabilities = set->forced_capabilities;
+       if (set->extra_capabilities != NULL) {
+               client->set.extra_capabilities =
+                       p_strarray_dup(pool, set->extra_capabilities);
+       }
 
        client->set.dns_client = set->dns_client;
        client->set.dns_client_socket_path =
index cefe24b19a82afa09ca5c20a889f52e037f625a9..fe8fd55f2203f9e903ceb93b6a8936b3bc810ac1 100644 (file)
@@ -45,6 +45,8 @@ struct smtp_client_settings {
        /* Capabilities that are assumed to be enabled no matter whether the
           server indicates support. */
        enum smtp_capability forced_capabilities;
+       /* Record these extra capabilities if returned in the EHLO response */
+       const char *const *extra_capabilities;
 
        struct dns_client *dns_client;
        const char *dns_client_socket_path;
index c257a16bca8dcf110e3ecc2718b8a56824ef91f0..598f96544ad61ea1d4d646c46007fa2dfd2831bb 100644 (file)
@@ -47,10 +47,17 @@ enum smtp_capability {
 
        SMTP_CAPABILITY__ORCPT              = BIT(24),
 };
+
 struct smtp_capability_name {
        const char *name;
        enum smtp_capability capability;
 };
+
+struct smtp_capability_extra {
+       const char *name;
+       const char *const *params;
+};
+
 extern const struct smtp_capability_name smtp_capability_names[];
 
 enum smtp_capability smtp_capability_find_by_name(const char *cap_name);