/*
- * imap.c -- IMAP2bis protocol methods
+ * imap.c -- IMAP2bis/IMAP4 protocol methods
*
* Copyright 1996 by Eric S. Raymond
* All rights reserved.
#include <stdlib.h>
#endif
#include "fetchmail.h"
+#include "socket.h"
-static int count, seen, recent, unseen;
+static int count, seen, recent, unseen, imap4;
-int imap_ok (sockfp, argbuf)
+int imap_ok (FILE *sockfp, char *argbuf)
/* parse command response */
-char *argbuf;
-FILE *sockfp;
{
char buf [POPBUFSIZE+1];
seen = 0;
do {
- if (fgets(buf, sizeof(buf), sockfp) == (char *)NULL)
+ if (!SockGets(buf, sizeof(buf), sockfp))
return(PS_SOCKET);
+ if (buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = '\0';
+ if (buf[strlen(buf)-1] == '\r')
+ buf[strlen(buf)-1] = '\r';
if (outlevel == O_VERBOSE)
- fprintf(stderr,"%s",buf);
+ error(0, 0, "IMAP< %s", buf);
/* interpret untagged status responses */
if (strstr(buf, "EXISTS"))
}
}
-int imap_getauth(sockfp, ctl, buf)
+int imap_getauth(FILE *sockfp, struct query *ctl, char *buf)
/* apply for connection authorization */
-FILE *sockfp;
-struct query *ctl;
-char *buf;
{
/* try to get authorized */
- return(gen_transact(sockfp,
+ int ok = gen_transact(sockfp,
"LOGIN %s \"%s\"",
- ctl->remotename, ctl->password));
+ ctl->remotename, ctl->password);
+
+ if (ok)
+ return(ok);
+
+ /* probe to see if we're running IMAP4 and can use RFC822.PEEK */
+ imap4 = ((gen_transact(sockfp, "CAPABILITY")) == 0);
+
+ return(0);
}
-static int imap_getrange(sockfp, ctl, countp, newp)
+static int imap_getrange(FILE *sockfp, struct query *ctl, int*countp, int*newp)
/* get range of messages to be fetched */
-FILE *sockfp;
-struct query *ctl;
-int *countp, *newp;
{
int ok;
return(0);
}
-static int imap_getsizes(sockfp, count, sizes)
+static int imap_getsizes(FILE *sockfp, int count, int *sizes)
/* capture the sizes of all messages */
-FILE *sockfp;
-int count;
-int *sizes;
{
char buf [POPBUFSIZE+1];
gen_send(sockfp, "FETCH 1:%d RFC822.SIZE", count);
- while (fgets(buf, sizeof(buf), sockfp) != (char *)NULL)
+ while (SockGets(buf, sizeof(buf), sockfp))
{
int num, size;
+ if (buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = '\0';
+ if (buf[strlen(buf)-1] == '\r')
+ buf[strlen(buf)-1] = '\r';
if (outlevel == O_VERBOSE)
- fprintf(stderr,"%s\n",buf);
+ error(0, 0, "IMAP< %s", buf);
if (strstr(buf, "OK"))
break;
else if (sscanf(buf, "* %d FETCH (RFC822.SIZE %d)", &num, &size) == 2)
else
sizes[num - 1] = -1;
}
- fseek(sockfp, 0L, SEEK_CUR);
return(0);
}
-static int imap_is_old(sockfp, ctl, num)
+static int imap_is_old(FILE *sockfp, struct query *ctl, int num)
/* is the given message old? */
-FILE *sockfp;
-struct query *ctl;
-int num;
{
int ok;
if ((ok = gen_transact(sockfp, "FETCH %d FLAGS", num)) != 0)
- exit(PS_ERROR);
+ return(PS_ERROR);
return(seen);
}
-static int imap_fetch(sockfp, number, lenp)
+static int imap_fetch(FILE *sockfp, int number, int *lenp)
/* request nth message */
-FILE *sockfp;
-int number;
-int *lenp;
{
char buf [POPBUFSIZE+1];
int num;
- gen_send(sockfp, "FETCH %d RFC822", number);
+ /*
+ * If we're using IMAP4, we can fetch the message without setting its
+ * seen flag. This is good! It means that if the protocol exchange
+ * craps out during the message, it will still be marked `unseen' on
+ * the server.
+ */
+ if (imap4)
+ gen_send(sockfp, "FETCH %d RFC822.PEEK", number);
+ else
+ gen_send(sockfp, "FETCH %d RFC822", number);
/* looking for FETCH response */
do {
- if (fgets(buf, sizeof(buf), sockfp) == (char *)NULL)
+ if (!SockGets(buf, sizeof(buf), sockfp))
return(PS_SOCKET);
} while
(sscanf(buf+2, "%d FETCH (RFC822 {%d}", &num, lenp) != 2);
- fseek(sockfp, 0L, SEEK_CUR);
if (num != number)
return(PS_ERROR);
return(0);
}
-static int imap_trail(sockfp, ctl, number)
+static int imap_trail(FILE *sockfp, struct query *ctl, int number)
/* discard tail of FETCH response after reading message text */
-FILE *sockfp;
-struct query *ctl;
-int number;
{
char buf [POPBUFSIZE+1];
- if (fgets(buf, sizeof(buf), sockfp) == (char *)NULL)
+ if (!SockGets(buf, sizeof(buf), sockfp))
return(PS_SOCKET);
else
- {
- fseek(sockfp, 0L, SEEK_CUR);
return(0);
- }
}
-static int imap_delete(sockfp, ctl, number)
+static int imap_delete(FILE *sockfp, struct query *ctl, int number)
/* set delete flag for given message */
-FILE *sockfp;
-struct query *ctl;
-int number;
{
- return(gen_transact(sockfp, "STORE %d +FLAGS (\\Deleted)", number));
+ /* use SILENT if possible as a minor throughput optimization */
+ return(gen_transact(sockfp,
+ imap4
+ ? "STORE %d +FLAGS.SILENT (\\Deleted)"
+ : "STORE %d +FLAGS (\\Deleted)",
+ number));
}
const static struct method imap =
"LOGOUT", /* the IMAP exit command */
};
-int doIMAP(ctl)
+int doIMAP(struct query *ctl)
/* retrieve messages using IMAP Version 2bis or Version 4 */
-struct query *ctl;
{
return(do_protocol(ctl, &imap));
}