21 #include "kmime_util.h"
24 #include <tdeglobal.h>
25 #include <tdelocale.h>
26 #include <kcharsets.h>
27 #include <tdeversion.h>
28 #if KDE_IS_VERSION( 3, 1, 90 )
29 #include <kcalendarsystem.h>
32 #include <tqtextcodec.h>
33 #include <tqstrlist.h>
35 #include <tqdatetime.h>
42 using namespace KMime;
46 TQStrIList c_harsetCache;
47 TQStrIList l_anguageCache;
49 const char* cachedCharset( const TQCString &name)
51 int idx=c_harsetCache.find(name.data());
53 return c_harsetCache.at(idx);
55 c_harsetCache.append(name.upper().data());
57 return c_harsetCache.last();
60 const char* cachedLanguage( const TQCString &name)
62 int idx=l_anguageCache.find(name.data());
64 return l_anguageCache.at(idx);
66 l_anguageCache.append(name.upper().data());
68 return l_anguageCache.last();
71 bool isUsAscii( const TQString &s)
73 uint sLength = s.length();
74 for (uint i=0; i<sLength; i++)
75 if (s.at(i).latin1()<=0)
82 const uchar specialsMap[16] = {
83 0x00, 0x00, 0x00, 0x00,
84 0x20, 0xCA, 0x00, 0x3A,
85 0x80, 0x00, 0x00, 0x1C,
86 0x00, 0x00, 0x00, 0x00
90 const uchar tSpecialsMap[16] = {
91 0x00, 0x00, 0x00, 0x00,
92 0x20, 0xC9, 0x00, 0x3F,
93 0x80, 0x00, 0x00, 0x1C,
94 0x00, 0x00, 0x00, 0x00
98 const uchar aTextMap[16] = {
99 0x00, 0x00, 0x00, 0x00,
100 0x5F, 0x35, 0xFF, 0xC5,
101 0x7F, 0xFF, 0xFF, 0xE3,
102 0xFF, 0xFF, 0xFF, 0xFE
106 const uchar tTextMap[16] = {
107 0x00, 0x00, 0x00, 0x00,
108 0x5F, 0x36, 0xFF, 0xC0,
109 0x7F, 0xFF, 0xFF, 0xE3,
110 0xFF, 0xFF, 0xFF, 0xFE
114 const uchar eTextMap[16] = {
115 0x00, 0x00, 0x00, 0x00,
116 0x40, 0x35, 0xFF, 0xC0,
117 0x7F, 0xFF, 0xFF, 0xE0,
118 0x7F, 0xFF, 0xFF, 0xE0
121 #if defined(_AIX) && defined(truncate)
125 TQString decodeRFC2047String( const TQCString &src, const char **usedCS,
126 const TQCString &defaultCS, bool forceCS)
128 TQCString result, str;
129 TQCString declaredCS;
130 const char *beg, *end, *mid, *pos=0;
131 char *dest, *endOfLastEncWord=0;
132 char encoding = '\0';
133 bool valid, onlySpacesSinceLastWord= false;
134 const int maxLen=400;
137 if(src.find( "=?") < 0)
140 result.truncate(src.length());
141 for (pos=src.data(), dest=result.data(); *pos; pos++)
143 if (pos[0]!= '=' || pos[1]!= '?')
146 if (onlySpacesSinceLastWord)
147 onlySpacesSinceLastWord = (pos[0]== ' ' || pos[1]== '\t');
155 for (i=2,pos+=2; i<maxLen && (*pos!= '?'&&(ispunct(*pos)||isalnum(*pos))); i++) {
159 if (*pos!= '?' || i<4 || i>=maxLen) valid = FALSE;
163 encoding = toupper(pos[1]);
164 if (pos[2]!= '?' || (encoding!= 'Q' && encoding!= 'B'))
173 while (i<maxLen && *pos && !(*pos== '?' && *(pos+1)== '='))
179 if (i>=maxLen || !*pos) valid = FALSE;
184 if (onlySpacesSinceLastWord)
185 dest=endOfLastEncWord;
188 str = TQCString(mid, ( int)(pos - mid + 1));
192 for (i=str.length()-1; i>=0; i--)
193 if (str[i]== '_') str[i]= ' ';
194 str = KCodecs::quotedPrintableDecode(str);
198 str = KCodecs::base64Decode(str);
201 for (i=0; str[i]; i++) {
207 endOfLastEncWord=dest;
208 onlySpacesSinceLastWord= true;
223 TQTextCodec *codec=0;
225 if (forceCS || declaredCS.isEmpty()) {
226 codec=TDEGlobal::charsets()->codecForName(defaultCS);
227 (*usedCS)=cachedCharset(defaultCS);
230 codec=TDEGlobal::charsets()->codecForName(declaredCS, ok);
232 codec=TDEGlobal::charsets()->codecForName(defaultCS);
233 (*usedCS)=cachedCharset(defaultCS);
236 (*usedCS)=cachedCharset(declaredCS);
239 return codec->toUnicode(result.data(), result.length());
242 TQString decodeRFC2047String( const TQCString &src)
245 return decodeRFC2047String(src, &usedCS, "utf-8", false);
248 TQCString encodeRFC2047String( const TQString &src, const char *charset,
249 bool addressHeader, bool allow8BitHeaders)
251 TQCString encoded8Bit, result, usedCS;
252 unsigned int start=0,end=0;
253 bool nonAscii= false, ok= true, useTQEncoding= false;
254 TQTextCodec *codec=0;
257 codec=TDEGlobal::charsets()->codecForName(usedCS, ok);
261 usedCS=TDEGlobal::locale()->encoding();
262 codec=TDEGlobal::charsets()->codecForName(usedCS, ok);
265 if (usedCS.find( "8859-")>=0)
268 encoded8Bit=codec->fromUnicode(src);
273 uint encoded8BitLength = encoded8Bit.length();
274 for ( unsigned int i=0; i<encoded8BitLength; i++) {
275 if (encoded8Bit[i]== ' ')
279 if ((( signed char)encoded8Bit[i]<0) || (encoded8Bit[i] == '\033') ||
280 (addressHeader && (strchr( "\"()<>@,.;:\\[]=",encoded8Bit[i])!=0))) {
288 while ((end<encoded8Bit.length())&&(encoded8Bit[end]!= ' '))
291 for ( unsigned int x=end;x<encoded8Bit.length();x++)
292 if ((( signed char)encoded8Bit[x]<0) || (encoded8Bit[x] == '\033') ||
293 (addressHeader && (strchr( "\"()<>@,.;:\\[]=",encoded8Bit[x])!=0))) {
294 end = encoded8Bit.length();
296 while ((end<encoded8Bit.length())&&(encoded8Bit[end]!= ' '))
300 result = encoded8Bit.left(start)+ "=?"+usedCS;
306 for ( unsigned int i=start;i<end;i++) {
311 if (((c>= 'a')&&(c<= 'z'))||
312 ((c>= 'A')&&(c<= 'Z'))||
313 ((c>= '0')&&(c<= '9')))
317 hexcode = ((c & 0xF0) >> 4) + 48;
318 if (hexcode >= 58) hexcode += 7;
320 hexcode = (c & 0x0F) + 48;
321 if (hexcode >= 58) hexcode += 7;
326 result += "?B?"+KCodecs::base64Encode(encoded8Bit.mid(start,end-start), false);
330 result += encoded8Bit.right(encoded8Bit.length()-end);
333 result = encoded8Bit;
338 TQCString uniqueString()
340 static char chars[] = "0123456789abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
345 unsigned int timeval;
349 ran=1+(int) (1000.0*rand()/(RAND_MAX+1.0));
350 timeval=(now/ran)+getpid();
352 for( int i=0; i<10; i++){
353 pos=(int) (61.0*rand()/(RAND_MAX+1.0));
357 ret.sprintf( "%d.%s", timeval, p);
363 TQCString multiPartBoundary()
366 ret= "nextPart"+uniqueString();
370 TQCString extractHeader( const TQCString &src, const char *name)
372 TQCString n=TQCString(name)+ ":";
373 int pos1=-1, pos2=0, len=src.length()-1;
376 if (n.lower() == src.left(n.length()).lower()) {
380 pos1 = src.find(n.data(),0, false);
386 if ( src.at( pos1 ) == ' ' )
390 if (src[pos2]!= '\n') {
392 pos2=src.find( "\n", pos2+1);
393 if(pos2==-1 || pos2==len || ( src[pos2+1]!= ' ' && src[pos2+1]!= '\t') )
400 if(pos2<0) pos2=len+1;
403 return src.mid(pos1, pos2-pos1);
405 return (src.mid(pos1, pos2-pos1).replace(TQRegExp( "\\s*\\n\\s*"), " "));
413 TQCString CRLFtoLF( const TQCString &s)
415 TQCString ret=s.copy();
416 ret.replace(TQRegExp( "\\r\\n"), "\n");
421 TQCString CRLFtoLF( const char *s)
424 ret.replace(TQRegExp( "\\r\\n"), "\n");
429 TQCString LFtoCRLF( const TQCString &s)
431 TQCString ret=s.copy();
432 ret.replace(TQRegExp( "\\n"), "\r\n");
437 void removeQuots(TQCString &str)
440 str.replace(TQRegExp( "[\\\"]"), "");
444 void removeQuots(TQString &str)
447 str.replace(TQRegExp( "[\\\"]"), "");
451 void addQuotes(TQCString &str, bool forceQuotes)
453 if ( forceQuotes || TQString(str).contains( TQRegExp( TQString( "\"|\\\\|=|\\]|\\[|:|;|,|\\.|,|@|<|>|\\)|\\(" ) ) ) ) {
455 str.replace(TQRegExp( "([\\\"])"), "\\\\1");
462 int DateFormatter::mDaylight = -1;
464 : mFormat( fType ), mCurrentTime( 0 )
469 DateFormatter::~DateFormatter()
472 DateFormatter::FormatType
486 bool shortFormat, bool includeSecs ) const
490 return fancy( otime );
493 return localized( otime, shortFormat, includeSecs, lang );
496 return cTime( otime );
510 bool shortFormat, bool includeSecs ) const
521 tmp.setTime_t(otime);
523 ret = tmp.toString( "ddd, dd MMM yyyy hh:mm:ss ").latin1();
532 if ( mCustomFormat.isEmpty() )
535 int z = mCustomFormat.find( "Z");
537 TQString ret = mCustomFormat;
541 ret.replace(z,1, zone(t));
544 ret = d.toString(ret);
552 mCustomFormat = format;
557 DateFormatter::getCustomFormat() const
559 return mCustomFormat;
567 #if defined(HAVE_TIMEZONE) || defined(HAVE_TM_GMTOFF)
568 struct tm *local = localtime( &otime );
571 #if defined(HAVE_TIMEZONE)
574 int secs = abs(timezone);
575 int neg = (timezone>0)?1:0;
576 int hours = secs/3600;
577 int mins = (secs - hours*3600)/60;
580 if ( local->tm_isdst > 0 ) {
589 ret.sprintf( "%c%.2d%.2d",(neg)? '-': '+', hours, mins);
591 #elif defined(HAVE_TM_GMTOFF)
593 int secs = abs( local->tm_gmtoff );
594 int neg = (local->tm_gmtoff<0)?1:0;
595 int hours = secs/3600;
596 int mins = (secs - hours*3600)/60;
598 if ( local->tm_isdst > 0 )
603 ret.sprintf( "%c%.2d%.2d",(neg)? '-': '+', hours, mins);
607 TQDateTime d1 = TQDateTime::fromString( asctime(gmtime(&otime)) );
608 TQDateTime d2 = TQDateTime::fromString( asctime(localtime(&otime)) );
609 int secs = d1.secsTo(d2);
610 int neg = (secs<0)?1:0;
612 int hours = secs/3600;
613 int mins = (secs - hours*3600)/60;
615 ret.sprintf( "%c%.2d%.2d",(neg)? '-': '+', hours, mins);
623 DateFormatter::qdateToTimeT( const TQDateTime& dt) const
625 TQDateTime epoch( TQDate(1970, 1,1), TQTime(00,00,00) );
629 TQDateTime d1 = TQDateTime::fromString( asctime(gmtime(&otime)) );
630 TQDateTime d2 = TQDateTime::fromString( asctime(localtime(&otime)) );
631 time_t drf = epoch.secsTo( dt ) - d1.secsTo( d2 );
639 TDELocale *locale = TDEGlobal::locale();
642 return i18n( "unknown" );
644 if ( !mCurrentTime ) {
645 time( &mCurrentTime );
646 mDate.setTime_t( mCurrentTime );
650 old.setTime_t( otime );
653 if ( mCurrentTime + 60 * 60 >= otime ) {
654 time_t diff = mCurrentTime - otime;
656 if ( diff < 24 * 60 * 60 ) {
657 if ( old.date().year() == mDate.date().year() &&
658 old.date().dayOfYear() == mDate.date().dayOfYear() )
659 return i18n( "Today %1" ).arg( locale->
660 formatTime( old.time(), true ) );
662 if ( diff < 2 * 24 * 60 * 60 ) {
663 TQDateTime yesterday( mDate.addDays( -1 ) );
664 if ( old.date().year() == yesterday.date().year() &&
665 old.date().dayOfYear() == yesterday.date().dayOfYear() )
666 return i18n( "Yesterday %1" ).arg( locale->
667 formatTime( old.time(), true) );
669 for ( int i = 3; i < 7; i++ )
670 if ( diff < i * 24 * 60 * 60 ) {
671 TQDateTime weekday( mDate.addDays( -i + 1 ) );
672 if ( old.date().year() == weekday.date().year() &&
673 old.date().dayOfYear() == weekday.date().dayOfYear() )
674 return i18n( "1. weekday, 2. time", "%1 %2" ).
675 # if KDE_IS_VERSION( 3, 1, 90 )
676 arg( locale->calendar()->weekDayName( old.date() ) ).
678 arg( locale->weekDayName( old.date().dayOfWeek() ) ).
680 arg( locale->formatTime( old.time(), true) );
684 return locale->formatDateTime( old );
690 const TQString& localeLanguage ) const
694 TDELocale *locale = TDEGlobal::locale();
696 tmp.setTime_t( otime );
699 if ( !localeLanguage.isEmpty() ) {
700 locale= new TDELocale(localeLanguage);
701 locale->setLanguage(localeLanguage);
702 locale->setCountry(localeLanguage);
703 ret = locale->formatDateTime( tmp, shortFormat, includeSecs );
706 ret = locale->formatDateTime( tmp, shortFormat, includeSecs );
715 return TQString::fromLatin1( ctime( &otime ) ).stripWhiteSpace() ;
722 strftime( cstr, 63, "%Y-%m-%d %H:%M:%S", localtime(&otime) );
723 return TQString( cstr );
735 const TQString& data, bool shortFormat, bool includeSecs )
738 if ( t == DateFormatter::Custom ) {
741 return f. dateString( otime, data, shortFormat, includeSecs );
746 bool shortFormat, bool includeSecs )
749 if ( t == DateFormatter::Custom ) {
752 return f. dateString( time(0), data, shortFormat, includeSecs );
763 DateFormatter::isDaylight()
765 if ( mDaylight == -1 ) {
766 time_t ntime = time( 0 );
767 struct tm *local = localtime( &ntime );
768 if ( local->tm_isdst > 0 ) {
775 } else if ( mDaylight != 0 )
|