--- 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