11 #include "kmmessage.h"
12 #include "mailinglist-magic.h"
13 #include "messageproperty.h"
14 using KMail::MessageProperty;
15 #include "objecttreeparser.h"
16 using KMail::ObjectTreeParser;
17 #include "kmfolderindex.h"
18 #include "undostack.h"
19 #include "kmversion.h"
20 #include "headerstrategy.h"
21 #include "globalsettings.h"
22 using KMail::HeaderStrategy;
23 #include "kmaddrbook.h"
24 #include "kcursorsaver.h"
25 #include "templateparser.h"
27 #include <libkpimidentities/identity.h>
28 #include <libkpimidentities/identitymanager.h>
29 #include <libemailfunctions/email.h>
31 #include <kpgpblock.h>
32 #include <kaddrbook.h>
34 #include <tdeapplication.h>
35 #include <tdeglobal.h>
36 #include <tdeglobalsettings.h>
38 #include <tdeconfig.h>
39 #include <tdehtml_part.h>
44 #include <tqtextcodec.h>
45 #include <tqmessagebox.h>
46 #include <kmime_util.h>
47 #include <kmime_charfreq.h>
49 #include <kmime_header_parsing.h>
50 using KMime::HeaderParsing::parseAddressList;
51 using namespace KMime::Types;
53 #include <mimelib/body.h>
54 #include <mimelib/field.h>
55 #include <mimelib/mimepp.h>
56 #include <mimelib/string.h>
60 #include <tdelocale.h>
66 #include <tdemessagebox.h>
69 using namespace KMime;
71 static DwString emptyString(
"");
74 static TQString sReplyLanguage, sReplyStr, sReplyAllStr, sIndentPrefixStr;
75 static bool sSmartQuote,
78 static TQStringList sPrefCharsets;
80 TQString KMMessage::sForwardStr;
81 const HeaderStrategy * KMMessage::sHeaderStrategy = HeaderStrategy::rich();
83 static void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart );
85 TQValueList<KMMessage*> KMMessage::sPendingDeletes;
93 mNeedsAssembly =
true;
109 mFolderOffset =
msgInfo.folderOffset();
111 mEncryptionState =
msgInfo.encryptionState();
112 mSignatureState =
msgInfo.signatureState();
113 mMDNSentState =
msgInfo.mdnSentState();
115 mFileName =
msgInfo.fileName();
130 void KMMessage::init( DwMessage* aMsg )
132 mNeedsAssembly =
false;
136 mMsg =
new DwMessage;
145 mStatus = KMMsgStatusNew;
146 mEncryptionState = KMMsgEncryptionStateUnknown;
147 mSignatureState = KMMsgSignatureStateUnknown;
148 mMDNSentState = KMMsgMDNStateUnknown;
157 void KMMessage::assign(
const KMMessage& other )
159 MessageProperty::forget(
this );
161 delete mUnencryptedMsg;
163 mNeedsAssembly =
true;
165 mMsg =
new DwMessage( *(other.mMsg) );
168 mOverrideCodec = other.mOverrideCodec;
169 mDecodeHTML = other.mDecodeHTML;
170 mMsgSize = other.mMsgSize;
171 mMsgLength = other.mMsgLength;
172 mFolderOffset = other.mFolderOffset;
173 mStatus = other.mStatus;
174 mEncryptionState = other.mEncryptionState;
175 mSignatureState = other.mSignatureState;
176 mMDNSentState = other.mMDNSentState;
177 mIsParsed = other.mIsParsed;
183 setDrafts( other.
drafts() );
194 kmkernel->undoStack()->msgDestroyed(
this );
199 void KMMessage::setReferences(
const TQCString& aStr)
201 if (aStr.isNull())
return;
202 mMsg->Headers().References().FromString(aStr);
203 mNeedsAssembly =
true;
210 DwHeaders& header = mMsg->Headers();
211 if (header.HasMessageId())
225 MessageProperty::setSerialCache(
this, newMsgSerNum );
238 return MessageProperty::transferInProgress( getMsgSerNum() );
245 MessageProperty::setTransferInProgress( getMsgSerNum(), value, force );
247 sPendingDeletes.remove(
this );
249 int idx = parent()->find(
this );
251 parent()->removeMsg( idx );
260 return headerField(
"Priority" ).contains(
"urgent",
false )
267 delete mUnencryptedMsg;
268 mUnencryptedMsg = unencrypted;
274 TQString& brokenAddress )
276 if ( aStr.isEmpty() ) {
277 return KPIM::AddressEmpty;
280 TQStringList list = KPIM::splitEmailAddrList( aStr );
281 for( TQStringList::const_iterator it = list.begin(); it != list.end(); ++it ) {
282 KPIM::EmailParseResult errorCode = KPIM::isValidEmailAddress( *it );
283 if ( errorCode != KPIM::AddressOk ) {
284 brokenAddress = ( *it );
288 return KPIM::AddressOk;
296 mNeedsAssembly =
false;
299 return mMsg->AsString();
303 const DwMessage* KMMessage::asDwMessage()
307 mNeedsAssembly =
false;
321 KMMessage msg(
new DwMessage( *this->mMsg ) );
329 KMMessage msg(
new DwMessage( *this->mMsg ) );
353 char str[2] = { 0, 0 };
365 str[0] =
static_cast<char>( mdnSentState() );
370 mNeedsAssembly =
false;
371 mMsg->Headers().Assemble();
372 mMsg->Assemble( mMsg->Headers(),
380 DwHeaders& header = mMsg->Headers();
382 if ( header.AsString().empty() )
384 return TQString::fromLatin1( header.AsString().c_str() );
391 return mMsg->Headers().ContentType();
394 void KMMessage::fromByteArray(
const TQByteArray & ba,
bool setStatus ) {
398 void KMMessage::fromString(
const TQCString & str,
bool aSeStatus ) {
405 mMsg =
new DwMessage;
406 mMsg->FromString( str );
411 setEncryptionStateChar(
headerField(
"X-KMail-EncryptionState").at(0) );
412 setSignatureStateChar(
headerField(
"X-KMail-SignatureState").at(0) );
413 setMDNSentState(
static_cast<KMMsgMDNSentState
>(
headerField(
"X-KMail-MDN-Sent").at(0).latin1() ) );
415 if ( invitationState() == KMMsgInvitationUnknown &&
readyToShow() )
416 updateInvitationState();
417 if ( attachmentState() == KMMsgAttachmentUnknown &&
readyToShow() )
418 updateAttachmentState();
420 mNeedsAssembly =
false;
428 TQString result, str;
435 unsigned int strLength(aStr.length());
436 for (uint i=0; i<strLength;) {
446 result += KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
447 date(), sReplyLanguage,
false );
453 result += fromStrip();
459 for (j=0; str[j]>
' '; j++)
461 unsigned int strLength(str.length());
462 for (; j < strLength && str[j] <=
' '; j++)
507 static void removeTrailingSpace( TQString &line )
509 int i = line.length()-1;
510 while( (i >= 0) && ((line[i] ==
' ') || (line[i] ==
'\t')))
515 static TQString splitLine( TQString &line)
517 removeTrailingSpace( line );
520 int l = line.length();
527 if ((c ==
'>') || (c ==
':') || (c ==
'|'))
529 else if ((c !=
' ') && (c !=
'\t'))
540 TQString result = line.left(j);
545 TQString result = line.left(j);
550 static TQString flowText(TQString &text,
const TQString& indent,
int maxLength)
555 return indent+
"<NULL>\n";
561 if ((
int) text.length() > maxLength)
564 while( (i >= 0) && (text[i] !=
' '))
579 TQString line = text.left(i);
580 if (i < (
int) text.length())
585 result += indent + line +
'\n';
592 static bool flushPart(TQString &msg, TQStringList &part,
593 const TQString &indent,
int maxLength)
595 maxLength -= indent.length();
596 if (maxLength < 20) maxLength = 20;
599 while ((part.begin() != part.end()) && part.last().isEmpty())
601 part.remove(part.fromLast());
605 for(TQStringList::Iterator it2 = part.begin();
609 TQString line = (*it2);
614 msg += flowText(text, indent, maxLength);
615 msg += indent +
'\n';
622 text +=
' '+line.stripWhiteSpace();
624 if (((
int) text.length() < maxLength) || ((
int) line.length() < (maxLength-10)))
625 msg += flowText(text, indent, maxLength);
629 msg += flowText(text, indent, maxLength);
631 bool appendEmptyLine =
true;
633 appendEmptyLine =
false;
636 return appendEmptyLine;
639 static TQString stripSignature(
const TQString & msg,
bool clearSigned ) {
641 return msg.left( msg.findRev( TQRegExp(
"\n--\\s?\n" ) ) );
643 return msg.left( msg.findRev(
"\n-- \n" ) );
650 bool firstPart =
true;
653 const TQStringList lines = TQStringList::split(
'\n', msg,
true);
656 for(TQStringList::const_iterator it = lines.begin();
662 const TQString indent = splitLine( line );
667 part.append(TQString());
677 if (oldIndent != indent)
681 if (part.count() && (oldIndent.length() < indent.length()))
683 TQStringList::Iterator it2 = part.fromLast();
684 while( (it2 != part.end()) && (*it2).isEmpty())
687 if ((it2 != part.end()) && ((*it2).endsWith(
":")))
689 fromLine = oldIndent + (*it2) +
'\n';
693 if (flushPart( result, part, oldIndent, maxLineLength))
695 if (oldIndent.length() > indent.length())
696 result += indent +
'\n';
698 result += oldIndent +
'\n';
700 if (!fromLine.isEmpty())
708 flushPart( result, part, oldIndent, maxLineLength);
715 TQCString& parsedString,
716 const TQTextCodec*& codec,
722 partNode * curNode = root->findType( DwMime::kTypeText,
723 DwMime::kSubtypeUnknown,
726 kdDebug(5006) <<
"\n\n======= KMMessage::parseTextStringFromDwPart() - "
727 << ( curNode ?
"text part found!\n" :
"sorry, no text node!\n" ) << endl;
729 isHTML = DwMime::kSubtypeHtml == curNode->subType();
731 ObjectTreeParser otp( 0, 0,
true,
false,
true );
732 otp.parseObjectTree( curNode );
733 parsedString = otp.rawReplyString();
734 codec = curNode->msgPart().codec();
741 bool allowDecryption )
const
744 Q_ASSERT( root->processed() );
746 TQCString parsedString;
748 const TQTextCodec *
codec = 0;
750 if ( !root )
return TQString();
753 if ( mOverrideCodec || !
codec )
756 if ( parsedString.isEmpty() )
759 bool clearSigned =
false;
763 if ( allowDecryption ) {
764 TQPtrList<Kpgp::Block> pgpBlocks;
765 TQStrList nonPgpBlocks;
766 if ( Kpgp::Module::prepareMessageForDecryption( parsedString,
771 if ( pgpBlocks.count() == 1 ) {
772 Kpgp::Block * block = pgpBlocks.first();
773 if ( block->type() == Kpgp::PgpMessageBlock ||
774 block->type() == Kpgp::ClearsignedBlock ) {
775 if ( block->type() == Kpgp::PgpMessageBlock ) {
784 result =
codec->toUnicode( nonPgpBlocks.first() )
785 +
codec->toUnicode( block->text() )
786 +
codec->toUnicode( nonPgpBlocks.last() );
792 if ( result.isEmpty() ) {
793 result =
codec->toUnicode( parsedString );
794 if ( result.isEmpty() )
799 if ( isHTML && mDecodeHTML ) {
800 TDEHTMLPart htmlPart;
801 htmlPart.setOnlyLocalReferences(
true );
802 htmlPart.setMetaRefreshEnabled(
false );
803 htmlPart.setPluginsEnabled(
false );
804 htmlPart.setJScriptEnabled(
false );
805 htmlPart.setJavaEnabled(
false );
807 htmlPart.write( result );
809 htmlPart.selectAll();
810 result = htmlPart.selectedText();
814 if ( aStripSignature )
815 return stripSignature( result, clearSigned );
824 partNode *root = partNode::fromMessage(
this );
828 ObjectTreeParser otp;
829 otp.parseObjectTree( root );
836 const TQString& aIndentStr,
837 const TQString& selection ,
838 bool aStripSignature ,
839 bool allowDecryption )
const
841 TQString content = selection.isEmpty() ?
842 asPlainText( aStripSignature, allowDecryption ) : selection ;
845 const int firstNonWS = content.find( TQRegExp(
"\\S" ) );
846 const int lineStart = content.findRev(
'\n', firstNonWS );
847 if ( lineStart >= 0 )
848 content.remove( 0,
static_cast<unsigned int>( lineStart ) );
852 content.replace(
'\n',
'\n' + indentStr );
853 content.prepend( indentStr );
857 if ( sSmartQuote && sWordWrap )
858 return headerStr +
smartQuote( content, sWrapCol );
859 return headerStr + content;
866 bool allowDecryption ,
867 const TQString &tmpl ,
868 const TQString &originatingAccount )
871 TQString mailingListStr, replyToStr, toStr;
872 TQStringList mailingListAddresses;
873 TQCString refStr, headerName;
874 bool replyAll =
true;
878 MailingList::name(
this, headerName, mailingListStr);
884 if ( parent() && parent()->isMailingListEnabled() &&
885 !parent()->mailingListPostAddress().isEmpty() ) {
886 mailingListAddresses << parent()->mailingListPostAddress();
888 if (
headerField(
"List-Post").find(
"mailto:", 0,
false ) != -1 ) {
890 TQRegExp rx(
"<mailto:([^@>]+)@([^>]+)>",
false );
891 if ( rx.search( listPost, 0 ) != -1 )
892 mailingListAddresses << rx.cap(1) +
'@' + rx.cap(2);
896 switch( replyStrategy ) {
897 case KMail::ReplySmart : {
898 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
901 else if ( !replyToStr.isEmpty() ) {
905 else if ( !mailingListAddresses.isEmpty() ) {
906 toStr = mailingListAddresses[0];
915 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
918 if ( toStr.isEmpty() && !recipients.isEmpty() )
919 toStr = recipients[0];
923 case KMail::ReplyList : {
924 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
927 else if ( !mailingListAddresses.isEmpty() ) {
928 toStr = mailingListAddresses[0];
930 else if ( !replyToStr.isEmpty() ) {
935 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
940 case KMail::ReplyAll : {
941 TQStringList recipients;
942 TQStringList ccRecipients;
945 if( !replyToStr.isEmpty() ) {
946 recipients += KPIM::splitEmailAddrList( replyToStr );
949 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
950 it != mailingListAddresses.end();
956 if ( !mailingListAddresses.isEmpty() ) {
958 if ( recipients.isEmpty() && !
from().isEmpty() ) {
961 ccRecipients +=
from();
962 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of CC recipients"
966 recipients.prepend( mailingListAddresses[0] );
970 if ( recipients.isEmpty() && !
from().isEmpty() ) {
973 recipients +=
from();
974 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of recipients"
983 if( !
cc().isEmpty() || !
to().isEmpty() ) {
986 list += KPIM::splitEmailAddrList(
to());
988 list += KPIM::splitEmailAddrList(
cc());
989 for( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
993 kdDebug(5006) <<
"Added " << *it <<
" to the list of CC recipients"
999 if ( !ccRecipients.isEmpty() ) {
1005 if ( toStr.isEmpty() && !ccRecipients.isEmpty() ) {
1006 toStr = ccRecipients[0];
1007 ccRecipients.pop_front();
1010 msg->setCc( ccRecipients.join(
", ") );
1013 if ( toStr.isEmpty() && !recipients.isEmpty() ) {
1015 toStr = recipients[0];
1019 case KMail::ReplyAuthor : {
1020 if ( !replyToStr.isEmpty() ) {
1021 TQStringList recipients = KPIM::splitEmailAddrList( replyToStr );
1024 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
1025 it != mailingListAddresses.end();
1029 if ( !recipients.isEmpty() ) {
1030 toStr = recipients.join(
", ");
1038 else if ( !
from().isEmpty() ) {
1044 case KMail::ReplyNone : {
1049 if (!originatingAccount.isEmpty()) {
1050 msg->setOriginatingAccountName(originatingAccount);
1056 if (!refStr.isEmpty())
1057 msg->setReferences(refStr);
1059 msg->setReplyToId(
msgId());
1071 msg->setSubject( replySubject() );
1073 formatString( GlobalSettings::self()->quoteString() ) );
1075 TemplateParser parser( msg, ( replyAll ? TemplateParser::ReplyAll : TemplateParser::Reply ) );
1077 if ( GlobalSettings::quoteSelectionOnly() ) {
1080 if ( !tmpl.isEmpty() ) {
1081 parser.process( tmpl,
this );
1083 parser.process(
this );
1087 msg->
link(
this, KMMsgStatusReplied);
1089 if ( parent() && parent()->putRepliesInSameFolder() )
1090 msg->setFcc( parent()->idString() );
1105 TQCString firstRef, lastRef, refStr, retRefStr;
1108 refStr =
headerField(
"References").stripWhiteSpace().latin1();
1110 if (refStr.isEmpty())
1113 i = refStr.find(
'<');
1114 j = refStr.find(
'>');
1115 firstRef = refStr.mid(i, j-i+1);
1116 if (!firstRef.isEmpty())
1117 retRefStr = firstRef +
' ';
1119 i = refStr.findRev(
'<');
1120 j = refStr.findRev(
'>');
1122 lastRef = refStr.mid(i, j-i+1);
1123 if (!lastRef.isEmpty() && lastRef != firstRef)
1124 retRefStr += lastRef +
' ';
1135 KMMessagePart msgPart;
1138 TQString strId = msg->
headerField(
"X-KMail-Identity" ).stripWhiteSpace();
1139 if ( !strId.isEmpty())
1140 id = strId.toUInt();
1141 const KPIM::Identity & ident =
1142 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1145 TQString strByWayOf = TQString(
"%1 (by way of %2 <%3>)")
1147 .arg( ident.fullName() )
1148 .arg( ident.primaryEmailAddress() );
1151 TQString strFrom = TQString(
"%1 <%2>")
1152 .arg( ident.fullName() )
1153 .arg( ident.primaryEmailAddress() );
1160 if ( origDate.isEmpty() )
1175 msg->
link(
this, KMMsgStatusForwarded);
1187 if (sHeaderStrategy == HeaderStrategy::all()) {
1188 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1191 str +=
"\n-------------------------------------------------------\n";
1193 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1194 s +=
"Subject: " +
subject() +
"\n";
1196 + KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
1197 date(), sReplyLanguage,
false )
1199 s +=
"From: " +
from() +
"\n";
1200 s +=
"To: " +
to() +
"\n";
1201 if (!
cc().isEmpty()) s +=
"Cc: " +
cc() +
"\n";
1204 str +=
"\n-------------------------------------------------------\n";
1214 DwHeaders& header = mMsg->Headers();
1215 DwField* field = header.FirstField();
1219 nextField = field->Next();
1220 if ( field->FieldNameStr().find(
"ontent" ) == DwString::npos
1221 && !whiteList.contains( TQString::fromLatin1( field->FieldNameStr().c_str() ) ) )
1222 header.RemoveField(field);
1236 if ( type() == DwMime::kTypeMultipart ||
1237 ( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypePlain ) ) {
1242 DwMediaType oldContentType = msg->mMsg->Headers().ContentType();
1247 TQStringList blacklist = GlobalSettings::self()->mimetypesToStripWhenInlineForwarding();
1248 for ( TQStringList::Iterator it = blacklist.begin(); it != blacklist.end(); ++it ) {
1249 TQString entry = (*it);
1250 int sep = entry.find(
'/' );
1251 TQCString type = entry.left( sep ).latin1();
1252 TQCString subtype = entry.mid( sep+1 ).latin1();
1253 kdDebug( 5006 ) <<
"Looking for blacklisted type: " << type <<
"/" << subtype << endl;
1254 while ( DwBodyPart * part = msg->
findDwBodyPart( type, subtype ) ) {
1255 msg->mMsg->Body().RemoveBodyPart( part );
1258 msg->mMsg->Assemble();
1262 msg->mMsg->Headers().ContentType().FromString( oldContentType.AsString() );
1263 msg->mMsg->Headers().ContentType().Parse();
1264 msg->mMsg->Assemble();
1266 else if( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypeHtml ) {
1270 msg->setType( DwMime::kTypeText );
1271 msg->setSubtype( DwMime::kSubtypeHtml );
1272 msg->mNeedsAssembly =
true;
1282 DwHeaders & header = msg->mMsg->Headers();
1283 header.MimeVersion().FromString(
"1.0");
1285 contentType.SetType( DwMime::kTypeMultipart );
1286 contentType.SetSubtype( DwMime::kSubtypeMixed );
1287 contentType.CreateBoundary(0);
1288 contentType.Assemble();
1291 KMMessagePart msgPart;
1295 KMMessagePart secondPart;
1296 secondPart.setType( type() );
1297 secondPart.setSubtype( subtype() );
1298 secondPart.setBody( mMsg->Body().AsString() );
1300 applyHeadersToMessagePart( mMsg->Headers(), &secondPart );
1302 msg->mNeedsAssembly =
true;
1307 msg->setSubject( forwardSubject() );
1310 if ( !tmpl.isEmpty() ) {
1311 parser.process( tmpl,
this );
1313 parser.process(
this );
1323 msg->
link(
this, KMMsgStatusForwarded);
1327 static const struct {
1328 const char * dontAskAgainID;
1331 } mdnMessageBoxes[] = {
1332 {
"mdnNormalAsk",
true,
1333 I18N_NOOP(
"This message contains a request to return a notification "
1334 "about your reception of the message.\n"
1335 "You can either ignore the request or let KMail send a "
1336 "\"denied\" or normal response.") },
1337 {
"mdnUnknownOption",
false,
1338 I18N_NOOP(
"This message contains a request to send a notification "
1339 "about your reception of the message.\n"
1340 "It contains a processing instruction that is marked as "
1341 "\"required\", but which is unknown to KMail.\n"
1342 "You can either ignore the request or let KMail send a "
1343 "\"failed\" response.") },
1344 {
"mdnMultipleAddressesInReceiptTo",
true,
1345 I18N_NOOP(
"This message contains a request to send a notification "
1346 "about your reception of the message,\n"
1347 "but it is requested to send the notification to more "
1348 "than one address.\n"
1349 "You can either ignore the request or let KMail send a "
1350 "\"denied\" or normal response.") },
1351 {
"mdnReturnPathEmpty",
true,
1352 I18N_NOOP(
"This message contains a request to send a notification "
1353 "about your reception of the message,\n"
1354 "but there is no return-path set.\n"
1355 "You can either ignore the request or let KMail send a "
1356 "\"denied\" or normal response.") },
1357 {
"mdnReturnPathNotInReceiptTo",
true,
1358 I18N_NOOP(
"This message contains a request to send a notification "
1359 "about your reception of the message,\n"
1360 "but the return-path address differs from the address "
1361 "the notification was requested to be sent to.\n"
1362 "You can either ignore the request or let KMail send a "
1363 "\"denied\" or normal response.") },
1366 static const int numMdnMessageBoxes
1367 =
sizeof mdnMessageBoxes /
sizeof *mdnMessageBoxes;
1370 static int requestAdviceOnMDN(
const char * what ) {
1371 for (
int i = 0 ; i < numMdnMessageBoxes ; ++i ) {
1372 if ( !qstrcmp( what, mdnMessageBoxes[i].dontAskAgainID ) ) {
1373 if ( mdnMessageBoxes[i].canDeny ) {
1375 int answer = TQMessageBox::information( 0,
1376 i18n(
"Message Disposition Notification Request"),
1377 i18n( mdnMessageBoxes[i].text ),
1378 i18n(
"&Ignore"), i18n(
"Send \"&denied\""), i18n(
"&Send") );
1379 return answer ? answer + 1 : 0 ;
1382 int answer = TQMessageBox::information( 0,
1383 i18n(
"Message Disposition Notification Request"),
1384 i18n( mdnMessageBoxes[i].text ),
1385 i18n(
"&Ignore"), i18n(
"&Send") );
1386 return answer ? answer + 2 : 0 ;
1390 kdWarning(5006) <<
"didn't find data for message box \""
1391 << what <<
"\"" << endl;
1396 MDN::DispositionType d,
1398 TQValueList<MDN::DispositionModifier> m )
1407 if ( mdnSentState() != KMMsgMDNStateUnknown &&
1408 mdnSentState() != KMMsgMDNNone )
1411 char st[2]; st[0] = (char)mdnSentState(); st[1] = 0;
1412 kdDebug(5006) <<
"mdnSentState() == '" << st <<
"'" << endl;
1417 DwMime::kSubtypeDispositionNotification ) ) {
1418 setMDNSentState( KMMsgMDNIgnore );
1423 TQString receiptTo =
headerField(
"Disposition-Notification-To");
1424 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1425 receiptTo.remove(
'\n' );
1428 MDN::SendingMode s = MDN::SentAutomatically;
1430 TDEConfigGroup mdnConfig( KMKernel::config(),
"MDN" );
1433 int mode = mdnConfig.readNumEntry(
"default-policy", 0 );
1434 if ( !mode || mode < 0 || mode > 3 ) {
1436 setMDNSentState( KMMsgMDNIgnore );
1446 TQString notificationOptions =
headerField(
"Disposition-Notification-Options");
1447 if ( notificationOptions.contains(
"required",
false ) ) {
1451 if ( !allowGUI )
return 0;
1452 mode = requestAdviceOnMDN(
"mdnUnknownOption" );
1453 s = MDN::SentManually;
1455 special = i18n(
"Header \"Disposition-Notification-Options\" contained "
1456 "required, but unknown parameter");
1464 kdDebug(5006) <<
"KPIM::splitEmailAddrList(receiptTo): "
1465 << KPIM::splitEmailAddrList(receiptTo).join(
"\n") << endl;
1466 if ( KPIM::splitEmailAddrList(receiptTo).count() > 1 ) {
1467 if ( !allowGUI )
return 0;
1468 mode = requestAdviceOnMDN(
"mdnMultipleAddressesInReceiptTo" );
1469 s = MDN::SentManually;
1477 AddrSpecList returnPathList = extractAddrSpecs(
"Return-Path");
1478 TQString returnPath = returnPathList.isEmpty() ? TQString()
1479 : returnPathList.front().localPart +
'@' + returnPathList.front().domain ;
1480 kdDebug(5006) <<
"clean return path: " << returnPath << endl;
1481 if ( returnPath.isEmpty() || !receiptTo.contains( returnPath,
false ) ) {
1482 if ( !allowGUI )
return 0;
1483 mode = requestAdviceOnMDN( returnPath.isEmpty() ?
1484 "mdnReturnPathEmpty" :
1485 "mdnReturnPathNotInReceiptTo" );
1486 s = MDN::SentManually;
1489 if ( a != KMime::MDN::AutomaticAction ) {
1492 if ( !allowGUI )
return 0;
1493 mode = requestAdviceOnMDN(
"mdnNormalAsk" );
1494 s = MDN::SentManually;
1499 setMDNSentState( KMMsgMDNIgnore );
1503 kdFatal(5006) <<
"KMMessage::createMDN(): The \"ask\" mode should "
1504 <<
"never appear here!" << endl;
1517 TQString finalRecipient = kmkernel->identityManager()
1518 ->identityForUoidOrDefault(
identityUoid() ).fullEmailAddr();
1529 DwHeaders & header = receipt->mMsg->Headers();
1530 header.MimeVersion().FromString(
"1.0");
1532 contentType.SetType( DwMime::kTypeMultipart );
1533 contentType.SetSubtype( DwMime::kSubtypeReport );
1534 contentType.CreateBoundary(0);
1535 receipt->mNeedsAssembly =
true;
1541 KMMessagePart firstMsgPart;
1542 firstMsgPart.setTypeStr(
"text" );
1543 firstMsgPart.setSubtypeStr(
"plain" );
1544 firstMsgPart.setBodyFromUnicode( description );
1548 KMMessagePart secondMsgPart;
1549 secondMsgPart.setType( DwMime::kTypeMessage );
1550 secondMsgPart.setSubtype( DwMime::kSubtypeDispositionNotification );
1553 secondMsgPart.setBodyEncoded( MDN::dispositionNotificationBodyContent(
1557 d, a, s, m, special ) );
1561 int num = mdnConfig.readNumEntry(
"quote-message", 0 );
1562 if ( num < 0 || num > 2 ) num = 0;
1563 MDN::ReturnContent returnContent =
static_cast<MDN::ReturnContent
>( num );
1565 KMMessagePart thirdMsgPart;
1566 switch ( returnContent ) {
1568 thirdMsgPart.setTypeStr(
"message" );
1569 thirdMsgPart.setSubtypeStr(
"rfc822" );
1573 case MDN::HeadersOnly:
1574 thirdMsgPart.setTypeStr(
"text" );
1575 thirdMsgPart.setSubtypeStr(
"rfc822-headers" );
1584 receipt->setTo( receiptTo );
1585 receipt->setSubject(
"Message Disposition Notification" );
1586 receipt->setReplyToId(
msgId() );
1591 kdDebug(5006) <<
"final message:\n" + receipt->
asString() << endl;
1596 KMMsgMDNSentState state = KMMsgMDNStateUnknown;
1598 case MDN::Displayed: state = KMMsgMDNDisplayed;
break;
1599 case MDN::Deleted: state = KMMsgMDNDeleted;
break;
1600 case MDN::Dispatched: state = KMMsgMDNDispatched;
break;
1601 case MDN::Processed: state = KMMsgMDNProcessed;
break;
1602 case MDN::Denied: state = KMMsgMDNDenied;
break;
1603 case MDN::Failed: state = KMMsgMDNFailed;
break;
1605 setMDNSentState( state );
1611 TQString result = s;
1612 TQRegExp rx(
"\\$\\{([a-z0-9-]+)\\}",
false );
1613 Q_ASSERT( rx.isValid() );
1615 TQRegExp rxDate(
"\\$\\{date\\}" );
1616 Q_ASSERT( rxDate.isValid() );
1618 TQString sDate = KMime::DateFormatter::formatDate(
1619 KMime::DateFormatter::Localized, date() );
1622 if( ( idx = rxDate.search( result, idx ) ) != -1 ) {
1623 result.replace( idx, rxDate.matchedLength(), sDate );
1627 while ( ( idx = rx.search( result, idx ) ) != -1 ) {
1628 TQString replacement =
headerField( TQString(rx.cap(1)).latin1() );
1629 result.replace( idx, rx.matchedLength(), replacement );
1630 idx += replacement.length();
1637 TQString str, receiptTo;
1640 receiptTo =
headerField(
"Disposition-Notification-To");
1641 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1642 receiptTo.remove(
'\n' );
1646 receipt->setTo(receiptTo);
1647 receipt->setSubject(i18n(
"Receipt: ") +
subject());
1649 str =
"Your message was successfully delivered.";
1650 str +=
"\n\n---------- Message header follows ----------\n";
1652 str +=
"--------------------------------------------\n";
1655 receipt->
setBody(str.latin1());
1664 const KPIM::Identity & ident =
1665 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1667 if(ident.fullEmailAddr().isEmpty())
1670 setFrom(ident.fullEmailAddr());
1672 if(ident.replyToAddr().isEmpty())
1675 setReplyTo(ident.replyToAddr());
1677 if(ident.bcc().isEmpty())
1680 setBcc(ident.bcc());
1682 if (ident.organization().isEmpty())
1687 if (ident.isDefault())
1690 setHeaderField(
"X-KMail-Identity", TQString::number( ident.uoid() ));
1692 if ( ident.transport().isEmpty() )
1697 if ( ident.fcc().isEmpty() )
1698 setFcc( TQString() );
1700 setFcc( ident.fcc() );
1702 if ( ident.drafts().isEmpty() )
1703 setDrafts( TQString() );
1705 setDrafts( ident.drafts() );
1707 if ( ident.templates().isEmpty() )
1708 setTemplates( TQString() );
1710 setTemplates( ident.templates() );
1728 TQString idString =
headerField(
"X-KMail-Identity").stripWhiteSpace();
1730 int id = idString.toUInt( &ok );
1732 if ( !ok ||
id == 0 )
1733 id = kmkernel->identityManager()->identityForAddress(
to() +
", " +
cc() ).uoid();
1734 if (
id == 0 && parent() )
1735 id = parent()->identity();
1748 if (!msg->
headerField(
"X-KMail-Transport").isEmpty())
1756 DwHeaders& header = mMsg->Headers();
1757 DwField* field = header.FirstField();
1760 if (mNeedsAssembly) mMsg->Assemble();
1761 mNeedsAssembly =
false;
1765 nextField = field->Next();
1766 if (field->FieldBody()->AsString().empty())
1768 header.RemoveField(field);
1769 mNeedsAssembly =
true;
1779 DwHeaders& header = mMsg->Headers();
1780 header.MimeVersion().FromString(
"1.0");
1786 contentType.SetType( DwMime::kTypeMultipart);
1787 contentType.SetSubtype(DwMime::kSubtypeMixed );
1790 contentType.CreateBoundary(0);
1792 mNeedsAssembly =
true;
1799 TDEConfigGroup general( KMKernel::config(),
"General" );
1800 DwHeaders& header = mMsg->Headers();
1803 if (!header.HasDate())
return "";
1804 unixTime = header.Date().AsUnixTime();
1808 return KMime::DateFormatter::formatDate(
1809 static_cast<KMime::DateFormatter::FormatType
>(general.readNumEntry(
"dateFormat", KMime::DateFormatter::Fancy )),
1810 unixTime, general.readEntry(
"customDateFormat" ));
1817 DwHeaders& header = mMsg->Headers();
1820 if (!header.HasDate())
return "";
1821 unixTime = header.Date().AsUnixTime();
1823 TQCString result = ctime(&unixTime);
1824 int len = result.length();
1825 if (result[len-1]==
'\n')
1826 result.truncate(len-1);
1833 TQString KMMessage::dateIsoStr()
const
1835 DwHeaders& header = mMsg->Headers();
1838 if (!header.HasDate())
return "";
1839 unixTime = header.Date().AsUnixTime();
1842 strftime(cstr, 63,
"%Y-%m-%d %H:%M:%S", localtime(&unixTime));
1843 return TQString(cstr);
1848 time_t KMMessage::date()
const
1850 time_t res = ( time_t )-1;
1851 DwHeaders& header = mMsg->Headers();
1852 if (header.HasDate())
1853 res = header.Date().AsUnixTime();
1861 struct timeval tval;
1862 gettimeofday(&tval, 0);
1863 setDate((time_t)tval.tv_sec);
1868 void KMMessage::setDate(time_t aDate)
1871 mMsg->Headers().Date().FromCalendarTime(aDate);
1872 mMsg->Headers().Date().Assemble();
1873 mNeedsAssembly =
true;
1879 void KMMessage::setDate(
const TQCString& aStr)
1881 DwHeaders& header = mMsg->Headers();
1883 header.Date().FromString(aStr);
1884 header.Date().Parse();
1885 mNeedsAssembly =
true;
1888 if (header.HasDate())
1889 mDate = header.Date().AsUnixTime();
1899 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1902 return KPIM::normalizeAddressesAndDecodeIDNs(
headers.join(
", " ) );
1907 void KMMessage::setTo(
const TQString& aStr)
1913 TQString KMMessage::toStrip()
const
1921 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Reply-To") );
1926 void KMMessage::setReplyTo(
const TQString& aStr)
1933 void KMMessage::setReplyTo(
KMMessage* aMsg)
1946 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1949 return KPIM::normalizeAddressesAndDecodeIDNs(
headers.join(
", " ) );
1954 void KMMessage::setCc(
const TQString& aStr)
1961 TQString KMMessage::ccStrip()
const
1970 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Bcc") );
1975 void KMMessage::setBcc(
const TQString& aStr)
1988 void KMMessage::setFcc(
const TQString &aStr )
1994 void KMMessage::setDrafts(
const TQString &aStr )
2000 void KMMessage::setTemplates(
const TQString &aStr )
2009 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(mParent->whoField().utf8()) );
2017 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"From") );
2022 void KMMessage::setFrom(
const TQString& bStr)
2024 TQString aStr = bStr;
2033 TQString KMMessage::fromStrip()
const
2040 AddrSpecList asl = extractAddrSpecs(
"Sender" );
2042 asl = extractAddrSpecs(
"From" );
2045 return asl.front().asString();
2056 void KMMessage::setSubject(
const TQString& aStr)
2071 void KMMessage::setXMark(
const TQString& aStr)
2081 int leftAngle, rightAngle;
2086 rightAngle =
replyTo.find(
'>' );
2087 if (rightAngle != -1)
2088 replyTo.truncate( rightAngle + 1 );
2090 leftAngle =
replyTo.findRev(
'<' );
2091 if (leftAngle != -1)
2099 ( -1 ==
replyTo.find(
'"' ) ) )
2104 if (leftAngle != -1)
2107 if (rightAngle != -1)
2120 TQString KMMessage::replyToIdMD5()
const {
2127 int leftAngle, rightAngle;
2132 leftAngle =
references.findRev(
'<', leftAngle - 1 );
2133 if( leftAngle != -1 )
2136 if( rightAngle != -1 )
2151 const int rightAngle = result.find(
'>' );
2152 if( rightAngle != -1 )
2153 result.truncate( rightAngle + 1 );
2155 return base64EncodedMD5( result );
2160 return base64EncodedMD5( stripOffPrefixes(
subject() ),
true );
2165 return base64EncodedMD5(
subject(),
true );
2174 void KMMessage::setReplyToId(
const TQString& aStr)
2187 const int rightAngle =
msgId.find(
'>' );
2188 if (rightAngle != -1)
2189 msgId.truncate( rightAngle + 1 );
2191 const int leftAngle =
msgId.findRev(
'<' );
2192 if (leftAngle != -1)
2199 TQString KMMessage::msgIdMD5()
const {
2200 return base64EncodedMD5(
msgId() );
2205 void KMMessage::setMsgId(
const TQString& aStr)
2218 void KMMessage::setMsgSizeServer(
size_t size)
2231 void KMMessage::setUID(ulong uid)
2241 const char * scursor = str.begin();
2243 return AddressList();
2244 const char *
const send = str.begin() + str.length();
2245 if ( !parseAddressList( scursor, send, result ) )
2246 kdDebug(5006) <<
"Error in address splitting: parseAddressList returned false!"
2255 AddrSpecList KMMessage::extractAddrSpecs(
const TQCString & header )
const {
2257 AddrSpecList result;
2258 for ( AddressList::const_iterator ait = al.begin() ; ait != al.end() ; ++ait )
2259 for ( MailboxList::const_iterator mit = (*ait).mailboxList.begin() ; mit != (*ait).mailboxList.end() ; ++mit )
2260 result.push_back( (*mit).addrSpec );
2265 if ( name.isEmpty() )
return TQCString();
2267 DwHeaders & header = mMsg->Headers();
2268 DwField * field = header.FindField( name );
2270 if ( !field )
return TQCString();
2272 return header.FieldBody( name.data() ).AsString().c_str();
2277 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2278 return TQValueList<TQCString>();
2280 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2282 for ( uint i = 0; i < v.size(); ++i ) {
2291 if ( aName.isEmpty() )
2294 if ( !mMsg->Headers().FindField( aName ) )
2297 return decodeRFC2047String( mMsg->Headers().FieldBody( aName.data() ).AsString().c_str(),
2304 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2305 return TQStringList();
2307 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2309 for ( uint i = 0; i < v.size(); ++i ) {
2319 DwHeaders & header = mMsg->Headers();
2320 DwField * field = header.FindField(aName);
2323 header.RemoveField(field);
2324 mNeedsAssembly =
true;
2330 DwHeaders & header = mMsg->Headers();
2331 while ( DwField * field = header.FindField(aName) ) {
2332 header.RemoveField(field);
2333 mNeedsAssembly =
true;
2340 HeaderFieldType type,
bool prepend )
2343 if ( type != Unstructured )
2344 kdDebug(5006) <<
"KMMessage::setHeaderField( \"" << aName <<
"\", \""
2345 << bValue <<
"\", " << type <<
" )" << endl;
2347 if (aName.isEmpty())
return;
2349 DwHeaders& header = mMsg->Headers();
2354 if (!bValue.isEmpty())
2356 TQString value = bValue;
2357 if ( type == Address )
2358 value = KPIM::normalizeAddressesAndEncodeIDNs( value );
2360 if ( type != Unstructured )
2361 kdDebug(5006) <<
"value: \"" << value <<
"\"" << endl;
2363 TQCString encoding = autoDetectCharset(
charset(), sPrefCharsets, value );
2364 if (encoding.isEmpty())
2366 aValue = encodeRFC2047String( value, encoding );
2368 if ( type != Unstructured )
2369 kdDebug(5006) <<
"aValue: \"" << aValue <<
"\"" << endl;
2373 if (str[str.length()-1] !=
':') str +=
": ";
2375 if ( !aValue.isEmpty() )
2376 str += aValue.data();
2377 if (str[str.length()-1] !=
'\n') str +=
'\n';
2379 field =
new DwField(str, mMsg);
2383 header.AddFieldAt( 1, field );
2385 header.AddOrReplaceField( field );
2386 mNeedsAssembly =
true;
2393 DwHeaders& header = mMsg->Headers();
2394 if (header.HasContentType())
return header.ContentType().TypeStr().c_str();
2400 int KMMessage::type()
const
2402 DwHeaders& header = mMsg->Headers();
2403 if (header.HasContentType())
return header.ContentType().Type();
2404 else return DwMime::kTypeNull;
2409 void KMMessage::setTypeStr(
const TQCString& aStr)
2413 mNeedsAssembly =
true;
2418 void KMMessage::setType(
int aType)
2422 mNeedsAssembly =
true;
2430 DwHeaders& header = mMsg->Headers();
2431 if (header.HasContentType())
return header.ContentType().SubtypeStr().c_str();
2437 int KMMessage::subtype()
const
2439 DwHeaders& header = mMsg->Headers();
2440 if (header.HasContentType())
return header.ContentType().Subtype();
2441 else return DwMime::kSubtypeNull;
2446 void KMMessage::setSubtypeStr(
const TQCString& aStr)
2450 mNeedsAssembly =
true;
2455 void KMMessage::setSubtype(
int aSubtype)
2459 mNeedsAssembly =
true;
2465 const TQCString& attr,
2466 const TQCString& val )
2469 DwParameter *param = mType.FirstParameter();
2471 if (!kasciistricmp(param->Attribute().c_str(), attr))
2474 param = param->Next();
2477 param =
new DwParameter;
2478 param->SetAttribute(DwString( attr ));
2479 mType.AddParameter( param );
2482 mType.SetModified();
2483 param->SetValue(DwString( val ));
2491 if (mNeedsAssembly) mMsg->Assemble();
2492 mNeedsAssembly =
false;
2494 mNeedsAssembly =
true;
2501 DwHeaders& header = mMsg->Headers();
2502 if (header.HasContentTransferEncoding())
2503 return header.ContentTransferEncoding().AsString().c_str();
2509 int KMMessage::contentTransferEncoding( DwEntity *entity )
const
2514 DwHeaders& header = entity->Headers();
2515 if ( header.HasContentTransferEncoding() )
2516 return header.ContentTransferEncoding().AsEnum();
2517 else return DwMime::kCteNull;
2522 void KMMessage::setContentTransferEncodingStr(
const TQCString& cteString,
2528 entity->Headers().ContentTransferEncoding().FromString( cteString );
2529 entity->Headers().ContentTransferEncoding().Parse();
2530 mNeedsAssembly =
true;
2535 void KMMessage::setContentTransferEncoding(
int cte, DwEntity *entity )
2540 entity->Headers().ContentTransferEncoding().FromEnum( cte );
2541 mNeedsAssembly =
true;
2548 return mMsg->Headers();
2555 mNeedsAssembly =
true;
2563 if ( mNeedsAssembly ) {
2565 mNeedsAssembly =
false;
2572 const DwString&
body = mMsg->Body().AsString();
2582 TQByteArray KMMessage::bodyDecodedBinary()
const
2585 const DwString& dwsrc = mMsg->Body().AsString();
2589 case DwMime::kCteBase64:
2590 DwDecodeBase64(dwsrc, dwstr);
2592 case DwMime::kCteQuotedPrintable:
2593 DwDecodeQuotedPrintable(dwsrc, dwstr);
2600 int len = dwstr.size();
2601 TQByteArray ba(len);
2602 memcpy(ba.data(),dwstr.data(),len);
2611 DwString dwsrc = mMsg->Body().AsString();
2615 case DwMime::kCteBase64:
2616 DwDecodeBase64(dwsrc, dwstr);
2618 case DwMime::kCteQuotedPrintable:
2619 DwDecodeQuotedPrintable(dwsrc, dwstr);
2641 TQValueList<int> allowedCtes;
2643 switch ( cf.type() ) {
2644 case CharFreq::SevenBitText:
2645 allowedCtes << DwMime::kCte7bit;
2646 case CharFreq::EightBitText:
2648 allowedCtes << DwMime::kCte8bit;
2649 case CharFreq::SevenBitData:
2650 if ( cf.printableRatio() > 5.0/6.0 ) {
2654 allowedCtes << DwMime::kCteQp;
2655 allowedCtes << DwMime::kCteBase64;
2657 allowedCtes << DwMime::kCteBase64;
2658 allowedCtes << DwMime::kCteQp;
2661 case CharFreq::EightBitData:
2662 allowedCtes << DwMime::kCteBase64;
2664 case CharFreq::None:
2674 if ( ( willBeSigned && cf.hasTrailingWhitespace() ) ||
2675 cf.hasLeadingFrom() ) {
2676 allowedCtes.remove( DwMime::kCte8bit );
2677 allowedCtes.remove( DwMime::kCte7bit );
2686 TQValueList<int> & allowedCte,
2694 CharFreq cf( aBuf );
2696 setCte( allowedCte[0], entity );
2697 setBodyEncodedBinary( aBuf, entity );
2703 TQValueList<int> & allowedCte,
2711 CharFreq cf( aBuf.data(), aBuf.size()-1 );
2713 setCte( allowedCte[0], entity );
2724 DwString dwSrc(aStr.data(), aStr.size()-1 );
2727 switch (cte( entity ))
2729 case DwMime::kCteBase64:
2730 DwEncodeBase64(dwSrc, dwResult);
2732 case DwMime::kCteQuotedPrintable:
2733 DwEncodeQuotedPrintable(dwSrc, dwResult);
2740 entity->Body().FromString(dwResult);
2741 mNeedsAssembly =
true;
2745 void KMMessage::setBodyEncodedBinary(
const TQByteArray& aStr, DwEntity *entity )
2750 DwString dwSrc(aStr.data(), aStr.size());
2753 switch ( cte( entity ) )
2755 case DwMime::kCteBase64:
2756 DwEncodeBase64( dwSrc, dwResult );
2758 case DwMime::kCteQuotedPrintable:
2759 DwEncodeQuotedPrintable( dwSrc, dwResult );
2766 entity->Body().FromString( dwResult );
2767 entity->Body().Parse();
2769 mNeedsAssembly =
true;
2777 mNeedsAssembly =
true;
2781 mMsg->Body().FromString(aStr);
2782 mNeedsAssembly =
true;
2786 mMsg->Body().FromString(aStr);
2787 mNeedsAssembly =
true;
2793 mMsg->Body().Parse();
2794 mNeedsAssembly =
true;
2810 TQPtrList< DwBodyPart > parts;
2816 && part->hasHeaders()
2817 && part->Headers().HasContentType()
2818 && part->Body().FirstBodyPart()
2819 && (DwMime::kTypeMultipart == part->Headers().ContentType().Type()) )
2821 parts.append( part );
2822 part = part->Body().FirstBodyPart();
2828 while (part && !(part->Next()) && !(parts.isEmpty()))
2830 part = parts.getLast();
2834 if (part && part->Body().Message() &&
2835 part->Body().Message()->Body().FirstBodyPart())
2837 part = part->Body().Message()->Body().FirstBodyPart();
2839 part = part->Next();
2850 return mMsg->Body().FirstBodyPart();
2857 DwBodyPart *curpart;
2858 TQPtrList< DwBodyPart > parts;
2865 while (curpart && !idx) {
2868 && curpart->hasHeaders()
2869 && curpart->Headers().HasContentType()
2870 && curpart->Body().FirstBodyPart()
2871 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2873 parts.append( curpart );
2874 curpart = curpart->Body().FirstBodyPart();
2877 if (curpart == aDwBodyPart)
2882 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2884 curpart = parts.getLast();
2888 curpart = curpart->Next();
2897 DwBodyPart *part, *curpart;
2898 TQPtrList< DwBodyPart > parts;
2905 while (curpart && !part) {
2908 && curpart->hasHeaders()
2909 && curpart->Headers().HasContentType()
2910 && curpart->Body().FirstBodyPart()
2911 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2913 parts.append( curpart );
2914 curpart = curpart->Body().FirstBodyPart();
2922 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2924 curpart = parts.getLast();
2928 curpart = curpart->Next();
2937 DwBodyPart *part, *curpart;
2938 TQPtrList< DwBodyPart > parts;
2944 while (curpart && !part) {
2947 && curpart->hasHeaders()
2948 && curpart->Headers().HasContentType()
2949 && curpart->Body().FirstBodyPart()
2950 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
2951 parts.append( curpart );
2952 curpart = curpart->Body().FirstBodyPart();
2958 if ( curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
2959 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
2960 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
2964 curpart->hasHeaders() &&
2965 curpart->Headers().HasContentType() &&
2966 curpart->Headers().ContentType().Type() == type &&
2967 curpart->Headers().ContentType().Subtype() == subtype) {
2972 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
2973 curpart = parts.getLast();
2977 curpart = curpart->Next();
2986 DwBodyPart *part, *curpart;
2987 TQPtrList< DwBodyPart > parts;
2993 while (curpart && !part) {
2996 && curpart->hasHeaders()
2997 && curpart->Headers().HasContentType()
2998 && curpart->Body().FirstBodyPart()
2999 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
3000 parts.append( curpart );
3001 curpart = curpart->Body().FirstBodyPart();
3007 if (curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
3008 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
3009 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
3013 curpart->hasHeaders() &&
3014 curpart->Headers().HasContentType() &&
3015 curpart->Headers().ContentType().TypeStr().c_str() == type &&
3016 curpart->Headers().ContentType().SubtypeStr().c_str() == subtype) {
3021 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
3022 curpart = parts.getLast();
3026 curpart = curpart->Next();
3033 void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart )
3045 TQCString additionalCTypeParams;
3046 if (headers.HasContentType())
3048 DwMediaType& ct = headers.ContentType();
3049 aPart->setOriginalContentTypeStr( ct.AsString().c_str() );
3050 aPart->setTypeStr(ct.TypeStr().c_str());
3051 aPart->setSubtypeStr(ct.SubtypeStr().c_str());
3052 DwParameter *param = ct.FirstParameter();
3055 if (!tqstricmp(param->Attribute().c_str(),
"charset")) {
3056 if (aPart->type() == DwMime::kTypeText) {
3057 aPart->setCharset(TQCString(param->Value().c_str()).lower());
3060 else if (!tqstrnicmp(param->Attribute().c_str(),
"name*", 5))
3061 aPart->setName(KMMsgBase::decodeRFC2231String(KMMsgBase::extractRFC2231HeaderField( param->Value().c_str(),
"name" )));
3063 additionalCTypeParams +=
';';
3064 additionalCTypeParams += param->AsString().c_str();
3066 param=param->Next();
3071 aPart->setTypeStr(
"text");
3072 aPart->setSubtypeStr(
"plain");
3074 aPart->setAdditionalCTypeParamStr( additionalCTypeParams );
3076 if (aPart->name().isEmpty())
3078 if (headers.HasContentType() && !headers.ContentType().Name().empty()) {
3079 aPart->setName(KMMsgBase::decodeRFC2047String(headers.
3080 ContentType().Name().c_str()) );
3081 }
else if (headers.HasSubject() && !headers.Subject().AsString().empty()) {
3082 aPart->setName( KMMsgBase::decodeRFC2047String(headers.
3083 Subject().AsString().c_str()) );
3088 if (headers.HasContentTransferEncoding())
3089 aPart->setCteStr(headers.ContentTransferEncoding().AsString().c_str());
3091 aPart->setCteStr(
"7bit");
3094 if (headers.HasContentDescription())
3095 aPart->setContentDescription( KMMsgBase::decodeRFC2047String(
3096 headers.ContentDescription().AsString().c_str() ) );
3098 aPart->setContentDescription(
"");
3101 if (headers.HasContentDisposition())
3102 aPart->setContentDisposition(headers.ContentDisposition().AsString().c_str());
3104 aPart->setContentDisposition(
"");
3116 if( aDwBodyPart && aDwBodyPart->hasHeaders() ) {
3121 TQString partId( aDwBodyPart->partId() );
3122 aPart->setPartSpecifier( partId );
3124 DwHeaders&
headers = aDwBodyPart->Headers();
3125 applyHeadersToMessagePart(
headers, aPart );
3129 aPart->setBody( aDwBodyPart->Body().AsString() );
3131 aPart->setBody( TQCString(
"") );
3134 if (
headers.HasContentId() ) {
3135 const TQCString contentId =
headers.ContentId().AsString().c_str();
3137 aPart->setContentId( contentId.mid( 1, contentId.length() - 2 ) );
3144 aPart->setTypeStr(
"");
3145 aPart->setSubtypeStr(
"");
3146 aPart->setCteStr(
"");
3150 aPart->setContentDescription(
"");
3151 aPart->setContentDisposition(
"");
3152 aPart->setBody(TQCString(
""));
3153 aPart->setContentId(
"");
3165 if ( DwBodyPart *part =
dwBodyPart( aIdx ) ) {
3167 if( aPart->name().isEmpty() )
3168 aPart->setName( i18n(
"Attachment: %1").arg( aIdx ) );
3176 mMsg->Body().DeleteBodyParts();
3184 DwBodyPart *dwpart = findPart( partIndex );
3188 if ( !part.isComplete() )
3191 DwBody *parentNode =
dynamic_cast<DwBody*
>( dwpart->Parent() );
3194 parentNode->RemoveBodyPart( dwpart );
3197 KMMessagePart dummyPart;
3198 dummyPart.duplicate( part );
3199 TQString comment = i18n(
"This attachment has been deleted.");
3200 if ( !part.fileName().isEmpty() )
3201 comment = i18n(
"The attachment '%1' has been deleted." ).arg( part.fileName() );
3202 dummyPart.setContentDescription( comment );
3203 dummyPart.setBodyEncodedBinary( TQByteArray() );
3204 TQCString cd = dummyPart.contentDisposition();
3205 if ( cd.find(
"inline", 0,
false ) == 0 ) {
3206 cd.replace( 0, 10,
"attachment" );
3207 dummyPart.setContentDisposition( cd );
3208 }
else if ( cd.isEmpty() ) {
3209 dummyPart.setContentDisposition(
"attachment" );
3212 parentNode->AddBodyPart( newDwPart );
3213 getTopLevelPart()->Assemble();
3220 DwBodyPart* part = DwBodyPart::NewBodyPart(emptyString, 0);
3225 TQCString
charset = aPart->charset();
3226 TQCString type = aPart->typeStr();
3227 TQCString subtype = aPart->subtypeStr();
3228 TQCString cte = aPart->cteStr();
3229 TQCString contDesc = aPart->contentDescriptionEncoded();
3230 TQCString contDisp = aPart->contentDisposition();
3231 TQCString name = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->name(),
charset );
3232 bool RFC2231encoded = aPart->name() != TQString(name);
3233 TQCString paramAttr = aPart->parameterAttribute();
3235 DwHeaders&
headers = part->Headers();
3237 DwMediaType& ct =
headers.ContentType();
3238 if (!type.isEmpty() && !subtype.isEmpty())
3240 ct.SetTypeStr(type.data());
3241 ct.SetSubtypeStr(subtype.data());
3244 param=
new DwParameter;
3245 param->SetAttribute(
"charset");
3246 param->SetValue(
charset.data());
3247 ct.AddParameter(param);
3251 TQCString additionalParam = aPart->additionalCTypeParamStr();
3252 if( !additionalParam.isEmpty() )
3255 DwString parA, parV;
3257 iL = additionalParam.length();
3259 i2 = additionalParam.find(
';', i1,
false);
3265 parAV = additionalParam.mid( i1, (i2-i1) );
3266 iM = parAV.find(
'=');
3269 parA = parAV.left( iM ).data();
3270 parV = parAV.right( parAV.length() - iM - 1 ).data();
3271 if( (
'"' == parV.at(0)) && (
'"' == parV.at(parV.length()-1)) )
3274 parV.erase( parV.length()-1 );
3279 parA = parAV.data();
3283 param =
new DwParameter;
3284 param->SetAttribute( parA );
3285 param->SetValue( parV );
3286 ct.AddParameter( param );
3289 i2 = additionalParam.find(
';', i1,
false);
3293 if ( !name.isEmpty() ) {
3296 DwParameter *nameParam;
3297 nameParam =
new DwParameter;
3298 nameParam->SetAttribute(
"name*");
3299 nameParam->SetValue(name.data(),
true);
3300 ct.AddParameter(nameParam);
3302 ct.SetName(name.data());
3306 if (!paramAttr.isEmpty())
3308 TQCString paramValue;
3309 paramValue = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->parameterValue(),
charset );
3310 DwParameter *param =
new DwParameter;
3311 if (aPart->parameterValue() != TQString(paramValue))
3313 param->SetAttribute((paramAttr +
'*').data());
3314 param->SetValue(paramValue.data(),
true);
3316 param->SetAttribute(paramAttr.data());
3317 param->SetValue(paramValue.data());
3319 ct.AddParameter(param);
3323 headers.Cte().FromString(cte);
3325 if (!contDesc.isEmpty())
3326 headers.ContentDescription().FromString(contDesc);
3328 if (!contDisp.isEmpty())
3329 headers.ContentDisposition().FromString(contDisp);
3331 const DwString bodyStr = aPart->dwBody();
3332 if (!bodyStr.empty())
3333 part->Body().FromString(bodyStr);
3335 part->Body().FromString(
"");
3337 if (!aPart->partSpecifier().isNull())
3338 part->SetPartId( aPart->partSpecifier().latin1() );
3340 if (aPart->decodedSize() > 0)
3341 part->SetBodySize( aPart->decodedSize() );
3350 mMsg->Body().AddBodyPart( aDwPart );
3351 mNeedsAssembly =
true;
3366 TQDateTime datetime = TQDateTime::currentDateTime();
3369 msgIdStr =
'<' + datetime.toString(
"yyyyMMddhhmm.sszzz" );
3371 TQString msgIdSuffix;
3372 TDEConfigGroup general( KMKernel::config(),
"General" );
3374 if( general.readBoolEntry(
"useCustomMessageIdSuffix",
false ) )
3375 msgIdSuffix = general.readEntry(
"myMessageIdSuffix" );
3377 if( !msgIdSuffix.isEmpty() )
3378 msgIdStr +=
'@' + msgIdSuffix;
3380 msgIdStr +=
'.' + KPIM::encodeIDN( addr );
3391 TQCString result( 1 + 6*(src.size()-1) );
3393 TQCString::ConstIterator s = src.begin();
3394 TQCString::Iterator d = result.begin();
3457 result.truncate( d - result.begin() );
3465 result = TQString::fromLatin1( KMMsgBase::encodeRFC2047String( str,
3467 result = KURL::encode_string( result );
3476 result = KURL::decode_string( url );
3477 result = KMMsgBase::decodeRFC2047String( result.latin1() );
3487 if ( aStr.isEmpty() )
3498 TQCString angleAddress;
3499 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3500 bool inQuotedString =
false;
3501 int commentLevel = 0;
3503 for (
const char* p = aStr.data(); *p; ++p ) {
3504 switch ( context ) {
3507 case '"' : inQuotedString = !inQuotedString;
3509 case '(' :
if ( !inQuotedString ) {
3510 context = InComment;
3516 case '<' :
if ( !inQuotedString ) {
3517 context = InAngleAddress;
3527 case ',' :
if ( !inQuotedString ) {
3529 if ( !result.isEmpty() )
3531 name = name.stripWhiteSpace();
3532 comment = comment.stripWhiteSpace();
3533 angleAddress = angleAddress.stripWhiteSpace();
3542 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3547 else if ( !name.isEmpty() ) {
3550 else if ( !comment.isEmpty() ) {
3553 else if ( !angleAddress.isEmpty() ) {
3554 result += angleAddress;
3557 comment = TQCString();
3558 angleAddress = TQCString();
3563 default : name += *p;
3569 case '(' : ++commentLevel;
3572 case ')' : --commentLevel;
3573 if ( commentLevel == 0 ) {
3585 default : comment += *p;
3589 case InAngleAddress : {
3591 case '"' : inQuotedString = !inQuotedString;
3594 case '>' :
if ( !inQuotedString ) {
3605 default : angleAddress += *p;
3611 if ( !result.isEmpty() )
3613 name = name.stripWhiteSpace();
3614 comment = comment.stripWhiteSpace();
3615 angleAddress = angleAddress.stripWhiteSpace();
3621 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3626 else if ( !name.isEmpty() ) {
3629 else if ( !comment.isEmpty() ) {
3632 else if ( !angleAddress.isEmpty() ) {
3633 result += angleAddress;
3646 if ( aStr.isEmpty() )
3657 TQString angleAddress;
3658 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3659 bool inQuotedString =
false;
3660 int commentLevel = 0;
3663 unsigned int strLength(aStr.length());
3664 for ( uint index = 0; index < strLength; ++index ) {
3666 switch ( context ) {
3668 switch ( ch.latin1() ) {
3669 case '"' : inQuotedString = !inQuotedString;
3671 case '(' :
if ( !inQuotedString ) {
3672 context = InComment;
3678 case '<' :
if ( !inQuotedString ) {
3679 context = InAngleAddress;
3686 if ( index < aStr.length() )
3687 name += aStr[index];
3689 case ',' :
if ( !inQuotedString ) {
3691 if ( !result.isEmpty() )
3693 name = name.stripWhiteSpace();
3694 comment = comment.stripWhiteSpace();
3695 angleAddress = angleAddress.stripWhiteSpace();
3704 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3709 else if ( !name.isEmpty() ) {
3712 else if ( !comment.isEmpty() ) {
3715 else if ( !angleAddress.isEmpty() ) {
3716 result += angleAddress;
3719 comment = TQString();
3720 angleAddress = TQString();
3725 default : name += ch;
3730 switch ( ch.latin1() ) {
3731 case '(' : ++commentLevel;
3734 case ')' : --commentLevel;
3735 if ( commentLevel == 0 ) {
3744 if ( index < aStr.length() )
3745 comment += aStr[index];
3747 default : comment += ch;
3751 case InAngleAddress : {
3752 switch ( ch.latin1() ) {
3753 case '"' : inQuotedString = !inQuotedString;
3756 case '>' :
if ( !inQuotedString ) {
3764 if ( index < aStr.length() )
3765 angleAddress += aStr[index];
3767 default : angleAddress += ch;
3773 if ( !result.isEmpty() )
3775 name = name.stripWhiteSpace();
3776 comment = comment.stripWhiteSpace();
3777 angleAddress = angleAddress.stripWhiteSpace();
3783 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3788 else if ( !name.isEmpty() ) {
3791 else if ( !comment.isEmpty() ) {
3794 else if ( !angleAddress.isEmpty() ) {
3795 result += angleAddress;
3808 unsigned int strLength(str.length());
3809 result.reserve( 6*strLength );
3810 for(
unsigned int i = 0; i < strLength; ++i )
3811 switch ( str[i].latin1() ) {
3825 if ( !removeLineBreaks )
3842 if( aEmail.isEmpty() )
3845 TQStringList addressList = KPIM::splitEmailAddrList( aEmail );
3848 for( TQStringList::ConstIterator it = addressList.begin();
3849 ( it != addressList.end() );
3851 if( !(*it).isEmpty() ) {
3854 TQString name, mail;
3855 KPIM::getNameAndMail( *it, name, mail );
3857 TQString prettyStripped;
3858 if ( name.stripWhiteSpace().isEmpty() ) {
3860 prettyStripped = mail;
3862 pretty = KPIM::quoteNameIfNecessary( name ) +
" <" + mail +
">";
3863 prettyStripped = name;
3867 result +=
"<a href=\"mailto:"
3869 +
"\" "+cssStyle+
">";
3885 result.truncate( result.length() - 2 );
3895 const TQStringList& list )
3897 TQStringList addresses( list );
3898 TQString addrSpec( KPIM::getEmailAddress( address ) );
3899 for ( TQStringList::Iterator it = addresses.begin();
3900 it != addresses.end(); ) {
3901 if ( kasciistricmp( addrSpec.utf8().data(),
3902 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 ) {
3903 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3905 it = addresses.remove( it );
3918 TQStringList addresses = list;
3919 for( TQStringList::Iterator it = addresses.begin();
3920 it != addresses.end(); ) {
3921 kdDebug(5006) <<
"Check whether " << *it <<
" is one of my addresses"
3923 if( kmkernel->identityManager()->thatIsMe( KPIM::getEmailAddress( *it ) ) ) {
3924 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3926 it = addresses.remove( it );
3938 const TQStringList& addresses )
3940 TQString addrSpec = KPIM::getEmailAddress( address );
3941 for( TQStringList::ConstIterator it = addresses.begin();
3942 it != addresses.end(); ++it ) {
3943 if ( kasciistricmp( addrSpec.utf8().data(),
3944 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 )
3955 if ( recipients.isEmpty() )
3958 TQStringList recipientList = KPIM::splitEmailAddrList( recipients );
3960 TQString expandedRecipients;
3961 for ( TQStringList::Iterator it = recipientList.begin();
3962 it != recipientList.end(); ++it ) {
3963 if ( !expandedRecipients.isEmpty() )
3964 expandedRecipients +=
", ";
3965 TQString receiver = (*it).stripWhiteSpace();
3968 TQString expandedList = KAddrBookExternal::expandDistributionList( receiver );
3969 if ( !expandedList.isEmpty() ) {
3970 expandedRecipients += expandedList;
3975 TQString expandedNickName = KabcBridge::expandNickName( receiver );
3976 if ( !expandedNickName.isEmpty() ) {
3977 expandedRecipients += expandedNickName;
3983 if ( receiver.find(
'@') == -1 ) {
3984 TDEConfigGroup general( KMKernel::config(),
"General" );
3985 TQString defaultdomain = general.readEntry(
"Default domain" );
3986 if( !defaultdomain.isEmpty() ) {
3987 expandedRecipients += receiver +
"@" + defaultdomain;
3994 expandedRecipients += receiver;
3997 return expandedRecipients;
4005 if ( loginName.isEmpty() )
4008 char hostnameC[256];
4010 hostnameC[255] =
'\0';
4012 if ( gethostname( hostnameC, 255 ) )
4013 hostnameC[0] =
'\0';
4014 TQString address = loginName;
4016 address += TQString::fromLocal8Bit( hostnameC );
4019 const KUser user( loginName );
4020 if ( user.isValid() ) {
4021 TQString fullName = user.fullName();
4022 if ( fullName.find( TQRegExp(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) ) != -1 )
4023 address =
'"' + fullName.replace(
'\\',
"\\" ).replace(
'"',
"\\" )
4024 +
"\" <" + address +
'>';
4026 address = fullName +
" <" + address +
'>';
4035 KMMsgBase::readConfig();
4037 TDEConfig *config=KMKernel::config();
4038 TDEConfigGroupSaver saver(config,
"General");
4040 config->setGroup(
"General");
4042 int languageNr = config->readNumEntry(
"reply-current-language",0);
4045 TDEConfigGroupSaver saver(config, TQString(
"KMMessage #%1").arg(languageNr));
4046 sReplyLanguage = config->readEntry(
"language",TDEGlobal::locale()->language());
4047 sReplyStr = config->readEntry(
"phrase-reply",
4048 i18n(
"On %D, you wrote:"));
4049 sReplyAllStr = config->readEntry(
"phrase-reply-all",
4050 i18n(
"On %D, %F wrote:"));
4051 sForwardStr = config->readEntry(
"phrase-forward",
4052 i18n(
"Forwarded Message"));
4053 sIndentPrefixStr = config->readEntry(
"indent-prefix",
">%_");
4057 TDEConfigGroupSaver saver(config,
"Composer");
4058 sSmartQuote = GlobalSettings::self()->smartQuote();
4059 sWordWrap = GlobalSettings::self()->wordWrap();
4060 sWrapCol = GlobalSettings::self()->lineWrapWidth();
4061 if ((sWrapCol == 0) || (sWrapCol > 78))
4066 sPrefCharsets = config->readListEntry(
"pref-charsets");
4070 TDEConfigGroupSaver saver(config,
"Reader");
4071 sHeaderStrategy = HeaderStrategy::create( config->readEntry(
"header-set-displayed",
"rich" ) );
4079 if (!sPrefCharsets.isEmpty())
4080 retval = sPrefCharsets[0].latin1();
4082 if (retval.isEmpty() || (retval ==
"locale")) {
4083 retval = TQCString(kmkernel->networkCodec()->mimeName());
4084 kasciitolower( retval.data() );
4087 if (retval ==
"jisx0208.1983-0") retval =
"iso-2022-jp";
4088 else if (retval ==
"ksc5601.1987-0") retval =
"euc-kr";
4094 return sPrefCharsets;
4100 if ( mMsg->Headers().HasContentType() ) {
4101 DwMediaType &mType=mMsg->Headers().ContentType();
4103 DwParameter *param=mType.FirstParameter();
4105 if (!kasciistricmp(param->Attribute().c_str(),
"charset"))
4106 return param->Value().c_str();
4107 else param=param->Next();
4116 kdWarning( type() != DwMime::kTypeText )
4117 <<
"KMMessage::setCharset(): trying to set a charset for a non-textual mimetype." << endl
4118 <<
"Fix this caller:" << endl
4119 <<
"====================================================================" << endl
4120 << kdBacktrace( 5 ) << endl
4121 <<
"====================================================================" << endl;
4126 DwMediaType &mType = entity->Headers().ContentType();
4128 DwParameter *param = mType.FirstParameter();
4132 if ( !kasciistricmp( param->Attribute().c_str(),
"charset" ) )
4135 param = param->Next();
4138 param =
new DwParameter;
4139 param->SetAttribute(
"charset" );
4140 mType.AddParameter( param );
4143 mType.SetModified();
4145 TQCString lowerCharset =
charset;
4146 kasciitolower( lowerCharset.data() );
4147 param->SetValue( DwString( lowerCharset ) );
4155 if (mStatus == aStatus)
4157 KMMsgBase::setStatus(aStatus, idx);
4162 if( mEncryptionState == s )
4164 mEncryptionState = s;
4166 KMMsgBase::setEncryptionState(s, idx);
4171 if( mSignatureState == s )
4173 mSignatureState = s;
4175 KMMsgBase::setSignatureState(s, idx);
4178 void KMMessage::setMDNSentState( KMMsgMDNSentState status,
int idx )
4180 if ( mMDNSentState ==
status )
4183 status = KMMsgMDNStateUnknown;
4186 KMMsgBase::setMDNSentState(
status, idx );
4192 Q_ASSERT( aStatus == KMMsgStatusReplied
4193 || aStatus == KMMsgStatusForwarded
4194 || aStatus == KMMsgStatusDeleted );
4196 TQString message =
headerField(
"X-KMail-Link-Message" );
4197 if ( !message.isEmpty() )
4199 TQString type =
headerField(
"X-KMail-Link-Type" );
4200 if ( !type.isEmpty() )
4203 message += TQString::number( aMsg->getMsgSerNum() );
4204 if ( aStatus == KMMsgStatusReplied )
4206 else if ( aStatus == KMMsgStatusForwarded )
4208 else if ( aStatus == KMMsgStatusDeleted )
4219 *reStatus = KMMsgStatusUnknown;
4221 TQString message =
headerField(
"X-KMail-Link-Message");
4223 message = message.section(
',', n, n);
4224 type = type.section(
',', n, n);
4226 if ( !message.isEmpty() && !type.isEmpty() ) {
4227 *retMsgSerNum = message.toULong();
4228 if ( type ==
"reply" )
4229 *reStatus = KMMsgStatusReplied;
4230 else if ( type ==
"forward" )
4231 *reStatus = KMMsgStatusForwarded;
4232 else if ( type ==
"deleted" )
4233 *reStatus = KMMsgStatusDeleted;
4240 if ( !part )
return 0;
4241 DwBodyPart* current;
4243 if ( part->partId() == partSpecifier )
4247 if ( part->hasHeaders() &&
4248 part->Headers().HasContentType() &&
4249 part->Body().FirstBodyPart() &&
4250 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) &&
4251 (current =
findDwBodyPart( part->Body().FirstBodyPart(), partSpecifier )) )
4257 if ( part->Body().Message() &&
4258 part->Body().Message()->Body().FirstBodyPart() &&
4259 (current =
findDwBodyPart( part->Body().Message()->Body().FirstBodyPart(),
4272 if ( !data.data() || !data.size() )
4275 DwString content( data.data(), data.size() );
4277 partSpecifier !=
"0" &&
4278 partSpecifier !=
"TEXT" )
4280 TQString specifier = partSpecifier;
4281 if ( partSpecifier.endsWith(
".HEADER") ||
4282 partSpecifier.endsWith(
".MIME") ) {
4284 specifier = partSpecifier.section(
'.', 0, -2 );
4289 kdDebug(5006) <<
"KMMessage::updateBodyPart " << specifier << endl;
4292 kdWarning(5006) <<
"KMMessage::updateBodyPart - can not find part "
4293 << specifier << endl;
4296 if ( partSpecifier.endsWith(
".MIME") )
4300 content.resize( TQMAX( content.length(), 2 ) - 2 );
4303 mLastUpdated->Headers().DeleteAllFields();
4304 mLastUpdated->Headers().FromString( content );
4305 mLastUpdated->Headers().Parse();
4306 }
else if ( partSpecifier.endsWith(
".HEADER") )
4309 mLastUpdated->Body().Message()->Headers().FromString( content );
4310 mLastUpdated->Body().Message()->Headers().Parse();
4313 mLastUpdated->Body().FromString( content );
4314 TQString parentSpec = partSpecifier.section(
'.', 0, -2 );
4315 if ( !parentSpec.isEmpty() )
4318 if ( parent && parent->hasHeaders() && parent->Headers().HasContentType() )
4320 const DwMediaType& contentType = parent->Headers().ContentType();
4321 if ( contentType.Type() == DwMime::kTypeMessage &&
4322 contentType.Subtype() == DwMime::kSubtypeRfc822 )
4326 parent->Body().Message()->Body().FromString( content );
4335 if ( partSpecifier ==
"TEXT" )
4337 mMsg->Body().FromString( content );
4338 mMsg->Body().Parse();
4340 mNeedsAssembly =
true;
4341 if (! partSpecifier.endsWith(
".HEADER") )
4348 void KMMessage::updateInvitationState()
4350 if ( mMsg && mMsg->hasHeaders() && mMsg->Headers().HasContentType() ) {
4351 TQString cntType = mMsg->Headers().ContentType().TypeStr().c_str();
4353 cntType += mMsg->Headers().ContentType().SubtypeStr().c_str();
4354 if ( cntType.lower() ==
"text/calendar" ) {
4359 setStatus( KMMsgStatusHasNoInvitation );
4364 void KMMessage::updateAttachmentState( DwBodyPart* part )
4376 bool filenameEmpty =
true;
4377 if ( part->hasHeaders() ) {
4378 if ( part->Headers().HasContentDisposition() ) {
4379 DwDispositionType cd = part->Headers().ContentDisposition();
4380 filenameEmpty = cd.Filename().empty();
4381 if ( filenameEmpty ) {
4383 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField( cd.AsString().c_str(),
"filename" ) ).isEmpty();
4389 if ( filenameEmpty && part->Headers().HasContentType() ) {
4390 DwMediaType contentType = part->Headers().ContentType();
4391 filenameEmpty = contentType.Name().empty();
4392 if ( filenameEmpty ) {
4394 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField(
4395 contentType.AsString().c_str(),
"name" ) ).isEmpty();
4400 if ( part->hasHeaders() &&
4401 ( ( part->Headers().HasContentDisposition() &&
4402 !part->Headers().ContentDisposition().Filename().empty() ) ||
4403 ( part->Headers().HasContentType() &&
4404 !filenameEmpty ) ) )
4407 if ( !part->Headers().HasContentType() ||
4408 ( part->Headers().HasContentType() &&
4409 part->Headers().ContentType().Subtype() != DwMime::kSubtypePgpSignature &&
4410 part->Headers().ContentType().Subtype() != DwMime::kSubtypePkcs7Signature ) )
4418 if ( part->hasHeaders() &&
4419 part->Headers().HasContentType() &&
4420 part->Body().FirstBodyPart() &&
4421 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) )
4423 updateAttachmentState( part->Body().FirstBodyPart() );
4427 if ( part->Body().Message() &&
4428 part->Body().Message()->Body().FirstBodyPart() )
4430 updateAttachmentState( part->Body().Message()->Body().FirstBodyPart() );
4435 updateAttachmentState( part->Next() );
4436 else if ( attachmentState() == KMMsgAttachmentUnknown )
4443 if ( encoding.isEmpty() )
4445 const TQTextCodec *
codec = KMMsgBase::codecForName( encoding );
4447 TQValueList<int> dummy;
4454 const TQTextCodec * c = mOverrideCodec;
4457 c = KMMsgBase::codecForName(
charset() );
4461 c = KMMsgBase::codecForName( GlobalSettings::self()->fallbackCharacterEncoding().latin1() );
4466 c = kmkernel->networkCodec();
4483 TQCString str( KPIM::getFirstEmailAddress(
rawHeaderField(
"From") ) );
4484 if ( str.isEmpty() )
4485 str =
"unknown@unknown.invalid";
4488 time_t t = ::time( 0 );
4490 const int len =
dateStr.length();
4494 return "From " + str +
" " +
dateStr +
"\n";
4499 sPendingDeletes <<
this;
4502 DwBodyPart* KMMessage::findPart(
int index )
4505 return findPartInternal( getTopLevelPart(), index, accu );
4508 DwBodyPart* KMMessage::findPartInternal(DwEntity * root,
int index,
int & accu)
4513 DwBodyPart *current =
dynamic_cast<DwBodyPart*
>( root );
4514 if ( index == accu )
4517 if ( root->Body().FirstBodyPart() )
4518 rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
4519 if ( !rv && current && current->Next() )
4520 rv = findPartInternal( current->Next(), index, accu );
4521 if ( !rv && root->Body().Message() )
4522 rv = findPartInternal( root->Body().Message(), index, accu );