]> git.llucax.com Git - software/mutt-debian.git/blobdiff - imap/util.c
sidebar: don't overwrite the status if status_on_top is enabled (Closes: 494735)
[software/mutt-debian.git] / imap / util.c
index 785d8f3b097e8c950fab7d3ca53c37e79464e341..b38268e22dc543472e906c6f1d00a06eb16f43c7 100644 (file)
@@ -1,22 +1,22 @@
 /*
  * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org>
  * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
 /*
  * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org>
  * Copyright (C) 1996-9 Brandon Long <blong@fiction.net>
- * Copyright (C) 1999-2005 Brendan Cully <brendan@kublai.com>
- * 
+ * Copyright (C) 1999-2009 Brendan Cully <brendan@kublai.com>
+ *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
  *     the Free Software Foundation; either version 2 of the License, or
  *     (at your option) any later version.
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
  *     the Free Software Foundation; either version 2 of the License, or
  *     (at your option) any later version.
- * 
+ *
  *     This program is distributed in the hope that it will be useful,
  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *     GNU General Public License for more details.
  *     This program is distributed in the hope that it will be useful,
  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *     GNU General Public License for more details.
- * 
+ *
  *     You should have received a copy of the GNU General Public License
  *     along with this program; if not, write to the Free Software
  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *     You should have received a copy of the GNU General Public License
  *     along with this program; if not, write to the Free Software
  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */ 
+ */
 
 /* general IMAP utility functions */
 
 
 /* general IMAP utility functions */
 
@@ -26,7 +26,6 @@
 #include "mx.h"        /* for M_IMAP */
 #include "url.h"
 #include "imap_private.h"
 #include "mx.h"        /* for M_IMAP */
 #include "url.h"
 #include "imap_private.h"
-#include "mutt_ssl.h"
 #ifdef USE_HCACHE
 #include "message.h"
 #include "hcache.h"
 #ifdef USE_HCACHE
 #include "message.h"
 #include "hcache.h"
 int imap_expand_path (char* path, size_t len)
 {
   IMAP_MBOX mx;
 int imap_expand_path (char* path, size_t len)
 {
   IMAP_MBOX mx;
+  IMAP_DATA* idata;
   ciss_url_t url;
   ciss_url_t url;
+  char fixedpath[LONG_STRING];
   int rc;
 
   if (imap_parse_path (path, &mx) < 0)
     return -1;
 
   int rc;
 
   if (imap_parse_path (path, &mx) < 0)
     return -1;
 
+  idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW);
   mutt_account_tourl (&mx.account, &url);
   mutt_account_tourl (&mx.account, &url);
-  url.path = mx.mbox;
+  imap_fix_path (idata, mx.mbox, fixedpath, sizeof (fixedpath));
+  url.path = fixedpath;
 
   rc = url_ciss_tostring (&url, path, len, U_DECODE_PASSWD);
   FREE (&mx.mbox);
 
   rc = url_ciss_tostring (&url, path, len, U_DECODE_PASSWD);
   FREE (&mx.mbox);
@@ -126,6 +129,8 @@ HEADER* imap_hcache_get (IMAP_DATA* idata, unsigned int uid)
   {
     if (*uv == idata->uid_validity)
       h = mutt_hcache_restore ((unsigned char*)uv, NULL);
   {
     if (*uv == idata->uid_validity)
       h = mutt_hcache_restore ((unsigned char*)uv, NULL);
+    else
+      dprint (3, (debugfile, "hcache uidvalidity mismatch: %u", *uv));
     FREE (&uv);
   }
 
     FREE (&uv);
   }
 
@@ -189,7 +194,7 @@ int imap_parse_path (const char* path, IMAP_MBOX* mx)
   }
 
   /* Defaults */
   }
 
   /* Defaults */
-  mx->account.flags = 0;
+  memset(&mx->account, 0, sizeof(mx->account));
   mx->account.port = ImapPort;
   mx->account.type = M_ACCT_TYPE_IMAP;
 
   mx->account.port = ImapPort;
   mx->account.type = M_ACCT_TYPE_IMAP;
 
@@ -223,7 +228,7 @@ int imap_parse_path (const char* path, IMAP_MBOX* mx)
     else
       /* walk past closing '}' */
       mx->mbox = safe_strdup (c+1);
     else
       /* walk past closing '}' */
       mx->mbox = safe_strdup (c+1);
