optimize string operations in IMAP parser
the string length is knowable in advance everywhere, so we can use that for strdups and short-circuiting comparisons.
This commit is contained in:
parent
c5e967f94d
commit
8d9c68f73a
|
@ -192,6 +192,7 @@ size_t strnlen( const char *str, size_t maxlen );
|
||||||
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 );
|
||||||
|
int equals_upper( const char *str, int strl, const char *cmp, uint cmpl );
|
||||||
|
|
||||||
#ifndef HAVE_TIMEGM
|
#ifndef HAVE_TIMEGM
|
||||||
time_t timegm( struct tm *tm );
|
time_t timegm( struct tm *tm );
|
||||||
|
|
141
src/drv_imap.c
141
src/drv_imap.c
|
@ -240,20 +240,23 @@ enum CAPABILITY {
|
||||||
COMPRESS_DEFLATE
|
COMPRESS_DEFLATE
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *cap_list[] = {
|
static const struct {
|
||||||
"LOGINDISABLED",
|
const char *str;
|
||||||
|
uint len;
|
||||||
|
} cap_list[] = {
|
||||||
|
{ "LOGINDISABLED", 13 },
|
||||||
#ifdef HAVE_LIBSASL
|
#ifdef HAVE_LIBSASL
|
||||||
"SASL-IR",
|
{ "SASL-IR", 7 },
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
"STARTTLS",
|
{ "STARTTLS", 8 },
|
||||||
#endif
|
#endif
|
||||||
"UIDPLUS",
|
{ "UIDPLUS", 7 },
|
||||||
"LITERAL+",
|
{ "LITERAL+", 8 },
|
||||||
"LITERAL-",
|
{ "LITERAL-", 8 },
|
||||||
"MOVE",
|
{ "MOVE", 4 },
|
||||||
"NAMESPACE",
|
{ "NAMESPACE", 9 },
|
||||||
"COMPRESS=DEFLATE"
|
{ "COMPRESS=DEFLATE", 16 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RESP_OK 0
|
#define RESP_OK 0
|
||||||
|
@ -719,7 +722,7 @@ imap_strchr( const char *s, char tc )
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
next_arg( char **ps )
|
next_arg( char **ps, uint *len )
|
||||||
{
|
{
|
||||||
char *ret, *s, *d;
|
char *ret, *s, *d;
|
||||||
char c;
|
char c;
|
||||||
|
@ -747,19 +750,26 @@ next_arg( char **ps )
|
||||||
*d++ = c;
|
*d++ = c;
|
||||||
}
|
}
|
||||||
*d = 0;
|
*d = 0;
|
||||||
|
*len = (uint)(d - ret);
|
||||||
|
if (!*s)
|
||||||
|
s = NULL;
|
||||||
} else {
|
} else {
|
||||||
ret = s;
|
ret = s;
|
||||||
while ((c = *s)) {
|
while ((c = *s)) {
|
||||||
if (isspace( (uchar)c )) {
|
if (isspace( (uchar)c )) {
|
||||||
|
*len = (uint)(s - ret);
|
||||||
*s++ = 0;
|
*s++ = 0;
|
||||||
break;
|
if (!*s)
|
||||||
|
s = NULL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
}
|
*len = (uint)(s - ret);
|
||||||
if (!*s)
|
|
||||||
s = NULL;
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
*ps = s;
|
*ps = s;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1076,7 +1086,7 @@ 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 (!strcmp( "\\Recent", list->val )) {
|
if (equals( list->val, list->len, "\\Recent", 7 )) {
|
||||||
*status |= M_RECENT;
|
*status |= M_RECENT;
|
||||||
goto flagok;
|
goto flagok;
|
||||||
}
|
}
|
||||||
|
@ -1160,13 +1170,14 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list )
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
}
|
}
|
||||||
const char *name = tmp->val;
|
const char *name = tmp->val;
|
||||||
|
uint namel = tmp->len;
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
if (!strcmp( "UID", name )) {
|
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" );
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
}
|
}
|
||||||
} else if (!strcmp( "FLAGS", name )) {
|
} else if (equals( name, namel, "FLAGS", 5 )) {
|
||||||
if (!is_list( tmp )) {
|
if (!is_list( tmp )) {
|
||||||
error( "IMAP error: unable to parse FLAGS\n" );
|
error( "IMAP error: unable to parse FLAGS\n" );
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
|
@ -1174,7 +1185,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list )
|
||||||
if (!parse_fetched_flags( tmp->child, &mask, &status ))
|
if (!parse_fetched_flags( tmp->child, &mask, &status ))
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
status |= M_FLAGS;
|
status |= M_FLAGS;
|
||||||
} else if (!strcmp( "INTERNALDATE", name )) {
|
} else if (equals( name, namel, "INTERNALDATE", 12 )) {
|
||||||
if (!is_atom( tmp )) {
|
if (!is_atom( tmp )) {
|
||||||
error( "IMAP error: unable to parse INTERNALDATE\n" );
|
error( "IMAP error: unable to parse INTERNALDATE\n" );
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
|
@ -1184,27 +1195,27 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list )
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
}
|
}
|
||||||
status |= M_DATE;
|
status |= M_DATE;
|
||||||
} else if (!strcmp( "RFC822.SIZE", name )) {
|
} else if (equals( name, namel, "RFC822.SIZE", 11 )) {
|
||||||
if (!is_atom( tmp ) || (size = strtoul( tmp->val, &ep, 10 ), *ep)) {
|
if (!is_atom( tmp ) || (size = strtoul( tmp->val, &ep, 10 ), *ep)) {
|
||||||
error( "IMAP error: unable to parse RFC822.SIZE\n" );
|
error( "IMAP error: unable to parse RFC822.SIZE\n" );
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
}
|
}
|
||||||
status |= M_SIZE;
|
status |= M_SIZE;
|
||||||
} else if (!strcmp( "BODY[]", name ) || !strcmp( "BODY[HEADER]", name )) {
|
} else if (equals( name, namel, "BODY[]", 6 ) || equals( name, namel, "BODY[HEADER]", 12 )) {
|
||||||
if (!is_atom( tmp )) {
|
if (!is_atom( tmp )) {
|
||||||
error( "IMAP error: unable to parse BODY[]\n" );
|
error( "IMAP error: unable to parse BODY[]\n" );
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
}
|
}
|
||||||
body = tmp;
|
body = tmp;
|
||||||
status |= M_BODY;
|
status |= M_BODY;
|
||||||
} else if (!strcmp( "BODY[HEADER.FIELDS", name )) {
|
} else if (equals( name, namel, "BODY[HEADER.FIELDS", 18 )) {
|
||||||
if (!is_list( tmp )) {
|
if (!is_list( tmp )) {
|
||||||
bfail:
|
bfail:
|
||||||
error( "IMAP error: unable to parse BODY[HEADER.FIELDS ...]\n" );
|
error( "IMAP error: unable to parse BODY[HEADER.FIELDS ...]\n" );
|
||||||
return LIST_BAD;
|
return LIST_BAD;
|
||||||
}
|
}
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
if (!is_atom( tmp ) || strcmp( tmp->val, "]" ))
|
if (!is_atom( tmp ) || !equals( tmp->val, tmp->len, "]", 1 ))
|
||||||
goto bfail;
|
goto bfail;
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
if (!is_atom( tmp ))
|
if (!is_atom( tmp ))
|
||||||
|
@ -1265,52 +1276,53 @@ static void
|
||||||
parse_capability( imap_store_t *ctx, char *cmd )
|
parse_capability( imap_store_t *ctx, char *cmd )
|
||||||
{
|
{
|
||||||
char *arg;
|
char *arg;
|
||||||
uint i;
|
uint i, argl;
|
||||||
|
|
||||||
free_string_list( ctx->auth_mechs );
|
free_string_list( ctx->auth_mechs );
|
||||||
ctx->auth_mechs = NULL;
|
ctx->auth_mechs = NULL;
|
||||||
ctx->caps = 0x80000000;
|
ctx->caps = 0x80000000;
|
||||||
while ((arg = next_arg( &cmd ))) {
|
while ((arg = next_arg( &cmd, &argl ))) {
|
||||||
if (starts_with( arg, -1, "AUTH=", 5 )) {
|
if (starts_with( arg, argl, "AUTH=", 5 )) {
|
||||||
add_string_list( &ctx->auth_mechs, arg + 5 );
|
add_string_list_n( &ctx->auth_mechs, arg + 5, argl - 5 );
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < as(cap_list); i++)
|
for (i = 0; i < as(cap_list); i++)
|
||||||
if (!strcmp( cap_list[i], arg ))
|
if (equals( arg, argl, cap_list[i].str, cap_list[i].len ))
|
||||||
ctx->caps |= 1 << i;
|
ctx->caps |= 1 << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx->caps &= ~ctx->conf->server->cap_mask;
|
ctx->caps &= ~ctx->conf->server->cap_mask;
|
||||||
if (!CAP(NOLOGIN))
|
if (!CAP(NOLOGIN))
|
||||||
add_string_list( &ctx->auth_mechs, "LOGIN" );
|
add_string_list_n( &ctx->auth_mechs, "LOGIN", 5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
|
parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
|
||||||
{
|
{
|
||||||
char *arg, *earg, *p;
|
char *arg, *earg, *p;
|
||||||
|
uint argl;
|
||||||
|
|
||||||
if (!s || *s != '[')
|
if (!s || *s != '[')
|
||||||
return RESP_OK; /* no response code */
|
return RESP_OK; /* no response code */
|
||||||
s++;
|
s++;
|
||||||
if (!(arg = next_arg( &s ))) {
|
if (!(arg = next_arg( &s, &argl ))) {
|
||||||
error( "IMAP error: malformed response code\n" );
|
error( "IMAP error: malformed response code\n" );
|
||||||
return RESP_CANCEL;
|
return RESP_CANCEL;
|
||||||
}
|
}
|
||||||
if (!strcmp( "UIDVALIDITY", arg )) {
|
if (equals( arg, argl, "UIDVALIDITY", 11 )) {
|
||||||
if (!(arg = next_arg( &s )) ||
|
if (!(arg = next_arg( &s, &argl )) ||
|
||||||
(ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg != ']'))
|
(ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg != ']'))
|
||||||
{
|
{
|
||||||
error( "IMAP error: malformed UIDVALIDITY status\n" );
|
error( "IMAP error: malformed UIDVALIDITY status\n" );
|
||||||
return RESP_CANCEL;
|
return RESP_CANCEL;
|
||||||
}
|
}
|
||||||
} else if (!strcmp( "UIDNEXT", arg )) {
|
} else if (equals( arg, argl, "UIDNEXT", 7 )) {
|
||||||
if (!(arg = next_arg( &s )) ||
|
if (!(arg = next_arg( &s, &argl )) ||
|
||||||
(ctx->uidnext = strtoul( arg, &earg, 10 ), *earg != ']'))
|
(ctx->uidnext = strtoul( arg, &earg, 10 ), *earg != ']'))
|
||||||
{
|
{
|
||||||
error( "IMAP error: malformed UIDNEXT status\n" );
|
error( "IMAP error: malformed UIDNEXT status\n" );
|
||||||
return RESP_CANCEL;
|
return RESP_CANCEL;
|
||||||
}
|
}
|
||||||
} else if (!strcmp( "CAPABILITY", arg )) {
|
} else if (equals( arg, argl, "CAPABILITY", 10 )) {
|
||||||
if (!s || !(p = strchr( s, ']' ))) {
|
if (!s || !(p = strchr( s, ']' ))) {
|
||||||
error( "IMAP error: malformed CAPABILITY status\n" );
|
error( "IMAP error: malformed CAPABILITY status\n" );
|
||||||
return RESP_CANCEL;
|
return RESP_CANCEL;
|
||||||
|
@ -1319,7 +1331,7 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
|
||||||
parse_capability( ctx, s );
|
parse_capability( ctx, s );
|
||||||
if (strstr( p + 1, "mac.com IMAP4 service (Oracle Communications Messaging Server" ))
|
if (strstr( p + 1, "mac.com IMAP4 service (Oracle Communications Messaging Server" ))
|
||||||
ctx->capability_hack = 1;
|
ctx->capability_hack = 1;
|
||||||
} else if (!strcmp( "ALERT]", arg )) {
|
} else if (equals( arg, argl, "ALERT]", 6 )) {
|
||||||
/* RFC2060 says that these messages MUST be displayed
|
/* RFC2060 says that these messages MUST be displayed
|
||||||
* to the user
|
* to the user
|
||||||
*/
|
*/
|
||||||
|
@ -1329,7 +1341,7 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
|
||||||
}
|
}
|
||||||
for (; isspace( (uchar)*s ); s++);
|
for (; isspace( (uchar)*s ); s++);
|
||||||
error( "*** IMAP ALERT *** %s\n", s );
|
error( "*** IMAP ALERT *** %s\n", s );
|
||||||
} else if (!strcmp( "APPENDUID", arg )) {
|
} else if (equals( arg, argl, "APPENDUID", 9 )) {
|
||||||
// The checks ensure that:
|
// The checks ensure that:
|
||||||
// - cmd => this is the final tagged response of a command, at which
|
// - cmd => this is the final tagged response of a command, at which
|
||||||
// point cmd was already removed from ctx->in_progress, so param.uid
|
// point cmd was already removed from ctx->in_progress, so param.uid
|
||||||
|
@ -1341,15 +1353,15 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
|
||||||
error( "IMAP error: unexpected APPENDUID status\n" );
|
error( "IMAP error: unexpected APPENDUID status\n" );
|
||||||
return RESP_CANCEL;
|
return RESP_CANCEL;
|
||||||
}
|
}
|
||||||
if (!(arg = next_arg( &s )) ||
|
if (!(arg = next_arg( &s, &argl )) ||
|
||||||
(ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg) ||
|
(ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg) ||
|
||||||
!(arg = next_arg( &s )) ||
|
!(arg = next_arg( &s, &argl )) ||
|
||||||
(cmd->param.uid = strtoul( arg, &earg, 10 ), *earg != ']'))
|
(cmd->param.uid = strtoul( arg, &earg, 10 ), *earg != ']'))
|
||||||
{
|
{
|
||||||
error( "IMAP error: malformed APPENDUID status\n" );
|
error( "IMAP error: malformed APPENDUID status\n" );
|
||||||
return RESP_CANCEL;
|
return RESP_CANCEL;
|
||||||
}
|
}
|
||||||
} else if (!strcmp( "PERMANENTFLAGS", arg )) {
|
} else if (equals( arg, argl, "PERMANENTFLAGS", 14 )) {
|
||||||
parse_list_init( &ctx->parse_list_sts );
|
parse_list_init( &ctx->parse_list_sts );
|
||||||
if (parse_imap_list( NULL, &s, &ctx->parse_list_sts ) != LIST_OK || *s != ']') {
|
if (parse_imap_list( NULL, &s, &ctx->parse_list_sts ) != LIST_OK || *s != ']') {
|
||||||
error( "IMAP error: malformed PERMANENTFLAGS status\n" );
|
error( "IMAP error: malformed PERMANENTFLAGS status\n" );
|
||||||
|
@ -1362,7 +1374,7 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s )
|
||||||
ret = RESP_CANCEL;
|
ret = RESP_CANCEL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!strcmp( tmp->val, "\\*" ) || !strcmp( tmp->val, "$Forwarded" )) {
|
if (equals( tmp->val, tmp->len, "\\*", 2 ) || equals( tmp->val, tmp->len, "$Forwarded", 10 )) {
|
||||||
ctx->has_forwarded = 1;
|
ctx->has_forwarded = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1385,7 +1397,7 @@ parse_list_rsp( imap_store_t *ctx, list_t *list )
|
||||||
if (!is_list( list ))
|
if (!is_list( list ))
|
||||||
return parse_list_perror( ctx );
|
return parse_list_perror( ctx );
|
||||||
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 ) && equals_upper( lp->val, lp->len, "\\NOSELECT", 9 ))
|
||||||
return parse_next_list( ctx, parse_namespace_rsp_p2 ); // (sic!)
|
return parse_next_list( ctx, parse_namespace_rsp_p2 ); // (sic!)
|
||||||
return parse_next_list( ctx, parse_list_rsp_p1 );
|
return parse_next_list( ctx, parse_list_rsp_p1 );
|
||||||
}
|
}
|
||||||
|
@ -1573,7 +1585,7 @@ imap_socket_read( void *aux )
|
||||||
imap_cmd_t *cmdp, **pcmdp;
|
imap_cmd_t *cmdp, **pcmdp;
|
||||||
char *cmd, *arg, *arg1, *p;
|
char *cmd, *arg, *arg1, *p;
|
||||||
int resp, resp2, tag;
|
int resp, resp2, tag;
|
||||||
uint seq;
|
uint seq, argl, argl1;
|
||||||
conn_iovec_t iov[2];
|
conn_iovec_t iov[2];
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -1599,19 +1611,17 @@ imap_socket_read( void *aux )
|
||||||
fflush( stdout );
|
fflush( stdout );
|
||||||
}
|
}
|
||||||
|
|
||||||
arg = next_arg( &cmd );
|
if (!(arg = next_arg( &cmd, &argl ))) {
|
||||||
if (!arg) {
|
|
||||||
error( "IMAP error: empty response\n" );
|
error( "IMAP error: empty response\n" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*arg == '*') {
|
if (*arg == '*') {
|
||||||
arg = next_arg( &cmd );
|
if (!(arg = next_arg( &cmd, &argl ))) {
|
||||||
if (!arg) {
|
|
||||||
error( "IMAP error: malformed untagged response\n" );
|
error( "IMAP error: malformed untagged response\n" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) {
|
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;
|
||||||
dogreet:
|
dogreet:
|
||||||
|
@ -1619,13 +1629,13 @@ imap_socket_read( void *aux )
|
||||||
imap_open_store_greeted( ctx );
|
imap_open_store_greeted( ctx );
|
||||||
if (imap_deref( ctx ))
|
if (imap_deref( ctx ))
|
||||||
return;
|
return;
|
||||||
} else if (!strcmp( "OK", arg )) {
|
} else if (equals( arg, argl, "OK", 2 )) {
|
||||||
parse_response_code( ctx, NULL, cmd );
|
parse_response_code( ctx, NULL, cmd );
|
||||||
if (ctx->greeting == GreetingPending) {
|
if (ctx->greeting == GreetingPending) {
|
||||||
ctx->greeting = GreetingOk;
|
ctx->greeting = GreetingOk;
|
||||||
goto dogreet;
|
goto dogreet;
|
||||||
}
|
}
|
||||||
} else if (!strcmp( "BYE", arg )) {
|
} else if (equals( arg, argl, "BYE", 3 )) {
|
||||||
if (!ctx->expectBYE) {
|
if (!ctx->expectBYE) {
|
||||||
ctx->greeting = GreetingBad;
|
ctx->greeting = GreetingBad;
|
||||||
error( "IMAP error: unexpected BYE response: %s\n", cmd );
|
error( "IMAP error: unexpected BYE response: %s\n", cmd );
|
||||||
|
@ -1638,22 +1648,22 @@ imap_socket_read( void *aux )
|
||||||
} else if (ctx->greeting == GreetingPending) {
|
} else if (ctx->greeting == GreetingPending) {
|
||||||
error( "IMAP error: bogus greeting response %s\n", arg );
|
error( "IMAP error: bogus greeting response %s\n", arg );
|
||||||
break;
|
break;
|
||||||
} else if (!strcmp( "NO", arg )) {
|
} else if (equals( arg, argl, "NO", 2 )) {
|
||||||
warn( "Warning from IMAP server: %s\n", cmd );
|
warn( "Warning from IMAP server: %s\n", cmd );
|
||||||
} else if (!strcmp( "BAD", arg )) {
|
} else if (equals( arg, argl, "BAD", 3 )) {
|
||||||
error( "Error from IMAP server: %s\n", cmd );
|
error( "Error from IMAP server: %s\n", cmd );
|
||||||
} else if (!strcmp( "CAPABILITY", arg )) {
|
} else if (equals( arg, argl, "CAPABILITY", 10 )) {
|
||||||
parse_capability( ctx, cmd );
|
parse_capability( ctx, cmd );
|
||||||
} else if (!strcmp( "LIST", arg ) || !strcmp( "LSUB", arg )) {
|
} else if (equals( arg, argl, "LIST", 4 ) || equals( arg, argl, "LSUB", 4 )) {
|
||||||
resp = parse_list( ctx, cmd, parse_list_rsp, "LIST" );
|
resp = parse_list( ctx, cmd, parse_list_rsp, "LIST" );
|
||||||
goto listret;
|
goto listret;
|
||||||
} else if (!strcmp( "NAMESPACE", arg )) {
|
} else if (equals( arg, argl, "NAMESPACE", 9 )) {
|
||||||
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 ))) {
|
} else if ((arg1 = next_arg( &cmd, &argl1 ))) {
|
||||||
if (!strcmp( "EXISTS", arg1 )) {
|
if (equals( arg1, argl1, "EXISTS", 6 )) {
|
||||||
ctx->total_msgs = atoi( arg );
|
ctx->total_msgs = atoi( arg );
|
||||||
} else if (!strcmp( "EXPUNGE", arg1 )) {
|
} else if (equals( arg1, argl1, "EXPUNGE", 7 )) {
|
||||||
if (!(seq = strtoul( arg, &arg1, 10 )) || *arg1) {
|
if (!(seq = strtoul( arg, &arg1, 10 )) || *arg1) {
|
||||||
badseq:
|
badseq:
|
||||||
error( "IMAP error: malformed sequence number '%s'\n", arg );
|
error( "IMAP error: malformed sequence number '%s'\n", arg );
|
||||||
|
@ -1661,9 +1671,9 @@ imap_socket_read( void *aux )
|
||||||
}
|
}
|
||||||
record_expunge( ctx, seq );
|
record_expunge( ctx, seq );
|
||||||
ctx->total_msgs--;
|
ctx->total_msgs--;
|
||||||
} else if (!strcmp( "RECENT", arg1 )) {
|
} else if (equals( arg1, argl1, "RECENT", 6 )) {
|
||||||
ctx->recent_msgs = atoi( arg );
|
ctx->recent_msgs = atoi( arg );
|
||||||
} else if (!strcmp( "FETCH", arg1 )) {
|
} else if (equals( arg1, argl1, "FETCH", 5 )) {
|
||||||
if (!(seq = strtoul( arg, &arg1, 10 )) || *arg1)
|
if (!(seq = strtoul( arg, &arg1, 10 )) || *arg1)
|
||||||
goto badseq;
|
goto badseq;
|
||||||
ctx->fetch_seq = seq;
|
ctx->fetch_seq = seq;
|
||||||
|
@ -1722,17 +1732,16 @@ imap_socket_read( void *aux )
|
||||||
ctx->in_progress_append = pcmdp;
|
ctx->in_progress_append = pcmdp;
|
||||||
if (!--ctx->num_in_progress)
|
if (!--ctx->num_in_progress)
|
||||||
socket_expect_activity( &ctx->conn, 0 );
|
socket_expect_activity( &ctx->conn, 0 );
|
||||||
arg = next_arg( &cmd );
|
if (!(arg = next_arg( &cmd, &argl ))) {
|
||||||
if (!arg) {
|
|
||||||
error( "IMAP error: malformed tagged response\n" );
|
error( "IMAP error: malformed tagged response\n" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!strcmp( "OK", arg )) {
|
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 (!strcmp( "NO", arg )) {
|
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( 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) );
|
||||||
|
@ -1746,7 +1755,7 @@ imap_socket_read( void *aux )
|
||||||
resp = RESP_NO;
|
resp = RESP_NO;
|
||||||
if (cmdp->param.failok) // SELECT
|
if (cmdp->param.failok) // SELECT
|
||||||
goto doresp;
|
goto doresp;
|
||||||
} else /*if (!strcmp( "BAD", arg ))*/ {
|
} else /*if (equals( arg, argl, "BAD", 3 ))*/ {
|
||||||
if (cmdp->param.failok == 2 && cmd && starts_with_upper( cmd, -1, "[TOOBIG]", 8 )) { // APPEND
|
if (cmdp->param.failok == 2 && cmd && starts_with_upper( cmd, -1, "[TOOBIG]", 8 )) { // APPEND
|
||||||
resp = RESP_NO;
|
resp = RESP_NO;
|
||||||
// Fall through - we still complain
|
// Fall through - we still complain
|
||||||
|
@ -2416,7 +2425,7 @@ imap_open_store_authenticate2( imap_store_t *ctx )
|
||||||
|
|
||||||
info( "Logging in...\n" );
|
info( "Logging in...\n" );
|
||||||
for (mech = srvc->auth_mechs; mech; mech = mech->next) {
|
for (mech = srvc->auth_mechs; mech; mech = mech->next) {
|
||||||
int any = !strcmp( mech->string, "*" );
|
int any = equals( mech->string, -1, "*", 1 );
|
||||||
for (cmech = ctx->auth_mechs; cmech; cmech = cmech->next) {
|
for (cmech = ctx->auth_mechs; cmech; cmech = cmech->next) {
|
||||||
if (any || !strcasecmp( mech->string, cmech->string )) {
|
if (any || !strcasecmp( mech->string, cmech->string )) {
|
||||||
if (!strcasecmp( cmech->string, "LOGIN" )) {
|
if (!strcasecmp( cmech->string, "LOGIN" )) {
|
||||||
|
@ -3616,7 +3625,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
|
||||||
arg = cfg->val;
|
arg = cfg->val;
|
||||||
do {
|
do {
|
||||||
for (u = 0; u < as(cap_list); u++) {
|
for (u = 0; u < as(cap_list); u++) {
|
||||||
if (!strcasecmp( cap_list[u], arg )) {
|
if (equals_upper( arg, -1, cap_list[u].str, cap_list[u].len )) {
|
||||||
server->cap_mask |= 1 << u;
|
server->cap_mask |= 1 << u;
|
||||||
goto gotcap;
|
goto gotcap;
|
||||||
}
|
}
|
||||||
|
|
24
src/util.c
24
src/util.c
|
@ -292,6 +292,15 @@ starts_with( const char *str, int strl, const char *cmp, uint cmpl )
|
||||||
return ((uint)strl >= cmpl) && !memcmp( str, cmp, cmpl );
|
return ((uint)strl >= cmpl) && !memcmp( str, cmp, cmpl );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
equals_upper_impl( const char *str, const char *cmp, uint cmpl )
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < cmpl; i++)
|
||||||
|
if (toupper( str[i] ) != cmp[i])
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl )
|
starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl )
|
||||||
{
|
{
|
||||||
|
@ -299,10 +308,7 @@ starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl )
|
||||||
strl = strnlen( str, cmpl + 1 );
|
strl = strnlen( str, cmpl + 1 );
|
||||||
if ((uint)strl < cmpl)
|
if ((uint)strl < cmpl)
|
||||||
return 0;
|
return 0;
|
||||||
for (uint i = 0; i < cmpl; i++)
|
return equals_upper_impl( str, cmp, cmpl );
|
||||||
if (toupper( str[i] ) != cmp[i])
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -313,6 +319,16 @@ equals( const char *str, int strl, const char *cmp, uint cmpl )
|
||||||
return ((uint)strl == cmpl) && !memcmp( str, cmp, cmpl );
|
return ((uint)strl == cmpl) && !memcmp( str, cmp, cmpl );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
equals_upper( const char *str, int strl, const char *cmp, uint cmpl )
|
||||||
|
{
|
||||||
|
if (strl < 0)
|
||||||
|
strl = strnlen( str, cmpl + 1 );
|
||||||
|
if ((uint)strl != cmpl)
|
||||||
|
return 0;
|
||||||
|
return equals_upper_impl( str, cmp, cmpl );
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAVE_TIMEGM
|
#ifndef HAVE_TIMEGM
|
||||||
/*
|
/*
|
||||||
Converts struct tm to time_t, assuming the data in tm is UTC rather
|
Converts struct tm to time_t, assuming the data in tm is UTC rather
|
||||||
|
|
Loading…
Reference in New Issue
Block a user