]> granicus.if.org Git - mutt/commitdiff
patch-bac.createplus-1
authorThomas Roessler <roessler@does-not-exist.org>
Mon, 21 Aug 2000 15:42:19 +0000 (15:42 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Mon, 21 Aug 2000 15:42:19 +0000 (15:42 +0000)
15 files changed:
OPS
browser.c
browser.h
buffy.c
doc/manual.sgml.head
functions.h
globals.h
imap/browse.c
imap/command.c
imap/imap.c
imap/imap.h
imap/imap_private.h
imap/message.c
imap/util.c
init.h

diff --git a/OPS b/OPS
index 2e027983e3748c88b3fb2e66c3e496ab78486d5b..046ef6086721917ec5ec42479944f062aca52ac7 100644 (file)
--- a/OPS
+++ b/OPS
@@ -26,6 +26,7 @@ OP_COMPOSE_EDIT_MIME "edit attachment using mailcap entry"
 OP_COMPOSE_EDIT_REPLY_TO "edit the Reply-To field"
 OP_COMPOSE_EDIT_SUBJECT "edit the subject of this message"
 OP_COMPOSE_EDIT_TO "edit the TO list"
+OP_CREATE_MAILBOX "create a new mailbox (IMAP only)"
 OP_EDIT_TYPE "edit attachment content type"
 OP_COMPOSE_GET_ATTACHMENT "get a temporary copy of an attachment"
 OP_COMPOSE_ISPELL "run ispell on the message"
@@ -116,7 +117,6 @@ OP_MAIN_TAG_PATTERN "tag messages matching a pattern"
 OP_MAIN_UNDELETE_PATTERN "undelete messages matching a pattern"
 OP_MAIN_UNTAG_PATTERN "untag messages matching a pattern"
 OP_MIDDLE_PAGE "move to the middle of the page"
-OP_NEW_MAILBOX "create a new mailbox (IMAP only)"
 OP_NEXT_ENTRY "move to the next entry"
 OP_NEXT_LINE "scroll down one line"
 OP_NEXT_PAGE "move to the next page"
index 4d76352cc0eb4addaa4a36666c3932dbb4d55463..4b8d5631d376db498014243a734048f51ddb1a1b 100644 (file)
--- a/browser.c
+++ b/browser.c
@@ -202,18 +202,20 @@ folder_format_str (char *dest, size_t destlen, char op, const char *src,
        snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
        snprintf (dest, destlen, tmp, permission);
       }
-      else
-      {
 #ifdef USE_IMAP
-       if (folder->ff->imap)
-       {
-         /* mark folders with subfolders AND mail */
-         sprintf (permission, "IMAP %c",
-            (folder->ff->inferiors && folder->ff->selectable) ? '+' : ' ');
-          snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-          snprintf (dest, destlen, tmp, permission);
-       }                                        
+      else if (folder->ff->imap)
+      {
+       /* mark folders with subfolders AND mail */
+       sprintf (permission, "IMAP %c",
+          (folder->ff->inferiors && folder->ff->selectable) ? '+' : ' ');
+       snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
+       snprintf (dest, destlen, tmp, permission);
+      }                                        
 #endif
+      else
+      {
+       snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
+       snprintf (dest, destlen, tmp, "");
       }
       break;
       
@@ -252,8 +254,16 @@ folder_format_str (char *dest, size_t destlen, char op, const char *src,
       break;
       
     case 'N':
+#ifdef USE_IMAP
+      if (mx_is_imap (folder->ff->desc))
+      {
+       snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
+       snprintf (dest, destlen, tmp, folder->ff->new);
+       break;
+      }
+#endif
       snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
-      snprintf (dest, destlen, tmp, folder->ff->is_new ? 'N' : ' ');
+      snprintf (dest, destlen, tmp, folder->ff->new ? 'N' : ' ');
       break;
       
     case 's':
@@ -327,7 +337,7 @@ static void add_folder (MUTTMENU *m, struct browser_state *state,
     memcpy ((state->entry)[state->entrylen].st, s, sizeof (struct stat));
   }
 
-  (state->entry)[state->entrylen].is_new = new;
+  (state->entry)[state->entrylen].new = new;
   (state->entry)[state->entrylen].name = safe_strdup (name);
   (state->entry)[state->entrylen].desc = safe_strdup (name);
 #ifdef USE_IMAP
@@ -815,8 +825,24 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
        mutt_ungetch (0, OP_CHECK_NEW);
        break;
 
-      case OP_NEW_MAILBOX:
-       mutt_error (_("Creating mailboxes is not yet supported."));
+      case OP_CREATE_MAILBOX:
+       if (!state.imap_browse)
+         mutt_error (_("Create is only supported for IMAP mailboxes"));
+       else
+       {
+         imap_mailbox_create (LastDir);
+         /* TODO: find a way to detect if the new folder would appear in
+          *   this window, and insert it without starting over. */
+         destroy_state (&state);
+         init_state (&state, NULL);
+         state.imap_browse = 1;
+         imap_browse (LastDir, &state);
+         menu->data = state.entry;
+         menu->current = 0; 
+         menu->top = 0; 
+         init_menu (&state, menu, title, sizeof (title), buffy);
+         MAYBE_REDRAW (menu->redraw);
+       }
        break;
 
       case OP_DELETE_MAILBOX:
@@ -824,7 +850,7 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
          mutt_error (_("Delete is only supported for IMAP mailboxes"));
        else
         {
-         char msg[LONG_STRING];
+         char msg[SHORT_STRING];
          IMAP_MBOX mx;
          int nentry = menu->current;
          
@@ -850,6 +876,7 @@ void _mutt_select_file (char *f, size_t flen, int buffy,
          }
          else
            mutt_message _("Mailbox not deleted.");
+         FREE (&mx.mbox);
         }
         break;
 #endif
index 7ad9e56e8f8624c407deef95b609fe626605a54c..4f2adda90184ab30b76b2b2ee14325f739924c86 100644 (file)
--- a/browser.h
+++ b/browser.h
@@ -29,6 +29,8 @@ struct folder_file
 
   char *name;
   char *desc;
+
+  unsigned short new;
 #ifdef USE_IMAP
   char delim;
   
@@ -37,7 +39,6 @@ struct folder_file
   unsigned inferiors : 1;
 #endif
   unsigned tagged : 1;
-  unsigned is_new : 1;
 };
 
 struct browser_state
diff --git a/buffy.c b/buffy.c
index cbdf74f16b23b90a5f654eb27910f9c8699136e6..5ed50a4a28c61f1976bcd05619ace4e677eb7fef 100644 (file)
--- a/buffy.c
+++ b/buffy.c
@@ -230,23 +230,11 @@ int mutt_buffy_check (int force)
   char path[_POSIX_PATH_MAX];
   struct stat contex_sb;
   time_t t;
-#ifdef USE_IMAP
-  static time_t last_imap_check = 0;
-  int do_imap_check = 1;
-
-  if (ImapCheckTimeout)
-  {
-    time_t now = time (NULL);
-    if (now - last_imap_check < ImapCheckTimeout)
-      do_imap_check = 0;
-    else
-      last_imap_check = now;
-  }
 
+#ifdef USE_IMAP
   /* update postponed count as well, on force */
   if (force)
     mutt_update_num_postponed ();
-
 #endif
 
   /* fastest return if there are no mailboxes */
@@ -272,37 +260,37 @@ int mutt_buffy_check (int force)
   
   for (tmp = Incoming; tmp; tmp = tmp->next)
   {
+    tmp->new = 0;
+
 #ifdef USE_IMAP
     if ((tmp->magic == M_IMAP) || mx_is_imap (tmp->path))
       tmp->magic = M_IMAP;
     else
 #endif
+    if (stat (tmp->path, &sb) != 0 || sb.st_size == 0 ||
+       (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 0))
     {
-      tmp->new = 0;
-      
-      if (stat (tmp->path, &sb) != 0 || sb.st_size == 0 ||
-         (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 0))
-      {
-       /* if the mailbox still doesn't exist, set the newly created flag to
-        * be ready for when it does.
-        */
-       tmp->newly_created = 1;
-       tmp->magic = 0;
+      /* if the mailbox still doesn't exist, set the newly created flag to
+       * be ready for when it does. */
+      tmp->newly_created = 1;
+      tmp->magic = 0;
 #ifdef BUFFY_SIZE
-       tmp->size = 0;
+      tmp->size = 0;
 #endif
-       continue;
-      }
+      continue;
     }
 
     /* check to see if the folder is the currently selected folder
      * before polling */
     if (!Context || !Context->path || 
 #ifdef USE_IMAP
-        /* unless folder is an IMAP folder */
-        tmp->magic == M_IMAP ||
+       (tmp->magic == M_IMAP && mutt_strcmp (tmp->path, Context->path)) ||
+       (tmp->magic != M_IMAP && (
 #endif
        sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)
+#ifdef USE_IMAP
+         ))
+#endif
     {
       switch (tmp->magic)
       {
@@ -355,22 +343,10 @@ int mutt_buffy_check (int force)
 
 #ifdef USE_IMAP
       case M_IMAP:
-        /* poll on do_imap_check, else return cached value.
-         * If the check is forced (eg on mailbox open), check only current
-         * folder */
-        if (do_imap_check || (force && Context && Context->path &&
-          !mutt_strcmp (Context->path, tmp->path)))
-        {
-          tmp->new = 0;
-          if (imap_mailbox_check (tmp->path, 1) > 0)
-          {
-            BuffyCount++;
-            tmp->new = 1;
-          }
-        }
-        else
-          if (tmp->new)
-            BuffyCount++;
+       if ((tmp->new = imap_mailbox_check (tmp->path, 1)) > 0)
+         BuffyCount++;
+       else
+         tmp->new = 0;
 
        break;
 #endif
index cf323526f84e65b0491752f3edfa19d9e3acf3f4..487cf0c3d470ed8eef5fcc6609a230711addc636 100644 (file)
@@ -2083,11 +2083,17 @@ at only the folders you are subscribed to, or all folders with the
 <em/toggle-subscribed/ command.  See also the 
 <ref id="imap&lowbar;list&lowbar;subscribed" name="&dollar;imap&lowbar;list&lowbar;subscribed"> variable.
 
-Polling for new mail is more expensive over IMAP than locally. For this reason
-the frequency at which Mutt will check for mail remotely can be controlled by
-the
-<ref id="imap&lowbar;checkinterval" name="&dollar;imap&lowbar;checkinterval">
-variable, which defaults to every 60 seconds.
+Polling for new mail on an IMAP server can cause noticeable delays. So, you'll
+want to carefully tune the
+<ref id="mail&lowbar;check" name="&dollar;mail&lowbar;check">
+and
+<ref id="timeout" name="&dollar;timeout">
+variables. Personally I use
+<tscreen><verb>
+set mail_check=90
+set timeout=15
+</verb></tscreen>
+with relatively good results over my slow modem line.
 
 Note that if you are using mbox as the mail store on UW servers prior to
 v12.250, the server has been reported to disconnect a client if another client
index 60d2fc3e56f6ac83fe1a498ef9cc8a5f7e6d6dcb..04993ae5a3c36829566fe90d7fdd9c6bcd83416c 100644 (file)
@@ -329,7 +329,7 @@ struct binding_t OpBrowser[] = {
   { "toggle-mailboxes", OP_TOGGLE_MAILBOXES,   "\t" },
   { "view-file",       OP_BROWSER_VIEW_FILE,   " " },
 #ifdef USE_IMAP
-  { "new-mailbox",      OP_NEW_MAILBOX,         "n" },
+  { "create-mailbox",   OP_CREATE_MAILBOX,      "C" },
   { "delete-mailbox",   OP_DELETE_MAILBOX,      "d" },
   { "subscribe",       OP_BROWSER_SUBSCRIBE,   "s" },
   { "unsubscribe",     OP_BROWSER_UNSUBSCRIBE, "u" },
index 3fab5fe09f1e3f834918bc9a9dd63baf88152fcd..871e59ff4356378903e417b4b9b25b1833514a54 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -51,7 +51,6 @@ WHERE char *Hostname;
 #ifdef USE_IMAP
 WHERE char *ImapUser INITVAL (NULL);
 WHERE char *ImapPass INITVAL (NULL);
-WHERE short ImapCheckTimeout;
 WHERE char *ImapHomeNamespace INITVAL (NULL);
 #endif
 WHERE char *InReplyTo;
index cd3b0470ad0d6226609af5fb3ced5ecf9d7d2aca..95ef83d67a283b39d9be8a9bbe33c01bc9e7e4c2 100644 (file)
@@ -67,22 +67,22 @@ int imap_browse (char* path, struct browser_state* state)
   strfcpy (list_cmd, option (OPTIMAPLSUB) ? "LSUB" : "LIST", sizeof (list_cmd));
 
   if (!(idata = imap_conn_find (&(mx.account), 0)))
-    return -1;
+    goto fail;
 
-  if (mx.mbox[0] == '\0')
+  if (!mx.mbox)
   {
     home_namespace = 1;
     mbox[0] = '\0';            /* Do not replace "" with "INBOX" here */
-    mx.mbox = ImapHomeNamespace;
+    mx.mbox = safe_strdup(ImapHomeNamespace);
     nns = 0;
     if (mutt_bit_isset(idata->capabilities,NAMESPACE))
     {
       mutt_message _("Getting namespaces...");
       if (browse_get_namespace (idata, nsbuf, sizeof (nsbuf), 
                         nsi, sizeof (nsi),  &nns) != 0)
-       return -1;
+       goto fail;
       if (browse_verify_namespace (idata, nsi, nns) != 0)
-       return -1;
+       goto fail;
     }
   }
 
@@ -110,7 +110,7 @@ int imap_browse (char* path, struct browser_state* state)
       {
         if (imap_parse_list_response (idata, &cur_folder, &noselect,
             &noinferiors, &idata->delim) != 0)
-          return -1;
+         goto fail;
 
         if (cur_folder)
         {
@@ -200,14 +200,14 @@ int imap_browse (char* path, struct browser_state* state)
      * server to see if it has descendants. */
     dprint (4, (debugfile, "imap_init_browse: adding INBOX\n"));
     if (browse_add_list_result (idata, "LIST \"\" \"INBOX\"", state, 0))
-      return -1;
+      goto fail;
   }
 
   nsup = state->entrylen;
 
   snprintf (buf, sizeof (buf), "%s \"\" \"%s%%\"", list_cmd, mbox);
   if (browse_add_list_result (idata, buf, state, 0))
-    return -1;
+    goto fail;
 
   qsort(&(state->entry[nsup]),state->entrylen-nsup,sizeof(state->entry[0]),
        (int (*)(const void*,const void*)) compare_names);
@@ -223,7 +223,60 @@ int imap_browse (char* path, struct browser_state* state)
   }
 
   mutt_clear_error ();
+  FREE (&mx.mbox);
+  return 0;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
+}
+
+/* imap_mailbox_create: Prompt for a new mailbox name, and try to create it */
+int imap_mailbox_create (const char* folder)
+{
+  IMAP_DATA* idata;
+  IMAP_MBOX mx;
+  char buf[LONG_STRING];
+  short n;
+
+  if (imap_parse_path (folder, &mx) < 0)
+  {
+    dprint (1, (debugfile, "imap_mailbox_create: Bad starting path %s\n",
+      folder));
+    return -1;
+  }
+
+  if (!(idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW)))
+  {
+    dprint (1, (debugfile, "imap_mailbox_create: Couldn't find open connection to %s", mx.account.host));
+    goto fail;
+  }
+  
+  strfcpy (buf, NONULL (mx.mbox), sizeof (buf));
+
+  /* append a delimiter if necessary */
+  n = mutt_strlen (buf);
+  if (n && (n < sizeof (buf) - 1) && (buf[n-1] != idata->delim))
+  {
+    buf[n++] = idata->delim;
+    buf[n] = '\0';
+  }
+  
+  if (mutt_get_field (_("Create mailbox: "), buf, sizeof (buf), M_FILE) < 0)
+    goto fail;
+
+  if (imap_create_mailbox (idata, buf) < 0)
+    goto fail;
+
+  mutt_message _("Mailbox created.");
+  sleep (1);
+
+  FREE (&mx.mbox);
   return 0;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
 }
 
 static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
@@ -247,7 +300,10 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
   {
     if (imap_parse_list_response(idata, &name, &noselect, &noinferiors,
         &idata->delim) != 0)
+    {
+      FREE (&mx.mbox);
       return -1;
+    }
 
     if (name)
     {
@@ -262,6 +318,7 @@ static int browse_add_list_result (IMAP_DATA* idata, const char* cmd,
   }
   while ((mutt_strncmp (idata->buf, idata->seq, SEQLEN) != 0));
 
+  FREE (&mx.mbox);
   return 0;
 }
 
@@ -300,7 +357,10 @@ static void imap_add_folder (char delim, char *folder, int noselect,
    * than at scan, since it's so expensive to scan. But that's big changes
    * to browser.c */
   if (!((regexec (Mask.rx, relpath, 0, NULL, 0) == 0) ^ Mask.not))
+  {
+    FREE (&mx.mbox);
     return;
+  }
 
   imap_qualify_path (tmp, sizeof (tmp), &mx, folder, NULL);
   (state->entry)[state->entrylen].name = safe_strdup (tmp);
@@ -322,6 +382,8 @@ static void imap_add_folder (char delim, char *folder, int noselect,
   (state->entry)[state->entrylen].selectable = !noselect;
   (state->entry)[state->entrylen].inferiors = !noinferiors;
   (state->entrylen)++;
+
+  FREE (&mx.mbox);
 }
 
 static int compare_names(struct folder_file *a, struct folder_file *b) 
index a406c942efc987b3ab9d35369fc3d610e3f55f46..babde98ee801072466822a1b72de4251d682c69b 100644 (file)
@@ -242,11 +242,11 @@ static void cmd_finish (IMAP_DATA* idata)
     {
       /* read new mail messages */
       dprint (2, (debugfile, "cmd_finish: Fetching new mail\n"));
-      count = imap_read_headers (idata, idata->ctx->msgcount, count-1)+1;
       /* check_status: curs_main uses imap_check_mailbox to detect
        *   whether the index needs updating */
       idata->check_status = IMAP_NEWMAIL_PENDING;
       idata->reopen &= ~IMAP_NEWMAIL_PENDING;
+      count = imap_read_headers (idata, idata->ctx->msgcount, count-1)+1;
     }
     else
     {
index c122df693329c9d34ca26b3fb37073d0ae74b72f..e66878ca6c00e48190f4cf5c754d79ea9767fd93 100644 (file)
@@ -45,18 +45,15 @@ static int imap_check_capabilities (IMAP_DATA* idata);
 static void imap_set_flag (IMAP_DATA* idata, int aclbit, int flag,
   const char* str, char* flags);
 
-int imap_create_mailbox (CONTEXT* ctx, char* mailbox)
+int imap_create_mailbox (IMAP_DATA* idata, char* mailbox)
 {
   char buf[LONG_STRING], mbox[LONG_STRING];
 
   imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
   snprintf (buf, sizeof (buf), "CREATE %s", mbox);
       
-  if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
-  {
-    imap_error ("imap_create_mailbox", CTX_DATA->buf);
+  if (imap_exec (idata, buf, 0) != 0)
     return -1;
-  }
 
   return 0;
 }
@@ -65,14 +62,11 @@ int imap_delete_mailbox (CONTEXT* ctx, char* mailbox)
 {
   char buf[LONG_STRING], mbox[LONG_STRING];
   
-  imap_quote_string (mbox, sizeof (mbox), mailbox);
+  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
   snprintf (buf, sizeof (buf), "DELETE %s", mbox);
 
   if (imap_exec ((IMAP_DATA*) ctx->data, buf, 0) != 0)
-  {
-    imap_error ("imap_delete_mailbox", CTX_DATA->buf);
     return -1;
-  }
 
   return 0;
 }
@@ -475,14 +469,14 @@ int imap_open_mailbox (CONTEXT* ctx)
 
   /* we require a connection which isn't currently in IMAP_SELECTED state */
   if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NOSELECT)))
-    return -1;
+    goto fail;
   conn = idata->conn;
 
   /* once again the context is new */
   ctx->data = idata;
 
   if (idata->status == IMAP_FATAL)
-    return -1;
+    goto fail;
 
   /* Clean up path and replace the one in the ctx */
   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
@@ -537,7 +531,7 @@ int imap_open_mailbox (CONTEXT* ctx)
       {
        dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
        if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
-         return -1;
+         goto fail;
       }
     }
     /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */
@@ -549,13 +543,13 @@ int imap_open_mailbox (CONTEXT* ctx)
       /* skip "OK [PERMANENT" so syntax is the same as FLAGS */
       pc += 13;
       if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
-       return -1;
+       goto fail;
     }
   }
   while (rc == IMAP_CMD_CONTINUE);
 
   if (rc != IMAP_CMD_DONE)
-    return -1;
+    goto fail;
 
   /* check for READ-ONLY notification */
   if (!strncmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11))