-  
+
     if ((c = strrchr (tmp, '@')))
     {
       *c = '\0';
     if ((c = strrchr (tmp, '@')))
     {
       *c = '\0';
@@ -231,14 +236,14 @@ int imap_parse_path (const char* path, IMAP_MBOX* mx)
       strfcpy (tmp, c+1, sizeof (tmp));
       mx->account.flags |= M_ACCT_USER;
     }
       strfcpy (tmp, c+1, sizeof (tmp));
       mx->account.flags |= M_ACCT_USER;
     }
-  
+
     if ((n = sscanf (tmp, "%127[^:/]%127s", mx->account.host, tmp)) < 1)
     {
       dprint (1, (debugfile, "imap_parse_path: NULL host in %s\n", path));
       FREE (&mx->mbox);
       return -1;
     }
     if ((n = sscanf (tmp, "%127[^:/]%127s", mx->account.host, tmp)) < 1)
     {
       dprint (1, (debugfile, "imap_parse_path: NULL host in %s\n", path));
       FREE (&mx->mbox);
       return -1;
     }
-  
+
     if (n > 1) {
       if (sscanf (tmp, ":%hu%127s", &(mx->account.port), tmp) >= 1)
        mx->account.flags |= M_ACCT_PORT;
     if (n > 1) {
       if (sscanf (tmp, ":%hu%127s", &(mx->account.port), tmp) >= 1)
        mx->account.flags |= M_ACCT_PORT;
@@ -265,10 +270,28 @@ int imap_parse_path (const char* path, IMAP_MBOX* mx)
 /* silly helper for mailbox name string comparisons, because of INBOX */
 int imap_mxcmp (const char* mx1, const char* mx2)
 {
 /* silly helper for mailbox name string comparisons, because of INBOX */
 int imap_mxcmp (const char* mx1, const char* mx2)
 {
+  char* b1;
+  char* b2;
+  int rc;
+
+  if (!mx1 || !*mx1)
+    mx1 = "INBOX";
+  if (!mx2 || !*mx2)
+    mx2 = "INBOX";
   if (!ascii_strcasecmp (mx1, "INBOX") && !ascii_strcasecmp (mx2, "INBOX"))
     return 0;
   if (!ascii_strcasecmp (mx1, "INBOX") && !ascii_strcasecmp (mx2, "INBOX"))
     return 0;
-  
-  return mutt_strcmp (mx1, mx2);
+
+  b1 = safe_malloc (strlen (mx1) + 1);
+  b2 = safe_malloc (strlen (mx2) + 1);
+
+  imap_fix_path (NULL, mx1, b1, strlen (mx1) + 1);
+  imap_fix_path (NULL, mx2, b2, strlen (mx2) + 1);
+
+  rc = mutt_strcmp (b1, b2);
+  FREE (&b1);
+  FREE (&b2);
+
+  return rc;
 }
 
 /* imap_pretty_mailbox: called by mutt_pretty_mailbox to make IMAP paths
 }
 
 /* imap_pretty_mailbox: called by mutt_pretty_mailbox to make IMAP paths
@@ -295,7 +318,7 @@ void imap_pretty_mailbox (char* path)
     {
       if (! hlen)
        home_match = 1;
     {
       if (! hlen)
        home_match = 1;
-      else
+      else if (ImapDelimChars)
        for (delim = ImapDelimChars; *delim != '\0'; delim++)
          if (target.mbox[hlen] == *delim)
            home_match = 1;
        for (delim = ImapDelimChars; *delim != '\0'; delim++)
          if (target.mbox[hlen] == *delim)
            home_match = 1;
@@ -354,6 +377,13 @@ IMAP_DATA* imap_new_idata (void)
   if (!(idata->cmdbuf = mutt_buffer_init (NULL)))
     FREE (&idata);
 
   if (!(idata->cmdbuf = mutt_buffer_init (NULL)))
     FREE (&idata);
 
+  idata->cmdslots = ImapPipelineDepth + 2;
+  if (!(idata->cmds = safe_calloc(idata->cmdslots, sizeof(*idata->cmds))))
+  {
+    mutt_buffer_free(&idata->cmdbuf);
+    FREE (&idata);
+  }
+
   return idata;
 }
 
   return idata;
 }
 
@@ -369,6 +399,7 @@ void imap_free_idata (IMAP_DATA** idata)
   mutt_buffer_free(&(*idata)->cmdbuf);
   FREE (&(*idata)->buf);
   mutt_bcache_close (&(*idata)->bcache);
   mutt_buffer_free(&(*idata)->cmdbuf);
   FREE (&(*idata)->buf);
   mutt_bcache_close (&(*idata)->bcache);
+  FREE (&(*idata)->cmds);
   FREE (idata);                /* __FREE_CHECKED__ */
 }
 
   FREE (idata);                /* __FREE_CHECKED__ */
 }
 
@@ -380,31 +411,40 @@ void imap_free_idata (IMAP_DATA** idata)
  * are not required to do this.
  * Moreover, IMAP servers may dislike the path ending with the delimiter.
  */
  * are not required to do this.
  * Moreover, IMAP servers may dislike the path ending with the delimiter.
  */
-char *imap_fix_path (IMAP_DATA *idata, char *mailbox, char *path, 
+char *imap_fix_path (IMAP_DATA *idata, const char *mailbox, char *path,
     size_t plen)
 {
     size_t plen)
 {
-  int x = 0;
+  int i = 0;
+  char delim = '\0';
+
+  if (idata)
+    delim = idata->delim;
 
 
-  while (mailbox && *mailbox && (x < (plen - 1)))
+  while (mailbox && *mailbox && i < plen - 1)
   {
   {
-    if ((*mailbox == '/') || (*mailbox == idata->delim))
+    if ((ImapDelimChars && strchr(ImapDelimChars, *mailbox))
+        || (delim && *mailbox == delim))
     {
     {
-      while ((*mailbox == '/') || (*mailbox == idata->delim)) mailbox++;
-      path[x] = idata->delim;
+      /* use connection delimiter if known. Otherwise use user delimiter */
+      if (!idata)
+        delim = *mailbox;
+
+      while (*mailbox
+            && ((ImapDelimChars && strchr(ImapDelimChars, *mailbox))
+                || (delim && *mailbox == delim)))
+        mailbox++;
+      path[i] = delim;
     }
     else
     {
     }
     else
     {
-      path[x] = *mailbox;
+      path[i] = *mailbox;
       mailbox++;
     }
       mailbox++;
     }
-    x++;
+    i++;
   }
   }
-  if (x && path[--x] != idata->delim)
-    x++;
-  path[x] = '\0';
-
-  if (!path[0])
-    strfcpy (path, "INBOX", plen);
+  if (i && path[--i] != delim)
+    i++;
+  path[i] = '\0';
 
   return path;
 }
 
   return path;
 }
@@ -498,7 +538,7 @@ time_t imap_parse_date (char *s)
   struct tm t;
   time_t tz;
 
   struct tm t;
   time_t tz;
 
-  t.tm_mday = (s[0] == ' '? s[1] - '0' : (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;
   s += 2;
   if (*s != '-')
     return 0;
@@ -540,6 +580,21 @@ time_t imap_parse_date (char *s)
   return (mutt_mktime (&t, 0) + tz);
 }
 
   return (mutt_mktime (&t, 0) + tz);
 }
 
+/* format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz.
+ * Caller should provide a buffer of IMAP_DATELEN bytes */
+void imap_make_date (char *buf, time_t timestamp)
+{
+  struct tm* tm = localtime (&timestamp);
+  time_t tz = mutt_local_tz (timestamp);
+
+  tz /= 60;
+
+  snprintf (buf, IMAP_DATELEN, "%02d-%s-%d %02d:%02d:%02d %+03d%02d",
+      tm->tm_mday, Months[tm->tm_mon], tm->tm_year + 1900,
+      tm->tm_hour, tm->tm_min, tm->tm_sec,
+      (int) tz / 60, (int) abs (tz) % 60);
+}
+
 /* imap_qualify_path: make an absolute IMAP folder target, given IMAP_MBOX
  *   and relative path. */
 void imap_qualify_path (char *dest, size_t len, IMAP_MBOX *mx, char* path)
 /* imap_qualify_path: make an absolute IMAP folder target, given IMAP_MBOX
  *   and relative path. */
 void imap_qualify_path (char *dest, size_t len, IMAP_MBOX *mx, char* path)
@@ -566,7 +621,7 @@ void imap_quote_string (char *dest, size_t dlen, const char *src)
   *pt++ = '"';
   /* save room for trailing quote-char */
   dlen -= 2;
   *pt++ = '"';
   /* save room for trailing quote-char */
   dlen -= 2;
-  
+
   for (; *s && dlen; s++)
   {
     if (strchr (quote, *s))
   for (; *s && dlen; s++)
   {
     if (strchr (quote, *s))
@@ -646,7 +701,7 @@ void imap_unmunge_mbox_name (char *s)
     imap_utf7_decode (&buf);
     strncpy (s, buf, strlen (s));
   }
     imap_utf7_decode (&buf);
     strncpy (s, buf, strlen (s));
   }
-  
+
   FREE (&buf);
 }
 
   FREE (&buf);
 }
 
