]> granicus.if.org Git - mutt/commitdiff
Brandon's IMAP patch.
authorThomas Roessler <roessler@does-not-exist.org>
Mon, 15 Jun 1998 15:19:45 +0000 (15:19 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Mon, 15 Jun 1998 15:19:45 +0000 (15:19 +0000)
commands.c
imap.c
mailbox.h
main.c
mx.c

index da508df92eb4844408b9e0c8d52c386bb7c13b2e..0144238f7ef7905d4e2044f7466e8a8405039245 100644 (file)
@@ -511,10 +511,13 @@ static int save_confirm_func (const char *s, struct stat *st)
 {
   char tmp[_POSIX_PATH_MAX];
   int ret = 1;
+  int magic = 0;
+
+  magic = mx_get_magic (s);
 
   if (stat (s, st) != -1)
   {
-    if (mx_get_magic (s) == -1)
+    if (magic == -1)
     {
       mutt_error ("%s is not a mailbox!", s);
       return 0;
@@ -529,22 +532,25 @@ static int save_confirm_func (const char *s, struct stat *st)
   }
   else
   {
-    st->st_mtime = 0;
-    st->st_atime = 0;
-    
-    if (errno == ENOENT)
+    if (magic != M_IMAP)
     {
-      if (option (OPTCONFIRMCREATE))
+      st->st_mtime = 0;
+      st->st_atime = 0;
+
+      if (errno == ENOENT)
       {
-       snprintf (tmp, sizeof (tmp), "Create %s?", s);
-       if (mutt_yesorno (tmp, 1) < 1)
-         ret = 0;
+       if (option (OPTCONFIRMCREATE))
+       {
+         snprintf (tmp, sizeof (tmp), "Create %s?", s);
+         if (mutt_yesorno (tmp, 1) < 1)
+           ret = 0;
+       }
+      }
+      else
+      {
+       mutt_perror (s);
+       return 0;
       }
-    }
-    else
-    {
-      mutt_perror (s);
-      return 0;
     }
   }
 
diff --git a/imap.c b/imap.c
index 619482c75e1dbedbde1f850dd39f96fb567b22c5..872e019b16b0237bb936f227b5276bb1ded71929 100644 (file)
--- a/imap.c
+++ b/imap.c
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 
 /* Minimal support for IMAP 4rev1 */
 
@@ -45,9 +46,21 @@ enum
   IMAP_FATAL = 1,
   IMAP_NEW_MAIL,
   IMAP_EXPUNGE,
-  IMAP_BYE
+  IMAP_BYE,
+  IMAP_OK_FAIL,
+  IMAP_OPEN_NEW
 };
 
+typedef struct
+{
+  char *server;
+  int uses;
+  int fd;
+  char inbuf[LONG_STRING];
+  int bufpos;
+  int available;
+} CONNECTION;
+
 typedef struct
 {
   int index;
@@ -59,36 +72,40 @@ typedef struct
   short status;
   unsigned short sequence;
   unsigned short newMailCount;
+  char *mailbox;
   short xxx;
   IMAP_CACHE cache[IMAP_CACHE_LEN];
+  CONNECTION *conn;
 } IMAP_DATA;
 
+#define CTX_DATA ((IMAP_DATA *) ctx->data)
+
+static CONNECTION *Connections = NULL;
+static int NumConnections = 0;
+
 /* simple read buffering to speed things up. */
-static int imap_readchar (int fd, char *c)
+static int imap_readchar (CONNECTION *conn, char *c)
 {
-  static char inbuf[LONG_STRING];
-  static int bufpos=0, available=0;
-  
-  if (bufpos>=available)
-  {
-    available = read (fd, inbuf, sizeof(inbuf));
-    bufpos = 0;
-    if (available <= 0)
-      return available; /* returns 0 for EOF or -1 for other error */
-  }
-  *c = inbuf[bufpos];
-  bufpos++;
+  if (conn->bufpos >= conn->available)
+  {
+    conn->available = read (conn->fd, conn->inbuf, sizeof(LONG_STRING));
+    conn->bufpos = 0;
+    if (conn->available <= 0)
+      return conn->available; /* returns 0 for EOF or -1 for other error */
+  }
+  *c = conn->inbuf[conn->bufpos];
+  conn->bufpos++;
   return 1;
 }
 
-static int imap_read_line (char *buf, size_t buflen, int fd)
+static int imap_read_line (char *buf, size_t buflen, CONNECTION *conn)
 {
   char ch;
   int i;
 
   for (i = 0; i < buflen; i++)
   {
-    if (imap_readchar (fd, &ch) != 1)
+    if (imap_readchar (conn, &ch) != 1)
       return (-1);
     if (ch == '\n')
       break;
@@ -98,22 +115,22 @@ static int imap_read_line (char *buf, size_t buflen, int fd)
   return (i + 1);
 }
 
-static int imap_read_line_d (char *buf, size_t buflen, int fd)
+static int imap_read_line_d (char *buf, size_t buflen, CONNECTION *conn)
 {
-  int r = imap_read_line (buf, buflen, fd);
+  int r = imap_read_line (buf, buflen, conn);
   dprint (1,(debugfile,"imap_read_line_d():%s\n", buf));
   return r;
 }
 
 static void imap_make_sequence (char *buf, size_t buflen, CONTEXT *ctx)
 {
-  snprintf (buf, buflen, "a%04d", ((IMAP_DATA *) ctx->data)->sequence++);
+  snprintf (buf, buflen, "a%04d", CTX_DATA->sequence++);
 }
 
-static int imap_write (int fd, const char *buf)
+static int imap_write (CONNECTION *conn, const char *buf)
 {
   dprint (1,(debugfile,"imap_write():%s", buf));
-  return (write (fd, buf, strlen (buf)));
+  return (write (conn->fd, buf, strlen (buf)));
 }
 
 static void imap_error (const char *where, const char *msg)
@@ -121,13 +138,43 @@ static void imap_error (const char *where, const char *msg)
   dprint (1, (debugfile, "imap_error(): unexpected response in %s: %s\n", where, msg));
 }
 
+static CONNECTION *imap_select_connection (char *host, int flags)
+{
+  int x;
+
+  if (flags != IMAP_OPEN_NEW)
+  {
+    for (x = 0; x < NumConnections; x++)
+    {
+      if (!strcmp (host, Connections[x].server))
+       return &Connections[x];
+    }
+  }
+  if (NumConnections == 0)
+  {
+    NumConnections = 1;
+    Connections = (CONNECTION *) safe_malloc (sizeof (CONNECTION));
+  }
+  else
+  {
+    NumConnections++;
+    safe_realloc ((void *)Connections, sizeof (CONNECTION) * NumConnections);
+  }
+  Connections[NumConnections - 1].bufpos = 0;
+  Connections[NumConnections - 1].available = 0;
+  Connections[NumConnections - 1].uses = 0;
+  Connections[NumConnections - 1].server = safe_strdup (host);
+
+  return &Connections[NumConnections - 1];
+}
+
 /* date is of the form: DD-MMM-YYYY HH:MM:SS +ZZzz */
 static time_t imap_parse_date (char *s)
 {
   struct tm t;
   time_t tz;
 
-  t.tm_mday = (s[0] - '0') * 10 + (s[1] - '0');
+  t.tm_mday = (s[0] == ' '? s[1] - '0' : (s[0] - '0') * 10 + (s[1] - '0'));  
   s += 2;
   if (*s != '-')
     return 0;
@@ -200,6 +247,7 @@ static int imap_parse_fetch (HEADER *h, char *s)
          /* we're about to get a new set of headers, so clear the old ones. */
          h->deleted=0; h->flagged=0;
          h->replied=0; h->read=0;
+         h->changed=0;
          s++;
          state = 1;
        }
@@ -230,7 +278,7 @@ static int imap_parse_fetch (HEADER *h, char *s)
          while (isdigit (*s))
            *ptmp++ = *s++;
          *ptmp = 0;
-         h->content->length = atoi (tmp);
+         h->content->length += atoi (tmp);
        }
        else if (*s == ')')
          s++; /* end of request */
@@ -278,7 +326,7 @@ static int imap_parse_fetch (HEADER *h, char *s)
   return 0;
 }
 
-static int imap_read_bytes (FILE *fp, int fd, long bytes)
+static int imap_read_bytes (FILE *fp, CONNECTION *conn, long bytes)
 {
   long pos;
   long len;
@@ -286,7 +334,7 @@ static int imap_read_bytes (FILE *fp, int fd, long bytes)
 
   for (pos = 0; pos < bytes; )
   {
-    len = imap_read_line (buf, sizeof (buf), fd);
+    len = imap_read_line (buf, sizeof (buf), conn);
     if (len < 0)
       return (-1);
     pos += len;
@@ -331,29 +379,28 @@ static int imap_handle_untagged (CONTEXT *ctx, char *s)
       /* new mail arrived */
       count = atoi (pn);
 
-      if (((IMAP_DATA *) ctx->data)->status != IMAP_EXPUNGE) { 
-       if (count <= ctx->msgcount)
-        {
-         /* something is wrong because the server reported fewer messages
-          * than we previously saw
-          */
-         mutt_error ("Fatal error.  Message count is out of sync!");
-         ((IMAP_DATA *) ctx->data)->status = IMAP_FATAL;
-         mx_fastclose_mailbox (ctx);
-         return (-1);
-        }
-        else
-        {
-         ((IMAP_DATA *) ctx->data)->status = IMAP_NEW_MAIL;
-         ((IMAP_DATA *) ctx->data)->newMailCount = count;
-        }
-      }      
+      if ( (CTX_DATA->status != IMAP_EXPUNGE) && 
+       count <= ctx->msgcount)
+      {
+       /* something is wrong because the server reported fewer messages
+        * than we previously saw
+        */
+       mutt_error ("Fatal error.  Message count is out of sync!");
+       CTX_DATA->status = IMAP_FATAL;
+       mx_fastclose_mailbox (ctx);
+       return (-1);
+      }
+      else
+      {
+       CTX_DATA->status = IMAP_NEW_MAIL;
+       CTX_DATA->newMailCount = count;
+      }
     }
     else if (strncasecmp ("EXPUNGE", s, 7) == 0)
     {
       /* a message was removed; reindex remaining messages     */
       /* (which amounts to decrementing indices of messages    */
-      /* with an index greater than the deleted one.           */
+      /* with an index greater than the deleted one.)          */
       ind = atoi (pn) - 1;
       for (n = 0; n < ctx->msgcount; n++)
         if (ctx->hdrs[n]->index > ind)
@@ -366,7 +413,7 @@ static int imap_handle_untagged (CONTEXT *ctx, char *s)
     s += 3;
     SKIPWS (s);
     mutt_error (s);
-    ((IMAP_DATA *) ctx->data)->status = IMAP_BYE;
+    CTX_DATA->status = IMAP_BYE;
     mx_fastclose_mailbox (ctx);
     return (-1);
   }
@@ -387,7 +434,7 @@ static int imap_read_header (CONTEXT *ctx, int msgno)
   char seq[8];
   char *pc;
   char *pn;
-  long bytes;
+  long bytes = 0;
 
   ctx->hdrs[ctx->msgcount]->index = ctx->msgcount;
 
@@ -399,11 +446,11 @@ static int imap_read_header (CONTEXT *ctx, int msgno)
 
   imap_make_sequence (seq, sizeof (seq), ctx);
   snprintf (buf, sizeof (buf), "%s FETCH %d RFC822.HEADER\r\n", seq, msgno + 1);
-  imap_write (ctx->fd, buf);
+  imap_write (CTX_DATA->conn, buf);
 
   do
   {
-    if (imap_read_line (buf, sizeof (buf), ctx->fd) < 0)
+    if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
     {
       return (-1);
     }
@@ -427,7 +474,7 @@ static int imap_read_header (CONTEXT *ctx, int msgno)
        *pc = 0;
        bytes = atoi (pn);
 
-       imap_read_bytes (fp, ctx->fd, bytes);
+       imap_read_bytes (fp, CTX_DATA->conn, bytes);
       }
       else if (imap_handle_untagged (ctx, buf) != 0)
          return (-1);
@@ -438,16 +485,19 @@ static int imap_read_header (CONTEXT *ctx, int msgno)
   rewind (fp);
   ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno]);
 
