12#include "mailinglist-magic.h"
13#include "messageproperty.h"
14using KMail::MessageProperty;
15#include "objecttreeparser.h"
16using KMail::ObjectTreeParser;
17#include "kmfolderindex.h"
20#include "headerstrategy.h"
21#include "globalsettings.h"
22using 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>
36#include <tdeapplication.h>
37#include <tdeglobalsettings.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>
52using KMime::HeaderParsing::parseAddressList;
53using namespace KMime::Types;
55#include <mimelib/body.h>
56#include <mimelib/field.h>
57#include <mimelib/mimepp.h>
58#include <mimelib/string.h>
68#include <tdemessagebox.h>
73static DwString emptyString(
"");
76static TQString sReplyLanguage, sReplyStr, sReplyAllStr, sIndentPrefixStr;
77static bool sSmartQuote,
80static TQStringList sPrefCharsets;
82TQString KMMessage::sForwardStr;
83const HeaderStrategy * KMMessage::sHeaderStrategy = HeaderStrategy::rich();
85static void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart );
87TQValueList<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();
132void KMMessage::init( DwMessage* aMsg )
134 mNeedsAssembly =
false;
138 mMsg =
new DwMessage;
147 mStatus = KMMsgStatusNew;
148 mEncryptionState = KMMsgEncryptionStateUnknown;
149 mSignatureState = KMMsgSignatureStateUnknown;
150 mMDNSentState = KMMsgMDNStateUnknown;
159void 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 );
201void 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();
305const 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();
396void KMMessage::fromByteArray(
const TQByteArray & ba,
bool setStatus ) {
400void 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++)
509static void removeTrailingSpace( TQString &line )
511 int i = line.length()-1;
512 while( (i >= 0) && ((line[i] ==
' ') || (line[i] ==
'\t')))
517static 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);
552static 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';
594static 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;
641static 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);
1329static 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.") },
1368static const int numMdnMessageBoxes
1369 =
sizeof mdnMessageBoxes /
sizeof *mdnMessageBoxes;
1372static 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);
1835TQString 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);
1850time_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);
1870void KMMessage::setDate(time_t aDate)
1873 mMsg->Headers().Date().FromCalendarTime(aDate);
1874 mMsg->Headers().Date().Assemble();
1875 mNeedsAssembly =
true;
1881void 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(
", " ) );
1909void KMMessage::setTo(
const TQString& aStr)
1915TQString KMMessage::toStrip()
const
1923 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Reply-To") );
1928void KMMessage::setReplyTo(
const TQString& aStr)
1935void KMMessage::setReplyTo(
KMMessage* aMsg)
1948 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1951 return KPIM::normalizeAddressesAndDecodeIDNs(
headers.join(
", " ) );
1956void KMMessage::setCc(
const TQString& aStr)
1963TQString KMMessage::ccStrip()
const
1972 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Bcc") );
1977void KMMessage::setBcc(
const TQString& aStr)
1990void KMMessage::setFcc(
const TQString &aStr )
1996void KMMessage::setDrafts(
const TQString &aStr )
2002void KMMessage::setTemplates(
const TQString &aStr )
2011 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(mParent->whoField().utf8()) );
2019 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"From") );
2024void KMMessage::setFrom(
const TQString& bStr)
2026 TQString aStr = bStr;
2035TQString KMMessage::fromStrip()
const
2042 AddrSpecList asl = extractAddrSpecs(
"Sender" );
2044 asl = extractAddrSpecs(
"From" );
2047 return asl.front().asString();
2058void KMMessage::setSubject(
const TQString& aStr)
2073void 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)
2122TQString 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 );
2176void 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)
2201TQString KMMessage::msgIdMD5()
const {
2202 return base64EncodedMD5(
msgId() );
2207void KMMessage::setMsgId(
const TQString& aStr)
2220void KMMessage::setMsgSizeServer(
size_t size)
2233void 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!"
2257AddrSpecList 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();
2402int KMMessage::type()
const
2404 DwHeaders& header = mMsg->Headers();
2405 if (header.HasContentType())
return header.ContentType().Type();
2406 else return DwMime::kTypeNull;
2411void KMMessage::setTypeStr(
const TQCString& aStr)
2415 mNeedsAssembly =
true;
2420void KMMessage::setType(
int aType)
2424 mNeedsAssembly =
true;
2432 DwHeaders& header = mMsg->Headers();
2433 if (header.HasContentType())
return header.ContentType().SubtypeStr().c_str();
2439int KMMessage::subtype()
const
2441 DwHeaders& header = mMsg->Headers();
2442 if (header.HasContentType())
return header.ContentType().Subtype();
2443 else return DwMime::kSubtypeNull;
2448void KMMessage::setSubtypeStr(
const TQCString& aStr)
2452 mNeedsAssembly =
true;
2457void 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();
2511int KMMessage::contentTransferEncoding( DwEntity *entity )
const
2516 DwHeaders& header = entity->Headers();
2517 if ( header.HasContentTransferEncoding() )
2518 return header.ContentTransferEncoding().AsEnum();
2519 else return DwMime::kCteNull;
2524void KMMessage::setContentTransferEncodingStr(
const TQCString& cteString,
2530 entity->Headers().ContentTransferEncoding().FromString( cteString );
2531 entity->Headers().ContentTransferEncoding().Parse();
2532 mNeedsAssembly =
true;
2537void 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();
2584TQByteArray 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;
2747void 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();
3035void 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);
4180void 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") )
4350void 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 );
4366void 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;
4504DwBodyPart* KMMessage::findPart(
int index )
4507 return findPartInternal( getTopLevelPart(), index, accu );
4510DwBodyPart* 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 );
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
uint identityUoid() const
int partNumber(DwBodyPart *aDwBodyPart) const
Get the number of the given DwBodyPart.
void link(const KMMessage *aMsg, KMMsgStatus aStatus)
Links this message to aMsg, setting link type to aStatus.
void updateBodyPart(const TQString partSpecifier, const TQByteArray &data)
Sets the body of the specified part.
static KPIM::EmailParseResult isValidEmailAddressList(const TQString &aStr, TQString &brokenAddress)
Validate a list of email addresses, and also allow aliases and distribution lists to be expanded befo...
TQString who() const
Get or set the 'Who' header field.
void setBody(const TQCString &aStr)
Set the message body.
static TQString generateMessageId(const TQString &addr)
Generates the Message-Id.
DwBodyPart * getFirstDwBodyPart() const
Get the 1st DwBodyPart.
TQCString bodyDecoded() const
Returns a decoded version of the body from the current content transfer encoding.
TQString formatString(const TQString &) const
Convert wildcards into normal string.
void setBodyFromUnicode(const TQString &str, DwEntity *entity=0)
Sets this body's content to str.
TQCString typeStr() const
Get or set the 'Content-Type' header field The member functions that involve enumerated types (ints) ...
static TQString quoteHtmlChars(const TQString &str, bool removeLineBreaks=false)
Quotes the following characters which have a special meaning in HTML: '<' '>' '&' '"'....
TQCString getRefStr() const
Creates reference string for reply to messages.
void setBodyEncoded(const TQCString &aStr, DwEntity *entity=0)
Set the message body, encoding it according to the current content transfer encoding.
TQString templates() const
Get or set the 'Templates' folder.
static void bodyPart(DwBodyPart *aDwBodyPart, KMMessagePart *aPart, bool withBody=true)
Fill the KMMessagePart structure for a given DwBodyPart.
void setDateToday()
Set the 'Date' header field to the current date.
void removeHeaderFields(const TQCString &name)
Remove all header fields with given name.
void parseTextStringFromDwPart(partNode *root, TQCString &parsedString, const TQTextCodec *&codec, bool &isHTML) const
Returns a decoded body part string to be further processed by function asQuotedString().
static KMime::Types::AddressList splitAddrField(const TQCString &str)
Splits the given address list into separate addresses.
size_t msgSizeServer() const
Get/set size on server.
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
TQCString body() const
Get the message body.
TQString msgId() const
Get or set the 'Message-Id' header field.
TQString from() const
Get or set the 'From' header field.
TQCString charset() const
Get the message charset.
static TQValueList< int > determineAllowedCtes(const KMime::CharFreq &cf, bool allow8Bit, bool willBeSigned)
Returns a list of content-transfer-encodings that can be used with the given result of the character ...
void setAutomaticFields(bool isMultipart=false)
Set fields that are either automatically set (Message-id) or that do not change from one message to a...
void setCharset(const TQCString &charset, DwEntity *entity=0)
Sets the charset of the message or a subpart of the message.
TQString asQuotedString(const TQString &headerStr, const TQString &indentStr, const TQString &selection=TQString(), bool aStripSignature=true, bool allowDecryption=true) const
Returns message body with quoting header and indented by the given indentation string.
bool readyToShow() const
Return if the message is ready to be shown.
TQString xmark() const
Get or set the 'X-Mark' header field.
static TQCString html2source(const TQCString &src)
Convert '<' into "<" resp.
TQString bcc() const
Get or set the 'Bcc' header field.
static void readConfig()
Reads config settings from group "KMMessage" and sets all internal variables (e.g.
KMMsgInfo * msgInfo()
Get the KMMsgInfo object that was set with setMsgInfo().
void setNeedsAssembly()
tell the message that internal data were changed (must be called after directly modifying message str...
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
static TQStringList stripMyAddressesFromAddressList(const TQStringList &list)
Strips all the user's addresses from an address list.
void setUnencryptedMsg(KMMessage *unencrypted)
Specifies an unencrypted copy of this message to be stored in a separate member variable to allow sav...
static bool addressIsInAddressList(const TQString &address, const TQStringList &addresses)
Returns true if the given address is contained in the given address list.
DwMediaType & dwContentType()
Return reference to Content-Type header for direct manipulation.
bool deleteBodyPart(int partIndex)
Delete a body part with the specified part index.
TQString replyToAuxIdMD5() const
Get the second to last id from the References header field.
TQString to() const
Get or set the 'To' header field.
TQString subject() const
Get or set the 'Subject' header field.
KMMessage * createForward(const TQString &tmpl=TQString())
Create a new message that is a forward of this message, filling all required header fields with the p...
void setStatusFields()
Set "Status" and "X-Status" fields of the message from the internal message status.
void removeHeaderField(const TQCString &name)
Remove header field with given name.
KMMsgEncryptionState encryptionState() const
Encryption status of the message.
static TQStringList stripAddressFromAddressList(const TQString &address, const TQStringList &addresses)
Strips an address from an address list.
TQCString headerAsSendableString() const
Return the message header with the headers that should not be sent stripped off.
TQCString subtypeStr() const
Subtype.
static TQString smartQuote(const TQString &msg, int maxLineLength)
Given argument msg add quoting characters and relayout for max width maxLength.
void addDwBodyPart(DwBodyPart *aDwPart)
Append a DwBodyPart to the message.
static const TQStringList & preferredCharsets()
Get a list of preferred message charsets.
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
TQValueList< TQCString > rawHeaderFields(const TQCString &field) const
Returns a list of the raw values of all header fields with the given name.
KMMessage * createReply(KMail::ReplyStrategy replyStrategy=KMail::ReplySmart, TQString selection=TQString(), bool noQuote=false, bool allowDecryption=true, const TQString &tmpl=TQString(), const TQString &originatingAccount=TQString())
Create a new message that is a reply to this message, filling all required header fields with the pro...
static TQString expandAliases(const TQString &recipients)
Expands aliases (distribution lists and nick names) and appends a domain part to all email addresses ...
virtual ~KMMessage()
Destructor.
TQStringList headerFields(const TQCString &name) const
Returns a list of the values of all header fields with the given name.
TQString asPlainTextFromObjectTree(partNode *root, bool stripSignature, bool allowDecryption) const
Same as asPlainText(), only that this method expects an already parsed object tree as paramter.
static void setDwMediaTypeParam(DwMediaType &mType, const TQCString &attr, const TQCString &val)
add or change a parameter of a DwMediaType field
TQCString asString() const
Return the entire message contents as a string.
static TQString encodeMailtoUrl(const TQString &str)
Encodes an email address as mailto URL.
KMime::Types::AddressList headerAddrField(const TQCString &name) const
Returns header address list as string list.
TQByteArray asSendableString() const
Return the message contents with the headers that should not be sent stripped off.
static TQCString stripEmailAddr(const TQCString &emailAddr)
This function generates a displayable string from a list of email addresses.
KMMessage * createRedirect(const TQString &toStr)
Create a new message that is a redirect to this message, filling all required header fields with the ...
static TQString emailAddrAsAnchor(const TQString &emailAddr, bool stripped=true, const TQString &cssStyle=TQString(), bool link=true)
Converts the email address(es) to (a) nice HTML mailto: anchor(s).
void setSignatureState(const KMMsgSignatureState, int idx=-1)
Set signature status of the message.
TQString bodyToUnicode(const TQTextCodec *codec=0) const
Returns the body part decoded to unicode.
TQString asPlainText(bool stripSignature, bool allowDecryption) const
Return the textual content of the message as plain text, converting HTML to plain text if necessary.
KMMessage * createMDN(KMime::MDN::ActionMode a, KMime::MDN::DispositionType d, bool allowGUI=false, TQValueList< KMime::MDN::DispositionModifier > m=TQValueList< KMime::MDN::DispositionModifier >())
Create a new message that is a MDN for this message, filling all required fields with proper values.
void addBodyPart(const KMMessagePart *aPart)
Append a body part to the message.
TQString references() const
Get or set the references for this message.
void removePrivateHeaderFields()
Remove all private header fields: Status: and X-KMail-
const DwString & asDwString() const
Return the entire message contents in the DwString.
bool transferInProgress() const
Return, if the message should not be deleted.
void setMsgSerNum(unsigned long newMsgSerNum=0)
Sets the message serial number.
void sanitizeHeaders(const TQStringList &whiteList=TQStringList())
Remove all headers but the content description ones, and those in the white list.
static TQString decodeMailtoUrl(const TQString &url)
Decodes a mailto URL.
TQString cc() const
Get or set the 'Cc' header field.
const TQTextCodec * codec() const
Get a TQTextCodec suitable for this message part.
bool isMessage() const
Returns TRUE if object is a real message (not KMMsgInfo or KMMsgBase)
KMMsgStatus status() const
Status of the message.
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
void applyIdentity(uint id)
Set the from, to, cc, bcc, encrytion etc headers as specified in the given identity.
void deleteWhenUnused()
Delete this message as soon as it no longer in use.
TQString strippedSubjectMD5() const
Get a hash of the subject with all prefixes such as Re: removed.
static TQCString defaultCharset()
Get the default message charset.
TQCString mboxMessageSeparator()
Returns an mbox message separator line for this message, i.e.
TQString replaceHeadersInString(const TQString &s) const
Replaces every occurrence of "${foo}" in s with headerField("foo")
TQCString id() const
Returns the message ID, useful for followups.
void initFromMessage(const KMMessage *msg, bool idHeaders=true)
Initialize headers fields according to the identity and the transport header of the given original me...
TQCString createForwardBody()
Create the forwarded body for the message.
void setBodyAndGuessCte(const TQByteArray &aBuf, TQValueList< int > &allowedCte, bool allow8Bit=false, bool willBeSigned=false, DwEntity *entity=0)
Sets body, encoded in the best fitting content-transfer-encoding, which is determined by character fr...
void cleanupHeader()
Removes empty fields from the header, e.g.
int numBodyParts() const
Number of body parts the message has.
KMMessage * unencryptedMsg() const
Returns an unencrypted copy of this message or 0 if none exists.
static TQString guessEmailAddressFromLoginName(const TQString &userName)
Uses the hostname as domain part and tries to determine the real name from the entries in the passwor...
KMMessage(KMFolder *parent=0)
Straight forward initialization.
TQString replyToId() const
Get or set the 'In-Reply-To' header field.
TQCString rawHeaderField(const TQCString &name) const
Returns the raw value of a header field with the given name.
void setContentTypeParam(const TQCString &attr, const TQCString &val)
add or change a parameter of the Content-Type field
TQString drafts() const
Get or set the 'Drafts' folder.
DwBodyPart * dwBodyPart(int aIdx) const
Get the DwBodyPart at position in aIdx.
void setMultiPartBody(const TQCString &aStr)
Hack to enable structured body parts to be set as flat text...
TQCString contentTransferEncodingStr() const
Get or set the 'Content-Transfer-Encoding' header field The member functions that involve enumerated ...
bool hasUnencryptedMsg() const
Returns TRUE if the message contains an unencrypted copy of itself.
TQString replyTo() const
Get or set the 'ReplyTo' header field.
KMMessage * createDeliveryReceipt() const
Create a new message that is a delivery receipt of this message, filling required header fileds with ...
void setEncryptionState(const KMMsgEncryptionState, int idx=-1)
Set encryption status of the message.
TQString fcc() const
Get or set the 'Fcc' header field.
void getLink(int n, ulong *retMsgSerNum, KMMsgStatus *reStatus) const
Returns the information for the Nth link into retMsg and reStatus.
TQCString dateShortStr() const
Returns the message date in asctime format or an empty string if the message lacks a Date header.
DwHeaders & headers() const
get the DwHeaders (make sure to call setNeedsAssembly() function after directly modyfying internal da...
TQString subjectMD5() const
Get a hash of the subject.
TQString headerAsString() const
Return header as string.
void initHeader(uint identity=0)
Initialize header fields.
bool subjectIsPrefixed() const
Is the subject prefixed by Re: or similar?
void setHeaderField(const TQCString &name, const TQString &value, HeaderFieldType type=Unstructured, bool prepend=false)
Set the header field with the given name to the given value.
void assembleIfNeeded()
Assemble the internal message.
ulong UID() const
Get/set UID.
DwBodyPart * findDwBodyPart(int type, int subtype) const
Return the first DwBodyPart matching a given Content-Type or zero, if no found.
void deleteBodyParts()
Delete all body parts.
TQString dateStr() const
Get or set the 'Date' header field.
KMMsgSignatureState signatureState() const
Signature status of the message.
DwBodyPart * createDWBodyPart(const KMMessagePart *aPart)
Compose a DwBodyPart (needed for adding a part to the message).
The TemplateParser transforms a message with a given template.
void setAllowDecryption(const bool allowDecryption)
Sets whether the template parser is allowed to decrypt the original message when needing its message ...
void setSelection(const TQString &selection)
Sets the selection.
TQByteArray ByteArray(const DwString &str)
Construct a TQByteArray from a DwString.
TQCString CString(const DwString &str)
Construct a TQCString from a DwString.
DwString dwString(const TQCString &str)
Construct a DwString from a TQCString.