]> granicus.if.org Git - mutt/commitdiff
Add support for utf-8 mailboxes in imap.
authorKevin McCarthy <kevin@8t8.us>
Thu, 17 Jul 2014 14:05:47 +0000 (16:05 +0200)
committerKevin McCarthy <kevin@8t8.us>
Thu, 17 Jul 2014 14:05:47 +0000 (16:05 +0200)
This adds support for RFC6855 to imap/*.c.

Thanks to Arnt Gulbrandsen for the original patch.

imap/browse.c
imap/command.c
imap/imap.c
imap/imap_private.h
imap/message.c
imap/utf7.c
imap/util.c

index 8b60bc782aafbffbe914cb51f0d31721f7fc8a57..2cd091dd1106109e13cbfb5e921c6c336ccc7154 100644 (file)
@@ -75,7 +75,7 @@ int imap_browse (char* path, struct browser_state* state)
     char *ptr;
     imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
     ptr = safe_strdup (mbox);
-    imap_utf7_encode (&ptr);
+    imap_utf_encode (idata, &ptr);
     mbox[sizeof (mbox) - 1] = '\0';
     strncpy (mbox, ptr, sizeof (mbox) - 1);
     FREE (&ptr);
@@ -400,11 +400,14 @@ static void imap_add_folder (char delim, char *folder, int noselect,
   char tmp[LONG_STRING];
   char relpath[LONG_STRING];
   IMAP_MBOX mx;
+  IMAP_DATA* idata;
 
   if (imap_parse_path (state->folder, &mx))
     return;
+  if (!(idata = imap_conn_find (&(mx.account), 0)))
+    return;
 
-  imap_unmunge_mbox_name (folder);
+  imap_unmunge_mbox_name (idata, folder);
 
   if (state->entrylen + 1 == state->entrymax)
   {
index 32f84178d7ff66afa982f765c63f7d715af3c608..5fd4e690d34c9521af5de8ec509e380a1f14e10c 100644 (file)
@@ -51,6 +51,7 @@ static void cmd_parse_fetch (IMAP_DATA* idata, char* s);
 static void cmd_parse_myrights (IMAP_DATA* idata, const char* s);
 static void cmd_parse_search (IMAP_DATA* idata, const char* s);
 static void cmd_parse_status (IMAP_DATA* idata, char* s);
+static void cmd_parse_enabled (IMAP_DATA* idata, const char* s);
 
 static const char * const Capabilities[] = {
   "IMAP4",
@@ -65,6 +66,7 @@ static const char * const Capabilities[] = {
   "LOGINDISABLED",
   "IDLE",
   "SASL-IR",
+  "ENABLE",
 
   NULL
 };
@@ -522,6 +524,8 @@ static int cmd_handle_untagged (IMAP_DATA* idata)
     cmd_parse_search (idata, s);
   else if (ascii_strncasecmp ("STATUS", s, 6) == 0)
     cmd_parse_status (idata, s);
+  else if (ascii_strncasecmp ("ENABLED", s, 7) == 0)
+    cmd_parse_enabled (idata, s);
   else if (ascii_strncasecmp ("BYE", s, 3) == 0)
   {
     dprint (2, (debugfile, "Handling BYE\n"));
@@ -728,7 +732,7 @@ static void cmd_parse_list (IMAP_DATA* idata, char* s)
   }
   else
   {
-    imap_unmunge_mbox_name (s);
+    imap_unmunge_mbox_name (idata, s);
     list->name = s;
   }
 
@@ -917,7 +921,7 @@ static void cmd_parse_status (IMAP_DATA* idata, char* s)
   {
     s = imap_next_word (mailbox);
     *(s - 1) = '\0';
-    imap_unmunge_mbox_name (mailbox);
+    imap_unmunge_mbox_name (idata, mailbox);
   }
 
   status = imap_mboxcache_get (idata, mailbox, 1);
@@ -1022,3 +1026,16 @@ static void cmd_parse_status (IMAP_DATA* idata, char* s)
     FREE (&mx.mbox);
   }
 }
+
+/* cmd_parse_enabled: record what the server has enabled */
+static void cmd_parse_enabled (IMAP_DATA* idata, const char* s)
+{
+  dprint (2, (debugfile, "Handling ENABLED\n"));
+
+  while ((s = imap_next_word ((char*)s)) && *s != '\0')
+  {
+    if (ascii_strncasecmp(s, "UTF8=ACCEPT", 11) == 0 ||
+        ascii_strncasecmp(s, "UTF8=ONLY", 9) == 0)
+      idata->unicode = 1;
+  }
+}
index ad15f5e1706d755f1895ea9cc08bad80eecaa382..b2fb2cbad8caa142b26711e3a70a9d77dc2e7e14 100644 (file)
@@ -92,7 +92,7 @@ int imap_access (const char* path, int flags)
     return 0;
   }
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
 
   if (mutt_bit_isset (idata->capabilities, IMAP4REV1))
     snprintf (buf, sizeof (buf), "STATUS %s (UIDVALIDITY)", mbox);
@@ -117,7 +117,7 @@ int imap_create_mailbox (IMAP_DATA* idata, char* mailbox)
 {
   char buf[LONG_STRING], mbox[LONG_STRING];
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
   snprintf (buf, sizeof (buf), "CREATE %s", mbox);
 
   if (imap_exec (idata, buf, 0) != 0)
@@ -135,8 +135,8 @@ int imap_rename_mailbox (IMAP_DATA* idata, IMAP_MBOX* mx, const char* newname)
   char newmbox[LONG_STRING];
   char buf[LONG_STRING];
 
-  imap_munge_mbox_name (oldmbox, sizeof (oldmbox), mx->mbox);
-  imap_munge_mbox_name (newmbox, sizeof (newmbox), newname);
+  imap_munge_mbox_name (idata, oldmbox, sizeof (oldmbox), mx->mbox);
+  imap_munge_mbox_name (idata, newmbox, sizeof (newmbox), newname);
 
   snprintf (buf, sizeof (buf), "RENAME %s %s", oldmbox, newmbox);
 
@@ -162,7 +162,7 @@ int imap_delete_mailbox (CONTEXT* ctx, IMAP_MBOX mx)
     idata = ctx->data;
   }
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mx.mbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mx.mbox);
   snprintf (buf, sizeof (buf), "DELETE %s", mbox);
 
   if (imap_exec ((IMAP_DATA*) idata, buf, 0) != 0)
