#include <des.h>
#define krb_get_err_text(e) (krb_err_txt[e])
#endif
-#if defined (__FreeBSD__) || defined(__linux__)
+#if defined(__NetBSD__) || (__FreeBSD__) || defined(__linux__)
#define krb_get_err_text(e) (krb_err_txt[e])
#endif
#include <krb.h>
#include <gssapi/gssapi_generic.h>
#endif
+#if OPIE
+#include <opie.h>
+#endif /* OPIE */
+
#ifndef strstr /* glibc-2.1 declares this as a macro */
extern char *strstr(); /* needed on sysV68 R3V7.1. */
#endif /* strstr */
#define IMAP4rev1 1 /* IMAP4 rev 1, RFC2060 */
static int count, seen, recent, unseen, deletions,expunged, imap_version;
+static char capabilities[MSGBUFSIZE+1];
int imap_ok(int sock, char *argbuf)
/* parse command response */
{
- char buf [POPBUFSIZE+1];
+ char buf [MSGBUFSIZE+1];
seen = 0;
do {
int ok;
+ char *cp;
if ((ok = gen_recv(sock, buf, sizeof(buf))))
return(ok);
+ /* all tokens in responses are caseblind */
+ for (cp = buf; *cp; cp++)
+ if (islower(*cp))
+ *cp = toupper(*cp);
+
/* interpret untagged status responses */
+ if (strstr(buf, "* CAPABILITY"))
+ strncpy(capabilities, buf + 12, sizeof(capabilities));
if (strstr(buf, "EXISTS"))
count = atoi(buf+2);
if (strstr(buf, "RECENT"))
unseen = atoi(cp);
}
if (strstr(buf, "FLAGS"))
- seen = (strstr(buf, "Seen") != (char *)NULL);
+ seen = (strstr(buf, "SEEN") != (char *)NULL);
} while
(tag[0] != '\0' && strncmp(buf, tag, strlen(tag)));
}
}
+#if OPIE
+static int do_otp(int sock, struct query *ctl)
+{
+ int i, rval;
+ char buffer[128];
+ char challenge[OPIE_CHALLENGE_MAX+1];
+ char response[OPIE_RESPONSE_MAX+1];
+
+ gen_send(sock, "AUTHENTICATE X-OTP");
+
+ if (rval = gen_recv(sock, buffer, sizeof(buffer)))
+ return rval;
+
+ if ((i = from64tobits(challenge, buffer)) < 0) {
+ error(0, -1, "Could not decode initial BASE64 challenge");
+ return PS_AUTHFAIL;
+ };
+
+
+ to64frombits(buffer, ctl->remotename, strlen(ctl->remotename));
+
+ if (outlevel == O_VERBOSE)
+ error(0, 0, "IMAP> %s", buffer);
+ SockWrite(sock, buffer, strlen(buffer));
+ SockWrite(sock, "\r\n", 2);
+
+ if (rval = gen_recv(sock, buffer, sizeof(buffer)))
+ return rval;
+
+ if ((i = from64tobits(challenge, buffer)) < 0) {
+ error(0, -1, "Could not decode OTP challenge");
+ return PS_AUTHFAIL;
+ };
+
+ rval = opiegenerator(challenge, !strcmp(ctl->password, "opie") ? "" : ctl->password, response);
+ if ((rval == -2) && !run.poll_interval) {
+ char secret[OPIE_SECRET_MAX+1];
+ fprintf(stderr, "Secret pass phrase: ");
+ if (opiereadpass(secret, sizeof(secret), 0))
+ rval = opiegenerator(challenge, secret, response);
+ memset(secret, 0, sizeof(secret));
+ };
+
+ if (rval)
+ return PS_AUTHFAIL;
+
+ to64frombits(buffer, response, strlen(response));
+
+ if (outlevel == O_VERBOSE)
+ error(0, 0, "IMAP> %s", buffer);
+ SockWrite(sock, buffer, strlen(buffer));
+ SockWrite(sock, "\r\n", 2);
+
+ if (rval = gen_recv(sock, buffer, sizeof(buffer)))
+ return rval;
+
+ if (strstr(buffer, "OK"))
+ return PS_SUCCESS;
+ else
+ return PS_AUTHFAIL;
+};
+#endif /* OPIE */
+
#ifdef KERBEROS_V4
#if SIZEOF_INT == 4
typedef int int32;
* credentials. RFC 1731 doesn't specify what to do, and since this
* support is only for authentication, we'll assume the server
* knows enough to flush its own credentials */
+ gss_release_buffer(&min_stat, &send_token);
return PS_SUCCESS;
}
}
#endif /* GSSAPI */
+int imap_canonicalize(char *result, char *passwd)
+/* encode an IMAP password as per RFC1730's quoting conventions */
+{
+ int i, j;
+
+ j = 0;
+ for (i = 0; i < strlen(passwd); i++)
+ {
+ if ((passwd[i] == '\\') || (passwd[i] == '"'))
+ result[j++] = '\\';
+ result[j++] = passwd[i];
+ }
+ result[j] = '\0';
+
+ return(i);
+}
+
int imap_getauth(int sock, struct query *ctl, char *greeting)
/* apply for connection authorization */
{
- char capabilities[POPBUFSIZE+1];
int ok = 0;
+ char password[PASSWORDLEN*2];
/* probe to see if we're running IMAP4 and can use RFC822.PEEK */
- gen_send(sock, "CAPABILITY");
- if ((ok = gen_recv(sock, capabilities, sizeof(capabilities))))
- return(ok);
- if (strstr(capabilities, "BAD"))
+ capabilities[0] = '\0';
+ if ((ok = gen_transact(sock, "CAPABILITY")) == PS_SUCCESS)
{
- imap_version = IMAP2;
- if (outlevel == O_VERBOSE)
- error(0, 0, "Protocol identified as IMAP2 or IMAP2BIS");
+ /* UW-IMAP server 10.173 notifies in all caps */
+ if (strstr(capabilities, "IMAP4REV1"))
+ {
+ imap_version = IMAP4rev1;
+ if (outlevel == O_VERBOSE)
+ error(0, 0, "Protocol identified as IMAP4 rev 1");
+ }
+ else
+ {
+ imap_version = IMAP4;
+ if (outlevel == O_VERBOSE)
+ error(0, 0, "Protocol identified as IMAP4 rev 0");
+ }
}
- /* UW-IMAP server 10.173 notifies in all caps */
- else if (strstr(capabilities, "IMAP4rev1") || strstr(capabilities, "IMAP4REV1"))
+ else if (ok == PS_ERROR)
{
- imap_version = IMAP4rev1;
+ imap_version = IMAP2;
if (outlevel == O_VERBOSE)
- error(0, 0, "Protocol identified as IMAP4 rev 1");
+ error(0, 0, "Protocol identified as IMAP2 or IMAP2BIS");
}
else
- {
- imap_version = IMAP4;
- if (outlevel == O_VERBOSE)
- error(0, 0, "Protocol identified as IMAP4 rev 0");
- }
+ return(ok);
- /* eat the tail of the CAPABILITY response (if any) */
- if ((peek_capable = (imap_version >= IMAP4)))
- {
- char scratchbuf[POPBUFSIZE]; /* don't clobber capabilities buffer */
+ peek_capable = (imap_version >= IMAP4);
- if ((ok = gen_recv(sock, scratchbuf, sizeof(scratchbuf))))
- return(ok);
- }
+#if OPIE
+ if ((ctl->server.protocol == P_IMAP) && strstr(capabilities, "AUTH=X-OTP"))
+ {
+ if (outlevel == O_VERBOSE)
+ error(0, 0, "OTP authentication is supported");
+ if (do_otp(sock, ctl) == PS_SUCCESS)
+ return(PS_SUCCESS);
+ };
+#endif /* OPIE */
#ifdef GSSAPI
if (strstr(capabilities, "AUTH=GSSAPI"))
}
#endif /* KERBEROS_V4 */
- /* try to get authorized in the ordinary (AUTH=LOGIN) way */
- ok = gen_transact(sock, "LOGIN %s \"%s\"", ctl->remotename, ctl->password);
+#ifdef __UNUSED__ /* The Cyrus IMAP4rev1 server chokes on this */
+ /* this handles either AUTH=LOGIN or AUTH-LOGIN */
+ if ((imap_version >= IMAP4rev1) && (!strstr(capabilities, "LOGIN"))) {
+ error(0,-1, "Required LOGIN capability not supported by server");
+ return PS_AUTHFAIL;
+ };
+#endif /* __UNUSED__ */
+
+ imap_canonicalize(password, ctl->password);
+ ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", ctl->remotename, password);
if (ok)
return(ok);
+
+ return(PS_SUCCESS);
+}
+
+static int internal_expunge(int sock)
+/* ship an expunge, resetting associated counters */
+{
+ int ok;
+
+ if ((ok = gen_transact(sock, "EXPUNGE")))
+ return(ok);
+
+ expunged += deletions;
+ deletions = 0;
+
+#ifdef IMAP_UID /* not used */
+ expunge_uids(ctl);
+#endif /* IMAP_UID */
return(PS_SUCCESS);
}
static int imap_getrange(int sock,
struct query *ctl,
const char *folder,
- int *countp, int *newp)
+ int *countp, int *newp, int *bytes)
/* get range of messages to be fetched */
{
int ok;
/* find out how many messages are waiting */
- recent = unseen = -1;
+ *bytes = recent = unseen = -1;
if (pass > 1)
{
*/
ok = 0;
if (deletions && ctl->expunge > 1)
- ok = gen_transact(sock, "EXPUNGE");
-#ifdef IMAP_UID /* not used */
- if (!ok)
- expunge_uids(ctl);
-#endif /* IMAP_UID */
+ internal_expunge(sock);
count = -1;
if (ok || gen_transact(sock, "NOOP"))
{
static int imap_getsizes(int sock, int count, int *sizes)
/* capture the sizes of all messages */
{
- char buf [POPBUFSIZE+1];
+ char buf [MSGBUFSIZE+1];
/*
* Some servers (as in, PMDF5.1-9.1 under OpenVMS 6.1)
static int imap_fetch_headers(int sock, struct query *ctl,int number,int *lenp)
/* request headers of nth message */
{
- char buf [POPBUFSIZE+1];
+ char buf [MSGBUFSIZE+1];
int num;
/* expunges change the fetch numbers */
static int imap_fetch_body(int sock, struct query *ctl, int number, int *lenp)
/* request body of nth message */
{
- char buf [POPBUFSIZE+1], *cp;
+ char buf [MSGBUFSIZE+1], *cp;
int num;
/* expunges change the fetch numbers */
for (;;)
{
- char buf[POPBUFSIZE+1];
+ char buf[MSGBUFSIZE+1];
int ok;
if ((ok = gen_recv(sock, buf, sizeof(buf))))
* the next session.
*/
if (NUM_NONZERO(ctl->expunge) && (deletions % ctl->expunge) == 0)
- {
- if ((ok = gen_transact(sock, "EXPUNGE")))
- return(ok);
-
-#ifdef IMAP_UID /* not used */
- expunge_uids(ctl);
-#endif /* IMAP_UID */
-
- expunged = deletions;
- deletions = 0;
- }
+ internal_expunge(sock);
return(PS_SUCCESS);
}
{
/* if expunges after deletion have been suppressed, ship one now */
if (NUM_SPECIFIED(ctl->expunge) && NUM_ZERO(ctl->expunge) && deletions)
- {
- int ok;
-
- if ((ok = gen_transact(sock, "EXPUNGE")))
- return(ok);
-
- expunged = deletions;
- deletions = 0;
-
-#ifdef IMAP_UID /* not used */
- expunge_uids(ctl);
-#endif /* IMAP_UID */
- }
+ internal_expunge(sock);
return(gen_transact(sock, "LOGOUT"));
}
const static struct method imap =
{
"IMAP", /* Internet Message Access Protocol */
- 143, /* standard IMAP2bis/IMAP4 port */
+#if INET6
+ "imap",
+#else /* INET6 */
+ 143, /* standard IMAP2bis/IMAP4 port */
+#endif /* INET6 */
TRUE, /* this is a tagged protocol */
FALSE, /* no message delimiter */
imap_ok, /* parse command response */
+ imap_canonicalize, /* deal with embedded slashes and spaces */
imap_getauth, /* get authorization */
imap_getrange, /* query range of messages */
imap_getsizes, /* get sizes of messages (used for --limit option */