]> Pileus Git - ~andy/fetchmail/blobdiff - imap.c
Drop back to using SockGets/SockWrite.
[~andy/fetchmail] / imap.c
diff --git a/imap.c b/imap.c
index c1dac5c8190ee6adad9620f14af2fd072ed82bcf..f9fdbbaa9f5f2463663efa9416367ae4be748cf3 100644 (file)
--- a/imap.c
+++ b/imap.c
@@ -1,5 +1,5 @@
 /*
- * imap.c -- IMAP2bis protocol methods
+ * imap.c -- IMAP2bis/IMAP4 protocol methods
  *
  * Copyright 1996 by Eric S. Raymond
  * All rights reserved.
@@ -9,28 +9,31 @@
 #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"))
@@ -71,31 +74,33 @@ int socket;
     }
 }
 
-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);
 
@@ -111,66 +116,64 @@ int *countp, *newp;
     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);
@@ -181,27 +184,26 @@ int *lenp;
        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 =
@@ -222,11 +224,10 @@ 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 */