more sophisticated CAPABILITY handling. also, don't issue the command if

the initial response already had it in the status code.
This commit is contained in:
Oswald Buddenhagen 2004-01-31 01:01:07 +00:00
parent 3e392b6aa2
commit a52fd7dde0
2 changed files with 62 additions and 38 deletions

View File

@ -42,6 +42,10 @@
# include <openssl/err.h> # include <openssl/err.h>
#endif #endif
#define as(ar) (sizeof(ar)/sizeof(ar[0]))
#define CAP(cap) (imap->caps & (1 << (cap)))
static int Tag; static int Tag;
const char *Flags[] = { const char *Flags[] = {
@ -395,14 +399,44 @@ parse_fetch (imap_t *imap, char *cmd)
return 0; 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_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 static void
parse_response_code (imap_t * imap, char *s) parse_response_code (imap_t * imap, char *s)
{ {
char *arg; char *arg, *p;
if (*s != '[') if (*s != '[')
return; /* no response code */ return; /* no response code */
s++; s++;
if (!(p = strchr (s, ']')))
{
fprintf (stderr, "IMAP error: malformed response code\n");
return;
}
*p++ = 0;
arg = next_arg (&s); arg = next_arg (&s);
@ -411,12 +445,17 @@ parse_response_code (imap_t * imap, char *s)
arg = next_arg (&s); arg = next_arg (&s);
imap->uidvalidity = atol (arg); imap->uidvalidity = atol (arg);
} }
else if (!strcmp ("CAPABILITY", arg))
{
parse_capability (imap, s);
}
else if (!strcmp ("ALERT", arg)) else if (!strcmp ("ALERT", arg))
{ {
/* RFC2060 says that these messages MUST be displayed /* RFC2060 says that these messages MUST be displayed
* to the user * 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)) else if (!strcmp ("CAPABILITY", arg))
{ {
while ((arg = next_arg (&cmd))) parse_capability (imap, 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
}
} }
else if (!strcmp ("LIST", arg)) else if (!strcmp ("LIST", arg))
{ {
@ -736,8 +761,8 @@ imap_connect (config_t * cfg)
fprintf (stderr, "IMAP error: unknown greeting response\n"); fprintf (stderr, "IMAP error: unknown greeting response\n");
goto bail; goto bail;
} }
/* let's see what this puppy can do... */ parse_response_code (imap, rsp);
if (imap_exec (imap, "CAPABILITY")) if (!imap->caps && imap_exec (imap, "CAPABILITY"))
goto bail; goto bail;
if (!preauth) if (!preauth)
@ -749,7 +774,7 @@ imap_connect (config_t * cfg)
if (cfg->use_sslv2 || cfg->use_sslv3 || cfg->use_tlsv1) if (cfg->use_sslv2 || cfg->use_sslv3 || cfg->use_tlsv1)
{ {
/* always try to select SSL support if available */ /* always try to select SSL support if available */
if (imap->have_starttls) if (CAP(STARTTLS))
{ {
if (imap_exec (imap, "STARTTLS")) if (imap_exec (imap, "STARTTLS"))
goto bail; goto bail;
@ -757,14 +782,6 @@ imap_connect (config_t * cfg)
goto bail; goto bail;
use_ssl = 1; 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")) if (imap_exec (imap, "CAPABILITY"))
goto bail; goto bail;
} }
@ -817,7 +834,7 @@ imap_connect (config_t * cfg)
} }
#if HAVE_LIBSSL #if HAVE_LIBSSL
if (imap->have_cram) if (CAP(CRAM))
{ {
info ("Authenticating with CRAM-MD5\n"); info ("Authenticating with CRAM-MD5\n");
imap->cram = 1; imap->cram = 1;
@ -832,7 +849,7 @@ imap_connect (config_t * cfg)
else else
#endif #endif
{ {
if (imap->have_nologin) if (CAP(NOLOGIN))
{ {
fprintf (stderr, "Skipping %s, server forbids LOGIN\n", cfg->path); fprintf (stderr, "Skipping %s, server forbids LOGIN\n", cfg->path);
goto bail; goto bail;
@ -850,7 +867,7 @@ imap_connect (config_t * cfg)
} /* !preauth */ } /* !preauth */
/* get NAMESPACE info */ /* 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")) if (imap_exec (imap, "NAMESPACE"))
goto bail; goto bail;
@ -1204,7 +1221,7 @@ imap_append_message (imap_t * imap, int fd, message_t * msg)
} }
extra = 0, i = 0; extra = 0, i = 0;
if (!imap->have_uidplus) if (!CAP(UIDPLUS))
{ {
nloop: nloop:
start = i; start = i;
@ -1266,7 +1283,7 @@ imap_append_message (imap_t * imap, int fd, message_t * msg)
} }
i = 0; i = 0;
if (!imap->have_uidplus) if (!CAP(UIDPLUS))
{ {
n1loop: n1loop:
start = i; start = i;

View File

@ -153,17 +153,24 @@ typedef struct
list_t *ns_personal; list_t *ns_personal;
list_t *ns_other; list_t *ns_other;
list_t *ns_shared; list_t *ns_shared;
unsigned int have_nologin:1; unsigned int caps;
unsigned int have_uidplus:1;
unsigned int have_namespace:1;
#if HAVE_LIBSSL #if HAVE_LIBSSL
unsigned int have_cram:1;
unsigned int have_starttls:1;
unsigned int cram:1; unsigned int cram:1;
#endif #endif
} }
imap_t; imap_t;
/* Keep in sync with cap_list */
enum CAPABILITY {
NOLOGIN,
UIDPLUS,
NAMESPACE,
#if HAVE_LIBSSL
CRAM,
STARTTLS,
#endif
};
/* flags for sync_mailbox */ /* flags for sync_mailbox */
#define SYNC_DELETE (1<<0) /* delete local that don't exist on server */ #define SYNC_DELETE (1<<0) /* delete local that don't exist on server */
#define SYNC_EXPUNGE (1<<1) /* don't fetch deleted messages */ #define SYNC_EXPUNGE (1<<1) /* don't fetch deleted messages */