+/* subtract the header length; the total message size will be added to this */
+  ctx->hdrs[msgno]->content->length = -bytes;
+
   fclose (fp);
   unlink (tempfile);
 
   /* get the status of this message */
   imap_make_sequence (seq, sizeof (seq), ctx);
   snprintf (buf, sizeof (buf), "%s FETCH %d FAST\r\n", seq, msgno + 1);
-  imap_write (ctx->fd, buf);
+  imap_write (CTX_DATA->conn, buf);
   do
   {
-    if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0)
+    if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
       break;
     if (buf[0] == '*')
     {
@@ -475,15 +525,15 @@ static int imap_read_header (CONTEXT *ctx, int msgno)
 }
 
 static int imap_exec (char *buf, size_t buflen,
-                     CONTEXT *ctx, const char *seq, const char *cmd)
+                     CONTEXT *ctx, const char *seq, const char *cmd, int flags)
 {
   int count;
 
-  imap_write (ctx->fd, cmd);
+  imap_write (CTX_DATA->conn, cmd);
 
   do
   {
-    if (imap_read_line_d (buf, buflen, ctx->fd) < 0)
+    if (imap_read_line_d (buf, buflen, CTX_DATA->conn) < 0)
       return (-1);
 
     if (buf[0] == '*' && imap_handle_untagged (ctx, buf) != 0)
@@ -491,16 +541,16 @@ static int imap_exec (char *buf, size_t buflen,
   }
   while (strncmp (buf, seq, SEQLEN) != 0);
 
-  if (((IMAP_DATA *) ctx->data)->status == IMAP_NEW_MAIL)
+  if (CTX_DATA->status == IMAP_NEW_MAIL)
   {
     /* read new mail messages */
 
     dprint (1, (debugfile, "imap_exec(): new mail detected\n"));
     mutt_message ("Fetching headers for new mail...");
 
-    ((IMAP_DATA *) ctx->data)->status = 0;
+    CTX_DATA->status = 0;
 
-    count = ((IMAP_DATA *) ctx->data)->newMailCount;
+    count = CTX_DATA->newMailCount;
     while (count > ctx->hdrmax)
       mx_alloc_memory (ctx);
 
@@ -513,12 +563,12 @@ static int imap_exec (char *buf, size_t buflen,
       /* check to make sure that new mail hasn't arrived in the middle of
        * checking for new mail (sigh)
        */
-      if (((IMAP_DATA *) ctx->data)->status == IMAP_NEW_MAIL)
+      if (CTX_DATA->status == IMAP_NEW_MAIL)
       {
-       count = ((IMAP_DATA *) ctx->data)->newMailCount;
+       count = CTX_DATA->newMailCount;
        while (count > ctx->hdrmax)
          mx_alloc_memory (ctx);
-       ((IMAP_DATA *) ctx->data)->status = 0;
+       CTX_DATA->status = 0;
       }
     }
 
@@ -529,6 +579,8 @@ static int imap_exec (char *buf, size_t buflen,
   {
     char *pc;
 
+    if (flags == IMAP_OK_FAIL)
+      return (-1);
     dprint (1, (debugfile, "imap_exec(): command failed: %s\n", buf));
     pc = buf + SEQLEN;
     SKIPWS (pc);
@@ -541,31 +593,14 @@ static int imap_exec (char *buf, size_t buflen,
   return 0;
 }
 
-int imap_open_mailbox (CONTEXT *ctx)
+static int imap_open_connection (CONTEXT *ctx, CONNECTION *conn)
 {
   struct sockaddr_in sin;
   struct hostent *he;
   char buf[LONG_STRING];
-  char bufout[LONG_STRING];
-  char host[SHORT_STRING];
   char user[SHORT_STRING];
   char pass[SHORT_STRING];
-  char mailbox[_POSIX_PATH_MAX];
   char seq[16];
-  int count = 0;
-  int n;
-  char *pc;
-
-  if (ctx->path[0] != '{')
-    return (-1);
-  for(n = 0, pc = ctx->path + 1; *pc && *pc != '}' && n < sizeof(host) - 1; 
-      n++, pc++)
-    host[n++] = *pc++;
-  if(*pc != '}')
-    return -1;
-  host[n] = 0;
-  pc++;
-  strfcpy (mailbox, pc, sizeof (mailbox));
 
   if (!ImapUser)
   {
@@ -583,7 +618,7 @@ int imap_open_mailbox (CONTEXT *ctx)
   if (!ImapPass)
   {
     pass[0]=0;
-    snprintf (buf, sizeof (buf), "Password for %s@%s: ", user, host);
+    snprintf (buf, sizeof (buf), "Password for %s@%s: ", user, conn->server);
     if (mutt_get_field (buf, pass, sizeof (pass), M_PASS) != 0 ||
         !pass[0])
     {
@@ -596,53 +631,48 @@ int imap_open_mailbox (CONTEXT *ctx)
   memset (&sin, 0, sizeof (sin));
   sin.sin_port = htons (IMAP_PORT);
   sin.sin_family = AF_INET;
-  if ((he = gethostbyname (host)) == NULL)
+  if ((he = gethostbyname (conn->server)) == NULL)
   {
-    mutt_perror (host);
+    mutt_perror (conn->server);
     return (-1);
   }
   memcpy (&sin.sin_addr, he->h_addr_list[0], he->h_length);
 
-  if ((ctx->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
+  if ((conn->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
   {
     mutt_perror ("socket");
     return (-1);
   }
 
-  mutt_message ("Connecting to %s...", host);
+  mutt_message ("Connecting to %s...", conn->server);
 
-  if (connect (ctx->fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
+  if (connect (conn->fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
   {
     mutt_perror ("connect");
-    close (ctx->fd);
+    close (conn->fd);
   }
 
-  if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0)
+  if (imap_read_line_d (buf, sizeof (buf), conn) < 0)
   {
-    close (ctx->fd);
+    close (conn->fd);
     return (-1);
   }
 
   if (strncmp ("* OK", buf, 4) != 0)
   {
-    imap_error ("imap_open_mailbox()", buf);
-    close (ctx->fd);
+    imap_error ("imap_open_connection()", buf);
+    close (conn->fd);
     return (-1);
   }
 
-  /* create IMAP-specific state struct */
-  ctx->data = safe_malloc (sizeof (IMAP_DATA));
-  memset (ctx->data, 0, sizeof (IMAP_DATA));
-
   mutt_message ("Logging in...");
-  imap_make_sequence (seq, sizeof (seq), ctx);
+  /* sequence numbers are currently context dependent, so just make one
+   * up for this first access to the server */
+  strcpy (seq, "l0000");
   snprintf (buf, sizeof (buf), "%s LOGIN %s %s\r\n", seq, user, pass);
-  if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0)
+  if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0)
   {
-    /* Most likely an invalid login; clear username and password for re-entry. */
-    FREE (&ImapUser);
-    FREE (&ImapPass);
-    imap_error ("imap_open_mailbox()", buf);
+    imap_error ("imap_open_connection()", buf);
     return (-1);
   }
   /* If they have a successful login, we may as well cache the user/password. */
@@ -651,14 +681,54 @@ int imap_open_mailbox (CONTEXT *ctx)
   if (!ImapPass)
     ImapPass = safe_strdup (pass);
 
-  mutt_message ("Selecting %s...", mailbox);
+  return 0;
+}
+
+int imap_open_mailbox (CONTEXT *ctx)
+{
+  CONNECTION *conn;
+  char buf[LONG_STRING];
+  char bufout[LONG_STRING];
+  char host[SHORT_STRING];
+  char seq[16];
+  int count = 0;
+  int n;
+  char *pc;
+
+  /* create IMAP-specific state struct */
+  ctx->data = safe_malloc (sizeof (IMAP_DATA));
+  memset (ctx->data, 0, sizeof (IMAP_DATA));
+
+  pc = ctx->path;
+  if (*pc != '{')
+    return (-1);
+  pc++;
+  n = 0;
+  while (*pc && *pc != '}')
+    host[n++] = *pc++;
+  host[n] = 0;
+  if (!*pc)
+    return (-1);
+  pc++;
+
+  CTX_DATA->mailbox = safe_strdup (pc);
+
+  conn = imap_select_connection (host, IMAP_OPEN_NEW);
+  CTX_DATA->conn = conn;
+
+  if (conn->uses == 0)
+    if (imap_open_connection (ctx, conn))
+      return (-1);
+  conn->uses++;
+
+  mutt_message ("Selecting %s...", CTX_DATA->mailbox);
   imap_make_sequence (seq, sizeof (seq), ctx);
-  snprintf (bufout, sizeof (bufout), "%s SELECT %s\r\n", seq, mailbox);
-  imap_write (ctx->fd, bufout);
+  snprintf (bufout, sizeof (bufout), "%s SELECT %s\r\n", seq, CTX_DATA->mailbox);
+  imap_write (CTX_DATA->conn, bufout);
 
   do
   {
-    if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0)
+    if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
       break;
 
     if (buf[0] == '*')
@@ -704,18 +774,89 @@ int imap_open_mailbox (CONTEXT *ctx)
     mx_update_context (ctx); /* increments ->msgcount */
 
     /* in case we get new mail while fetching the headers */
-    if (((IMAP_DATA *) ctx->data)->status == IMAP_NEW_MAIL)
+    if (CTX_DATA->status == IMAP_NEW_MAIL)
     {
-      count = ((IMAP_DATA *) ctx->data)->newMailCount;
+      count = CTX_DATA->newMailCount;
       while (count > ctx->hdrmax)
        mx_alloc_memory (ctx);
-      ((IMAP_DATA *) ctx->data)->status = 0;
+      CTX_DATA->status = 0;
     }
   }
 
   return 0;
 }
 
+static int imap_create_mailbox (CONTEXT *ctx)
+{
+  char seq[8];
+  char buf[LONG_STRING];
+
+  imap_make_sequence (seq, sizeof (seq), ctx);
+  snprintf (buf, sizeof (buf), "%s CREATE %s\r\n", seq, CTX_DATA->mailbox);
+      
+  if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0)
+  {
+    imap_error ("imap_sync_mailbox()", buf);
+    return (-1);
+  }
+  return 0;
+}
+
+int imap_open_mailbox_append (CONTEXT *ctx)
+{
+  CONNECTION *conn;
+  char host[SHORT_STRING];
+  char buf[LONG_STRING];
+  char seq[16];
+  int n;
+  char *pc;
+
+  /* create IMAP-specific state struct */
+  ctx->data = safe_malloc (sizeof (IMAP_DATA));
+  memset (ctx->data, 0, sizeof (IMAP_DATA));
+
+  pc = ctx->path;
+  if (*pc != '{')
+    return (-1);
+  pc++;
+  n = 0;
+  while (*pc && *pc != '}')
+    host[n++] = *pc++;
+  host[n] = 0;
+  if (!*pc)
+    return (-1);
+  pc++;
+
+  CTX_DATA->mailbox = pc;
+
+  conn = imap_select_connection (host, 0);
+  CTX_DATA->conn = conn;
+
+  if (conn->uses == 0)
+    if (imap_open_connection (ctx, conn))
+      return (-1);
+  conn->uses++;
+
+  /* check mailbox existance */
+
+  imap_make_sequence (seq, sizeof (seq), ctx);
+  snprintf (buf, sizeof (buf), "%s STATUS %s (UIDVALIDITY)\r\n", seq, 
+      CTX_DATA->mailbox);
+      
+  if (imap_exec (buf, sizeof (buf), ctx, seq, buf, IMAP_OK_FAIL) != 0)
+  {
+    if (option (OPTCONFIRMCREATE))
+    {
+      snprintf (buf, sizeof (buf), "Create %s?", CTX_DATA->mailbox);
+      if (mutt_yesorno (buf, 1) < 1)
+       return (-1);
+      if (imap_create_mailbox (ctx) < 0)
+       return (-1);
+    }
+  }
+  return 0;
+}
+
 int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
 {
   char seq[8];
@@ -727,7 +868,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   IMAP_CACHE *cache;
 
   /* see if we already have the message in our cache */
-  cache = &((IMAP_DATA *) ctx->data)->cache[ctx->hdrs[msgno]->index % IMAP_CACHE_LEN];
+  cache = &CTX_DATA->cache[ctx->hdrs[msgno]->index % IMAP_CACHE_LEN];
 
   if (cache->path)
   {
@@ -763,10 +904,10 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   imap_make_sequence (seq, sizeof (seq), ctx);
   snprintf (buf, sizeof (buf), "%s FETCH %d RFC822\r\n", seq,
            ctx->hdrs[msgno]->index + 1);
-  imap_write (ctx->fd, buf);
+  imap_write (CTX_DATA->conn, buf);
   do
   {
-    if (imap_read_line (buf, sizeof (buf), ctx->fd) < 0)
+    if (imap_read_line (buf, sizeof (buf), CTX_DATA->conn) < 0)
     {
       return (-1);
     }
@@ -789,7 +930,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
          pc++;
        *pc = 0;
        bytes = atoi (pn);
-       imap_read_bytes (msg->fp, ctx->fd, bytes);
+       imap_read_bytes (msg->fp, CTX_DATA->conn, bytes);
       }
       else if (imap_handle_untagged (ctx, buf) != 0)
        return (-1);
@@ -806,27 +947,119 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   return 0;
 }
 
+int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
+{
+  FILE *fp;
+  struct stat s;
+  char seq[8];
+  char buf[LONG_STRING];
+
+  if (stat (msg->path, &s) == -1)
+  {
+    mutt_perror (msg->path);
+    return (-1);
+  }
+
+  if ((fp = safe_fopen (msg->path, "r")) == NULL)
+  {
+    mutt_perror (msg->path);
+    return (-1);
+  }
+
+  mutt_message ("Sending APPEND command ...");
+  imap_make_sequence (seq, sizeof (seq), ctx);
+  snprintf (buf, sizeof (buf), "%s APPEND %s {%d}\r\n", seq, 
+      CTX_DATA->mailbox, s.st_size);
+
+  imap_write (CTX_DATA->conn, buf);
+
+  do 
+  {
+    if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
+    {
+      fclose (fp);
+      return (-1);
+    }
+
+    if (buf[0] == '*' && imap_handle_untagged (ctx, buf) != 0)
+    {
+      return (-1);
+      fclose (fp);
+    }
+  }
+  while ((strncmp (buf, seq, SEQLEN) != 0) && (buf[0] != '+'));
+
+  if (buf[0] != '+')
+  {
+    char *pc;
+
+    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf));
+
+    pc = buf + SEQLEN;
+    SKIPWS (pc);
+    pc = imap_next_word (pc);
+    mutt_error (pc);
+    sleep (1);
+    fclose (fp);
+    return (-1);
+  }
+
+  mutt_message ("Uploading message ...");
+  while (fgets (buf, sizeof (buf), fp) != NULL)
+  {
+    imap_write (CTX_DATA->conn, buf);
+  }
+  imap_write (CTX_DATA->conn, "\r\n");
+  fclose (fp);
+
+  do
+  {
+    if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
+      return (-1);
+
+    if (buf[0] == '*' && imap_handle_untagged (ctx, buf) != 0)
+      return (-1);
+  }
+  while (strncmp (buf, seq, SEQLEN) != 0);
+
+  if (!imap_code (buf))
+  {
+    char *pc;
+
+    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n", buf));
+    pc = buf + SEQLEN;
+    SKIPWS (pc);
+    pc = imap_next_word (pc);
+    mutt_error (pc);
+    sleep (1);
+    return (-1);
+  }
+
+  return 0;
+}
+
 int imap_close_connection (CONTEXT *ctx)
 {
   char buf[LONG_STRING];
   char seq[8];
 
   /* if the server didn't shut down on us, close the connection gracefully */
-  if (((IMAP_DATA *) ctx->data)->status != IMAP_BYE)
+  if (CTX_DATA->status != IMAP_BYE)
   {
     mutt_message ("Closing connection to IMAP server...");
     imap_make_sequence (seq, sizeof (seq), ctx);
     snprintf (buf, sizeof (buf), "%s LOGOUT\r\n", seq);
-    imap_write (ctx->fd, buf);
+    imap_write (CTX_DATA->conn, buf);
     do
     {
-      if (imap_read_line_d (buf, sizeof (buf), ctx->fd) < 0)
+      if (imap_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
        break;
     }
     while (strncmp (seq, buf, SEQLEN) != 0);
     mutt_clear_error ();
   }
-  close (ctx->fd);
+  close (CTX_DATA->conn->fd);
+  CTX_DATA->conn->uses--;
   return 0;
 }
 
@@ -840,11 +1073,11 @@ int imap_sync_mailbox (CONTEXT *ctx)
   /* save status changes */
   for (n = 0; n < ctx->msgcount; n++)
   {
-    snprintf (tmp, sizeof (tmp), "Saving message status flags... [%d/%d]", n+1, 
-      ctx->msgcount);
-    mutt_message (tmp);
     if (ctx->hdrs[n]->deleted || ctx->hdrs[n]->changed)
     {
+      snprintf (tmp, sizeof (tmp), "Saving message status flags... [%d/%d]", n+1, 
+        ctx->msgcount);
+      mutt_message (tmp);
       *tmp = 0;
       if (ctx->hdrs[n]->read)
        strcat (tmp, "\\Seen ");
@@ -860,7 +1093,7 @@ int imap_sync_mailbox (CONTEXT *ctx)
       imap_make_sequence (seq, sizeof (seq), ctx);
       snprintf (buf, sizeof (buf), "%s STORE %d FLAGS.SILENT (%s)\r\n", seq, 
        ctx->hdrs[n]->index + 1, tmp);
-      if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0)
+      if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0)
       {
        imap_error ("imap_sync_mailbox()", buf);
        return (-1);
@@ -869,17 +1102,25 @@ int imap_sync_mailbox (CONTEXT *ctx)
   }
 
   mutt_message ("Expunging messages from server...");
-  ((IMAP_DATA *) ctx->data)->status = IMAP_EXPUNGE;
+  CTX_DATA->status = IMAP_EXPUNGE;
   imap_make_sequence (seq, sizeof (seq), ctx);
   snprintf (buf, sizeof (buf), "%s EXPUNGE\r\n", seq);
-  if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0)
+  if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0)
   {
     imap_error ("imap_sync_mailbox()", buf);
     return (-1);
   }
-  ((IMAP_DATA *) ctx->data)->status = 0;
-  /* WARNING: Messages need to be reindexed at this point after the expunge, or */
-  /* mutt will become -very- confused unless it's quitting. */
+  CTX_DATA->status = 0;
+
+  for (n = 0; n < IMAP_CACHE_LEN; n++)
+  {
+    if (CTX_DATA->cache[n].path)
+    {
+      unlink (CTX_DATA->cache[n].path);
+      safe_free ((void **) &CTX_DATA->cache[n].path);
+    }
+  }
+
   return 0;
 }
 
@@ -887,13 +1128,16 @@ void imap_fastclose_mailbox (CONTEXT *ctx)
 {
   int i;
 
+  /* Check to see if the mailbox is actually open */
+  if (!ctx->data)
+    return;
   imap_close_connection (ctx);
   for (i = 0; i < IMAP_CACHE_LEN; i++)
   {
-    if (((IMAP_DATA *) ctx->data)->cache[i].path)
+    if (CTX_DATA->cache[i].path)
     {
-      unlink (((IMAP_DATA *) ctx->data)->cache[i].path);
-      safe_free ((void **) &((IMAP_DATA *) ctx->data)->cache[i].path);
+      unlink (CTX_DATA->cache[i].path);
+      safe_free ((void **) &CTX_DATA->cache[i].path);
     }
   }
   safe_free ((void **) &ctx->data);
@@ -909,7 +1153,7 @@ int imap_close_mailbox (CONTEXT *ctx)
   mutt_message ("Closing mailbox...");
   imap_make_sequence (seq, sizeof (seq), ctx);
   snprintf (buf, sizeof (buf), "%s CLOSE\r\n", seq);
-  if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0)
+  if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0)
   {
     imap_error ("imap_close_mailbox()", buf);
     return (-1);
@@ -934,7 +1178,7 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint)
 
   imap_make_sequence (seq, sizeof (seq), ctx);
   snprintf (buf, sizeof (buf), "%s NOOP\r\n", seq);
-  if (imap_exec (buf, sizeof (buf), ctx, seq, buf) != 0)
+  if (imap_exec (buf, sizeof (buf), ctx, seq, buf, 0) != 0)
   {
     imap_error ("imap_check_mailbox()", buf);
     return (-1);
index ad9d841722a8ea4383e8914c3d88279a9a6bc3f1..44b227ce7537beefd9ab01dab835e47944746d0f 100644 (file)
--- a/mailbox.h
+++ b/mailbox.h
@@ -37,6 +37,7 @@ typedef struct
 {
   FILE *fp;    /* pointer to the message data */
 #ifdef USE_IMAP
+  CONTEXT *ctx;        /* context (mailbox) for this message */
   char *path;  /* path to temp file */
 #endif /* USE_IMAP */
   short magic; /* type of mailbox this message belongs to */
diff --git a/main.c b/main.c
index 2bea7ce7524fba2b03a006340e727cc41b8ab63f..4d1cce3cf81545d4fd29f1ca957f0b102e870296 100644 (file)
--- a/main.c
+++ b/main.c
@@ -210,9 +210,9 @@ static void show_version (void)
 
 
 #ifdef BUFFY_SIZE
-       "+BUFFY_SIZE"
+       "+BUFFY_SIZE "
 #else
-       "-BUFFY_SIZE"
+       "-BUFFY_SIZE "
 #endif
        );
   puts (
diff --git a/mx.c b/mx.c
index a1b93c53f1c7941204b6da6b27565d5de59aad38..b996404416c16fe587e7becd10b60fec5c5ff2c9 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -468,9 +468,18 @@ int mx_set_magic (const char *s)
 static int mx_open_mailbox_append (CONTEXT *ctx)
 {
   ctx->append = 1;
+  ctx->magic = mx_get_magic (ctx->path);
+
+#ifdef USE_IMAP
+  if (ctx->magic == M_IMAP)
+  {
+    return imap_open_mailbox_append (ctx);
+  }
+  else
+#endif
   if (access (ctx->path, W_OK) == 0)
   {
-    switch (ctx->magic = mx_get_magic (ctx->path))
+    switch (ctx->magic)
     {
       case 0:
        mutt_error ("%s is not a mailbox.", ctx->path);
@@ -1082,6 +1091,20 @@ int mbox_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr)
   return 0;
 }
 
+#ifdef USE_IMAP
+int imap_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr)
+{
+  char tmp[_POSIX_PATH_MAX];
+
+  mutt_mktemp(tmp);
+  if ((msg->fp = safe_fopen (tmp, "w")) == NULL)
+    return (-1);
+  msg->path = safe_strdup(tmp);
+  msg->ctx = dest;
+  return 0;
+}
+#endif
+
 /* args:
  *     dest    destintation mailbox
  *     hdr     message being copied (required for maildir support, because
@@ -1106,6 +1129,11 @@ MESSAGE *mx_open_new_message (CONTEXT *dest, HEADER *hdr, int flags)
     case M_MH:
       func = mh_open_new_message;
       break;
+#ifdef USE_IMAP
+    case M_IMAP:
+      func = imap_open_new_message;
+      break;
+#endif
     default:
       dprint (1, (debugfile, "mx_open_new_message(): function unimplemented for mailbox type %d.\n",
                  dest->magic));
@@ -1121,7 +1149,8 @@ MESSAGE *mx_open_new_message (CONTEXT *dest, HEADER *hdr, int flags)
     if (dest->magic == M_MMDF)
       fputs (MMDF_SEP, msg->fp);
 
-    if (msg->magic != M_MAILDIR && (flags & M_ADD_FROM))
+    if ((msg->magic != M_MAILDIR) && (msg->magic != M_IMAP) && 
+       (flags & M_ADD_FROM))
     {
       if (hdr)
       {
@@ -1420,8 +1449,26 @@ int mx_close_message (MESSAGE **msg)
     }
   }
 
-  if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR || (*msg)->magic == M_IMAP)
-    r = fclose ((*msg)->fp);
+  switch ((*msg)->magic) 
+  {
+    case M_MH:
+    case M_MAILDIR:
+      r = fclose ((*msg)->fp);
+      break;
+
+#ifdef USE_IMAP
+    case M_IMAP:
+      r = fclose ((*msg)->fp);
+      if ((*msg)->write && (*msg)->ctx->append)
+      {
+       r = imap_append_message ((*msg)->ctx, *msg);
+       unlink ((*msg)->path);
+      }
+#endif
+
+    default:
+      break;
+  }
 
   free (*msg);
   *msg = NULL;
@@ -1456,8 +1503,9 @@ void mx_update_context (CONTEXT *ctx)
 {
   HEADER *h = ctx->hdrs[ctx->msgcount];
 
-
-
+#ifdef USE_IMAP
+#include "imap.h"
+#endif