// kmmsginfo.cpp

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmmsginfo.h"
#include "kmmessage.h"
//#include "kmmsgpart.h" // for encode

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <mimelib/datetime.h>

class KMMsgInfo::KMMsgInfoPrivate
{
public:
    enum {
        SUBJECT_SET = 0x01, TOSTRIP_SET = 0x02, REPLYTO_SET = 0x04, MSGID_SET=0x08,
        DATE_SET = 0x10, OFFSET_SET = 0x20, SIZE_SET = 0x40, SIZESERVER_SET = 0x80,
        XMARK_SET=0x100, FROMSTRIP_SET=0x200, FILE_SET=0x400, ENCRYPTION_SET=0x800,
        SIGNATURE_SET=0x1000, MDN_SET=0x2000, REPLYTOAUX_SET = 0x4000,
        STRIPPEDSUBJECT_SET = 0x8000,  UID_SET = 0x10000,
        TO_SET = 0x20000, FROM_SET = 0x40000,

        ALL_SET = 0xFFFFFF, NONE_SET = 0x000000
    };
    uint modifiers;
    TQString subject, fromStrip, toStrip, replyToIdMD5, replyToAuxIdMD5,
            strippedSubjectMD5, msgIdMD5, xmark, file;
    off_t folderOffset;
    size_t msgSize, msgSizeServer;
    time_t date;
    KMMsgEncryptionState encryptionState;
    KMMsgSignatureState signatureState;
    KMMsgMDNSentState mdnSentState;
    ulong UID;
    TQString to, from;

    KMMsgInfoPrivate() : modifiers(NONE_SET) { }
    KMMsgInfoPrivate& operator=(const KMMsgInfoPrivate& other) {
        modifiers = NONE_SET;
        if (other.modifiers & SUBJECT_SET) {
            modifiers |= SUBJECT_SET;
            subject = other.subject;
        }
        if (other.modifiers & STRIPPEDSUBJECT_SET) {
            modifiers |= STRIPPEDSUBJECT_SET;
            strippedSubjectMD5 = other.strippedSubjectMD5;
        }
        if (other.modifiers & FROMSTRIP_SET) {
            modifiers |= FROMSTRIP_SET;
            fromStrip = other.fromStrip;
        }
        if (other.modifiers & FILE_SET) {
            modifiers |= FILE_SET;
            file = other.file;
        }
        if (other.modifiers & TOSTRIP_SET) {
            modifiers |= TOSTRIP_SET;
            toStrip = other.toStrip;
        }
        if (other.modifiers & REPLYTO_SET) {
            modifiers |= REPLYTO_SET;
            replyToIdMD5 = other.replyToIdMD5;
        }
        if (other.modifiers & REPLYTOAUX_SET) {
            modifiers |= REPLYTOAUX_SET;
            replyToAuxIdMD5 = other.replyToAuxIdMD5;
        }

        if(other.modifiers & MSGID_SET) {
            modifiers |= MSGID_SET;
            msgIdMD5 = other.msgIdMD5;
        }
        if(other.modifiers & XMARK_SET) {
            modifiers |= XMARK_SET;
            xmark = other.xmark;
        }
        if(other.modifiers & OFFSET_SET) {
            modifiers |= OFFSET_SET;
            folderOffset = other.folderOffset;
        }
        if(other.modifiers & SIZE_SET) {
            modifiers |= SIZE_SET;
            msgSize = other.msgSize;
        }
        if(other.modifiers & DATE_SET) {
            modifiers |= DATE_SET;
            date = other.date;
        }
        if(other.modifiers & ENCRYPTION_SET) {
            modifiers |= ENCRYPTION_SET;
            encryptionState = other.encryptionState;
        }
        if(other.modifiers & SIGNATURE_SET) {
            modifiers |= SIGNATURE_SET;
            signatureState = other.signatureState;
        }
        if(other.modifiers & MDN_SET) {
            modifiers |= MDN_SET;
            mdnSentState = other.mdnSentState;
        }
        if(other.modifiers & SIZESERVER_SET) {
            modifiers |= SIZESERVER_SET;
            msgSizeServer = other.msgSizeServer;
        }
        if(other.modifiers & UID_SET) {
            modifiers |= UID_SET;
            UID = other.UID;
        }
        if (other.modifiers & TO_SET) {
            modifiers |= TO_SET;
            to = other.to;
        }
        if (other.modifiers & FROM_SET) {
            modifiers |= FROM_SET;
            from = other.from;
        }
        return *this;
    }
};

//-----------------------------------------------------------------------------
KMMsgInfo::KMMsgInfo(KMFolder* p, off_t off, short len) :
    KMMsgBase(p),
    kd(0)
{
    setIndexOffset(off);
    setIndexLength(len);
    setEnableUndo(true);
}


//-----------------------------------------------------------------------------
KMMsgInfo::~KMMsgInfo()
{
    delete kd;
}


#if 0 // currently unused
//-----------------------------------------------------------------------------
KMMsgInfo& KMMsgInfo::operator=(const KMMsgInfo& other)
{
    KMMsgBase::assign(&other);
    if(other.kd) {
        if(!kd)
            kd = new KMMsgInfoPrivate;
        *kd = *other.kd;
    } else {
        delete kd;
        kd = 0;
    }
    mStatus = other.status();
    return *this;
}
#endif

//-----------------------------------------------------------------------------
KMMsgInfo& KMMsgInfo::operator=(const KMMessage& msg)
{
    KMMsgBase::assign(&msg.toMsgBase());
    if(!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers = KMMsgInfoPrivate::ALL_SET;
    kd->subject = msg.subject();
    kd->fromStrip = msg.fromStrip();
    kd->toStrip = msg.toStrip();
    kd->replyToIdMD5 = msg.replyToIdMD5();
    kd->replyToAuxIdMD5 = msg.replyToAuxIdMD5();
    kd->strippedSubjectMD5 = msg.strippedSubjectMD5();
    kd->msgIdMD5 = msg.msgIdMD5();
    kd->xmark = msg.xmark();
    mStatus = msg.status();
    kd->folderOffset = msg.folderOffset();
    kd->msgSize = msg.msgSize();
    kd->date = msg.date();
    kd->file = msg.fileName();
    kd->encryptionState = msg.encryptionState();
    kd->signatureState = msg.signatureState();
    kd->mdnSentState = msg.mdnSentState();
    kd->msgSizeServer = msg.msgSizeServer();
    kd->UID = msg.UID();
    kd->to = msg.to();
    kd->from = msg.from();
    return *this;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::init(const TQCString& aSubject, const TQCString& aFrom,
                     const TQCString& aTo, time_t aDate,
                     KMMsgStatus aStatus, const TQCString& aXMark,
                     const TQCString& replyToId, const TQCString& replyToAuxId,
                     const TQCString& msgId,
                     KMMsgEncryptionState encryptionState,
                     KMMsgSignatureState signatureState,
                     KMMsgMDNSentState mdnSentState,
                     const TQCString& prefCharset,
                     off_t aFolderOffset, size_t aMsgSize,
                     size_t aMsgSizeServer, ulong aUID)
{
    mIndexOffset = 0;
    mIndexLength = 0;
    if(!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers = KMMsgInfoPrivate::ALL_SET;
    kd->subject = decodeRFC2047String(aSubject, prefCharset);
    kd->fromStrip = decodeRFC2047String( KMMessage::stripEmailAddr( aFrom ), prefCharset );
    kd->toStrip = decodeRFC2047String( KMMessage::stripEmailAddr( aTo ), prefCharset );
    kd->replyToIdMD5 = base64EncodedMD5( replyToId );
    kd->replyToAuxIdMD5 = base64EncodedMD5( replyToAuxId );
    kd->strippedSubjectMD5 = base64EncodedMD5( KMMessage::stripOffPrefixes( kd->subject ), true /*utf8*/ );
    kd->msgIdMD5 = base64EncodedMD5( msgId );
    kd->xmark = aXMark;
    kd->folderOffset = aFolderOffset;
    mStatus    = aStatus;
    kd->msgSize = aMsgSize;
    kd->date = aDate;
    kd->file = "";
    kd->encryptionState = encryptionState;
    kd->signatureState = signatureState;
    kd->mdnSentState = mdnSentState;
    kd->msgSizeServer = aMsgSizeServer;
    kd->UID = aUID;
    kd->to = aTo;
    kd->from = aFrom;
    mDirty = false;
}

void KMMsgInfo::init(const TQCString& aSubject, const TQCString& aFrom,
                     const TQCString& aTo, time_t aDate,
                     KMMsgStatus aStatus, const TQCString& aXMark,
                     const TQCString& replyToId, const TQCString& replyToAuxId,
                     const TQCString& msgId,
                     const TQCString& aFileName,
                     KMMsgEncryptionState encryptionState,
                     KMMsgSignatureState signatureState,
                     KMMsgMDNSentState mdnSentState,
                     const TQCString& prefCharset,
                     size_t aMsgSize,
             size_t aMsgSizeServer, ulong aUID)
{
  // use the "normal" init for most stuff
  init( aSubject, aFrom, aTo, aDate, aStatus, aXMark, replyToId, replyToAuxId,
        msgId, encryptionState, signatureState, mdnSentState, prefCharset,
        (unsigned long)0, aMsgSize, aMsgSizeServer, aUID );
  kd->file = aFileName;
}


//-----------------------------------------------------------------------------
TQString KMMsgInfo::subject(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::SUBJECT_SET)
        return kd->subject;
    return getStringPart(MsgSubjectPart);
}

//-----------------------------------------------------------------------------
TQString KMMsgInfo::fromStrip(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::FROMSTRIP_SET)
        return kd->fromStrip;
    return getStringPart(MsgFromStripPart);
}

//-----------------------------------------------------------------------------
TQString KMMsgInfo::from() const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::FROM_SET)
        return kd->from;
    return getStringPart( MsgFromPart );
}


//-----------------------------------------------------------------------------
TQString KMMsgInfo::fileName(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::FILE_SET)
        return kd->file;
    return getStringPart(MsgFilePart);
}


//-----------------------------------------------------------------------------
TQString KMMsgInfo::toStrip(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::TOSTRIP_SET)
        return kd->toStrip;
    return getStringPart(MsgToStripPart);
}

//-----------------------------------------------------------------------------
TQString KMMsgInfo::to() const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::TO_SET)
        return kd->to;
    return getStringPart( MsgToPart );
}

//-----------------------------------------------------------------------------
TQString KMMsgInfo::xmark(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::XMARK_SET)
        return kd->xmark;
    return getStringPart(MsgXMarkPart);
}


//-----------------------------------------------------------------------------
TQString KMMsgInfo::replyToIdMD5(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::REPLYTO_SET)
        return kd->replyToIdMD5;
    return getStringPart(MsgReplyToIdMD5Part);
}

//-----------------------------------------------------------------------------
TQString KMMsgInfo::replyToAuxIdMD5() const
{
    if( kd && kd->modifiers & KMMsgInfoPrivate::REPLYTOAUX_SET )
        return kd->replyToAuxIdMD5;
    return getStringPart( MsgReplyToAuxIdMD5Part );
}

//-----------------------------------------------------------------------------
TQString KMMsgInfo::strippedSubjectMD5() const
{
    if( kd && kd->modifiers & KMMsgInfoPrivate::STRIPPEDSUBJECT_SET )
        return kd->strippedSubjectMD5;
    return getStringPart( MsgStrippedSubjectMD5Part );
}


//-----------------------------------------------------------------------------
bool KMMsgInfo::subjectIsPrefixed() const
{
    return strippedSubjectMD5() != base64EncodedMD5( subject().stripWhiteSpace(), true /*utf8*/ );
}

//-----------------------------------------------------------------------------
TQString KMMsgInfo::msgIdMD5(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::MSGID_SET)
        return kd->msgIdMD5;
    return getStringPart(MsgIdMD5Part);
}


//-----------------------------------------------------------------------------
void KMMsgInfo::setSubject(const TQString& aSubject)
{
    if(aSubject == subject())
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::SUBJECT_SET;
    kd->subject = aSubject;
    mDirty = true;
}


//-----------------------------------------------------------------------------
void KMMsgInfo::setXMark(const TQString& aXMark)
{
    if (aXMark == xmark())
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::XMARK_SET;
    kd->xmark = aXMark;
    mDirty = true;
}


//-----------------------------------------------------------------------------
void KMMsgInfo::setReplyToIdMD5(const TQString& aReplyToIdMD5)
{
    if (aReplyToIdMD5 == replyToIdMD5())
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::REPLYTO_SET;
    kd->replyToIdMD5 = aReplyToIdMD5;
    mDirty = true;
}


//-----------------------------------------------------------------------------
void KMMsgInfo::setReplyToAuxIdMD5( const TQString& aReplyToAuxIdMD5 )
{
    if( aReplyToAuxIdMD5 == replyToAuxIdMD5() )
        return;

    if( !kd )
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::REPLYTOAUX_SET;
    kd->replyToAuxIdMD5 = aReplyToAuxIdMD5;
    mDirty = true;
}


//-----------------------------------------------------------------------------
void KMMsgInfo::initStrippedSubjectMD5()
{
    if( kd && kd->modifiers & KMMsgInfoPrivate::STRIPPEDSUBJECT_SET )
        return;
    TQString rawSubject = KMMessage::stripOffPrefixes( subject() );
    TQString subjectMD5 = base64EncodedMD5( rawSubject, true /*utf8*/ );
    if( !kd )
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::STRIPPEDSUBJECT_SET;
    kd->strippedSubjectMD5 = subjectMD5;
    mDirty = true;
}


