Re: ANNOUNCE: development balsa-2.1.1 released




On 03/02/2004 12:19:24 AM, J.A. Magallon wrote:
> 
> On 02.29, Pawel Salek wrote:
> > Hello,
> >
> > Balsa team would like to officially announce balsa-2.1.1 release
> > available at http://balsa.gnome.org/
> >
> 
> Uh, how did this pass your compiler ?
> 
> imap-handle.c:286: error: conflicting types for
> 'imap_mbox_handle_reconnect'

gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5) seems to be very  
forgiving. I have just fixed it in cvs (and few more, too). The patch  
contains the fixes (+implementation of UTF7 for mailbox names - it cannot  
hurt). Thanks for pointing this out!

Pawel

Index: libbalsa/imap/imap-auth.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/imap/imap-auth.c,v
retrieving revision 1.9
diff -u -r1.9 imap-auth.c
--- libbalsa/imap/imap-auth.c	29 Feb 2004 16:40:37 -0000	1.9
+++ libbalsa/imap/imap-auth.c	2 Mar 2004 23:13:22 -0000
@@ -30,7 +30,7 @@
 #include "imap_private.h"
 
 /* ordered from strongest to weakest */
-ImapAuthenticator imap_authenticators_arr[] = {
+static ImapAuthenticator imap_authenticators_arr[] = {
   imap_auth_cram,
   imap_auth_login,
   NULL
Index: libbalsa/imap/imap-commands.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/imap/imap-commands.c,v
retrieving revision 1.33
diff -u -r1.33 imap-commands.c
--- libbalsa/imap/imap-commands.c	2 Mar 2004 10:57:56 -0000	1.33
+++ libbalsa/imap/imap-commands.c	2 Mar 2004 23:13:23 -0000
@@ -23,6 +23,7 @@
 #include "imap-commands.h"
 #include "imap_private.h"
 #include "siobuf.h"
+#include "util.h"
 
 #define ELEMENTS(x) (sizeof (x) / sizeof(x[0]))
 struct msg_set {
@@ -50,11 +51,11 @@
     if(seq<=hi && (num=incl(seq, data)) != 0) {
       switch(mode) {
       case BEGIN: 
-        sprintf(buf, "%d", num); g_string_append(res, buf); 
+        sprintf(buf, "%u", num); g_string_append(res, buf); 
         mode = LASTIN; break;
       case RANGE:
         if(num!=prev+1) {
-          sprintf(buf, ":%d,%d", prev, num); g_string_append(res, buf); 
+          sprintf(buf, ":%u,%u", prev, num); g_string_append(res, buf); 
           mode = LASTIN;
         }
         break;
@@ -64,7 +65,7 @@
           break;
         } /* else fall through */
       case LASTOUT: 
-        sprintf(buf, ",%d", num); g_string_append(res, buf); 
+        sprintf(buf, ",%u", num); g_string_append(res, buf); 
         mode = LASTIN; break;
       }
     } else {
@@ -73,7 +74,7 @@
       case LASTOUT: break;
       case LASTIN: mode = LASTOUT; break;
       case RANGE: 
-        sprintf(buf, ":%d", prev); g_string_append(res, buf); 
+        sprintf(buf, ":%u", prev); g_string_append(res, buf); 
         mode = LASTOUT;
         break;
       }
@@ -203,7 +204,7 @@
 imap_mbox_select(ImapMboxHandle* handle, const char *mbox,
                  gboolean *readonly_mbox)
 {
-  gchar* cmd;
+  gchar* cmd, *mbx7;
   ImapResponse rc;
 
   if (handle->state == IMHS_SELECTED && strcmp(handle->mbox, mbox) == 0)
@@ -213,7 +214,10 @@
   mbox_view_dispose(&handle->mbox_view);
   handle->unseen = 0;
 
-  cmd = g_strdup_printf("SELECT \"%s\"", mbox);
+  mbx7 = imap_utf8_to_mailbox(mbox);
+
+  cmd = g_strdup_printf("SELECT \"%s\"", mbx7);
+  g_free(mbx7);
   rc= imap_cmd_exec(handle, cmd);
   g_free(cmd);
   if(rc == IMR_OK) {
@@ -234,9 +238,10 @@
 ImapResponse
 imap_mbox_examine(ImapMboxHandle* handle, const char* mbox)
 {
-  gchar* cmd = g_strdup_printf("EXAMINE %s", mbox);
+  gchar *mbx7 = imap_utf8_to_mailbox(mbox);
+  gchar* cmd = g_strdup_printf("EXAMINE \"%s\"", mbx7);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
-  g_free(cmd);
+  g_free(mbx7); g_free(cmd);
   if(rc == IMR_OK) {
     g_free(handle->mbox);
     handle->mbox = g_strdup(mbox);
@@ -248,11 +253,12 @@
 
 /* 6.3.3 CREATE Command */
 ImapResponse
-imap_mbox_create(ImapMboxHandle* handle, const char* new_mbox)
+imap_mbox_create(ImapMboxHandle* handle, const char* mbox)
 {
-  gchar* cmd = g_strdup_printf("CREATE \"%s\"", new_mbox);
+  gchar *mbx7 = imap_utf8_to_mailbox(mbox);
+  gchar* cmd = g_strdup_printf("CREATE \"%s\"", mbx7);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
-  g_free(cmd);
+  g_free(mbx7); g_free(cmd);
   return rc;
 }
 
@@ -261,7 +267,8 @@
 ImapResponse
 imap_mbox_delete(ImapMboxHandle* handle, const char* mbox)
 {
-  gchar* cmd = g_strdup_printf("DELETE \"%s\"", mbox);
+  gchar *mbx7 = imap_utf8_to_mailbox(mbox);
+  gchar* cmd = g_strdup_printf("DELETE \"%s\"", mbx7);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
   g_free(cmd);
   return rc;
@@ -274,7 +281,10 @@
 		 const char* old_mbox,
 		 const char* new_mbox)
 {
-  gchar* cmd = g_strdup_printf("RENAME \"%s\" \"%s\"", old_mbox, new_mbox);
+  gchar *mbx7o = imap_utf8_to_mailbox(old_mbox);
+  gchar *mbx7n = imap_utf8_to_mailbox(old_mbox);
+
+  gchar* cmd = g_strdup_printf("RENAME \"%s\" \"%s\"", mbx7o, mbx7n);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
   g_free(cmd);
   return rc;
@@ -287,11 +297,12 @@
 imap_mbox_subscribe(ImapMboxHandle* handle,
 		    const char* mbox, gboolean subscribe)
 {
+  gchar *mbx7 = imap_utf8_to_mailbox(mbox);
   gchar* cmd = g_strdup_printf("%s \"%s\"",
 			       subscribe ? "SUBSCRIBE" : "UNSUBSCRIBE",
-			       mbox);
+			       mbx7);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
-  g_free(cmd);
+  g_free(mbx7); g_free(cmd);
   return rc;
 }
 
@@ -300,7 +311,8 @@
 ImapResponse
 imap_mbox_list(ImapMboxHandle *handle, const char* what)
 {
-  gchar * cmd = g_strdup_printf("LIST \"%s\" \"%%\"", what);
+  gchar *mbx7 = imap_utf8_to_mailbox(what);
+  gchar *cmd = g_strdup_printf("LIST \"%s\" \"%%\"", mbx7);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
   g_free(cmd);
   return rc;
@@ -311,9 +323,10 @@
 ImapResponse
 imap_mbox_lsub(ImapMboxHandle *handle, const char* what)
 {
-  gchar * cmd = g_strdup_printf("LSUB \"%s\" \"%%\"", what);
+  gchar *mbx7 = imap_utf8_to_mailbox(what);
+  gchar *cmd = g_strdup_printf("LSUB \"%s\" \"%%\"", mbx7);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
-  g_free(cmd);
+  g_free(mbx7); g_free(cmd);
   return rc;
 }
 
@@ -324,7 +337,7 @@
 
 /* 6.3.11 APPEND Command */
 static gchar*
-enum_flag_to_str(ImapMsgFlag flg)
+enum_flag_to_str(ImapMsgFlags flg)
 {
   GString *flags_str = g_string_new("");
   unsigned idx;
@@ -343,62 +356,61 @@
                  ImapMsgFlags flags, size_t sz,
                  ImapAppendFunc dump_cb, void *arg)
 {
+  int use_literal = imap_mbox_handle_can_do(handle, IMCAP_LITERAL);
   unsigned cmdno;
   ImapResponse rc;
-  /* FIXME: quoting */
+  gchar *mbx7 = imap_utf8_to_mailbox(mbox);
   gchar *cmd;
+  char *litstr = use_literal ? "+" : "";
+  char buf[4096];
+  size_t s, delta;
+  int c;
 
   if(flags) {
     gchar *str = enum_flag_to_str(flags);
-    cmd = g_strdup_printf("APPEND \"%s\" (%s) {%d}", mbox, str, sz);
+    cmd = g_strdup_printf("APPEND \"%s\" (%s) {%u%s}", mbx7, str, sz, litstr);
     g_free(str);
   } else 
-    cmd = g_strdup_printf("APPEND \"%s\" {%d}", mbox, sz);
+    cmd = g_strdup_printf("APPEND \"%s\" {%u%s}", mbx7, sz, litstr);
 
-  rc = imap_cmd_start(handle, cmd, &cmdno);
-  g_free(cmd);
-  if (rc<0) /* irrecoverable connection error. */
+  c = imap_cmd_start(handle, cmd, &cmdno);
+  g_free(mbx7); g_free(cmd);
+  if (c<0) /* irrecoverable connection error. */
     return IMR_SEVERED;
+  if(use_literal)
+    rc = IMR_RESPOND; /* we do it without flushing */
+  else {
+    sio_flush(handle->sio);
+    do {
+      rc = imap_cmd_step (handle, cmdno);
+    } while (rc == IMR_UNTAGGED);
+    if(rc != IMR_RESPOND) return rc;
+    while( (c=sio_getc(handle->sio)) != -1 && c != '\n');
+  } 
 
+  for(s=0; s<sz; s+= delta) {
+    delta = dump_cb(buf, sizeof(buf), arg);
+    if(s+delta>sz) delta = sz-s;
+    sio_write(handle->sio, buf, delta);
+  }
+  
+  /* It has been though observed that "Cyrus IMAP4 v2.0.16-p1
+   * server" can hang if the flush isn't done under following conditions:
+   * a). TLS is enabled, b). message contains NUL characters.  NUL
+   * characters are forbidden (RFC3501, sect. 4.3.1) and we probably
+   * should make sure on a higher level that they are not sent.
+   */
+  /* sio_flush(handle->sio); */
+  sio_write(handle->sio, "\r\n", 2);
   sio_flush(handle->sio);
   do {
     rc = imap_cmd_step (handle, cmdno);
   } while (rc == IMR_UNTAGGED);
-  
-  if (rc == IMR_RESPOND) {
-    char buf[4096];
-    size_t s, delta;
-    int c;
-    while( (c=sio_getc(handle->sio)) != -1 && c != '\n');
-    for(s=0; s<sz; s+= delta) {
-      delta = dump_cb(buf, sizeof(buf), arg);
-      if(s+delta>sz) delta = sz-s;
-      sio_write(handle->sio, buf, delta);
-    }
 
-    /* It has been though observed that "Cyrus IMAP4 v2.0.16-p1
-     * server" can hang if this isn't done under following conditions:
-     * a). TLS is enabled, b). message contains NUL characters.  NUL
-     * characters are forbidden (RFC3501, sect. 4.3.1) and we probably
-     * should make sure on a higher level that they are not sent.
-     */
-    sio_flush(handle->sio);
-    sio_write(handle->sio, "\r\n", 2);
-    sio_flush(handle->sio);
-    do {
-      rc = imap_cmd_step (handle, cmdno);
-    } while (rc == IMR_UNTAGGED);
-  } /* FIXME: else unexpected response */
   return rc;
 }
 
-#if USE_STRING_BUF	/* not used currently */
-struct string_buf {
-  char *string;
-  unsigned pos;
-};
-#endif
-#if USE_IMAP_APPEND_STR	/* not used currently */
+#ifdef USE_IMAP_APPEND_STR	/* not used currently */
 static size_t
 pass_str(char* buf, size_t sz, void*arg)
 {
@@ -461,40 +473,6 @@
   return handle->unseen;
 }
 
-static void
-find_next_cb(ImapMboxHandle* handle, unsigned seqno, unsigned *res)
-{
-  if(!*res)
-    *res = seqno;
-}
-
-
-/* should chain up the callbacks */
-unsigned
-imap_mbox_find_next(ImapMboxHandle* handle, unsigned start, 
-                    const char *search_str)
-{
-  ImapResponse rc;
-  unsigned seqno = 0;
-  void *arg;
-  ImapSearchCb cb;
-  const char *filter_str = mbox_view_get_str(&handle->mbox_view);
-
-  cb  = handle->search_cb;  handle->search_cb  = (ImapSearchCb)find_next_cb;
-  arg = handle->search_arg; handle->search_arg = &seqno;
-  while(seqno==0 && start<=handle->exists) {
-    unsigned top = start+3000>handle->exists ? handle->exists : start+3000;
-    gchar * cmd = g_strdup_printf("SEARCH %d:%d (FROM \"%s\"%s%s)",
-                                  start, top, search_str,
-                                  *filter_str?" ":"", filter_str);
-    rc = imap_cmd_exec(handle, cmd);
-    g_free(cmd);
-    start = top+1;
-  }
-  handle->search_cb = cb; handle->search_arg = arg;
-  return seqno;
-}
-
 struct find_all_data {
   unsigned *seqno;
   unsigned msgcnt, allocated;
@@ -667,7 +645,7 @@
   char cmd[40];
   handle->body_cb  = body_cb;
   handle->body_arg = arg;
-  snprintf(cmd, sizeof(cmd), "FETCH %d BODY[%s]", seqno, section);
+  snprintf(cmd, sizeof(cmd), "FETCH %u BODY[%s]", seqno, section);
   return imap_cmd_exec(handle, cmd);
 }
 
@@ -727,7 +705,7 @@
   gchar* cmd, *str;
 
   str = enum_flag_to_str(flg);
-  cmd = g_strdup_printf("STORE %d %cFLAGS (%s)", seq,
+  cmd = g_strdup_printf("STORE %u %cFLAGS (%s)", seq,
                         state ? '+' : '-', str);
   g_free(str);
   rc = imap_cmd_exec(h, cmd);
@@ -743,9 +721,10 @@
 imap_mbox_handle_copy(ImapMboxHandle* handle, unsigned seqno,
                       const gchar *dest)
 {
-  gchar *cmd = g_strdup_printf("COPY %u \"%s\"", seqno, dest);
+  gchar *mbx7 = imap_utf8_to_mailbox(dest);
+  gchar *cmd = g_strdup_printf("COPY %u \"%s\"", seqno, mbx7);
   ImapResponse rc = imap_cmd_exec(handle, cmd);
-  g_free(cmd);
+  g_free(mbx7); g_free(cmd);
   return rc;
 }
 
Index: libbalsa/imap/imap-commands.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/imap/imap-commands.h,v
retrieving revision 1.17
diff -u -r1.17 imap-commands.h
--- libbalsa/imap/imap-commands.h	29 Feb 2004 16:40:37 -0000	1.17
+++ libbalsa/imap/imap-commands.h	2 Mar 2004 23:13:23 -0000
@@ -45,7 +45,7 @@
 ImapResponse imap_mbox_append(ImapMboxHandle *handle, const char *mbox,
                               ImapMsgFlags flags, size_t sz, 
                               ImapAppendFunc dump_cb,  void* arg);
-#if USE_IMAP_APPEND_STR /* not used currently */
+#ifdef USE_IMAP_APPEND_STR /* not used currently */
 ImapResponse imap_mbox_append_str(ImapMboxHandle *handle, const char *mbox,
                               ImapMsgFlags flags, size_t sz, char *txt);
 #endif
Index: libbalsa/imap/imap-handle.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/imap/imap-handle.c,v
retrieving revision 1.43
diff -u -r1.43 imap-handle.c
--- libbalsa/imap/imap-handle.c	2 Mar 2004 10:57:56 -0000	1.43
+++ libbalsa/imap/imap-handle.c	2 Mar 2004 23:13:23 -0000
@@ -46,8 +46,6 @@
 #include "siobuf.h"
 #include "util.h"
 
-FILE *debug_stream = NULL;
-
 #define LONG_STRING 512
 #define ELEMENTS(x) (sizeof (x) / sizeof(x[0]))
 
@@ -572,6 +570,8 @@
 
   mbox_view_dispose(&handle->mbox_view);
   imap_mbox_resize_cache(handle, 0);
+
+  G_OBJECT_CLASS(parent_class)->finalize(gobject);  
 }
 
 typedef void (*ImapTasklet)(ImapMboxHandle*, void*);
@@ -714,7 +714,7 @@
   rc = imap_cmd_exec(h, cmd);
   g_free(cmd);
   h->search_cb = cb; h->search_arg = arg;
-  return 1;
+  return rc == IMR_OK;
 }
 
 const char*
@@ -1084,9 +1084,8 @@
     return IMR_SEVERED;
 
   /* create sequence for command */
-  rc = imap_cmd_start(handle, cmd, &cmdno);
-  if (rc<0) /* irrecoverable connection error. */
-    return IMR_SEVERED;
+  if (imap_cmd_start(handle, cmd, &cmdno)<0)
+    return IMR_SEVERED;  /* irrecoverable connection error. */
 
   sio_flush(handle->sio);
   do {
@@ -1239,8 +1238,6 @@
 
 #include "imap-handle.h"
 
-ImapResponse (*handler)(ImapMboxHandle *h);
-
 static void
 ignore_bad_charset(struct siobuf *sio, int c)
 {
@@ -1432,7 +1429,7 @@
     "HasChildren", "HasNoChildren"
   };
   int flags = 0;
-  char buf[LONG_STRING], *s;
+  char buf[LONG_STRING], *s, *mbx;
   int c, delim;
   ImapResponse rc;
 
@@ -1464,10 +1461,12 @@
   if(sio_getc(h->sio) != ' ') return IMR_PROTOCOL;
   /* mailbox */
   s = imap_get_astring(h->sio, &c);
+  mbx = imap_mailbox_to_utf8(s);
   rc = ir_check_crlf(h, c);
   g_signal_emit(G_OBJECT(h), imap_mbox_handle_signals[signal],
-                0, delim, &flags, s);
+                0, delim, &flags, mbx);
   g_free(s);
+  g_free(mbx);
   return rc;
 }
 
Index: libbalsa/imap/imap-handle.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/imap/imap-handle.h,v
retrieving revision 1.20
diff -u -r1.20 imap-handle.h
--- libbalsa/imap/imap-handle.h	29 Feb 2004 16:40:37 -0000	1.20
+++ libbalsa/imap/imap-handle.h	2 Mar 2004 23:13:23 -0000
@@ -138,8 +138,8 @@
 
 ImapResult imap_mbox_handle_connect(ImapMboxHandle* r, const char *hst, 
                                     int over_ssl);
-ImapResponse imap_mbox_handle_reconnect(ImapMboxHandle* r,
-                                        gboolean *readonly);
+ImapResult imap_mbox_handle_reconnect(ImapMboxHandle* r,
+                                      gboolean *readonly);
 unsigned imap_mbox_handle_require_tls(ImapMboxHandle* r, unsigned state);
 
 /* int below is a boolean */
Index: libbalsa/imap/util.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/imap/util.c,v
retrieving revision 1.4
diff -u -r1.4 util.c
--- libbalsa/imap/util.c	29 Feb 2004 16:40:37 -0000	1.4
+++ libbalsa/imap/util.c	2 Mar 2004 23:13:23 -0000
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
+#include <stdlib.h>
 #include "util.h"
 
 #define SKIPWS(c) while (*(c) && isspace ((unsigned char) *(c))) c++;
@@ -136,7 +137,7 @@
   
 #define BAD     -1
 #define base64val(c) Index_64[(unsigned int)(c)]
-char B64Chars[64] = {
+static char B64Chars[64] = {
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
   'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
@@ -144,7 +145,7 @@
   '8', '9', '+', '/'
 };
 
-int Index_64[128] = {
+static int Index_64[128] = {
     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
@@ -229,3 +230,233 @@
 
   return len;
 }
+
+
+/* ===================================================================
+ * UTF-7 conversion routines as in RFC 2192
+ * =================================================================== */
+/* UTF7 modified base64 alphabet */
+static char base64chars[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
+#define UNDEFINED 64
+
+/* UTF16 definitions */
+#define UTF16MASK       0x03FFUL
+#define UTF16SHIFT      10
+#define UTF16BASE       0x10000UL
+#define UTF16HIGHSTART  0xD800UL
+#define UTF16HIGHEND    0xDBFFUL
+#define UTF16LOSTART    0xDC00UL
+#define UTF16LOEND      0xDFFFUL
+
+
+/* Convert an IMAP mailbox to a UTF-8 string.
+ *  dst needs to have roughly 4 times the storage space of src
+ *    Hex encoding can triple the size of the input
+ *    UTF-7 can be slightly denser than UTF-8
+ *     (worst case: 8 octets UTF-7 becomes 9 octets UTF-8)
+ */
+char*
+imap_mailbox_to_utf8(const unsigned char *mbox)
+{
+  unsigned c, i, bitcount;
+  unsigned long ucs4, utf16, bitbuf;
+  unsigned char base64[256];
+  const unsigned char *src;
+  char *dst, *res  = malloc(2*strlen(mbox)+1);
+  
+  bitbuf = 0;
+  dst = res;
+  src = mbox;
+  if(!dst) return NULL;
+  /* initialize modified base64 decoding table */
+  memset(base64, UNDEFINED, sizeof (base64));
+  for (i = 0; i < sizeof (base64chars); ++i) {
+    base64[(unsigned)base64chars[i]] = i;
+  }
+  
+  /* loop until end of string */
+  while (*src != '\0') {
+    c = *src++;
+    /* deal with literal characters and &- */
+    if (c != '&' || *src == '-') {
+      /* encode literally */
+      *dst++ = c;
+      /* skip over the '-' if this is an &- sequence */
+      if (c == '&') ++src;
+    } else {
+      /* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */
+      bitbuf = 0;
+      bitcount = 0;
+      ucs4 = 0;
+      while ((c = base64[(unsigned char) *src]) != UNDEFINED) {
+        ++src;
+        bitbuf = (bitbuf << 6) | c;
+        bitcount += 6;
+        /* enough bits for a UTF-16 character? */
+        if (bitcount >= 16) {
+          bitcount -= 16;
+          utf16 = (bitcount ? bitbuf >> bitcount
+                   : bitbuf) & 0xffff;
+          /* convert UTF16 to UCS4 */
+          if
+            (utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND) {
+            ucs4 = (utf16 - UTF16HIGHSTART) << UTF16SHIFT;
+            continue;
+          } else if
+            (utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND) {
+            ucs4 += utf16 - UTF16LOSTART + UTF16BASE;
+          } else {
+            ucs4 = utf16;
+          }
+          
+          /* convert UTF-16 range of UCS4 to UTF-8 */
+          if (ucs4 <= 0x7fUL) {
+            dst[0] = ucs4;
+            dst += 1;
+          } else if (ucs4 <= 0x7ffUL) {
+            dst[0] = 0xc0 | (ucs4 >> 6);
+            dst[1] = 0x80 | (ucs4 & 0x3f);
+            dst += 2;
+          } else if (ucs4 <= 0xffffUL) {
+            dst[0] = 0xe0 | (ucs4 >> 12);
+            dst[1] = 0x80 | ((ucs4 >> 6) & 0x3f);
+            dst[2] = 0x80 | (ucs4 & 0x3f);
+            dst += 3;
+          } else {
+            dst[0] = 0xf0 | (ucs4 >> 18);
+            dst[1] = 0x80 | ((ucs4 >> 12) & 0x3f);
+            dst[2] = 0x80 | ((ucs4 >> 6) & 0x3f);
+            dst[3] = 0x80 | (ucs4 & 0x3f);
+            dst += 4;
+          }
+        }
+      }
+      /* skip over trailing '-' in modified UTF-7 encoding */
+      if (*src == '-') ++src;
+    }
+  }
+  /* terminate destination string */
+  *dst = '\0';
+  return res;
+}
+
+/* Convert hex coded UTF-8 string to modified UTF-7 IMAP mailbox
+ *  dst should be about twice the length of src to deal with non-hex
+ *  coded URLs
+ */
+char*
+imap_utf8_to_mailbox(const unsigned char *src)
+{
+  unsigned int utf8pos, utf8total, c, utf7mode, bitstogo, utf16flag;
+  unsigned long ucs4 = 0, bitbuf = 0;
+
+  /* initialize hex lookup table */
+  unsigned char *dst, *res = malloc(2*strlen(src)+1);
+  dst = res;
+  if(!dst) return NULL;
+
+  utf7mode = 0;
+  utf8total = 0;
+  bitstogo = 0;
+  utf8pos = 0;
+  while ((c = *src) != '\0') {
+    ++src;
+    /* normal character? */
+    if (c >= ' ' && c <= '~') {
+      /* switch out of UTF-7 mode */
+      if (utf7mode) {
+        if (bitstogo) {
+          *dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
+        }
+        *dst++ = '-';
+        utf7mode = 0;
+        utf8pos  = 0;
+        bitstogo = 0;
+        utf8total= 0;
+      }
+      *dst++ = c;
+      /* encode '&' as '&-' */
+      if (c == '&') {
+        *dst++ = '-';
+      }
+      continue;
+    }
+    /* switch to UTF-7 mode */
+    if (!utf7mode) {
+      *dst++ = '&';
+      utf7mode = 1;
+    }
+    /* Encode US-ASCII characters as themselves */
+    if (c < 0x80) {
+      ucs4 = c;
+      utf8total = 1;
+    } else if (utf8total) {
+      /* save UTF8 bits into UCS4 */
+      ucs4 = (ucs4 << 6) | (c & 0x3FUL);
+      if (++utf8pos < utf8total) {
+        continue;
+      }
+    } else {
+      utf8pos = 1;
+      if (c < 0xE0) {
+        utf8total = 2;
+        ucs4 = c & 0x1F;
+      } else if (c < 0xF0) {
+        utf8total = 3;
+        ucs4 = c & 0x0F;
+      } else {
+        /* NOTE: can't convert UTF8 sequences longer than 4 */
+        utf8total = 4;
+        ucs4 = c & 0x03;
+      }
+      continue;
+    }
+    /* loop to split ucs4 into two utf16 chars if necessary */
+    utf8total = 0;
+    do {
+      if (ucs4 >= UTF16BASE) {
+        ucs4 -= UTF16BASE;
+        bitbuf = (bitbuf << 16) | ((ucs4 >> UTF16SHIFT)
+                                   + UTF16HIGHSTART);
+        ucs4 = (ucs4 & UTF16MASK) + UTF16LOSTART;
+        utf16flag = 1;
+      } else {
+        bitbuf = (bitbuf << 16) | ucs4;
+        utf16flag = 0;
+      }
+      bitstogo += 16;
+      /* spew out base64 */
+      while (bitstogo >= 6) {
+        bitstogo -= 6;
+        *dst++ = base64chars[(bitstogo ? (bitbuf >> bitstogo)
+                              : bitbuf)
+                             & 0x3F];
+      }
+    } while (utf16flag);
+  }
+  /* if in UTF-7 mode, finish in ASCII */
+  if (utf7mode) {
+    if (bitstogo) {
+      *dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
+    }
+    *dst++ = '-';
+  }
+  /* tie off string */
+  *dst = '\0';
+  return res;
+}
+
+#if 0
+int main(int argc, char *argv[])
+{
+  int i;
+  for(i=1; i<argc; i++) {
+    char *mbx = imap_utf8_to_mailbox(argv[i]);
+    char *utf8 = imap_mailbox_to_utf8(mbx);
+    printf("orig='%s' mbx='%s' back='%s'\n", argv[i], mbx, utf8);
+    free(mbx); free(utf8);
+  }
+  return 0;
+}
+#endif
Index: libbalsa/imap/util.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/imap/util.h,v
retrieving revision 1.3
diff -u -r1.3 util.h
--- libbalsa/imap/util.h	29 Feb 2004 16:40:37 -0000	1.3
+++ libbalsa/imap/util.h	2 Mar 2004 23:13:23 -0000
@@ -28,4 +28,7 @@
                         size_t len, size_t olen);
 int lit_conv_from_base64(char *out, const char *in);
 
+char* imap_mailbox_to_utf8(const unsigned char *src);
+char* imap_utf8_to_mailbox(const unsigned char *src);
+
 #endif

--=-nwTs0j4VlFf5ger7Kyvg--



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]