@@ -595,13 +589,13 @@ int imap_open_mailbox (CONTEXT* ctx)
     mutt_error ("%s", s);
     idata->state = IMAP_AUTHENTICATED;
     sleep (1);
-    return -1;
+    goto fail;
   }
 
   if (mutt_bit_isset (idata->capabilities, ACL))
   {
     if (imap_check_acl (idata))
-      return -1;
+      goto fail;
   }
   /* assume we have all rights if ACL is unavailable */
   else
@@ -623,7 +617,12 @@ int imap_open_mailbox (CONTEXT* ctx)
   count = imap_read_headers (idata, 0, count - 1) + 1;
 
   dprint (1, (debugfile, "imap_open_mailbox(): msgcount is %d\n", ctx->msgcount));
+  FREE (&mx.mbox);
   return 0;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
 }
 
 int imap_open_mailbox_append (CONTEXT *ctx)
@@ -642,7 +641,7 @@ int imap_open_mailbox_append (CONTEXT *ctx)
    * ctx is brand new and mostly empty */
 
   if (!(idata = imap_conn_find (&(mx.account), 0)))
-    return -1;
+    goto fail;
   conn = idata->conn;
 
   ctx->magic = M_IMAP;
@@ -665,7 +664,7 @@ int imap_open_mailbox_append (CONTEXT *ctx)
     /* STATUS not supported */
     mutt_message _("Unable to append to IMAP mailboxes at this server");
 