//-----------------------------------------------------------------------------
void KMMsgInfo::setMsgIdMD5(const TQString& aMsgIdMD5)
{
    if (aMsgIdMD5 == msgIdMD5())
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::MSGID_SET;
    kd->msgIdMD5 = aMsgIdMD5;
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setEncryptionState( const KMMsgEncryptionState s, int idx )
{
    if (s == encryptionState())
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::ENCRYPTION_SET;
    kd->encryptionState = s;
    KMMsgBase::setEncryptionState(s, idx); //base does more "stuff"
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setSignatureState( const KMMsgSignatureState s, int idx )
{
    if (s == signatureState())
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::SIGNATURE_SET;
    kd->signatureState = s;
    KMMsgBase::setSignatureState(s, idx); //base does more "stuff"
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setMDNSentState( const KMMsgMDNSentState s, int idx )
{
    if (s == mdnSentState())
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::MDN_SET;
    kd->mdnSentState = s;
    KMMsgBase::setMDNSentState(s, idx); //base does more "stuff"
    mDirty = true;
}

//-----------------------------------------------------------------------------
KMMsgStatus KMMsgInfo::status(void) const
{
    if (mStatus == KMMsgStatusUnknown) {
        KMMsgStatus st = (KMMsgStatus)getLongPart(MsgStatusPart);
        if (!st) {
            // We are opening an old index for the first time, get the legacy
            // status and merge it in.
            mLegacyStatus = (KMLegacyMsgStatus)getLongPart(MsgLegacyStatusPart);
            st = KMMsgStatusRead;
            switch (mLegacyStatus) {
                case KMLegacyMsgStatusUnknown:
                    st = KMMsgStatusUnknown;
                    break;
                case KMLegacyMsgStatusNew:
                    st = KMMsgStatusNew;
                    break;
                case KMLegacyMsgStatusUnread:
                    st = KMMsgStatusUnread;
                    break;
                case KMLegacyMsgStatusRead:
                    st = KMMsgStatusRead;
                    break;
                case KMLegacyMsgStatusOld:
                    st = KMMsgStatusOld;
                    break;
                case KMLegacyMsgStatusDeleted:
                    st |= KMMsgStatusDeleted;
                    break;
                case KMLegacyMsgStatusReplied:
                    st |= KMMsgStatusReplied;
                    break;
                case KMLegacyMsgStatusForwarded:
                    st |= KMMsgStatusForwarded;
                    break;
                case KMLegacyMsgStatusQueued:
                    st |= KMMsgStatusQueued;
                    break;
                case KMLegacyMsgStatusSent:
                    st |= KMMsgStatusSent;
                    break;
                case KMLegacyMsgStatusFlag:
                    st |= KMMsgStatusFlag;
                    break;
                default:
                    break;
            }

        }
        mStatus = st;
    }
    return mStatus;
}


//-----------------------------------------------------------------------------
KMMsgEncryptionState KMMsgInfo::encryptionState() const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::ENCRYPTION_SET)
      return kd->encryptionState;
    unsigned long encState = getLongPart(MsgCryptoStatePart) & 0x0000FFFF;
    return encState ? (KMMsgEncryptionState)encState : KMMsgEncryptionStateUnknown;
}


KMMsgSignatureState KMMsgInfo::signatureState() const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::SIGNATURE_SET)
      return kd->signatureState;
    unsigned long sigState = getLongPart(MsgCryptoStatePart) >> 16;
    return sigState ? (KMMsgSignatureState)sigState : KMMsgSignatureStateUnknown;
}

KMMsgMDNSentState KMMsgInfo::mdnSentState() const {
    if (kd && kd->modifiers & KMMsgInfoPrivate::MDN_SET)
      return kd->mdnSentState;
    unsigned long mdnState = getLongPart(MsgMDNSentPart);
    return mdnState ? (KMMsgMDNSentState)mdnState : KMMsgMDNStateUnknown;
}


//-----------------------------------------------------------------------------
off_t KMMsgInfo::folderOffset(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::OFFSET_SET)
        return kd->folderOffset;
    return getLongPart(MsgOffsetPart);
}

//-----------------------------------------------------------------------------
size_t KMMsgInfo::msgSize(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::SIZE_SET)
        return kd->msgSize;
    return getLongPart(MsgSizePart);
}

