make IMAP parsing case insensitive

it's easy to overlook, but the spec demands this. we got away with it so
far, as everyone just uses UPPERCASE ... for the things we use so far.
This commit is contained in:
Oswald Buddenhagen 2021-11-25 13:40:09 +01:00
parent 8d9c68f73a
commit 6b9d4311d2
3 changed files with 22 additions and 6 deletions

View File

@ -189,6 +189,8 @@ void *memrchr( const void *s, int c, size_t n );
size_t strnlen( const char *str, size_t maxlen ); size_t strnlen( const char *str, size_t maxlen );
#endif #endif
void to_upper( char *str, uint len );
int starts_with( const char *str, int strl, const char *cmp, uint cmpl ); int starts_with( const char *str, int strl, const char *cmp, uint cmpl );
int starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl ); int starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl );
int equals( const char *str, int strl, const char *cmp, uint cmpl ); int equals( const char *str, int strl, const char *cmp, uint cmpl );

View File

@ -924,7 +924,7 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
if (sts->level && *s == ')') if (sts->level && *s == ')')
break; break;
cur->len = (uint)(s - p); cur->len = (uint)(s - p);
if (equals( p, (int)cur->len, "NIL", 3 )) if (equals_upper( p, (int)cur->len, "NIL", 3 ))
cur->val = NIL; cur->val = NIL;
else else
cur->val = nfstrndup( p, cur->len ); cur->val = nfstrndup( p, cur->len );
@ -1086,12 +1086,13 @@ parse_fetched_flags( list_t *list, uchar *flags, uchar *status )
} }
if (list->val[0] != '\\' && list->val[0] != '$') if (list->val[0] != '\\' && list->val[0] != '$')
continue; continue;
if (equals( list->val, list->len, "\\Recent", 7 )) { to_upper( list->val, list->len );
if (equals( list->val, list->len, "\\RECENT", 7 )) {
*status |= M_RECENT; *status |= M_RECENT;
goto flagok; goto flagok;
} }
for (uint i = 0; i < as(Flags); i++) { for (uint i = 0; i < as(Flags); i++) {
if (!strcmp( Flags[i], list->val )) { if (!strcasecmp( Flags[i], list->val )) {
*flags |= 1 << i; *flags |= 1 << i;
goto flagok; goto flagok;
} }
@ -1169,9 +1170,10 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list )
error( "IMAP error: bogus item name in FETCH response\n" ); error( "IMAP error: bogus item name in FETCH response\n" );
return LIST_BAD; return LIST_BAD;
} }
const char *name = tmp->val; char *name = tmp->val;
uint namel = tmp->len; uint namel = tmp->len;
tmp = tmp->next; tmp = tmp->next;
to_upper( name, namel );
if (equals( name, namel, "UID", 3 )) { if (equals( name, namel, "UID", 3 )) {
if (!is_atom( tmp ) || (uid = strtoul( tmp->val, &ep, 10 ), *ep)) { if (!is_atom( tmp ) || (uid = strtoul( tmp->val, &ep, 10 ), *ep)) {
error( "IMAP error: unable to parse UID\n" ); error( "IMAP error: unable to parse UID\n" );
@ -1282,6 +1284,7 @@ parse_capability( imap_store_t *ctx, char *cmd )
ctx->auth_mechs = NULL; ctx->auth_mechs = NULL;
ctx->caps = 0x80000000; ctx->caps = 0x80000000;
while ((arg = next_arg( &cmd, &argl ))) { while ((arg = next_arg( &cmd, &argl ))) {
to_upper( arg, argl );
if (starts_with( arg, argl, "AUTH=", 5 )) { if (starts_with( arg, argl, "AUTH=", 5 )) {
add_string_list_n( &ctx->auth_mechs, arg + 5, argl - 5 ); add_string_list_n( &ctx->auth_mechs, arg + 5, argl - 5 );
} else { } else {
@ -1308,6 +1311,7 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
error( "IMAP error: malformed response code\n" ); error( "IMAP error: malformed response code\n" );
return RESP_CANCEL; return RESP_CANCEL;
} }
to_upper( arg, argl );
if (equals( arg, argl, "UIDVALIDITY", 11 )) { if (equals( arg, argl, "UIDVALIDITY", 11 )) {
if (!(arg = next_arg( &s, &argl )) || if (!(arg = next_arg( &s, &argl )) ||
(ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg != ']')) (ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg != ']'))
@ -1374,7 +1378,7 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
ret = RESP_CANCEL; ret = RESP_CANCEL;
break; break;
} }
if (equals( tmp->val, tmp->len, "\\*", 2 ) || equals( tmp->val, tmp->len, "$Forwarded", 10 )) { if (equals( tmp->val, tmp->len, "\\*", 2 ) || equals_upper( tmp->val, tmp->len, "$FORWARDED", 10 )) {
ctx->has_forwarded = 1; ctx->has_forwarded = 1;
break; break;
} }
@ -1621,6 +1625,7 @@ imap_socket_read( void *aux )
break; break;
} }
to_upper( arg, argl );
if (ctx->greeting == GreetingPending && equals( arg, argl, "PREAUTH", 7 )) { if (ctx->greeting == GreetingPending && equals( arg, argl, "PREAUTH", 7 )) {
parse_response_code( ctx, NULL, cmd ); parse_response_code( ctx, NULL, cmd );
ctx->greeting = GreetingPreauth; ctx->greeting = GreetingPreauth;
@ -1661,6 +1666,7 @@ imap_socket_read( void *aux )
resp = parse_list( ctx, cmd, parse_namespace_rsp, "NAMESPACE" ); resp = parse_list( ctx, cmd, parse_namespace_rsp, "NAMESPACE" );
goto listret; goto listret;
} else if ((arg1 = next_arg( &cmd, &argl1 ))) { } else if ((arg1 = next_arg( &cmd, &argl1 ))) {
to_upper( arg1, argl1 );
if (equals( arg1, argl1, "EXISTS", 6 )) { if (equals( arg1, argl1, "EXISTS", 6 )) {
ctx->total_msgs = atoi( arg ); ctx->total_msgs = atoi( arg );
} else if (equals( arg1, argl1, "EXPUNGE", 7 )) { } else if (equals( arg1, argl1, "EXPUNGE", 7 )) {
@ -1736,13 +1742,14 @@ imap_socket_read( void *aux )
error( "IMAP error: malformed tagged response\n" ); error( "IMAP error: malformed tagged response\n" );
break; break;
} }
to_upper( arg, argl );
if (equals( arg, argl, "OK", 2 )) { if (equals( arg, argl, "OK", 2 )) {
if (cmdp->param.to_trash) if (cmdp->param.to_trash)
ctx->trashnc = TrashKnown; /* Can't get NO [TRYCREATE] any more. */ ctx->trashnc = TrashKnown; /* Can't get NO [TRYCREATE] any more. */
resp = RESP_OK; resp = RESP_OK;
} else { } else {
if (equals( arg, argl, "NO", 2 )) { if (equals( arg, argl, "NO", 2 )) {
if (cmdp->param.create && cmd && starts_with( cmd, -1, "[TRYCREATE]", 11 )) { /* APPEND or UID COPY */ if (cmdp->param.create && cmd && starts_with_upper( cmd, -1, "[TRYCREATE]", 11 )) { /* APPEND or UID COPY */
imap_cmd_trycreate_t *cmd2 = imap_cmd_trycreate_t *cmd2 =
(imap_cmd_trycreate_t *)new_imap_cmd( sizeof(*cmd2) ); (imap_cmd_trycreate_t *)new_imap_cmd( sizeof(*cmd2) );
cmd2->orig_cmd = cmdp; cmd2->orig_cmd = cmdp;

View File

@ -284,6 +284,13 @@ strnlen( const char *str, size_t maxlen )
#endif #endif
void
to_upper( char *str, uint len )
{
for (uint i = 0; i < len; i++)
str[i] = toupper( str[i] );
}
int int
starts_with( const char *str, int strl, const char *cmp, uint cmpl ) starts_with( const char *str, int strl, const char *cmp, uint cmpl )
{ {