-    return -1;
+    goto fail;
   }
 
   r = imap_exec (idata, buf, IMAP_CMD_FAIL_OK);
@@ -674,16 +673,21 @@ int imap_open_mailbox_append (CONTEXT *ctx)
     /* command failed cause folder doesn't exist */
     snprintf (buf, sizeof (buf), _("Create %s?"), mailbox);
     if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1)
-      return -1;
+      goto fail;
 
-    if (imap_create_mailbox (ctx, mailbox) < 0)
-      return -1;
+    if (imap_create_mailbox (idata, mailbox) < 0)
+      goto fail;
   }
   else if (r == -1)
     /* Hmm, some other failure */
-    return -1;
+    goto fail;
 
+  FREE (&mx.mbox);
   return 0;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
 }
 
 /* imap_logout: Gracefully log out of server. */
@@ -915,12 +919,12 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
 
         mutt_remove_trailing_ws (flags);
 
-        snprintf (buf, sizeof (buf), "STORE %d -FLAGS.SILENT (%s)",
-          ctx->hdrs[n]->index + 1, flags);
+        snprintf (buf, sizeof (buf), "UID STORE %d -FLAGS.SILENT (%s)",
+          HEADER_DATA (ctx->hdrs[n])->uid, flags);
       }
       else
-        snprintf (buf, sizeof (buf), "STORE %d FLAGS.SILENT (%s)",
-          ctx->hdrs[n]->index + 1, flags);
+        snprintf (buf, sizeof (buf), "UID STORE %d FLAGS.SILENT (%s)",
+          HEADER_DATA (ctx->hdrs[n])->uid, flags);
 
       /* after all this it's still possible to have no flags, if you
        * have no ACL rights */
@@ -964,15 +968,14 @@ void imap_close_mailbox (CONTEXT* ctx)
   if (!idata)
     return;
 
-  idata->reopen &= IMAP_REOPEN_ALLOW;
-
   if ((idata->status != IMAP_FATAL) &&
       (idata->state == IMAP_SELECTED) &&
       (ctx == idata->ctx))
   {
     if (!(idata->noclose) && imap_exec (idata, "CLOSE", 0))
       imap_error ("CLOSE failed", idata->buf);
-    
+
+    idata->reopen &= IMAP_REOPEN_ALLOW;
     idata->state = IMAP_AUTHENTICATED;
     FREE (&(idata->mailbox));
   }
@@ -1001,45 +1004,33 @@ void imap_close_mailbox (CONTEXT* ctx)
  */
 int imap_check_mailbox (CONTEXT *ctx, int *index_hint)
 {
-  static time_t checktime=0;
+  /* overload keyboard timeout to avoid many mailbox checks in a row.
+   * Most users don't like having to wait exactly when they press a key. */
+  static time_t LastCheck = 0;
 
   IMAP_DATA* idata;
-  time_t t = 0;
+  time_t now;
 
   idata = (IMAP_DATA*) ctx->data;
 
-  /* 
-   * gcc thinks it has to warn about uninitialized use
-   * of t.  This is wrong.
-   */
-  
-  if (ImapCheckTimeout)
-  { 
-    t = time(NULL);
-    t -= checktime;
-  }
-
-  /* TODO: wtf?! */
-  if ((ImapCheckTimeout && t >= ImapCheckTimeout)
-      || ((idata->reopen & IMAP_REOPEN_ALLOW) && (idata->reopen & ~IMAP_REOPEN_ALLOW)))
-  {
-    if (ImapCheckTimeout) checktime += t;
+  now = time(NULL);
+  if (now > LastCheck + Timeout) {
+    LastCheck = now;
 
     if (imap_exec (idata, "NOOP", 0) != 0)
     {
       imap_error ("imap_check_mailbox", idata->buf);
       return -1;
     }
+  }
     
-    if (idata->check_status & IMAP_NEWMAIL_PENDING)
-    {
-      idata->check_status &= ~IMAP_NEWMAIL_PENDING;
-      return M_NEW_MAIL;
-    }
-    
-    /* TODO: we should be able to detect external changes and return
-     *   M_REOPENED here. */
+  if (idata->check_status & IMAP_NEWMAIL_PENDING)
+  {
+    idata->check_status &= ~IMAP_NEWMAIL_PENDING;
+    return M_NEW_MAIL;
   }
+  /* TODO: we should be able to detect external changes and return
+   *   M_REOPENED here. */
   
   return 0;
 }
@@ -1071,7 +1062,7 @@ int imap_mailbox_check (char* path, int new)
     connflags = M_IMAP_CONN_NONEW;
 
   if (!(idata = imap_conn_find (&(mx.account), connflags)))
-    return -1;
+    goto fail;
   conn = idata->conn;
 
   imap_fix_path (idata, mx.mbox, buf, sizeof (buf));
@@ -1099,11 +1090,9 @@ int imap_mailbox_check (char* path, int new)
       new ? "RECENT" : "MESSAGES");
   }
   else
-  {
     /* Server does not support STATUS, and this is not the current mailbox.
      * There is no lightweight way to check recent arrivals */
-      return -1;
-  }
+    goto fail;
 
   imap_cmd_start (idata, buf);
 
@@ -1128,8 +1117,8 @@ int imap_mailbox_check (char* path, int new)
        {
          if (*s != '0')
          {
-           dprint (1, (debugfile, "Mail in %s\n", path));
            msgcount = atoi(s);
+           dprint (2, (debugfile, "%d new messages in %s\n", msgcount, path));
          }
        }
       }
@@ -1139,7 +1128,12 @@ int imap_mailbox_check (char* path, int new)
   }
   while (rc == IMAP_CMD_CONTINUE);
 
+  FREE (&mx.mbox);
   return msgcount;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
 }
 
 /* all this listing/browsing is a mess. I don't like that name is a pointer
@@ -1227,7 +1221,7 @@ int imap_subscribe (char *path, int subscribe)
     return -1;
 
   if (!(idata = imap_conn_find (&(mx.account), 0)))
-    return -1;
+    goto fail;
   
   conn = idata->conn;
 
@@ -1242,9 +1236,14 @@ int imap_subscribe (char *path, int subscribe)
     "UNSUBSCRIBE", mbox);
 
   if (imap_exec (idata, buf, 0) < 0)
-    return -1;
+    goto fail;
 
+  FREE (&mx.mbox);
   return 0;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
 }
 
 /* imap_complete: given a partial IMAP folder path, return a string which
@@ -1272,7 +1271,7 @@ int imap_complete(char* dest, size_t dlen, char* path) {
 
   /* don't open a new socket just for completion */
   if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NONEW)))
