deal sensibly with permanent errors
don't retry dead Stores for every Channel. this also introduces a state for transient errors (specifically, connect failures), but this is currently unused.
This commit is contained in:
		
							parent
							
								
									5f265ad7da
								
							
						
					
					
						commit
						74c78c70b9
					
				
					 4 changed files with 42 additions and 18 deletions
				
			
		| 
						 | 
					@ -27,6 +27,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct driver driver_t;
 | 
					typedef struct driver driver_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FAIL_TEMP   0  /* Retry immediately (also: no error) */
 | 
				
			||||||
 | 
					#define FAIL_WAIT   1  /* Retry after some time (if at all) */
 | 
				
			||||||
 | 
					#define FAIL_FINAL  2  /* Don't retry until store reconfiguration */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct store_conf {
 | 
					typedef struct store_conf {
 | 
				
			||||||
	struct store_conf *next;
 | 
						struct store_conf *next;
 | 
				
			||||||
	char *name;
 | 
						char *name;
 | 
				
			||||||
| 
						 | 
					@ -37,6 +41,7 @@ typedef struct store_conf {
 | 
				
			||||||
	const char *trash;
 | 
						const char *trash;
 | 
				
			||||||
	uint max_size; /* off_t is overkill */
 | 
						uint max_size; /* off_t is overkill */
 | 
				
			||||||
	char trash_remote_new, trash_only_new;
 | 
						char trash_remote_new, trash_only_new;
 | 
				
			||||||
 | 
						char failed;
 | 
				
			||||||
} store_conf_t;
 | 
					} store_conf_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* For message->flags */
 | 
					/* For message->flags */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1508,7 +1508,13 @@ static void imap_open_store_finalize( imap_store_t * );
 | 
				
			||||||
#ifdef HAVE_LIBSSL
 | 
					#ifdef HAVE_LIBSSL
 | 
				
			||||||
static void imap_open_store_ssl_bail( imap_store_t * );
 | 
					static void imap_open_store_ssl_bail( imap_store_t * );
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
static void imap_open_store_bail( imap_store_t * );
 | 
					static void imap_open_store_bail( imap_store_t *, int );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					imap_open_store_bad( void *aux )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						imap_open_store_bail( (imap_store_t *)aux, FAIL_TEMP );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