@@ -672,10 +727,10 @@ int imap_wordcasecmp(const char *a, const char *b)
   return ascii_strcasecmp(a, tmp);
 }
 
   return ascii_strcasecmp(a, tmp);
 }
 
-/* 
+/*
  * Imap keepalive: poll the current folder to keep the
  * connection alive.
  * Imap keepalive: poll the current folder to keep the
  * connection alive.
- * 
+ *
  */
 
 static RETSIGTYPE alrm_handler (int sig)
  */
 
 static RETSIGTYPE alrm_handler (int sig)
@@ -694,6 +749,8 @@ void imap_keepalive (void)
   {
     if (conn->account.type == M_ACCT_TYPE_IMAP)
     {
   {
     if (conn->account.type == M_ACCT_TYPE_IMAP)
     {
+      int need_free = 0;
+
       idata = (IMAP_DATA*) conn->data;
 
       if (idata->state >= IMAP_AUTHENTICATED
       idata = (IMAP_DATA*) conn->data;
 
       if (idata->state >= IMAP_AUTHENTICATED
@@ -705,9 +762,17 @@ void imap_keepalive (void)
        {
          ctx = safe_calloc (1, sizeof (CONTEXT));
          ctx->data = idata;
        {
          ctx = safe_calloc (1, sizeof (CONTEXT));
          ctx->data = idata;
+         /* imap_close_mailbox will set ctx->iadata->ctx to NULL, so we can't
+          * rely on the value of iadata->ctx to determine if this placeholder
+          * context needs to be freed.
+          */
+         need_free = 1;
        }
        }
+       /* if the imap connection closes during this call, ctx may be invalid
+        * after this point, and thus should not be read.
+        */
        imap_check_mailbox (ctx, NULL, 1);
        imap_check_mailbox (ctx, NULL, 1);
-       if (!idata->ctx)
+       if (need_free)
          FREE (&ctx);
       }
     }
          FREE (&ctx);
       }
     }
@@ -724,7 +789,7 @@ int imap_wait_keepalive (pid_t pid)
   int rc;
 
   short imap_passive = option (OPTIMAPPASSIVE);
   int rc;
 
   short imap_passive = option (OPTIMAPPASSIVE);
-  
+
   set_option (OPTIMAPPASSIVE);
   set_option (OPTKEEPQUIET);
 
   set_option (OPTIMAPPASSIVE);
   set_option (OPTKEEPQUIET);
 
@@ -749,7 +814,7 @@ int imap_wait_keepalive (pid_t pid)
   }
 
   alarm (0);   /* cancel a possibly pending alarm */
   }
 
   alarm (0);   /* cancel a possibly pending alarm */