-    return -1;
+    goto fail;
   conn = idata->conn;
 
   /* reformat path for IMAP list, and append wildcard */
@@ -1336,8 +1335,11 @@ int imap_complete(char* dest, size_t dlen, char* path) {
     imap_qualify_path (dest, dlen, &mx, completion, NULL);
     mutt_pretty_mailbox (dest);
 
+    FREE (&mx.mbox);
     return 0;
   }
 
+ fail:
+  FREE (&mx.mbox);
   return -1;
 }
index 99eaacaa0a82000d77af7fe2571111bc446aa05e..1e26941e5f712f16a53e034f057b2547fe07486c 100644 (file)
@@ -32,7 +32,6 @@ typedef struct
 
 /* imap.c */
 int imap_check_mailbox (CONTEXT *ctx, int *index_hint);
-int imap_create_mailbox (CONTEXT* idata, char* mailbox);
 int imap_close_connection (CONTEXT *ctx);
 int imap_delete_mailbox (CONTEXT* idata, char* mailbox);
 int imap_open_mailbox (CONTEXT *ctx);
@@ -49,6 +48,7 @@ void imap_disallow_reopen (CONTEXT *ctx);
 
 /* browse.c */
 int imap_browse (char* path, struct browser_state* state);
+int imap_mailbox_create (const char* folder);
 
 /* message.c */
 int imap_append_message (CONTEXT* ctx, MESSAGE* msg);
