introduce ability to flatten the hierarchy of Stores
This commit is contained in:
		
							parent
							
								
									2585dd3324
								
							
						
					
					
						commit
						dfd7516b9a
					
				
					 5 changed files with 55 additions and 5 deletions
				
			
		
							
								
								
									
										13
									
								
								src/config.c
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								src/config.c
									
										
									
									
									
								
							|  | @ -430,7 +430,18 @@ parse_generic_store( store_conf_t *store, conffile_t *cfg, int *err ) | |||
| 		store->max_size = parse_size( cfg ); | ||||
| 	else if (!strcasecmp( "MapInbox", cfg->cmd )) | ||||
| 		store->map_inbox = nfstrdup( cfg->val ); | ||||
| 	else { | ||||
| 	else if (!strcasecmp( "Flatten", cfg->cmd )) { | ||||
| 		int sl = strlen( cfg->val ); | ||||
| 		if (sl != 1) { | ||||
| 			error( "%s:%d: malformed flattened hierarchy delimiter\n", cfg->file, cfg->line ); | ||||
| 			*err = 1; | ||||
| 		} else if (cfg->val[0] == '/') { | ||||
| 			error( "%s:%d: flattened hierarchy delimiter cannot be the canonical delimiter '/'\n", cfg->file, cfg->line ); | ||||
| 			*err = 1; | ||||
| 		} else { | ||||
| 			store->flat_delim = cfg->val[0]; | ||||
| 		} | ||||
| 	} else { | ||||
| 		error( "%s:%d: unknown keyword '%s'\n", cfg->file, cfg->line, cfg->cmd ); | ||||
| 		*err = 1; | ||||
| 	} | ||||
|  |  | |||
|  | @ -142,6 +142,7 @@ typedef struct store_conf { | |||
| 	const char *trash; | ||||
| 	unsigned max_size; /* off_t is overkill */ | ||||
| 	unsigned trash_remote_new:1, trash_only_new:1; | ||||
| 	char flat_delim; | ||||
| } store_conf_t; | ||||
| 
 | ||||
| typedef struct string_list { | ||||
|  | @ -216,7 +217,8 @@ typedef struct store { | |||
| 	void *bad_callback_aux; | ||||
| 
 | ||||
| 	/* currently open mailbox */ | ||||
| 	const char *name; /* foreign! maybe preset? */ | ||||
| 	const char *orig_name; /* foreign! maybe preset? */ | ||||
| 	char *name; /* foreign! maybe preset? */ | ||||
| 	char *path; /* own */ | ||||
| 	message_t *msgs; /* own */ | ||||
| 	int uidvalidity; | ||||
|  |  | |||
|  | @ -718,12 +718,21 @@ static void | |||
| store_listed( int sts, void *aux ) | ||||
| { | ||||
| 	MVARS(aux) | ||||
| 	string_list_t *box; | ||||
| 
 | ||||
| 	switch (sts) { | ||||
| 	case DRV_CANCELED: | ||||
| 		return; | ||||
| 	case DRV_OK: | ||||
| 		mvars->ctx[t]->listed = 1; | ||||
| 		if (mvars->ctx[t]->conf->flat_delim) { | ||||
| 			for (box = mvars->ctx[t]->boxes; box; box = box->next) { | ||||
| 				if (map_name( box->string, mvars->ctx[t]->conf->flat_delim, '/' ) < 0) { | ||||
| 					error( "Error: flattened mailbox name '%s' contains canonical hierarchy delimiter\n", box->string ); | ||||
| 					mvars->ret = mvars->skip = 1; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if (mvars->ctx[t]->conf->map_inbox) | ||||
| 			add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox ); | ||||
| 		break; | ||||
|  |  | |||
							
								
								
									
										12
									
								
								src/mbsync.1
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								src/mbsync.1
									
										
									
									
									
								
							|  | @ -150,6 +150,15 @@ Channels section. | |||
| This virtual mailbox does not support subfolders. | ||||
| .. | ||||
| .TP | ||||
| \fBFlatten\fR \fIdelim\fR | ||||
| Flatten the hierarchy within this Store by substituting the canonical | ||||
| hierarchy delimiter \fB/\fR with \fIdelim\fR. | ||||
| This can be useful when the MUA used to access the Store provides | ||||
| suboptimal handling of hierarchical mailboxes, as is the case with | ||||
| \fBMutt\fR. | ||||
| A common choice for the delimiter is \fB.\fR. | ||||
| .. | ||||
| .TP | ||||
| \fBTrash\fR \fImailbox\fR | ||||
| Specifies a mailbox (relative to \fBPath\fR) to copy deleted messages to | ||||
| prior to expunging. See \fBINHERENT PROBLEMS\fR below. | ||||
|  | @ -318,6 +327,9 @@ This option is meaningless if a \fBPath\fR was specified. | |||
| \fBPathDelimiter\fR \fIdelim\fR | ||||
| Specify the server's hierarchy delimiter character. | ||||
| (Default: taken from the server's first "personal" NAMESPACE) | ||||
| .br | ||||
| Do \fBNOT\fR abuse this to re-interpret the hierarchy. | ||||
| Use \fBFlatten\fR instead. | ||||
| .. | ||||
| .SS Channels | ||||
| .TP | ||||
|  |  | |||
							
								
								
									
										22
									
								
								src/sync.c
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								src/sync.c
									
										
									
									
									
								
							|  | @ -467,6 +467,7 @@ stats( sync_vars_t *svars ) | |||
| static void sync_bail( sync_vars_t *svars ); | ||||
| static void sync_bail1( sync_vars_t *svars ); | ||||
| static void sync_bail2( sync_vars_t *svars ); | ||||
| static void sync_bail3( sync_vars_t *svars ); | ||||
| static void cancel_done( void *aux ); | ||||
| 
 | ||||
| static void | ||||
|  | @ -605,9 +606,16 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan, | |||
| 	svars->srecadd = &svars->srecs; | ||||
| 
 | ||||
| 	for (t = 0; t < 2; t++) { | ||||
| 		ctx[t]->name = | ||||
| 		ctx[t]->orig_name = | ||||
| 			(!names[t] || (ctx[t]->conf->map_inbox && !strcmp( ctx[t]->conf->map_inbox, names[t] ))) ? | ||||
| 				"INBOX" : names[t]; | ||||
| 		ctx[t]->name = nfstrdup( ctx[t]->orig_name ); | ||||
| 		if (ctx[t]->conf->flat_delim && map_name( ctx[t]->name, '/', ctx[t]->conf->flat_delim ) < 0) { | ||||
| 			error( "Error: canonical mailbox name '%s' contains flattened hierarchy delimiter\n", ctx[t]->name ); | ||||
| 			svars->ret = SYNC_FAIL; | ||||
| 			sync_bail3( svars ); | ||||
| 			return; | ||||
| 		} | ||||
| 		ctx[t]->uidvalidity = -1; | ||||
| 		set_bad_callback( ctx[t], store_bad, AUX ); | ||||
| 		svars->drv[t] = ctx[t]->conf->driver; | ||||
|  | @ -615,7 +623,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan, | |||
| 	/* Both boxes must be fully set up at this point, so that error exit paths
 | ||||
| 	 * don't run into uninitialized variables. */ | ||||
| 	for (t = 0; t < 2; t++) { | ||||
| 		info( "Selecting %s %s...\n", str_ms[t], ctx[t]->name ); | ||||
| 		info( "Selecting %s %s...\n", str_ms[t], ctx[t]->orig_name ); | ||||
| 		DRIVER_CALL(select( ctx[t], (chan->ops[t] & OP_CREATE) != 0, box_selected, AUX )); | ||||
| 	} | ||||
| } | ||||
|  | @ -696,7 +704,7 @@ box_selected( int sts, void *aux ) | |||
| 	} | ||||
| 	if (fcntl( svars->lfd, F_SETLK, &lck )) { | ||||
| 		error( "Error: channel :%s:%s-:%s:%s is locked\n", | ||||
| 		         chan->stores[M]->name, ctx[M]->name, chan->stores[S]->name, ctx[S]->name ); | ||||
| 		         chan->stores[M]->name, ctx[M]->orig_name, chan->stores[S]->name, ctx[S]->orig_name ); | ||||
| 		svars->ret = SYNC_FAIL; | ||||
| 		sync_bail1( svars ); | ||||
| 		return; | ||||
|  | @ -1721,6 +1729,14 @@ sync_bail2( sync_vars_t *svars ) | |||
| 	free( svars->jname ); | ||||
| 	free( svars->dname ); | ||||
| 	flushn(); | ||||
| 	sync_bail3( svars ); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| sync_bail3( sync_vars_t *svars ) | ||||
| { | ||||
| 	free( svars->ctx[M]->name ); | ||||
| 	free( svars->ctx[S]->name ); | ||||
| 	sync_deref( svars ); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue