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