imap_open_store( store_conf_t *conf, const char *label,
 | 
					imap_open_store( store_conf_t *conf, const char *label,
 | 
				
			||||||
| 
						 | 
					@ -1540,7 +1546,7 @@ imap_open_store( store_conf_t *conf, const char *label,
 | 
				
			||||||
			ctx->delimiter = 0;
 | 
								ctx->delimiter = 0;
 | 
				
			||||||
			ctx->callbacks.imap_open = cb;
 | 
								ctx->callbacks.imap_open = cb;
 | 
				
			||||||
			ctx->callback_aux = aux;
 | 
								ctx->callback_aux = aux;
 | 
				
			||||||
			set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx );
 | 
								set_bad_callback( &ctx->gen, imap_open_store_bad, ctx );
 | 
				
			||||||
			imap_open_store_namespace( ctx );
 | 
								imap_open_store_namespace( ctx );
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1551,7 +1557,7 @@ imap_open_store( store_conf_t *conf, const char *label,
 | 
				
			||||||
	ctx->ref_count = 1;
 | 
						ctx->ref_count = 1;
 | 
				
			||||||
	ctx->callbacks.imap_open = cb;
 | 
						ctx->callbacks.imap_open = cb;
 | 
				
			||||||
	ctx->callback_aux = aux;
 | 
						ctx->callback_aux = aux;
 | 
				
			||||||
	set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx );
 | 
						set_bad_callback( &ctx->gen, imap_open_store_bad, ctx );
 | 
				
			||||||
	ctx->in_progress_append = &ctx->in_progress;
 | 
						ctx->in_progress_append = &ctx->in_progress;
 | 
				
			||||||
	ctx->pending_append = &ctx->pending;
 | 
						ctx->pending_append = &ctx->pending;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1571,7 +1577,7 @@ imap_open_store_connected( int ok, void *aux )
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ok)
 | 
						if (!ok)
 | 
				
			||||||
		imap_open_store_bail( ctx );
 | 
							imap_open_store_bail( ctx, FAIL_WAIT );
 | 
				
			||||||
#ifdef HAVE_LIBSSL
 | 
					#ifdef HAVE_LIBSSL
 | 
				
			||||||
	else if (srvc->ssl_type == SSL_IMAPS)
 | 
						else if (srvc->ssl_type == SSL_IMAPS)
 | 
				
			||||||
		socket_start_tls( &ctx->conn, imap_open_store_tlsstarted1 );
 | 
							socket_start_tls( &ctx->conn, imap_open_store_tlsstarted1 );
 | 
				
			||||||
| 
						 | 
					@ -1602,7 +1608,7 @@ static void
 | 
				
			||||||
imap_open_store_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
					imap_open_store_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (response == RESP_NO)
 | 
						if (response == RESP_NO)
 | 
				
			||||||
		imap_open_store_bail( ctx );
 | 
							imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
	else if (response == RESP_OK)
 | 
						else if (response == RESP_OK)
 | 
				
			||||||
		imap_open_store_authenticate( ctx );
 | 
							imap_open_store_authenticate( ctx );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1623,7 +1629,7 @@ imap_open_store_authenticate( imap_store_t *ctx )
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				error( "IMAP error: SSL support not available\n" );
 | 
									error( "IMAP error: SSL support not available\n" );
 | 
				
			||||||
				imap_open_store_bail( ctx );
 | 
									imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1633,7 +1639,7 @@ imap_open_store_authenticate( imap_store_t *ctx )
 | 
				
			||||||
#ifdef HAVE_LIBSSL
 | 
					#ifdef HAVE_LIBSSL
 | 
				
			||||||
		if (srvc->ssl_type == SSL_STARTTLS) {
 | 
							if (srvc->ssl_type == SSL_STARTTLS) {
 | 
				
			||||||
			error( "IMAP error: SSL support not available\n" );
 | 
								error( "IMAP error: SSL support not available\n" );
 | 
				
			||||||
			imap_open_store_bail( ctx );
 | 
								imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -1646,7 +1652,7 @@ static void
 | 
				
			||||||
imap_open_store_authenticate_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
					imap_open_store_authenticate_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (response == RESP_NO)
 | 
						if (response == RESP_NO)
 | 
				
			||||||
		imap_open_store_bail( ctx );
 | 
							imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
	else if (response == RESP_OK)
 | 
						else if (response == RESP_OK)
 | 
				
			||||||
		socket_start_tls( &ctx->conn, imap_open_store_tlsstarted2 );
 | 
							socket_start_tls( &ctx->conn, imap_open_store_tlsstarted2 );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1666,7 +1672,7 @@ static void
 | 
				
			||||||
imap_open_store_authenticate_p3( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
					imap_open_store_authenticate_p3( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (response == RESP_NO)
 | 
						if (response == RESP_NO)
 | 
				
			||||||
		imap_open_store_bail( ctx );
 | 
							imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
	else if (response == RESP_OK)
 | 
						else if (response == RESP_OK)
 | 
				
			||||||
		imap_open_store_authenticate2( ctx );
 | 
							imap_open_store_authenticate2( ctx );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1872,7 +1878,7 @@ do_sasl_auth( imap_store_t *ctx, struct imap_cmd *cmdp ATTR_UNUSED, const char *
 | 
				
			||||||
	return socket_write( &ctx->conn, iov, iovcnt );
 | 
						return socket_write( &ctx->conn, iov, iovcnt );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bail:
 | 
					  bail:
 | 
				
			||||||
	imap_open_store_bail( ctx );
 | 
						imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1996,14 +2002,14 @@ imap_open_store_authenticate2( imap_store_t *ctx )
 | 
				
			||||||
	error( "IMAP error: server supports no acceptable authentication mechanism\n" );
 | 
						error( "IMAP error: server supports no acceptable authentication mechanism\n" );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bail:
 | 
					  bail:
 | 
				
			||||||
	imap_open_store_bail( ctx );
 | 
						imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
imap_open_store_authenticate2_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
					imap_open_store_authenticate2_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (response == RESP_NO)
 | 
						if (response == RESP_NO)
 | 
				
			||||||
		imap_open_store_bail( ctx );
 | 
							imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
	else if (response == RESP_OK)
 | 
						else if (response == RESP_OK)
 | 
				
			||||||
		imap_open_store_namespace( ctx );
 | 
							imap_open_store_namespace( ctx );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2030,7 +2036,7 @@ static void
 | 
				
			||||||
imap_open_store_namespace_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
					imap_open_store_namespace_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (response == RESP_NO) {
 | 
						if (response == RESP_NO) {
 | 
				
			||||||
		imap_open_store_bail( ctx );
 | 
							imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
	} else if (response == RESP_OK) {
 | 
						} else if (response == RESP_OK) {
 | 
				
			||||||
		ctx->got_namespace = 1;
 | 
							ctx->got_namespace = 1;
 | 
				
			||||||
		imap_open_store_namespace2( ctx );
 | 
							imap_open_store_namespace2( ctx );
 | 
				
			||||||
| 
						 | 
					@ -2061,7 +2067,7 @@ imap_open_store_namespace2( imap_store_t *ctx )
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		imap_open_store_finalize( ctx );
 | 
							imap_open_store_finalize( ctx );
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		imap_open_store_bail( ctx );
 | 
							imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2095,15 +2101,16 @@ imap_open_store_ssl_bail( imap_store_t *ctx )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* This avoids that we try to send LOGOUT to an unusable socket. */
 | 
						/* This avoids that we try to send LOGOUT to an unusable socket. */
 | 
				
			||||||
	socket_close( &ctx->conn );
 | 
						socket_close( &ctx->conn );
 | 
				
			||||||
	imap_open_store_bail( ctx );
 | 
						imap_open_store_bail( ctx, FAIL_FINAL );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
imap_open_store_bail( imap_store_t *ctx )
 | 
					imap_open_store_bail( imap_store_t *ctx, int failed )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void (*cb)( store_t *srv, void *aux ) = ctx->callbacks.imap_open;
 | 
						void (*cb)( store_t *srv, void *aux ) = ctx->callbacks.imap_open;
 | 
				
			||||||
	void *aux = ctx->callback_aux;
 | 
						void *aux = ctx->callback_aux;
 | 
				
			||||||
 | 
						ctx->gen.conf->failed = failed;
 | 
				
			||||||
	imap_cancel_store( &ctx->gen );
 | 
						imap_cancel_store( &ctx->gen );
 | 
				
			||||||
	cb( 0, aux );
 | 
						cb( 0, aux );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,16 +126,18 @@ maildir_join_path( const char *prefix, const char *box )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
maildir_validate_path( const store_conf_t *conf )
 | 
					maildir_validate_path( store_conf_t *conf )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct stat st;
 | 
						struct stat st;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!conf->path) {
 | 
						if (!conf->path) {
 | 
				
			||||||
		error( "Maildir error: store '%s' has no Path\n", conf->name );
 | 
							error( "Maildir error: store '%s' has no Path\n", conf->name );
 | 
				
			||||||
 | 
							conf->failed = FAIL_FINAL;
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) {
 | 
						if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) {
 | 
				
			||||||
		error( "Maildir error: cannot open store '%s'\n", conf->path );
 | 
							error( "Maildir error: cannot open store '%s'\n", conf->path );
 | 
				
			||||||
 | 
							conf->failed = FAIL_FINAL;
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -414,6 +416,7 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx )
 | 
				
			||||||
			return DRV_BOX_BAD;
 | 
								return DRV_BOX_BAD;
 | 
				
			||||||
		if (make_box_dir( buf, bl )) {
 | 
							if (make_box_dir( buf, bl )) {
 | 
				
			||||||
			sys_error( "Maildir error: cannot create mailbox '%s'", box );
 | 
								sys_error( "Maildir error: cannot create mailbox '%s'", box );
 | 
				
			||||||
 | 
								ctx->gen.conf->failed = FAIL_FINAL;
 | 
				
			||||||
			maildir_invoke_bad_callback( &ctx->gen );
 | 
								maildir_invoke_bad_callback( &ctx->gen );
 | 
				
			||||||
			return DRV_CANCELED;
 | 
								return DRV_CANCELED;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/main.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								src/main.c
									
										
									
									
									
								
							| 
						 | 
					@ -601,9 +601,17 @@ sync_chans( main_vars_t *mvars, int ent )
 | 
				
			||||||
		merge_actions( mvars->chan, mvars->ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 );
 | 
							merge_actions( mvars->chan, mvars->ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 );
 | 
				
			||||||
		merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
 | 
							merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mvars->state[M] = mvars->state[S] = ST_FRESH;
 | 
					 | 
				
			||||||
		info( "Channel %s\n", mvars->chan->name );
 | 
							info( "Channel %s\n", mvars->chan->name );
 | 
				
			||||||
		mvars->skip = mvars->cben = 0;
 | 
							mvars->skip = mvars->cben = 0;
 | 
				
			||||||
 | 
							for (t = 0; t < 2; t++) {
 | 
				
			||||||
 | 
								if (mvars->chan->stores[t]->failed != FAIL_TEMP) {
 | 
				
			||||||
 | 
									info( "Skipping due to failed %s store %s.\n", str_ms[t], mvars->chan->stores[t]->name );
 | 
				
			||||||
 | 
									mvars->skip = 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mvars->skip)
 | 
				
			||||||
 | 
								goto next2;
 | 
				
			||||||
 | 
							mvars->state[M] = mvars->state[S] = ST_FRESH;
 | 
				
			||||||
		if (mvars->chan->stores[M]->driver->flags & mvars->chan->stores[S]->driver->flags & DRV_VERBOSE)
 | 
							if (mvars->chan->stores[M]->driver->flags & mvars->chan->stores[S]->driver->flags & DRV_VERBOSE)
 | 
				
			||||||
			labels[M] = "M: ", labels[S] = "S: ";
 | 
								labels[M] = "M: ", labels[S] = "S: ";
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
| 
						 | 
					@ -694,6 +702,7 @@ sync_chans( main_vars_t *mvars, int ent )
 | 
				
			||||||
		free_string_list( mvars->cboxes );
 | 
							free_string_list( mvars->cboxes );
 | 
				
			||||||
		free_string_list( mvars->boxes[M] );
 | 
							free_string_list( mvars->boxes[M] );
 | 
				
			||||||
		free_string_list( mvars->boxes[S] );
 | 
							free_string_list( mvars->boxes[S] );
 | 
				
			||||||
 | 
						  next2:
 | 
				
			||||||
		if (mvars->all) {
 | 
							if (mvars->all) {
 | 
				
			||||||
			if (!(mvars->chan = mvars->chan->next))
 | 
								if (!(mvars->chan = mvars->chan->next))
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue