---
 src/drv_imap.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)

diff --git a/src/drv_imap.c b/src/drv_imap.c
index 7bc88f6..918dead 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -35,6 +35,8 @@
 #include <ctype.h>
 #include <time.h>
 #include <sys/wait.h>
+#include <iconv.h>
+#include <langinfo.h>
 
 #ifdef HAVE_LIBSASL
 # include <sasl/sasl.h>
@@ -237,6 +239,7 @@ static const char *cap_list[] = {
 #define RESP_OK       0
 #define RESP_NO       1
 #define RESP_CANCEL   2
+#define UTF7_INBOX_NAME_MAX_LENGTH 2048
 
 static INLINE void imap_ref( imap_store_t *ctx ) { ++ctx->ref_count; }
 static int imap_deref( imap_store_t *ctx );
@@ -273,6 +276,121 @@ new_imap_cmd( int size )
        cmdp->gen.callback = cb; \
        cmdp->gen.callback_aux = aux;
 
+static void
+change_shift_char(char const *src, char *dest,
+               size_t max_length,
+               char const old_shift, char const new_shift)
+{
+       for ( ; *src != '\0' && max_length != 0; src++, dest++ ) {
+               // decode litteral old_shift
+               if (*src == old_shift && *(src + 1) == '-') {
+                       *dest = *src;
+                       src++;
+                       if (*src == '\0')
+                               break ;
+               }
+               // replace shift
+               else if (*src == old_shift) {
+                       *dest = new_shift;
+               }
+               // encode litteral new_shift
+               else if (*src == new_shift) {
+                       *dest = new_shift;
+                       dest++;
+                       max_length--;
+                       *dest = '-';
+               }
+               else
+                       *dest = *src;
+               max_length--;
+       }
+       *dest = '\0';
+}
+
+static void
+imap_to_utf7(char const *src, char *dest,
+               size_t max_length)
+{
+       change_shift_char(src, dest, max_length, '&', '+');
+}
+
+static void
+utf7_to_imap(char const *src, char *dest,
+               size_t max_length)
+{
+       change_shift_char(src, dest, max_length, '+', '&');
+}
+
+static char *
+decode_utf7_imap(const char * utf7_imap_string)
+{
+       char   utf7_plain[UTF7_INBOX_NAME_MAX_LENGTH + 1];
+
+       assert(utf7_imap_string != NULL);
+       imap_to_utf7(utf7_imap_string, utf7_plain, UTF7_INBOX_NAME_MAX_LENGTH);
+
+       size_t length = strlen(utf7_plain);
+       iconv_t conv_state = iconv_open(nl_langinfo(CODESET) , "UTF-7");
+       char *  locale_encoding = NULL;
+       if (conv_state != (iconv_t)-1) {
+               size_t output_size = sizeof(*locale_encoding) * (length + 1) * 
4;
+               // Use a safety margin should locale encoding produce a longer 
string
+               locale_encoding = nfmalloc(output_size);
+               char * utf7 = utf7_plain;
+               char * local = locale_encoding;
+
+               if ((size_t)-1 == iconv(
+                                       conv_state,
+                                       &utf7, &length,
+                                       &local, &output_size)) {
+                       error( "Unicode error: the folling string could not be 
converted to system locale :\n");
+                       error( utf7_imap_string);
+                       error (nl_langinfo(CODESET));
+                       free(locale_encoding);
+                       locale_encoding = NULL;
+               } else {
+                       *local = '\0';
+               }
+       }
+       iconv_close(conv_state);
+       return locale_encoding;
+}
+
+static char *
+encode_utf7_imap(const char * locale_string)
+{
+       char utf7[UTF7_INBOX_NAME_MAX_LENGTH + 1];
+       size_t length = strlen(locale_string);
+       char * imap = NULL;
+
+       assert(locale_string != NULL);
+       // + locale_string is a valid locale string.
+
+       iconv_t conv_state = iconv_open("UTF-7" , nl_langinfo(CODESET));
+       if (conv_state != (iconv_t)-1) {
+               size_t output_size = UTF7_INBOX_NAME_MAX_LENGTH;
+               // Use a safety margin should utf7 encoding produce a longer 
string
+               char *utf7_plain = utf7;
+
+               if ((size_t)-1 == iconv(
+                                       conv_state,
+                                       &locale_string, &length,
+                                       &utf7_plain, &output_size)) {
+                       error( "Unicode error: the folling string could not be 
converted to UTF-7\n");
+                       error( locale_string);
+                       error (nl_langinfo(CODESET));
+               } else {
+                       *utf7_plain = '\0';
+                       imap = nfmalloc(sizeof(*imap) * (strlen(utf7) + 1) * 2);
+                       // Transcoding can produce a string twice as long in 
the worse case.
+                       utf7_to_imap(utf7, imap, UTF7_INBOX_NAME_MAX_LENGTH);
+               }
+       }
+       iconv_close(conv_state);
+
+       return imap;
+}
+
 static void
 done_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd, int response )
 {
-- 
2.26.2



_______________________________________________
isync-devel mailing list
isync-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to