36 #include <sys/types.h>
41 #include <QtCore/QTextCodec>
42 #include <QtCore/QBuffer>
43 #include <QtCore/QRegExp>
44 #include <QtCore/QByteArray>
45 #include <QtCore/QLatin1Char>
48 using namespace KIMAP;
54 static const unsigned char base64chars[] =
55 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
58 static const char especials[17] =
"()<>@,;:\"/[]?.= ";
61 #define UTF16MASK 0x03FFUL
63 #define UTF16BASE 0x10000UL
64 #define UTF16HIGHSTART 0xD800UL
65 #define UTF16HIGHEND 0xDBFFUL
66 #define UTF16LOSTART 0xDC00UL
67 #define UTF16LOEND 0xDFFFUL
71 QByteArray KIMAP::decodeImapFolderName(
const QByteArray &inSrc )
73 unsigned char c, i, bitcount;
74 unsigned long ucs4, utf16, bitbuf;
75 unsigned char base64[256], utf8[6];
76 unsigned int srcPtr = 0;
78 QByteArray src = inSrc;
79 uint srcLen = inSrc.length();
82 memset( base64, UNDEFINED,
sizeof( base64 ) );
83 for ( i = 0; i <
sizeof( base64chars ); ++i ) {
84 base64[(int)base64chars[i]] = i;
88 while ( srcPtr < srcLen ) {
91 if ( c !=
'&' || src[srcPtr] ==
'-' ) {
103 while ( ( c = base64[(
unsigned char)src[srcPtr]] ) != UNDEFINED ) {
105 bitbuf = ( bitbuf << 6 ) | c;
108 if ( bitcount >= 16 ) {
110 utf16 = ( bitcount ? bitbuf >> bitcount : bitbuf ) & 0xffff;
112 if ( utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND ) {
113 ucs4 = ( utf16 - UTF16HIGHSTART ) << UTF16SHIFT;
115 }
else if ( utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND ) {
116 ucs4 += utf16 - UTF16LOSTART + UTF16BASE;
121 if ( ucs4 <= 0x7fUL ) {
124 }
else if ( ucs4 <= 0x7ffUL ) {
125 utf8[0] = 0xc0 | ( ucs4 >> 6 );
126 utf8[1] = 0x80 | ( ucs4 & 0x3f );
128 }
else if ( ucs4 <= 0xffffUL ) {
129 utf8[0] = 0xe0 | ( ucs4 >> 12 );
130 utf8[1] = 0x80 | ( ( ucs4 >> 6 ) & 0x3f );
131 utf8[2] = 0x80 | ( ucs4 & 0x3f );
134 utf8[0] = 0xf0 | ( ucs4 >> 18 );
135 utf8[1] = 0x80 | ( ( ucs4 >> 12 ) & 0x3f );
136 utf8[2] = 0x80 | ( ( ucs4 >> 6 ) & 0x3f );
137 utf8[3] = 0x80 | ( ucs4 & 0x3f );
141 for ( c = 0; c < i; ++c ) {
147 if ( src[srcPtr] ==
'-' ) {
155 QString KIMAP::decodeImapFolderName(
const QString &inSrc )
157 return QString::fromUtf8( decodeImapFolderName( inSrc.toUtf8() ).data() );
162 QByteArray KIMAP::quoteIMAP(
const QByteArray &src )
164 uint len = src.length();
166 result.reserve( 2 * len );
167 for (
unsigned int i = 0; i < len; i++ ) {
168 if ( src[i] ==
'"' || src[i] ==
'\\' ) {
177 QString KIMAP::quoteIMAP(
const QString &src )
179 uint len = src.length();
181 result.reserve( 2 * len );
182 for (
unsigned int i = 0; i < len; i++ ) {
183 if ( src[i] ==
'"' || src[i] ==
'\\' ) {
193 QString KIMAP::encodeImapFolderName(
const QString &inSrc )
195 return QString::fromUtf8( encodeImapFolderName( inSrc.toUtf8() ).data() );
198 QByteArray KIMAP::encodeImapFolderName(
const QByteArray &inSrc )
200 unsigned int utf8pos, utf8total, c, utf7mode, bitstogo, utf16flag;
201 unsigned int ucs4, bitbuf;
202 QByteArray src = inSrc;
212 while ( srcPtr < src.length () ) {
213 c = (
unsigned char)src[srcPtr++];
215 if ( c >=
' ' && c <=
'~' ) {
219 dst += base64chars[( bitbuf << ( 6 - bitstogo ) ) & 0x3F];
241 }
else if ( utf8total ) {
243 ucs4 = ( ucs4 << 6 ) | ( c & 0x3FUL );
244 if ( ++utf8pos < utf8total ) {
252 }
else if ( c < 0xF0 ) {
266 if ( ucs4 >= UTF16BASE ) {
269 ( bitbuf << 16 ) | ( ( ucs4 >> UTF16SHIFT ) + UTF16HIGHSTART );
270 ucs4 = ( ucs4 & UTF16MASK ) + UTF16LOSTART;
273 bitbuf = ( bitbuf << 16 ) | ucs4;
278 while ( bitstogo >= 6 ) {
281 base64chars[( bitstogo ? ( bitbuf >> bitstogo ) : bitbuf ) & 0x3F];
289 dst += base64chars[( bitbuf << ( 6 - bitstogo ) ) & 0x3F];
293 return quoteIMAP( dst );
297 QTextCodec *KIMAP::codecForName(
const QString &str )
299 if ( str.isEmpty () ) {
302 return QTextCodec::codecForName ( str.toLower ().
303 replace (
"windows",
"cp" ).toLatin1 () );
307 const QString KIMAP::decodeRFC2047String(
const QString &str )
311 return decodeRFC2047String( str, throw_away );
315 const QString KIMAP::decodeRFC2047String(
const QString &str,
320 return decodeRFC2047String( str, charset, throw_away );
324 const QString KIMAP::decodeRFC2047String(
const QString &str,
329 if ( !str.contains(
"=?" ) ) {
334 QByteArray aStr = str.toAscii ();
336 char *pos, *beg, *end, *mid = 0;
338 char encoding = 0, ch;
340 const int maxLen = 200;
344 for ( pos = aStr.data (); *pos; pos++ ) {
345 if ( pos[0] !=
'=' || pos[1] !=
'?' ) {
353 for ( i = 2, pos += 2;
355 ( *pos !=
'?' && ( ispunct( *pos ) || isalnum ( *pos ) ) );
358 if ( *pos !=
'?' || i < 4 || i >= maxLen ) {
361 charset = QByteArray( beg, i - 1 );
362 int pt = charset.lastIndexOf(
'*' );
365 language = charset.right( charset.length () - pt - 1 );
368 charset.truncate( pt );
371 encoding = toupper( pos[1] );
372 if ( pos[2] !=
'?' ||
373 ( encoding !=
'Q' && encoding !=
'B' &&
374 encoding !=
'q' && encoding !=
'b' ) ) {
384 while ( i < maxLen && *pos && !( *pos ==
'?' && *( pos + 1 ) ==
'=' ) ) {
389 if ( i >= maxLen || !*pos ) {
396 cstr = QByteArray (mid).left( (
int)( mid - pos - 1 ) );
397 if ( encoding ==
'Q' ) {
399 for ( i = cstr.length () - 1; i >= 0; --i ) {
400 if ( cstr[i] ==
'_' ) {
406 cstr = KCodecs::quotedPrintableDecode( cstr );
411 cstr = QByteArray::fromBase64( cstr );
414 int len = cstr.length();
415 for ( i = 0; i < len; ++i ) {
429 if ( !charset.isEmpty () ) {
430 QTextCodec *aCodec = codecForName( charset.toAscii () );
433 return aCodec->toUnicode( result );
440 const QString KIMAP::encodeRFC2047String(
const QString &str )
442 return encodeRFC2047String( str.toLatin1() );
446 const QByteArray KIMAP::encodeRFC2047String(
const QByteArray &str )
448 if ( str.isEmpty () ) {
452 const signed char *latin =
453 reinterpret_cast<const signed char *
>
454 ( str.data() ), *l, *start, *stop;
459 int resultLen = 3 * str.length() / 2;
460 QByteArray result( resultLen,
'\0' );
478 for ( i = 0; i < 16; ++i ) {
479 if ( *l == especials[i] ) {
487 if ( l - start + 2 * numQuotes >= 58 || *l == 60 ) {
494 while ( stop >= start && *stop != 32 ) {
497 if ( stop <= start ) {
503 if ( resultLen - rptr - 1 <= start - latin + 1 + 16 ) {
505 resultLen += ( start - latin + 1 ) * 2 + 20;
506 result.resize( resultLen );
508 while ( latin < start ) {
509 result[rptr++] = *latin;
512 result.replace( rptr, 15,
"=?iso-8859-1?q?" );
514 if ( resultLen - rptr - 1 <= 3 * ( stop - latin + 1 ) ) {
515 resultLen += ( stop - latin + 1 ) * 4 + 20;
516 result.resize( resultLen );
518 while ( latin < stop ) {
521 for ( i = 0; i < 16; ++i ) {
522 if ( *latin == especials[i] ) {
530 result[rptr++] =
'=';
531 hexcode = ( ( *latin & 0xF0 ) >> 4 ) + 48;
532 if ( hexcode >= 58 ) {
535 result[rptr++] = hexcode;
536 hexcode = ( *latin & 0x0F ) + 48;
537 if ( hexcode >= 58 ) {
540 result[rptr++] = hexcode;
542 result[rptr++] = *latin;
546 result[rptr++] =
'?';
547 result[rptr++] =
'=';
550 if ( rptr == resultLen - 1 ) {
552 result.resize( resultLen );
554 result[rptr++] = *latin;
564 const QString KIMAP::encodeRFC2231String(
const QString &str )
566 if ( str.isEmpty () ) {
570 signed char *latin = (
signed char *)calloc( 1, str.length () + 1 );
571 char *latin_us = (
char *)latin;
572 strcpy( latin_us, str.toLatin1 () );
573 signed char *l = latin;
591 for ( i = 0; i < 16; ++i ) {
592 if ( *l == especials[i] ) {
598 hexcode = ( ( *l & 0xF0 ) >> 4 ) + 48;
599 if ( hexcode >= 58 ) {
603 hexcode = ( *l & 0x0F ) + 48;
604 if ( hexcode >= 58 ) {
618 const QString KIMAP::decodeRFC2231String(
const QString &str )
620 int p = str.indexOf (
'\'' );
627 int l = str.lastIndexOf(
'\'' );
635 QString charset = str.left ( p );
636 QString st = str.mid ( l + 1 );
637 QString language = str.mid ( p + 1, l - p - 1 );
643 while ( p < (
int) st.length () ) {
644 if ( st.at( p ) == 37 ) {
645 ch = st.at( p + 1 ).toLatin1 () - 48;
649 ch2 = st.at( p + 2 ).toLatin1 () - 48;
653 st.replace( p, 1, ch * 16 + ch2 );
654 st.remove ( p + 1, 2 );