]> git.llucax.com Git - software/mutt-debian.git/blobdiff - imap/util.c
Standards-Version upgraded to 3.9.2.0, no changes required
[software/mutt-debian.git] / imap / util.c
index 45e5673ba7af5ef54a10dc50123ffddfc70aa260..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-2008 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 */
 
@@ -54,6 +54,7 @@
 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;
   char fixedpath[LONG_STRING];
   int rc;
   ciss_url_t url;
   char fixedpath[LONG_STRING];
   int rc;
@@ -61,8 +62,9 @@ int imap_expand_path (char* path, size_t len)
   if (imap_parse_path (path, &mx) < 0)
     return -1;
 
   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);
-  imap_fix_path(NULL, mx.mbox, fixedpath, sizeof (fixedpath));
+  imap_fix_path (idata, mx.mbox, fixedpath, sizeof (fixedpath));
   url.path = fixedpath;
 
   rc = url_ciss_tostring (&url, path, len, U_DECODE_PASSWD);
   url.path = fixedpath;
 
   rc = url_ciss_tostring (&url, path, len, U_DECODE_PASSWD);
@@ -127,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);
   }
 
@@ -224,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';
@@ -232,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;
@@ -266,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
@@ -296,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;
@@ -389,25 +411,27 @@ 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)
 {
   int i = 0;
     size_t plen)
 {
   int i = 0;
-  char delim;
-  
+  char delim = '\0';
+
   if (idata)
     delim = idata->delim;
   if (idata)
     delim = idata->delim;
-  else if (ImapDelimChars && ImapDelimChars[0])
-    delim = ImapDelimChars[0];
-  else
-    delim = '/';
 
   while (mailbox && *mailbox && i < plen - 1)
   {
 
   while (mailbox && *mailbox && i < plen - 1)
   {
-    if (strchr(ImapDelimChars, *mailbox) || *mailbox == delim)
+    if ((ImapDelimChars && strchr(ImapDelimChars, *mailbox))
+        || (delim && *mailbox == delim))
     {
     {
-      while (*mailbox &&
-            (strchr(ImapDelimChars, *mailbox) || *mailbox == 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;
     }
         mailbox++;
       path[i] = delim;
     }
@@ -514,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;
@@ -556,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)
@@ -582,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))
@@ -662,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);
 }
 
@@ -688,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)
@@ -710,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
@@ -721,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);
       }
     }
@@ -740,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);
 
@@ -765,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);