]> granicus.if.org Git - mutt/commitdiff
Unified IMAP command code.
authorThomas Roessler <roessler@does-not-exist.org>
Sat, 5 Aug 2000 17:50:01 +0000 (17:50 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Sat, 5 Aug 2000 17:50:01 +0000 (17:50 +0000)
12 files changed:
imap/Makefile.am
imap/auth_anon.c
imap/auth_cram.c
imap/auth_gss.c
imap/auth_login.c
imap/auth_sasl.c
imap/browse.c
imap/command.c
imap/imap.c
imap/imap_private.h
imap/message.c
mutt_socket.c

index 9f5a6fa70d37368dc96037dac43d3462a31c3598..c049fae0bfc5a49ba08f23fa7bd77930d3e6b093 100644 (file)
@@ -9,7 +9,7 @@ endif
 if USE_SASL
 SASLSOURCES = auth_sasl.c
 else
-CRAMSOURCES = auth_cram.c
+CRAMSOURCES = auth_cram.c md5c.c
 endif
 
 if USE_SSL
@@ -25,5 +25,5 @@ noinst_LIBRARIES = libimap.a
 noinst_HEADERS = auth.h imap_private.h md5.h message.h $(SSLHEADERS)
 
 libimap_a_SOURCES = auth.c auth_anon.c auth_login.c browse.c \
-       command.c imap.c imap.h md5c.c message.c utf7.c \
+       command.c imap.c imap.h message.c utf7.c \
        util.c $(GSSSOURCES) $(SASLSOURCES) $(CRAMSOURCES) $(SSLSOURCES)
index 09ec71dbf24c8aa751b8b59c013fae2188859ce9..a7fd87ff6e96d70f0a906799e1e74fb4e6dc8f09 100644 (file)
@@ -25,7 +25,7 @@
 /* this is basically a stripped-down version of the cram-md5 method. */
 imap_auth_res_t imap_auth_anon (IMAP_DATA* idata)
 {
-  char buf[LONG_STRING];
+  int rc;
 
   if (!mutt_bit_isset (idata->capabilities, AUTH_ANON))
     return IMAP_AUTH_UNAVAIL;
@@ -40,29 +40,29 @@ imap_auth_res_t imap_auth_anon (IMAP_DATA* idata)
 
   imap_cmd_start (idata, "AUTHENTICATE ANONYMOUS");
 
-  if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
-  {
-    dprint (1, (debugfile, "Error receiving server response.\n"));
-    goto bail;
-  }
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
 
-  if (buf[0] != '+')
+  if (rc != IMAP_CMD_RESPOND)
   {
     dprint (1, (debugfile, "Invalid response from server.\n"));
     goto bail;
   }
 
-  strfcpy (buf, "ZHVtbXkK\r\n", sizeof (buf));         /* base64 ("dummy") */
-
-  mutt_socket_write (idata->conn, buf);
+  mutt_socket_write (idata->conn, "ZHVtbXkK\r\n"); /* base64 ("dummy") */
 
-  if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
+  
+  if (rc != IMAP_CMD_DONE)
   {
     dprint (1, (debugfile, "Error receiving server response.\n"));
     goto bail;
   }
 
-  if (imap_code (buf))
+  if (imap_code (idata->buf))
     return IMAP_AUTH_SUCCESS;
 
  bail:
index 9736ee36f1f83a01287f929b64d9b2f98ecf3d09..00e0f0d9ecbd5639a05ebb62136963a06cc50daf 100644 (file)
@@ -36,6 +36,7 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata)
   char ibuf[LONG_STRING], obuf[LONG_STRING];
   unsigned char hmac_response[MD5_DIGEST_LEN];
   int len;
+  int rc;
 
   if (!mutt_bit_isset (idata->capabilities, ACRAM_MD5))
     return IMAP_AUTH_UNAVAIL;
@@ -56,19 +57,17 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata)
    * primary host name of the server. The syntax of the unencoded form must
    * correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3].
    */
-  if (mutt_socket_readln (ibuf, sizeof (ibuf), idata->conn) < 0)
-  {
-    dprint (1, (debugfile, "Error receiving server response.\n"));
-    goto bail;
-  }
-
-  if (ibuf[0] != '+')
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
+  
+  if (rc != IMAP_CMD_RESPOND)
   {
     dprint (1, (debugfile, "Invalid response from server: %s\n", ibuf));
     goto bail;
   }
 
-  if ((len = mutt_from_base64 (obuf, ibuf + 2)) == -1)
+  if ((len = mutt_from_base64 (obuf, idata->buf + 2)) == -1)
   {
     dprint (1, (debugfile, "Error decoding base64 response.\n"));
     goto bail;
@@ -103,13 +102,17 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata)
   strcpy (ibuf + strlen (ibuf), "\r\n");
   mutt_socket_write (idata->conn, ibuf);
 
-  if (mutt_socket_readln (ibuf, LONG_STRING, idata->conn) < 0)
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
+
+  if (rc != IMAP_CMD_DONE)
   {
     dprint (1, (debugfile, "Error receiving server response.\n"));
     goto bail;
   }
 
-  if (imap_code (ibuf))
+  if (imap_code (idata->buf))
     return IMAP_AUTH_SUCCESS;
 
  bail:
index 96f79b56363d3cc141dd18a3d0be30a909d0d950..bf59c019b17e8d88ef0cd47c6bd5f25e2a6e9455 100644 (file)
@@ -54,6 +54,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
   OM_uint32 maj_stat, min_stat;
   char buf1[GSS_BUFSIZE], buf2[GSS_BUFSIZE], server_conf_flags;
   unsigned long buf_size;
+  int rc;
 
   if (!mutt_bit_isset (idata->capabilities, AGSSAPI))
     return IMAP_AUTH_UNAVAIL;
@@ -88,14 +89,11 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
   imap_cmd_start (idata, "AUTHENTICATE GSSAPI");
 
   /* expect a null continuation response ("+") */
-  if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
-  {
-    dprint (1, (debugfile, "Error receiving server response.\n"));
-    gss_release_name (&min_stat, &target_name);
-    goto bail;
-  }
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
 
-  if (buf1[0] != '+')
+  if (rc != IMAP_CMD_RESPOND)
   {
     dprint (2, (debugfile, "Invalid response from server: %s\n", buf1));
     gss_release_name (&min_stat, &target_name);
@@ -128,7 +126,9 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
       gss_release_name (&min_stat, &target_name);
       /* end authentication attempt */
       mutt_socket_write (idata->conn, "*\r\n");
-      mutt_socket_readln (buf1, sizeof (buf1), idata->conn);
+      do
+       rc = imap_cmd_resp (idata);
+      while (rc == IMAP_CMD_CONTINUE);
       goto bail;
     }
 
@@ -141,14 +141,18 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
 
     if (maj_stat == GSS_S_CONTINUE_NEEDED)
     {
-      if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
+      do
+       rc = imap_cmd_resp (idata);
+      while (rc == IMAP_CMD_CONTINUE);
+
+      if (rc != IMAP_CMD_RESPOND)
       {
         dprint (1, (debugfile, "Error receiving server response.\n"));
         gss_release_name (&min_stat, &target_name);
        goto bail;
       }
 
-      request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+      request_buf.length = mutt_from_base64 (buf2, idata->buf + 2);
       request_buf.value = buf2;
       sec_token = &request_buf;
     }
@@ -158,12 +162,16 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
   gss_release_name (&min_stat, &target_name);
 
   /* get security flags and buffer size */
-  if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
+
+  if (rc != IMAP_CMD_RESPOND)
   {
     dprint (1, (debugfile, "Error receiving server response.\n"));
     goto bail;
   }
-  request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
+  request_buf.length = mutt_from_base64 (buf2, idata->buf + 2);
   request_buf.value = buf2;
 
   maj_stat = gss_unwrap (&min_stat, context, &request_buf, &send_token,
@@ -221,13 +229,16 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
   mutt_socket_write (idata->conn, buf1);
 
   /* Joy of victory or agony of defeat? */
-  if (mutt_socket_readln (buf1, GSS_BUFSIZE, idata->conn) < 0)
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
+  if (rc != IMAP_CMD_DONE)
   {
     dprint (1, (debugfile, "Error receiving server response.\n"));
     mutt_socket_write(idata->conn, "*\r\n");
     goto bail;
   }
-  if (imap_code (buf1))
+  if (imap_code (idata->buf))
   {
     /* flush the security context */
     dprint (2, (debugfile, "Releasing GSS credentials\n"));
index 757c35380a2d0778abca3274dcb819734724ad91..731f14f3c5a5d6f0c4a9064e1c39a3d236ef7c06 100644 (file)
@@ -26,7 +26,7 @@
 imap_auth_res_t imap_auth_login (IMAP_DATA* idata)
 {
   char q_user[SHORT_STRING], q_pass[SHORT_STRING];
-  char buf[LONG_STRING];
+  char buf[STRING];
   int rc;
 
   if (mutt_account_getuser (&idata->conn->account))
@@ -49,8 +49,7 @@ imap_auth_res_t imap_auth_login (IMAP_DATA* idata)
 #endif
 
   snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass);
-  rc = imap_exec (buf, sizeof (buf), idata, buf,
-    IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
+  rc = imap_exec (idata, buf, IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
   
   if (!rc)
     return IMAP_AUTH_SUCCESS;
index 946500ec82fa2d8d76e577e89dc07a6d7c92fcd3..5e01331b97f39b434a6990c8e818382f9f6ae23f 100644 (file)
@@ -31,7 +31,7 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
 {
   sasl_conn_t* saslconn;
   sasl_interact_t* interaction = NULL;
-  int rc;
+  int rc, irc;
   char buf[LONG_STRING];
   const char* mech;
   char* pc;
@@ -92,27 +92,27 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
 
   snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech);
   imap_cmd_start (idata, buf);
+  irc = IMAP_CMD_CONTINUE;
 
   /* looping protocol */
   while (rc == SASL_CONTINUE)
   {
-    if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+    do
+      irc = imap_cmd_resp (idata);
+    while (irc == IMAP_CMD_CONTINUE);
+
+    if (irc == IMAP_CMD_FAIL)
       goto bail;
 
-    if (!mutt_strncmp (buf, "+ ", 2))
+    if (irc == IMAP_CMD_RESPOND)
     {
-      if (sasl_decode64 (buf+2, strlen (buf+2), buf, &len) != SASL_OK)
+      if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, &len) !=
+         SASL_OK)
       {
        dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n"));
        goto bail;
       }
     }
-    else if ((buf[0] == '*'))
-    {
-      if (imap_handle_untagged (idata, buf))
-       goto bail;
-      else continue;
-    }
 
     if (!client_start)
       do
@@ -146,14 +146,14 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
     }
   }
 
-  while (mutt_strncmp (buf, idata->seq, SEQLEN))
-    if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
-      goto bail;
+  while (irc != IMAP_CMD_DONE)
+    if ((irc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+      break;
 
   if (rc != SASL_OK)
     goto bail;
 
-  if (imap_code (buf))
+  if (imap_code (idata->buf))
   {
     mutt_sasl_setup_conn (idata->conn, saslconn);
     return IMAP_AUTH_SUCCESS;
index c63487ee1a2522773bd4fa0fe70e546f188933f0..1571a705366589fc961c8dcc453df161e2e86a5d 100644 (file)
@@ -36,10 +36,11 @@ static int browse_get_namespace (IMAP_DATA *idata, char *nsbuf, int nsblen,
 static int browse_verify_namespace (IMAP_DATA* idata,
   IMAP_NAMESPACE_INFO* nsi, int nns);
 
+/* imap_browse: IMAP hook into the folder browser, fills out browser_state,
+ *   given a current folder to browse */
 int imap_browse (char* path, struct browser_state* state)
 {
-  CONNECTION *conn;
-  IMAP_DATA *idata;
+  IMAP_DATA* idata;
   char buf[LONG_STRING];
   char nsbuf[LONG_STRING];
   char mbox[LONG_STRING];
@@ -67,7 +68,6 @@ int imap_browse (char* path, struct browser_state* state)
 
   if (!(idata = imap_conn_find (&(mx.account), 0)))
     return -1;
-  conn = idata->conn;
 
   if (mx.mbox[0] == '\0')
   {
@@ -84,24 +84,6 @@ int imap_browse (char* path, struct browser_state* state)
       if (browse_verify_namespace (idata, nsi, nns) != 0)
        return -1;
     }
-    /* What if you have a shared namespace of ""? You'll never be
-     * able to browse it. This isn't conjecture: connect to the Cyrus
-     * reference server (cyrus.andrew.cmu.edu) as anonymous. argh! */
-#if 0
-    if (!mx.mbox)   /* Any explicitly set imap_home_namespace wins */
-    { 
-      for (i = 0; i < nns; i++)
-       if (nsi[i].listable &&
-           (nsi[i].type == IMAP_NS_PERSONAL || nsi[i].type == IMAP_NS_SHARED))
-       {
-         mx.mbox = nsi->prefix;
-         nsi->home_namespace = 1;
-         break;
-       }
-    }
-    else
-      dprint (4, (debugfile, "Home namespace: %s\n", mx.mbox));
-#endif
   }
 
   mutt_message _("Getting folder list...");
@@ -116,7 +98,7 @@ int imap_browse (char* path, struct browser_state* state)
     strncpy (mbox, buf, sizeof (mbox) - 1);
     n = mutt_strlen (mbox);
 
-    dprint (3, (debugfile, "imap_init_browse: mbox: %s\n", mbox));
+    dprint (3, (debugfile, "imap_browse: mbox: %s\n", mbox));
 
     /* if our target exists and has inferiors, enter it if we
      * aren't already going to */
@@ -126,8 +108,8 @@ int imap_browse (char* path, struct browser_state* state)
       imap_cmd_start (idata, buf);
       do 
       {
-        if (imap_parse_list_response(idata, buf, sizeof(buf), &cur_folder,
-           &noselect, &noinferiors, &(idata->delim)) != 0)
+        if (imap_parse_list_response (idata, &cur_folder, &noselect,
+            &noinferiors, &idata->delim) != 0)
           return -1;
 
         if (cur_folder)
@@ -142,7 +124,7 @@ int imap_browse (char* path, struct browser_state* state)
           }
         }
       }
-      while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+      while (mutt_strncmp (idata->buf, idata->seq, SEQLEN));
     }
 
     /* if we're descending a folder, mark it as current in browser_state */
@@ -247,7 +229,6 @@ int imap_browse (char* path, struct browser_state* state)
 static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
   struct browser_state* state, short isparent)
 {
-  char buf[LONG_STRING];
   char *name;
   int noselect;
   int noinferiors;
@@ -264,8 +245,8 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
 
   do 
   {
-    if (imap_parse_list_response(idata, buf, sizeof(buf), &name,
-        &noselect, &noinferiors, &(idata->delim)) != 0)
+    if (imap_parse_list_response(idata, &name, &noselect, &noinferiors,
+        &idata->delim) != 0)
       return -1;
 
     if (name)
@@ -279,7 +260,7 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
           isparent);
     }
   }
-  while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+  while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
 
   return 0;
 }
@@ -351,13 +332,13 @@ static int compare_names(struct folder_file *a, struct folder_file *b)
 static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
   IMAP_NAMESPACE_INFO* nsi, int nsilen, int* nns)
 {
-  char buf[LONG_STRING];
   char *s;
   int n;
   char ns[LONG_STRING];
   char delim = '/';
   int type;
   int nsbused = 0;
+  int rc;
 
   *nns = 0;
   nsbuf[nsblen-1] = '\0';
@@ -366,89 +347,84 @@ static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
   
   do 
   {
-    if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
-      return -1;
+    if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+      break;
 
-    if (buf[0] == '*') 
+    s = imap_next_word (idata->buf);
+    if (mutt_strncasecmp ("NAMESPACE", s, 9) == 0)
     {
-      s = imap_next_word (buf);
-      if (mutt_strncasecmp ("NAMESPACE", s, 9) == 0)
+      /* There are three sections to the response, User, Other, Shared,
+       * and maybe more by extension */
+      for (type = IMAP_NS_PERSONAL; *s; type++)
       {
-       /* There are three sections to the response, User, Other, Shared,
-        * and maybe more by extension */
-       for (type = IMAP_NS_PERSONAL; *s; type++)
+       s = imap_next_word (s);
+       if (*s && strncmp (s, "NIL", 3))
        {
-         s = imap_next_word (s);
-         if (*s && strncmp (s, "NIL", 3))
+         s++;
+         while (*s && *s != ')')
          {
-           s++;
-           while (*s && *s != ')')
-           {
-             s++; /* skip ( */
-             /* copy namespace */
-             n = 0;
-             delim = '\0';
+           s++; /* skip ( */
+           /* copy namespace */
+           n = 0;
+           delim = '\0';
 
-             if (*s == '\"')
+           if (*s == '\"')
+           {
+             s++;
+             while (*s && *s != '\"') 
              {
-               s++;
-               while (*s && *s != '\"') 
-               {
-                 if (*s == '\\')
-                   s++;
-                 ns[n++] = *s;
+               if (*s == '\\')
                  s++;
-               }
+               ns[n++] = *s;
+               s++;
              }
-             else
-               while (*s && !ISSPACE (*s)) 
-               {
-                 ns[n++] = *s;
-                 s++;
-               }
-             ns[n] = '\0';
-             /* delim? */
-             s = imap_next_word (s);
-             /* delimiter is meaningless if namespace is "". Why does
-              * Cyrus provide one?! */
-             if (n && *s && *s == '\"')
-              {
-               if (s[1] && s[2] == '\"')
-                 delim = s[1];
-               else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
-                 delim = s[2];
-              }
-             /* skip "" namespaces, they are already listed at the root */
-             if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen))
+           }
+           else
+             while (*s && !ISSPACE (*s)) 
              {
-               dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns));
-               nsi->type = type;
-               /* Cyrus doesn't append the delimiter to the namespace,
-                * but UW-IMAP does. We'll strip it here and add it back
-                * as if it were a normal directory, from the browser */
-               if (n && (ns[n-1] == delim))
-                 ns[--n] = '\0';
-               strncpy(nsbuf+nsbused,ns,nsblen-nsbused-1);
-               nsi->prefix = nsbuf+nsbused;
-               nsbused += n+1;
-               nsi->delim = delim;
-               nsi++;
-               (*nns)++;
+               ns[n++] = *s;
+               s++;
              }
-             while (*s && *s != ')') s++;
-             s++;
+           ns[n] = '\0';
+           /* delim? */
+           s = imap_next_word (s);
+           /* delimiter is meaningless if namespace is "". Why does
+            * Cyrus provide one?! */
+           if (n && *s && *s == '\"')
+           {
+             if (s[1] && s[2] == '\"')
+               delim = s[1];
+             else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+               delim = s[2];
+           }
+           /* skip "" namespaces, they are already listed at the root */
+           if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen))
+           {
+             dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns));
+             nsi->type = type;
+             /* Cyrus doesn't append the delimiter to the namespace,
+              * but UW-IMAP does. We'll strip it here and add it back
+              * as if it were a normal directory, from the browser */
+             if (n && (ns[n-1] == delim))
+               ns[--n] = '\0';
+             strncpy (nsbuf+nsbused,ns,nsblen-nsbused-1);
+             nsi->prefix = nsbuf+nsbused;
+             nsbused += n+1;
+             nsi->delim = delim;
+             nsi++;
+             (*nns)++;
            }
+           while (*s && *s != ')') s++;
+           s++;
          }
        }
       }
-      else
-      {
-       if (imap_handle_untagged (idata, buf) != 0)
-         return (-1);
-      }
     }
   }
-  while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+  while (rc == IMAP_CMD_CONTINUE);
+
+  if (rc != IMAP_CMD_DONE)
+    return -1;
 
   return 0;
 }
@@ -481,12 +457,12 @@ static int browse_verify_namespace (IMAP_DATA* idata,
     nsi->home_namespace = 0;
     do 
     {
-      if (imap_parse_list_response(idata, buf, sizeof(buf), &name,
-          &(nsi->noselect), &(nsi->noinferiors), &delim) != 0)
+      if (imap_parse_list_response(idata, &name, &nsi->noselect,
+          &nsi->noinferiors, &delim) != 0)
        return -1;
       nsi->listable |= (name != NULL);
     }
-    while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+    while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
   }
 
   return 0;
index 02d2bb3c2acdd8bd0d61dd4f02d4004b2cbadf4c..8d6282963f5d24944138831f1c88a66b03550128 100644 (file)
@@ -29,6 +29,8 @@
 #include <ctype.h>
 #include <stdlib.h>
 
+#define IMAP_CMD_BUFSIZE 512
+
 /* forward declarations */
 static void cmd_make_sequence (char* buf, size_t buflen);
 static void cmd_parse_capabilities (IMAP_DATA* idata, char* s);
@@ -60,6 +62,67 @@ void imap_cmd_start (IMAP_DATA* idata, const char* cmd)
   safe_free ((void**) &out);
 }
 
+/* imap_cmd_resp: Reads server responses from an IMAP command, detects
+ *   tagged completion response, handles untagged messages, can read
+ *   arbitrarily large strings (using malloc, so don't make it _too_
+ *   large!). */
+int imap_cmd_resp (IMAP_DATA* idata)
+{
+  unsigned int len = 0;
+  int c;
+
+  /* read into buffer, expanding buffer as necessary until we have a full
+   * line */
+  do
+  {
+    if (len == idata->blen)
+    {
+      safe_realloc ((void**) &idata->buf, idata->blen + IMAP_CMD_BUFSIZE);
+      idata->blen = idata->blen + IMAP_CMD_BUFSIZE;
+      dprint (3, (debugfile, "imap_cmd_resp: grew buffer to %u bytes\n", idata->blen));
+    }
+
+    if ((c = mutt_socket_readln (idata->buf + len, idata->blen - len,
+      idata->conn)) < 0)
+    {
+      dprint (1, (debugfile, "imap_cmd_resp: Error while reading server response.\n"));
+      return IMAP_CMD_FAIL;
+    }
+
+    len += c;
+  }
+  /* if we've read all the way to the end of the buffer, we haven't read a
+   * full line (mutt_socket_readln strips the \r, so we always have at least
+   * one character free when we've read a full line) */
+  while (len == idata->blen);
+
+  /* don't let one large string make idata->buf hog memory forever */
+  if ((idata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
+  {
+    safe_realloc ((void**) &idata->buf, IMAP_CMD_BUFSIZE);
+    idata->blen = IMAP_CMD_BUFSIZE;
+    dprint (3, (debugfile, "imap_cmd_resp: shrank buffer to %u bytes\n", idata->blen));
+  }
+  
+  /* handle untagged messages. The caller still gets its shot afterwards. */
+  if (!strncmp (idata->buf, "* ", 2) &&
+      imap_handle_untagged (idata, idata->buf))
+    return IMAP_CMD_FAIL;
+
+  /* server demands a continuation response from us */
+  if (!strncmp (idata->buf, "+ ", 2))
+    return IMAP_CMD_RESPOND;
+
+  /* tagged completion code */
+  if (!mutt_strncmp (idata->buf, idata->seq, SEQLEN))
+  {
+    imap_cmd_finish (idata);
+    return IMAP_CMD_DONE;
+  }
+
+  return IMAP_CMD_CONTINUE;
+}
+
 /* imap_cmd_finish: When the caller has finished reading command responses,
  *   it must call this routine to perform cleanup (eg fetch new mail if
  *   detected, do expunge) */
@@ -104,7 +167,6 @@ void imap_cmd_finish (IMAP_DATA* idata)
   }
 
   idata->status = 0;
-  mutt_clear_error ();
 }
 
 /* imap_code: returns 1 if the command result was OK, or 0 if NO or BAD */
@@ -123,11 +185,11 @@ int imap_code (const char *s)
  *   IMAP_CMD_PASS: command contains a password. Suppress logging.
  * Return 0 on success, -1 on Failure, -2 on OK Failure
  */
-int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
-  int flags)
+int imap_exec (IMAP_DATA* idata, const char* cmd, int flags)
 {
   char* out;
   int outlen;
+  int rc;
 
   /* create sequence for command */
   cmd_make_sequence (idata->seq, sizeof (idata->seq));
@@ -142,30 +204,24 @@ int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
   safe_free ((void**) &out);
 
   do
-  {
-    if (mutt_socket_readln (buf, buflen, idata->conn) < 0)
-      return -1;
-
-    if (buf[0] == '*' && imap_handle_untagged (idata, buf) != 0)
-      return -1;
-  }
-  while (mutt_strncmp (buf, idata->seq, SEQLEN) != 0);
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
 
-  imap_cmd_finish (idata);
+  if (rc != IMAP_CMD_DONE)
+    return -1;
 
-  if (!imap_code (buf))
+  if (!imap_code (idata->buf))
   {
     char *pc;
 
     if (flags & IMAP_CMD_FAIL_OK)
       return -2;
 
-    dprint (1, (debugfile, "imap_exec: command failed: %s\n", buf));
-    pc = buf + SEQLEN;
-    SKIPWS (pc);
+    dprint (1, (debugfile, "imap_exec: command failed: %s\n", idata->buf));
+    pc = idata->buf;
     pc = imap_next_word (pc);
     mutt_error ("%s", pc);
-    sleep (1);
+    sleep (2);
 
     return -1;
   }
@@ -174,7 +230,7 @@ int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
 }
 
 /* imap_handle_untagged: fallback parser for otherwise unhandled messages. */
-int imap_handle_untagged (IMAP_DATA *idata, char *s)
+int imap_handle_untagged (IMAP_DATA* idata, char* s)
 {
   char *pn;
   int count;
@@ -191,6 +247,8 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
      */
     if (mutt_strncasecmp ("EXISTS", s, 6) == 0)
     {
+      dprint (2, (debugfile, "Handling EXISTS\n"));
+
       /* new mail arrived */
       count = atoi (pn);
 
@@ -232,6 +290,12 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
     cmd_parse_myrights (idata, s);
   else if (mutt_strncasecmp ("BYE", s, 3) == 0)
   {
+    dprint (2, (debugfile, "Handling BYE\n"));
+
+    /* check if we're logging out */
+    if (idata->status == IMAP_BYE)
+      return 0;
+
     /* server shut down our connection */
     s += 3;
     SKIPWS (s);
@@ -246,13 +310,12 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s)
   }
   else if (option (OPTIMAPSERVERNOISE) && (mutt_strncasecmp ("NO", s, 2) == 0))
   {
+    dprint (2, (debugfile, "Handling untagged NO\n"));
+
     /* Display the warning message from the server */
     mutt_error ("%s", s+3);
     sleep (2);
   }
-  else
-    dprint (1, (debugfile, "imap_handle_untagged(): unhandled request: %s\n",
-      s));
 
   return 0;
 }
@@ -274,6 +337,8 @@ static void cmd_parse_capabilities (IMAP_DATA* idata, char* s)
 {
   int x;
 
+  dprint (2, (debugfile, "Handling CAPABILITY\n"));
+
   idata->capstr = safe_strdup (imap_next_word (s));
   
   while (*s) 
@@ -295,6 +360,8 @@ static void cmd_parse_expunge (IMAP_DATA* idata, char* s)
   int expno, cur;
   HEADER* h;
 
+  dprint (2, (debugfile, "Handling EXPUNGE\n"));
+
   expno = atoi (s);
 
   /* walk headers, zero seqno of expunged message, decrement seqno of those
@@ -317,6 +384,8 @@ static void cmd_parse_expunge (IMAP_DATA* idata, char* s)
 /* cmd_parse_myrights: set rights bits according to MYRIGHTS response */
 static void cmd_parse_myrights (IMAP_DATA* idata, char* s)
 {
+  dprint (2, (debugfile, "Handling MYRIGHTS\n"));
+
   s = imap_next_word (s);
   s = imap_next_word (s);
 
index ca66b2f46527f7cc9ff09f8aa5f46b9ecd095437..102b9820feea63cc2ceb838dac332650c3f5c0ad 100644 (file)
@@ -52,11 +52,12 @@ int imap_create_mailbox (CONTEXT* ctx, char* mailbox)
   imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
   snprintf (buf, sizeof (buf), "CREATE %s", mbox);
       
-  if (imap_exec (buf, sizeof (buf), CTX_DATA, buf, 0) != 0)
+  if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
   {
-    imap_error ("imap_create_mailbox()", buf);
+    imap_error ("imap_create_mailbox", CTX_DATA->buf);
     return -1;
   }
+
   return 0;
 }
 
@@ -67,8 +68,11 @@ int imap_delete_mailbox (CONTEXT* ctx, char* mailbox)
   imap_quote_string (mbox, sizeof (mbox), mailbox);
   snprintf (buf, sizeof (buf), "DELETE %s", mbox);
 
-  if (imap_exec (buf, sizeof (buf), CTX_DATA, buf, 0) != 0)
+  if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
+  {
+    imap_error ("imap_delete_mailbox", CTX_DATA->buf);
     return -1;
+  }
 
   return 0;
 }
@@ -429,8 +433,8 @@ int imap_reopen_mailbox (IMAP_DATA* idata)
 
 static int imap_get_delim (IMAP_DATA *idata)
 {
-  char buf[LONG_STRING];
   char *s;
+  int rc;
 
   /* assume that the delim is /.  If this fails, we're in bigger trouble
    * than getting the delim wrong */
@@ -440,31 +444,31 @@ static int imap_get_delim (IMAP_DATA *idata)
 
   do 
   {
-    if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
-      return -1;
+    if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+      break;
 
-    if (buf[0] == '*') 
+    s = imap_next_word (idata->buf);
+    if (mutt_strncasecmp ("LIST", s, 4) == 0)
     {
-      s = imap_next_word (buf);
-      if (mutt_strncasecmp ("LIST", s, 4) == 0)
-      {
-       s = imap_next_word (s);
-       s = imap_next_word (s);
-       if (s && s[0] == '\"' && s[1] && s[2] == '\"')
-         idata->delim = s[1];
-       else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
-         idata->delim = s[2];
-      }
-      else
-      {
-       if (imap_handle_untagged (idata, buf) != 0)
-         return -1;
-      }
+      s = imap_next_word (s);
+      s = imap_next_word (s);
+      if (s && s[0] == '\"' && s[1] && s[2] == '\"')
+       idata->delim = s[1];
+      else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+       idata->delim = s[2];
     }
   }
-  while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
+  while (rc == IMAP_CMD_CONTINUE);
 
-  return 0;
+  if (rc != IMAP_CMD_DONE)
+  {
+    dprint (1, (debugfile, "imap_get_delim: failed.\n"));
+    return -1;
+  }
+
+  dprint (2, (debugfile, "Delimiter: %c\n", idata->delim));
+
+  return -1;
 }
 
 /* get rights for folder, let imap_handle_untagged do the rest */
@@ -475,7 +479,7 @@ static int imap_check_acl (IMAP_DATA *idata)
 
   imap_munge_mbox_name (mbox, sizeof(mbox), idata->mailbox);
   snprintf (buf, sizeof (buf), "MYRIGHTS %s", mbox);