-  
+
   sigaction (SIGALRM, &oldalrm, NULL);
   sigprocmask (SIG_SETMASK, &oldmask, NULL);
 
   sigaction (SIGALRM, &oldalrm, NULL);
   sigprocmask (SIG_SETMASK, &oldmask, NULL);
 
@@ -773,3 +838,13 @@ void imap_disallow_reopen (CONTEXT *ctx)
   if (ctx && ctx->magic == M_IMAP && CTX_DATA->ctx == ctx)
     CTX_DATA->reopen &= ~IMAP_REOPEN_ALLOW;
 }
   if (ctx && ctx->magic == M_IMAP && CTX_DATA->ctx == ctx)
     CTX_DATA->reopen &= ~IMAP_REOPEN_ALLOW;
 }
+
+int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2)
+{
+  IMAP_DATA* a1_idata = imap_conn_find (a1, M_IMAP_CONN_NONEW);
+  IMAP_DATA* a2_idata = imap_conn_find (a2, M_IMAP_CONN_NONEW);
+  const ACCOUNT* a1_canon = a1_idata == NULL ? a1 : &a1_idata->conn->account;
+  const ACCOUNT* a2_canon = a2_idata == NULL ? a2 : &a2_idata->conn->account;
+
+  return mutt_account_match (a1_canon, a2_canon);
+}