centralize disposal of parsed IMAP lists

makes the code less cluttered, and it's harder to introduce leaks.

this has the hypothetical disadvantage that due to freeing being
delayed, the peak memory usage would rise significantly if we chained to
another parse_list() call which produces a big list while already
holding a big list, but that isn't the case anywhere.
This commit is contained in:
Oswald Buddenhagen 2019-11-11 13:51:14 +01:00
parent 7af7354dbc
commit b91dd5b3bc

View File

@ -886,6 +886,7 @@ parse_list_continue( imap_store_t *ctx, char *s )
list = (resp == LIST_BAD) ? NULL : ctx->parse_list_sts.head; list = (resp == LIST_BAD) ? NULL : ctx->parse_list_sts.head;
ctx->parse_list_sts.head = NULL; ctx->parse_list_sts.head = NULL;
resp = ctx->parse_list_sts.callback( ctx, list, s ); resp = ctx->parse_list_sts.callback( ctx, list, s );
free_list( list );
} }
return resp; return resp;
} }
@ -910,7 +911,6 @@ parse_namespace_rsp( imap_store_t *ctx, list_t *list, char *s )
if (!list) { if (!list) {
bad: bad:
error( "IMAP error: malformed NAMESPACE response\n" ); error( "IMAP error: malformed NAMESPACE response\n" );
free_list( list );
return LIST_BAD; return LIST_BAD;
} }
if (list->val != NIL) { if (list->val != NIL) {
@ -931,22 +931,19 @@ parse_namespace_rsp( imap_store_t *ctx, list_t *list, char *s )
ctx->ns_delimiter = nsp_1st_dl->val[0]; ctx->ns_delimiter = nsp_1st_dl->val[0];
// Namespace response extensions may follow here; we don't care. // Namespace response extensions may follow here; we don't care.
} }
free_list( list );
return parse_list( ctx, s, parse_namespace_rsp_p2 ); return parse_list( ctx, s, parse_namespace_rsp_p2 );
} }
static int static int
parse_namespace_rsp_p2( imap_store_t *ctx, list_t *list, char *s ) parse_namespace_rsp_p2( imap_store_t *ctx, list_t *list ATTR_UNUSED, char *s )
{ {
free_list( list );
return parse_list( ctx, s, parse_namespace_rsp_p3 ); return parse_list( ctx, s, parse_namespace_rsp_p3 );
} }
static int static int
parse_namespace_rsp_p3( imap_store_t *ctx ATTR_UNUSED, list_t *list, char *s ATTR_UNUSED ) parse_namespace_rsp_p3( imap_store_t *ctx ATTR_UNUSED, list_t *list ATTR_UNUSED, char *s ATTR_UNUSED )
{ {
free_list( list );
return LIST_OK; return LIST_OK;
} }
@ -982,7 +979,6 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
if (!is_list( list )) { if (!is_list( list )) {
error( "IMAP error: bogus FETCH response\n" ); error( "IMAP error: bogus FETCH response\n" );
free_list( list );
return LIST_BAD; return LIST_BAD;
} }
@ -1105,7 +1101,6 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
if (cmdp->param.uid == uid) if (cmdp->param.uid == uid)
goto gotuid; goto gotuid;
error( "IMAP error: unexpected FETCH response (UID %u)\n", uid ); error( "IMAP error: unexpected FETCH response (UID %u)\n", uid );
free_list( list );
return LIST_BAD; return LIST_BAD;
gotuid: gotuid:
msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data; msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data;
@ -1131,7 +1126,6 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
cur->gen.tuid[0] = 0; cur->gen.tuid[0] = 0;
} }
free_list( list );
return LIST_OK; return LIST_OK;
} }
@ -1239,16 +1233,12 @@ parse_list_rsp( imap_store_t *ctx, list_t *list, char *cmd )
list_t *lp; list_t *lp;
if (!is_list( list )) { if (!is_list( list )) {
free_list( list );
error( "IMAP error: malformed LIST response\n" ); error( "IMAP error: malformed LIST response\n" );
return LIST_BAD; return LIST_BAD;
} }
for (lp = list->child; lp; lp = lp->next) for (lp = list->child; lp; lp = lp->next)
if (is_atom( lp ) && !strcasecmp( lp->val, "\\NoSelect" )) { if (is_atom( lp ) && !strcasecmp( lp->val, "\\NoSelect" ))
free_list( list );
return LIST_OK; return LIST_OK;
}
free_list( list );
return parse_list( ctx, cmd, parse_list_rsp_p1 ); return parse_list( ctx, cmd, parse_list_rsp_p1 );
} }
@ -1257,7 +1247,6 @@ parse_list_rsp_p1( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED )
{ {
if (!is_opt_atom( list )) { if (!is_opt_atom( list )) {
error( "IMAP error: malformed LIST response\n" ); error( "IMAP error: malformed LIST response\n" );
free_list( list );
return LIST_BAD; return LIST_BAD;
} }
if (!ctx->delimiter[0] && is_atom( list )) if (!ctx->delimiter[0] && is_atom( list ))
@ -1297,7 +1286,6 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED )
if (!is_atom( list )) { if (!is_atom( list )) {
error( "IMAP error: malformed LIST response\n" ); error( "IMAP error: malformed LIST response\n" );
free_list( list );
return LIST_BAD; return LIST_BAD;
} }
arg = list->val; arg = list->val;
@ -1308,7 +1296,7 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED )
memcpy( arg, "INBOX", 5 ); memcpy( arg, "INBOX", 5 );
} else if ((l = strlen( ctx->prefix ))) { } else if ((l = strlen( ctx->prefix ))) {
if (!starts_with( arg, argl, ctx->prefix, l )) if (!starts_with( arg, argl, ctx->prefix, l ))
goto skip; return LIST_OK;
arg += l; arg += l;
argl -= l; argl -= l;
// A folder named "INBOX" would be indistinguishable from the // A folder named "INBOX" would be indistinguishable from the
@ -1318,19 +1306,17 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED )
if (is_INBOX( ctx, arg, argl )) { if (is_INBOX( ctx, arg, argl )) {
if (!arg[5]) // No need to complain about subfolders as well. if (!arg[5]) // No need to complain about subfolders as well.
warn( "IMAP warning: ignoring INBOX in %s\n", ctx->prefix ); warn( "IMAP warning: ignoring INBOX in %s\n", ctx->prefix );
goto skip; return LIST_OK;
} }
} }
if (argl >= 5 && !memcmp( arg + argl - 5, ".lock", 5 )) /* workaround broken servers */ if (argl >= 5 && !memcmp( arg + argl - 5, ".lock", 5 )) /* workaround broken servers */
goto skip; return LIST_OK;
if (map_name( arg, (char **)&narg, offsetof(string_list_t, string), ctx->delimiter, "/") < 0) { if (map_name( arg, (char **)&narg, offsetof(string_list_t, string), ctx->delimiter, "/") < 0) {
warn( "IMAP warning: ignoring mailbox %s (reserved character '/' in name)\n", arg ); warn( "IMAP warning: ignoring mailbox %s (reserved character '/' in name)\n", arg );
goto skip; return LIST_OK;
} }
narg->next = ctx->boxes; narg->next = ctx->boxes;
ctx->boxes = narg; ctx->boxes = narg;
skip:
free_list( list );
return LIST_OK; return LIST_OK;
} }