-  if (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0)
+  if (imap_exec (idata, buf, 0) != 0)
   {
     imap_error ("imap_check_acl", buf);
     return -1;
@@ -486,11 +490,9 @@ static int imap_check_acl (IMAP_DATA *idata)
 /* imap_check_capabilities: make sure we can log in to this server. */
 static int imap_check_capabilities (IMAP_DATA* idata)
 {
-  char buf[LONG_STRING];
-
-  if (imap_exec (buf, sizeof (buf), idata, "CAPABILITY", 0) != 0)
+  if (imap_exec (idata, "CAPABILITY", 0) != 0)
   {
-    imap_error ("imap_check_capabilities", buf);
+    imap_error ("imap_check_capabilities", idata->buf);
     return -1;
   }
 
@@ -566,17 +568,17 @@ int imap_open_connection (IMAP_DATA* idata)
 
   idata->state = IMAP_CONNECTED;
 
-  if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+  if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE)
     goto bail;
 
-  if (mutt_strncmp ("* OK", buf, 4) == 0)
+  if (mutt_strncmp ("* OK", idata->buf, 4) == 0)
   {
     if (imap_check_capabilities (idata) || imap_authenticate (idata))
       goto bail;
   }
-  else if (mutt_strncmp ("* PREAUTH", buf, 9) == 0)
+  else if (mutt_strncmp ("* PREAUTH", idata->buf, 9) == 0)
   {
-    if (imap_check_capabilities(idata) != 0)
+    if (imap_check_capabilities (idata) != 0)
       goto bail;
   } 
   else
@@ -662,8 +664,8 @@ int imap_open_mailbox (CONTEXT* ctx)
   char buf[LONG_STRING];
   char bufout[LONG_STRING];
   int count = 0;
-  int n;
   IMAP_MBOX mx;
+  int rc;
   
   if (imap_parse_path (ctx->path, &mx))
   {
@@ -677,7 +679,7 @@ int imap_open_mailbox (CONTEXT* ctx)
   conn = idata->conn;
 
   /* once again the context is new */
-  ctx->data = (void *) idata;
+  ctx->data = idata;
 
   /* Clean up path and replace the one in the ctx */
   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
@@ -707,56 +709,53 @@ int imap_open_mailbox (CONTEXT* ctx)
   {
     char *pc;
     
-    if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
+    if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
       break;
 
-    if (buf[0] == '*')
+    pc = idata->buf + 2;
+    pc = imap_next_word (pc);
+    if (!mutt_strncasecmp ("EXISTS", pc, 6))
     {
-      pc = buf + 2;
+      /* imap_handle_untagged will have picked up the EXISTS message and
+       * set the NEW_MAIL flag. We clear it here. */
+      idata->status = 0;
+      count = idata->newMailCount;
+      idata->newMailCount = 0;
+    }
 
-      if (isdigit (*pc))
-      {
-       char *pn = pc;
+    pc = idata->buf + 2;
 
-       while (*pc && isdigit (*pc))
-         pc++;
-       *pc++ = '\0';
-       n = atoi (pn);
-       SKIPWS (pc);
-       if (mutt_strncasecmp ("EXISTS", pc, 6) == 0)
-         count = n;
-      }
-      /* Obtain list of available flags here, may be overridden by a
-       * PERMANENTFLAGS tag in the OK response */
-      else if (mutt_strncasecmp ("FLAGS", pc, 5) == 0)
-      {
-        /* don't override PERMANENTFLAGS */
-        if (!idata->flags)
-        {
-          dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
-          if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
-            return -1;
-        }
-      }
-      /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
-      else if (mutt_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
+    /* Obtain list of available flags here, may be overridden by a
+     * PERMANENTFLAGS tag in the OK response */
+    if (mutt_strncasecmp ("FLAGS", pc, 5) == 0)
+    {
+      /* don't override PERMANENTFLAGS */
+      if (!idata->flags)
       {
-        dprint (2, (debugfile,
-          "Getting mailbox PERMANENTFLAGS\n"));
-        /* safe to call on NULL */
-        mutt_free_list (&(idata->flags));
-       /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
-        pc += 13;
-        if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
-          return -1;
+       dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
+       if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
+         return -1;
       }
-      else if (imap_handle_untagged (idata, buf) != 0)
-       return (-1);
+    }
+    /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
+    else if (mutt_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0)
+    {
+      dprint (2, (debugfile, "Getting mailbox PERMANENTFLAGS\n"));
+      /* safe to call on NULL */
+      mutt_free_list (&(idata->flags));
+      /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
+      pc += 13;
+      if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
+       return -1;
     }
   }
-  while (mutt_strncmp (idata->seq, buf, mutt_strlen (idata->seq)) != 0);
+  while (rc == IMAP_CMD_CONTINUE);
+
+  if (rc != IMAP_CMD_DONE)
+    return -1;
+
   /* check for READ-ONLY notification */
-  if (!strncmp (imap_get_qualifier (buf), "[READ-ONLY]", 11))
+  if (!strncmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11))
   {
     dprint (2, (debugfile, "Mailbox is read-only.\n"));
     ctx->readonly = 1;
@@ -785,10 +784,10 @@ int imap_open_mailbox (CONTEXT* ctx)
   }
 #endif
 
-  if (!imap_code (buf))
+  if (!imap_code (idata->buf))
   {
     char *s;
-    s = imap_next_word (buf); /* skip seq */
+    s = imap_next_word (idata->buf); /* skip seq */
     s = imap_next_word (s); /* Skip response */
     mutt_error ("%s", s);
     idata->state = IMAP_AUTHENTICATED;
@@ -866,7 +865,7 @@ int imap_open_mailbox_append (CONTEXT *ctx)
     return -1;
   }
 
-  r = imap_exec (buf, sizeof (buf), idata, buf, IMAP_CMD_FAIL_OK);
+  r = imap_exec (idata, buf, IMAP_CMD_FAIL_OK);
   if (r == -2)
   {
     /* command failed cause folder doesn't exist */
@@ -884,18 +883,15 @@ int imap_open_mailbox_append (CONTEXT *ctx)
   return 0;
 }
 
+/* imap_logout: Gracefully log out of server. */
 void imap_logout (IMAP_DATA* idata)
 {
-  char buf[LONG_STRING];
-
+  /* we set status here to let imap_handle_untagged know we _expect_ to
+   * receive a bye response (so it doesn't freak out and close the conn) */
+  idata->status = IMAP_BYE;
   imap_cmd_start (idata, "LOGOUT");
-
-  do
-  {
-    if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
-      break;
-  }
-  while (mutt_strncmp (idata->seq, buf, SEQLEN) != 0);
+  while (imap_cmd_resp (idata) == IMAP_CMD_CONTINUE)
+    ;
 }
 
 int imap_close_connection (CONTEXT *ctx)
@@ -1070,7 +1066,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
       mutt_message (_("Marking %d messages deleted..."), deleted);
       snprintf (tmp, sizeof (tmp), "UID STORE %s +FLAGS.SILENT (\\Deleted)",
         buf);
-      if (imap_exec (buf, sizeof (buf), idata, tmp, 0) != 0)
+      if (imap_exec (idata, tmp, 0) != 0)
         /* continue, let regular store try before giving up */
         dprint(2, (debugfile, "imap_sync_mailbox: fast delete failed\n"));
       else
@@ -1125,7 +1121,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
 
       /* after all this it's still possible to have no flags, if you
        * have no ACL rights */
-      if (*flags && (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0) &&
+      if (*flags && (imap_exec (idata, buf, 0) != 0) &&
         (err_continue != M_YES))
       {
         err_continue = imap_continue ("imap_sync_mailbox: STORE failed", buf);
@@ -1143,7 +1139,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
       mutt_bit_isset(idata->rights, IMAP_ACL_DELETE))
   {
     mutt_message _("Expunging messages from server...");
-    if (imap_exec (buf, sizeof (buf), CTX_DATA, "EXPUNGE", 0) != 0)
+    if (imap_exec (idata, "EXPUNGE", 0) != 0)
     {
       imap_error ("imap_sync_mailbox: EXPUNGE failed", buf);
       return -1;
@@ -1157,7 +1153,6 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
 void imap_close_mailbox (CONTEXT* ctx)
 {
   IMAP_DATA* idata;
-  char buf[LONG_STRING];
   int i;
 
   idata = (IMAP_DATA*) ctx->data;
@@ -1172,8 +1167,8 @@ void imap_close_mailbox (CONTEXT* ctx)
     if (!(idata->noclose))
     {
       mutt_message _("Closing mailbox...");
-      if (imap_exec (buf, sizeof (buf), idata, "CLOSE", 0) != 0)
-        imap_error ("CLOSE failed", buf);
+      if (imap_exec (idata, "CLOSE", 0) != 0)
+        imap_error ("CLOSE failed", idata->buf);
     }
     
     idata->state = IMAP_AUTHENTICATED;
@@ -1204,10 +1199,13 @@ void imap_close_mailbox (CONTEXT* ctx)
  */
 int imap_check_mailbox (CONTEXT *ctx, int *index_hint)
 {
-  char buf[LONG_STRING];
   static time_t checktime=0;
+
+  IMAP_DATA* idata;
   time_t t = 0;
 
+  idata = (IMAP_DATA*) ctx->data;
+
   /* 
    * gcc thinks it has to warn about uninitialized use
    * of t.  This is wrong.
@@ -1219,21 +1217,22 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint)
     t -= checktime;
   }
 
+  /* TODO: wtf?! */
   if ((ImapCheckTimeout && t >= ImapCheckTimeout)
-      || ((CTX_DATA->reopen & IMAP_REOPEN_ALLOW) && (CTX_DATA->reopen & ~IMAP_REOPEN_ALLOW)))
+      || ((idata->reopen & IMAP_REOPEN_ALLOW) && (idata->reopen & ~IMAP_REOPEN_ALLOW)))
   {
     if (ImapCheckTimeout) checktime += t;
 
-    CTX_DATA->check_status = 0;
-    if (imap_exec (buf, sizeof (buf), CTX_DATA, "NOOP", 0) != 0)
+    idata->check_status = 0;
+    if (imap_exec (idata, "NOOP", 0) != 0)
     {
-      imap_error ("imap_check_mailbox()", buf);
+      imap_error ("imap_check_mailbox", idata->buf);
       return -1;
     }
     
-    if (CTX_DATA->check_status == IMAP_NEW_MAIL)
+    if (idata->check_status == IMAP_NEW_MAIL)
       return M_NEW_MAIL;
-    if (CTX_DATA->check_status == IMAP_REOPENED)
+    if (idata->check_status == IMAP_REOPENED)
       return M_REOPENED;
   }
   
@@ -1257,6 +1256,7 @@ int imap_mailbox_check (char* path, int new)
   int msgcount = 0;
   int connflags = 0;
   IMAP_MBOX mx;
+  int rc;
   
   if (imap_parse_path (path, &mx))
     return -1;
@@ -1304,119 +1304,107 @@ int imap_mailbox_check (char* path, int new)
 
   do 
   {
-    if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-      return -1;
+    if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+      break;
 
-    if (buf[0] == '*') 
+    s = imap_next_word (idata->buf);
+    if (mutt_strncasecmp ("STATUS", s, 6) == 0)
     {
-      s = imap_next_word (buf);
-      if (mutt_strncasecmp ("STATUS", s, 6) == 0)
+      s = imap_next_word (s);
+      /* The mailbox name may or may not be quoted here. We could try to 
+       * munge the server response and compare with quoted (or vise versa)
+       * but it is probably more efficient to just strncmp against both. */
+      if (mutt_strncmp (mbox_unquoted, s, mutt_strlen (mbox_unquoted)) == 0
+         || mutt_strncmp (mbox, s, mutt_strlen (mbox)) == 0)
       {
        s = imap_next_word (s);
-       /* The mailbox name may or may not be quoted here. We could try to 
-        * munge the server response and compare with quoted (or vise versa)
-        * but it is probably more efficient to just strncmp against both. */
-       if (mutt_strncmp (mbox_unquoted, s, mutt_strlen (mbox_unquoted)) == 0
-           || mutt_strncmp (mbox, s, mutt_strlen (mbox)) == 0)
+       s = imap_next_word (s);
+       if (isdigit (*s))
        {
-         s = imap_next_word (s);
-         s = imap_next_word (s);
-         if (isdigit (*s))
+         if (*s != '0')
          {
-           if (*s != '0')
-           {
-             dprint (1, (debugfile, "Mail in %s\n", path));
-             msgcount = atoi(s);
-           }
+           dprint (1, (debugfile, "Mail in %s\n", path));
+           msgcount = atoi(s);
          }
        }
-       else
-         dprint (1, (debugfile, "imap_mailbox_check: STATUS response doesn't match requested mailbox.\n"));
       }
       else
-      {
-       if (conn->data && 
-           imap_handle_untagged (idata, buf) != 0)
-         return -1;
-      }
+       dprint (1, (debugfile, "imap_mailbox_check: STATUS response doesn't match requested mailbox.\n"));
     }
   }
-  while ((mutt_strncmp (buf, idata->seq, SEQLEN) != 0));
-
-  imap_cmd_finish (idata);
+  while (rc == IMAP_CMD_CONTINUE);
 
   return msgcount;
 }
 
-int imap_parse_list_response(IMAP_DATA* idata, char *buf, int buflen,
-  char **name, int *noselect, int *noinferiors, char *delim)
+/* all this listing/browsing is a mess. I don't like that name is a pointer
+ *   into idata->buf (used to be a pointer into the passed in buffer, just
+ *   as bad), nor do I like the fact that the fetch is done here. This
+ *   code can't possibly handle non-LIST untagged responses properly.
+ *   FIXME. ?! */
+int imap_parse_list_response(IMAP_DATA* idata, char **name, int *noselect,
+  int *noinferiors, char *delim)
 {
   char *s;
   long bytes;
+  int rc;
 
   *name = NULL;
 
-  if (mutt_socket_readln (buf, buflen, idata->conn) < 0)
+  rc = imap_cmd_resp (idata);
+  if (rc == IMAP_CMD_DONE)
+    return 0;
+  if (rc != IMAP_CMD_CONTINUE)
     return -1;
 
-  if (buf[0] == '*')
+  s = imap_next_word (idata->buf);
+  if ((mutt_strncasecmp ("LIST", s, 4) == 0) ||
+      (mutt_strncasecmp ("LSUB", s, 4) == 0))
   {
-    s = imap_next_word (buf);
-    if ((mutt_strncasecmp ("LIST", s, 4) == 0) ||
-       (mutt_strncasecmp ("LSUB", s, 4) == 0))
-    {
-      *noselect = 0;
-      *noinferiors = 0;
+    *noselect = 0;
+    *noinferiors = 0;
       
-      s = imap_next_word (s); /* flags */
-      if (*s == '(')
-      {
-       char *ep;
-       
-       s++;
-       ep = s;
-       while (*ep && *ep != ')') ep++;
-       do {
-         if (!strncasecmp (s, "\\NoSelect", 9))
-           *noselect = 1;
-         if (!strncasecmp (s, "\\NoInferiors", 12))
-           *noinferiors = 1;
-         if (*s != ')')
-           s++;
-         while (*s && *s != '\\' && *s != ')') s++;
-       } while (s != ep);
-      }
-      else
-       return (0);
-      s = imap_next_word (s); /* delim */
-      /* Reset the delimiter, this can change */
-      if (strncmp (s, "NIL", 3))
+    s = imap_next_word (s); /* flags */
+    if (*s == '(')
+    {
+      char *ep;
+
+      s++;
+      ep = s;
+      while (*ep && *ep != ')') ep++;
+      do
       {
-       if (s && s[0] == '\"' && s[1] && s[2] == '\"')
-         *delim = s[1];
-       else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
-         *delim = s[2];
-      }
-      s = imap_next_word (s); /* name */
-      if (s && *s == '{')      /* Literal */
-      { 
-       int len;
-       
-       if (imap_get_literal_count(buf, &bytes) < 0)
-         return -1;
-       len = mutt_socket_readln (buf, buflen, idata->conn);
-       if (len < 0)
-         return -1;
-       *name = buf;
-      }
-      else
-       *name = s;
+       if (!strncasecmp (s, "\\NoSelect", 9))
+         *noselect = 1;
+       if (!strncasecmp (s, "\\NoInferiors", 12))
+         *noinferiors = 1;
+       if (*s != ')')
+         s++;
+       while (*s && *s != '\\' && *s != ')') s++;
+      } while (s != ep);
     }
     else
+      return 0;
+    s = imap_next_word (s); /* delim */
+    /* Reset the delimiter, this can change */
+    if (strncmp (s, "NIL", 3))
     {
-      if (imap_handle_untagged (idata, buf) != 0)
+      if (s && s[0] == '\"' && s[1] && s[2] == '\"')
+       *delim = s[1];
+      else if (s && s[0] == '\"' && s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
+       *delim = s[2];
+    }
+    s = imap_next_word (s); /* name */
+    if (s && *s == '{')        /* Literal */
+    { 
+      if (imap_get_literal_count(idata->buf, &bytes) < 0)
        return -1;
+      if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE)
+       return -1;
+      *name = idata->buf;
     }
+    else
+      *name = s;
   }
 
   return 0;
@@ -1448,7 +1436,7 @@ int imap_subscribe (char *path, int subscribe)
   snprintf (buf, sizeof (buf), "%s %s", subscribe ? "SUBSCRIBE" :
     "UNSUBSCRIBE", mbox);
 
-  if (imap_exec (buf, sizeof (buf), idata, buf, 0) < 0)
+  if (imap_exec (idata, buf, 0) < 0)
     return -1;
 
   return 0;
@@ -1499,8 +1487,8 @@ int imap_complete(char* dest, size_t dlen, char* path) {
   strfcpy (completion, mx.mbox, sizeof(completion));
   do
   {
-    if (imap_parse_list_response(idata, buf, sizeof(buf), &list_word,
-        &noselect, &noinferiors, &delim))
+    if (imap_parse_list_response(idata, &list_word, &noselect, &noinferiors,
+        &delim))
       break;
 
     if (list_word)
@@ -1535,7 +1523,7 @@ int imap_complete(char* dest, size_t dlen, char* path) {
       completions++;
     }
   }
-  while (mutt_strncmp(idata->seq, buf, SEQLEN));
+  while (mutt_strncmp(idata->seq, idata->buf, SEQLEN));
 
   if (completions)
   {
index e404f19d0c5eeea317c5c6846e340e56a4ac8f99..fe197a644f0e97dd3ad6f701350505aab86595f6 100644 (file)
 #define IMAP_LOG_LTRL 4
 #define IMAP_LOG_PASS 5
 
+/* IMAP command responses */
+#define IMAP_CMD_DONE     (0)
+#define IMAP_CMD_FAIL     (-1)
+#define IMAP_CMD_CONTINUE (1)
+#define IMAP_CMD_RESPOND  (2)
+
 /* number of entries in the hash table */
 #define IMAP_CACHE_LEN 10
 
@@ -145,6 +151,10 @@ typedef struct
   unsigned char status;
   unsigned char check_status;
   unsigned char capabilities[(CAPMAX + 7)/8];
+  char seq[SEQLEN+1];
+  /* command input buffer */
+  char* buf;
+  unsigned int blen;
   /* let me explain capstr: SASL needs the capability string (not bits).
    * we have 3 options:
    *   1. rerun CAPABILITY inside SASL function.
@@ -154,7 +164,6 @@ typedef struct
    * tracking all possible capabilities. bah. (1) I don't like because
    * it's just no fun to get the same information twice */
   char* capstr;
-  char seq[SEQLEN+1];
 
   /* The following data is all specific to the currently SELECTED mbox */
   char delim;
@@ -180,8 +189,8 @@ int imap_make_msg_set (IMAP_DATA* idata, char* buf, size_t buflen, int flag,
 int imap_open_connection (IMAP_DATA* idata);
 IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags);
 time_t imap_parse_date (char* s);
-int imap_parse_list_response(IMAP_DATA* idata, char* buf, int buflen,
-  char** name, int* noselect, int* noinferiors, char* delim);
+int imap_parse_list_response(IMAP_DATA* idata, char** name, int* noselect,
+  int* noinferiors, char* delim);
 int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes);
 void imap_expunge_mailbox (IMAP_DATA* idata);
 int imap_reopen_mailbox (IMAP_DATA* idata);
@@ -192,10 +201,10 @@ int imap_authenticate (IMAP_DATA* idata);
 
 /* command.c */
 void imap_cmd_start (IMAP_DATA* idata, const char* cmd);
+int imap_cmd_resp (IMAP_DATA* idata);
 void imap_cmd_finish (IMAP_DATA* idata);
 int imap_code (const char* s);
-int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd,
-  int flags);
+int imap_exec (IMAP_DATA* idata, const char* cmd, int flags);
 int imap_handle_untagged (IMAP_DATA* idata, char* s);
 
 /* message.c */
index 3ea4b4cce0abdc3db6e22fc5d5a5c336f9479a86..a5e5fccd25add026d97afc3ccd7d5c0ce720065b 100644 (file)
@@ -45,23 +45,26 @@ static char* msg_parse_flags (IMAP_HEADER* h, char* s);
  */
 int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
 {
+  IMAP_DATA* idata;
   char buf[LONG_STRING];
   char hdrreq[STRING];
   FILE *fp;
   char tempfile[_POSIX_PATH_MAX];
   int msgno;
   IMAP_HEADER h;
-  int rc;
+  int rc, mfhrc;
   int fetchlast = 0;
   const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO LINES X-LABEL";
+
+  idata = (IMAP_DATA*) ctx->data;
   
   /* define search string */
-  if (mutt_bit_isset (CTX_DATA->capabilities,IMAP4REV1))
+  if (mutt_bit_isset (idata->capabilities,IMAP4REV1))
   {
     snprintf (hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s)]", 
       want_headers); 
   } 
-  else if (mutt_bit_isset (CTX_DATA->capabilities,IMAP4))
+  else if (mutt_bit_isset (idata->capabilities,IMAP4))
   {
     snprintf (hdrreq, sizeof (hdrreq), "RFC822.HEADER.LINES (%s)", 
       want_headers);
@@ -69,7 +72,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
   else
   {    /* Unable to fetch headers for lower versions */
     mutt_error _("Unable to fetch headers from this IMAP server version.");
-    sleep (1); /* pause a moment to let the user see the error */
+    sleep (2); /* pause a moment to let the user see the error */
     return -1;
   }
 
@@ -102,7 +105,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
         "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1,
         msgend + 1, hdrreq);
 
-      imap_cmd_start (CTX_DATA, buf);
+      imap_cmd_start (idata, buf);
 
       fetchlast = msgend + 1;
     }
@@ -118,72 +121,66 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
      */
     do
     {
-      rc = 0;
-
-      if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
-      {
-       imap_free_header_data ((void**) &h.data);
-       fclose (fp);
-        return -1;
-      }
-
-      if (buf[0] == '*')
-      {
-       if ((rc = msg_fetch_header (ctx, &h, buf, fp)))
-       {
-         if (rc == -1 && !imap_handle_untagged (CTX_DATA, buf))
-           continue;
-         else
-         {
-           imap_free_header_data ((void**) h.data);
-           fclose (fp);
-           return -1;
-         }
-       }
+      mfhrc = 0;
+
+      rc = imap_cmd_resp (idata);
+      if (rc != IMAP_CMD_CONTINUE)
+       break;
+
+      if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, fp)) == -1)
+       continue;
+      else if (mfhrc < 0)
+       break;
+
+      /* make sure we don't get remnants from older larger message headers */
+      fputs ("\n\n", fp);
+
+      /* update context with message header */
+      ctx->hdrs[msgno] = mutt_new_header ();
+      ctx->hdrs[msgno]->index = ctx->msgcount;
+
+      /* messages which have not been expunged are ACTIVE (borrowed from mh 
+       * folders) */
+      ctx->hdrs[msgno]->active = 1;
+      ctx->hdrs[msgno]->read = h.read;
+      ctx->hdrs[msgno]->old = h.old;
+      ctx->hdrs[msgno]->deleted = h.deleted;
+      ctx->hdrs[msgno]->flagged = h.flagged;
+      ctx->hdrs[msgno]->replied = h.replied;
+      ctx->hdrs[msgno]->changed = h.changed;
+      ctx->hdrs[msgno]->received = h.received;
+      ctx->hdrs[msgno]->data = (void *) (h.data);
+
+      rewind (fp);
+      /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends
+       *   on h.received being set */
+      ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno],
+        0, 0);
+      /* content built as a side-effect of mutt_read_rfc822_header */
+      ctx->hdrs[msgno]->content->length = h.content_length;
+
+      mx_update_context (ctx); /* increments ->msgcount */
+    }
+    while ((rc != IMAP_CMD_DONE) && ((mfhrc == -1) ||
+      ((msgno + 1) >= fetchlast)));
 
