commit d3f118be79686adfcd085211ad3a4b3fa892bf4e
Author: Oswald Buddenhagen <o...@users.sf.net>
Date:   Mon May 30 23:04:52 2022 +0200

    re-interpret relative local paths in config file
    
    this makes config+data file "sets" relocatable, which is useful for
    testing.
    
    this is technically a gratuitous backwards incompatible behavior
    change, but to the degree that anyone uses relative paths at all, they
    almost certainly rely on PWD being set up such that they won't see a
    difference.

 NEWS              |  3 +++
 src/config.c      | 25 +++++++++++++++++++------
 src/config.h      |  3 ++-
 src/drv_imap.c    |  6 +++---
 src/drv_maildir.c |  6 +++---
 src/mbsync.1      |  5 ++++-
 src/run-tests.pl  |  8 ++++----
 src/sync.h        |  2 +-
 8 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/NEWS b/NEWS
index 5513385e..aa53a198 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,9 @@
 Changed default config & state locations to follow the XDG basedir spec.
 The old locations remain supported.
 
+The reference point for relative local paths in the configuration file
+is now the file's containing directory.
+
 [1.4.0]
 
 The 'isync' compatibility wrapper was removed.
diff --git a/src/config.c b/src/config.c
index 65e080fc..880f0271 100644
--- a/src/config.c
+++ b/src/config.c
@@ -23,7 +23,7 @@ char FieldDelimiter = ':';
 static store_conf_t *stores;
 
 char *
-expand_strdup( const char *s )
+expand_strdup( const char *s, const conffile_t *cfile )
 {
        struct passwd *pw;
        const char *p, *q;
@@ -51,6 +51,9 @@ expand_strdup( const char *s )
                }
                nfasprintf( &r, "%s%s", q, p ? p : "" );
                return r;
+       } else if (*s != '/') {
+               nfasprintf( &r, "%.*s%s", cfile->path_len, cfile->file, s );
+               return r;
        } else {
                return nfstrdup( s );
        }
