kmail Library API Documentation

kmmsgbase.cpp

00001 // kmmsgbase.cpp
00002 
00003 #include <config.h>
00004 
00005 #include "kmmsgbase.h"
00006 
00007 #include "kmfolderindex.h"
00008 #include "kmfolder.h"
00009 #include "kmheaders.h"
00010 #include "kmmsgdict.h"
00011 #include "messageproperty.h"
00012 using KMail::MessageProperty;
00013 
00014 #include <kdebug.h>
00015 #include <kglobal.h>
00016 #include <kcharsets.h>
00017 #include <kmdcodec.h>
00018 #include <krfcdate.h>
00019 
00020 #include <mimelib/mimepp.h>
00021 #include <kmime_codecs.h>
00022 
00023 #include <qtextcodec.h>
00024 #include <qdeepcopy.h>
00025 #include <qregexp.h>
00026 
00027 #include <ctype.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 
00031 #ifdef HAVE_BYTESWAP_H
00032 #include <byteswap.h>
00033 #endif
00034 
00035 // We define functions as kmail_swap_NN so that we don't get compile errors
00036 // on platforms where bswap_NN happens to be a function instead of a define.
00037 
00038 /* Swap bytes in 16 bit value.  */
00039 #ifdef bswap_16
00040 #define kmail_swap_16(x) bswap_16(x)
00041 #else
00042 #define kmail_swap_16(x) \
00043      ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
00044 #endif
00045 
00046 /* Swap bytes in 32 bit value.  */
00047 #ifdef bswap_32
00048 #define kmail_swap_32(x) bswap_32(x)
00049 #else
00050 #define kmail_swap_32(x) \
00051      ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |           \
00052       (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
00053 #endif
00054 
00055 /* Swap bytes in 64 bit value.  */
00056 #ifdef bswap_64
00057 #define kmail_swap_64(x) bswap_64(x)
00058 #else
00059 #define kmail_swap_64(x) \
00060      ((((x) & 0xff00000000000000ull) >> 56)                   \
00061       | (((x) & 0x00ff000000000000ull) >> 40)                     \
00062       | (((x) & 0x0000ff0000000000ull) >> 24)                     \
00063       | (((x) & 0x000000ff00000000ull) >> 8)                      \
00064       | (((x) & 0x00000000ff000000ull) << 8)                      \
00065       | (((x) & 0x0000000000ff0000ull) << 24)                     \
00066       | (((x) & 0x000000000000ff00ull) << 40)                     \
00067       | (((x) & 0x00000000000000ffull) << 56))
00068 #endif
00069 
00070 //-----------------------------------------------------------------------------
00071 KMMsgBase::KMMsgBase(KMFolder* aParentFolder)
00072   : mParent( aParentFolder ), mIndexOffset( 0 ),
00073     mIndexLength( 0 ), mDirty( false ), mEnableUndo( false ), mStatus( KMMsgStatusUnknown )
00074 {
00075 }
00076 
00077 
00078 //-----------------------------------------------------------------------------
00079 KMMsgBase::~KMMsgBase()
00080 {
00081   MessageProperty::forget( this );
00082 }
00083 
00084 KMFolderIndex* KMMsgBase::storage() const
00085 {
00086   // TODO: How did this ever work? What about KMFolderSearch that does
00087   // not inherit KMFolderIndex?
00088   if( mParent )
00089     return static_cast<KMFolderIndex*>( mParent->storage() );
00090   return 0;
00091 }
00092 
00093 //-----------------------------------------------------------------------------
00094 void KMMsgBase::assign(const KMMsgBase* other)
00095 {
00096   mParent = other->mParent;
00097   mDirty  = other->mDirty;
00098   mIndexOffset = other->mIndexOffset;
00099   mIndexLength = other->mIndexLength;
00100   MessageProperty::forget( this );
00101   //bool otherTransfer = MessageProperty::transferInProgress( other );
00102   //MessageProperty::setTransferInProgress( this, otherTransfer );
00103 }
00104 
00105 
00106 //-----------------------------------------------------------------------------
00107 KMMsgBase& KMMsgBase::operator=(const KMMsgBase& other)
00108 {
00109   assign(&other);
00110   return *this;
00111 }
00112 
00113 
00114 //----------------------------------------------------------------------------
00115 KMMsgBase::KMMsgBase( const KMMsgBase& other )
00116 {
00117     assign( &other );
00118 }
00119 
00120 
00121 //-----------------------------------------------------------------------------
00122 bool KMMsgBase::isMessage(void) const
00123 {
00124   return FALSE;
00125 }
00126 //-----------------------------------------------------------------------------
00127 void KMMsgBase::toggleStatus(const KMMsgStatus aStatus, int idx)
00128 {
00129   mDirty = true;
00130   KMMsgStatus oldStatus = status();
00131   if ( status() & aStatus ) {
00132     mStatus &= ~aStatus;
00133   } else {
00134     mStatus |= aStatus;
00135     // Ignored and Watched are toggleable, yet mutually exclusive.
00136     // That is an arbitrary restriction on my part. HAR HAR HAR :) -till
00137     if (aStatus == KMMsgStatusWatched)
00138       mStatus &= ~KMMsgStatusIgnored;
00139     if (aStatus == KMMsgStatusIgnored) {
00140       mStatus &= ~KMMsgStatusWatched;
00141       // Set to read. Don't use setStatus, that emits msgStatusChanged
00142       // and we only want to do that once.
00143       mStatus &= ~KMMsgStatusUnread;
00144       mStatus &= ~KMMsgStatusNew;
00145       mStatus |= KMMsgStatusRead;
00146     }
00147     if (aStatus == KMMsgStatusSpam)
00148       mStatus &= ~KMMsgStatusHam;
00149     if (aStatus == KMMsgStatusHam)
00150       mStatus &= ~KMMsgStatusSpam;
00151   }
00152   if (storage()) {
00153      if (idx < 0)
00154        idx = storage()->find( this );
00155      storage()->msgStatusChanged( oldStatus, status(), idx );
00156      storage()->headerOfMsgChanged(this, idx);
00157   }
00158 
00159 }
00160 
00161 //-----------------------------------------------------------------------------
00162 void KMMsgBase::setStatus(const KMMsgStatus aStatus, int idx)
00163 {
00164   mDirty = TRUE;
00165   KMMsgStatus oldStatus = status();
00166   switch (aStatus) {
00167     case KMMsgStatusRead:
00168       // Unset unread and new, set read
00169       mStatus &= ~KMMsgStatusUnread;
00170       mStatus &= ~KMMsgStatusNew;
00171       mStatus |= KMMsgStatusRead;
00172       break;
00173 
00174     case KMMsgStatusUnread:
00175       // unread overrides read
00176       mStatus &= ~KMMsgStatusOld;
00177       mStatus &= ~KMMsgStatusRead;
00178       mStatus &= ~KMMsgStatusNew;
00179       mStatus |= KMMsgStatusUnread;
00180       break;
00181 
00182     case KMMsgStatusOld:
00183       // old can't be new or unread
00184       mStatus &= ~KMMsgStatusNew;
00185       mStatus &= ~KMMsgStatusUnread;
00186       mStatus |= KMMsgStatusOld;
00187       break;
00188 
00189     case KMMsgStatusNew:
00190       // new overrides old and read
00191       mStatus &= ~KMMsgStatusOld;
00192       mStatus &= ~KMMsgStatusRead;
00193       mStatus &= ~KMMsgStatusUnread;
00194       mStatus |= KMMsgStatusNew;
00195       break;
00196 
00197     case KMMsgStatusDeleted:
00198       mStatus |= KMMsgStatusDeleted;
00199       break;
00200 
00201     case KMMsgStatusReplied:
00202       mStatus |= KMMsgStatusReplied;
00203       break;
00204 
00205     case KMMsgStatusForwarded:
00206       mStatus |= KMMsgStatusForwarded;
00207       break;
00208 
00209     case KMMsgStatusQueued:
00210       mStatus |= KMMsgStatusQueued;
00211       break;
00212 
00213     case KMMsgStatusSent:
00214       mStatus &= ~KMMsgStatusQueued;
00215       mStatus &= ~KMMsgStatusUnread;
00216       mStatus &= ~KMMsgStatusNew;
00217       mStatus |= KMMsgStatusSent;
00218       break;
00219 
00220     case KMMsgStatusFlag:
00221       mStatus |= KMMsgStatusFlag;
00222       break;
00223 
00224     // Watched and ignored are mutually exclusive
00225     case KMMsgStatusWatched:
00226       mStatus &= ~KMMsgStatusIgnored;
00227       mStatus |= KMMsgStatusWatched;
00228       break;
00229 
00230     case KMMsgStatusIgnored:
00231       mStatus &= ~KMMsgStatusWatched;
00232       mStatus |= KMMsgStatusIgnored;
00233       break;
00234     // as are ham and spam
00235     case KMMsgStatusSpam:
00236       mStatus &= ~KMMsgStatusHam;
00237       mStatus |= KMMsgStatusSpam;
00238       break;
00239     case KMMsgStatusHam:
00240       mStatus &= ~KMMsgStatusSpam;
00241       mStatus |= KMMsgStatusHam;
00242       break;
00243     case KMMsgStatusHasAttach:
00244       mStatus &= ~KMMsgStatusHasNoAttach;
00245       mStatus |= KMMsgStatusHasAttach;
00246       break;
00247     case KMMsgStatusHasNoAttach:
00248       mStatus &= ~KMMsgStatusHasAttach;
00249       mStatus |= KMMsgStatusHasNoAttach;
00250       break;
00251     default:
00252       mStatus = aStatus;
00253       break;
00254   }
00255 
00256   if ( oldStatus != mStatus && storage() ) {
00257     if (idx < 0)
00258       idx = storage()->find( this );
00259     storage()->msgStatusChanged( oldStatus, status(), idx );
00260     storage()->headerOfMsgChanged( this, idx );
00261   }
00262 }
00263 
00264 
00265 
00266 //-----------------------------------------------------------------------------
00267 void KMMsgBase::setStatus(const char* aStatusStr, const char* aXStatusStr)
00268 {
00269   // first try to find status from "X-Status" field if given
00270   if (aXStatusStr) {
00271     if (strchr(aXStatusStr, 'N')) setStatus(KMMsgStatusNew);
00272     if (strchr(aXStatusStr, 'U')) setStatus(KMMsgStatusUnread);
00273     if (strchr(aXStatusStr, 'O')) setStatus(KMMsgStatusOld);
00274     if (strchr(aXStatusStr, 'R')) setStatus(KMMsgStatusRead);
00275     if (strchr(aXStatusStr, 'D')) setStatus(KMMsgStatusDeleted);
00276     if (strchr(aXStatusStr, 'A')) setStatus(KMMsgStatusReplied);
00277     if (strchr(aXStatusStr, 'F')) setStatus(KMMsgStatusForwarded);
00278     if (strchr(aXStatusStr, 'Q')) setStatus(KMMsgStatusQueued);
00279     if (strchr(aXStatusStr, 'S')) setStatus(KMMsgStatusSent);
00280     if (strchr(aXStatusStr, 'G')) setStatus(KMMsgStatusFlag);
00281     if (strchr(aXStatusStr, 'P')) setStatus(KMMsgStatusSpam);
00282     if (strchr(aXStatusStr, 'H')) setStatus(KMMsgStatusHam);
00283     if (strchr(aXStatusStr, 'T')) setStatus(KMMsgStatusHasAttach);
00284     if (strchr(aXStatusStr, 'C')) setStatus(KMMsgStatusHasNoAttach);
00285   }
00286 
00287   // Merge the contents of the "Status" field
00288   if (aStatusStr) {
00289     if ((aStatusStr[0]== 'R' && aStatusStr[1]== 'O') ||
00290         (aStatusStr[0]== 'O' && aStatusStr[1]== 'R')) {
00291       setStatus( KMMsgStatusOld );
00292       setStatus( KMMsgStatusRead );
00293     }
00294     else if (aStatusStr[0] == 'R')
00295       setStatus(KMMsgStatusRead);
00296     else if (aStatusStr[0] == 'D')
00297       setStatus(KMMsgStatusDeleted);
00298     else
00299       setStatus(KMMsgStatusNew);
00300   }
00301 }
00302 
00303 
00304 void KMMsgBase::setEncryptionState( const KMMsgEncryptionState /*status*/, int idx )
00305 {
00306     //kdDebug(5006) << "***setEncryptionState1( " << status << " )" << endl;
00307     mDirty = TRUE;
00308     if (storage())
00309         storage()->headerOfMsgChanged(this, idx);
00310 }
00311 
00312 void KMMsgBase::setEncryptionStateChar( QChar status, int idx )
00313 {
00314     //kdDebug(5006) << "***setEncryptionState2( " << (status.isNull() ? '?' : status.latin1()) << " )" << endl;
00315 
00316     if( status.latin1() == (char)KMMsgEncryptionStateUnknown )
00317         setEncryptionState( KMMsgEncryptionStateUnknown, idx );
00318     else if( status.latin1() == (char)KMMsgNotEncrypted )
00319         setEncryptionState( KMMsgNotEncrypted, idx );
00320     else if( status.latin1() == (char)KMMsgPartiallyEncrypted )
00321         setEncryptionState( KMMsgPartiallyEncrypted, idx );
00322     else if( status.latin1() == (char)KMMsgFullyEncrypted )
00323         setEncryptionState( KMMsgFullyEncrypted, idx );
00324     else
00325         setEncryptionState( KMMsgEncryptionStateUnknown, idx );
00326 }
00327 
00328 
00329 void KMMsgBase::setSignatureState( const KMMsgSignatureState /*status*/, int idx )
00330 {
00331     //kdDebug(5006) << "***setSignatureState1( " << status << " )" << endl;
00332     mDirty = TRUE;
00333     if (storage())
00334          storage()->headerOfMsgChanged(this, idx);
00335 }
00336 
00337 void KMMsgBase::setMDNSentState( KMMsgMDNSentState, int idx ) {
00338   mDirty = true;
00339   if ( storage() )
00340     storage()->headerOfMsgChanged(this, idx);
00341 }
00342 
00343 void KMMsgBase::setSignatureStateChar( QChar status, int idx )
00344 {
00345     //kdDebug(5006) << "***setSignatureState2( " << (status.isNull() ? '?' : status.latin1()) << " )" << endl;
00346 
00347     if( status.latin1() == (char)KMMsgSignatureStateUnknown )
00348         setSignatureState( KMMsgSignatureStateUnknown, idx );
00349     else if( status.latin1() == (char)KMMsgNotSigned )
00350         setSignatureState( KMMsgNotSigned, idx );
00351     else if( status.latin1() == (char)KMMsgPartiallySigned )
00352         setSignatureState( KMMsgPartiallySigned,idx );
00353     else if( status.latin1() == (char)KMMsgFullySigned )
00354         setSignatureState( KMMsgFullySigned, idx );
00355     else
00356         setSignatureState( KMMsgSignatureStateUnknown, idx );
00357 }
00358 
00359 //-----------------------------------------------------------------------------
00360 bool KMMsgBase::isUnread(void) const
00361 {
00362   KMMsgStatus st = status();
00363   return (st & KMMsgStatusUnread);
00364 }
00365 
00366 //-----------------------------------------------------------------------------
00367 bool KMMsgBase::isNew(void) const
00368 {
00369   KMMsgStatus st = status();
00370   return (st & KMMsgStatusNew);
00371 }
00372 
00373 //-----------------------------------------------------------------------------
00374 bool KMMsgBase::isOfUnknownStatus(void) const
00375 {
00376   KMMsgStatus st = status();
00377   return (st == KMMsgStatusUnknown);
00378 }
00379 
00380 //-----------------------------------------------------------------------------
00381 bool KMMsgBase::isOld(void) const
00382 {
00383   KMMsgStatus st = status();
00384   return (st & KMMsgStatusOld);
00385 }
00386 
00387 //-----------------------------------------------------------------------------
00388 bool KMMsgBase::isRead(void) const
00389 {
00390   KMMsgStatus st = status();
00391   return (st & KMMsgStatusRead);
00392 }
00393 
00394 //-----------------------------------------------------------------------------
00395 bool KMMsgBase::isDeleted(void) const
00396 {
00397   KMMsgStatus st = status();
00398   return (st & KMMsgStatusDeleted);
00399 }
00400 
00401 //-----------------------------------------------------------------------------
00402 bool KMMsgBase::isReplied(void) const
00403 {
00404   KMMsgStatus st = status();
00405   return (st & KMMsgStatusReplied);
00406 }
00407 
00408 //-----------------------------------------------------------------------------
00409 bool KMMsgBase::isForwarded(void) const
00410 {
00411   KMMsgStatus st = status();
00412   return (st & KMMsgStatusForwarded);
00413 }
00414 
00415 //-----------------------------------------------------------------------------
00416 bool KMMsgBase::isQueued(void) const
00417 {
00418   KMMsgStatus st = status();
00419   return (st & KMMsgStatusQueued);
00420 }
00421 
00422 //-----------------------------------------------------------------------------
00423 bool KMMsgBase::isSent(void) const
00424 {
00425   KMMsgStatus st = status();
00426   return (st & KMMsgStatusSent);
00427 }
00428 
00429 //-----------------------------------------------------------------------------
00430 bool KMMsgBase::isImportant(void) const
00431 {
00432   KMMsgStatus st = status();
00433   return (st & KMMsgStatusFlag);
00434 }
00435 
00436 //-----------------------------------------------------------------------------
00437 bool KMMsgBase::isWatched(void) const
00438 {
00439   KMMsgStatus st = status();
00440   return (st & KMMsgStatusWatched);
00441 }
00442 
00443 //-----------------------------------------------------------------------------
00444 bool KMMsgBase::isIgnored(void) const
00445 {
00446   KMMsgStatus st = status();
00447   return (st & KMMsgStatusIgnored);
00448 }
00449 
00450 //-----------------------------------------------------------------------------
00451 bool KMMsgBase::isSpam(void) const
00452 {
00453   KMMsgStatus st = status();
00454   return (st & KMMsgStatusSpam);
00455 }
00456 
00457 //-----------------------------------------------------------------------------
00458 bool KMMsgBase::isHam(void) const
00459 {
00460   KMMsgStatus st = status();
00461   return (st & KMMsgStatusHam);
00462 }
00463 
00464 //-----------------------------------------------------------------------------
00465 bool KMMsgBase::isTodo(void) const
00466 {
00467   KMMsgStatus st = status();
00468   return (st & KMMsgStatusTodo);
00469 }
00470 
00471 //-----------------------------------------------------------------------------
00472 QCString KMMsgBase::statusToStr(const KMMsgStatus status)
00473 {
00474   QCString sstr;
00475   if (status & KMMsgStatusNew) sstr += 'N';
00476   if (status & KMMsgStatusUnread) sstr += 'U';
00477   if (status & KMMsgStatusOld) sstr += 'O';
00478   if (status & KMMsgStatusRead) sstr += 'R';
00479   if (status & KMMsgStatusDeleted) sstr += 'D';
00480   if (status & KMMsgStatusReplied) sstr += 'A';
00481   if (status & KMMsgStatusForwarded) sstr += 'F';
00482   if (status & KMMsgStatusQueued) sstr += 'Q';
00483   if (status & KMMsgStatusSent) sstr += 'S';
00484   if (status & KMMsgStatusFlag) sstr += 'G';
00485   if (status & KMMsgStatusWatched) sstr += 'W';
00486   if (status & KMMsgStatusIgnored) sstr += 'I';
00487   if (status & KMMsgStatusSpam) sstr += 'P';
00488   if (status & KMMsgStatusHam) sstr += 'H';
00489   if (status & KMMsgStatusHasAttach) sstr += 'T';
00490   if (status & KMMsgStatusHasNoAttach) sstr += 'C';
00491 
00492   return sstr;
00493 }
00494 
00495 //-----------------------------------------------------------------------------
00496 QString KMMsgBase::statusToSortRank()
00497 {
00498   QString sstr = "bcbbbbbbb";
00499 
00500   // put watched ones first, then normal ones, ignored ones last
00501   if (status() & KMMsgStatusWatched) sstr[0] = 'a';
00502   if (status() & KMMsgStatusIgnored) sstr[0] = 'c';
00503 
00504   // Second level. One of new, old, read, unread
00505   if (status() & KMMsgStatusNew) sstr[1] = 'a';
00506   if (status() & KMMsgStatusUnread) sstr[1] = 'b';
00507   //if (status() & KMMsgStatusOld) sstr[1] = 'c';
00508   //if (status() & KMMsgStatusRead) sstr[1] = 'c';
00509 
00510   // Third level. In somewhat arbitrary order.
00511   if (status() & KMMsgStatusDeleted) sstr[2] = 'a';
00512   if (status() & KMMsgStatusFlag) sstr[3] = 'a';
00513   if (status() & KMMsgStatusReplied) sstr[4] = 'a';
00514   if (status() & KMMsgStatusForwarded) sstr[5] = 'a';
00515   if (status() & KMMsgStatusQueued) sstr[6] = 'a';
00516   if (status() & KMMsgStatusSent) sstr[7] = 'a';
00517   if (status() & KMMsgStatusHam) sstr[8] = 'a';
00518   if (status() & KMMsgStatusSpam) sstr[8] = 'c';
00519 
00520   return sstr;
00521 }
00522 
00523 
00524 //-----------------------------------------------------------------------------
00525 void KMMsgBase::setDate(const QCString& aDateStr)
00526 {
00527   setDate( KRFCDate::parseDate( aDateStr ) );
00528 }
00529 
00530 
00531 //-----------------------------------------------------------------------------
00532 QString KMMsgBase::dateStr(void) const
00533 {
00534   time_t d = date();
00535   return KMime::DateFormatter::formatDate(KMime::DateFormatter::Fancy, d);
00536 }
00537 
00538 
00539 //-----------------------------------------------------------------------------
00540 QString KMMsgBase::skipKeyword(const QString& aStr, QChar sepChar,
00541                    bool* hasKeyword)
00542 {
00543   unsigned int i = 0, maxChars = 3;
00544   QString str = aStr;
00545 
00546   while (str[0] == ' ') str.remove(0,1);
00547   if (hasKeyword) *hasKeyword=FALSE;
00548 
00549   for (i=0; i < str.length() && i < maxChars; i++)
00550   {
00551     if (str[i] < 'A' || str[i] == sepChar) break;
00552   }
00553 
00554   if (str[i] == sepChar) // skip following spaces too
00555   {
00556     do {
00557       i++;
00558     } while (str[i] == ' ');
00559     if (hasKeyword) *hasKeyword=TRUE;
00560     return str.mid(i);
00561   }
00562   return str;
00563 }
00564 
00565 
00566 //-----------------------------------------------------------------------------
00567 const QTextCodec* KMMsgBase::codecForName(const QCString& _str)
00568 {
00569   if (_str.isEmpty()) return 0;
00570   return KGlobal::charsets()->codecForName(_str.lower());
00571 }
00572 
00573 
00574 //-----------------------------------------------------------------------------
00575 QCString KMMsgBase::toUsAscii(const QString& _str, bool *ok)
00576 {
00577   bool all_ok =true;
00578   QString result = _str;
00579   int len = result.length();
00580   for (int i = 0; i < len; i++)
00581     if (result.at(i).unicode() >= 128) {
00582       result.at(i) = '?';
00583       all_ok = false;
00584     }
00585   if (ok)
00586     *ok = all_ok;
00587   return result.latin1();
00588 }
00589 
00590 
00591 //-----------------------------------------------------------------------------
00592 QStringList KMMsgBase::supportedEncodings(bool usAscii)
00593 {
00594   QStringList encodingNames = KGlobal::charsets()->availableEncodingNames();
00595   QStringList encodings;
00596   QMap<QString,bool> mimeNames;
00597   for (QStringList::Iterator it = encodingNames.begin();
00598     it != encodingNames.end(); it++)
00599   {
00600     QTextCodec *codec = KGlobal::charsets()->codecForName(*it);
00601     QString mimeName = (codec) ? QString(codec->mimeName()).lower() : (*it);
00602     if (mimeNames.find(mimeName) == mimeNames.end())
00603     {
00604       encodings.append(KGlobal::charsets()->languageForEncoding(*it)
00605         + " ( " + mimeName + " )");
00606       mimeNames.insert(mimeName, TRUE);
00607     }
00608   }
00609   encodings.sort();
00610   if (usAscii) encodings.prepend(KGlobal::charsets()
00611     ->languageForEncoding("us-ascii") + " ( us-ascii )");
00612   return encodings;
00613 }
00614 
00615 namespace {
00616   // don't rely on isblank(), which is a GNU extension in
00617   // <cctype>. But if someone wants to write a configure test for
00618   // isblank(), we can then rename this function to isblank and #ifdef
00619   // it's definition...
00620   inline bool isBlank( char ch ) { return ch == ' ' || ch == '\t' ; }
00621 
00622   QCString unfold( const QCString & header ) {
00623     if ( header.isEmpty() )
00624       return QCString();
00625 
00626     QCString result( header.size() ); // size() >= length()+1 and size() is O(1)
00627     char * d = result.data();
00628 
00629     for ( const char * s = header.data() ; *s ; )
00630       if ( *s == '\r' ) { // ignore
00631     ++s;
00632     continue;
00633       } else if ( *s == '\n' ) { // unfold
00634     while ( isBlank( *++s ) );
00635     *d++ = ' ';
00636       } else
00637     *d++ = *s++;
00638 
00639     *d++ = '\0';
00640 
00641     result.truncate( d - result.data() );
00642     return result;
00643   }
00644 }
00645 
00646 
00647 //-----------------------------------------------------------------------------
00648 QString KMMsgBase::decodeRFC2047String(const QCString& aStr)
00649 {
00650   if ( aStr.isEmpty() )
00651     return QString::null;
00652 
00653   const QCString str = unfold( aStr );
00654 
00655   if ( str.isEmpty() )
00656     return QString::null;
00657 
00658   if ( str.find( "=?" ) < 0 )
00659     return kmkernel->networkCodec()->toUnicode( str );
00660 
00661   QString result;
00662   QCString LWSP_buffer;
00663   bool lastWasEncodedWord = false;
00664   static const int maxLen = 200;
00665 
00666   for ( const char * pos = str.data() ; *pos ; ++pos ) {
00667     // collect LWSP after encoded-words,
00668     // because we might need to throw it out
00669     // (when the next word is an encoded-word)
00670     if ( lastWasEncodedWord && isBlank( pos[0] ) ) {
00671       LWSP_buffer += pos[0];
00672       continue;
00673     }
00674     // verbatimly copy normal text
00675     if (pos[0]!='=' || pos[1]!='?') {
00676       result += LWSP_buffer + pos[0];
00677       LWSP_buffer = 0;
00678       lastWasEncodedWord = FALSE;
00679       continue;
00680     }
00681     // found possible encoded-word
00682     const char * const beg = pos;
00683     {
00684       // parse charset name
00685       QCString charset;
00686       int i = 2;
00687       for (pos+=2; i<maxLen && (*pos!='?'&&(*pos==' '||ispunct(*pos)||isalnum(*pos))); ++i) {
00688     charset += *pos;
00689     pos++;
00690       }
00691       if (*pos!='?' || i<4 || i>=maxLen)
00692     goto invalid_encoded_word;
00693 
00694       // get encoding and check delimiting question marks
00695       const char encoding[2] = { pos[1], '\0' };
00696       if (pos[2]!='?' || (encoding[0]!='Q' && encoding[0]!='q' &&
00697               encoding[0]!='B' && encoding[0]!='b'))
00698     goto invalid_encoded_word;
00699       pos+=3; i+=3; // skip ?x?
00700       const char * enc_start = pos;
00701       // search for end of encoded part
00702       while (i<maxLen && *pos && !(*pos=='?' && *(pos+1)=='=')) {
00703     i++;
00704     pos++;
00705       }
00706       if (i>=maxLen || !*pos)
00707     goto invalid_encoded_word;
00708 
00709       // valid encoding: decode and throw away separating LWSP
00710       const KMime::Codec * c = KMime::Codec::codecForName( encoding );
00711       kdFatal( !c, 5006 ) << "No \"" << encoding << "\" codec!?" << endl;
00712 
00713       QByteArray in; in.setRawData( enc_start, pos - enc_start );
00714       const QByteArray enc = c->decode( in );
00715       in.resetRawData( enc_start, pos - enc_start );
00716 
00717       const QTextCodec * codec = codecForName(charset);
00718       if (!codec) codec = kmkernel->networkCodec();
00719       result += codec->toUnicode(enc);
00720       lastWasEncodedWord = true;
00721 
00722       ++pos; // eat '?' (for loop eats '=')
00723       LWSP_buffer = 0;
00724     }
00725     continue;
00726   invalid_encoded_word:
00727     // invalid encoding, keep separating LWSP.
00728     pos = beg;
00729     if ( !LWSP_buffer.isNull() )
00730       result += LWSP_buffer;
00731     result += "=?";
00732     lastWasEncodedWord = false;
00733     ++pos; // eat '?' (for loop eats '=')
00734     LWSP_buffer = 0;
00735   }
00736   return result;
00737 }
00738 
00739 
00740 //-----------------------------------------------------------------------------
00741 static const QCString especials = "()<>@,;:\"/[]?.= \033";
00742 
00743 QCString KMMsgBase::encodeRFC2047Quoted( const QCString & s, bool base64 ) {
00744   const char * codecName = base64 ? "b" : "q" ;
00745   const KMime::Codec * codec = KMime::Codec::codecForName( codecName );
00746   kdFatal( !codec, 5006 ) << "No \"" << codecName << "\" found!?" << endl;
00747   QByteArray in; in.setRawData( s.data(), s.length() );
00748   const QByteArray result = codec->encode( in );
00749   in.resetRawData( s.data(), s.length() );
00750   return QCString( result.data(), result.size() + 1 );
00751 }
00752 
00753 QCString KMMsgBase::encodeRFC2047String(const QString& _str,
00754   const QCString& charset)
00755 {
00756   static const QString dontQuote = "\"()<>,@";
00757 
00758   if (_str.isEmpty()) return QCString();
00759   if (charset == "us-ascii") return toUsAscii(_str);
00760 
00761   QCString cset;
00762   if (charset.isEmpty()) cset = QCString(kmkernel->networkCodec()->mimeName()).lower();
00763     else cset = charset;
00764   const QTextCodec *codec = codecForName(cset);
00765   if (!codec) codec = kmkernel->networkCodec();
00766 
00767   unsigned int nonAscii = 0;
00768   for (unsigned int i = 0; i < _str.length(); i++)
00769     if (_str.at(i).unicode() >= 128) nonAscii++;
00770   bool useBase64 = (nonAscii * 6 > _str.length());
00771 
00772   unsigned int start, stop, p, pos = 0, encLength;
00773   QCString result;
00774   bool breakLine = FALSE;
00775   const unsigned int maxLen = 75 - 7 - cset.length();
00776 
00777   while (pos < _str.length())
00778   {
00779     start = pos; p = pos;
00780     while (p < _str.length())
00781     {
00782       if (!breakLine && (_str.at(p) == ' ' || dontQuote.find(_str.at(p)) != -1))
00783         start = p + 1;
00784       if (_str.at(p).unicode() >= 128 || _str.at(p).unicode() < 32)
00785         break;
00786       p++;
00787     }
00788     if (breakLine || p < _str.length())
00789     {
00790       while (dontQuote.find(_str.at(start)) != -1) start++;
00791       stop = start;
00792       while (stop < _str.length() && dontQuote.find(_str.at(stop)) == -1)
00793         stop++;
00794       result += _str.mid(pos, start - pos).latin1();
00795       encLength = encodeRFC2047Quoted(codec->fromUnicode(_str.
00796         mid(start, stop - start)), useBase64).length();
00797       breakLine = (encLength > maxLen);
00798       if (breakLine)
00799       {
00800         int dif = (stop - start) / 2;
00801         int step = dif;
00802         while (abs(step) > 1)
00803         {
00804           encLength = encodeRFC2047Quoted(codec->fromUnicode(_str.
00805             mid(start, dif)), useBase64).length();
00806           step = (encLength > maxLen) ? (-abs(step) / 2) : (abs(step) / 2);
00807           dif += step;
00808         }
00809         stop = start + dif;
00810       }
00811       p = stop;
00812       while (p > start && _str.at(p) != ' ') p--;
00813       if (p > start) stop = p;
00814       if (result.right(3) == "?= ") start--;
00815       if (result.right(5) == "?=\n  ") {
00816         start--; result.truncate(result.length() - 1);
00817       }
00818       int lastNewLine = result.findRev("\n ");
00819       if (!result.mid(lastNewLine).stripWhiteSpace().isEmpty()
00820         && result.length() - lastNewLine + encLength + 2 > maxLen)
00821           result += "\n ";
00822       result += "=?";
00823       result += cset;
00824       result += (useBase64) ? "?b?" : "?q?";
00825       result += encodeRFC2047Quoted(codec->fromUnicode(_str.mid(start,
00826         stop - start)), useBase64);
00827       result += "?=";
00828       if (breakLine) result += "\n ";
00829       pos = stop;
00830     } else {
00831       result += _str.mid(pos).latin1();
00832       break;
00833     }
00834   }
00835   return result;
00836 }
00837 
00838 
00839 //-----------------------------------------------------------------------------
00840 QCString KMMsgBase::encodeRFC2231String( const QString& _str,
00841                                          const QCString& charset )
00842 {
00843   if ( _str.isEmpty() )
00844     return QCString();
00845 
00846   QCString cset;
00847   if ( charset.isEmpty() )
00848     cset = QCString( kmkernel->networkCodec()->mimeName() ).lower();
00849   else
00850     cset = charset;
00851   const QTextCodec *codec = codecForName( cset );
00852   QCString latin;
00853   if ( charset == "us-ascii" )
00854     latin = toUsAscii( _str );
00855   else if ( codec )
00856     latin = codec->fromUnicode( _str );
00857   else
00858     latin = _str.local8Bit();
00859 
00860   char *l;
00861   for ( l = latin.data(); *l; ++l ) {
00862     if ( ( *l & 0xE0 == 0 ) || ( *l & 0x80 ) )
00863       // *l is control character or 8-bit char
00864       break;
00865   }
00866   if ( !*l )
00867     return latin;
00868 
00869   QCString result = cset + "''";
00870   for ( l = latin.data(); *l; ++l ) {
00871     bool needsQuoting = ( *l & 0x80 );
00872     if( !needsQuoting ) {
00873       int len = especials.length();
00874       for ( int i = 0; i < len; i++ )
00875         if ( *l == especials[i] ) {
00876           needsQuoting = true;
00877           break;
00878         }
00879     }
00880     if ( needsQuoting ) {
00881       result += '%';
00882       unsigned char hexcode;
00883       hexcode = ( ( *l & 0xF0 ) >> 4 ) + 48;
00884       if ( hexcode >= 58 )
00885         hexcode += 7;
00886       result += hexcode;
00887       hexcode = ( *l & 0x0F ) + 48;
00888       if ( hexcode >= 58 )
00889         hexcode += 7;
00890       result += hexcode;
00891     } else {
00892       result += *l;
00893     }
00894   }
00895   return result;
00896 }
00897 
00898 
00899 //-----------------------------------------------------------------------------
00900 QString KMMsgBase::decodeRFC2231String(const QCString& _str)
00901 {
00902   int p = _str.find('\'');
00903   if (p < 0) return kmkernel->networkCodec()->toUnicode(_str);
00904 
00905   QCString charset = _str.left(p);
00906 
00907   QCString st = _str.mid(_str.findRev('\'') + 1);
00908   char ch, ch2;
00909   p = 0;
00910   while (p < (int)st.length())
00911   {
00912     if (st.at(p) == 37)
00913     {
00914       ch = st.at(p+1) - 48;
00915       if (ch > 16) ch -= 7;
00916       ch2 = st.at(p+2) - 48;
00917       if (ch2 > 16) ch2 -= 7;
00918       st.at(p) = ch * 16 + ch2;
00919       st.remove( p+1, 2 );
00920     }
00921     p++;
00922   }
00923   QString result;
00924   const QTextCodec * codec = codecForName( charset );
00925   if ( !codec )
00926     codec = kmkernel->networkCodec();
00927   return codec->toUnicode( st );
00928 }
00929 
00930 QCString KMMsgBase::extractRFC2231HeaderField( const QCString &aStr, const QCString &field )
00931 {
00932   int n=-1;
00933   QCString str;
00934   bool found = false;
00935   while ( n<=0 || found ) {
00936     QString pattern( field );
00937     pattern += "[*]"; // match a literal * after the fieldname, as defined by RFC 2231
00938     if ( n>=0 ) { // If n<0, check for fieldname*=..., otherwise for fieldname*n=
00939       pattern += QString::number(n) + "[*]?";
00940     }
00941     pattern += "=";
00942 
00943     QRegExp fnamePart( pattern, FALSE );
00944     int startPart = fnamePart.search( aStr );
00945     int endPart;
00946     found = ( startPart >= 0 );
00947     if ( found ) {
00948       startPart += fnamePart.matchedLength();
00949       // Quoted values end at the ending quote
00950       if ( aStr[startPart] == '"' ) {
00951         startPart++; // the double quote isn't part of the filename
00952         endPart = aStr.find('"', startPart) - 1;
00953       }
00954       else {
00955         endPart = aStr.find(';', startPart) - 1;
00956       }
00957       if (endPart < 0)
00958         endPart = 32767;
00959       str += aStr.mid( startPart, endPart-startPart+1).stripWhiteSpace();
00960     }
00961     n++;
00962   }
00963   return str;
00964 }
00965 
00966 QString KMMsgBase::base64EncodedMD5( const QString & s, bool utf8 ) {
00967   if (s.stripWhiteSpace().isEmpty()) return "";
00968   if ( utf8 )
00969     return base64EncodedMD5( s.stripWhiteSpace().utf8() ); // QCString overload
00970   else
00971     return base64EncodedMD5( s.stripWhiteSpace().latin1() ); // const char * overload
00972 }
00973 
00974 QString KMMsgBase::base64EncodedMD5( const QCString & s ) {
00975   if (s.stripWhiteSpace().isEmpty()) return "";
00976   return base64EncodedMD5( s.stripWhiteSpace().data() );
00977 }
00978 
00979 QString KMMsgBase::base64EncodedMD5( const char * s, int len ) {
00980   if (!s || !len) return "";
00981   static const int Base64EncodedMD5Len = 22;
00982   KMD5 md5( s, len );
00983   return md5.base64Digest().left( Base64EncodedMD5Len );
00984 }
00985 
00986 
00987 //-----------------------------------------------------------------------------
00988 QCString KMMsgBase::autoDetectCharset(const QCString &_encoding, const QStringList &encodingList, const QString &text)
00989 {
00990     QStringList charsets = encodingList;
00991     if (!_encoding.isEmpty())
00992     {
00993        QString currentCharset = QString::fromLatin1(_encoding);
00994        charsets.remove(currentCharset);
00995        charsets.prepend(currentCharset);
00996     }
00997 
00998     QStringList::ConstIterator it = charsets.begin();
00999     for (; it != charsets.end(); ++it)
01000     {
01001        QCString encoding = (*it).latin1();
01002        if (encoding == "locale")
01003           encoding = QCString(kmkernel->networkCodec()->mimeName()).lower();
01004        if (text.isEmpty())
01005          return encoding;
01006        if (encoding == "us-ascii") {
01007          bool ok;
01008          (void) KMMsgBase::toUsAscii(text, &ok);
01009          if (ok)
01010             return encoding;
01011        }
01012        else
01013        {
01014          const QTextCodec *codec = KMMsgBase::codecForName(encoding);
01015          if (!codec) {
01016            kdDebug(5006) << "Auto-Charset: Something is wrong and I can not get a codec. [" << encoding << "]" << endl;
01017          } else {
01018            if (codec->canEncode(text))
01019               return encoding;
01020          }
01021        }
01022     }
01023     return 0;
01024 }
01025 
01026 
01027 //-----------------------------------------------------------------------------
01028 unsigned long KMMsgBase::getMsgSerNum() const
01029 {
01030   unsigned long msn = MessageProperty::serialCache( this );
01031   if (msn)
01032     return msn;
01033   if (mParent) {
01034     int index = mParent->find((KMMsgBase*)this);
01035     msn = kmkernel->msgDict()->getMsgSerNum(mParent, index);
01036     if (msn)
01037       MessageProperty::setSerialCache( this, msn );
01038   }
01039   return msn;
01040 }
01041 
01042 
01043 //-----------------------------------------------------------------------------
01044 bool KMMsgBase::readyToShow()
01045 {
01046   return MessageProperty::readyToShow( getMsgSerNum() );
01047 }
01048 
01049 
01050 //-----------------------------------------------------------------------------
01051 void KMMsgBase::setReadyToShow(bool value)
01052 {
01053   MessageProperty::setReadyToShow( getMsgSerNum(), value );
01054 }
01055 
01056 
01057 //-----------------------------------------------------------------------------
01058 bool KMMsgBase::transferInProgress()
01059 {
01060   return MessageProperty::transferInProgress( getMsgSerNum() );
01061 }
01062 
01063 
01064 //-----------------------------------------------------------------------------
01065 void KMMsgBase::setTransferInProgress(bool value, bool force)
01066 {
01067   MessageProperty::setTransferInProgress( getMsgSerNum(), value, force );
01068 }
01069 
01070 
01071 //-----------------------------------------------------------------------------
01072 KMMsgAttachmentState KMMsgBase::attachmentState() const
01073 {
01074   KMMsgStatus st = status();
01075   if (st & KMMsgStatusHasAttach)
01076     return KMMsgHasAttachment;
01077   else if (st & KMMsgStatusHasNoAttach)
01078     return KMMsgHasNoAttachment;
01079   else
01080     return KMMsgAttachmentUnknown;
01081 }
01082 
01083 //-----------------------------------------------------------------------------
01084 static void swapEndian(QString &str)
01085 {
01086   uint len = str.length();
01087   str = QDeepCopy<QString>(str);
01088   QChar *unicode = const_cast<QChar*>( str.unicode() );
01089   for (uint i = 0; i < len; i++)
01090     unicode[i] = kmail_swap_16(unicode[i].unicode());
01091 }
01092 
01093 //-----------------------------------------------------------------------------
01094 static int g_chunk_length = 0, g_chunk_offset=0;
01095 static uchar *g_chunk = 0;
01096 
01097 namespace {
01098   template < typename T > void copy_from_stream( T & x ) {
01099     if( g_chunk_offset + int(sizeof(T)) > g_chunk_length ) {
01100       g_chunk_offset = g_chunk_length;
01101       kdDebug( 5006 ) << "This should never happen.. "
01102               << __FILE__ << ":" << __LINE__ << endl;
01103       x = 0;
01104     } else {
01105       // the memcpy is optimized out by the compiler for the values
01106       // of sizeof(T) that is called with
01107       memcpy( &x, g_chunk + g_chunk_offset, sizeof(T) );
01108       g_chunk_offset += sizeof(T);
01109     }
01110   }
01111 }
01112 
01113 //-----------------------------------------------------------------------------
01114 QString KMMsgBase::getStringPart(MsgPartType t) const
01115 {
01116   QString ret;
01117 
01118   g_chunk_offset = 0;
01119   bool using_mmap = FALSE;
01120   bool swapByteOrder = storage()->indexSwapByteOrder();
01121   if (storage()->indexStreamBasePtr()) {
01122     if (g_chunk)
01123     free(g_chunk);
01124     using_mmap = TRUE;
01125     g_chunk = storage()->indexStreamBasePtr() + mIndexOffset;
01126     g_chunk_length = mIndexLength;
01127   } else {
01128     if(!storage()->mIndexStream)
01129       return ret;
01130     if (g_chunk_length < mIndexLength)
01131     g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength);
01132     off_t first_off=ftell(storage()->mIndexStream);
01133     fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01134     fread( g_chunk, mIndexLength, 1, storage()->mIndexStream);
01135     fseek(storage()->mIndexStream, first_off, SEEK_SET);
01136   }
01137 
01138   MsgPartType type;
01139   Q_UINT16 l;
01140   while(g_chunk_offset < mIndexLength) {
01141     Q_UINT32 tmp;
01142     copy_from_stream(tmp);
01143     copy_from_stream(l);
01144     if (swapByteOrder)
01145     {
01146        tmp = kmail_swap_32(tmp);
01147        l = kmail_swap_16(l);
01148     }
01149     type = (MsgPartType) tmp;
01150     if(g_chunk_offset + l > mIndexLength) {
01151     kdDebug(5006) << "This should never happen.. " << __FILE__ << ":" << __LINE__ << endl;
01152     break;
01153     }
01154     if(type == t) {
01155         // This works because the QString constructor does a memcpy.
01156         // Otherwise we would need to be concerned about the alignment.
01157     if(l)
01158         ret = QString((QChar *)(g_chunk + g_chunk_offset), l/2);
01159     break;
01160     }
01161     g_chunk_offset += l;
01162   }
01163   if(using_mmap) {
01164       g_chunk_length = 0;
01165       g_chunk = 0;
01166   }
01167   // Normally we need to swap the byte order because the QStrings are written
01168   // in the style of Qt2 (MSB -> network ordered).
01169   // QStrings in Qt3 expect host ordering.
01170   // On e.g. Intel host ordering is LSB, on e.g. Sparc it is MSB.
01171 
01172 #ifndef WORDS_BIGENDIAN
01173   // #warning Byte order is little endian (swap is true)
01174   swapEndian(ret);
01175 #else
01176   // #warning Byte order is big endian (swap is false)
01177 #endif
01178 
01179   return ret;
01180 }
01181 
01182 //-----------------------------------------------------------------------------
01183 off_t KMMsgBase::getLongPart(MsgPartType t) const
01184 {
01185   off_t ret = 0;
01186 
01187   g_chunk_offset = 0;
01188   bool using_mmap = FALSE;
01189   int sizeOfLong = storage()->indexSizeOfLong();
01190   bool swapByteOrder = storage()->indexSwapByteOrder();
01191   if (storage()->indexStreamBasePtr()) {
01192     if (g_chunk)
01193       free(g_chunk);
01194     using_mmap = TRUE;
01195     g_chunk = storage()->indexStreamBasePtr() + mIndexOffset;
01196     g_chunk_length = mIndexLength;
01197   } else {
01198     if (!storage()->mIndexStream)
01199       return ret;
01200     assert(mIndexLength >= 0);
01201     if (g_chunk_length < mIndexLength)
01202       g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength);
01203     off_t first_off=ftell(storage()->mIndexStream);
01204     fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01205     fread( g_chunk, mIndexLength, 1, storage()->mIndexStream);
01206     fseek(storage()->mIndexStream, first_off, SEEK_SET);
01207   }
01208 
01209   MsgPartType type;
01210   Q_UINT16 l;
01211   while (g_chunk_offset < mIndexLength) {
01212     Q_UINT32 tmp;
01213     copy_from_stream(tmp);
01214     copy_from_stream(l);
01215     if (swapByteOrder)
01216     {
01217        tmp = kmail_swap_32(tmp);
01218        l = kmail_swap_16(l);
01219     }
01220     type = (MsgPartType) tmp;
01221 
01222     if (g_chunk_offset + l > mIndexLength) {
01223       kdDebug(5006) << "This should never happen.. " << __FILE__ << ":" << __LINE__ << endl;
01224       break;
01225     }
01226     if(type == t) {
01227       assert(sizeOfLong == l);
01228       if (sizeOfLong == sizeof(ret))
01229       {
01230      copy_from_stream(ret);
01231          if (swapByteOrder)
01232          {
01233             if (sizeof(ret) == 4)
01234                ret = kmail_swap_32(ret);
01235             else
01236                ret = kmail_swap_64(ret);
01237          }
01238       }
01239       else if (sizeOfLong == 4)
01240       {
01241          // Long is stored as 4 bytes in index file, sizeof(long) = 8
01242          Q_UINT32 ret_32;
01243          copy_from_stream(ret_32);
01244          if (swapByteOrder)
01245             ret_32 = kmail_swap_32(ret_32);
01246          ret = ret_32;
01247       }
01248       else if (sizeOfLong == 8)
01249       {
01250          // Long is stored as 8 bytes in index file, sizeof(long) = 4
01251          Q_UINT32 ret_1;
01252          Q_UINT32 ret_2;
01253          copy_from_stream(ret_1);
01254          copy_from_stream(ret_2);
01255          if (!swapByteOrder)
01256          {
01257             // Index file order is the same as the order of this CPU.
01258 #ifndef WORDS_BIGENDIAN
01259             // Index file order is little endian
01260             ret = ret_1; // We drop the 4 most significant bytes
01261 #else
01262             // Index file order is big endian
01263             ret = ret_2; // We drop the 4 most significant bytes
01264 #endif
01265          }
01266          else
01267          {
01268             // Index file order is different from this CPU.
01269 #ifndef WORDS_BIGENDIAN
01270             // Index file order is big endian
01271             ret = ret_2; // We drop the 4 most significant bytes
01272 #else
01273             // Index file order is little endian
01274             ret = ret_1; // We drop the 4 most significant bytes
01275 #endif
01276             // We swap the result to host order.
01277             ret = kmail_swap_32(ret);
01278          }
01279 
01280       }
01281       break;
01282     }
01283     g_chunk_offset += l;
01284   }
01285   if(using_mmap) {
01286     g_chunk_length = 0;
01287     g_chunk = 0;
01288   }
01289   return ret;
01290 }
01291 
01292 #ifndef WORDS_BIGENDIAN
01293 // We need to use swab to swap bytes to network byte order
01294 #define memcpy_networkorder(to, from, len)  swab((char *)(from), (char *)(to), len)
01295 #else
01296 // We're already in network byte order
01297 #define memcpy_networkorder(to, from, len)  memcpy(to, from, len)
01298 #endif
01299 
01300 #define STORE_DATA_LEN(type, x, len, network_order) do { \
01301     int len2 = (len > 256) ? 256 : len; \
01302     if(csize < (length + (len2 + sizeof(short) + sizeof(MsgPartType)))) \
01303            ret = (uchar *)realloc(ret, csize += len2+sizeof(short)+sizeof(MsgPartType)); \
01304         Q_UINT32 t = (Q_UINT32) type; memcpy(ret+length, &t, sizeof(t)); \
01305         Q_UINT16 l = len2; memcpy(ret+length+sizeof(t), &l, sizeof(l)); \
01306         if (network_order) \
01307            memcpy_networkorder(ret+length+sizeof(t)+sizeof(l), x, len2); \
01308         else \
01309            memcpy(ret+length+sizeof(t)+sizeof(l), x, len2); \
01310         length += len2+sizeof(t)+sizeof(l); \
01311     } while(0)
01312 #define STORE_DATA(type, x) STORE_DATA_LEN(type, &x, sizeof(x), false)
01313 
01314 //-----------------------------------------------------------------------------
01315 const uchar *KMMsgBase::asIndexString(int &length) const
01316 {
01317   unsigned int csize = 256;
01318   static uchar *ret = 0; //different static buffer here for we may use the other buffer in the functions below
01319   if(!ret)
01320     ret = (uchar *)malloc(csize);
01321   length = 0;
01322 
01323   unsigned long tmp;
01324   QString tmp_str;
01325 
01326   //these is at the beginning because it is queried quite often
01327   tmp_str = msgIdMD5().stripWhiteSpace();
01328   STORE_DATA_LEN(MsgIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01329   tmp = mLegacyStatus;
01330   STORE_DATA(MsgLegacyStatusPart, tmp);
01331 
01332   //these are completely arbitrary order
01333   tmp_str = fromStrip().stripWhiteSpace();
01334   STORE_DATA_LEN(MsgFromPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01335   tmp_str = subject().stripWhiteSpace();
01336   STORE_DATA_LEN(MsgSubjectPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01337   tmp_str = toStrip().stripWhiteSpace();
01338   STORE_DATA_LEN(MsgToPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01339   tmp_str = replyToIdMD5().stripWhiteSpace();
01340   STORE_DATA_LEN(MsgReplyToIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01341   tmp_str = xmark().stripWhiteSpace();
01342   STORE_DATA_LEN(MsgXMarkPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01343   tmp_str = fileName().stripWhiteSpace();
01344   STORE_DATA_LEN(MsgFilePart, tmp_str.unicode(), tmp_str.length() * 2, true);
01345   tmp = msgSize();
01346   STORE_DATA(MsgSizePart, tmp);
01347   tmp = folderOffset();
01348   STORE_DATA(MsgOffsetPart, tmp);
01349   tmp = date();
01350   STORE_DATA(MsgDatePart, tmp);
01351   tmp = (signatureState() << 16) | encryptionState();
01352   STORE_DATA(MsgCryptoStatePart, tmp);
01353   tmp = mdnSentState();
01354   STORE_DATA(MsgMDNSentPart, tmp);
01355 
01356   tmp_str = replyToAuxIdMD5().stripWhiteSpace();
01357   STORE_DATA_LEN(MsgReplyToAuxIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01358 
01359   tmp_str = strippedSubjectMD5().stripWhiteSpace();
01360   STORE_DATA_LEN(MsgStrippedSubjectMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01361 
01362   tmp = status();
01363   STORE_DATA(MsgStatusPart, tmp);
01364 
01365   tmp = msgSizeServer();
01366   STORE_DATA(MsgSizeServerPart, tmp);
01367   tmp = UID();
01368   STORE_DATA(MsgUIDPart, tmp);
01369 
01370   return ret;
01371 }
01372 #undef STORE_DATA_LEN
01373 #undef STORE_DATA
01374 
01375 bool KMMsgBase::syncIndexString() const
01376 {
01377   if(!dirty())
01378     return TRUE;
01379   int len;
01380   const uchar *buffer = asIndexString(len);
01381   if (len == mIndexLength) {
01382     Q_ASSERT(storage()->mIndexStream);
01383     fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01384     assert( mIndexOffset > 0 );
01385     fwrite( buffer, len, 1, storage()->mIndexStream);
01386     return TRUE;
01387   }
01388   return FALSE;
01389 }
01390 
01391 static QStringList sReplySubjPrefixes, sForwardSubjPrefixes;
01392 static bool sReplaceSubjPrefix, sReplaceForwSubjPrefix;
01393 
01394 //-----------------------------------------------------------------------------
01395 void KMMsgBase::readConfig()
01396 {
01397   KConfigGroup composerGroup( KMKernel::config(), "Composer" );
01398   sReplySubjPrefixes = composerGroup.readListEntry("reply-prefixes", ',');
01399   if (sReplySubjPrefixes.isEmpty())
01400     sReplySubjPrefixes << "Re\\s*:" << "Re\\[\\d+\\]:" << "Re\\d+:";
01401   sReplaceSubjPrefix = composerGroup.readBoolEntry("replace-reply-prefix", true);
01402   sForwardSubjPrefixes = composerGroup.readListEntry("forward-prefixes", ',');
01403   if (sForwardSubjPrefixes.isEmpty())
01404     sForwardSubjPrefixes << "Fwd:" << "FW:";
01405   sReplaceForwSubjPrefix = composerGroup.readBoolEntry("replace-forward-prefix", true);
01406 }
01407 
01408 //-----------------------------------------------------------------------------
01409 // static
01410 QString KMMsgBase::stripOffPrefixes( const QString& str )
01411 {
01412   return replacePrefixes( str, sReplySubjPrefixes + sForwardSubjPrefixes,
01413                           true, QString::null ).stripWhiteSpace();
01414 }
01415 
01416 //-----------------------------------------------------------------------------
01417 // static
01418 QString KMMsgBase::replacePrefixes( const QString& str,
01419                                     const QStringList& prefixRegExps,
01420                                     bool replace,
01421                                     const QString& newPrefix )
01422 {
01423   bool recognized = false;
01424   // construct a big regexp that
01425   // 1. is anchored to the beginning of str (sans whitespace)
01426   // 2. matches at least one of the part regexps in prefixRegExps
01427   QString bigRegExp = QString::fromLatin1("^(?:\\s+|(?:%1))+\\s*")
01428                       .arg( prefixRegExps.join(")|(?:") );
01429   QRegExp rx( bigRegExp, false /*case insens.*/ );
01430   if ( !rx.isValid() ) {
01431     kdWarning(5006) << "KMMessage::replacePrefixes(): bigRegExp = \""
01432                     << bigRegExp << "\"\n"
01433                     << "prefix regexp is invalid!" << endl;
01434     // try good ole Re/Fwd:
01435     recognized = str.startsWith( newPrefix );
01436   } else { // valid rx
01437     QString tmp = str;
01438     if ( rx.search( tmp ) == 0 ) {
01439       recognized = true;
01440       if ( replace )
01441     return tmp.replace( 0, rx.matchedLength(), newPrefix + ' ' );
01442     }
01443   }
01444   if ( !recognized )
01445     return newPrefix + ' ' + str;
01446   else
01447     return str;
01448 }
01449 
01450 //-----------------------------------------------------------------------------
01451 QString KMMsgBase::cleanSubject() const
01452 {
01453   return cleanSubject( sReplySubjPrefixes + sForwardSubjPrefixes,
01454                true, QString::null ).stripWhiteSpace();
01455 }
01456 
01457 //-----------------------------------------------------------------------------
01458 QString KMMsgBase::cleanSubject( const QStringList & prefixRegExps,
01459                                  bool replace,
01460                                  const QString & newPrefix ) const
01461 {
01462   return KMMsgBase::replacePrefixes( subject(), prefixRegExps, replace,
01463                                      newPrefix );
01464 }
01465 
01466 //-----------------------------------------------------------------------------
01467 QString KMMsgBase::forwardSubject() const {
01468   return cleanSubject( sForwardSubjPrefixes, sReplaceForwSubjPrefix, "Fwd:" );
01469 }
01470 
01471 //-----------------------------------------------------------------------------
01472 QString KMMsgBase::replySubject() const {
01473   return cleanSubject( sReplySubjPrefixes, sReplaceSubjPrefix, "Re:" );
01474 }
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Dec 21 14:25:00 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003