index b574ee819d2893ea48d261e747130bf6b7a31a22..9611890e4d1f5ceeb4944a1a385b99b0a0433397 100644 (file)
@@ -44,7 +44,7 @@
 #define SEQLEN 5
 
 #define IMAP_REOPEN_ALLOW    (1<<0)
-#define IMAP_EXPUNGE_PENDING  (1<<1)
+#define IMAP_EXPUNGE_PENDING (1<<1)
 #define IMAP_NEWMAIL_PENDING (1<<2)
 
 /* imap_exec flags (see imap_exec) */
@@ -172,6 +172,7 @@ typedef struct
 
 /* -- private IMAP functions -- */
 /* imap.c */
+int imap_create_mailbox (IMAP_DATA* idata, char* mailbox);
 int imap_make_msg_set (IMAP_DATA* idata, char* buf, size_t buflen, int flag,
   int changed);
 int imap_open_connection (IMAP_DATA* idata);
index ad25e9183ffc9305a95a793d74bbac1e63009437..9db78bb1a542084a356814648be6afa903a512b8 100644 (file)
@@ -192,6 +192,7 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
 int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
 {
   IMAP_DATA* idata;
+  HEADER* h;
   char buf[LONG_STRING];
   char path[_POSIX_PATH_MAX];
   char *pc;
@@ -293,9 +294,10 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
                 !ctx->hdrs[msgno]->changed)
        {
          IMAP_HEADER newh;
-         HEADER* h = ctx->hdrs[msgno];
          unsigned char readonly;
 
+         h = ctx->hdrs[msgno];
+
          memset (&newh, 0, sizeof (newh));
          newh.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
 
@@ -348,23 +350,37 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
   /* Update the header information.  Previously, we only downloaded a
    * portion of the headers, those required for the main display.
    */
+  h = ctx->hdrs[msgno];
   rewind (msg->fp);
-  mutt_free_envelope (&ctx->hdrs[msgno]->env);
-  ctx->hdrs[msgno]->env = mutt_read_rfc822_header (msg->fp, ctx->hdrs[msgno],0, 0);
-  ctx->hdrs[msgno]->lines = 0;
+  /* I hate do this here, since it's so low-level, but I'm not sure where
+   * I can abstract it. Problem: the id and subj hashes lose their keys when
+   * mutt_free_envelope gets called, but keep their spots in the hash. This
+   * confuses threading. Alternatively we could try to merge the new
+   * envelope into the old one. Also messy and lowlevel. */
+  if (h->env->message_id)
+    hash_delete (ctx->id_hash, h->env->message_id, h, NULL);
+  if (h->env->real_subj)
+    hash_delete (ctx->subj_hash, h->env->real_subj, h, NULL);
+  mutt_free_envelope (&h->env);
+  h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0);
+  if (h->env->message_id)
+    hash_insert (ctx->id_hash, h->env->message_id, h, 0);
+  if (h->env->real_subj)
+    hash_insert (ctx->subj_hash, h->env->real_subj, h, 1);
+
+  h->lines = 0;
   fgets (buf, sizeof (buf), msg->fp);
   while (!feof (msg->fp))
   {
-    ctx->hdrs[msgno]->lines++;
+    h->lines++;
     fgets (buf, sizeof (buf), msg->fp);
   }
 
-  ctx->hdrs[msgno]->content->length = ftell (msg->fp) - 
-                                        ctx->hdrs[msgno]->content->offset;
+  h->content->length = ftell (msg->fp) - h->content->offset;
 
   /* This needs to be done in case this is a multipart message */
 #ifdef HAVE_PGP
-  ctx->hdrs[msgno]->pgp = pgp_query (ctx->hdrs[msgno]->content);
+  h->pgp = pgp_query (h->content);
 #endif /* HAVE_PGP */
 
   mutt_clear_error();
@@ -405,7 +421,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
   if ((fp = fopen (msg->path, "r")) == NULL)
   {
     mutt_perror (msg->path);
-    return (-1);
+    goto fail;
   }
 
   for (last = EOF, len = 0; (c = fgetc(fp)) != EOF; last = c)
@@ -438,7 +454,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
     mutt_error ("%s", pc);
     sleep (1);
     fclose (fp);
-    return (-1);
+    goto fail;
   }
 
   mutt_message _("Uploading message ...");
@@ -474,10 +490,15 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
     pc = imap_next_word (pc);
     mutt_error ("%s", pc);
     sleep (1);
