commit 00d08e4f484eafd5acae38bdb09bc4d969fa3250
Author: Oswald Buddenhagen <[email protected]>
Date:   Sat Aug 3 15:10:57 2013 +0200

    support multi-character path separators
    
    this applies to both the IMAP PathDelimiter (which is needed by Lotus
    Domino), as well as the Flatten-ed separators.

 src/config.c   |   18 +++++-------
 src/drv_imap.c |   71 +++++++++++++++++++++++++++++++----------------
 src/isync.h    |    4 +-
 src/main.c     |   13 ++++++---
 src/mbsync.1   |    4 +-
 src/sync.c     |    5 ++-
 src/util.c     |   61 ++++++++++++++++++++++++++++++++---------
 7 files changed, 119 insertions(+), 57 deletions(-)

diff --git a/src/config.c b/src/config.c
index 124e1ee..2c2a086 100644
--- a/src/config.c
+++ b/src/config.c
@@ -497,16 +497,14 @@ parse_generic_store( store_conf_t *store, conffile_t *cfg 
)
        else if (!strcasecmp( "MapInbox", cfg->cmd ))
                store->map_inbox = nfstrdup( cfg->val );
        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 );
-                       cfg->err = 1;
-               } else if (cfg->val[0] == '/') {
-                       error( "%s:%d: flattened hierarchy delimiter cannot be 
the canonical delimiter '/'\n", cfg->file, cfg->line );
-                       cfg->err = 1;
-               } else {
-                       store->flat_delim = cfg->val[0];
-               }
+               const char *p;
+               for (p = cfg->val; *p; p++)
+                       if (*p == '/') {
+                               error( "%s:%d: flattened hierarchy delimiter 
cannot contain the canonical delimiter '/'\n", cfg->file, cfg->line );
+                               cfg->err = 1;
+                               return;
+                       }
+               store->flat_delim = nfstrdup( cfg->val );
        } else {
                error( "%s:%d: unknown keyword '%s'\n", cfg->file, cfg->line, 
cfg->cmd );
                cfg->err = 1;
diff --git a/src/drv_imap.c b/src/drv_imap.c
index 4ed8c6f..abfc760 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -52,7 +52,7 @@ typedef struct imap_store_conf {
        store_conf_t gen;
        imap_server_conf_t *server;
        unsigned use_namespace:1;
-       char delimiter;
+       char *delimiter;
 } imap_store_conf_t;
 
 typedef struct imap_message {
@@ -88,7 +88,7 @@ typedef struct imap_store {
        /* trash folder's existence is not confirmed yet */
        enum { TrashUnknown, TrashChecking, TrashKnown } trashnc;
        unsigned got_namespace:1;
-       char delimiter; /* hierarchy delimiter */
+       char *delimiter; /* hierarchy delimiter */
        list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
        message_t **msgapp; /* FETCH results */
        unsigned caps; /* CAPABILITY results */
@@ -913,13 +913,29 @@ parse_list_rsp( imap_store_t *ctx, list_t *list, char 
*cmd )
        free_list( list );
        arg = next_arg( &cmd );
        if (!ctx->delimiter)
-               ctx->delimiter = *arg;
+               ctx->delimiter = nfstrdup( arg );
        return parse_list( ctx, cmd, parse_list_rsp_p2 );
 }
 
 static int
+is_inbox( imap_store_t *ctx, const char *arg )
+{
+       int i;
+       char c;
+
+       if (memcmp( arg, "INBOX", 5 ))
+               return 0;
+       if (arg[5])
+               for (i = 0; (c = ctx->delimiter[i]); i++)
+                       if (arg[i + 5] != c)
+                               return 0;
+       return 1;
+}
+
+static int
 parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED )
 {
+       string_list_t *narg;
        char *arg;
        int l;
 
@@ -929,12 +945,12 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char 
*cmd ATTR_UNUSED )
                return LIST_BAD;
        }
        arg = list->val;
-       if (memcmp( arg, "INBOX", 5 ) || (arg[5] && arg[5] != ctx->delimiter)) {
+       if (!is_inbox( ctx, arg )) {
                l = strlen( ctx->gen.conf->path );
                if (memcmp( arg, ctx->gen.conf->path, l ))
                        goto skip;
                arg += l;
-               if (!memcmp( arg, "INBOX", 5 ) && (!arg[5] || arg[5] == 
ctx->delimiter)) {
+               if (is_inbox( ctx, arg )) {
                        if (!arg[5])
                                warn( "IMAP warning: ignoring INBOX in %s\n", 
ctx->gen.conf->path );
                        goto skip;
@@ -942,36 +958,37 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char 
*cmd ATTR_UNUSED )
        }
        if (!memcmp( arg + strlen( arg ) - 5, ".lock", 5 )) /* workaround 
broken servers */
                goto skip;
-       if (map_name( arg, ctx->delimiter, '/') < 0) {
+       if (map_name( arg, (char **)&narg, offsetof(string_list_t, string), 
ctx->delimiter, "/") < 0) {
                warn( "IMAP warning: ignoring mailbox %s (reserved character 
'/' in name)\n", arg );
                goto skip;
        }
-       add_string_list( &ctx->gen.boxes, arg );
+       narg->next = ctx->gen.boxes;
+       ctx->gen.boxes = narg;
   skip:
        free_list( list );
        return LIST_OK;
 }
 
 static int
-prepare_name( char *buf, const imap_store_t *ctx, const char *prefix, const 
char *name )
+prepare_name( char **buf, const imap_store_t *ctx, const char *prefix, const 
char *name )
 {
-       int pl;
+       int pl = strlen( prefix );
 
-       nfsnprintf( buf, 1024, "%s%n%s", prefix, &pl, name );
-       switch (map_name( buf + pl, '/', ctx->delimiter )) {
+       switch (map_name( name, buf, pl, "/", ctx->delimiter )) {
        case -1:
-               error( "IMAP error: mailbox name %s contains server's hierarchy 
delimiter\n", buf + pl );
+               error( "IMAP error: mailbox name %s contains server's hierarchy 
delimiter\n", name );
                return -1;
        case -2:
                error( "IMAP error: server's hierarchy delimiter not known\n" );
                return -1;
        default:
+               memcpy( *buf, prefix, pl );
                return 0;
        }
 }
 
 static int
-prepare_box( char *buf, const imap_store_t *ctx )
+prepare_box( char **buf, const imap_store_t *ctx )
 {
        const char *name = ctx->gen.name;
 
@@ -980,7 +997,7 @@ prepare_box( char *buf, const imap_store_t *ctx )
 }
 
 static int
-prepare_trash( char *buf, const imap_store_t *ctx )
+prepare_trash( char **buf, const imap_store_t *ctx )
 {
        return prepare_name( buf, ctx, ctx->prefix, ctx->gen.conf->trash );
 }
@@ -1183,6 +1200,7 @@ imap_cancel_store( store_t *gctx )
        free_list( ctx->ns_personal );
        free_list( ctx->ns_other );
        free_list( ctx->ns_shared );
+       free( ctx->delimiter );
        imap_deref( ctx );
 }
 
@@ -1330,6 +1348,7 @@ imap_open_store( store_conf_t *conf,
                        ctx->gen.boxes = 0;
                        ctx->gen.listed = 0;
                        ctx->gen.conf = conf;
+                       free( ctx->delimiter );
                        ctx->delimiter = 0;
                        ctx->callbacks.imap_open = cb;
                        ctx->callback_aux = aux;
@@ -1570,7 +1589,7 @@ imap_open_store_namespace( imap_store_t *ctx )
        imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
 
        ctx->prefix = cfg->gen.path;
-       ctx->delimiter = cfg->delimiter;
+       ctx->delimiter = cfg->delimiter ? nfstrdup( cfg->delimiter ) : 0;
        if (((!*ctx->prefix && cfg->use_namespace) || !cfg->delimiter) && 
CAP(NAMESPACE)) {
                /* get NAMESPACE info */
                if (!ctx->got_namespace)
@@ -1608,7 +1627,7 @@ imap_open_store_namespace2( imap_store_t *ctx )
                if (!*ctx->prefix && cfg->use_namespace)
                        ctx->prefix = nsp_1st_ns->val;
                if (!ctx->delimiter)
-                       ctx->delimiter = *nsp_1st_dl->val;
+                       ctx->delimiter = nfstrdup( nsp_1st_dl->val );
        }
        imap_open_store_finalize( ctx );
 }
@@ -1656,12 +1675,12 @@ imap_select( store_t *gctx, int create,
 {
        imap_store_t *ctx = (imap_store_t *)gctx;
        struct imap_cmd_simple *cmd;
-       char buf[1024];
+       char *buf;
 
        free_generic_messages( gctx->msgs );
        gctx->msgs = 0;
 
-       if (prepare_box( buf, ctx ) < 0) {
+       if (prepare_box( &buf, ctx ) < 0) {
                cb( DRV_BOX_BAD, aux );
                return;
        }
@@ -1673,6 +1692,7 @@ imap_select( store_t *gctx, int create,
        cmd->gen.param.trycreate = 1;
        imap_exec( ctx, &cmd->gen, imap_done_simple_box,
                   "SELECT \"%s\"", buf );
+       free( buf );
 }
 
 /******************* imap_load *******************/
@@ -1878,17 +1898,18 @@ imap_trash_msg( store_t *gctx, message_t *msg,
 {
        imap_store_t *ctx = (imap_store_t *)gctx;
        struct imap_cmd_simple *cmd;
-       char buf[1024];
+       char *buf;
 
        INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
        cmd->gen.param.create = 1;
        cmd->gen.param.to_trash = 1;
-       if (prepare_trash( buf, ctx ) < 0) {
+       if (prepare_trash( &buf, ctx ) < 0) {
                cb( DRV_BOX_BAD, aux );
                return;
        }
        imap_exec( ctx, &cmd->gen, imap_done_simple_msg,
                   "UID COPY %d \"%s\"", msg->uid, buf );
+       free( buf );
 }
 
 /******************* imap_store_msg *******************/
@@ -1901,8 +1922,9 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int 
to_trash,
 {
        imap_store_t *ctx = (imap_store_t *)gctx;
        struct imap_cmd_out_uid *cmd;
+       char *buf;
        int d;
-       char flagstr[128], datestr[64], buf[1024];
+       char flagstr[128], datestr[64];
 
        d = 0;
        if (data->flags) {
@@ -1919,12 +1941,12 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int 
to_trash,
        if (to_trash) {
                cmd->gen.param.create = 1;
                cmd->gen.param.to_trash = 1;
-               if (prepare_trash( buf, ctx ) < 0) {
+               if (prepare_trash( &buf, ctx ) < 0) {
                        cb( DRV_BOX_BAD, -1, aux );
                        return;
                }
        } else {
-               if (prepare_box( buf, ctx ) < 0) {
+               if (prepare_box( &buf, ctx ) < 0) {
                        cb( DRV_BOX_BAD, -1, aux );
                        return;
                }
@@ -1945,6 +1967,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int 
to_trash,
                imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
                           "APPEND \"%s\" %s", buf, flagstr );
        }
+       free( buf );
 }
 
 static void
@@ -2143,7 +2166,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
                        else if (!strcasecmp( "Path", cfg->cmd ))
                                store->gen.path = nfstrdup( cfg->val );
                        else if (!strcasecmp( "PathDelimiter", cfg->cmd ))
-                               store->delimiter = *cfg->val;
+                               store->delimiter = nfstrdup( cfg->val );
                        else
                                parse_generic_store( &store->gen, cfg );
                        continue;
diff --git a/src/isync.h b/src/isync.h
index b6c7233..5176313 100644
--- a/src/isync.h
+++ b/src/isync.h
@@ -142,11 +142,11 @@ typedef struct store_conf {
        char *name;
        driver_t *driver;
        const char *path; /* should this be here? its interpretation is 
driver-specific */
+       const char *flat_delim;
        const char *map_inbox;
        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 {
@@ -440,7 +440,7 @@ void ATTR_NORETURN oob( void );
 
 char *expand_strdup( const char *s );
 
-int map_name( char *arg, char in, char out );
+int map_name(const char *arg, char **result, int reserve, const char *in, 
const char *out );
 
 void sort_ints( int *arr, int len );
 
diff --git a/src/main.c b/src/main.c
index 741107c..0adc45b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -744,7 +744,7 @@ static void
 store_listed( int sts, void *aux )
 {
        MVARS(aux)
-       string_list_t *box;
+       string_list_t **box;
 
        switch (sts) {
        case DRV_CANCELED:
@@ -752,10 +752,15 @@ store_listed( int sts, void *aux )
        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 );
+                       for (box = &mvars->ctx[t]->boxes; *box; box = 
&(*box)->next) {
+                               string_list_t *nbox;
+                               if (map_name( (*box)->string, (char **)&nbox, 
offsetof(string_list_t, 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;
+                               } else {
+                                       nbox->next = (*box)->next;
+                                       free( *box );
+                                       *box = nbox;
                                }
                        }
                }
diff --git a/src/mbsync.1 b/src/mbsync.1
index 7925c69..965e65f 100644
--- a/src/mbsync.1
+++ b/src/mbsync.1
@@ -20,7 +20,7 @@
 \" As a special exception, mbsync may be linked with the OpenSSL library,
 \" despite that library's more restrictive license.
 ..
-.TH mbsync 1 "2013 Apr 20"
+.TH mbsync 1 "2013 Aug 3"
 ..
 .SH NAME
 mbsync - synchronize IMAP4 and Maildir mailboxes
@@ -352,7 +352,7 @@ This option is meaningless if a \fBPath\fR was specified.
 ..
 .TP
 \fBPathDelimiter\fR \fIdelim\fR
-Specify the server's hierarchy delimiter character.
+Specify the server's hierarchy delimiter.
 (Default: taken from the server's first "personal" NAMESPACE)
 .br
 Do \fBNOT\fR abuse this to re-interpret the hierarchy.
diff --git a/src/sync.c b/src/sync.c
index d97d2c7..5633fbf 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -618,8 +618,9 @@ sync_boxes( store_t *ctx[], const char *names[], 
channel_conf_t *chan,
                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) {
+               if (!ctx[t]->conf->flat_delim) {
+                       ctx[t]->name = nfstrdup( ctx[t]->orig_name );
+               } else if (map_name( ctx[t]->orig_name, &ctx[t]->name, 0, "/", 
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 );
diff --git a/src/util.c b/src/util.c
index ba05efa..2b89a7d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -361,24 +361,59 @@ expand_strdup( const char *s )
 
 /* Return value: 0 = ok, -1 = out found in arg, -2 = in found in arg but no 
out specified */
 int
-map_name( char *arg, char in, char out )
+map_name( const char *arg, char **result, int reserve, const char *in, const 
char *out )
 {
-       int l, k;
+       char *p;
+       int i, l, ll, num, inl, outl;
 
-       if (!in || in == out)
+       l = strlen( arg );
+       if (!in) {
+         copy:
+               *result = nfmalloc( reserve + l + 1 );
+               memcpy( *result + reserve, arg, l + 1 );
                return 0;
-       for (l = 0; arg[l]; l++)
-               if (arg[l] == in) {
-                       if (!out)
-                               return -2;
-                       arg[l] = out;
-               } else if (arg[l] == out) {
-                       /* restore original name for printing error message */
-                       for (k = 0; k < l; k++)
-                               if (arg[k] == out)
-                                       arg[k] = in;
+       }
+       inl = strlen( in );
+       if (out) {
+               outl = strlen( out );
+               if (inl == outl && !memcmp( in, out, inl ))
+                       goto copy;
+       }
+       for (num = 0, i = 0; i < l; ) {
+               for (ll = 0; ll < inl; ll++)
+                       if (arg[i + ll] != in[ll])
+                               goto fout;
+               num++;
+               i += inl;
+               continue;
+         fout:
+               if (out) {
+                       for (ll = 0; ll < outl; ll++)
+                               if (arg[i + ll] != out[ll])
+                                       goto fnexti;
                        return -1;
                }
+         fnexti:
+               i++;
+       }
+       if (!num)
+               goto copy;
+       if (!out)
+               return -2;
+       *result = nfmalloc( reserve + l + num * (outl - inl) + 1 );
+       p = *result + reserve;
+       for (i = 0; i < l; ) {
+               for (ll = 0; ll < inl; ll++)
+                       if (arg[i + ll] != in[ll])
+                               goto rnexti;
+               memcpy( p, out, outl );
+               p += outl;
+               i += inl;
+               continue;
+         rnexti:
+               *p++ = arg[i++];
+       }
+       *p = 0;
        return 0;
 }
 

------------------------------------------------------------------------------
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk
_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to