libkmime

kmime_util.cpp
00001 /*
00002     kmime_util.cpp
00003 
00004     KMime, the KDE internet mail/usenet news message library.
00005     Copyright (c) 2001 the KMime authors.
00006     See file AUTHORS for details
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012     You should have received a copy of the GNU General Public License
00013     along with this program; if not, write to the Free Software Foundation,
00014     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
00015 */
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #include <config.h>
00019 #endif
00020 
00021 #include "kmime_util.h"
00022 
00023 #include <kmdcodec.h> // for KCodec::{quotedPrintableDe,base64{En,De}}code
00024 #include <tdeglobal.h>
00025 #include <tdelocale.h>
00026 #include <kcharsets.h>
00027 #include <tdeversion.h>
00028 #if KDE_IS_VERSION( 3, 1, 90 )
00029 #include <kcalendarsystem.h>
00030 #endif
00031 
00032 #include <tqtextcodec.h>
00033 #include <tqstrlist.h> // for TQStrIList
00034 #include <tqregexp.h>
00035 #include <tqdatetime.h>
00036 
00037 #include <stdlib.h>
00038 #include <ctype.h>
00039 #include <time.h> // for time()
00040 #include <unistd.h> // for getpid()
00041 
00042 using namespace KMime;
00043 
00044 namespace KMime {
00045 
00046 TQStrIList c_harsetCache;
00047 TQStrIList l_anguageCache;
00048 
00049 const char* cachedCharset(const TQCString &name)
00050 {
00051   int idx=c_harsetCache.find(name.data());
00052   if(idx>-1)
00053     return c_harsetCache.at(idx);
00054 
00055   c_harsetCache.append(name.upper().data());
00056   //kdDebug() << "KNMimeBase::cachedCharset() number of cs " << c_harsetCache.count() << endl;
00057   return c_harsetCache.last();
00058 }
00059 
00060 const char* cachedLanguage(const TQCString &name)
00061 {
00062   int idx=l_anguageCache.find(name.data());
00063   if(idx>-1)
00064     return l_anguageCache.at(idx);
00065 
00066   l_anguageCache.append(name.upper().data());
00067   //kdDebug() << "KNMimeBase::cachedCharset() number of cs " << c_harsetCache.count() << endl;
00068   return l_anguageCache.last();
00069 }
00070 
00071 bool isUsAscii(const TQString &s)
00072 {
00073   uint sLength = s.length();
00074   for (uint i=0; i<sLength; i++)
00075     if (s.at(i).latin1()<=0)    // c==0: non-latin1, c<0: non-us-ascii
00076       return false;
00077 
00078   return true;
00079 }
00080 
00081 // "(),.:;<>@[\]
00082 const uchar specialsMap[16] = {
00083   0x00, 0x00, 0x00, 0x00, // CTLs
00084   0x20, 0xCA, 0x00, 0x3A, // SPACE ... '?'
00085   0x80, 0x00, 0x00, 0x1C, // '@' ... '_'
00086   0x00, 0x00, 0x00, 0x00  // '`' ... DEL
00087 };
00088 
00089 // "(),:;<>@[\]/=?
00090 const uchar tSpecialsMap[16] = {
00091   0x00, 0x00, 0x00, 0x00, // CTLs
00092   0x20, 0xC9, 0x00, 0x3F, // SPACE ... '?'
00093   0x80, 0x00, 0x00, 0x1C, // '@' ... '_'
00094   0x00, 0x00, 0x00, 0x00  // '`' ... DEL
00095 };
00096 
00097 // all except specials, CTLs, SPACE.
00098 const uchar aTextMap[16] = {
00099   0x00, 0x00, 0x00, 0x00,
00100   0x5F, 0x35, 0xFF, 0xC5,
00101   0x7F, 0xFF, 0xFF, 0xE3,
00102   0xFF, 0xFF, 0xFF, 0xFE
00103 };
00104 
00105 // all except tspecials, CTLs, SPACE.
00106 const uchar tTextMap[16] = {
00107   0x00, 0x00, 0x00, 0x00,
00108   0x5F, 0x36, 0xFF, 0xC0,
00109   0x7F, 0xFF, 0xFF, 0xE3,
00110   0xFF, 0xFF, 0xFF, 0xFE
00111 };
00112 
00113 // none except a-zA-Z0-9!*+-/
00114 const uchar eTextMap[16] = {
00115   0x00, 0x00, 0x00, 0x00,
00116   0x40, 0x35, 0xFF, 0xC0,
00117   0x7F, 0xFF, 0xFF, 0xE0,
00118   0x7F, 0xFF, 0xFF, 0xE0
00119 };
00120 
00121 #if defined(_AIX) && defined(truncate)
00122 #undef truncate
00123 #endif
00124 
00125 TQString decodeRFC2047String(const TQCString &src, const char **usedCS,
00126                 const TQCString &defaultCS, bool forceCS)
00127 {
00128   TQCString result, str;
00129   TQCString declaredCS;
00130   const char *beg, *end, *mid, *pos=0;
00131   char *dest, *endOfLastEncWord=0;
00132   char encoding = '\0';
00133   bool valid, onlySpacesSinceLastWord=false;
00134   const int maxLen=400;
00135   int i;
00136 
00137   if(src.find("=?") < 0)
00138     result = src.copy();
00139   else {
00140     result.truncate(src.length());
00141     for (pos=src.data(), dest=result.data(); *pos; pos++)
00142     {
00143       if (pos[0]!='=' || pos[1]!='?')
00144       {
00145         *dest++ = *pos;
00146         if (onlySpacesSinceLastWord)
00147           onlySpacesSinceLastWord = (pos[0]==' ' || pos[1]=='\t');
00148         continue;
00149       }
00150       beg = pos+2;
00151       end = beg;
00152       valid = TRUE;
00153       // parse charset name
00154       declaredCS="";
00155       for (i=2,pos+=2; i<maxLen && (*pos!='?'&&(ispunct(*pos)||isalnum(*pos))); i++) {
00156         declaredCS+=(*pos);
00157         pos++;
00158       }
00159       if (*pos!='?' || i<4 || i>=maxLen) valid = FALSE;
00160       else
00161       {
00162         // get encoding and check delimiting question marks
00163         encoding = toupper(pos[1]);
00164         if (pos[2]!='?' || (encoding!='Q' && encoding!='B'))
00165           valid = FALSE;
00166         pos+=3;
00167         i+=3;
00168       }
00169       if (valid)
00170       {
00171         mid = pos;
00172         // search for end of encoded part
00173         while (i<maxLen && *pos && !(*pos=='?' && *(pos+1)=='='))
00174         {
00175           i++;
00176           pos++;
00177         }
00178         end = pos+2;//end now points to the first char after the encoded string
00179         if (i>=maxLen || !*pos) valid = FALSE;
00180       }
00181 
00182       if (valid) {
00183         // cut all linear-white space between two encoded words
00184         if (onlySpacesSinceLastWord)
00185           dest=endOfLastEncWord;
00186 
00187         if (mid < pos) {
00188           str = TQCString(mid, (int)(pos - mid + 1));
00189           if (encoding == 'Q')
00190           {
00191             // decode quoted printable text
00192             for (i=str.length()-1; i>=0; i--)
00193               if (str[i]=='_') str[i]=' ';
00194             str = KCodecs::quotedPrintableDecode(str);
00195           }
00196           else
00197           {
00198             str = KCodecs::base64Decode(str);
00199           }
00200           if (!str.isNull()) {
00201             for (i=0; str[i]; i++) {
00202               *dest++ = str[i];
00203             }
00204           }
00205         }
00206 
00207         endOfLastEncWord=dest;
00208         onlySpacesSinceLastWord=true;
00209 
00210         pos = end -1;
00211       }
00212       else
00213       {
00214         pos = beg - 2;
00215         *dest++ = *pos++;
00216         *dest++ = *pos;
00217       }
00218     }
00219     *dest = '\0';
00220   }
00221 
00222   //find suitable TQTextCodec
00223   TQTextCodec *codec=0;
00224   bool ok=true;
00225   if (forceCS || declaredCS.isEmpty()) {
00226     codec=TDEGlobal::charsets()->codecForName(defaultCS);
00227     (*usedCS)=cachedCharset(defaultCS);
00228   }
00229   else {
00230     codec=TDEGlobal::charsets()->codecForName(declaredCS, ok);
00231     if(!ok) {     //no suitable codec found => use default charset
00232       codec=TDEGlobal::charsets()->codecForName(defaultCS);
00233       (*usedCS)=cachedCharset(defaultCS);
00234     }
00235     else
00236       (*usedCS)=cachedCharset(declaredCS);
00237   }
00238 
00239   return codec->toUnicode(result.data(), result.length());
00240 }
00241 
00242 TQString decodeRFC2047String(const TQCString &src)
00243 {
00244   const char *usedCS;
00245   return decodeRFC2047String(src, &usedCS, "utf-8", false);
00246 }
00247 
00248 TQCString encodeRFC2047String(const TQString &src, const char *charset,
00249                  bool addressHeader, bool allow8BitHeaders)
00250 {
00251   TQCString encoded8Bit, result, usedCS;
00252   unsigned int start=0,end=0;
00253   bool nonAscii=false, ok=true, useTQEncoding=false;
00254   TQTextCodec *codec=0;
00255 
00256   usedCS=charset;
00257   codec=TDEGlobal::charsets()->codecForName(usedCS, ok);
00258 
00259   if(!ok) {
00260     //no codec available => try local8Bit and hope the best ;-)
00261     usedCS=TDEGlobal::locale()->encoding();
00262     codec=TDEGlobal::charsets()->codecForName(usedCS, ok);
00263   }
00264 
00265   if (usedCS.find("8859-")>=0)  // use "B"-Encoding for non iso-8859-x charsets
00266     useTQEncoding=true;
00267 
00268   encoded8Bit=codec->fromUnicode(src);
00269 
00270   if(allow8BitHeaders)
00271     return encoded8Bit;
00272 
00273   uint encoded8BitLength = encoded8Bit.length();
00274   for (unsigned int i=0; i<encoded8BitLength; i++) {
00275     if (encoded8Bit[i]==' ')    // encoding starts at word boundaries
00276       start = i+1;
00277 
00278     // encode escape character, for japanese encodings...
00279     if (((signed char)encoded8Bit[i]<0) || (encoded8Bit[i] == '\033') ||
00280         (addressHeader && (strchr("\"()<>@,.;:\\[]=",encoded8Bit[i])!=0))) {
00281       end = start;   // non us-ascii char found, now we determine where to stop encoding
00282       nonAscii=true;
00283       break;
00284     }
00285   }
00286 
00287   if (nonAscii) {
00288     while ((end<encoded8Bit.length())&&(encoded8Bit[end]!=' '))  // we encode complete words
00289       end++;
00290 
00291     for (unsigned int x=end;x<encoded8Bit.length();x++)
00292       if (((signed char)encoded8Bit[x]<0) || (encoded8Bit[x] == '\033') ||
00293           (addressHeader && (strchr("\"()<>@,.;:\\[]=",encoded8Bit[x])!=0))) {
00294         end = encoded8Bit.length();     // we found another non-ascii word
00295 
00296       while ((end<encoded8Bit.length())&&(encoded8Bit[end]!=' '))  // we encode complete words
00297         end++;
00298     }
00299 
00300     result = encoded8Bit.left(start)+"=?"+usedCS;
00301 
00302     if (useTQEncoding) {
00303       result += "?Q?";
00304 
00305       char c,hexcode;                       // implementation of the "Q"-encoding described in RFC 2047
00306       for (unsigned int i=start;i<end;i++) {
00307         c = encoded8Bit[i];
00308         if (c == ' ')       // make the result readable with not MIME-capable readers
00309           result+='_';
00310         else
00311           if (((c>='a')&&(c<='z'))||      // paranoid mode, we encode *all* special characters to avoid problems
00312               ((c>='A')&&(c<='Z'))||      // with "From" & "To" headers
00313               ((c>='0')&&(c<='9')))
00314             result+=c;
00315           else {
00316             result += "=";                 // "stolen" from KMail ;-)
00317             hexcode = ((c & 0xF0) >> 4) + 48;
00318             if (hexcode >= 58) hexcode += 7;
00319             result += hexcode;
00320             hexcode = (c & 0x0F) + 48;
00321             if (hexcode >= 58) hexcode += 7;
00322             result += hexcode;
00323           }
00324       }
00325     } else {
00326       result += "?B?"+KCodecs::base64Encode(encoded8Bit.mid(start,end-start), false);
00327     }
00328 
00329     result +="?=";
00330     result += encoded8Bit.right(encoded8Bit.length()-end);
00331   }
00332   else
00333     result = encoded8Bit;
00334 
00335   return result;
00336 }
00337 
00338 TQCString uniqueString()
00339 {
00340   static char chars[] = "0123456789abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
00341   time_t now;
00342   TQCString ret;
00343   char p[11];
00344   int pos, ran;
00345   unsigned int timeval;
00346 
00347   p[10]='\0';
00348   now=time(0);
00349   ran=1+(int) (1000.0*rand()/(RAND_MAX+1.0));
00350   timeval=(now/ran)+getpid();
00351 
00352   for(int i=0; i<10; i++){
00353     pos=(int) (61.0*rand()/(RAND_MAX+1.0));
00354     //kdDebug(5003) << pos << endl;
00355     p[i]=chars[pos];
00356   }
00357   ret.sprintf("%d.%s", timeval, p);
00358 
00359   return ret;
00360 }
00361 
00362 
00363 TQCString multiPartBoundary()
00364 {
00365   TQCString ret;
00366   ret="nextPart"+uniqueString();
00367   return ret;
00368 }
00369 
00370 TQCString extractHeader(const TQCString &src, const char *name)
00371 {
00372   TQCString n=TQCString(name)+":";
00373   int pos1=-1, pos2=0, len=src.length()-1;
00374   bool folded(false);
00375 
00376   if (n.lower() == src.left(n.length()).lower()) {
00377     pos1 = 0;
00378   } else {
00379     n.prepend("\n");
00380     pos1 = src.find(n.data(),0,false);
00381   }
00382 
00383   if (pos1>-1) {    //there is a header with the given name
00384     pos1+=n.length(); //skip the name
00385     // skip the usual space after the colon
00386     if ( src.at( pos1 ) == ' ' )
00387       ++pos1;
00388     pos2=pos1;
00389 
00390     if (src[pos2]!='\n') {  // check if the header is not empty
00391       while(1) {
00392         pos2=src.find("\n", pos2+1);
00393         if(pos2==-1 || pos2==len || ( src[pos2+1]!=' ' && src[pos2+1]!='\t') ) //break if we reach the end of the string, honor folded lines
00394           break;
00395         else
00396           folded = true;
00397       }
00398     }
00399 
00400     if(pos2<0) pos2=len+1; //take the rest of the string
00401 
00402     if (!folded)
00403       return src.mid(pos1, pos2-pos1);
00404     else
00405       return (src.mid(pos1, pos2-pos1).replace(TQRegExp("\\s*\\n\\s*")," "));
00406   }
00407   else {
00408     return TQCString(0); //header not found
00409   }
00410 }
00411 
00412 
00413 TQCString CRLFtoLF(const TQCString &s)
00414 {
00415   TQCString ret=s.copy();
00416   ret.replace(TQRegExp("\\r\\n"), "\n");
00417   return ret;
00418 }
00419 
00420 
00421 TQCString CRLFtoLF(const char *s)
00422 {
00423   TQCString ret=s;
00424   ret.replace(TQRegExp("\\r\\n"), "\n");
00425   return ret;
00426 }
00427 
00428 
00429 TQCString LFtoCRLF(const TQCString &s)
00430 {
00431   TQCString ret=s.copy();
00432   ret.replace(TQRegExp("\\n"), "\r\n");
00433   return ret;
00434 }
00435 
00436 
00437 void removeQuots(TQCString &str)
00438 {
00439   // Removes any quote or backslash caracter
00440   str.replace(TQRegExp("[\\\"]"), "");
00441 }
00442 
00443 
00444 void removeQuots(TQString &str)
00445 {
00446   // Removes any quote or backslash caracter
00447   str.replace(TQRegExp("[\\\"]"), "");
00448 }
00449 
00450 
00451 void addQuotes(TQCString &str, bool forceQuotes)
00452 {
00453   if ( forceQuotes || TQString(str).contains( TQRegExp( TQString( "\"|\\\\|=|\\]|\\[|:|;|,|\\.|,|@|<|>|\\)|\\(" ) ) ) ) {
00454     // Adds a backslash in front of any existing quote or backslash caracter
00455     str.replace(TQRegExp("([\\\"])"), "\\\\1");
00456     // Adds quote at beginning and end of thestring
00457     str.insert(0,'"');
00458     str.append("\"");
00459   }
00460 }
00461 
00462 int DateFormatter::mDaylight = -1;
00463 DateFormatter::DateFormatter(FormatType fType)
00464   : mFormat( fType ), mCurrentTime( 0 )
00465 {
00466 
00467 }
00468 
00469 DateFormatter::~DateFormatter()
00470 {/*empty*/}
00471 
00472 DateFormatter::FormatType
00473 DateFormatter::getFormat() const
00474 {
00475   return mFormat;
00476 }
00477 
00478 void
00479 DateFormatter::setFormat( FormatType t )
00480 {
00481   mFormat = t;
00482 }
00483 
00484 TQString
00485 DateFormatter::dateString( time_t otime , const TQString& lang ,
00486                bool shortFormat, bool includeSecs ) const
00487 {
00488   switch ( mFormat ) {
00489   case Fancy:
00490     return fancy( otime );
00491     break;
00492   case Localized:
00493     return localized( otime, shortFormat, includeSecs, lang );
00494     break;
00495   case CTime:
00496     return cTime( otime );
00497     break;
00498   case Iso:
00499     return isoDate( otime );
00500     break;
00501   case Custom:
00502     return custom( otime );
00503     break;
00504   }
00505   return TQString();
00506 }
00507 
00508 TQString
00509 DateFormatter::dateString(const TQDateTime& dtime, const TQString& lang,
00510                bool shortFormat, bool includeSecs ) const
00511 {
00512   return DateFormatter::dateString( qdateToTimeT(dtime), lang, shortFormat, includeSecs );
00513 }
00514 
00515 TQCString
00516 DateFormatter::rfc2822(time_t otime) const
00517 {
00518   TQDateTime tmp;
00519   TQCString  ret;
00520 
00521   tmp.setTime_t(otime);
00522 
00523   ret = tmp.toString("ddd, dd MMM yyyy hh:mm:ss ").latin1();
00524   ret += zone(otime);
00525 
00526   return ret;
00527 }
00528 
00529 TQString
00530 DateFormatter::custom(time_t t) const
00531 {
00532   if ( mCustomFormat.isEmpty() )
00533     return TQString();
00534 
00535   int z = mCustomFormat.find("Z");
00536   TQDateTime d;
00537   TQString ret = mCustomFormat;
00538 
00539   d.setTime_t(t);
00540   if ( z != -1 ) {
00541     ret.replace(z,1,zone(t));
00542   }
00543 
00544   ret = d.toString(ret);
00545 
00546   return ret;
00547 }
00548 
00549 void
00550 DateFormatter::setCustomFormat(const TQString& format)
00551 {
00552   mCustomFormat = format;
00553   mFormat = Custom;
00554 }
00555 
00556 TQString
00557 DateFormatter::getCustomFormat() const
00558 {
00559   return mCustomFormat;
00560 }
00561 
00562 
00563 TQCString
00564 DateFormatter::zone(time_t otime) const
00565 {
00566   TQCString ret;
00567 #if defined(HAVE_TIMEZONE) || defined(HAVE_TM_GMTOFF)
00568   struct tm *local = localtime( &otime );
00569 #endif
00570 
00571 #if defined(HAVE_TIMEZONE)
00572 
00573   //hmm, could make hours & mins static
00574   int secs = abs(timezone);
00575   int neg  = (timezone>0)?1:0;
00576   int hours = secs/3600;
00577   int mins  = (secs - hours*3600)/60;
00578 
00579   // adjust to daylight
00580   if ( local->tm_isdst > 0 ) {
00581       mDaylight = 1;
00582       if ( neg )
00583         --hours;
00584       else
00585         ++hours;
00586   } else
00587       mDaylight = 0;
00588 
00589   ret.sprintf("%c%.2d%.2d",(neg)?'-':'+', hours, mins);
00590 
00591 #elif defined(HAVE_TM_GMTOFF)
00592 
00593   int secs = abs( local->tm_gmtoff );
00594   int neg  = (local->tm_gmtoff<0)?1:0; //no, I don't know why it's backwards :o
00595   int hours = secs/3600;
00596   int mins  = (secs - hours*3600)/60;
00597 
00598   if ( local->tm_isdst > 0 )
00599       mDaylight = 1;
00600   else
00601       mDaylight = 0;
00602 
00603   ret.sprintf("%c%.2d%.2d",(neg)?'-':'+', hours, mins);
00604 
00605 #else
00606 
00607   TQDateTime d1 = TQDateTime::fromString( asctime(gmtime(&otime)) );
00608   TQDateTime d2 = TQDateTime::fromString( asctime(localtime(&otime)) );
00609   int secs = d1.secsTo(d2);
00610   int neg = (secs<0)?1:0;
00611   secs = abs(secs);
00612   int hours = secs/3600;
00613   int mins  = (secs - hours*3600)/60;
00614   // daylight should be already taken care of here
00615   ret.sprintf("%c%.2d%.2d",(neg)?'-':'+', hours, mins);
00616 
00617 #endif /* HAVE_TIMEZONE */
00618 
00619   return ret;
00620 }
00621 
00622 time_t
00623 DateFormatter::qdateToTimeT(const TQDateTime& dt) const
00624 {
00625   TQDateTime epoch( TQDate(1970, 1,1), TQTime(00,00,00) );
00626   time_t otime;
00627   time( &otime );
00628 
00629   TQDateTime d1 = TQDateTime::fromString( asctime(gmtime(&otime)) );
00630   TQDateTime d2 = TQDateTime::fromString( asctime(localtime(&otime)) );
00631   time_t drf = epoch.secsTo( dt ) - d1.secsTo( d2 );
00632 
00633   return drf;
00634 }
00635 
00636 TQString
00637 DateFormatter::fancy(time_t otime) const
00638 {
00639   TDELocale *locale = TDEGlobal::locale();
00640 
00641   if ( otime <= 0 )
00642     return i18n( "unknown" );
00643 
00644   if ( !mCurrentTime ) {
00645     time( &mCurrentTime );
00646     mDate.setTime_t( mCurrentTime );
00647   }
00648 
00649   TQDateTime old;
00650   old.setTime_t( otime );
00651 
00652   // not more than an hour in the future
00653   if ( mCurrentTime + 60 * 60 >= otime ) {
00654     time_t diff = mCurrentTime - otime;
00655 
00656     if ( diff < 24 * 60 * 60 ) {
00657       if ( old.date().year() == mDate.date().year() &&
00658        old.date().dayOfYear() == mDate.date().dayOfYear() )
00659     return i18n( "Today %1" ).arg( locale->
00660                        formatTime( old.time(), true ) );
00661     }
00662     if ( diff < 2 * 24 * 60 * 60 ) {
00663       TQDateTime yesterday( mDate.addDays( -1 ) );
00664       if ( old.date().year() == yesterday.date().year() &&
00665        old.date().dayOfYear() == yesterday.date().dayOfYear() )
00666     return i18n( "Yesterday %1" ).arg( locale->
00667                        formatTime( old.time(), true) );
00668     }
00669     for ( int i = 3; i < 7; i++ )
00670       if ( diff < i * 24 * 60 * 60 ) {
00671     TQDateTime weekday( mDate.addDays( -i + 1 ) );
00672     if ( old.date().year() == weekday.date().year() &&
00673          old.date().dayOfYear() == weekday.date().dayOfYear() )
00674       return i18n( "1. weekday, 2. time", "%1 %2" ).
00675 #if KDE_IS_VERSION( 3, 1, 90 )
00676         arg( locale->calendar()->weekDayName( old.date() ) ).
00677 #else
00678         arg( locale->weekDayName( old.date().dayOfWeek() ) ).
00679 #endif
00680         arg( locale->formatTime( old.time(), true) );
00681       }
00682   }
00683 
00684   return locale->formatDateTime( old );
00685 
00686 }
00687 
00688 TQString
00689 DateFormatter::localized(time_t otime, bool shortFormat, bool includeSecs,
00690              const TQString& localeLanguage ) const
00691 {
00692   TQDateTime tmp;
00693   TQString ret;
00694   TDELocale *locale = TDEGlobal::locale();
00695 
00696   tmp.setTime_t( otime );
00697 
00698 
00699   if ( !localeLanguage.isEmpty() ) {
00700     locale=new TDELocale(localeLanguage);
00701     locale->setLanguage(localeLanguage);
00702     locale->setCountry(localeLanguage);
00703     ret = locale->formatDateTime( tmp, shortFormat, includeSecs );
00704     delete locale;
00705   } else {
00706     ret = locale->formatDateTime( tmp, shortFormat, includeSecs );
00707   }
00708 
00709   return ret;
00710 }
00711 
00712 TQString
00713 DateFormatter::cTime(time_t otime) const
00714 {
00715   return TQString::fromLatin1( ctime(  &otime ) ).stripWhiteSpace() ;
00716 }
00717 
00718 TQString
00719 DateFormatter::isoDate(time_t otime) const
00720 {
00721   char cstr[64];
00722   strftime( cstr, 63, "%Y-%m-%d %H:%M:%S", localtime(&otime) );
00723   return TQString( cstr );
00724 }
00725 
00726 
00727 void
00728 DateFormatter::reset()
00729 {
00730   mCurrentTime = 0;
00731 }
00732 
00733 TQString
00734 DateFormatter::formatDate(DateFormatter::FormatType t, time_t otime,
00735               const TQString& data, bool shortFormat, bool includeSecs )
00736 {
00737   DateFormatter f( t );
00738   if ( t == DateFormatter::Custom ) {
00739     f.setCustomFormat( data );
00740   }
00741   return f.dateString( otime, data, shortFormat, includeSecs );
00742 }
00743 
00744 TQString
00745 DateFormatter::formatCurrentDate( DateFormatter::FormatType t, const TQString& data,
00746                   bool shortFormat, bool includeSecs )
00747 {
00748   DateFormatter f( t );
00749   if ( t == DateFormatter::Custom ) {
00750     f.setCustomFormat( data );
00751   }
00752   return f.dateString( time(0), data, shortFormat, includeSecs );
00753 }
00754 
00755 TQCString
00756 DateFormatter::rfc2822FormatDate( time_t t )
00757 {
00758   DateFormatter f;
00759   return f.rfc2822( t );
00760 }
00761 
00762 bool
00763 DateFormatter::isDaylight()
00764 {
00765   if ( mDaylight == -1 ) {
00766     time_t ntime = time( 0 );
00767     struct tm *local = localtime( &ntime );
00768     if ( local->tm_isdst > 0 ) {
00769       mDaylight = 1;
00770       return true;
00771     } else {
00772       mDaylight = 0;
00773       return false;
00774     }
00775   } else if ( mDaylight != 0 )
00776     return true;
00777   else
00778     return false;
00779 }
00780 
00781 } // namespace KMime