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 <kasciistringtools.h>
33 #include <kpgpblock.h>
34 #include <kaddrbook.h>
36 #include <tdeapplication.h>
37 #include <tdeglobalsettings.h>
39 #include <tdeconfig.h>
40 #include <tdehtml_part.h>
43 #include <kasciistricmp.h>
46 #include <tqtextcodec.h>
47 #include <tqmessagebox.h>
48 #include <kmime_util.h>
49 #include <kmime_charfreq.h>
51 #include <kmime_header_parsing.h>
52 using KMime::HeaderParsing::parseAddressList;
53 using namespace KMime::Types;
55 #include <mimelib/body.h>
56 #include <mimelib/field.h>
57 #include <mimelib/mimepp.h>
58 #include <mimelib/string.h>
62 #include <tdelocale.h>
68 #include <tdemessagebox.h>
71 using namespace KMime;
73 static DwString emptyString(
"");
76 static TQString sReplyLanguage, sReplyStr, sReplyAllStr, sIndentPrefixStr;
77 static bool sSmartQuote,
80 static TQStringList sPrefCharsets;
82 TQString KMMessage::sForwardStr;
83 const HeaderStrategy * KMMessage::sHeaderStrategy = HeaderStrategy::rich();
85 static void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart );
87 TQValueList<KMMessage*> KMMessage::sPendingDeletes;
95 mNeedsAssembly =
true;
111 mFolderOffset =
msgInfo.folderOffset();
113 mEncryptionState =
msgInfo.encryptionState();
114 mSignatureState =
msgInfo.signatureState();
115 mMDNSentState =
msgInfo.mdnSentState();
117 mFileName =
msgInfo.fileName();
132 void KMMessage::init( DwMessage* aMsg )
134 mNeedsAssembly =
false;
138 mMsg =
new DwMessage;
147 mStatus = KMMsgStatusNew;
148 mEncryptionState = KMMsgEncryptionStateUnknown;
149 mSignatureState = KMMsgSignatureStateUnknown;
150 mMDNSentState = KMMsgMDNStateUnknown;
159 void KMMessage::assign(
const KMMessage& other )
161 MessageProperty::forget(
this );
163 delete mUnencryptedMsg;
165 mNeedsAssembly =
true;
167 mMsg =
new DwMessage( *(other.mMsg) );
170 mOverrideCodec = other.mOverrideCodec;
171 mDecodeHTML = other.mDecodeHTML;
172 mMsgSize = other.mMsgSize;
173 mMsgLength = other.mMsgLength;
174 mFolderOffset = other.mFolderOffset;
175 mStatus = other.mStatus;
176 mEncryptionState = other.mEncryptionState;
177 mSignatureState = other.mSignatureState;
178 mMDNSentState = other.mMDNSentState;
179 mIsParsed = other.mIsParsed;
185 setDrafts( other.
drafts() );
196 kmkernel->undoStack()->msgDestroyed(
this );
201 void KMMessage::setReferences(
const TQCString& aStr)
203 if (aStr.isNull())
return;
204 mMsg->Headers().References().FromString(aStr);
205 mNeedsAssembly =
true;
212 DwHeaders& header = mMsg->Headers();
213 if (header.HasMessageId())
227 MessageProperty::setSerialCache(
this, newMsgSerNum );
240 return MessageProperty::transferInProgress( getMsgSerNum() );
247 MessageProperty::setTransferInProgress( getMsgSerNum(), value, force );
249 sPendingDeletes.remove(
this );
251 int idx = parent()->find(
this );
253 parent()->removeMsg( idx );
262 return headerField(
"Priority" ).contains(
"urgent",
false )
269 delete mUnencryptedMsg;
270 mUnencryptedMsg = unencrypted;
276 TQString& brokenAddress )
278 if ( aStr.isEmpty() ) {
279 return KPIM::AddressEmpty;
282 TQStringList list = KPIM::splitEmailAddrList( aStr );
283 for( TQStringList::const_iterator it = list.begin(); it != list.end(); ++it ) {
284 KPIM::EmailParseResult errorCode = KPIM::isValidEmailAddress( *it );
285 if ( errorCode != KPIM::AddressOk ) {
286 brokenAddress = ( *it );
290 return KPIM::AddressOk;
298 mNeedsAssembly =
false;
301 return mMsg->AsString();
305 const DwMessage* KMMessage::asDwMessage()
309 mNeedsAssembly =
false;
323 KMMessage msg(
new DwMessage( *this->mMsg ) );
331 KMMessage msg(
new DwMessage( *this->mMsg ) );
355 char str[2] = { 0, 0 };
367 str[0] =
static_cast<char>( mdnSentState() );
372 mNeedsAssembly =
false;
373 mMsg->Headers().Assemble();
374 mMsg->Assemble( mMsg->Headers(),
382 DwHeaders& header = mMsg->Headers();
384 if ( header.AsString().empty() )
386 return TQString::fromLatin1( header.AsString().c_str() );
393 return mMsg->Headers().ContentType();
396 void KMMessage::fromByteArray(
const TQByteArray & ba,
bool setStatus ) {
400 void KMMessage::fromString(
const TQCString & str,
bool aSeStatus ) {
407 mMsg =
new DwMessage;
408 mMsg->FromString( str );
413 setEncryptionStateChar(
headerField(
"X-KMail-EncryptionState").at(0) );
414 setSignatureStateChar(
headerField(
"X-KMail-SignatureState").at(0) );
415 setMDNSentState(
static_cast<KMMsgMDNSentState
>(
headerField(
"X-KMail-MDN-Sent").at(0).latin1() ) );
417 if ( invitationState() == KMMsgInvitationUnknown &&
readyToShow() )
418 updateInvitationState();
419 if ( attachmentState() == KMMsgAttachmentUnknown &&
readyToShow() )
420 updateAttachmentState();
422 mNeedsAssembly =
false;
430 TQString result, str;
437 unsigned int strLength(aStr.length());
438 for (uint i=0; i<strLength;) {
448 result += KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
449 date(), sReplyLanguage,
false );
455 result += fromStrip();
461 for (j=0; str[j]>
' '; j++)
463 unsigned int strLength(str.length());
464 for (; j < strLength && str[j] <=
' '; j++)
509 static void removeTrailingSpace( TQString &line )
511 int i = line.length()-1;
512 while( (i >= 0) && ((line[i] ==
' ') || (line[i] ==
'\t')))
517 static TQString splitLine( TQString &line)
519 removeTrailingSpace( line );
522 int l = line.length();
529 if ((c ==
'>') || (c ==
':') || (c ==
'|'))
531 else if ((c !=
' ') && (c !=
'\t'))
542 TQString result = line.left(j);
547 TQString result = line.left(j);
552 static TQString flowText(TQString &text,
const TQString& indent,
int maxLength)
557 return indent+
"<NULL>\n";
563 if ((
int) text.length() > maxLength)
566 while( (i >= 0) && (text[i] !=
' '))
581 TQString line = text.left(i);
582 if (i < (
int) text.length())
587 result += indent + line +
'\n';
594 static bool flushPart(TQString &msg, TQStringList &part,
595 const TQString &indent,
int maxLength)
597 maxLength -= indent.length();
598 if (maxLength < 20) maxLength = 20;
601 while ((part.begin() != part.end()) && part.last().isEmpty())
603 part.remove(part.fromLast());
607 for(TQStringList::Iterator it2 = part.begin();
611 TQString line = (*it2);
616 msg += flowText(text, indent, maxLength);
617 msg += indent +
'\n';
624 text +=
' '+line.stripWhiteSpace();
626 if (((
int) text.length() < maxLength) || ((
int) line.length() < (maxLength-10)))
627 msg += flowText(text, indent, maxLength);
631 msg += flowText(text, indent, maxLength);
633 bool appendEmptyLine =
true;
635 appendEmptyLine =
false;
638 return appendEmptyLine;
641 static TQString stripSignature(
const TQString & msg,
bool clearSigned ) {
643 return msg.left( msg.findRev( TQRegExp(
"\n--\\s?\n" ) ) );
645 return msg.left( msg.findRev(
"\n-- \n" ) );
652 bool firstPart =
true;
655 const TQStringList lines = TQStringList::split(
'\n', msg,
true);
658 for(TQStringList::const_iterator it = lines.begin();
664 const TQString indent = splitLine( line );
669 part.append(TQString());
679 if (oldIndent != indent)
683 if (part.count() && (oldIndent.length() < indent.length()))
685 TQStringList::Iterator it2 = part.fromLast();
686 while( (it2 != part.end()) && (*it2).isEmpty())
689 if ((it2 != part.end()) && ((*it2).endsWith(
":")))
691 fromLine = oldIndent + (*it2) +
'\n';
695 if (flushPart( result, part, oldIndent, maxLineLength))
697 if (oldIndent.length() > indent.length())
698 result += indent +
'\n';
700 result += oldIndent +
'\n';
702 if (!fromLine.isEmpty())
710 flushPart( result, part, oldIndent, maxLineLength);
717 TQCString& parsedString,
718 const TQTextCodec*& codec,
724 partNode * curNode = root->findType( DwMime::kTypeText,
725 DwMime::kSubtypeUnknown,
728 kdDebug(5006) <<
"\n\n======= KMMessage::parseTextStringFromDwPart() - "
729 << ( curNode ?
"text part found!\n" :
"sorry, no text node!\n" ) << endl;
731 isHTML = DwMime::kSubtypeHtml == curNode->subType();
733 ObjectTreeParser otp( 0, 0,
true,
false,
true );
734 otp.parseObjectTree( curNode );
735 parsedString = otp.rawReplyString();
736 codec = curNode->msgPart().codec();
743 bool allowDecryption )
const
746 Q_ASSERT( root->processed() );
748 TQCString parsedString;
750 const TQTextCodec *
codec = 0;
752 if ( !root )
return TQString();
755 if ( mOverrideCodec || !
codec )
758 if ( parsedString.isEmpty() )
761 bool clearSigned =
false;
765 if ( allowDecryption ) {
766 TQPtrList<Kpgp::Block> pgpBlocks;
767 TQStrList nonPgpBlocks;
768 if ( Kpgp::Module::prepareMessageForDecryption( parsedString,
773 if ( pgpBlocks.count() == 1 ) {
774 Kpgp::Block * block = pgpBlocks.first();
775 if ( block->type() == Kpgp::PgpMessageBlock ||
776 block->type() == Kpgp::ClearsignedBlock ) {
777 if ( block->type() == Kpgp::PgpMessageBlock ) {
786 result =
codec->toUnicode( nonPgpBlocks.first() )
787 +
codec->toUnicode( block->text() )
788 +
codec->toUnicode( nonPgpBlocks.last() );
794 if ( result.isEmpty() ) {
795 result =
codec->toUnicode( parsedString );
796 if ( result.isEmpty() )
801 if ( isHTML && mDecodeHTML ) {
802 TDEHTMLPart htmlPart;
803 htmlPart.setOnlyLocalReferences(
true );
804 htmlPart.setMetaRefreshEnabled(
false );
805 htmlPart.setPluginsEnabled(
false );
806 htmlPart.setJScriptEnabled(
false );
807 htmlPart.setJavaEnabled(
false );
809 htmlPart.write( result );
811 htmlPart.selectAll();
812 result = htmlPart.selectedText();
816 if ( aStripSignature )
817 return stripSignature( result, clearSigned );
826 partNode *root = partNode::fromMessage(
this );
830 ObjectTreeParser otp;
831 otp.parseObjectTree( root );
838 const TQString& aIndentStr,
839 const TQString& selection ,
840 bool aStripSignature ,
841 bool allowDecryption )
const
843 TQString content = selection.isEmpty() ?
844 asPlainText( aStripSignature, allowDecryption ) : selection ;
847 const int firstNonWS = content.find( TQRegExp(
"\\S" ) );
848 const int lineStart = content.findRev(
'\n', firstNonWS );
849 if ( lineStart >= 0 )
850 content.remove( 0,
static_cast<unsigned int>( lineStart ) );
854 content.replace(
'\n',
'\n' + indentStr );
855 content.prepend( indentStr );
859 if ( sSmartQuote && sWordWrap )
860 return headerStr +
smartQuote( content, sWrapCol );
861 return headerStr + content;
868 bool allowDecryption ,
869 const TQString &tmpl ,
870 const TQString &originatingAccount )
873 TQString mailingListStr, replyToStr, toStr;
874 TQStringList mailingListAddresses;
875 TQCString refStr, headerName;
876 bool replyAll =
true;
880 MailingList::name(
this, headerName, mailingListStr);
886 if ( parent() && parent()->isMailingListEnabled() &&
887 !parent()->mailingListPostAddress().isEmpty() ) {
888 mailingListAddresses << parent()->mailingListPostAddress();
890 if (
headerField(
"List-Post").find(
"mailto:", 0,
false ) != -1 ) {
892 TQRegExp rx(
"<mailto:([^@>]+)@([^>]+)>",
false );
893 if ( rx.search( listPost, 0 ) != -1 )
894 mailingListAddresses << rx.cap(1) +
'@' + rx.cap(2);
898 switch( replyStrategy ) {
899 case KMail::ReplySmart : {
900 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
903 else if ( !replyToStr.isEmpty() ) {
907 else if ( !mailingListAddresses.isEmpty() ) {
908 toStr = mailingListAddresses[0];
917 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
920 if ( toStr.isEmpty() && !recipients.isEmpty() )
921 toStr = recipients[0];
925 case KMail::ReplyList : {
926 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
929 else if ( !mailingListAddresses.isEmpty() ) {
930 toStr = mailingListAddresses[0];
932 else if ( !replyToStr.isEmpty() ) {
937 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
942 case KMail::ReplyAll : {
943 TQStringList recipients;
944 TQStringList ccRecipients;
947 if( !replyToStr.isEmpty() ) {
948 recipients += KPIM::splitEmailAddrList( replyToStr );
951 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
952 it != mailingListAddresses.end();
958 if ( !mailingListAddresses.isEmpty() ) {
960 if ( recipients.isEmpty() && !
from().isEmpty() ) {
963 ccRecipients +=
from();
964 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of CC recipients"
968 recipients.prepend( mailingListAddresses[0] );
972 if ( recipients.isEmpty() && !
from().isEmpty() ) {
975 recipients +=
from();
976 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of recipients"
985 if( !
cc().isEmpty() || !
to().isEmpty() ) {
988 list += KPIM::splitEmailAddrList(
to());
990 list += KPIM::splitEmailAddrList(
cc());
991 for( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
995 kdDebug(5006) <<
"Added " << *it <<
" to the list of CC recipients"
1001 if ( !ccRecipients.isEmpty() ) {
1007 if ( toStr.isEmpty() && !ccRecipients.isEmpty() ) {
1008 toStr = ccRecipients[0];
1009 ccRecipients.pop_front();
1012 msg->setCc( ccRecipients.join(
", ") );
1015 if ( toStr.isEmpty() && !recipients.isEmpty() ) {
1017 toStr = recipients[0];
1021 case KMail::ReplyAuthor : {
1022 if ( !replyToStr.isEmpty() ) {
1023 TQStringList recipients = KPIM::splitEmailAddrList( replyToStr );
1026 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
1027 it != mailingListAddresses.end();
1031 if ( !recipients.isEmpty() ) {
1032 toStr = recipients.join(
", ");
1040 else if ( !
from().isEmpty() ) {
1046 case KMail::ReplyNone : {
1051 if (!originatingAccount.isEmpty()) {
1052 msg->setOriginatingAccountName(originatingAccount);
1058 if (!refStr.isEmpty())
1059 msg->setReferences(refStr);
1061 msg->setReplyToId(
msgId());
1073 msg->setSubject( replySubject() );
1075 formatString( GlobalSettings::self()->quoteString() ) );
1077 TemplateParser parser( msg, ( replyAll ? TemplateParser::ReplyAll : TemplateParser::Reply ) );
1079 if ( GlobalSettings::quoteSelectionOnly() ) {
1082 if ( !tmpl.isEmpty() ) {
1083 parser.process( tmpl,
this );
1085 parser.process(
this );
1089 msg->
link(
this, KMMsgStatusReplied);
1091 if ( parent() && parent()->putRepliesInSameFolder() )
1092 msg->setFcc( parent()->idString() );
1107 TQCString firstRef, lastRef, refStr, retRefStr;
1110 refStr =
headerField(
"References").stripWhiteSpace().latin1();
1112 if (refStr.isEmpty())
1115 i = refStr.find(
'<');
1116 j = refStr.find(
'>');
1117 firstRef = refStr.mid(i, j-i+1);
1118 if (!firstRef.isEmpty())
1119 retRefStr = firstRef +
' ';
1121 i = refStr.findRev(
'<');
1122 j = refStr.findRev(
'>');
1124 lastRef = refStr.mid(i, j-i+1);
1125 if (!lastRef.isEmpty() && lastRef != firstRef)
1126 retRefStr += lastRef +
' ';
1137 KMMessagePart msgPart;
1140 TQString strId = msg->
headerField(
"X-KMail-Identity" ).stripWhiteSpace();
1141 if ( !strId.isEmpty())
1142 id = strId.toUInt();
1143 const KPIM::Identity & ident =
1144 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1147 TQString strByWayOf = TQString(
"%1 (by way of %2 <%3>)")
1149 .arg( ident.fullName() )
1150 .arg( ident.primaryEmailAddress() );
1153 TQString strFrom = TQString(
"%1 <%2>")
1154 .arg( ident.fullName() )
1155 .arg( ident.primaryEmailAddress() );
1162 if ( origDate.isEmpty() )
1177 msg->
link(
this, KMMsgStatusForwarded);
1189 if (sHeaderStrategy == HeaderStrategy::all()) {
1190 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1193 str +=
"\n-------------------------------------------------------\n";
1195 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1196 s +=
"Subject: " +
subject() +
"\n";
1198 + KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
1199 date(), sReplyLanguage,
false )
1201 s +=
"From: " +
from() +
"\n";
1202 s +=
"To: " +
to() +
"\n";
1203 if (!
cc().isEmpty()) s +=
"Cc: " +
cc() +
"\n";
1206 str +=
"\n-------------------------------------------------------\n";
1216 DwHeaders& header = mMsg->Headers();
1217 DwField* field = header.FirstField();
1221 nextField = field->Next();
1222 if ( field->FieldNameStr().find(
"ontent" ) == DwString::npos
1223 && !whiteList.contains( TQString::fromLatin1( field->FieldNameStr().c_str() ) ) )
1224 header.RemoveField(field);
1238 if ( type() == DwMime::kTypeMultipart ||
1239 ( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypePlain ) ) {
1244 DwMediaType oldContentType = msg->mMsg->Headers().ContentType();
1249 TQStringList blacklist = GlobalSettings::self()->mimetypesToStripWhenInlineForwarding();
1250 for ( TQStringList::Iterator it = blacklist.begin(); it != blacklist.end(); ++it ) {
1251 TQString entry = (*it);
1252 int sep = entry.find(
'/' );
1253 TQCString type = entry.left( sep ).latin1();
1254 TQCString subtype = entry.mid( sep+1 ).latin1();
1255 kdDebug( 5006 ) <<
"Looking for blacklisted type: " << type <<
"/" << subtype << endl;
1256 while ( DwBodyPart * part = msg->
findDwBodyPart( type, subtype ) ) {
1257 msg->mMsg->Body().RemoveBodyPart( part );
1260 msg->mMsg->Assemble();
1264 msg->mMsg->Headers().ContentType().FromString( oldContentType.AsString() );
1265 msg->mMsg->Headers().ContentType().Parse();
1266 msg->mMsg->Assemble();
1268 else if( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypeHtml ) {
1272 msg->setType( DwMime::kTypeText );
1273 msg->setSubtype( DwMime::kSubtypeHtml );
1274 msg->mNeedsAssembly =
true;
1284 DwHeaders & header = msg->mMsg->Headers();
1285 header.MimeVersion().FromString(
"1.0");
1287 contentType.SetType( DwMime::kTypeMultipart );
1288 contentType.SetSubtype( DwMime::kSubtypeMixed );
1289 contentType.CreateBoundary(0);
1290 contentType.Assemble();
1293 KMMessagePart msgPart;
1297 KMMessagePart secondPart;
1298 secondPart.setType( type() );
1299 secondPart.setSubtype( subtype() );
1300 secondPart.setBody( mMsg->Body().AsString() );
1302 applyHeadersToMessagePart( mMsg->Headers(), &secondPart );
1304 msg->mNeedsAssembly =
true;
1309 msg->setSubject( forwardSubject() );
1312 if ( !tmpl.isEmpty() ) {
1313 parser.process( tmpl,
this );
1315 parser.process(
this );
1325 msg->
link(
this, KMMsgStatusForwarded);
1329 static const struct {
1330 const char * dontAskAgainID;
1333 } mdnMessageBoxes[] = {
1334 {
"mdnNormalAsk",
true,
1335 I18N_NOOP(
"This message contains a request to return a notification "
1336 "about your reception of the message.\n"
1337 "You can either ignore the request or let KMail send a "
1338 "\"denied\" or normal response.") },
1339 {
"mdnUnknownOption",
false,
1340 I18N_NOOP(
"This message contains a request to send a notification "
1341 "about your reception of the message.\n"
1342 "It contains a processing instruction that is marked as "
1343 "\"required\", but which is unknown to KMail.\n"
1344 "You can either ignore the request or let KMail send a "
1345 "\"failed\" response.") },
1346 {
"mdnMultipleAddressesInReceiptTo",
true,
1347 I18N_NOOP(
"This message contains a request to send a notification "
1348 "about your reception of the message,\n"
1349 "but it is requested to send the notification to more "
1350 "than one address.\n"
1351 "You can either ignore the request or let KMail send a "
1352 "\"denied\" or normal response.") },
1353 {
"mdnReturnPathEmpty",
true,
1354 I18N_NOOP(
"This message contains a request to send a notification "
1355 "about your reception of the message,\n"
1356 "but there is no return-path set.\n"
1357 "You can either ignore the request or let KMail send a "
1358 "\"denied\" or normal response.") },
1359 {
"mdnReturnPathNotInReceiptTo",
true,
1360 I18N_NOOP(
"This message contains a request to send a notification "
1361 "about your reception of the message,\n"
1362 "but the return-path address differs from the address "
1363 "the notification was requested to be sent to.\n"
1364 "You can either ignore the request or let KMail send a "
1365 "\"denied\" or normal response.") },
1368 static const int numMdnMessageBoxes
1369 =
sizeof mdnMessageBoxes /
sizeof *mdnMessageBoxes;
1372 static int requestAdviceOnMDN(
const char * what ) {
1373 for (
int i = 0 ; i < numMdnMessageBoxes ; ++i ) {
1374 if ( !qstrcmp( what, mdnMessageBoxes[i].dontAskAgainID ) ) {
1375 if ( mdnMessageBoxes[i].canDeny ) {
1377 int answer = TQMessageBox::information( 0,
1378 i18n(
"Message Disposition Notification Request"),
1379 i18n( mdnMessageBoxes[i].text ),
1380 i18n(
"&Ignore"), i18n(
"Send \"&denied\""), i18n(
"&Send") );
1381 return answer ? answer + 1 : 0 ;
1384 int answer = TQMessageBox::information( 0,
1385 i18n(
"Message Disposition Notification Request"),
1386 i18n( mdnMessageBoxes[i].text ),
1387 i18n(
"&Ignore"), i18n(
"&Send") );
1388 return answer ? answer + 2 : 0 ;
1392 kdWarning(5006) <<
"didn't find data for message box \""
1393 << what <<
"\"" << endl;
1398 MDN::DispositionType d,
1400 TQValueList<MDN::DispositionModifier> m )
1409 if ( mdnSentState() != KMMsgMDNStateUnknown &&
1410 mdnSentState() != KMMsgMDNNone )
1413 char st[2]; st[0] = (char)mdnSentState(); st[1] = 0;
1414 kdDebug(5006) <<
"mdnSentState() == '" << st <<
"'" << endl;
1419 DwMime::kSubtypeDispositionNotification ) ) {
1420 setMDNSentState( KMMsgMDNIgnore );
1425 TQString receiptTo =
headerField(
"Disposition-Notification-To");
1426 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1427 receiptTo.remove(
'\n' );
1430 MDN::SendingMode s = MDN::SentAutomatically;
1432 TDEConfigGroup mdnConfig( KMKernel::config(),
"MDN" );
1435 int mode = mdnConfig.readNumEntry(
"default-policy", 0 );
1436 if ( !mode || mode < 0 || mode > 3 ) {
1438 setMDNSentState( KMMsgMDNIgnore );
1448 TQString notificationOptions =
headerField(
"Disposition-Notification-Options");
1449 if ( notificationOptions.contains(
"required",
false ) ) {
1453 if ( !allowGUI )
return 0;
1454 mode = requestAdviceOnMDN(
"mdnUnknownOption" );
1455 s = MDN::SentManually;
1457 special = i18n(
"Header \"Disposition-Notification-Options\" contained "
1458 "required, but unknown parameter");
1466 kdDebug(5006) <<
"KPIM::splitEmailAddrList(receiptTo): "
1467 << KPIM::splitEmailAddrList(receiptTo).join(
"\n") << endl;
1468 if ( KPIM::splitEmailAddrList(receiptTo).count() > 1 ) {
1469 if ( !allowGUI )
return 0;
1470 mode = requestAdviceOnMDN(
"mdnMultipleAddressesInReceiptTo" );
1471 s = MDN::SentManually;
1479 AddrSpecList returnPathList = extractAddrSpecs(
"Return-Path");
1480 TQString returnPath = returnPathList.isEmpty() ? TQString()
1481 : returnPathList.front().localPart +
'@' + returnPathList.front().domain ;
1482 kdDebug(5006) <<
"clean return path: " << returnPath << endl;
1483 if ( returnPath.isEmpty() || !receiptTo.contains( returnPath,
false ) ) {
1484 if ( !allowGUI )
return 0;
1485 mode = requestAdviceOnMDN( returnPath.isEmpty() ?
1486 "mdnReturnPathEmpty" :
1487 "mdnReturnPathNotInReceiptTo" );
1488 s = MDN::SentManually;
1491 if ( a != KMime::MDN::AutomaticAction ) {
1494 if ( !allowGUI )
return 0;
1495 mode = requestAdviceOnMDN(
"mdnNormalAsk" );
1496 s = MDN::SentManually;
1501 setMDNSentState( KMMsgMDNIgnore );
1505 kdFatal(5006) <<
"KMMessage::createMDN(): The \"ask\" mode should "
1506 <<
"never appear here!" << endl;
1519 TQString finalRecipient = kmkernel->identityManager()
1520 ->identityForUoidOrDefault(
identityUoid() ).fullEmailAddr();
1531 DwHeaders & header = receipt->mMsg->Headers();
1532 header.MimeVersion().FromString(
"1.0");
1534 contentType.SetType( DwMime::kTypeMultipart );
1535 contentType.SetSubtype( DwMime::kSubtypeReport );
1536 contentType.CreateBoundary(0);
1537 receipt->mNeedsAssembly =
true;
1543 KMMessagePart firstMsgPart;
1544 firstMsgPart.setTypeStr(
"text" );
1545 firstMsgPart.setSubtypeStr(
"plain" );
1546 firstMsgPart.setBodyFromUnicode( description );
1550 KMMessagePart secondMsgPart;
1551 secondMsgPart.setType( DwMime::kTypeMessage );
1552 secondMsgPart.setSubtype( DwMime::kSubtypeDispositionNotification );
1555 secondMsgPart.setBodyEncoded( MDN::dispositionNotificationBodyContent(
1559 d, a, s, m, special ) );
1563 int num = mdnConfig.readNumEntry(
"quote-message", 0 );
1564 if ( num < 0 || num > 2 ) num = 0;
1565 MDN::ReturnContent returnContent =
static_cast<MDN::ReturnContent
>( num );
1567 KMMessagePart thirdMsgPart;
1568 switch ( returnContent ) {
1570 thirdMsgPart.setTypeStr(
"message" );
1571 thirdMsgPart.setSubtypeStr(
"rfc822" );
1575 case MDN::HeadersOnly:
1576 thirdMsgPart.setTypeStr(
"text" );
1577 thirdMsgPart.setSubtypeStr(
"rfc822-headers" );
1586 receipt->setTo( receiptTo );
1587 receipt->setSubject(
"Message Disposition Notification" );
1588 receipt->setReplyToId(
msgId() );
1593 kdDebug(5006) <<
"final message:\n" + receipt->
asString() << endl;
1598 KMMsgMDNSentState state = KMMsgMDNStateUnknown;
1600 case MDN::Displayed: state = KMMsgMDNDisplayed;
break;
1601 case MDN::Deleted: state = KMMsgMDNDeleted;
break;
1602 case MDN::Dispatched: state = KMMsgMDNDispatched;
break;
1603 case MDN::Processed: state = KMMsgMDNProcessed;
break;
1604 case MDN::Denied: state = KMMsgMDNDenied;
break;
1605 case MDN::Failed: state = KMMsgMDNFailed;
break;
1607 setMDNSentState( state );
1613 TQString result = s;
1614 TQRegExp rx(
"\\$\\{([a-z0-9-]+)\\}",
false );
1615 Q_ASSERT( rx.isValid() );
1617 TQRegExp rxDate(
"\\$\\{date\\}" );
1618 Q_ASSERT( rxDate.isValid() );
1620 TQString sDate = KMime::DateFormatter::formatDate(
1621 KMime::DateFormatter::Localized, date() );
1624 if( ( idx = rxDate.search( result, idx ) ) != -1 ) {
1625 result.replace( idx, rxDate.matchedLength(), sDate );
1629 while ( ( idx = rx.search( result, idx ) ) != -1 ) {
1630 TQString replacement =
headerField( TQString(rx.cap(1)).latin1() );
1631 result.replace( idx, rx.matchedLength(), replacement );
1632 idx += replacement.length();
1639 TQString str, receiptTo;
1642 receiptTo =
headerField(
"Disposition-Notification-To");
1643 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1644 receiptTo.remove(
'\n' );
1648 receipt->setTo(receiptTo);
1649 receipt->setSubject(i18n(
"Receipt: ") +
subject());
1651 str =
"Your message was successfully delivered.";
1652 str +=
"\n\n---------- Message header follows ----------\n";
1654 str +=
"--------------------------------------------\n";
1657 receipt->
setBody(str.latin1());
1666 const KPIM::Identity & ident =
1667 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1669 if(ident.fullEmailAddr().isEmpty())
1672 setFrom(ident.fullEmailAddr());
1674 if(ident.replyToAddr().isEmpty())
1677 setReplyTo(ident.replyToAddr());
1679 if(ident.bcc().isEmpty())
1682 setBcc(ident.bcc());
1684 if (ident.organization().isEmpty())
1689 if (ident.isDefault())
1692 setHeaderField(
"X-KMail-Identity", TQString::number( ident.uoid() ));
1694 if ( ident.transport().isEmpty() )
1699 if ( ident.fcc().isEmpty() )
1700 setFcc( TQString() );
1702 setFcc( ident.fcc() );
1704 if ( ident.drafts().isEmpty() )
1705 setDrafts( TQString() );
1707 setDrafts( ident.drafts() );
1709 if ( ident.templates().isEmpty() )
1710 setTemplates( TQString() );
1712 setTemplates( ident.templates() );
1730 TQString idString =
headerField(
"X-KMail-Identity").stripWhiteSpace();
1732 int id = idString.toUInt( &ok );
1734 if ( !ok ||
id == 0 )
1735 id = kmkernel->identityManager()->identityForAddress(
to() +
", " +
cc() ).uoid();
1736 if (
id == 0 && parent() )
1737 id = parent()->identity();
1750 if (!msg->
headerField(
"X-KMail-Transport").isEmpty())
1758 DwHeaders& header = mMsg->Headers();
1759 DwField* field = header.FirstField();
1762 if (mNeedsAssembly) mMsg->Assemble();
1763 mNeedsAssembly =
false;
1767 nextField = field->Next();
1768 if (field->FieldBody()->AsString().empty())
1770 header.RemoveField(field);
1771 mNeedsAssembly =
true;
1781 DwHeaders& header = mMsg->Headers();
1782 header.MimeVersion().FromString(
"1.0");
1788 contentType.SetType( DwMime::kTypeMultipart);
1789 contentType.SetSubtype(DwMime::kSubtypeMixed );
1792 contentType.CreateBoundary(0);
1794 mNeedsAssembly =
true;
1801 TDEConfigGroup general( KMKernel::config(),
"General" );
1802 DwHeaders& header = mMsg->Headers();
1805 if (!header.HasDate())
return "";
1806 unixTime = header.Date().AsUnixTime();
1810 return KMime::DateFormatter::formatDate(
1811 static_cast<KMime::DateFormatter::FormatType
>(general.readNumEntry(
"dateFormat", KMime::DateFormatter::Fancy )),
1812 unixTime, general.readEntry(
"customDateFormat" ));
1819 DwHeaders& header = mMsg->Headers();
1822 if (!header.HasDate())
return "";
1823 unixTime = header.Date().AsUnixTime();
1825 TQCString result = ctime(&unixTime);
1826 int len = result.length();
1827 if (result[len-1]==
'\n')
1828 result.truncate(len-1);
1835 TQString KMMessage::dateIsoStr()
const
1837 DwHeaders& header = mMsg->Headers();
1840 if (!header.HasDate())
return "";
1841 unixTime = header.Date().AsUnixTime();
1844 strftime(cstr, 63,
"%Y-%m-%d %H:%M:%S", localtime(&unixTime));
1845 return TQString(cstr);
1850 time_t KMMessage::date()
const
1852 time_t res = ( time_t )-1;
1853 DwHeaders& header = mMsg->Headers();
1854 if (header.HasDate())
1855 res = header.Date().AsUnixTime();
1863 struct timeval tval;
1864 gettimeofday(&tval, 0);
1865 setDate((time_t)tval.tv_sec);
1870 void KMMessage::setDate(time_t aDate)
1873 mMsg->Headers().Date().FromCalendarTime(aDate);
1874 mMsg->Headers().Date().Assemble();
1875 mNeedsAssembly =
true;
1881 void KMMessage::setDate(
const TQCString& aStr)
1883 DwHeaders& header = mMsg->Headers();
1885 header.Date().FromString(aStr);
1886 header.Date().Parse();
1887 mNeedsAssembly =
true;
1890 if (header.HasDate())
1891 mDate = header.Date().AsUnixTime();
1901 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1904 return KPIM::normalizeAddressesAndDecodeIDNs(
headers.join(
", " ) );
1909 void KMMessage::setTo(
const TQString& aStr)
1915 TQString KMMessage::toStrip()
const
1923 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Reply-To") );
1928 void KMMessage::setReplyTo(
const TQString& aStr)
1935 void KMMessage::setReplyTo(
KMMessage* aMsg)
1948 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1951 return KPIM::normalizeAddressesAndDecodeIDNs(
headers.join(
", " ) );
1956 void KMMessage::setCc(
const TQString& aStr)
1963 TQString KMMessage::ccStrip()
const
1972 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Bcc") );
1977 void KMMessage::setBcc(
const TQString& aStr)
1990 void KMMessage::setFcc(
const TQString &aStr )
1996 void KMMessage::setDrafts(
const TQString &aStr )
2002 void KMMessage::setTemplates(
const TQString &aStr )
2011 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(mParent->whoField().utf8()) );
2019 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"From") );
2024 void KMMessage::setFrom(
const TQString& bStr)
2026 TQString aStr = bStr;
2035 TQString KMMessage::fromStrip()
const
2042 AddrSpecList asl = extractAddrSpecs(
"Sender" );
2044 asl = extractAddrSpecs(
"From" );
2047 return asl.front().asString();
2058 void KMMessage::setSubject(
const TQString& aStr)
2073 void KMMessage::setXMark(
const TQString& aStr)
2083 int leftAngle, rightAngle;
2088 rightAngle =
replyTo.find(
'>' );
2089 if (rightAngle != -1)
2090 replyTo.truncate( rightAngle + 1 );
2092 leftAngle =
replyTo.findRev(
'<' );
2093 if (leftAngle != -1)
2101 ( -1 ==
replyTo.find(
'"' ) ) )
2106 if (leftAngle != -1)
2109 if (rightAngle != -1)
2122 TQString KMMessage::replyToIdMD5()
const {
2129 int leftAngle, rightAngle;
2134 leftAngle =
references.findRev(
'<', leftAngle - 1 );
2135 if( leftAngle != -1 )
2138 if( rightAngle != -1 )
2153 const int rightAngle = result.find(
'>' );
2154 if( rightAngle != -1 )
2155 result.truncate( rightAngle + 1 );
2157 return base64EncodedMD5( result );
2162 return base64EncodedMD5( stripOffPrefixes(
subject() ),
true );
2167 return base64EncodedMD5(
subject(),
true );
2176 void KMMessage::setReplyToId(
const TQString& aStr)
2189 const int rightAngle =
msgId.find(
'>' );
2190 if (rightAngle != -1)
2191 msgId.truncate( rightAngle + 1 );
2193 const int leftAngle =
msgId.findRev(
'<' );
2194 if (leftAngle != -1)
2201 TQString KMMessage::msgIdMD5()
const {
2202 return base64EncodedMD5(
msgId() );
2207 void KMMessage::setMsgId(
const TQString& aStr)
2220 void KMMessage::setMsgSizeServer(
size_t size)
2233 void KMMessage::setUID(ulong uid)
2243 const char * scursor = str.begin();
2245 return AddressList();
2246 const char *
const send = str.begin() + str.length();
2247 if ( !parseAddressList( scursor, send, result ) )
2248 kdDebug(5006) <<
"Error in address splitting: parseAddressList returned false!"
2257 AddrSpecList KMMessage::extractAddrSpecs(
const TQCString & header )
const {
2259 AddrSpecList result;
2260 for ( AddressList::const_iterator ait = al.begin() ; ait != al.end() ; ++ait )
2261 for ( MailboxList::const_iterator mit = (*ait).mailboxList.begin() ; mit != (*ait).mailboxList.end() ; ++mit )
2262 result.push_back( (*mit).addrSpec );
2267 if ( name.isEmpty() )
return TQCString();
2269 DwHeaders & header = mMsg->Headers();
2270 DwField * field = header.FindField( name );
2272 if ( !field )
return TQCString();
2274 return header.FieldBody( name.data() ).AsString().c_str();
2279 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2280 return TQValueList<TQCString>();
2282 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2284 for ( uint i = 0; i < v.size(); ++i ) {
2293 if ( aName.isEmpty() )
2296 if ( !mMsg->Headers().FindField( aName ) )
2299 return decodeRFC2047String( mMsg->Headers().FieldBody( aName.data() ).AsString().c_str(),
2306 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2307 return TQStringList();
2309 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2311 for ( uint i = 0; i < v.size(); ++i ) {
2321 DwHeaders & header = mMsg->Headers();
2322 DwField * field = header.FindField(aName);
2325 header.RemoveField(field);
2326 mNeedsAssembly =
true;
2332 DwHeaders & header = mMsg->Headers();
2333 while ( DwField * field = header.FindField(aName) ) {
2334 header.RemoveField(field);
2335 mNeedsAssembly =
true;
2342 HeaderFieldType type,
bool prepend )
2345 if ( type != Unstructured )
2346 kdDebug(5006) <<
"KMMessage::setHeaderField( \"" << aName <<
"\", \""
2347 << bValue <<
"\", " << type <<
" )" << endl;
2349 if (aName.isEmpty())
return;
2351 DwHeaders& header = mMsg->Headers();
2356 if (!bValue.isEmpty())
2358 TQString value = bValue;
2359 if ( type == Address )
2360 value = KPIM::normalizeAddressesAndEncodeIDNs( value );
2362 if ( type != Unstructured )
2363 kdDebug(5006) <<
"value: \"" << value <<
"\"" << endl;
2365 TQCString encoding = autoDetectCharset(
charset(), sPrefCharsets, value );
2366 if (encoding.isEmpty())
2368 aValue = encodeRFC2047String( value, encoding );
2370 if ( type != Unstructured )
2371 kdDebug(5006) <<
"aValue: \"" << aValue <<
"\"" << endl;
2375 if (str[str.length()-1] !=
':') str +=
": ";
2377 if ( !aValue.isEmpty() )
2378 str += aValue.data();
2379 if (str[str.length()-1] !=
'\n') str +=
'\n';
2381 field =
new DwField(str, mMsg);
2385 header.AddFieldAt( 1, field );
2387 header.AddOrReplaceField( field );
2388 mNeedsAssembly =
true;
2395 DwHeaders& header = mMsg->Headers();
2396 if (header.HasContentType())
return header.ContentType().TypeStr().c_str();
2402 int KMMessage::type()
const
2404 DwHeaders& header = mMsg->Headers();
2405 if (header.HasContentType())
return header.ContentType().Type();
2406 else return DwMime::kTypeNull;
2411 void KMMessage::setTypeStr(
const TQCString& aStr)
2415 mNeedsAssembly =
true;
2420 void KMMessage::setType(
int aType)
2424 mNeedsAssembly =
true;
2432 DwHeaders& header = mMsg->Headers();
2433 if (header.HasContentType())
return header.ContentType().SubtypeStr().c_str();
2439 int KMMessage::subtype()
const
2441 DwHeaders& header = mMsg->Headers();
2442 if (header.HasContentType())
return header.ContentType().Subtype();
2443 else return DwMime::kSubtypeNull;
2448 void KMMessage::setSubtypeStr(
const TQCString& aStr)
2452 mNeedsAssembly =
true;
2457 void KMMessage::setSubtype(
int aSubtype)
2461 mNeedsAssembly =
true;
2467 const TQCString& attr,
2468 const TQCString& val )
2471 DwParameter *param = mType.FirstParameter();
2473 if (!kasciistricmp(param->Attribute().c_str(), attr))
2476 param = param->Next();
2479 param =
new DwParameter;
2480 param->SetAttribute(DwString( attr ));
2481 mType.AddParameter( param );
2484 mType.SetModified();
2485 param->SetValue(DwString( val ));
2493 if (mNeedsAssembly) mMsg->Assemble();
2494 mNeedsAssembly =
false;
2496 mNeedsAssembly =
true;
2503 DwHeaders& header = mMsg->Headers();
2504 if (header.HasContentTransferEncoding())
2505 return header.ContentTransferEncoding().AsString().c_str();
2511 int KMMessage::contentTransferEncoding( DwEntity *entity )
const
2516 DwHeaders& header = entity->Headers();
2517 if ( header.HasContentTransferEncoding() )
2518 return header.ContentTransferEncoding().AsEnum();
2519 else return DwMime::kCteNull;
2524 void KMMessage::setContentTransferEncodingStr(
const TQCString& cteString,
2530 entity->Headers().ContentTransferEncoding().FromString( cteString );
2531 entity->Headers().ContentTransferEncoding().Parse();
2532 mNeedsAssembly =
true;
2537 void KMMessage::setContentTransferEncoding(
int cte, DwEntity *entity )
2542 entity->Headers().ContentTransferEncoding().FromEnum( cte );
2543 mNeedsAssembly =
true;
2550 return mMsg->Headers();
2557 mNeedsAssembly =
true;
2565 if ( mNeedsAssembly ) {
2567 mNeedsAssembly =
false;
2574 const DwString&
body = mMsg->Body().AsString();
2584 TQByteArray KMMessage::bodyDecodedBinary()
const
2587 const DwString& dwsrc = mMsg->Body().AsString();
2591 case DwMime::kCteBase64:
2592 DwDecodeBase64(dwsrc, dwstr);
2594 case DwMime::kCteQuotedPrintable:
2595 DwDecodeQuotedPrintable(dwsrc, dwstr);
2602 int len = dwstr.size();
2603 TQByteArray ba(len);
2604 memcpy(ba.data(),dwstr.data(),len);
2613 DwString dwsrc = mMsg->Body().AsString();
2617 case DwMime::kCteBase64:
2618 DwDecodeBase64(dwsrc, dwstr);
2620 case DwMime::kCteQuotedPrintable:
2621 DwDecodeQuotedPrintable(dwsrc, dwstr);
2643 TQValueList<int> allowedCtes;
2645 switch ( cf.type() ) {
2646 case CharFreq::SevenBitText:
2647 allowedCtes << DwMime::kCte7bit;
2648 case CharFreq::EightBitText:
2650 allowedCtes << DwMime::kCte8bit;
2651 case CharFreq::SevenBitData:
2652 if ( cf.printableRatio() > 5.0/6.0 ) {
2656 allowedCtes << DwMime::kCteQp;
2657 allowedCtes << DwMime::kCteBase64;
2659 allowedCtes << DwMime::kCteBase64;
2660 allowedCtes << DwMime::kCteQp;
2663 case CharFreq::EightBitData:
2664 allowedCtes << DwMime::kCteBase64;
2666 case CharFreq::None:
2676 if ( ( willBeSigned && cf.hasTrailingWhitespace() ) ||
2677 cf.hasLeadingFrom() ) {
2678 allowedCtes.remove( DwMime::kCte8bit );
2679 allowedCtes.remove( DwMime::kCte7bit );
2688 TQValueList<int> & allowedCte,
2696 CharFreq cf( aBuf );
2698 setCte( allowedCte[0], entity );
2699 setBodyEncodedBinary( aBuf, entity );
2705 TQValueList<int> & allowedCte,
2713 CharFreq cf( aBuf.data(), aBuf.size()-1 );
2715 setCte( allowedCte[0], entity );
2726 DwString dwSrc(aStr.data(), aStr.size()-1 );
2729 switch (cte( entity ))
2731 case DwMime::kCteBase64:
2732 DwEncodeBase64(dwSrc, dwResult);
2734 case DwMime::kCteQuotedPrintable:
2735 DwEncodeQuotedPrintable(dwSrc, dwResult);
2742 entity->Body().FromString(dwResult);
2743 mNeedsAssembly =
true;
2747 void KMMessage::setBodyEncodedBinary(
const TQByteArray& aStr, DwEntity *entity )
2752 DwString dwSrc(aStr.data(), aStr.size());
2755 switch ( cte( entity ) )
2757 case DwMime::kCteBase64:
2758 DwEncodeBase64( dwSrc, dwResult );
2760 case DwMime::kCteQuotedPrintable:
2761 DwEncodeQuotedPrintable( dwSrc, dwResult );
2768 entity->Body().FromString( dwResult );
2769 entity->Body().Parse();
2771 mNeedsAssembly =
true;
2779 mNeedsAssembly =
true;
2783 mMsg->Body().FromString(aStr);
2784 mNeedsAssembly =
true;
2788 mMsg->Body().FromString(aStr);
2789 mNeedsAssembly =
true;
2795 mMsg->Body().Parse();
2796 mNeedsAssembly =
true;
2812 TQPtrList< DwBodyPart > parts;
2818 && part->hasHeaders()
2819 && part->Headers().HasContentType()
2820 && part->Body().FirstBodyPart()
2821 && (DwMime::kTypeMultipart == part->Headers().ContentType().Type()) )
2823 parts.append( part );
2824 part = part->Body().FirstBodyPart();
2830 while (part && !(part->Next()) && !(parts.isEmpty()))
2832 part = parts.getLast();
2836 if (part && part->Body().Message() &&
2837 part->Body().Message()->Body().FirstBodyPart())
2839 part = part->Body().Message()->Body().FirstBodyPart();
2841 part = part->Next();
2852 return mMsg->Body().FirstBodyPart();
2859 DwBodyPart *curpart;
2860 TQPtrList< DwBodyPart > parts;
2867 while (curpart && !idx) {
2870 && curpart->hasHeaders()
2871 && curpart->Headers().HasContentType()
2872 && curpart->Body().FirstBodyPart()
2873 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2875 parts.append( curpart );
2876 curpart = curpart->Body().FirstBodyPart();
2879 if (curpart == aDwBodyPart)
2884 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2886 curpart = parts.getLast();
2890 curpart = curpart->Next();
2899 DwBodyPart *part, *curpart;
2900 TQPtrList< DwBodyPart > parts;
2907 while (curpart && !part) {
2910 && curpart->hasHeaders()
2911 && curpart->Headers().HasContentType()
2912 && curpart->Body().FirstBodyPart()
2913 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2915 parts.append( curpart );
2916 curpart = curpart->Body().FirstBodyPart();
2924 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2926 curpart = parts.getLast();
2930 curpart = curpart->Next();
2939 DwBodyPart *part, *curpart;
2940 TQPtrList< DwBodyPart > parts;
2946 while (curpart && !part) {
2949 && curpart->hasHeaders()
2950 && curpart->Headers().HasContentType()
2951 && curpart->Body().FirstBodyPart()
2952 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
2953 parts.append( curpart );
2954 curpart = curpart->Body().FirstBodyPart();
2960 if ( curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
2961 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
2962 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
2966 curpart->hasHeaders() &&
2967 curpart->Headers().HasContentType() &&
2968 curpart->Headers().ContentType().Type() == type &&
2969 curpart->Headers().ContentType().Subtype() == subtype) {
2974 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
2975 curpart = parts.getLast();
2979 curpart = curpart->Next();
2988 DwBodyPart *part, *curpart;
2989 TQPtrList< DwBodyPart > parts;
2995 while (curpart && !part) {
2998 && curpart->hasHeaders()
2999 && curpart->Headers().HasContentType()
3000 && curpart->Body().FirstBodyPart()
3001 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
3002 parts.append( curpart );
3003 curpart = curpart->Body().FirstBodyPart();
3009 if (curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
3010 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
3011 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
3015 curpart->hasHeaders() &&
3016 curpart->Headers().HasContentType() &&
3017 curpart->Headers().ContentType().TypeStr().c_str() == type &&
3018 curpart->Headers().ContentType().SubtypeStr().c_str() == subtype) {
3023 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
3024 curpart = parts.getLast();
3028 curpart = curpart->Next();
3035 void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart )
3047 TQCString additionalCTypeParams;
3048 if (headers.HasContentType())
3050 DwMediaType& ct = headers.ContentType();
3051 aPart->setOriginalContentTypeStr( ct.AsString().c_str() );
3052 aPart->setTypeStr(ct.TypeStr().c_str());
3053 aPart->setSubtypeStr(ct.SubtypeStr().c_str());
3054 DwParameter *param = ct.FirstParameter();
3057 if (!tqstricmp(param->Attribute().c_str(),
"charset")) {
3058 if (aPart->type() == DwMime::kTypeText) {
3059 aPart->setCharset(TQCString(param->Value().c_str()).lower());
3062 else if (!tqstrnicmp(param->Attribute().c_str(),
"name*", 5))
3063 aPart->setName(KMMsgBase::decodeRFC2231String(KMMsgBase::extractRFC2231HeaderField( param->Value().c_str(),
"name" )));
3065 additionalCTypeParams +=
';';
3066 additionalCTypeParams += param->AsString().c_str();
3068 param=param->Next();
3073 aPart->setTypeStr(
"text");
3074 aPart->setSubtypeStr(
"plain");
3076 aPart->setAdditionalCTypeParamStr( additionalCTypeParams );
3078 if (aPart->name().isEmpty())
3080 if (headers.HasContentType() && !headers.ContentType().Name().empty()) {
3081 aPart->setName(KMMsgBase::decodeRFC2047String(headers.
3082 ContentType().Name().c_str()) );
3083 }
else if (headers.HasSubject() && !headers.Subject().AsString().empty()) {
3084 aPart->setName( KMMsgBase::decodeRFC2047String(headers.
3085 Subject().AsString().c_str()) );
3090 if (headers.HasContentTransferEncoding())
3091 aPart->setCteStr(headers.ContentTransferEncoding().AsString().c_str());
3093 aPart->setCteStr(
"7bit");
3096 if (headers.HasContentDescription())
3097 aPart->setContentDescription( KMMsgBase::decodeRFC2047String(
3098 headers.ContentDescription().AsString().c_str() ) );
3100 aPart->setContentDescription(
"");
3103 if (headers.HasContentDisposition())
3104 aPart->setContentDisposition(headers.ContentDisposition().AsString().c_str());
3106 aPart->setContentDisposition(
"");
3118 if( aDwBodyPart && aDwBodyPart->hasHeaders() ) {
3123 TQString partId( aDwBodyPart->partId() );
3124 aPart->setPartSpecifier( partId );
3126 DwHeaders&
headers = aDwBodyPart->Headers();
3127 applyHeadersToMessagePart(
headers, aPart );
3131 aPart->setBody( aDwBodyPart->Body().AsString() );
3133 aPart->setBody( TQCString(
"") );
3136 if (
headers.HasContentId() ) {
3137 const TQCString contentId =
headers.ContentId().AsString().c_str();
3139 aPart->setContentId( contentId.mid( 1, contentId.length() - 2 ) );
3146 aPart->setTypeStr(
"");
3147 aPart->setSubtypeStr(
"");
3148 aPart->setCteStr(
"");
3152 aPart->setContentDescription(
"");
3153 aPart->setContentDisposition(
"");
3154 aPart->setBody(TQCString(
""));
3155 aPart->setContentId(
"");
3167 if ( DwBodyPart *part =
dwBodyPart( aIdx ) ) {
3169 if( aPart->name().isEmpty() )
3170 aPart->setName( i18n(
"Attachment: %1").arg( aIdx ) );
3178 mMsg->Body().DeleteBodyParts();
3186 DwBodyPart *dwpart = findPart( partIndex );
3190 if ( !part.isComplete() )
3193 DwBody *parentNode =
dynamic_cast<DwBody*
>( dwpart->Parent() );
3196 parentNode->RemoveBodyPart( dwpart );
3199 KMMessagePart dummyPart;
3200 dummyPart.duplicate( part );
3201 TQString comment = i18n(
"This attachment has been deleted.");
3202 if ( !part.fileName().isEmpty() )
3203 comment = i18n(
"The attachment '%1' has been deleted." ).arg( part.fileName() );
3204 dummyPart.setContentDescription( comment );
3205 dummyPart.setBodyEncodedBinary( TQByteArray() );
3206 TQCString cd = dummyPart.contentDisposition();
3207 if ( cd.find(
"inline", 0,
false ) == 0 ) {
3208 cd.replace( 0, 10,
"attachment" );
3209 dummyPart.setContentDisposition( cd );
3210 }
else if ( cd.isEmpty() ) {
3211 dummyPart.setContentDisposition(
"attachment" );
3214 parentNode->AddBodyPart( newDwPart );
3215 getTopLevelPart()->Assemble();
3222 DwBodyPart* part = DwBodyPart::NewBodyPart(emptyString, 0);
3227 TQCString
charset = aPart->charset();
3228 TQCString type = aPart->typeStr();
3229 TQCString subtype = aPart->subtypeStr();
3230 TQCString cte = aPart->cteStr();
3231 TQCString contDesc = aPart->contentDescriptionEncoded();
3232 TQCString contDisp = aPart->contentDisposition();
3233 TQCString name = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->name(),
charset );
3234 bool RFC2231encoded = aPart->name() != TQString(name);
3235 TQCString paramAttr = aPart->parameterAttribute();
3237 DwHeaders&
headers = part->Headers();
3239 DwMediaType& ct =
headers.ContentType();
3240 if (!type.isEmpty() && !subtype.isEmpty())
3242 ct.SetTypeStr(type.data());
3243 ct.SetSubtypeStr(subtype.data());
3246 param=
new DwParameter;
3247 param->SetAttribute(
"charset");
3248 param->SetValue(
charset.data());
3249 ct.AddParameter(param);
3253 TQCString additionalParam = aPart->additionalCTypeParamStr();
3254 if( !additionalParam.isEmpty() )
3257 DwString parA, parV;
3259 iL = additionalParam.length();
3261 i2 = additionalParam.find(
';', i1,
false);
3267 parAV = additionalParam.mid( i1, (i2-i1) );
3268 iM = parAV.find(
'=');
3271 parA = parAV.left( iM ).data();
3272 parV = parAV.right( parAV.length() - iM - 1 ).data();
3273 if( (
'"' == parV.at(0)) && (
'"' == parV.at(parV.length()-1)) )
3276 parV.erase( parV.length()-1 );
3281 parA = parAV.data();
3285 param =
new DwParameter;
3286 param->SetAttribute( parA );
3287 param->SetValue( parV );
3288 ct.AddParameter( param );
3291 i2 = additionalParam.find(
';', i1,
false);
3295 if ( !name.isEmpty() ) {
3298 DwParameter *nameParam;
3299 nameParam =
new DwParameter;
3300 nameParam->SetAttribute(
"name*");
3301 nameParam->SetValue(name.data(),
true);
3302 ct.AddParameter(nameParam);
3304 ct.SetName(name.data());
3308 if (!paramAttr.isEmpty())
3310 TQCString paramValue;
3311 paramValue = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->parameterValue(),
charset );
3312 DwParameter *param =
new DwParameter;
3313 if (aPart->parameterValue() != TQString(paramValue))
3315 param->SetAttribute((paramAttr +
'*').data());
3316 param->SetValue(paramValue.data(),
true);
3318 param->SetAttribute(paramAttr.data());
3319 param->SetValue(paramValue.data());
3321 ct.AddParameter(param);
3325 headers.Cte().FromString(cte);
3327 if (!contDesc.isEmpty())
3328 headers.ContentDescription().FromString(contDesc);
3330 if (!contDisp.isEmpty())
3331 headers.ContentDisposition().FromString(contDisp);
3333 const DwString bodyStr = aPart->dwBody();
3334 if (!bodyStr.empty())
3335 part->Body().FromString(bodyStr);
3337 part->Body().FromString(
"");
3339 if (!aPart->partSpecifier().isNull())
3340 part->SetPartId( aPart->partSpecifier().latin1() );
3342 if (aPart->decodedSize() > 0)
3343 part->SetBodySize( aPart->decodedSize() );
3352 mMsg->Body().AddBodyPart( aDwPart );
3353 mNeedsAssembly =
true;
3368 TQDateTime datetime = TQDateTime::currentDateTime();
3371 msgIdStr =
'<' + datetime.toString(
"yyyyMMddhhmm.sszzz" );
3373 TQString msgIdSuffix;
3374 TDEConfigGroup general( KMKernel::config(),
"General" );
3376 if( general.readBoolEntry(
"useCustomMessageIdSuffix",
false ) )
3377 msgIdSuffix = general.readEntry(
"myMessageIdSuffix" );
3379 if( !msgIdSuffix.isEmpty() )
3380 msgIdStr +=
'@' + msgIdSuffix;
3382 msgIdStr +=
'.' + KPIM::encodeIDN( addr );
3393 TQCString result( 1 + 6*(src.size()-1) );
3395 TQCString::ConstIterator s = src.begin();
3396 TQCString::Iterator d = result.begin();
3459 result.truncate( d - result.begin() );
3467 result = TQString::fromLatin1( KMMsgBase::encodeRFC2047String( str,
3469 result = KURL::encode_string( result );
3478 result = KURL::decode_string( url );
3479 result = KMMsgBase::decodeRFC2047String( result.latin1() );
3489 if ( aStr.isEmpty() )
3500 TQCString angleAddress;
3501 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3502 bool inQuotedString =
false;
3503 int commentLevel = 0;
3505 for (
const char* p = aStr.data(); *p; ++p ) {
3506 switch ( context ) {
3509 case '"' : inQuotedString = !inQuotedString;
3511 case '(' :
if ( !inQuotedString ) {
3512 context = InComment;
3518 case '<' :
if ( !inQuotedString ) {
3519 context = InAngleAddress;
3529 case ',' :
if ( !inQuotedString ) {
3531 if ( !result.isEmpty() )
3533 name = name.stripWhiteSpace();
3534 comment = comment.stripWhiteSpace();
3535 angleAddress = angleAddress.stripWhiteSpace();
3544 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3549 else if ( !name.isEmpty() ) {
3552 else if ( !comment.isEmpty() ) {
3555 else if ( !angleAddress.isEmpty() ) {
3556 result += angleAddress;
3559 comment = TQCString();
3560 angleAddress = TQCString();
3565 default : name += *p;
3571 case '(' : ++commentLevel;
3574 case ')' : --commentLevel;
3575 if ( commentLevel == 0 ) {
3587 default : comment += *p;
3591 case InAngleAddress : {
3593 case '"' : inQuotedString = !inQuotedString;
3596 case '>' :
if ( !inQuotedString ) {
3607 default : angleAddress += *p;
3613 if ( !result.isEmpty() )
3615 name = name.stripWhiteSpace();
3616 comment = comment.stripWhiteSpace();
3617 angleAddress = angleAddress.stripWhiteSpace();
3623 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3628 else if ( !name.isEmpty() ) {
3631 else if ( !comment.isEmpty() ) {
3634 else if ( !angleAddress.isEmpty() ) {
3635 result += angleAddress;
3648 if ( aStr.isEmpty() )
3659 TQString angleAddress;
3660 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3661 bool inQuotedString =
false;
3662 int commentLevel = 0;
3665 unsigned int strLength(aStr.length());
3666 for ( uint index = 0; index < strLength; ++index ) {
3668 switch ( context ) {
3670 switch ( ch.latin1() ) {
3671 case '"' : inQuotedString = !inQuotedString;
3673 case '(' :
if ( !inQuotedString ) {
3674 context = InComment;
3680 case '<' :
if ( !inQuotedString ) {
3681 context = InAngleAddress;
3688 if ( index < aStr.length() )
3689 name += aStr[index];
3691 case ',' :
if ( !inQuotedString ) {
3693 if ( !result.isEmpty() )
3695 name = name.stripWhiteSpace();
3696 comment = comment.stripWhiteSpace();
3697 angleAddress = angleAddress.stripWhiteSpace();
3706 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3711 else if ( !name.isEmpty() ) {
3714 else if ( !comment.isEmpty() ) {
3717 else if ( !angleAddress.isEmpty() ) {
3718 result += angleAddress;
3721 comment = TQString();
3722 angleAddress = TQString();
3727 default : name += ch;
3732 switch ( ch.latin1() ) {
3733 case '(' : ++commentLevel;
3736 case ')' : --commentLevel;
3737 if ( commentLevel == 0 ) {
3746 if ( index < aStr.length() )
3747 comment += aStr[index];
3749 default : comment += ch;
3753 case InAngleAddress : {
3754 switch ( ch.latin1() ) {
3755 case '"' : inQuotedString = !inQuotedString;
3758 case '>' :
if ( !inQuotedString ) {
3766 if ( index < aStr.length() )
3767 angleAddress += aStr[index];
3769 default : angleAddress += ch;
3775 if ( !result.isEmpty() )
3777 name = name.stripWhiteSpace();
3778 comment = comment.stripWhiteSpace();
3779 angleAddress = angleAddress.stripWhiteSpace();
3785 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3790 else if ( !name.isEmpty() ) {
3793 else if ( !comment.isEmpty() ) {
3796 else if ( !angleAddress.isEmpty() ) {
3797 result += angleAddress;
3810 unsigned int strLength(str.length());
3811 result.reserve( 6*strLength );
3812 for(
unsigned int i = 0; i < strLength; ++i )
3813 switch ( str[i].latin1() ) {
3827 if ( !removeLineBreaks )
3844 if( aEmail.isEmpty() )
3847 TQStringList addressList = KPIM::splitEmailAddrList( aEmail );
3850 for( TQStringList::ConstIterator it = addressList.begin();
3851 ( it != addressList.end() );
3853 if( !(*it).isEmpty() ) {
3856 TQString name, mail;
3857 KPIM::getNameAndMail( *it, name, mail );
3859 TQString prettyStripped;
3860 if ( name.stripWhiteSpace().isEmpty() ) {
3862 prettyStripped = mail;
3864 pretty = KPIM::quoteNameIfNecessary( name ) +
" <" + mail +
">";
3865 prettyStripped = name;
3869 result +=
"<a href=\"mailto:"
3871 +
"\" "+cssStyle+
">";
3887 result.truncate( result.length() - 2 );
3897 const TQStringList& list )
3899 TQStringList addresses( list );
3900 TQString addrSpec( KPIM::getEmailAddress( address ) );
3901 for ( TQStringList::Iterator it = addresses.begin();
3902 it != addresses.end(); ) {
3903 if ( kasciistricmp( addrSpec.utf8().data(),
3904 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 ) {
3905 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3907 it = addresses.remove( it );
3920 TQStringList addresses = list;
3921 for( TQStringList::Iterator it = addresses.begin();
3922 it != addresses.end(); ) {
3923 kdDebug(5006) <<
"Check whether " << *it <<
" is one of my addresses"
3925 if( kmkernel->identityManager()->thatIsMe( KPIM::getEmailAddress( *it ) ) ) {
3926 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3928 it = addresses.remove( it );
3940 const TQStringList& addresses )
3942 TQString addrSpec = KPIM::getEmailAddress( address );
3943 for( TQStringList::ConstIterator it = addresses.begin();
3944 it != addresses.end(); ++it ) {
3945 if ( kasciistricmp( addrSpec.utf8().data(),
3946 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 )
3957 if ( recipients.isEmpty() )
3960 TQStringList recipientList = KPIM::splitEmailAddrList( recipients );
3962 TQString expandedRecipients;
3963 for ( TQStringList::Iterator it = recipientList.begin();
3964 it != recipientList.end(); ++it ) {
3965 if ( !expandedRecipients.isEmpty() )
3966 expandedRecipients +=
", ";
3967 TQString receiver = (*it).stripWhiteSpace();
3970 TQString expandedList = KAddrBookExternal::expandDistributionList( receiver );
3971 if ( !expandedList.isEmpty() ) {
3972 expandedRecipients += expandedList;
3977 TQString expandedNickName = KabcBridge::expandNickName( receiver );
3978 if ( !expandedNickName.isEmpty() ) {
3979 expandedRecipients += expandedNickName;
3985 if ( receiver.find(
'@') == -1 ) {
3986 TDEConfigGroup general( KMKernel::config(),
"General" );
3987 TQString defaultdomain = general.readEntry(
"Default domain" );
3988 if( !defaultdomain.isEmpty() ) {
3989 expandedRecipients += receiver +
"@" + defaultdomain;
3996 expandedRecipients += receiver;
3999 return expandedRecipients;
4007 if ( loginName.isEmpty() )
4010 char hostnameC[256];
4012 hostnameC[255] =
'\0';
4014 if ( gethostname( hostnameC, 255 ) )
4015 hostnameC[0] =
'\0';
4016 TQString address = loginName;
4018 address += TQString::fromLocal8Bit( hostnameC );
4021 const KUser user( loginName );
4022 if ( user.isValid() ) {
4023 TQString fullName = user.fullName();
4024 if ( fullName.find( TQRegExp(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) ) != -1 )
4025 address =
'"' + fullName.replace(
'\\',
"\\" ).replace(
'"',
"\\" )
4026 +
"\" <" + address +
'>';
4028 address = fullName +
" <" + address +
'>';
4037 KMMsgBase::readConfig();
4039 TDEConfig *config=KMKernel::config();
4040 TDEConfigGroupSaver saver(config,
"General");
4042 config->setGroup(
"General");
4044 int languageNr = config->readNumEntry(
"reply-current-language",0);
4047 TDEConfigGroupSaver saver(config, TQString(
"KMMessage #%1").arg(languageNr));
4048 sReplyLanguage = config->readEntry(
"language",TDEGlobal::locale()->language());
4049 sReplyStr = config->readEntry(
"phrase-reply",
4050 i18n(
"On %D, you wrote:"));
4051 sReplyAllStr = config->readEntry(
"phrase-reply-all",
4052 i18n(
"On %D, %F wrote:"));
4053 sForwardStr = config->readEntry(
"phrase-forward",
4054 i18n(
"Forwarded Message"));
4055 sIndentPrefixStr = config->readEntry(
"indent-prefix",
">%_");
4059 TDEConfigGroupSaver saver(config,
"Composer");
4060 sSmartQuote = GlobalSettings::self()->smartQuote();
4061 sWordWrap = GlobalSettings::self()->wordWrap();
4062 sWrapCol = GlobalSettings::self()->lineWrapWidth();
4063 if ((sWrapCol == 0) || (sWrapCol > 78))
4068 sPrefCharsets = config->readListEntry(
"pref-charsets");
4072 TDEConfigGroupSaver saver(config,
"Reader");
4073 sHeaderStrategy = HeaderStrategy::create( config->readEntry(
"header-set-displayed",
"rich" ) );
4081 if (!sPrefCharsets.isEmpty())
4082 retval = sPrefCharsets[0].latin1();
4084 if (retval.isEmpty() || (retval ==
"locale")) {
4085 retval = TQCString(kmkernel->networkCodec()->mimeName());
4086 KPIM::kAsciiToLower( retval.data() );
4089 if (retval ==
"jisx0208.1983-0") retval =
"iso-2022-jp";
4090 else if (retval ==
"ksc5601.1987-0") retval =
"euc-kr";
4096 return sPrefCharsets;
4102 if ( mMsg->Headers().HasContentType() ) {
4103 DwMediaType &mType=mMsg->Headers().ContentType();
4105 DwParameter *param=mType.FirstParameter();
4107 if (!kasciistricmp(param->Attribute().c_str(),
"charset"))
4108 return param->Value().c_str();
4109 else param=param->Next();
4118 kdWarning( type() != DwMime::kTypeText )
4119 <<
"KMMessage::setCharset(): trying to set a charset for a non-textual mimetype." << endl
4120 <<
"Fix this caller:" << endl
4121 <<
"====================================================================" << endl
4122 << kdBacktrace( 5 ) << endl
4123 <<
"====================================================================" << endl;
4128 DwMediaType &mType = entity->Headers().ContentType();
4130 DwParameter *param = mType.FirstParameter();
4134 if ( !kasciistricmp( param->Attribute().c_str(),
"charset" ) )
4137 param = param->Next();
4140 param =
new DwParameter;
4141 param->SetAttribute(
"charset" );
4142 mType.AddParameter( param );
4145 mType.SetModified();
4147 TQCString lowerCharset =
charset;
4148 KPIM::kAsciiToLower( lowerCharset.data() );
4149 param->SetValue( DwString( lowerCharset ) );
4157 if (mStatus == aStatus)
4159 KMMsgBase::setStatus(aStatus, idx);
4164 if( mEncryptionState == s )
4166 mEncryptionState = s;
4168 KMMsgBase::setEncryptionState(s, idx);
4173 if( mSignatureState == s )
4175 mSignatureState = s;
4177 KMMsgBase::setSignatureState(s, idx);
4180 void KMMessage::setMDNSentState( KMMsgMDNSentState status,
int idx )
4182 if ( mMDNSentState ==
status )
4185 status = KMMsgMDNStateUnknown;
4188 KMMsgBase::setMDNSentState(
status, idx );
4194 Q_ASSERT( aStatus == KMMsgStatusReplied
4195 || aStatus == KMMsgStatusForwarded
4196 || aStatus == KMMsgStatusDeleted );
4198 TQString message =
headerField(
"X-KMail-Link-Message" );
4199 if ( !message.isEmpty() )
4201 TQString type =
headerField(
"X-KMail-Link-Type" );
4202 if ( !type.isEmpty() )
4205 message += TQString::number( aMsg->getMsgSerNum() );
4206 if ( aStatus == KMMsgStatusReplied )
4208 else if ( aStatus == KMMsgStatusForwarded )
4210 else if ( aStatus == KMMsgStatusDeleted )
4221 *reStatus = KMMsgStatusUnknown;
4223 TQString message =
headerField(
"X-KMail-Link-Message");
4225 message = message.section(
',', n, n);
4226 type = type.section(
',', n, n);
4228 if ( !message.isEmpty() && !type.isEmpty() ) {
4229 *retMsgSerNum = message.toULong();
4230 if ( type ==
"reply" )
4231 *reStatus = KMMsgStatusReplied;
4232 else if ( type ==
"forward" )
4233 *reStatus = KMMsgStatusForwarded;
4234 else if ( type ==
"deleted" )
4235 *reStatus = KMMsgStatusDeleted;
4242 if ( !part )
return 0;
4243 DwBodyPart* current;
4245 if ( part->partId() == partSpecifier )
4249 if ( part->hasHeaders() &&
4250 part->Headers().HasContentType() &&
4251 part->Body().FirstBodyPart() &&
4252 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) &&
4253 (current =
findDwBodyPart( part->Body().FirstBodyPart(), partSpecifier )) )
4259 if ( part->Body().Message() &&
4260 part->Body().Message()->Body().FirstBodyPart() &&
4261 (current =
findDwBodyPart( part->Body().Message()->Body().FirstBodyPart(),
4274 if ( !data.data() || !data.size() )
4277 DwString content( data.data(), data.size() );
4279 partSpecifier !=
"0" &&
4280 partSpecifier !=
"TEXT" )
4282 TQString specifier = partSpecifier;
4283 if ( partSpecifier.endsWith(
".HEADER") ||
4284 partSpecifier.endsWith(
".MIME") ) {
4286 specifier = partSpecifier.section(
'.', 0, -2 );
4291 kdDebug(5006) <<
"KMMessage::updateBodyPart " << specifier << endl;
4294 kdWarning(5006) <<
"KMMessage::updateBodyPart - can not find part "
4295 << specifier << endl;
4298 if ( partSpecifier.endsWith(
".MIME") )
4302 content.resize( TQMAX( content.length(), 2 ) - 2 );
4305 mLastUpdated->Headers().DeleteAllFields();
4306 mLastUpdated->Headers().FromString( content );
4307 mLastUpdated->Headers().Parse();
4308 }
else if ( partSpecifier.endsWith(
".HEADER") )
4311 mLastUpdated->Body().Message()->Headers().FromString( content );
4312 mLastUpdated->Body().Message()->Headers().Parse();
4315 mLastUpdated->Body().FromString( content );
4316 TQString parentSpec = partSpecifier.section(
'.', 0, -2 );
4317 if ( !parentSpec.isEmpty() )
4320 if ( parent && parent->hasHeaders() && parent->Headers().HasContentType() )
4322 const DwMediaType& contentType = parent->Headers().ContentType();
4323 if ( contentType.Type() == DwMime::kTypeMessage &&
4324 contentType.Subtype() == DwMime::kSubtypeRfc822 )
4328 parent->Body().Message()->Body().FromString( content );
4337 if ( partSpecifier ==
"TEXT" )
4339 mMsg->Body().FromString( content );
4340 mMsg->Body().Parse();
4342 mNeedsAssembly =
true;
4343 if (! partSpecifier.endsWith(
".HEADER") )
4350 void KMMessage::updateInvitationState()
4352 if ( mMsg && mMsg->hasHeaders() && mMsg->Headers().HasContentType() ) {
4353 TQString cntType = mMsg->Headers().ContentType().TypeStr().c_str();
4355 cntType += mMsg->Headers().ContentType().SubtypeStr().c_str();
4356 if ( cntType.lower() ==
"text/calendar" ) {
4361 setStatus( KMMsgStatusHasNoInvitation );
4366 void KMMessage::updateAttachmentState( DwBodyPart* part )
4378 bool filenameEmpty =
true;
4379 if ( part->hasHeaders() ) {
4380 if ( part->Headers().HasContentDisposition() ) {
4381 DwDispositionType cd = part->Headers().ContentDisposition();
4382 filenameEmpty = cd.Filename().empty();
4383 if ( filenameEmpty ) {
4385 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField( cd.AsString().c_str(),
"filename" ) ).isEmpty();
4391 if ( filenameEmpty && part->Headers().HasContentType() ) {
4392 DwMediaType contentType = part->Headers().ContentType();
4393 filenameEmpty = contentType.Name().empty();
4394 if ( filenameEmpty ) {
4396 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField(
4397 contentType.AsString().c_str(),
"name" ) ).isEmpty();
4402 if ( part->hasHeaders() &&
4403 ( ( part->Headers().HasContentDisposition() &&
4404 !part->Headers().ContentDisposition().Filename().empty() ) ||
4405 ( part->Headers().HasContentType() &&
4406 !filenameEmpty ) ) )
4409 if ( !part->Headers().HasContentType() ||
4410 ( part->Headers().HasContentType() &&
4411 part->Headers().ContentType().Subtype() != DwMime::kSubtypePgpSignature &&
4412 part->Headers().ContentType().Subtype() != DwMime::kSubtypePkcs7Signature ) )
4420 if ( part->hasHeaders() &&
4421 part->Headers().HasContentType() &&
4422 part->Body().FirstBodyPart() &&
4423 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) )
4425 updateAttachmentState( part->Body().FirstBodyPart() );
4429 if ( part->Body().Message() &&
4430 part->Body().Message()->Body().FirstBodyPart() )
4432 updateAttachmentState( part->Body().Message()->Body().FirstBodyPart() );
4437 updateAttachmentState( part->Next() );
4438 else if ( attachmentState() == KMMsgAttachmentUnknown )
4445 if ( encoding.isEmpty() )
4447 const TQTextCodec *
codec = KMMsgBase::codecForName( encoding );
4449 TQValueList<int> dummy;
4456 const TQTextCodec * c = mOverrideCodec;
4459 c = KMMsgBase::codecForName(
charset() );
4463 c = KMMsgBase::codecForName( GlobalSettings::self()->fallbackCharacterEncoding().latin1() );
4468 c = kmkernel->networkCodec();
4485 TQCString str( KPIM::getFirstEmailAddress(
rawHeaderField(
"From") ) );
4486 if ( str.isEmpty() )
4487 str =
"unknown@unknown.invalid";
4490 time_t t = ::time( 0 );
4492 const int len =
dateStr.length();
4496 return "From " + str +
" " +
dateStr +
"\n";
4501 sPendingDeletes <<
this;
4504 DwBodyPart* KMMessage::findPart(
int index )
4507 return findPartInternal( getTopLevelPart(), index, accu );
4510 DwBodyPart* KMMessage::findPartInternal(DwEntity * root,
int index,
int & accu)
4515 DwBodyPart *current =
dynamic_cast<DwBodyPart*
>( root );
4516 if ( index == accu )
4519 if ( root->Body().FirstBodyPart() )
4520 rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
4521 if ( !rv && current && current->Next() )
4522 rv = findPartInternal( current->Next(), index, accu );
4523 if ( !rv && root->Body().Message() )
4524 rv = findPartInternal( root->Body().Message(), index, accu );