#if defined(STDC_HEADERS)
#include <stdlib.h>
#include <limits.h>
+#include <errno.h>
#endif
#include "fetchmail.h"
#include "socket.h"
#include "i18n.h"
-#if OPIE_ENABLE
+#ifdef OPIE_ENABLE
#endif /* OPIE_ENABLE */
#ifndef strstr /* glibc-2.1 declares this as a macro */
-extern char *strstr(); /* needed on sysV68 R3V7.1. */
+extern char *strstr(const char *, const char *); /* needed on sysV68 R3V7.1. */
#endif /* strstr */
/* imap_version values */
/* all tokens in responses are caseblind */
for (cp = buf; *cp; cp++)
- if (islower(*cp))
- *cp = toupper(*cp);
+ if (islower((unsigned char)*cp))
+ *cp = toupper((unsigned char)*cp);
/* interpret untagged status responses */
if (strstr(buf, "* CAPABILITY"))
char *cp;
/* skip the tag */
- for (cp = buf; !isspace(*cp); cp++)
+ for (cp = buf; !isspace((unsigned char)*cp); cp++)
continue;
- while (isspace(*cp))
+ while (isspace((unsigned char)*cp))
cp++;
if (strncasecmp(cp, "OK", 2) == 0)
}
}
-#if NTLM_ENABLE
+#ifdef NTLM_ENABLE
#include "ntlm.h"
static tSmbNtlmAuthRequest request;
if (outlevel >= O_VERBOSE)
report(stdout, GT_("will idle after poll\n"));
}
+
+ peek_capable = (imap_version >= IMAP4);
}
static int imap_getauth(int sock, struct query *ctl, char *greeting)
flag did_stls = FALSE;
#endif /* SSL_ENABLE */
+ /*
+ * Assumption: expunges are cheap, so we want to do them
+ * after every message unless user said otherwise.
+ */
+ if (NUM_SPECIFIED(ctl->expunge))
+ expunge_period = NUM_VALUE_OUT(ctl->expunge);
+ else
+ expunge_period = 1;
+
capa_probe(sock, ctl);
/*
preauth = FALSE; /* reset for the next session */
return(PS_SUCCESS);
}
- /*
- * Time to authenticate the user.
- * Try the protocol variants that don't require passwords first.
- */
- ok = PS_AUTHFAIL;
-
-#ifdef GSSAPI
- if ((ctl->server.authenticate == A_ANY
- || ctl->server.authenticate == A_GSSAPI)
- && strstr(capabilities, "AUTH=GSSAPI"))
- if(ok = do_gssauth(sock, "AUTHENTICATE", ctl->server.truename, ctl->remotename))
- {
- /* SASL cancellation of authentication */
- gen_send(sock, "*");
- if(ctl->server.authenticate != A_ANY)
- return ok;
- }
- else
- return ok;
-#endif /* GSSAPI */
-
-#ifdef KERBEROS_V4
- if ((ctl->server.authenticate == A_ANY
- || ctl->server.authenticate == A_KERBEROS_V4
- || ctl->server.authenticate == A_KERBEROS_V5)
- && strstr(capabilities, "AUTH=KERBEROS_V4"))
- {
- if ((ok = do_rfc1731(sock, "AUTHENTICATE", ctl->server.truename)))
- {
- /* SASL cancellation of authentication */
- gen_send(sock, "*");
- if(ctl->server.authenticate != A_ANY)
- return ok;
- }
- else
- return ok;
- }
-#endif /* KERBEROS_V4 */
#ifdef SSL_ENABLE
if ((!ctl->sslproto || !strcmp(ctl->sslproto,"tls1"))
}
#endif /* SSL_ENABLE */
- peek_capable = (imap_version >= IMAP4);
-
- /*
- * Assumption: expunges are cheap, so we want to do them
- * after every message unless user said otherwise.
+ /*
+ * Time to authenticate the user.
+ * Try the protocol variants that don't require passwords first.
*/
- if (NUM_SPECIFIED(ctl->expunge))
- expunge_period = NUM_VALUE_OUT(ctl->expunge);
- else
- expunge_period = 1;
+ ok = PS_AUTHFAIL;
+
+#ifdef GSSAPI
+ if ((ctl->server.authenticate == A_ANY
+ || ctl->server.authenticate == A_GSSAPI)
+ && strstr(capabilities, "AUTH=GSSAPI"))
+ if(ok = do_gssauth(sock, "AUTHENTICATE", "imap", ctl->server.truename, ctl->remotename))
+ {
+ /* SASL cancellation of authentication */
+ gen_send(sock, "*");
+ if(ctl->server.authenticate != A_ANY)
+ return ok;
+ }
+ else
+ return ok;
+#endif /* GSSAPI */
+
+#ifdef KERBEROS_V4
+ if ((ctl->server.authenticate == A_ANY
+ || ctl->server.authenticate == A_KERBEROS_V4
+ || ctl->server.authenticate == A_KERBEROS_V5)
+ && strstr(capabilities, "AUTH=KERBEROS_V4"))
+ {
+ if ((ok = do_rfc1731(sock, "AUTHENTICATE", ctl->server.truename)))
+ {
+ /* SASL cancellation of authentication */
+ gen_send(sock, "*");
+ if(ctl->server.authenticate != A_ANY)
+ return ok;
+ }
+ else
+ return ok;
+ }
+#endif /* KERBEROS_V4 */
/*
* No such luck. OK, now try the variants that mask your password
return ok;
}
-#if OPIE_ENABLE
+#ifdef OPIE_ENABLE
if ((ctl->server.authenticate == A_ANY
|| ctl->server.authenticate == A_OTP)
&& strstr(capabilities, "AUTH=X-OTP"))
imap_canonicalize(remotename, ctl->remotename, NAMELEN);
imap_canonicalize(password, ctl->password, PASSWORDLEN);
- strcpy(shroud, password);
+#ifdef HAVE_SNPRINTF
+ snprintf(shroud, sizeof (shroud), "\"%s\"", password);
+#else
+ strcpy(shroud, "\"");
+ strcat(shroud, password);
+ strcat(shroud, "\"");
+#endif
ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", remotename, password);
shroud[0] = '\0';
#ifdef SSL_ENABLE
memset(unseen_messages, 0, count * sizeof(unsigned int));
unseen = 0;
- gen_send(sock, "SEARCH UNSEEN");
+ /* don't count deleted messages, in case user enabled keep last time */
+ gen_send(sock, "SEARCH UNSEEN NOT DELETED");
do {
ok = gen_recv(sock, buf, sizeof(buf));
if (ok != 0)
while (*cp && unseen < count)
{
/* skip whitespace */
- while (*cp && isspace(*cp))
+ while (*cp && isspace((unsigned char)*cp))
cp++;
if (*cp)
{
return(PS_SUCCESS);
}
-static int imap_getsizes(int sock, int count, int *sizes)
-/* capture the sizes of all messages */
+static int imap_getpartialsizes(int sock, int first, int last, int *sizes)
+/* capture the sizes of messages #first-#last */
{
char buf [MSGBUFSIZE+1];
* on the fact that the sizes array has been preinitialized with a
* known-bad size value.
*/
- /* if fetchall is specified, startcount is 1;
- * else if there is new mail, startcount is first unseen message;
- * else startcount is greater than count.
- */
- if (count == startcount)
- gen_send(sock, "FETCH %d RFC822.SIZE", count);
- else if (count > startcount)
- gen_send(sock, "FETCH %d:%d RFC822.SIZE", startcount, count);
+
+ /* expunges change the fetch numbers */
+ first -= expunged;
+ last -= expunged;
+
+ if (last == first)
+ gen_send(sock, "FETCH %d RFC822.SIZE", last);
+ else if (last > first)
+ gen_send(sock, "FETCH %d:%d RFC822.SIZE", first, last);
else /* no unseen messages! */
return(PS_SUCCESS);
for (;;)
break;
else if (sscanf(buf, "* %u FETCH (RFC822.SIZE %u)", &num, &size) == 2)
{
- if (num > 0 && num <= count)
- sizes[num - 1] = size;
+ if (num >= first && num <= last)
+ sizes[num - first] = size;
else
report(stderr, "Warning: ignoring bogus data for message sizes returned by the server.\n");
}
return(PS_SUCCESS);
}
+static int imap_getsizes(int sock, int count, int *sizes)
+/* capture the sizes of all messages */
+{
+ return imap_getpartialsizes(sock, 1, count, sizes);
+}
+
static int imap_is_old(int sock, struct query *ctl, int number)
/* is the given message old? */
{
static char *skip_token(char *ptr)
{
- while(isspace(*ptr)) ptr++;
- while(!isspace(*ptr) && !iscntrl(*ptr)) ptr++;
- while(isspace(*ptr)) ptr++;
+ while(isspace((unsigned char)*ptr)) ptr++;
+ while(!isspace((unsigned char)*ptr) && !iscntrl((unsigned char)*ptr)) ptr++;
+ while(isspace((unsigned char)*ptr)) ptr++;
return(ptr);
}
/*
* Try to extract a length from the FETCH response. RFC2060 requires
* it to be present, but at least one IMAP server (Novell GroupWise)
- * botches this.
+ * botches this. The overflow check is needed because of a broken
+ * server called dbmail that returns huge garbage lengths.
*/
- if ((cp = strchr(buf, '{')))
- *lenp = atoi(cp + 1);
+ if ((cp = strchr(buf, '{'))) {
+ errno = 0;
+ *lenp = (int)strtol(cp + 1, (char **)NULL, 10);
+ if (errno == ERANGE && (*lenp == LONG_MAX || *lenp == LONG_MIN))
+ *lenp = -1; /* length is too big/small for us to handle */
+ }
else
*lenp = -1; /* missing length part in FETCH reponse */
return(gen_transact(sock, "LOGOUT"));
}
-const static struct method imap =
+static const struct method imap =
{
"IMAP", /* Internet Message Access Protocol */
-#if INET6_ENABLE
+#ifdef INET6_ENABLE
"imap",
"imaps",
#else /* INET6_ENABLE */
imap_getauth, /* get authorization */
imap_getrange, /* query range of messages */
imap_getsizes, /* get sizes of messages (used for ESMTP SIZE option) */
+ imap_getpartialsizes, /* get sizes of subset of messages (used for ESMTP SIZE option) */
imap_is_old, /* no UID check */
imap_fetch_headers, /* request given message headers */
imap_fetch_body, /* request given message body */