/*
- * imap.c -- IMAP2bis protocol methods
+ * imap.c -- IMAP2bis/IMAP4 protocol methods
*
* Copyright 1996 by Eric S. Raymond
* All rights reserved.
#include <config.h>
#include <stdio.h>
#include <string.h>
-#include "socket.h"
+#include <ctype.h>
+#if defined(STDC_HEADERS)
+#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 (socket, argbuf)
+int imap_ok (FILE *sockfp, char *argbuf)
/* parse command response */
-char *argbuf;
-int socket;
{
- int ok;
char buf [POPBUFSIZE+1];
- char *bufp;
- int n;
seen = 0;
do {
- if (SockGets(socket, buf, sizeof(buf)) < 0)
+ 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\n",buf);
+ error(0, 0, "IMAP< %s", buf);
/* interpret untagged status responses */
if (strstr(buf, "EXISTS"))
}
}
-int imap_getauth(socket, queryctl, buf)
+int imap_getauth(FILE *sockfp, struct query *ctl, char *buf)
/* apply for connection authorization */
-int socket;
-struct hostrec *queryctl;
-char *buf;
{
/* try to get authorized */
- return(gen_transact(socket,
+ int ok = gen_transact(sockfp,
"LOGIN %s \"%s\"",
- queryctl->remotename, queryctl->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 imap_getrange(socket, queryctl, countp, newp)
+static int imap_getrange(FILE *sockfp, struct query *ctl, int*countp, int*newp)
/* get range of messages to be fetched */
-int socket;
-struct hostrec *queryctl;
-int *countp, *newp;
{
int ok;
/* find out how many messages are waiting */
recent = unseen = 0;
- ok = gen_transact(socket,
+ ok = gen_transact(sockfp,
"SELECT %s",
- queryctl->mailbox[0] ? queryctl->mailbox : "INBOX");
+ ctl->mailbox[0] ? ctl->mailbox : "INBOX");
if (ok != 0)
return(ok);
return(0);
}
-static int *imap_getsizes(socket, count)
+static int imap_getsizes(FILE *sockfp, int count, int *sizes)
/* capture the sizes of all messages */
-int socket;
-int count;
{
- int ok, *sizes;
+ char buf [POPBUFSIZE+1];
- if ((sizes = (int *)malloc(sizeof(int) * count)) == (int *)NULL)
- return((int *)NULL);
- else
+ gen_send(sockfp, "FETCH 1:%d RFC822.SIZE", count);
+ while (SockGets(buf, sizeof(buf), sockfp))
{
- char buf [POPBUFSIZE+1];
+ int num, size;
- gen_send(socket, "FETCH 1:%d RFC822.SIZE", count);
- while (SockGets(socket, buf, sizeof(buf)) >= 0)
- {
- int num, size;
-
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"%s\n",buf);
- if (strstr(buf, "OK"))
- break;
- else if (sscanf(buf, "* %d FETCH (RFC822.SIZE %d)", &num, &size) == 2)
- sizes[num - 1] = size;
- else
- sizes[num - 1] = -1;
- }
-
- return(sizes);
+ 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)
+ error(0, 0, "IMAP< %s", buf);
+ if (strstr(buf, "OK"))
+ break;
+ else if (sscanf(buf, "* %d FETCH (RFC822.SIZE %d)", &num, &size) == 2)
+ sizes[num - 1] = size;
+ else
+ sizes[num - 1] = -1;
}
+
+ return(0);
}
-static imap_is_old(socket, queryctl, num)
-int socket;
-struct hostrec *queryctl;
-int num;
+static int imap_is_old(FILE *sockfp, struct query *ctl, int num)
+/* is the given message old? */
{
- char buf [POPBUFSIZE+1];
int ok;
- if ((ok = gen_transact(socket, "FETCH %d FLAGS", num)) != 0)
- exit(PS_ERROR);
+ if ((ok = gen_transact(sockfp, "FETCH %d FLAGS", num)) != 0)
+ return(PS_ERROR);
return(seen);
}
-static int imap_fetch(socket, number, lenp)
+static int imap_fetch(FILE *sockfp, int number, int *lenp)
/* request nth message */
-int socket;
-int number;
-int *lenp;
{
char buf [POPBUFSIZE+1];
int num;
- gen_send(socket, "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 (SockGets(socket, buf,sizeof(buf)) < 0)
+ if (!SockGets(buf, sizeof(buf), sockfp))
return(PS_SOCKET);
} while
(sscanf(buf+2, "%d FETCH (RFC822 {%d}", &num, lenp) != 2);
return(0);
}
-static imap_trail(socket, queryctl, number)
-/* discard tail of FETCH response */
-int socket;
-struct hostrec *queryctl;
-int number;
+static int imap_trail(FILE *sockfp, struct query *ctl, int number)
+/* discard tail of FETCH response after reading message text */
{
char buf [POPBUFSIZE+1];
- if (SockGets(socket, buf,sizeof(buf)) < 0)
+ if (!SockGets(buf, sizeof(buf), sockfp))
return(PS_SOCKET);
else
return(0);
}
-static imap_delete(socket, queryctl, number)
+static int imap_delete(FILE *sockfp, struct query *ctl, int number)
/* set delete flag for given message */
-int socket;
-struct hostrec *queryctl;
-int number;
{
- return(gen_transact(socket, "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 (queryctl)
+int doIMAP(struct query *ctl)
/* retrieve messages using IMAP Version 2bis or Version 4 */
-struct hostrec *queryctl;
{
- return(do_protocol(queryctl, &imap));
+ return(do_protocol(ctl, &imap));
}
/* imap.c ends here */