Imported Debian patch 0.63.0-6
[hcoop/debian/courier-authlib.git] / unicode / utf7imap.c
diff --git a/unicode/utf7imap.c b/unicode/utf7imap.c
new file mode 100755 (executable)
index 0000000..894a6f7
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+** 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};