2020#include "imap-quote.h"
2121#include "imap-login-commands.h"
2222#include "imap-login-settings.h"
23+ #include "imap-capability-list.h"
2324
2425#if LOGIN_MAX_INBUF_SIZE < 1024 + 2
2526# error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters
@@ -93,31 +94,80 @@ static const char *get_capability(struct client *client)
9394{
9495 struct imap_client * imap_client = (struct imap_client * )client ;
9596 string_t * cap_str = t_str_new (256 );
96- bool explicit_capability = FALSE;
97-
98- if (* imap_client -> set -> imap_capability == '\0' )
99- str_append (cap_str , CAPABILITY_BANNER_STRING );
100- else if (* imap_client -> set -> imap_capability != '+' ) {
101- explicit_capability = TRUE;
102- str_append (cap_str , imap_client -> set -> imap_capability );
103- } else {
104- str_append (cap_str , CAPABILITY_BANNER_STRING );
105- str_append_c (cap_str , ' ' );
106- str_append (cap_str , imap_client -> set -> imap_capability + 1 );
107- }
10897
109- if (!explicit_capability ) {
110- if (imap_client -> set -> imap_literal_minus )
111- str_append (cap_str , " LITERAL-" );
112- else
113- str_append (cap_str , " LITERAL+" );
98+ /* iterate capability list and append each capability if conditions met */
99+ const struct imap_capability * capp ;
100+ array_foreach (& imap_client -> capability_list -> imap_capabilities , capp ) {
101+ /* local flags variable will get filled with all the flags
102+ that matched the current conditions -- then at the end
103+ if FLAG_REQUIRE_ALL is present the local flags variable
104+ is compared against the command flags to check for a
105+ perfect match */
106+ uint32_t flags = 0 ;
107+ if (capp -> flags ) {
108+ /* is this pre-auth? (yes) */
109+ if ((capp -> flags & CAP_PREAUTH ) != 0 ) {
110+ flags |= CAP_PREAUTH ;
111+ }
112+ /* is starttls active? */
113+ if ((capp -> flags & CAP_TLSACTIVE ) != 0 &&
114+ client -> starttls ) {
115+ flags |= CAP_TLSACTIVE ;
116+ }
117+ /* is starttls inactive? */
118+ if ((capp -> flags & CAP_TLSINACTIVE ) != 0 &&
119+ !client -> starttls ) {
120+ flags |= CAP_TLSINACTIVE ;
121+ }
122+ /* is ssl active? */
123+ if ((capp -> flags & CAP_SSLACTIVE ) != 0 &&
124+ (!client -> starttls && client -> tls )) {
125+ flags |= CAP_SSLACTIVE ;
126+ }
127+ /* is ssl inactive? */
128+ if ((capp -> flags & CAP_SSLINACTIVE ) != 0 &&
129+ (client -> starttls || !client -> tls )) {
130+ flags |= CAP_SSLINACTIVE ;
131+ }
132+ /* is login disabled? */
133+ if ((capp -> flags & CAP_NO_LOGIN ) != 0 &&
134+ is_login_cmd_disabled (client )) {
135+ flags |= CAP_NO_LOGIN ;
136+ }
137+ /* are we secure? */
138+ if ((capp -> flags & CAP_SECURE ) != 0 &&
139+ client -> tls ) {
140+ flags |= CAP_SECURE ;
141+ }
142+ /* are we insecure? */
143+ if ((capp -> flags & CAP_INSECURE ) != 0 &&
144+ !client -> tls ) {
145+ flags |= CAP_INSECURE ;
146+ }
147+
148+ bool add = FALSE;
149+ /* now check if CAP_REQUIRE_ALL is present */
150+ if ((capp -> flags & CAP_REQUIRE_ALL ) != 0 ) {
151+ /* did we match all? */
152+ if ((capp -> flags & ~CAP_REQUIRE_ALL ) == flags ) {
153+ add = TRUE;
154+ }
155+ /* no CAP_REQUIRE_ALL - did we match any flags? */
156+ } else if (flags > 0 ) {
157+ add = TRUE;
158+ }
159+
160+ /* should we add this entry? */
161+ if (add ) {
162+ if (* str_c (cap_str ) != '\0' ) {
163+ str_append_c (cap_str , ' ' );
164+ }
165+ str_append (cap_str , capp -> command );
166+ }
167+ }
114168 }
115169
116- if (client_is_tls_enabled (client ) && !client -> tls )
117- str_append (cap_str , " STARTTLS" );
118- if (is_login_cmd_disabled (client ))
119- str_append (cap_str , " LOGINDISABLED" );
120-
170+ /* grab the AUTH= capabilities from auth server */
121171 client_authenticate_get_capabilities (client , cap_str );
122172 return str_c (cap_str );
123173}
@@ -381,6 +431,7 @@ static struct client *imap_client_alloc(pool_t pool)
381431static void imap_client_create (struct client * client , void * * other_sets )
382432{
383433 struct imap_client * imap_client = (struct imap_client * )client ;
434+ bool explicit_capability = FALSE;
384435
385436 imap_client -> set = other_sets [0 ];
386437 imap_client -> parser =
@@ -389,6 +440,54 @@ static void imap_client_create(struct client *client, void **other_sets)
389440 IMAP_LOGIN_MAX_LINE_LENGTH );
390441 if (imap_client -> set -> imap_literal_minus )
391442 imap_parser_enable_literal_minus (imap_client -> parser );
443+
444+ /* create our capability list from CAPABILITY_BANNER_STRING */
445+ imap_client -> capability_list =
446+ imap_capability_list_create (NULL );
447+
448+ /* do we have capabilities defined in our settings? */
449+ if (* imap_client -> set -> imap_capability != '\0' ) {
450+ /* does the configuration start with a + sign? */
451+ if (* imap_client -> set -> imap_capability == '+' ) {
452+ /* add the capability banner string to the cap list */
453+ imap_capability_list_append_string (imap_client -> capability_list ,
454+ CAPABILITY_BANNER_STRING );
455+ /* add everything after the plus to our cap list */
456+ imap_capability_list_append_string (imap_client -> capability_list ,
457+ imap_client -> set -> imap_capability + 1 );
458+ } else {
459+ /* add everything to our cap list */
460+ imap_capability_list_append_string (imap_client -> capability_list ,
461+ imap_client -> set -> imap_capability );
462+ explicit_capability = TRUE;
463+ }
464+ } else {
465+ /* add the capability banner string to the cap list */
466+ imap_capability_list_append_string (imap_client -> capability_list ,
467+ CAPABILITY_BANNER_STRING );
468+ }
469+
470+ /* add STARTTLS to cap list if it is needed */
471+ if (strcmp (client -> ssl_set -> ssl , "no" ) != 0 ) {
472+ imap_capability_list_add (imap_client -> capability_list ,
473+ "STARTTLS" , CAP_REQUIRE_ALL | CAP_PREAUTH | CAP_INSECURE );
474+ }
475+
476+ /* add LOGINDISABLED to cap list */
477+ imap_capability_list_add (imap_client -> capability_list ,
478+ "LOGINDISABLED" , CAP_REQUIRE_ALL | CAP_PREAUTH | CAP_NO_LOGIN );
479+
480+ /* Add the LITERAL+/- if the capability isn't explicitly set */
481+ if (!explicit_capability ) {
482+ if (imap_client -> set -> imap_literal_minus ) {
483+ imap_capability_list_add (imap_client -> capability_list ,
484+ "LITERAL-" , CAP_ALWAYS );
485+ } else {
486+ imap_capability_list_add (imap_client -> capability_list ,
487+ "LITERAL+" , CAP_ALWAYS );
488+ }
489+ }
490+
392491 client -> io = io_add_istream (client -> input , client_input , client );
393492}
394493
0 commit comments