-    return (-1);
+    goto fail;
   }
 
+  FREE (&mx.mbox);
   return 0;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
 }
 
 /* imap_copy_messages: use server COPY command to copy messages to another
@@ -510,7 +531,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
   {
     dprint (3, (debugfile, "imap_copy_message: %s not same server as %s\n",
       dest, ctx->path));
-    return 1;
+    goto fail;
   }
 
   imap_fix_path (idata, mx.mbox, cmd, sizeof (cmd));
@@ -522,7 +543,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
     if (!rc)
     {
       dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n"));
-      return -1;
+      goto fail;
     }
     mutt_message (_("Copying %d messages to %s..."), rc, cmd);
   }
@@ -543,17 +564,17 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
     if (strncmp (imap_get_qualifier (idata->buf), "[TRYCREATE]", 11))
     {
       imap_error ("imap_copy_messages", idata->buf);
-      return -1;
+      goto fail;
     }
     dprint (2, (debugfile, "imap_copy_messages: server suggests TRYCREATE\n"));
     snprintf (buf, sizeof (buf), _("Create %s?"), mbox);
     if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1)
     {
       mutt_clear_error ();
-      return -1;
+      goto fail;
     }
-    if (imap_create_mailbox (ctx, mbox) < 0)
-      return -1;
+    if (imap_create_mailbox (idata, mbox) < 0)
+      goto fail;
 
     /* try again */
     rc = imap_exec (idata, cmd, 0);
@@ -561,7 +582,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
   if (rc != 0)
   {
     imap_error ("imap_copy_messages", idata->buf);
-    return -1;
+    goto fail;
   }
 
   /* cleanup */
@@ -585,7 +606,12 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
     }
   }
 
+  FREE (&mx.mbox);
   return 0;
+
+ fail:
+  FREE (&mx.mbox);
+  return -1;
 }
 
 /* imap_add_keywords: concatenate custom IMAP tags to list, if they
index aa64c4a38f8424d3f97cf6266b74dec2df21cb98..51a6311235c9285d9475a81a639ed45d6885f8f3 100644 (file)
@@ -127,7 +127,8 @@ char *imap_next_word (char *s)
 }
 
 /* imap_parse_path: given an IMAP mailbox name, return host, port
- *   and a path IMAP servers will recognise. */
+ *   and a path IMAP servers will recognise.
+ * mx.mbox is malloc'd, caller must free it */
 int imap_parse_path (const char* path, IMAP_MBOX* mx)
 {
   char tmp[128];
@@ -144,7 +145,7 @@ int imap_parse_path (const char* path, IMAP_MBOX* mx)
     return -1;
   else
     /* walk past closing '}' */
-    mx->mbox = strdup (c+1);
+    mx->mbox = safe_strdup (c+1);
   
   /* Defaults */
   mx->account.flags = 0;
@@ -161,6 +162,7 @@ int imap_parse_path (const char* path, IMAP_MBOX* mx)
   if ((n = sscanf (tmp, "%128[^:/]%128s", mx->account.host, tmp)) < 1)
   {
     dprint (1, (debugfile, "imap_parse_path: NULL host in %s\n", path));
+    FREE (&mx->mbox);
     return -1;
   }
   
@@ -176,6 +178,7 @@ int imap_parse_path (const char* path, IMAP_MBOX* mx)
 #endif
       {
        dprint (1, (debugfile, "imap_parse_path: Unknown connection type in %s\n", path));
+       FREE (&mx->mbox);
        return -1;
       }
     }
@@ -383,12 +386,14 @@ int imap_wait_keepalive (pid_t pid)
 
   sigaction (SIGALRM, &act, &oldalrm);
 
-  alarm (ImapCheckTimeout > 0 ? ImapCheckTimeout : 60);
+  /* RFC 2060 specifies a minimum of 30 minutes before disconnect when in
+   * the AUTHENTICATED state. We'll poll at half that. */
+  alarm (900);
   while (waitpid (pid, &rc, 0) < 0 && errno == EINTR)
   {
     alarm (0); /* cancel a possibly pending alarm */
     imap_keepalive ();
-    alarm (ImapCheckTimeout > 0 ? ImapCheckTimeout : 60);
+    alarm (900);
   }
 
   alarm (0);   /* cancel a possibly pending alarm */
diff --git a/init.h b/init.h
index 42d8bb877edf984dc4a820db80bab6ae815bdb44..1713cffcbbcf862c0cb8afb814d7230e5718debd 100644 (file)
--- a/init.h
+++ b/init.h
@@ -657,12 +657,6 @@ struct option_t MuttVars[] = {
   ** list.
   */
 #ifdef USE_IMAP
-  { "imap_checkinterval",      DT_NUM,  R_NONE, UL &ImapCheckTimeout, 60 },
-  /*
-  ** .pp
-  ** This variable configures how often (in seconds) IMAP should look for
-  ** new mail.
-  */
 # ifdef USE_SSL
   { "imap_force_ssl",          DT_BOOL, R_NONE, OPTIMAPFORCESSL, 0 },
   /*