]> 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 0e75524de941a114b6b9730e1beb2efb7e1dadad..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.
 #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"))
@@ -71,23 +74,25 @@ FILE *sockfp;
     }
 }
 
-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;
 
@@ -111,21 +116,22 @@ int *countp, *newp;
     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)
@@ -133,43 +139,44 @@ int       *sizes;
        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);
@@ -177,30 +184,26 @@ int *lenp;
        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 =
@@ -221,9 +224,8 @@ 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));
 }