@@ -220,7 +223,7 @@ getopt_helper( conffile_t *cfile, int *cops, channel_conf_t 
*conf )
                } while ((arg = get_arg( cfile, ARG_OPTIONAL, NULL )));
                conf->ops[F] |= XOP_HAVE_TYPE;
        } else if (!strcasecmp( "SyncState", cfile->cmd )) {
-               conf->sync_state = expand_strdup( cfile->val );
+               conf->sync_state = !strcmp( cfile->val, "*" ) ? "*" : 
expand_strdup( cfile->val, cfile );
        } else if (!strcasecmp( "CopyArrivalDate", cfile->cmd )) {
                conf->use_internal_date = parse_bool( cfile );
        } else if (!strcasecmp( "MaxMessages", cfile->cmd )) {
@@ -354,24 +357,34 @@ load_config( const char *where )
        char buf[1024];
 
        if (!where) {
+               int path_len, path_len2;
                const char *config_home = getenv( "XDG_CONFIG_HOME" );
                if (config_home)
-                       nfsnprintf( path, sizeof(path), "%s/isyncrc", 
config_home );
+                       nfsnprintf( path, sizeof(path), "%s/%nisyncrc", 
config_home, &path_len );
                else
-                       nfsnprintf( path, sizeof(path), "%s/.config/isyncrc", 
Home );
-               nfsnprintf( path2, sizeof(path2), "%s/.mbsyncrc", Home );
+                       nfsnprintf( path, sizeof(path), "%s/.config/%nisyncrc", 
Home, &path_len );
+               nfsnprintf( path2, sizeof(path2), "%s/%n.mbsyncrc", Home, 
&path_len2 );
                struct stat st;
                int ex = !lstat( path, &st );
                int ex2 = !lstat( path2, &st );
                if (ex2 && !ex) {
                        cfile.file = path2;
+                       cfile.path_len = path_len2;
                } else {
                        if (ex && ex2)
                                warn( "Both %s and %s exist; using the 
former.\n", path, path2 );
                        cfile.file = path;
+                       cfile.path_len = path_len;
                }
        } else {
-               cfile.file = where;
+               const char *sl = strrchr( where, '/' );
+               if (!sl) {
+                       nfsnprintf( path, sizeof(path), "./%n%s", 
&cfile.path_len, where );
+                       cfile.file = path;
+               } else {
+                       cfile.path_len = sl - where + 1;
+                       cfile.file = where;
+               }
        }
 
        info( "Reading configuration file %s\n", cfile.file );
diff --git a/src/config.h b/src/config.h
index 063c1286..bc255114 100644
--- a/src/config.h
+++ b/src/config.h
@@ -18,6 +18,7 @@ typedef struct {
        int line;
        int err;
        int ms_warn;
+       int path_len;
        char *cmd, *val, *rest;
 } conffile_t;
 
@@ -26,7 +27,7 @@ extern char FieldDelimiter;
 #define ARG_OPTIONAL 0
 #define ARG_REQUIRED 1
 
-char *expand_strdup( const char *s );
+char *expand_strdup( const char *s, const conffile_t *cfile );
 
 char *get_arg( conffile_t *cfile, int required, int *comment );
 
diff --git a/src/drv_imap.c b/src/drv_imap.c
index 4ac00ec9..34cc9515 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -3590,7 +3590,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
                        } while ((arg = get_arg( cfg, ARG_OPTIONAL, NULL )));
 #ifdef HAVE_LIBSSL
                } else if (!strcasecmp( "CertificateFile", cfg->cmd )) {
-                       server->sconf.cert_file = expand_strdup( cfg->val );
+                       server->sconf.cert_file = expand_strdup( cfg->val, cfg 
);
                        if (access( server->sconf.cert_file, R_OK )) {
                                sys_error( "%s:%d: CertificateFile '%s'",
                                           cfg->file, cfg->line, 
server->sconf.cert_file );
@@ -3599,14 +3599,14 @@ imap_parse_store( conffile_t *cfg, store_conf_t 
**storep )
                } else if (!strcasecmp( "SystemCertificates", cfg->cmd )) {
                        server->sconf.system_certs = parse_bool( cfg );
                } else if (!strcasecmp( "ClientCertificate", cfg->cmd )) {
-                       server->sconf.client_certfile = expand_strdup( cfg->val 
);
+                       server->sconf.client_certfile = expand_strdup( 
cfg->val, cfg );
                        if (access( server->sconf.client_certfile, R_OK )) {
                                sys_error( "%s:%d: ClientCertificate '%s'",
                                           cfg->file, cfg->line, 
server->sconf.client_certfile );
                                cfg->err = 1;
                        }
                } else if (!strcasecmp( "ClientKey", cfg->cmd )) {
-                       server->sconf.client_keyfile = expand_strdup( cfg->val 
);
+                       server->sconf.client_keyfile = expand_strdup( cfg->val, 
cfg );
                        if (access( server->sconf.client_keyfile, R_OK )) {
                                sys_error( "%s:%d: ClientKey '%s'",
                                           cfg->file, cfg->line, 
server->sconf.client_keyfile );
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
index 6c1daa4e..c1de4dcb 100644
--- a/src/drv_maildir.c
+++ b/src/drv_maildir.c
@@ -1857,9 +1857,9 @@ maildir_parse_store( conffile_t *cfg, store_conf_t 
**storep )
 
        while (getcline( cfg ) && cfg->cmd) {
                if (!strcasecmp( "Inbox", cfg->cmd )) {
-                       store->inbox = expand_strdup( cfg->val );
+                       store->inbox = expand_strdup( cfg->val, cfg );
                } else if (!strcasecmp( "Path", cfg->cmd )) {
-                       store->path = expand_strdup( cfg->val );
+                       store->path = expand_strdup( cfg->val, cfg );
 #ifdef USE_DB
                } else if (!strcasecmp( "AltMap", cfg->cmd )) {
                        store->alt_map = parse_bool( cfg );
@@ -1892,7 +1892,7 @@ maildir_parse_store( conffile_t *cfg, store_conf_t 
**storep )
                }
        }
        if (!store->inbox)
-               store->inbox = expand_strdup( "~/Maildir" );
+               store->inbox = expand_strdup( "~/Maildir", NULL );
        if (store->sub_style == SUB_MAILDIRPP && store->path) {
                error( "Maildir store '%s': Setting Path is incompatible with 
'SubFolders Maildir++'\n", store->name );
                cfg->err = 1;
diff --git a/src/mbsync.1 b/src/mbsync.1
index fe08ccfd..403b2ce7 100644
--- a/src/mbsync.1
+++ b/src/mbsync.1
@@ -105,6 +105,8 @@ and literal double quotes and backslashes (\fB\\\fR) must 
be backslash-escaped.
 All keywords (including those used as arguments) are case-insensitive.
 Bash-like home directory expansion using the tilde (\fB~\fR) is supported
 in all options which represent local paths.
+The reference point for relative local paths is the configuration file's
+containing directory.
 There are a few global options, the others apply to particular sections.
 Sections begin with a section-starting keyword and are terminated by an empty
 line or end of file.
@@ -205,7 +207,8 @@ yet all messages are archived.
 (Default: \fBno\fR)
 .
 .SS Maildir Stores
-The reference point for relative \fBPath\fRs is the current working directory.
+The reference point for relative \fBPath\fRs is the configuration file's
+containing directory.
 .P
 As \fBmbsync\fR needs UIDs, but no standardized UID storage scheme exists for
 Maildir, \fBmbsync\fR supports two schemes, each with its pros and cons.
diff --git a/src/run-tests.pl b/src/run-tests.pl
index d771ebdf..2477826f 100755
--- a/src/run-tests.pl
+++ b/src/run-tests.pl
@@ -289,12 +289,12 @@ sub writecfg($)
 "FSync no
 
 MaildirStore far
-Path ./
-Inbox ./far
+Path \"\"
+Inbox far
 ".$$sfx[0]."
 MaildirStore near
-Path ./
-Inbox ./near
+Path \"\"
+Inbox near
 ".$$sfx[1]."
 Channel test
 Far :far:
diff --git a/src/sync.h b/src/sync.h
index dbcbeded..d0916098 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -35,7 +35,7 @@ typedef struct channel_conf {
        const char *name;
        store_conf_t *stores[2];
        const char *boxes[2];
-       char *sync_state;
+       const char *sync_state;
        string_list_t *patterns;
        int ops[2];
        int max_messages;  // For near side only.


_______________________________________________
isync-devel mailing list
isync-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to