commit a52fd7dde034eb7f4ff7ebe62af1d4aa5f64cf8e
parent 3e392b6aa2709f814e378187c848d8f1de662c78
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Sat, 31 Jan 2004 01:01:07 +0000
more sophisticated CAPABILITY handling. also, don't issue the command if
the initial response already had it in the status code.
Diffstat:
M | src/imap.c | | | 83 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
M | src/isync.h | | | 17 | ++++++++++++----- |
2 files changed, 62 insertions(+), 38 deletions(-)
diff --git a/src/imap.c b/src/imap.c
@@ -42,6 +42,10 @@
# include <openssl/err.h>
#endif
+#define as(ar) (sizeof(ar)/sizeof(ar[0]))
+
+#define CAP(cap) (imap->caps & (1 << (cap)))
+
static int Tag;
const char *Flags[] = {
@@ -395,14 +399,44 @@ parse_fetch (imap_t *imap, char *cmd)
return 0;
}
+/* Keep this in sync with enum CAPABILITY */
+const char *cap_list[] = {
+ "LOGINDISABLED",
+ "UIDPLUS",
+ "NAMESPACE",
+#if HAVE_LIBSSL
+ "AUTH=CRAM-MD5",
+ "STARTTLS",
+#endif
+};
+
static void
-parse_response_code (imap_t * imap, char *s)
+parse_capability (imap_t *imap, char *cmd)
{
char *arg;
+ unsigned i;
+
+ imap->caps = 0x80000000;
+ while ((arg = next_arg (&cmd)))
+ for (i = 0; i < as(cap_list); i++)
+ if (!strcmp (cap_list[i], arg))
+ imap->caps |= 1 << i;
+}
+
+static void
+parse_response_code (imap_t * imap, char *s)
+{
+ char *arg, *p;
if (*s != '[')
return; /* no response code */
s++;
+ if (!(p = strchr (s, ']')))
+ {
+ fprintf (stderr, "IMAP error: malformed response code\n");
+ return;
+ }
+ *p++ = 0;
arg = next_arg (&s);
@@ -411,12 +445,17 @@ parse_response_code (imap_t * imap, char *s)
arg = next_arg (&s);
imap->uidvalidity = atol (arg);
}
+ else if (!strcmp ("CAPABILITY", arg))
+ {
+ parse_capability (imap, s);
+ }
else if (!strcmp ("ALERT", arg))
{
/* RFC2060 says that these messages MUST be displayed
* to the user
*/
- fprintf (stderr, "*** IMAP ALERT *** %s\n", s);
+ for (; isspace ((unsigned char)*p); p++);
+ fprintf (stderr, "*** IMAP ALERT *** %s\n", p);
}
}
@@ -477,21 +516,7 @@ imap_exec (imap_t * imap, const char *fmt, ...)
}
else if (!strcmp ("CAPABILITY", arg))
{
- while ((arg = next_arg (&cmd)))
- {
- if (!strcmp ("UIDPLUS", arg))
- imap->have_uidplus = 1;
- else if (!strcmp ("NAMESPACE", arg))
- imap->have_namespace = 1;
- else if (!strcmp ("LOGINDISABLED", arg))
- imap->have_nologin = 1;
-#if HAVE_LIBSSL
- else if (!strcmp ("STARTTLS", arg))
- imap->have_starttls = 1;
- else if (!strcmp ("AUTH=CRAM-MD5", arg))
- imap->have_cram = 1;
-#endif
- }
+ parse_capability (imap, cmd);
}
else if (!strcmp ("LIST", arg))
{
@@ -736,8 +761,8 @@ imap_connect (config_t * cfg)
fprintf (stderr, "IMAP error: unknown greeting response\n");
goto bail;
}
- /* let's see what this puppy can do... */
- if (imap_exec (imap, "CAPABILITY"))
+ parse_response_code (imap, rsp);
+ if (!imap->caps && imap_exec (imap, "CAPABILITY"))
goto bail;
if (!preauth)
@@ -749,7 +774,7 @@ imap_connect (config_t * cfg)
if (cfg->use_sslv2 || cfg->use_sslv3 || cfg->use_tlsv1)
{
/* always try to select SSL support if available */
- if (imap->have_starttls)
+ if (CAP(STARTTLS))
{
if (imap_exec (imap, "STARTTLS"))
goto bail;
@@ -757,14 +782,6 @@ imap_connect (config_t * cfg)
goto bail;
use_ssl = 1;
- /* to conform to RFC2595 we need to forget all information
- * retrieved from CAPABILITY invocations before STARTTLS.
- */
- imap->have_uidplus = 0;
- imap->have_namespace = 0;
- imap->have_cram = 0;
- imap->have_nologin = 0;
- /* imap->have_starttls = 0; */
if (imap_exec (imap, "CAPABILITY"))
goto bail;
}
@@ -817,7 +834,7 @@ imap_connect (config_t * cfg)
}
#if HAVE_LIBSSL
- if (imap->have_cram)
+ if (CAP(CRAM))
{
info ("Authenticating with CRAM-MD5\n");
imap->cram = 1;
@@ -832,7 +849,7 @@ imap_connect (config_t * cfg)
else
#endif
{
- if (imap->have_nologin)
+ if (CAP(NOLOGIN))
{
fprintf (stderr, "Skipping %s, server forbids LOGIN\n", cfg->path);
goto bail;
@@ -850,7 +867,7 @@ imap_connect (config_t * cfg)
} /* !preauth */
/* get NAMESPACE info */
- if (!global.folder && cfg->use_namespace && imap->have_namespace)
+ if (!global.folder && cfg->use_namespace && CAP(NAMESPACE))
{
if (imap_exec (imap, "NAMESPACE"))
goto bail;
@@ -1204,7 +1221,7 @@ imap_append_message (imap_t * imap, int fd, message_t * msg)
}
extra = 0, i = 0;
- if (!imap->have_uidplus)
+ if (!CAP(UIDPLUS))
{
nloop:
start = i;
@@ -1266,7 +1283,7 @@ imap_append_message (imap_t * imap, int fd, message_t * msg)
}
i = 0;
- if (!imap->have_uidplus)
+ if (!CAP(UIDPLUS))
{
n1loop:
start = i;
diff --git a/src/isync.h b/src/isync.h
@@ -153,17 +153,24 @@ typedef struct
list_t *ns_personal;
list_t *ns_other;
list_t *ns_shared;
- unsigned int have_nologin:1;
- unsigned int have_uidplus:1;
- unsigned int have_namespace:1;
+ unsigned int caps;
#if HAVE_LIBSSL
- unsigned int have_cram:1;
- unsigned int have_starttls:1;
unsigned int cram:1;
#endif
}
imap_t;
+/* Keep in sync with cap_list */
+enum CAPABILITY {
+ NOLOGIN,
+ UIDPLUS,
+ NAMESPACE,
+#if HAVE_LIBSSL
+ CRAM,
+ STARTTLS,
+#endif
+};
+
/* flags for sync_mailbox */
#define SYNC_DELETE (1<<0) /* delete local that don't exist on server */
#define SYNC_EXPUNGE (1<<1) /* don't fetch deleted messages */