-       /* make sure we don't get remnants from older larger message headers */
-       fputs ("\n\n", fp);
-
-       /* update context with message header */
-       ctx->hdrs[msgno] = mutt_new_header ();
-       ctx->hdrs[msgno]->index = ctx->msgcount;
-
-       /* messages which have not been expunged are ACTIVE (borrowed from
-        * mh folders) */
-       ctx->hdrs[msgno]->active = 1;
-       ctx->hdrs[msgno]->read = h.read;
-       ctx->hdrs[msgno]->old = h.old;
-       ctx->hdrs[msgno]->deleted = h.deleted;
-       ctx->hdrs[msgno]->flagged = h.flagged;
-       ctx->hdrs[msgno]->replied = h.replied;
-       ctx->hdrs[msgno]->changed = h.changed;
-       ctx->hdrs[msgno]->received = h.received;
-       ctx->hdrs[msgno]->data = (void *) (h.data);
-
-       rewind (fp);
-       /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends
-        *   on h.received being set */
-       ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno],
-          0, 0);
-       /* content built as a side-effect of mutt_read_rfc822_header */
-       ctx->hdrs[msgno]->content->length = h.content_length;
-
-       mx_update_context (ctx); /* increments ->msgcount */
+    if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_DONE)))
+    {
+      imap_free_header_data ((void**) &h.data);
+      fclose (fp);
 
-      }
+      return -1;
     }
