--- /dev/null
+/*
+** Copyright 2000-2003 Double Precision, Inc.
+** See COPYING for distribution information.
+**
+*/
+
+#include "unicode_config.h"
+#include "unicode.h"
+#include <string.h>
+#include <stdlib.h>
+
+static const char rcsid[]="$Id: utf7imap.c,v 1.6 2004/05/23 14:28:25 mrsam Exp $";
+
+static const char mbase64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
+
+static char mbase64_lookup[256];
+static int mbase64_lookup_init=0;
+
+unicode_char *unicode_modutf7touc(const char *s, int *err)
+{
+ size_t l=strlen(s), i;
+ unicode_char *uc=malloc(sizeof(unicode_char)*(l+1));
+ /* That's the worst case scenario, that's all. */
+
+ if (!uc)
+ return (NULL);
+
+ if (err)
+ *err= -1;
+
+ /* First time through - initialize fast lookup table */
+
+ if (!mbase64_lookup_init)
+ {
+ mbase64_lookup_init=1;
+
+ for (i=0; i<256; i++)
+ mbase64_lookup[i]= (char)-1;
+
+ for (i=0; mbase64[i]; i++)
+ mbase64_lookup[(int)mbase64[i]]=i;
+ }
+ i=0;
+
+ for (l=0; s[l]; l++)
+ {
+ unicode_char uu;
+ int bitcount;
+
+ if ( s[l] < 0x20 || s[l] >= 0x7F )
+ {
+ free(uc);
+ if (err) *err=l;
+ return (NULL);
+ }
+
+ if ( s[l] != '&' )
+ {
+ uc[i++]= (int)(unsigned char)s[l];
+ continue;
+ }
+
+ if ( s[++l] == '-' )
+ {
+ uc[i++]='&';
+ continue;
+ }
+
+ bitcount=0;
+ uu=0;
+
+ for ( ; s[l] != '-'; l++)
+ {
+ int bits;
+
+ if ((char)(bits=
+ mbase64_lookup[s[l] & 255]) == (char)-1)
+ {
+ free(uc);
+ if (err) *err=l;
+ return (0);
+ }
+
+ if (bitcount + 6 >= 16)
+ /* These six more bits are enough for UCS2 */
+ {
+ int n=bitcount + 6 - 16; /* Leftover */
+
+ uu = (uu << (6-n)) | (bits >> n);
+ uc[i++] = (uu & 0xFFFF);
+
+ uu = bits; /* The leftovers */
+ bitcount=n;
+ }
+ else
+ {
+ uu = (uu << 6) | bits;
+ bitcount += 6;
+ }
+ }
+ }
+ uc[i]=0;
+ return (uc);
+}
+
+static size_t uctoutf7_pass(const unicode_char *, const unicode_char *,
+ char *);
+
+char *unicode_uctomodutf7(const unicode_char *p)
+{
+ return unicode_uctomodutf7x(p, NULL);
+}
+
+char *unicode_uctomodutf7x(const unicode_char *p,
+ const unicode_char *specials)
+{
+ size_t n=uctoutf7_pass(p, specials, NULL);
+ char *s=malloc(n);
+
+ if (s)
+ uctoutf7_pass(p, specials, s);
+ return (s);
+}
+
+static int is_special(unicode_char uc, const unicode_char *specials)
+{
+ while (specials && *specials)
+ if (*specials++ == uc)
+ return 1;
+
+ return uc < 0x20 || uc >= 0x7F;
+}
+
+static size_t uctoutf7_pass(const unicode_char *uc,
+ const unicode_char *specials,
+ char *p)
+{
+ size_t n=0;
+
+ while (*uc)
+ {
+ unsigned bits, bitcount;
+
+ if (!is_special(*uc, specials))
+ {
+ /* Straightforward deal for straightforward ASCII */
+
+ if (p)
+ *p++ = (char)*uc;
+ ++n;
+
+ if (*uc++ == '&')
+ {
+ if (p) *p++ = '-';
+ ++n;
+ }
+ continue;
+ }
+
+ if (p) *p++ = '&'; /* Begin modified base64 */
+ ++n;
+
+ bits=bitcount=0;
+ while ( *uc && is_special(*uc, specials))
+ {
+ unicode_char uu= *uc++ & 0xFFFF;
+ int counter=16;
+
+ if (!uu) uu=0xFFFD;
+
+ /* Process 16 bits */
+
+ while (counter)
+ {
+ int x;
+
+ if (counter + bitcount < 6)
+ {
+ /* Add these bits, then we're done */
+
+ bits = (bits << counter) |
+ (uu >> (16-counter));
+ bitcount += counter;
+ break;
+ }
+
+ /* Have enough bits to encode */
+
+ x= 6 - bitcount;
+
+ bits = (bits << x) | (uu >> (16-x));
+ uu = (uu << x) & 0xFFFF;
+ counter -= x;
+
+ if (p)
+ *p++ = mbase64[bits];
+ ++n;
+ bits=bitcount=0;
+ }
+ }
+
+ if (bitcount) /* Leftovers */
+ {
+ bits <<= (6-bitcount);
+ if (p)
+ *p++ = mbase64[bits];
+ ++n;
+ }
+
+ if (p)
+ *p++ = '-';
+ ++n;
+ /* End modified base64 */
+ }
+
+ if (p)
+ *p=0;
+ ++n;
+ return (n);
+}
+
+static char *toupper_func(const struct unicode_info *u,
+ const char *cp, int *ip)
+{
+ unicode_char *uc=unicode_modutf7touc(cp, ip), *p;
+ char *s;
+
+ if (!uc) return (0);
+
+ for (p=uc; *p; p++)
+ *p=unicode_uc(*p);
+
+ s=unicode_uctomodutf7(uc);
+ if (!s && ip)
+ *ip=0;
+ free(uc);
+ return (s);
+}
+
+static char *tolower_func(const struct unicode_info *u,
+ const char *cp, int *ip)
+{
+ unicode_char *uc=unicode_modutf7touc(cp, ip), *p;
+ char *s;
+
+ if (!uc) return (0);
+
+ for (p=uc; *p; p++)
+ *p=unicode_lc(*p);
+
+ s=unicode_uctomodutf7(uc);
+ free(uc);
+ if (!s && ip)
+ *ip=0;
+ return (s);
+}
+
+static char *totitle_func(const struct unicode_info *u,
+ const char *cp, int *ip)
+{
+ unicode_char *uc=unicode_modutf7touc(cp, ip), *p;
+ char *s;
+
+ if (!uc) return (0);
+
+ for (p=uc; *p; p++)
+ *p=unicode_tc(*p);
+
+ s=unicode_uctomodutf7(uc);
+ if (!s && ip)
+ *ip=0;
+ free(uc);
+ return (s);
+}
+
+static unicode_char *tou(const struct unicode_info *ui, const char *cs,
+ int *err)
+{
+ return unicode_modutf7touc(cs, err);
+}
+
+
+static char *fromu(const struct unicode_info *ui,
+ const unicode_char *uc, int *err)
+{
+ if (err) *err= -1;
+ return unicode_uctomodutf7(uc);
+}
+
+const struct unicode_info unicode_IMAP_MODUTF7 = {
+ "X-IMAP-MODUTF-7",
+ UNICODE_UTF | UNICODE_MB |
+ UNICODE_HEADER_BASE64,
+ tou,
+ fromu,
+ toupper_func,
+ tolower_func,
+ totitle_func};