|
@@ -641,6 +641,12 @@ next_arg( char **ps )
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+is_opt_atom( list_t *list )
|
|
|
+{
|
|
|
+ return list && list->val && list->val != LIST;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
is_atom( list_t *list )
|
|
|
{
|
|
@@ -841,33 +847,50 @@ static int parse_namespace_rsp_p2( imap_store_t *, list_t *, char * );
|
|
|
static int parse_namespace_rsp_p3( imap_store_t *, list_t *, char * );
|
|
|
|
|
|
static int
|
|
|
-parse_namespace_rsp_fail( void )
|
|
|
+parse_namespace_check( list_t *list )
|
|
|
{
|
|
|
+ if (!list)
|
|
|
+ goto bad;
|
|
|
+ if (list->val == NIL)
|
|
|
+ return 0;
|
|
|
+ if (list->val != LIST)
|
|
|
+ goto bad;
|
|
|
+ for (list = list->child; list; list = list->next) {
|
|
|
+ if (list->val != LIST)
|
|
|
+ goto bad;
|
|
|
+ if (!is_atom( list->child ))
|
|
|
+ goto bad;
|
|
|
+ if (!is_opt_atom( list->child->next ))
|
|
|
+ goto bad;
|
|
|
+ /* Namespace response extensions may follow here; we don't care. */
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ bad:
|
|
|
error( "IMAP error: malformed NAMESPACE response\n" );
|
|
|
- return LIST_BAD;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
parse_namespace_rsp( imap_store_t *ctx, list_t *list, char *s )
|
|
|
{
|
|
|
- if (!(ctx->ns_personal = list))
|
|
|
- return parse_namespace_rsp_fail();
|
|
|
+ if (parse_namespace_check( (ctx->ns_personal = list) ))
|
|
|
+ return LIST_BAD;
|
|
|
return parse_list( ctx, s, parse_namespace_rsp_p2 );
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
parse_namespace_rsp_p2( imap_store_t *ctx, list_t *list, char *s )
|
|
|
{
|
|
|
- if (!(ctx->ns_other = list))
|
|
|
- return parse_namespace_rsp_fail();
|
|
|
+ if (parse_namespace_check( (ctx->ns_other = list) ))
|
|
|
+ return LIST_BAD;
|
|
|
return parse_list( ctx, s, parse_namespace_rsp_p3 );
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
parse_namespace_rsp_p3( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
|
|
|
{
|
|
|
- if (!(ctx->ns_shared = list))
|
|
|
- return parse_namespace_rsp_fail();
|
|
|
+ if (parse_namespace_check( (ctx->ns_shared = list) ))
|
|
|
+ return LIST_BAD;
|
|
|
return LIST_OK;
|
|
|
}
|
|
|
|
|
@@ -1964,7 +1987,9 @@ imap_open_store_authenticate2( imap_store_t *ctx )
|
|
|
imap_server_conf_t *srvc = cfg->server;
|
|
|
string_list_t *mech, *cmech;
|
|
|
int auth_login = 0;
|
|
|
+ int skipped_login = 0;
|
|
|
#ifdef HAVE_LIBSASL
|
|
|
+ const char *saslavail;
|
|
|
char saslmechs[1024], *saslend = saslmechs;
|
|
|
#endif
|
|
|
|
|
@@ -1976,19 +2001,20 @@ imap_open_store_authenticate2( imap_store_t *ctx )
|
|
|
if (!strcasecmp( cmech->string, "LOGIN" )) {
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
if (ctx->conn.ssl || !any)
|
|
|
+#else
|
|
|
+ if (!any)
|
|
|
#endif
|
|
|
auth_login = 1;
|
|
|
- } else {
|
|
|
+ else
|
|
|
+ skipped_login = 1;
|
|
|
#ifdef HAVE_LIBSASL
|
|
|
+ } else {
|
|
|
int len = strlen( cmech->string );
|
|
|
if (saslend + len + 2 > saslmechs + sizeof(saslmechs))
|
|
|
oob();
|
|
|
*saslend++ = ' ';
|
|
|
memcpy( saslend, cmech->string, len + 1 );
|
|
|
saslend += len;
|
|
|
-#else
|
|
|
- error( "IMAP error: authentication mechanism %s is not supported\n", cmech->string );
|
|
|
- goto bail;
|
|
|
#endif
|
|
|
}
|
|
|
}
|
|
@@ -2016,6 +2042,8 @@ imap_open_store_authenticate2( imap_store_t *ctx )
|
|
|
|
|
|
rc = sasl_client_new( "imap", srvc->sconf.host, NULL, NULL, NULL, 0, &ctx->sasl );
|
|
|
if (rc != SASL_OK) {
|
|
|
+ if (rc == SASL_NOMECH)
|
|
|
+ goto notsasl;
|
|
|
if (!ctx->sasl)
|
|
|
goto saslbail;
|
|
|
error( "Error: %s\n", sasl_errdetail( ctx->sasl ) );
|
|
@@ -2023,6 +2051,8 @@ imap_open_store_authenticate2( imap_store_t *ctx )
|
|
|
}
|
|
|
|
|
|
rc = sasl_client_start( ctx->sasl, saslmechs + 1, &interact, CAP(SASLIR) ? &out : NULL, &out_len, &gotmech );
|
|
|
+ if (rc == SASL_NOMECH)
|
|
|
+ goto notsasl;
|
|
|
if (gotmech)
|
|
|
info( "Authenticating with SASL mechanism %s...\n", gotmech );
|
|
|
/* Technically, we are supposed to loop over sasl_client_start(),
|
|
@@ -2041,6 +2071,16 @@ imap_open_store_authenticate2( imap_store_t *ctx )
|
|
|
imap_exec( ctx, cmd, done_sasl_auth, enc ? "AUTHENTICATE %s %s" : "AUTHENTICATE %s", gotmech, enc );
|
|
|
free( enc );
|
|
|
return;
|
|
|
+ notsasl:
|
|
|
+ if (!ctx->sasl || sasl_listmech( ctx->sasl, NULL, "", "", "", &saslavail, NULL, NULL ) != SASL_OK)
|
|
|
+ saslavail = "(none)"; /* EXTERNAL is always there anyway. */
|
|
|
+ if (!auth_login) {
|
|
|
+ error( "IMAP error: selected SASL mechanism(s) not available;\n"
|
|
|
+ " selected:%s\n available: %s\n", saslmechs, saslavail );
|
|
|
+ goto skipnote;
|
|
|
+ }
|
|
|
+ info( "NOT using available SASL mechanism(s): %s\n", saslavail );
|
|
|
+ sasl_dispose( &ctx->sasl );
|
|
|
}
|
|
|
#endif
|
|
|
if (auth_login) {
|
|
@@ -2055,6 +2095,12 @@ imap_open_store_authenticate2( imap_store_t *ctx )
|
|
|
return;
|
|
|
}
|
|
|
error( "IMAP error: server supports no acceptable authentication mechanism\n" );
|
|
|
+#ifdef HAVE_LIBSASL
|
|
|
+ skipnote:
|
|
|
+#endif
|
|
|
+ if (skipped_login)
|
|
|
+ error( "Note: not using LOGIN because connection is not encrypted;\n"
|
|
|
+ " use 'AuthMechs LOGIN' explicitly to force it.\n" );
|
|
|
|
|
|
bail:
|
|
|
imap_open_store_bail( ctx, FAIL_FINAL );
|
|
@@ -2129,22 +2175,20 @@ static void
|
|
|
imap_open_store_namespace2( imap_store_t *ctx )
|
|
|
{
|
|
|
imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
|
|
|
- list_t *nsp, *nsp_1st, *nsp_1st_ns, *nsp_1st_dl;
|
|
|
+ list_t *nsp, *nsp_1st;
|
|
|
|
|
|
/* XXX for now assume 1st personal namespace */
|
|
|
if (is_list( (nsp = ctx->ns_personal) ) &&
|
|
|
- is_list( (nsp_1st = nsp->child) ) &&
|
|
|
- is_atom( (nsp_1st_ns = nsp_1st->child) ) &&
|
|
|
- is_atom( (nsp_1st_dl = nsp_1st_ns->next) ))
|
|
|
+ is_list( (nsp_1st = nsp->child) ))
|
|
|
{
|
|
|
+ list_t *nsp_1st_ns = nsp_1st->child;
|
|
|
+ list_t *nsp_1st_dl = nsp_1st_ns->next;
|
|
|
if (!ctx->prefix && cfg->use_namespace)
|
|
|
ctx->prefix = nsp_1st_ns->val;
|
|
|
- if (!ctx->delimiter[0])
|
|
|
+ if (!ctx->delimiter[0] && is_atom( nsp_1st_dl ))
|
|
|
ctx->delimiter[0] = nsp_1st_dl->val[0];
|
|
|
- imap_open_store_finalize( ctx );
|
|
|
- } else {
|
|
|
- imap_open_store_bail( ctx, FAIL_FINAL );
|
|
|
}
|
|
|
+ imap_open_store_finalize( ctx );
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -2318,7 +2362,7 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t ex
|
|
|
imap_submit_load( ctx, buf, 0, sts );
|
|
|
}
|
|
|
if (maxuid == INT_MAX)
|
|
|
- maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 1000000000;
|
|
|
+ maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 0x7fffffff;
|
|
|
if (maxuid >= minuid) {
|
|
|
if ((ctx->gen.opts & OPEN_FIND) && minuid < newuid) {
|
|
|
sprintf( buf, "%d:%d", minuid, newuid - 1 );
|