File indexing completed on 2024-09-22 04:52:48
0001 /********************************************************************** 0002 * 0003 * rfccodecs.cpp - handler for various rfc/mime encodings 0004 * Copyright (C) 2000 s.carstens@gmx.de 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Library General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Library General Public License 0017 * along with this library; see the file COPYING.LIB. If not, write to 0018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 * 0021 *********************************************************************/ 0022 /** 0023 * @file 0024 * This file is part of the IMAP support library and defines the 0025 * RfcCodecs class. 0026 * 0027 * @brief 0028 * Defines the RfcCodecs class. 0029 * 0030 * @author Sven Carstens 0031 */ 0032 0033 #include "rfccodecs.h" 0034 0035 #include <ctype.h> 0036 #include <sys/types.h> 0037 0038 #include <stdio.h> 0039 #include <stdlib.h> 0040 0041 #include <QtCore/QTextCodec> 0042 #include <QtCore/QBuffer> 0043 #include <QtCore/QByteArray> 0044 #include <QtCore/QLatin1Char> 0045 #include "kcodecs.h" 0046 0047 using namespace KIMAP; 0048 0049 // This part taken from rfc 2192 IMAP URL Scheme. C. Newman. September 1997. 0050 // adapted to QT-Toolkit by Sven Carstens <s.carstens@gmx.de> 2000 0051 0052 //@cond PRIVATE 0053 static const unsigned char base64chars[] = 0054 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; 0055 #define UNDEFINED 64 0056 #define MAXLINE 76 0057 0058 /* UTF16 definitions */ 0059 #define UTF16MASK 0x03FFUL 0060 #define UTF16SHIFT 10 0061 #define UTF16BASE 0x10000UL 0062 #define UTF16HIGHSTART 0xD800UL 0063 #define UTF16HIGHEND 0xDBFFUL 0064 #define UTF16LOSTART 0xDC00UL 0065 #define UTF16LOEND 0xDFFFUL 0066 //@endcond 0067 0068 //----------------------------------------------------------------------------- 0069 QString KIMAP::decodeImapFolderName( const QByteArray &src ) 0070 { 0071 unsigned char c, i, bitcount; 0072 unsigned long ucs4, utf16, bitbuf; 0073 unsigned char base64[256], utf8[6]; 0074 unsigned int srcPtr = 0; 0075 QByteArray dst; 0076 uint srcLen = src.length(); 0077 0078 /* initialize modified base64 decoding table */ 0079 memset( base64, UNDEFINED, sizeof( base64 ) ); 0080 for ( i = 0; i < sizeof( base64chars ); ++i ) { 0081 base64[(int)base64chars[i]] = i; 0082 } 0083 0084 /* loop until end of string */ 0085 while ( srcPtr < srcLen ) { 0086 c = src[srcPtr++]; 0087 /* deal with literal characters and &- */ 0088 if ( c != '&' || src[srcPtr] == '-' ) { 0089 /* encode literally */ 0090 dst += c; 0091 /* skip over the '-' if this is an &- sequence */ 0092 if ( c == '&' ) { 0093 srcPtr++; 0094 } 0095 } else { 0096 /* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */ 0097 bitbuf = 0; 0098 bitcount = 0; 0099 ucs4 = 0; 0100 while ( ( c = base64[(unsigned char)src[srcPtr]] ) != UNDEFINED ) { 0101 ++srcPtr; 0102 bitbuf = ( bitbuf << 6 ) | c; 0103 bitcount += 6; 0104 /* enough bits for a UTF-16 character? */ 0105 if ( bitcount >= 16 ) { 0106 bitcount -= 16; 0107 utf16 = ( bitcount ? bitbuf >> bitcount : bitbuf ) & 0xffff; 0108 /* convert UTF16 to UCS4 */ 0109 if ( utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND ) { 0110 ucs4 = ( utf16 - UTF16HIGHSTART ) << UTF16SHIFT; 0111 continue; 0112 } else if ( utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND ) { 0113 ucs4 += utf16 - UTF16LOSTART + UTF16BASE; 0114 } else { 0115 ucs4 = utf16; 0116 } 0117 /* convert UTF-16 range of UCS4 to UTF-8 */ 0118 if ( ucs4 <= 0x7fUL ) { 0119 utf8[0] = ucs4; 0120 i = 1; 0121 } else if ( ucs4 <= 0x7ffUL ) { 0122 utf8[0] = 0xc0 | ( ucs4 >> 6 ); 0123 utf8[1] = 0x80 | ( ucs4 & 0x3f ); 0124 i = 2; 0125 } else if ( ucs4 <= 0xffffUL ) { 0126 utf8[0] = 0xe0 | ( ucs4 >> 12 ); 0127 utf8[1] = 0x80 | ( ( ucs4 >> 6 ) & 0x3f ); 0128 utf8[2] = 0x80 | ( ucs4 & 0x3f ); 0129 i = 3; 0130 } else { 0131 utf8[0] = 0xf0 | ( ucs4 >> 18 ); 0132 utf8[1] = 0x80 | ( ( ucs4 >> 12 ) & 0x3f ); 0133 utf8[2] = 0x80 | ( ( ucs4 >> 6 ) & 0x3f ); 0134 utf8[3] = 0x80 | ( ucs4 & 0x3f ); 0135 i = 4; 0136 } 0137 /* copy it */ 0138 for ( c = 0; c < i; ++c ) { 0139 dst += utf8[c]; 0140 } 0141 } 0142 } 0143 /* skip over trailing '-' in modified UTF-7 encoding */ 0144 if ( src[srcPtr] == '-' ) { 0145 ++srcPtr; 0146 } 0147 } 0148 } 0149 return QString::fromUtf8( dst.data () ); 0150 } 0151 0152 //----------------------------------------------------------------------------- 0153 QByteArray KIMAP::encodeImapFolderName( const QString &inSrc ) 0154 { 0155 unsigned int utf8pos, utf8total, c, utf7mode, bitstogo, utf16flag; 0156 unsigned int ucs4, bitbuf; 0157 QByteArray src = inSrc.toUtf8 (); 0158 QByteArray dst; 0159 0160 int srcPtr = 0; 0161 utf7mode = 0; 0162 utf8total = 0; 0163 bitstogo = 0; 0164 utf8pos = 0; 0165 bitbuf = 0; 0166 ucs4 = 0; 0167 while ( srcPtr < src.length () ) { 0168 c = (unsigned char)src[srcPtr++]; 0169 /* normal character? */ 0170 if ( c >= ' ' && c <= '~' ) { 0171 /* switch out of UTF-7 mode */ 0172 if ( utf7mode ) { 0173 if ( bitstogo ) { 0174 dst += base64chars[( bitbuf << ( 6 - bitstogo ) ) & 0x3F]; 0175 bitstogo = 0; 0176 } 0177 dst += '-'; 0178 utf7mode = 0; 0179 } 0180 dst += c; 0181 /* encode '&' as '&-' */ 0182 if ( c == '&' ) { 0183 dst += '-'; 0184 } 0185 continue; 0186 } 0187 /* switch to UTF-7 mode */ 0188 if ( !utf7mode ) { 0189 dst += '&'; 0190 utf7mode = 1; 0191 } 0192 /* Encode US-ASCII characters as themselves */ 0193 if ( c < 0x80 ) { 0194 ucs4 = c; 0195 utf8total = 1; 0196 } else if ( utf8total ) { 0197 /* save UTF8 bits into UCS4 */ 0198 ucs4 = ( ucs4 << 6 ) | ( c & 0x3FUL ); 0199 if ( ++utf8pos < utf8total ) { 0200 continue; 0201 } 0202 } else { 0203 utf8pos = 1; 0204 if ( c < 0xE0 ) { 0205 utf8total = 2; 0206 ucs4 = c & 0x1F; 0207 } else if ( c < 0xF0 ) { 0208 utf8total = 3; 0209 ucs4 = c & 0x0F; 0210 } else { 0211 /* NOTE: can't convert UTF8 sequences longer than 4 */ 0212 utf8total = 4; 0213 ucs4 = c & 0x03; 0214 } 0215 continue; 0216 } 0217 /* loop to split ucs4 into two utf16 chars if necessary */ 0218 utf8total = 0; 0219 do 0220 { 0221 if ( ucs4 >= UTF16BASE ) { 0222 ucs4 -= UTF16BASE; 0223 bitbuf = 0224 ( bitbuf << 16 ) | ( ( ucs4 >> UTF16SHIFT ) + UTF16HIGHSTART ); 0225 ucs4 = ( ucs4 & UTF16MASK ) + UTF16LOSTART; 0226 utf16flag = 1; 0227 } else { 0228 bitbuf = ( bitbuf << 16 ) | ucs4; 0229 utf16flag = 0; 0230 } 0231 bitstogo += 16; 0232 /* spew out base64 */ 0233 while ( bitstogo >= 6 ) { 0234 bitstogo -= 6; 0235 dst += 0236 base64chars[( bitstogo ? ( bitbuf >> bitstogo ) : bitbuf ) & 0x3F]; 0237 } 0238 } 0239 while ( utf16flag ); 0240 } 0241 /* if in UTF-7 mode, finish in ASCII */ 0242 if ( utf7mode ) { 0243 if ( bitstogo ) { 0244 dst += base64chars[( bitbuf << ( 6 - bitstogo ) ) & 0x3F]; 0245 } 0246 dst += '-'; 0247 } 0248 return dst; 0249 }