-    while ((rc == -1) || ((msgno + 1) >= fetchlast &&
-      !mutt_strncmp (CTX_DATA->seq, buf, SEQLEN) != 0));
-
+       
     /* h.data shouldn't be freed here, it is kept in ctx->headers */
 
     /* in case we get new mail while fetching the headers */
-    if (CTX_DATA->status == IMAP_NEW_MAIL)
+    if (idata->status == IMAP_NEW_MAIL)
     {
-      msgend = CTX_DATA->newMailCount - 1;
+      msgend = idata->newMailCount - 1;
       while ((msgend) >= ctx->hdrmax)
        mx_alloc_memory (ctx);
-      CTX_DATA->status = 0;
+      idata->status = 0;
     }
   }
 
@@ -194,6 +191,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
 
 int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
 {
+  IMAP_DATA* idata;
   char buf[LONG_STRING];
   char path[_POSIX_PATH_MAX];
   char *pc;
@@ -201,10 +199,13 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   int uid;
   int cacheno;
   IMAP_CACHE *cache;
+  int rc;
+
+  idata = (IMAP_DATA*) ctx->data;
 
   /* see if we already have the message in our cache */
   cacheno = HEADER_DATA(ctx->hdrs[msgno])->uid % IMAP_CACHE_LEN;
-  cache = &CTX_DATA->cache[cacheno];
+  cache = &idata->cache[cacheno];
 
   if (cache->path)
   {
@@ -240,104 +241,102 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   snprintf (buf, sizeof (buf), "UID FETCH %d RFC822",
     HEADER_DATA(ctx->hdrs[msgno])->uid);
 
-  imap_cmd_start (CTX_DATA, buf);
+  imap_cmd_start (idata, buf);
   do
   {
-    if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
-      goto bail;
+    if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+      continue;
 
-    if (buf[0] == '*')
+    pc = idata->buf;
+    pc = imap_next_word (pc);
+    pc = imap_next_word (pc);
+    if (!mutt_strncasecmp ("FETCH", pc, 5))
     {
-      pc = buf;
-      pc = imap_next_word (pc);
-      pc = imap_next_word (pc);
-      if (mutt_strncasecmp ("FETCH", pc, 5) == 0)
+      while (*pc)
       {
-       while (*pc)
+       pc = imap_next_word (pc);
+       if (pc[0] == '(')
+         pc++;
+       if (strncasecmp ("UID", pc, 3) == 0)
        {
          pc = imap_next_word (pc);
-         if (pc[0] == '(')
-           pc++;
-         if (strncasecmp ("UID", pc, 3) == 0)
-         {
-           pc = imap_next_word (pc);
-           uid = atoi (pc);
-           if (uid != HEADER_DATA(ctx->hdrs[msgno])->uid)
-             mutt_error (_("The message index is incorrect. Try reopening the mailbox."));
-         }
-         else if (strncasecmp ("RFC822", pc, 6) == 0)
+         uid = atoi (pc);
+         if (uid != HEADER_DATA(ctx->hdrs[msgno])->uid)
+           mutt_error (_("The message index is incorrect. Try reopening the mailbox."));
+       }
+       else if (strncasecmp ("RFC822", pc, 6) == 0)
+       {
+         pc = imap_next_word (pc);
+         if (imap_get_literal_count(pc, &bytes) < 0)
          {
-           pc = imap_next_word (pc);
-           if (imap_get_literal_count(pc, &bytes) < 0)
-           {
-             imap_error ("imap_fetch_message()", buf);
-             goto bail;
-           }
-           if (imap_read_literal (msg->fp, CTX_DATA, bytes) < 0)
-             goto bail;
-           /* pick up trailing line */
-           if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
-             goto bail;
-           pc = buf;
+           imap_error ("imap_fetch_message()", buf);
+           goto bail;
          }
-          /* UW-IMAP will provide a FLAGS update here if the FETCH causes a
-           * change (eg from \Unseen to \Seen).
-           * Uncommitted changes in mutt take precedence. If we decide to
-           * incrementally update flags later, this won't stop us syncing */
-          else if ((strncasecmp ("FLAGS", pc, 5) == 0) &&
-            !ctx->hdrs[msgno]->changed)
-          {
-           IMAP_HEADER newh;
-            HEADER* h = ctx->hdrs[msgno];
-           unsigned char readonly;
-
-           memset (&newh, 0, sizeof (newh));
-           newh.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
-
-            dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n"));
-            if ((pc = msg_parse_flags (&newh, pc)) == NULL)
-             goto bail;
+         if (imap_read_literal (msg->fp, idata, bytes) < 0)
+           goto bail;
+         /* pick up trailing line */
+         if ((rc = imap_cmd_resp (idata)) != IMAP_CMD_CONTINUE)
+           goto bail;
+         pc = idata->buf;
+       }
+       /* UW-IMAP will provide a FLAGS update here if the FETCH causes a
+        * change (eg from \Unseen to \Seen).
+        * Uncommitted changes in mutt take precedence. If we decide to
+        * incrementally update flags later, this won't stop us syncing */
+       else if ((strncasecmp ("FLAGS", pc, 5) == 0) &&
+                !ctx->hdrs[msgno]->changed)
+       {
+         IMAP_HEADER newh;
+         HEADER* h = ctx->hdrs[msgno];
+         unsigned char readonly;
+
+         memset (&newh, 0, sizeof (newh));
+         newh.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
+
+         dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n"));
+         if ((pc = msg_parse_flags (&newh, pc)) == NULL)
+           goto bail;
              
-           /* this is less efficient than the code which used to be here,
-            * but (1) this is only invoked when fetching messages, and (2)
-            * this way, we can make sure that side effects of flag changes
-            * are taken account of the proper way.
-            */
-
-           /* YAUH (yet another ugly hack): temporarily set context to
-            * read-write even if it's read-only, so *server* updates of
-            * flags can be processed by mutt_set_flag. ctx->changed must
-            * be restored afterwards */
-           readonly = ctx->readonly;
-           ctx->readonly = 0;
+         /* this is less efficient than the code which used to be here,
+          * but (1) this is only invoked when fetching messages, and (2)
+          * this way, we can make sure that side effects of flag changes
+          * are taken account of the proper way.
+          */
+
+         /* YAUH (yet another ugly hack): temporarily set context to
+          * read-write even if it's read-only, so *server* updates of
+          * flags can be processed by mutt_set_flag. ctx->changed must
+          * be restored afterwards */
+         readonly = ctx->readonly;
+         ctx->readonly = 0;
            
-           mutt_set_flag (ctx, h, M_NEW, 
-                   !(newh.read || newh.old || h->read || h->old));
-           mutt_set_flag (ctx, h, M_OLD, newh.old);
-           mutt_set_flag (ctx, h, M_READ, h->read || newh.read);
-           mutt_set_flag (ctx, h, M_DELETE, h->deleted || newh.deleted);
-           mutt_set_flag (ctx, h, M_FLAG, h->flagged || newh.flagged);
-           mutt_set_flag (ctx, h, M_REPLIED, h->replied || newh.replied);
-
-            /* this message is now definitively *not* changed (mutt_set_flag
-             * marks things changed as a side-effect) */
-            h->changed = 0;
-           ctx->changed &= ~readonly;
-           ctx->readonly = readonly;
-
-            mutt_free_list (&(HEADER_DATA(h)->keywords));
-            HEADER_DATA(h)->keywords = newh.data->keywords;
-           FREE(&newh.data);
-          }
+         mutt_set_flag (ctx, h, M_NEW, 
+                        !(newh.read || newh.old || h->read || h->old));
+         mutt_set_flag (ctx, h, M_OLD, newh.old);
+         mutt_set_flag (ctx, h, M_READ, h->read || newh.read);
+         mutt_set_flag (ctx, h, M_DELETE, h->deleted || newh.deleted);
+         mutt_set_flag (ctx, h, M_FLAG, h->flagged || newh.flagged);
+         mutt_set_flag (ctx, h, M_REPLIED, h->replied || newh.replied);
+
+         /* this message is now definitively *not* changed (mutt_set_flag
+          * marks things changed as a side-effect) */
+         h->changed = 0;
+         ctx->changed &= ~readonly;
+         ctx->readonly = readonly;
+
+         mutt_free_list (&(HEADER_DATA(h)->keywords));
+         HEADER_DATA(h)->keywords = newh.data->keywords;
+         FREE(&newh.data);
        }
       }
-      else if (imap_handle_untagged (CTX_DATA, buf) != 0)
-       goto bail;
     }
   }
-  while (mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0);
+  while (rc == IMAP_CMD_CONTINUE);
 
-  if (!imap_code (buf))
+  if (rc != IMAP_CMD_DONE)
+    goto bail;
+
+  if (!imap_code (idata->buf))
     goto bail;
     
   /* Update the header information.  Previously, we only downloaded a
@@ -380,6 +379,7 @@ bail:
 
 int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
 {
+  IMAP_DATA* idata;
   FILE *fp;
   char buf[LONG_STRING];
   char mbox[LONG_STRING];
@@ -387,11 +387,14 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
   size_t len;
   int c, last;
   IMAP_MBOX mx;
+  int rc;
+
+  idata = (IMAP_DATA*) ctx->data;
 
   if (imap_parse_path (ctx->path, &mx))
-    return (-1);
+    return -1;
 
-  imap_fix_path (CTX_DATA, mx.mbox, mailbox, sizeof (mailbox));
+  imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
   
   if ((fp = fopen (msg->path, "r")) == NULL)
   {
@@ -411,31 +414,19 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
   imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
   snprintf (buf, sizeof (buf), "APPEND %s {%d}", mbox, len);
 
-  imap_cmd_start (CTX_DATA, buf);
-
-  do 
-  {
-    if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
-    {
-      fclose (fp);
-      return (-1);
-    }
+  imap_cmd_start (idata, buf);
 
-    if (buf[0] == '*' && imap_handle_untagged (CTX_DATA, buf) != 0)
-    {
-      fclose (fp);
-      return (-1);
-    }
-  }
-  while ((mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0) && (buf[0] != '+'));
+  do
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
 
-  if (buf[0] != '+')
+  if (rc != IMAP_CMD_RESPOND)
   {
     char *pc;
 
-    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf));
+    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf));
 
-    pc = buf + SEQLEN;
+    pc = idata->buf + SEQLEN;
     SKIPWS (pc);
     pc = imap_next_word (pc);
     mutt_error ("%s", pc);
@@ -454,31 +445,25 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
     buf[len++] = c;
 
     if (len > sizeof(buf) - 3)
-      flush_buffer(buf, &len, CTX_DATA->conn);
+      flush_buffer(buf, &len, idata->conn);
   }
   
   if (len)
-    flush_buffer(buf, &len, CTX_DATA->conn);
+    flush_buffer(buf, &len, idata->conn);
 
-  mutt_socket_write (CTX_DATA->conn, "\r\n");
+  mutt_socket_write (idata->conn, "\r\n");
   fclose (fp);
 
   do
-  {
-    if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn) < 0)
-      return (-1);
+    rc = imap_cmd_resp (idata);
+  while (rc == IMAP_CMD_CONTINUE);
 
-    if (buf[0] == '*' && imap_handle_untagged (CTX_DATA, buf) != 0)
-      return (-1);
-  }
-  while (mutt_strncmp (buf, CTX_DATA->seq, SEQLEN) != 0);
-
-  if (!imap_code (buf))
+  if (!imap_code (idata->buf))
   {
     char *pc;
 
-    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf));
-    pc = buf + SEQLEN;
+    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", idata->buf));
+    pc = idata->buf + SEQLEN;
     SKIPWS (pc);
     pc = imap_next_word (pc);
     mutt_error ("%s", pc);
@@ -497,6 +482,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
  *       1: non-fatal error - try fetch/append */
 int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
 {
+  IMAP_DATA* idata;
   char buf[HUGE_STRING];
   char cmd[LONG_STRING];
   char mbox[LONG_STRING];
@@ -505,6 +491,8 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
   int n;
   IMAP_MBOX mx;
 
+  idata = (IMAP_DATA*) ctx->data;
+
   if (imap_parse_path (dest, &mx))
   {
     dprint (1, (debugfile, "imap_copy_message: bad destination %s\n", dest));
@@ -519,12 +507,12 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
     return 1;
   }
 
-  imap_fix_path (CTX_DATA, mx.mbox, cmd, sizeof (cmd));
+  imap_fix_path (idata, mx.mbox, cmd, sizeof (cmd));
 
   /* Null HEADER* means copy tagged messages */
   if (!h)
   {
-    rc = imap_make_msg_set (CTX_DATA, buf, sizeof (buf), M_TAG, 0);
+    rc = imap_make_msg_set (idata, buf, sizeof (buf), M_TAG, 0);
     if (!rc)
     {
       dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n"));
@@ -542,13 +530,13 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
   strncpy (mbox, cmd, sizeof (mbox));
   imap_munge_mbox_name (mmbox, sizeof (mmbox), cmd);
   snprintf (cmd, sizeof (cmd), "UID COPY %s %s", buf, mmbox);
-  rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, IMAP_CMD_FAIL_OK);
+  rc = imap_exec (idata, cmd, IMAP_CMD_FAIL_OK);
   if (rc == -2)
   {
     /* bail out if command failed for reasons other than nonexistent target */
-    if (strncmp (imap_get_qualifier (buf), "[TRYCREATE]", 11))
+    if (strncmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11))
     {
-      imap_error ("imap_copy_messages", buf);
+      imap_error ("imap_copy_messages", idata->buf);
       return -1;
     }
     dprint (2, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n"));
@@ -562,11 +550,11 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
       return -1;
 
     /* try again */
-    rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, 0);
+    rc = imap_exec (idata, cmd, 0);
   }
   if (rc != 0)
   {
-    imap_error ("imap_copy_messages", buf);
+    imap_error ("imap_copy_messages", idata->buf);
     return -1;
   }
 
@@ -633,9 +621,12 @@ void imap_free_header_data (void** data)
  *     -2 if the string is a corrupt fetch response */
 static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp)
 {
+  IMAP_DATA* idata;
   long bytes;
   int rc = -1; /* default now is that string isn't FETCH response*/
 
+  idata = (IMAP_DATA*) ctx->data;
+
   if (buf[0] != '*')
     return rc;
   
@@ -660,17 +651,16 @@ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp)
   
   if (imap_get_literal_count (buf, &bytes) < 0)
     return rc;
-  imap_read_literal (fp, CTX_DATA, bytes);
+  imap_read_literal (fp, idata, bytes);
 
   /* we may have other fields of the FETCH _after_ the literal
    * (eg Domino puts FLAGS here). Nothing wrong with that, either.
    * This all has to go - we should accept literals and nonliterals
    * interchangeably at any time. */
-  if (mutt_socket_readln (buf, sizeof (buf), CTX_DATA->conn)
-      < 0)
-    return rc;
-
-  if (msg_parse_fetch (h, buf) == -1)
+  if (imap_cmd_resp (idata) != IMAP_CMD_CONTINUE)
+    return -2;
+  
+  if (msg_parse_fetch (h, idata->buf) == -1)
     return rc;
 
   rc = 0; /* success */
index 12dc8f455ec128a03f1cbea4260a265e60c346d9..1470450879c6b57bfbb5c48208de4d2af50df5bf 100644 (file)
@@ -110,13 +110,14 @@ int mutt_socket_readln_d (char* buf, size_t buflen, CONNECTION* conn, int dbg)
 
   /* strip \r from \r\n termination */
   if (i && buf[i-1] == '\r')
-    buf[i-1] = '\0';
+    buf[--i] = '\0';
   else
     buf[i] = '\0';
 
   dprint (dbg, (debugfile, "< %s\n", buf));
   
-  return i+1;
+  /* number of bytes read, not strlen */
+  return i + 1;
 }
 
 CONNECTION* mutt_socket_head (void)