diff --git a/NEWS b/NEWS index 6e094e6..5513385 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +[1.5.0] + +Changed default config & state locations to follow the XDG basedir spec. +The old locations remain supported. + [1.4.0] The 'isync' compatibility wrapper was removed. diff --git a/src/config.c b/src/config.c index 4cb8361..65e080f 100644 --- a/src/config.c +++ b/src/config.c @@ -11,6 +11,8 @@ #include #include +#include +#include #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__) char FieldDelimiter = ';'; @@ -348,12 +350,26 @@ load_config( const char *where ) char *arg, *p; uint len, max_size; int cops, gcops, glob_ok, fn, i; - char path[_POSIX_PATH_MAX]; + char path[_POSIX_PATH_MAX], path2[_POSIX_PATH_MAX]; char buf[1024]; if (!where) { - nfsnprintf( path, sizeof(path), "%s/." EXE "rc", Home ); - cfile.file = path; + const char *config_home = getenv( "XDG_CONFIG_HOME" ); + if (config_home) + nfsnprintf( path, sizeof(path), "%s/isyncrc", config_home ); + else + nfsnprintf( path, sizeof(path), "%s/.config/isyncrc", Home ); + nfsnprintf( path2, sizeof(path2), "%s/.mbsyncrc", Home ); + struct stat st; + int ex = !lstat( path, &st ); + int ex2 = !lstat( path2, &st ); + if (ex2 && !ex) { + cfile.file = path2; + } else { + if (ex && ex2) + warn( "Both %s and %s exist; using the former.\n", path, path2 ); + cfile.file = path; + } } else { cfile.file = where; } @@ -538,7 +554,25 @@ load_config( const char *where ) if (cfile.ms_warn) warn( "Notice: Master/Slave are deprecated; use Far/Near instead.\n" ); cfile.err |= merge_ops( gcops, global_conf.ops ); - if (!global_conf.sync_state) - global_conf.sync_state = expand_strdup( "~/." EXE "/" ); + if (!global_conf.sync_state) { + const char *state_home = getenv( "XDG_STATE_HOME" ); + if (state_home) + nfsnprintf( path, sizeof(path), "%s/isync/", state_home ); + else + nfsnprintf( path, sizeof(path), "%s/.local/state/isync/", Home ); + nfsnprintf( path2, sizeof(path2), "%s/.mbsync/", Home ); + struct stat st; + int ex = !lstat( path, &st ); + int ex2 = !lstat( path2, &st ); + if (ex2 && !ex) { + global_conf.sync_state = nfstrdup( path2 ); + } else { + if (ex && ex2) { + error( "Error: both %s and %s exist; delete one or set SyncState globally.\n", path, path2 ); + cfile.err = 1; + } + global_conf.sync_state = nfstrdup( path ); + } + } return cfile.err; } diff --git a/src/mbsync.1 b/src/mbsync.1 index e39aa69..fe08ccf 100644 --- a/src/mbsync.1 +++ b/src/mbsync.1 @@ -32,7 +32,8 @@ Multiple replicas of each mailbox can be maintained. .TP \fB-c\fR, \fB--config\fR \fIfile\fR Read configuration from \fIfile\fR. -By default, the configuration is read from ~/.mbsyncrc. +By default, the configuration is read from $XDG_CONFIG_HOME/isyncrc, and +if that does not exist, ~/.mbsyncrc is tried in turn. .TP \fB-a\fR, \fB--all\fR Select all configured Channels. Any Channel/Group specifications on the @@ -672,7 +673,8 @@ the appended string is made up according to the pattern \fB:\fIfar-store\fB:\fIfar-box\fB_:\fInear-store\fB:\fInear-box\fR (see also \fBFieldDelimiter\fR below). .br -(Global default: \fI~/.mbsync/\fR). +(Global default: \fI$XDG_STATE_HOME/isync/\fR, with a fallback to +\fI~/.mbsync/\fR if only that exists) . .SS Groups .TP @@ -795,12 +797,18 @@ There is no risk as long as the IMAP mailbox is accessed by only one client . .SH FILES .TP -.B ~/.mbsyncrc +.B $XDG_CONFIG_HOME/isyncrc Default configuration file. See also the example file in the documentation directory. .TP +.B $XDG_STATE_HOME/isync/ +Directory containing synchronization state files. +.TP +.B ~/.mbsyncrc +Legacy configuration file. +.TP .B ~/.mbsync/ -Directory containing synchronization state files +Legacy directory containing synchronization state files. . .SH SEE ALSO mdconvert(1), mutt(1), maildir(5)