@@ -386,6 +386,9 @@ IMAP_DATA* imap_conn_find (const ACCOUNT* account, int flags)
   {
     /* capabilities may have changed */
     imap_exec (idata, "CAPABILITY", IMAP_CMD_QUEUE);
+    /* enable RFC6855, if the server supports that */
+    if (mutt_bit_isset (idata->capabilities, ENABLE))
+      imap_exec (idata, "ENABLE UTF8=ACCEPT", IMAP_CMD_QUEUE);
     /* get root delimiter, '/' as default */
     idata->delim = '/';
     imap_exec (idata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
@@ -596,7 +599,7 @@ int imap_open_mailbox (CONTEXT* ctx)
   idata->newMailCount = 0;
 
   mutt_message (_("Selecting %s..."), idata->mailbox);
-  imap_munge_mbox_name (buf, sizeof(buf), idata->mailbox);
+  imap_munge_mbox_name (idata, buf, sizeof(buf), idata->mailbox);
 
   /* pipeline ACL test */
   if (mutt_bit_isset (idata->capabilities, ACL))
@@ -1521,7 +1524,7 @@ int imap_buffy_check (int force)
     if (!lastdata)
       lastdata = idata;
 
-    imap_munge_mbox_name (munged, sizeof (munged), name);
+    imap_munge_mbox_name (idata, munged, sizeof (munged), name);
     snprintf (command, sizeof (command),
              "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
 
@@ -1569,9 +1572,9 @@ int imap_status (char* path, int queue)
   else if (mutt_bit_isset(idata->capabilities,IMAP4REV1) ||
           mutt_bit_isset(idata->capabilities,STATUS))
   {
-    imap_munge_mbox_name (mbox, sizeof(mbox), buf);
+    imap_munge_mbox_name (idata, mbox, sizeof(mbox), buf);
     snprintf (buf, sizeof (buf), "STATUS %s (%s)", mbox, "MESSAGES");
-    imap_unmunge_mbox_name (mbox);
+    imap_unmunge_mbox_name (idata, mbox);
   }
   else
     /* Server does not support STATUS, and this is not the current mailbox.
@@ -1851,14 +1854,14 @@ int imap_subscribe (char *path, int subscribe)
     mutt_message (_("Subscribing to %s..."), buf);
   else
     mutt_message (_("Unsubscribing from %s..."), buf);
-  imap_munge_mbox_name (mbox, sizeof(mbox), buf);
+  imap_munge_mbox_name (idata, mbox, sizeof(mbox), buf);
 
   snprintf (buf, sizeof (buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mbox);
 
   if (imap_exec (idata, buf, 0) < 0)
     goto fail;
 
-  imap_unmunge_mbox_name(mx.mbox);
+  imap_unmunge_mbox_name(idata, mx.mbox);
   if (subscribe)
     mutt_message (_("Subscribed to %s"), mx.mbox);
   else
index ab7ba8a9e8800ebfd04462e6657a580eed186db8..ef1d2d217468fc912e891a979ffeb0a5de4d982f 100644 (file)
@@ -115,6 +115,7 @@ enum
   LOGINDISABLED,               /*           LOGINDISABLED */
   IDLE,                         /* RFC 2177: IDLE */
   SASL_IR,                      /* SASL initial response draft */
+  ENABLE,                       /* RFC 5161 */
 
   CAPMAX
 };
@@ -144,7 +145,7 @@ typedef struct
 typedef struct
 {
   char* name;
-  
+
   char delim;
   /* if we end up storing a lot of these we could turn this into a bitfield */
   unsigned char noselect;
@@ -186,6 +187,10 @@ typedef struct
   char* buf;
   unsigned int blen;
   
+  /* If nonzero, we can send UTF-8, and the server will use UTF8 rather
+   * than mUTF7 */
+  int unicode;
+
   /* if set, the response parser will store results for complicated commands
    * here. */
   IMAP_COMMAND_TYPE cmdtype;
@@ -289,13 +294,13 @@ void imap_make_date (char* buf, time_t timestamp);
 void imap_qualify_path (char *dest, size_t len, IMAP_MBOX *mx, char* path);
 void imap_quote_string (char* dest, size_t slen, const char* src);
 void imap_unquote_string (char* s);
-void imap_munge_mbox_name (char *dest, size_t dlen, const char *src);
-void imap_unmunge_mbox_name (char *s);
+void imap_munge_mbox_name (IMAP_DATA *idata, char *dest, size_t dlen, const char *src);
+void imap_unmunge_mbox_name (IMAP_DATA *idata, char *s);
 int imap_wordcasecmp(const char *a, const char *b);
 
 /* utf7.c */
-void imap_utf7_encode (char **s);
-void imap_utf7_decode (char **s);
+void imap_utf_encode (IMAP_DATA *idata, char **s);
+void imap_utf_decode (IMAP_DATA *idata, char **s);
 
 #if USE_HCACHE
 /* typedef size_t (*hcache_keylen_t)(const char* fn); */
index 3877381817cdb1db97cb14490198219e58ac8b24..3972f60f52b9f18f4d231175ed94a0b745677879 100644 (file)
@@ -642,7 +642,7 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
   mutt_progress_init (&progressbar, _("Uploading message..."),
                      M_PROGRESS_SIZE, NetInc, len);
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
   imap_make_date (internaldate, msg->received);
 
   imap_flags[0] = imap_flags[1] = 0;
@@ -773,7 +773,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
   imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
   if (!*mbox)
     strfcpy (mbox, "INBOX", sizeof (mbox));
-  imap_munge_mbox_name (mmbox, sizeof (mmbox), mbox);
+  imap_munge_mbox_name (idata, mmbox, sizeof (mmbox), mbox);
 
   /* loop in case of TRYCREATE */
   do
index a433971c42088ca079a0968fb27e01949745aa12..ed8723c8be43fb2bf4fd8232739e57090d6463f1 100644 (file)
@@ -252,30 +252,40 @@ static char *utf8_to_utf7 (const char *u8, size_t u8len, char **u7,
   return 0;
 }
 
-void imap_utf7_encode (char **s)
+void imap_utf_encode (IMAP_DATA *idata, char **s)
 {
   if (Charset)
   {
     char *t = safe_strdup (*s);
-    if (!mutt_convert_string (&t, Charset, "utf-8", 0))
+    if (t && !mutt_convert_string (&t, Charset, "utf-8", 0))
     {
-      char *u7 = utf8_to_utf7 (t, strlen (t), NULL, 0);
       FREE (s);                /* __FREE_CHECKED__ */
-      *s = u7;
+      if (idata->unicode)
+        *s = safe_strdup (t);
+      else
+        *s = utf8_to_utf7 (t, strlen (t), NULL, 0);
     }
     FREE (&t);
   }
 }
 
-void imap_utf7_decode (char **s)
+void imap_utf_decode (IMAP_DATA *idata, char **s)
 {
+  char *t;
+
   if (Charset)
   {
-    char *t = utf7_to_utf8 (*s, strlen (*s), 0, 0);
+    if (idata->unicode)
+      t = safe_strdup (*s);
+    else
+      t = utf7_to_utf8 (*s, strlen (*s), 0, 0);
+
     if (t && !mutt_convert_string (&t, "utf-8", Charset, 0))
     {
       FREE (s);                /* __FREE_CHECKED__ */
       *s = t;
     }
+    else
+      FREE (&t);
   }
 }
index c05465a3e8ff9ed238672eee02bdbc76bfc465f2..9b9f07f658ddef560fe6f1c4262d9bf95cdfa139 100644 (file)
@@ -673,23 +673,24 @@ void imap_unquote_string (char *s)
   *d = '\0';
 }
 
+
 /*
  * Quoting and UTF-7 conversion
  */
 
-void imap_munge_mbox_name (char *dest, size_t dlen, const char *src)
+void imap_munge_mbox_name (IMAP_DATA *idata, char *dest, size_t dlen, const char *src)
 {
   char *buf;
 
   buf = safe_strdup (src);
-  imap_utf7_encode (&buf);
+  imap_utf_encode (idata, &buf);
 
   imap_quote_string (dest, dlen, buf);
 
   FREE (&buf);
 }
 
-void imap_unmunge_mbox_name (char *s)
+void imap_unmunge_mbox_name (IMAP_DATA *idata, char *s)
 {
   char *buf;
 
@@ -698,7 +699,7 @@ void imap_unmunge_mbox_name (char *s)
   buf = safe_strdup (s);
   if (buf)
   {
-    imap_utf7_decode (&buf);
+    imap_utf_decode (idata, &buf);
     strncpy (s, buf, strlen (s));
   }