commit 4e3094cb94880d8763937d23c0435ff02484722c
Author: Oswald Buddenhagen <[email protected]>
Date: Wed Sep 25 20:55:32 2013 +0200
support backslashes and quotes in quoted IMAP strings
the RFCs require it - well hidden in the BNF at the bottom.
patch somewhat inspired by "guns" <[email protected]>.
src/drv_imap.c | 161 ++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 136 insertions(+), 25 deletions(-)
diff --git a/src/drv_imap.c b/src/drv_imap.c
index 798320d..4940b5b 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -355,6 +355,88 @@ submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
return send_imap_cmd( ctx, cmd );
}
+/* Minimal printf() replacement that supports an %\s format sequence to print
backslash-escaped
+ * string literals. Note that this does not automatically add quotes around
the printed string,
+ * so it is possible to concatenate multiple segments. */
+static char *
+imap_vprintf( const char *fmt, va_list ap )
+{
+ const char *s, *es;
+ char *d, *ed;
+ int maxlen;
+ char c;
+ char buf[1024]; /* Minimal supported command buffer size per IMAP spec.
*/
+
+ d = buf;
+ ed = d + sizeof(buf);
+ s = fmt;
+ for (;;) {
+ c = *fmt;
+ if (!c || c == '%') {
+ int l = fmt - s;
+ if (d + l > ed)
+ oob();
+ memcpy( d, s, l );
+ d += l;
+ if (!c) {
+ l = d - buf;
+ ed = nfmalloc( l + 1 );
+ memcpy( ed, buf, l );
+ ed[l] = 0;
+ return ed;
+ }
+ maxlen = INT_MAX;
+ c = *++fmt;
+ if (c == '\\') {
+ c = *++fmt;
+ if (c != 's') {
+ fputs( "Fatal: unsupported escaped
format specifier. Please report a bug.\n", stderr );
+ abort();
+ }
+ s = va_arg( ap, const char * );
+ while ((c = *s++)) {
+ if (d + 2 > ed)
+ oob();
+ if (c == '\\' || c == '"')
+ *d++ = '\\';
+ *d++ = c;
+ }
+ } else { /* \\ cannot be combined with anything else. */
+ if (c == '.') {
+ c = *++fmt;
+ if (c != '*') {
+ fputs( "Fatal: unsupported
string length specification. Please report a bug.\n", stderr );
+ abort();
+ }
+ maxlen = va_arg( ap , int );
+ c = *++fmt;
+ }
+ if (c == 'c') {
+ if (d + 1 > ed)
+ oob();
+ *d++ = (char)va_arg( ap , int );
+ } else if (c == 's') {
+ s = va_arg( ap, const char * );
+ es = memchr( s, 0, maxlen );
+ l = es ? es - s : maxlen;
+ if (d + l > ed)
+ oob();
+ memcpy( d, s, l );
+ d += l;
+ } else if (c == 'd') {
+ d += nfsnprintf( d, ed - d, "%d",
va_arg( ap , int ) );
+ } else {
+ fputs( "Fatal: unsupported format
specifier. Please report a bug.\n", stderr );
+ abort();
+ }
+ }
+ s = ++fmt;
+ } else {
+ fmt++;
+ }
+ }
+}
+
static int
imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp,
void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response
),
@@ -366,7 +448,7 @@ imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp,
cmdp = new_imap_cmd( sizeof(*cmdp) );
cmdp->param.done = done;
va_start( ap, fmt );
- nfvasprintf( &cmdp->cmd, fmt, ap );
+ cmdp->cmd = imap_vprintf( fmt, ap );
va_end( ap );
return submit_imap_cmd( ctx, cmdp );
}
@@ -457,10 +539,25 @@ imap_refcounted_done_box( imap_store_t *ctx ATTR_UNUSED,
struct imap_cmd *cmd, i
imap_refcounted_done( sts );
}
+static const char *
+imap_strchr( const char *s, char tc )
+{
+ for (;; s++) {
+ char c = *s;
+ if (c == '\\')
+ c = *++s;
+ if (!c)
+ return 0;
+ if (c == tc)
+ return s;
+ }
+}
+
static char *
next_arg( char **ps )
{
- char *ret, *s;
+ char *ret, *s, *d;
+ char c;
assert( ps );
s = *ps;
@@ -473,20 +570,30 @@ next_arg( char **ps )
return 0;
}
if (*s == '"') {
- ++s;
- ret = s;
- s = strchr( s, '"' );
+ s++;
+ ret = d = s;
+ while ((c = *s++) != '"') {
+ if (c == '\\')
+ c = *s++;
+ if (!c) {
+ *ps = 0;
+ return 0;
+ }
+ *d++ = c;
+ }
+ *d = 0;
} else {
ret = s;
- while (*s && !isspace( (unsigned char)*s ))
+ while ((c = *s)) {
+ if (isspace( (unsigned char)c )) {
+ *s++ = 0;
+ break;
+ }
s++;
+ }
}
- if (s) {
- if (*s)
- *s++ = 0;
- if (!*s)
- s = 0;
- }
+ if (!*s)
+ s = 0;
*ps = s;
return ret;
@@ -529,8 +636,9 @@ static int
parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
{
list_t *cur, **curp;
- char *s = *sp, *p;
+ char *s = *sp, *d, *p;
int bytes;
+ char c;
assert( sts );
assert( sts->level > 0 );
@@ -595,12 +703,15 @@ parse_imap_list( imap_store_t *ctx, char **sp,
parse_list_state_t *sts )
} else if (*s == '"') {
/* quoted string */
s++;
- p = s;
- for (; *s != '"'; s++)
- if (!*s)
+ p = d = s;
+ while ((c = *s++) != '"') {
+ if (c == '\\')
+ c = *s++;
+ if (!c)
goto bail;
- cur->len = s - p;
- s++;
+ *d++ = c;
+ }
+ cur->len = d - p;
cur->val = nfmalloc( cur->len + 1 );
memcpy( cur->val, p, cur->len );
cur->val[cur->len] = 0;
@@ -1140,7 +1251,7 @@ imap_socket_read( void *aux )
cmd2->gen.param.high_prio = 1;
p = strchr( cmdp->cmd, '"' );
if (imap_exec( ctx, &cmd2->gen,
get_cmd_result_p2,
- "CREATE %.*s",
strchr( p + 1, '"' ) - p + 1, p ) < 0)
+ "CREATE %.*s",
imap_strchr( p + 1, '"' ) - p + 1, p ) < 0)
return;
continue;
}
@@ -1571,7 +1682,7 @@ imap_open_store_authenticate2( imap_store_t *ctx )
#endif
warn( "*** IMAP Warning *** Password is being sent in the
clear\n" );
imap_exec( ctx, 0, imap_open_store_authenticate2_p2,
- "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass );
+ "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass );
return;
bail:
@@ -1695,7 +1806,7 @@ imap_select( store_t *gctx, int create,
cmd->gen.param.create = create;
cmd->gen.param.trycreate = 1;
imap_exec( ctx, &cmd->gen, imap_done_simple_box,
- "SELECT \"%s\"", buf );
+ "SELECT \"%\\s\"", buf );
free( buf );
}
@@ -1912,7 +2023,7 @@ imap_trash_msg( store_t *gctx, message_t *msg,
return;
}
imap_exec( ctx, &cmd->gen, imap_done_simple_msg,
- "UID COPY %d \"%s\"", msg->uid, buf );
+ "UID COPY %d \"%\\s\"", msg->uid, buf );
free( buf );
}
@@ -1966,10 +2077,10 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int
to_trash,
# pragma GCC diagnostic pop
#endif
imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
- "APPEND \"%s\" %s\"%s\" ", buf, flagstr, datestr );
+ "APPEND \"%\\s\" %s\"%\\s\" ", buf, flagstr, datestr
);
} else {
imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
- "APPEND \"%s\" %s", buf, flagstr );
+ "APPEND \"%\\s\" %s", buf, flagstr );
}
free( buf );
}
@@ -2023,7 +2134,7 @@ imap_list( store_t *gctx, int flags,
if (((flags & LIST_PATH) &&
imap_exec( ctx, imap_refcounted_new_cmd( sts ),
imap_refcounted_done_box,
- "LIST \"\" \"%s*\"", ctx->prefix ) < 0) ||
+ "LIST \"\" \"%\\s*\"", ctx->prefix ) < 0) ||
((flags & LIST_INBOX) && (!(flags & LIST_PATH) || *ctx->prefix) &&
imap_exec( ctx, imap_refcounted_new_cmd( sts ),
imap_refcounted_done_box,
"LIST \"\" INBOX*" ) < 0))
------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60134071&iu=/4140/ostg.clktrk
_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel