@ -75,6 +75,7 @@ typedef struct {
list_t * head , * * stack [ MAX_LIST_DEPTH ] ;
list_t * head , * * stack [ MAX_LIST_DEPTH ] ;
int ( * callback ) ( imap_store_t * ctx , list_t * list ) ;
int ( * callback ) ( imap_store_t * ctx , list_t * list ) ;
int level , need_bytes ;
int level , need_bytes ;
const char * err ;
} parse_list_state_t ;
} parse_list_state_t ;
typedef struct imap_cmd imap_cmd_t ;
typedef struct imap_cmd imap_cmd_t ;
@ -109,6 +110,7 @@ union imap_store {
uint caps ; // CAPABILITY results
uint caps ; // CAPABILITY results
string_list_t * auth_mechs ;
string_list_t * auth_mechs ;
parse_list_state_t parse_list_sts ;
parse_list_state_t parse_list_sts ;
const char * parse_list_what ;
char * parse_list_cmd ;
char * parse_list_cmd ;
// Command queue
// Command queue
imap_cmd_t * pending , * * pending_append ;
imap_cmd_t * pending , * * pending_append ;
@ -819,8 +821,10 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
goto getbytes ;
goto getbytes ;
}
}
if ( ! s )
if ( ! s ) {
sts - > err = " missing value " ;
return LIST_BAD ;
return LIST_BAD ;
}
for ( ; ; ) {
for ( ; ; ) {
while ( isspace ( ( uchar ) * s ) )
while ( isspace ( ( uchar ) * s ) )
s + + ;
s + + ;
@ -836,7 +840,7 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
if ( * s = = ' ( ' ) {
if ( * s = = ' ( ' ) {
/* sublist */
/* sublist */
if ( sts - > level = = MAX_LIST_DEPTH )
if ( sts - > level = = MAX_LIST_DEPTH )
goto bail ;
goto toodeep ;
s + + ;
s + + ;
cur - > val = LIST ;
cur - > val = LIST ;
sts - > stack [ sts - > level + + ] = curp ;
sts - > stack [ sts - > level + + ] = curp ;
@ -846,11 +850,12 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
} else if ( ctx & & * s = = ' { ' ) {
} else if ( ctx & & * s = = ' { ' ) {
/* literal */
/* literal */
bytes = ( int ) ( cur - > len = strtoul ( s + 1 , & s , 10 ) ) ;
bytes = ( int ) ( cur - > len = strtoul ( s + 1 , & s , 10 ) ) ;
if ( * s ! = ' } ' | | * + + s )
if ( * s ! = ' } ' | | * + + s ) {
sts - > err = " malformed literal " ;
goto bail ;
goto bail ;
}
if ( ( uint ) bytes > = INT_MAX ) {
if ( ( uint ) bytes > = INT_MAX ) {
error ( " IMAP error: excessively large literal from %s "
sts - > err = " excessively large literal - THIS MIGHT BE AN ATTEMPT TO HACK YOU! " ;
" - THIS MIGHT BE AN ATTEMPT TO HACK YOU! \n " , ctx - > conn . name ) ;
goto bail ;
goto bail ;
}
}
@ -861,7 +866,7 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
n = socket_read ( & ctx - > conn , s , ( uint ) bytes ) ;
n = socket_read ( & ctx - > conn , s , ( uint ) bytes ) ;
if ( n < 0 ) {
if ( n < 0 ) {
badeof :
badeof :
error ( " IMAP error: unexpected EOF from %s \n " , ctx - > conn . name ) ;
sts - > err = " unexpected EOF " ;
goto bail ;
goto bail ;
}
}
bytes - = n ;
bytes - = n ;
@ -891,8 +896,10 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
while ( ( c = * s + + ) ! = ' " ' ) {
while ( ( c = * s + + ) ! = ' " ' ) {
if ( c = = ' \\ ' )
if ( c = = ' \\ ' )
c = * s + + ;
c = * s + + ;
if ( ! c )
if ( ! c ) {
sts - > err = " unterminated quoted string " ;
goto bail ;
goto bail ;
}
* d + + = c ;
* d + + = c ;
}
}
cur - > len = ( uint ) ( d - p ) ;
cur - > len = ( uint ) ( d - p ) ;
@ -914,9 +921,11 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
if ( ! sts - > level )
if ( ! sts - > level )
break ;
break ;
next2 :
next2 :
if ( ! * s )
if ( ! * s ) {
sts - > err = " unterminated list " ;
goto bail ;
goto bail ;
}
}
}
* sp = s ;
* sp = s ;
return LIST_OK ;
return LIST_OK ;
@ -926,6 +935,8 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
sts - > need_bytes = bytes ;
sts - > need_bytes = bytes ;
return LIST_PARTIAL ;
return LIST_PARTIAL ;
}
}
toodeep :
sts - > err = " too deeply nested lists " ;
bail :
bail :
free_list ( sts - > head ) ;
free_list ( sts - > head ) ;
sts - > level = 0 ;
sts - > level = 0 ;
@ -937,6 +948,7 @@ parse_list_init( parse_list_state_t *sts )
{
{
sts - > need_bytes = - 1 ;
sts - > need_bytes = - 1 ;
sts - > level = 1 ;
sts - > level = 1 ;
sts - > err = NULL ;
sts - > head = NULL ;
sts - > head = NULL ;
sts - > stack [ 0 ] = & sts - > head ;
sts - > stack [ 0 ] = & sts - > head ;
}
}
@ -964,12 +976,23 @@ parse_next_list( imap_store_t *ctx, int (*cb)( imap_store_t *ctx, list_t *list )
}
}
static int
static int
parse_list ( imap_store_t * ctx , char * s , int ( * cb ) ( imap_store_t * ctx , list_t * list ) )
parse_list ( imap_store_t * ctx , char * s , int ( * cb ) ( imap_store_t * ctx , list_t * list ) , const char * what )
{
{
ctx - > parse_list_cmd = s ;
ctx - > parse_list_cmd = s ;
ctx - > parse_list_what = what ;
return parse_next_list ( ctx , cb ) ;
return parse_next_list ( ctx , cb ) ;
}
}
static int
parse_list_perror ( imap_store_t * ctx )
{
if ( ! ctx - > parse_list_sts . err )
ctx - > parse_list_sts . err = " unexpected value " ;
error ( " IMAP error: malformed %s response from %s: %s \n " ,
ctx - > parse_list_what , ctx - > conn . name , ctx - > parse_list_sts . err ) ;
return LIST_BAD ;
}
static int parse_namespace_rsp_p2 ( imap_store_t * , list_t * ) ;
static int parse_namespace_rsp_p2 ( imap_store_t * , list_t * ) ;
static int parse_namespace_rsp_p3 ( imap_store_t * , list_t * ) ;
static int parse_namespace_rsp_p3 ( imap_store_t * , list_t * ) ;
@ -981,8 +1004,7 @@ parse_namespace_rsp( imap_store_t *ctx, list_t *list )
if ( ! list ) {
if ( ! list ) {
bad :
bad :
error ( " IMAP error: malformed NAMESPACE response \n " ) ;
return parse_list_perror ( ctx ) ;
return LIST_BAD ;
}
}
if ( list - > val ! = NIL ) {
if ( list - > val ! = NIL ) {
if ( list - > val ! = LIST )
if ( list - > val ! = LIST )
@ -1121,10 +1143,8 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list )
uint uid = 0 , size = 0 , msgid_len = 0 ;
uint uid = 0 , size = 0 , msgid_len = 0 ;
time_t date = 0 ;
time_t date = 0 ;
if ( ! is_list ( list ) ) {
if ( ! is_list ( list ) )
error ( " IMAP error: bogus FETCH response \n " ) ;
return parse_list_perror ( ctx ) ;
return LIST_BAD ;
}
for ( tmp = list - > child ; tmp ; tmp = tmp - > next ) {
for ( tmp = list - > child ; tmp ; tmp = tmp - > next ) {
if ( ! is_atom ( tmp ) ) {
if ( ! is_atom ( tmp ) ) {
@ -1354,10 +1374,8 @@ parse_list_rsp( imap_store_t *ctx, list_t *list )
{
{
list_t * lp ;
list_t * lp ;
if ( ! is_list ( list ) ) {
if ( ! is_list ( list ) )
error ( " IMAP error: malformed LIST response \n " ) ;
return parse_list_perror ( ctx ) ;
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 " ) )
return LIST_OK ;
return LIST_OK ;
@ -1367,10 +1385,8 @@ parse_list_rsp( imap_store_t *ctx, list_t *list )
static int
static int
parse_list_rsp_p1 ( imap_store_t * ctx , list_t * list )
parse_list_rsp_p1 ( imap_store_t * ctx , list_t * list )
{
{
if ( ! is_opt_atom ( list ) ) {
if ( ! is_opt_atom ( list ) )
error ( " IMAP error: malformed LIST response \n " ) ;
return parse_list_perror ( ctx ) ;
return LIST_BAD ;
}
if ( ! ctx - > delimiter [ 0 ] & & is_atom ( list ) )
if ( ! ctx - > delimiter [ 0 ] & & is_atom ( list ) )
ctx - > delimiter [ 0 ] = list - > val [ 0 ] ;
ctx - > delimiter [ 0 ] = list - > val [ 0 ] ;
return parse_next_list ( ctx , parse_list_rsp_p2 ) ;
return parse_next_list ( ctx , parse_list_rsp_p2 ) ;
@ -1413,10 +1429,8 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list )
int argl ;
int argl ;
uint l ;
uint l ;
if ( ! is_atom ( list ) ) {
if ( ! is_atom ( list ) )
error ( " IMAP error: malformed LIST response \n " ) ;
return parse_list_perror ( ctx ) ;
return LIST_BAD ;
}
arg = list - > val ;
arg = list - > val ;
argl = ( int ) list - > len ;
argl = ( int ) list - > len ;
if ( argl > 1000 ) {
if ( argl > 1000 ) {
@ -1623,10 +1637,10 @@ imap_socket_read( void *aux )
} else if ( ! strcmp ( " CAPABILITY " , arg ) ) {
} else if ( ! strcmp ( " CAPABILITY " , arg ) ) {
parse_capability ( ctx , cmd ) ;
parse_capability ( ctx , cmd ) ;
} else if ( ! strcmp ( " LIST " , arg ) | | ! strcmp ( " LSUB " , arg ) ) {
} else if ( ! strcmp ( " LIST " , arg ) | | ! strcmp ( " LSUB " , arg ) ) {
resp = parse_list ( ctx , cmd , parse_list_rsp ) ;
resp = parse_list ( ctx , cmd , parse_list_rsp , " LIST " ) ;
goto listret ;
goto listret ;
} else if ( ! strcmp ( " NAMESPACE " , arg ) ) {
} else if ( ! strcmp ( " NAMESPACE " , arg ) ) {
resp = parse_list ( ctx , cmd , parse_namespace_rsp ) ;
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 ) ) ) {
if ( ! strcmp ( " EXISTS " , arg1 ) ) {
if ( ! strcmp ( " EXISTS " , arg1 ) ) {
@ -1645,7 +1659,7 @@ imap_socket_read( void *aux )
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 ;
resp = parse_list ( ctx , cmd , parse_fetch_rsp ) ;
resp = parse_list ( ctx , cmd , parse_fetch_rsp , " FETCH " ) ;
goto listret ;
goto listret ;
}
}
} else {
} else {