//-----------------------------------------------------------------------------
time_t KMMsgInfo::date(void) const
{
    time_t res;
    if (kd && kd->modifiers & KMMsgInfoPrivate::DATE_SET)
      res = kd->date;
    else
      res = getLongPart(MsgDatePart);
    return res;
}

//-----------------------------------------------------------------------------
size_t KMMsgInfo::msgSizeServer(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::SIZESERVER_SET)
      return kd->msgSizeServer;
    return getLongPart(MsgSizeServerPart);
}

//-----------------------------------------------------------------------------
ulong KMMsgInfo::UID(void) const
{
    if (kd && kd->modifiers & KMMsgInfoPrivate::UID_SET)
      return kd->UID;
    return getLongPart(MsgUIDPart);
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setMsgSize(size_t sz)
{
    if (sz == msgSize())
        return;

    if(!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::SIZE_SET;
    kd->msgSize = sz;
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setMsgSizeServer(size_t sz)
{
    if (sz == msgSizeServer())
      return;

    if(!kd)
      kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::SIZESERVER_SET;
    kd->msgSizeServer = sz;
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setUID(ulong uid)
{
    if (uid == UID())
      return;

    if(!kd)
      kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::UID_SET;
    kd->UID = uid;
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setFolderOffset(off_t offs)
{
    if (folderOffset() == offs)
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::OFFSET_SET;
    kd->folderOffset = offs;
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setFileName(const TQString& file)
{
    if (fileName() == file)
        return;

    if (!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::FILE_SET;
    kd->file = file;
    mDirty = true;
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setStatus(const KMMsgStatus aStatus, int idx)
{
    if(aStatus == status())
        return;
    KMMsgBase::setStatus(aStatus, idx); //base does more "stuff"
}

//-----------------------------------------------------------------------------
void KMMsgInfo::setDate(time_t aUnixTime)
{
    if(aUnixTime == date())
        return;

    if(!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers |= KMMsgInfoPrivate::DATE_SET;
    kd->date = aUnixTime;
    mDirty = true;
}

void KMMsgInfo::setFrom( const TQString &from )
{
  if ( !kd )
    kd = new KMMsgInfoPrivate;
  kd->modifiers |= KMMsgInfoPrivate::FROM_SET;
  kd->from = from;
  mDirty = true;
}

void KMMsgInfo::setTo( const TQString &to )
{
  if ( !kd )
    kd = new KMMsgInfoPrivate;
  kd->modifiers |= KMMsgInfoPrivate::TO_SET;
  kd->to = to;
  mDirty = true;
}

//--- For compatability with old index files
void KMMsgInfo::compat_fromOldIndexString(const TQCString& str, bool toUtf8)
{
    const char *start, *offset;

    if(!kd)
        kd = new KMMsgInfoPrivate;
    kd->modifiers = KMMsgInfoPrivate::ALL_SET;
    kd->xmark   = str.mid(33, 3).stripWhiteSpace();
    kd->folderOffset = str.mid(2,9).toULong();
    kd->msgSize = str.mid(12,9).toULong();
    kd->date = (time_t)str.mid(22,10).toULong();
    mStatus = (KMMsgStatus)str.at(0);
    if (toUtf8) {
        kd->subject = str.mid(37, 100).stripWhiteSpace();
        kd->fromStrip = str.mid(138, 50).stripWhiteSpace();
        kd->toStrip = str.mid(189, 50).stripWhiteSpace();
    } else {
        start = offset = str.data() + 37;
        while (*start == ' ' && start - offset < 100) start++;
        kd->subject = TQString::fromUtf8(str.mid(start - str.data(),
            100 - (start - offset)), 100 - (start - offset));
        start = offset = str.data() + 138;
        while (*start == ' ' && start - offset < 50) start++;
        kd->fromStrip = TQString::fromUtf8(str.mid(start - str.data(),
            50 - (start - offset)), 50 - (start - offset));
        start = offset = str.data() + 189;
        while (*start == ' ' && start - offset < 50) start++;
        kd->toStrip = TQString::fromUtf8(str.mid(start - str.data(),
            50 - (start - offset)), 50 - (start - offset));
    }
    kd->replyToIdMD5 = str.mid(240, 22).stripWhiteSpace();
    kd->msgIdMD5 = str.mid(263, 22).stripWhiteSpace();
    mDirty = false;
}

bool KMMsgInfo::dirty(void) const
{
    if( KMMsgBase::dirty() )
      return true;
    return kd && kd->modifiers != KMMsgInfoPrivate::NONE_SET;
}