12 #include "kmmessage.h"
13 #include "mailinglist-magic.h"
14 #include "messageproperty.h"
15 using KMail::MessageProperty;
16 #include "objecttreeparser.h"
17 using KMail::ObjectTreeParser;
18 #include "kmfolderindex.h"
19 #include "undostack.h"
20 #include "kmversion.h"
21 #include "headerstrategy.h"
22 #include "globalsettings.h"
23 using KMail::HeaderStrategy;
24 #include "kmaddrbook.h"
25 #include "kcursorsaver.h"
26 #include "templateparser.h"
28 #include <libkpimidentities/identity.h>
29 #include <libkpimidentities/identitymanager.h>
30 #include <libemailfunctions/email.h>
32 #include <kasciistringtools.h>
34 #include <kpgpblock.h>
35 #include <kaddrbook.h>
37 #include <tdeapplication.h>
38 #include <tdeglobalsettings.h>
40 #include <tdeconfig.h>
41 #include <tdehtml_part.h>
44 #include <kasciistricmp.h>
47 #include <tqtextcodec.h>
48 #include <tqmessagebox.h>
49 #include <kmime_util.h>
50 #include <kmime_charfreq.h>
52 #include <kmime_header_parsing.h>
53 using KMime::HeaderParsing::parseAddressList;
54 using namespace KMime::Types;
56 #include <mimelib/body.h>
57 #include <mimelib/field.h>
58 #include <mimelib/mimepp.h>
59 #include <mimelib/string.h>
63 #include <tdelocale.h>
69 #include <tdemessagebox.h>
72 using namespace KMime;
74 static DwString emptyString(
"");
77 static TQString sReplyLanguage, sReplyStr, sReplyAllStr, sIndentPrefixStr;
78 static bool sSmartQuote,
81 static TQStringList sPrefCharsets;
83 TQString KMMessage::sForwardStr;
84 const HeaderStrategy * KMMessage::sHeaderStrategy = HeaderStrategy::rich();
86 static void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart );
88 TQValueList<KMMessage*> KMMessage::sPendingDeletes;
96 mNeedsAssembly =
true;
111 mMsgSize = msgInfo.msgSize();
112 mFolderOffset = msgInfo.folderOffset();
113 mStatus = msgInfo.status();
114 mEncryptionState = msgInfo.encryptionState();
115 mSignatureState = msgInfo.signatureState();
116 mMDNSentState = msgInfo.mdnSentState();
117 mDate = msgInfo.date();
118 mFileName = msgInfo.fileName();
119 KMMsgBase::assign(&msgInfo);
133 void KMMessage::init( DwMessage* aMsg )
135 mNeedsAssembly =
false;
139 mMsg =
new DwMessage;
148 mStatus = KMMsgStatusNew;
149 mEncryptionState = KMMsgEncryptionStateUnknown;
150 mSignatureState = KMMsgSignatureStateUnknown;
151 mMDNSentState = KMMsgMDNStateUnknown;
160 void KMMessage::assign(
const KMMessage& other )
162 MessageProperty::forget(
this );
164 delete mUnencryptedMsg;
166 mNeedsAssembly =
true;
168 mMsg =
new DwMessage( *(other.mMsg) );
171 mOverrideCodec = other.mOverrideCodec;
172 mDecodeHTML = other.mDecodeHTML;
173 mMsgSize = other.mMsgSize;
174 mMsgLength = other.mMsgLength;
175 mFolderOffset = other.mFolderOffset;
176 mStatus = other.mStatus;
177 mEncryptionState = other.mEncryptionState;
178 mSignatureState = other.mSignatureState;
179 mMDNSentState = other.mMDNSentState;
180 mIsParsed = other.mIsParsed;
186 setDrafts( other.
drafts() );
197 kmkernel->undoStack()->msgDestroyed(
this );
202 void KMMessage::setReferences(
const TQCString& aStr)
204 if (aStr.isNull())
return;
205 mMsg->Headers().References().FromString(aStr);
206 mNeedsAssembly =
true;
213 DwHeaders& header = mMsg->Headers();
214 if (header.HasMessageId())
228 MessageProperty::setSerialCache(
this, newMsgSerNum );
250 sPendingDeletes.remove(
this );
252 int idx = parent()->find(
this );
254 parent()->removeMsg( idx );
263 return headerField(
"Priority" ).contains(
"urgent",
false )
270 delete mUnencryptedMsg;
271 mUnencryptedMsg = unencrypted;
277 TQString& brokenAddress )
279 if ( aStr.isEmpty() ) {
280 return KPIM::AddressEmpty;
283 TQStringList list = KPIM::splitEmailAddrList( aStr );
284 for( TQStringList::const_iterator it = list.begin(); it != list.end(); ++it ) {
285 KPIM::EmailParseResult errorCode = KPIM::isValidEmailAddress( *it );
286 if ( errorCode != KPIM::AddressOk ) {
287 brokenAddress = ( *it );
291 return KPIM::AddressOk;
299 mNeedsAssembly =
false;
302 return mMsg->AsString();
306 const DwMessage* KMMessage::asDwMessage()
310 mNeedsAssembly =
false;
324 KMMessage msg(
new DwMessage( *this->mMsg ) );
332 KMMessage msg(
new DwMessage( *this->mMsg ) );
356 char str[2] = { 0, 0 };
368 str[0] =
static_cast<char>( mdnSentState() );
373 mNeedsAssembly =
false;
374 mMsg->Headers().Assemble();
375 mMsg->Assemble( mMsg->Headers(),
383 DwHeaders& header = mMsg->Headers();
385 if ( header.AsString().empty() )
387 return TQString::fromLatin1( header.AsString().c_str() );
394 return mMsg->Headers().ContentType();
397 void KMMessage::fromByteArray(
const TQByteArray & ba,
bool setStatus ) {
398 return fromDwString( DwString( ba.data(), ba.size() ), setStatus );
401 void KMMessage::fromString(
const TQCString & str,
bool aSeStatus ) {
408 mMsg =
new DwMessage;
409 mMsg->FromString( str );
414 setEncryptionStateChar(
headerField(
"X-KMail-EncryptionState").at(0) );
415 setSignatureStateChar(
headerField(
"X-KMail-SignatureState").at(0) );
416 setMDNSentState( static_cast<KMMsgMDNSentState>(
headerField(
"X-KMail-MDN-Sent").at(0).latin1() ) );
418 if ( invitationState() == KMMsgInvitationUnknown &&
readyToShow() )
419 updateInvitationState();
420 if ( attachmentState() == KMMsgAttachmentUnknown &&
readyToShow() )
421 updateAttachmentState();
423 mNeedsAssembly =
false;
431 TQString result, str;
438 unsigned int strLength(aStr.length());
439 for (uint i=0; i<strLength;) {
449 result += KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
450 date(), sReplyLanguage,
false );
456 result += fromStrip();
462 for (j=0; str[j]>
' '; j++)
464 unsigned int strLength(str.length());
465 for (; j < strLength && str[j] <=
' '; j++)
510 static void removeTrailingSpace( TQString &line )
512 int i = line.length()-1;
513 while( (i >= 0) && ((line[i] ==
' ') || (line[i] ==
'\t')))
518 static TQString splitLine( TQString &line)
520 removeTrailingSpace( line );
523 int l = line.length();
530 if ((c ==
'>') || (c ==
':') || (c ==
'|'))
532 else if ((c !=
' ') && (c !=
'\t'))
543 TQString result = line.left(j);
548 TQString result = line.left(j);
553 static TQString flowText(TQString &text,
const TQString& indent,
int maxLength)
558 return indent+
"<NULL>\n";
564 if ((
int) text.length() > maxLength)
567 while( (i >= 0) && (text[i] !=
' '))
582 TQString line = text.left(i);
583 if (i < (
int) text.length())
588 result += indent + line +
'\n';
595 static bool flushPart(TQString &msg, TQStringList &part,
596 const TQString &indent,
int maxLength)
598 maxLength -= indent.length();
599 if (maxLength < 20) maxLength = 20;
602 while ((part.begin() != part.end()) && part.last().isEmpty())
604 part.remove(part.fromLast());
608 for(TQStringList::Iterator it2 = part.begin();
612 TQString line = (*it2);
617 msg += flowText(text, indent, maxLength);
618 msg += indent +
'\n';
625 text +=
' '+line.stripWhiteSpace();
627 if (((
int) text.length() < maxLength) || ((
int) line.length() < (maxLength-10)))
628 msg += flowText(text, indent, maxLength);
632 msg += flowText(text, indent, maxLength);
634 bool appendEmptyLine =
true;
636 appendEmptyLine =
false;
639 return appendEmptyLine;
642 static TQString stripSignature(
const TQString & msg,
bool clearSigned ) {
644 return msg.left( msg.findRev( TQRegExp(
"\n--\\s?\n" ) ) );
646 return msg.left( msg.findRev(
"\n-- \n" ) );
653 bool firstPart =
true;
656 const TQStringList lines = TQStringList::split(
'\n', msg,
true);
659 for(TQStringList::const_iterator it = lines.begin();
665 const TQString indent = splitLine( line );
670 part.append(TQString());
680 if (oldIndent != indent)
684 if (part.count() && (oldIndent.length() < indent.length()))
686 TQStringList::Iterator it2 = part.fromLast();
687 while( (it2 != part.end()) && (*it2).isEmpty())
690 if ((it2 != part.end()) && ((*it2).endsWith(
":")))
692 fromLine = oldIndent + (*it2) +
'\n';
696 if (flushPart( result, part, oldIndent, maxLineLength))
698 if (oldIndent.length() > indent.length())
699 result += indent +
'\n';
701 result += oldIndent +
'\n';
703 if (!fromLine.isEmpty())
711 flushPart( result, part, oldIndent, maxLineLength);
718 TQCString& parsedString,
719 const TQTextCodec*& codec,
725 partNode * curNode = root->findType( DwMime::kTypeText,
726 DwMime::kSubtypeUnknown,
729 kdDebug(5006) <<
"\n\n======= KMMessage::parseTextStringFromDwPart() - "
730 << ( curNode ?
"text part found!\n" :
"sorry, no text node!\n" ) << endl;
732 isHTML = DwMime::kSubtypeHtml == curNode->subType();
734 ObjectTreeParser otp( 0, 0,
true,
false,
true );
735 otp.parseObjectTree( curNode );
736 parsedString = otp.rawReplyString();
737 codec = curNode->msgPart().codec();
744 bool allowDecryption )
const
747 Q_ASSERT( root->processed() );
749 TQCString parsedString;
751 const TQTextCodec *
codec = 0;
753 if ( !root )
return TQString();
756 if ( mOverrideCodec || !codec )
757 codec = this->
codec();
759 if ( parsedString.isEmpty() )
762 bool clearSigned =
false;
766 if ( allowDecryption ) {
767 TQPtrList<Kpgp::Block> pgpBlocks;
768 TQStrList nonPgpBlocks;
769 if ( Kpgp::Module::prepareMessageForDecryption( parsedString,
774 if ( pgpBlocks.count() == 1 ) {
775 Kpgp::Block * block = pgpBlocks.first();
776 if ( block->type() == Kpgp::PgpMessageBlock ||
777 block->type() == Kpgp::ClearsignedBlock ) {
778 if ( block->type() == Kpgp::PgpMessageBlock ) {
787 result = codec->toUnicode( nonPgpBlocks.first() )
788 + codec->toUnicode( block->text() )
789 + codec->toUnicode( nonPgpBlocks.last() );
795 if ( result.isEmpty() ) {
796 result = codec->toUnicode( parsedString );
797 if ( result.isEmpty() )
802 if ( isHTML && mDecodeHTML ) {
803 TDEHTMLPart htmlPart;
804 htmlPart.setOnlyLocalReferences(
true );
805 htmlPart.setMetaRefreshEnabled(
false );
806 htmlPart.setPluginsEnabled(
false );
807 htmlPart.setJScriptEnabled(
false );
808 htmlPart.setJavaEnabled(
false );
810 htmlPart.write( result );
812 htmlPart.selectAll();
813 result = htmlPart.selectedText();
817 if ( aStripSignature )
818 return stripSignature( result, clearSigned );
827 partNode *root = partNode::fromMessage(
this );
831 ObjectTreeParser otp;
832 otp.parseObjectTree( root );
839 const TQString& aIndentStr,
840 const TQString& selection ,
841 bool aStripSignature ,
842 bool allowDecryption )
const
844 TQString content = selection.isEmpty() ?
845 asPlainText( aStripSignature, allowDecryption ) : selection ;
848 const int firstNonWS = content.find( TQRegExp(
"\\S" ) );
849 const int lineStart = content.findRev(
'\n', firstNonWS );
850 if ( lineStart >= 0 )
851 content.remove( 0, static_cast<unsigned int>( lineStart ) );
855 content.replace(
'\n',
'\n' + indentStr );
856 content.prepend( indentStr );
860 if ( sSmartQuote && sWordWrap )
861 return headerStr +
smartQuote( content, sWrapCol );
862 return headerStr + content;
869 bool allowDecryption ,
870 const TQString &tmpl ,
871 const TQString &originatingAccount )
874 TQString mailingListStr, replyToStr, toStr;
875 TQStringList mailingListAddresses;
876 TQCString refStr, headerName;
877 bool replyAll =
true;
881 MailingList::name(
this, headerName, mailingListStr);
887 if ( parent() && parent()->isMailingListEnabled() &&
888 !parent()->mailingListPostAddress().isEmpty() ) {
889 mailingListAddresses << parent()->mailingListPostAddress();
891 if (
headerField(
"List-Post").find(
"mailto:", 0,
false ) != -1 ) {
893 TQRegExp rx(
"<mailto:([^@>]+)@([^>]+)>",
false );
894 if ( rx.search( listPost, 0 ) != -1 )
895 mailingListAddresses << rx.cap(1) +
'@' + rx.cap(2);
899 switch( replyStrategy ) {
900 case KMail::ReplySmart : {
901 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
904 else if ( !replyToStr.isEmpty() ) {
908 else if ( !mailingListAddresses.isEmpty() ) {
909 toStr = mailingListAddresses[0];
918 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
921 if ( toStr.isEmpty() && !recipients.isEmpty() )
922 toStr = recipients[0];
926 case KMail::ReplyList : {
927 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
930 else if ( !mailingListAddresses.isEmpty() ) {
931 toStr = mailingListAddresses[0];
933 else if ( !replyToStr.isEmpty() ) {
938 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
943 case KMail::ReplyAll : {
944 TQStringList recipients;
945 TQStringList ccRecipients;
948 if( !replyToStr.isEmpty() ) {
949 recipients += KPIM::splitEmailAddrList( replyToStr );
952 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
953 it != mailingListAddresses.end();
959 if ( !mailingListAddresses.isEmpty() ) {
961 if ( recipients.isEmpty() && !
from().isEmpty() ) {
964 ccRecipients +=
from();
965 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of CC recipients"
969 recipients.prepend( mailingListAddresses[0] );
973 if ( recipients.isEmpty() && !
from().isEmpty() ) {
976 recipients +=
from();
977 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of recipients"
986 if( !
cc().isEmpty() || !
to().isEmpty() ) {
989 list += KPIM::splitEmailAddrList(
to());
991 list += KPIM::splitEmailAddrList(
cc());
992 for( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
996 kdDebug(5006) <<
"Added " << *it <<
" to the list of CC recipients"
1002 if ( !ccRecipients.isEmpty() ) {
1008 if ( toStr.isEmpty() && !ccRecipients.isEmpty() ) {
1009 toStr = ccRecipients[0];
1010 ccRecipients.pop_front();
1013 msg->setCc( ccRecipients.join(
", ") );
1016 if ( toStr.isEmpty() && !recipients.isEmpty() ) {
1018 toStr = recipients[0];
1022 case KMail::ReplyAuthor : {
1023 if ( !replyToStr.isEmpty() ) {
1024 TQStringList recipients = KPIM::splitEmailAddrList( replyToStr );
1027 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
1028 it != mailingListAddresses.end();
1032 if ( !recipients.isEmpty() ) {
1033 toStr = recipients.join(
", ");
1041 else if ( !
from().isEmpty() ) {
1047 case KMail::ReplyNone : {
1052 if (!originatingAccount.isEmpty()) {
1053 msg->setOriginatingAccountName(originatingAccount);
1059 if (!refStr.isEmpty())
1060 msg->setReferences(refStr);
1062 msg->setReplyToId(
msgId());
1074 msg->setSubject( replySubject() );
1076 formatString( GlobalSettings::self()->quoteString() ) );
1078 TemplateParser parser( msg, ( replyAll ? TemplateParser::ReplyAll : TemplateParser::Reply ) );
1080 if ( GlobalSettings::quoteSelectionOnly() ) {
1083 if ( !tmpl.isEmpty() ) {
1084 parser.process( tmpl,
this );
1086 parser.process(
this );
1090 msg->
link(
this, KMMsgStatusReplied);
1092 if ( parent() && parent()->putRepliesInSameFolder() )
1093 msg->setFcc( parent()->idString() );
1108 TQCString firstRef, lastRef, refStr, retRefStr;
1111 refStr =
headerField(
"References").stripWhiteSpace().latin1();
1113 if (refStr.isEmpty())
1116 i = refStr.find(
'<');
1117 j = refStr.find(
'>');
1118 firstRef = refStr.mid(i, j-i+1);
1119 if (!firstRef.isEmpty())
1120 retRefStr = firstRef +
' ';
1122 i = refStr.findRev(
'<');
1123 j = refStr.findRev(
'>');
1125 lastRef = refStr.mid(i, j-i+1);
1126 if (!lastRef.isEmpty() && lastRef != firstRef)
1127 retRefStr += lastRef +
' ';
1138 KMMessagePart msgPart;
1141 TQString strId = msg->
headerField(
"X-KMail-Identity" ).stripWhiteSpace();
1142 if ( !strId.isEmpty())
1143 id = strId.toUInt();
1144 const KPIM::Identity & ident =
1145 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1148 TQString strByWayOf = TQString(
"%1 (by way of %2 <%3>)")
1150 .arg( ident.fullName() )
1151 .arg( ident.primaryEmailAddress() );
1154 TQString strFrom = TQString(
"%1 <%2>")
1155 .arg( ident.fullName() )
1156 .arg( ident.primaryEmailAddress() );
1163 if ( origDate.isEmpty() )
1178 msg->
link(
this, KMMsgStatusForwarded);
1190 if (sHeaderStrategy == HeaderStrategy::all()) {
1191 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1194 str +=
"\n-------------------------------------------------------\n";
1196 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1197 s +=
"Subject: " +
subject() +
"\n";
1199 + KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
1200 date(), sReplyLanguage,
false )
1202 s +=
"From: " +
from() +
"\n";
1203 s +=
"To: " +
to() +
"\n";
1204 if (!
cc().isEmpty()) s +=
"Cc: " +
cc() +
"\n";
1207 str +=
"\n-------------------------------------------------------\n";
1217 DwHeaders& header = mMsg->Headers();
1218 DwField* field = header.FirstField();
1222 nextField = field->Next();
1223 if ( field->FieldNameStr().find(
"ontent" ) == DwString::npos
1224 && !whiteList.contains( TQString::fromLatin1( field->FieldNameStr().c_str() ) ) )
1225 header.RemoveField(field);
1239 if ( type() == DwMime::kTypeMultipart ||
1240 ( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypePlain ) ) {
1245 DwMediaType oldContentType = msg->mMsg->Headers().ContentType();
1250 TQStringList blacklist = GlobalSettings::self()->mimetypesToStripWhenInlineForwarding();
1251 for ( TQStringList::Iterator it = blacklist.begin(); it != blacklist.end(); ++it ) {
1252 TQString entry = (*it);
1253 int sep = entry.find(
'/' );
1254 TQCString type = entry.left( sep ).latin1();
1255 TQCString subtype = entry.mid( sep+1 ).latin1();
1256 kdDebug( 5006 ) <<
"Looking for blacklisted type: " << type <<
"/" << subtype << endl;
1257 while ( DwBodyPart * part = msg->
findDwBodyPart( type, subtype ) ) {
1258 msg->mMsg->Body().RemoveBodyPart( part );
1261 msg->mMsg->Assemble();
1265 msg->mMsg->Headers().ContentType().FromString( oldContentType.AsString() );
1266 msg->mMsg->Headers().ContentType().Parse();
1267 msg->mMsg->Assemble();
1269 else if( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypeHtml ) {
1273 msg->setType( DwMime::kTypeText );
1274 msg->setSubtype( DwMime::kSubtypeHtml );
1275 msg->mNeedsAssembly =
true;
1285 DwHeaders & header = msg->mMsg->Headers();
1286 header.MimeVersion().FromString(
"1.0");
1288 contentType.SetType( DwMime::kTypeMultipart );
1289 contentType.SetSubtype( DwMime::kSubtypeMixed );
1290 contentType.CreateBoundary(0);
1291 contentType.Assemble();
1294 KMMessagePart msgPart;
1298 KMMessagePart secondPart;
1299 secondPart.setType( type() );
1300 secondPart.setSubtype( subtype() );
1301 secondPart.setBody( mMsg->Body().AsString() );
1303 applyHeadersToMessagePart( mMsg->Headers(), &secondPart );
1305 msg->mNeedsAssembly =
true;
1310 msg->setSubject( forwardSubject() );
1313 if ( !tmpl.isEmpty() ) {
1314 parser.process( tmpl,
this );
1316 parser.process(
this );
1326 msg->
link(
this, KMMsgStatusForwarded);
1330 static const struct {
1331 const char * dontAskAgainID;
1334 } mdnMessageBoxes[] = {
1335 {
"mdnNormalAsk",
true,
1336 I18N_NOOP(
"This message contains a request to return a notification "
1337 "about your reception of the message.\n"
1338 "You can either ignore the request or let KMail send a "
1339 "\"denied\" or normal response.") },
1340 {
"mdnUnknownOption",
false,
1341 I18N_NOOP(
"This message contains a request to send a notification "
1342 "about your reception of the message.\n"
1343 "It contains a processing instruction that is marked as "
1344 "\"required\", but which is unknown to KMail.\n"
1345 "You can either ignore the request or let KMail send a "
1346 "\"failed\" response.") },
1347 {
"mdnMultipleAddressesInReceiptTo",
true,
1348 I18N_NOOP(
"This message contains a request to send a notification "
1349 "about your reception of the message,\n"
1350 "but it is requested to send the notification to more "
1351 "than one address.\n"
1352 "You can either ignore the request or let KMail send a "
1353 "\"denied\" or normal response.") },
1354 {
"mdnReturnPathEmpty",
true,
1355 I18N_NOOP(
"This message contains a request to send a notification "
1356 "about your reception of the message,\n"
1357 "but there is no return-path set.\n"
1358 "You can either ignore the request or let KMail send a "
1359 "\"denied\" or normal response.") },
1360 {
"mdnReturnPathNotInReceiptTo",
true,
1361 I18N_NOOP(
"This message contains a request to send a notification "
1362 "about your reception of the message,\n"
1363 "but the return-path address differs from the address "
1364 "the notification was requested to be sent to.\n"
1365 "You can either ignore the request or let KMail send a "
1366 "\"denied\" or normal response.") },
1369 static const int numMdnMessageBoxes
1370 =
sizeof mdnMessageBoxes /
sizeof *mdnMessageBoxes;
1373 static int requestAdviceOnMDN(
const char * what ) {
1374 for (
int i = 0 ; i < numMdnMessageBoxes ; ++i ) {
1375 if ( !qstrcmp( what, mdnMessageBoxes[i].dontAskAgainID ) ) {
1376 if ( mdnMessageBoxes[i].canDeny ) {
1378 int answer = TQMessageBox::information( 0,
1379 i18n(
"Message Disposition Notification Request"),
1380 i18n( mdnMessageBoxes[i].text ),
1381 i18n(
"&Ignore"), i18n(
"Send \"&denied\""), i18n(
"&Send") );
1382 return answer ? answer + 1 : 0 ;
1385 int answer = TQMessageBox::information( 0,
1386 i18n(
"Message Disposition Notification Request"),
1387 i18n( mdnMessageBoxes[i].text ),
1388 i18n(
"&Ignore"), i18n(
"&Send") );
1389 return answer ? answer + 2 : 0 ;
1393 kdWarning(5006) <<
"didn't find data for message box \""
1394 << what <<
"\"" << endl;
1399 MDN::DispositionType d,
1401 TQValueList<MDN::DispositionModifier> m )
1410 if ( mdnSentState() != KMMsgMDNStateUnknown &&
1411 mdnSentState() != KMMsgMDNNone )
1414 char st[2]; st[0] = (char)mdnSentState(); st[1] = 0;
1415 kdDebug(5006) <<
"mdnSentState() == '" << st <<
"'" << endl;
1420 DwMime::kSubtypeDispositionNotification ) ) {
1421 setMDNSentState( KMMsgMDNIgnore );
1426 TQString receiptTo =
headerField(
"Disposition-Notification-To");
1427 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1428 receiptTo.remove(
'\n' );
1431 MDN::SendingMode s = MDN::SentAutomatically;
1433 TDEConfigGroup mdnConfig( KMKernel::config(),
"MDN" );
1436 int mode = mdnConfig.readNumEntry(
"default-policy", 0 );
1437 if ( !mode || mode < 0 || mode > 3 ) {
1439 setMDNSentState( KMMsgMDNIgnore );
1449 TQString notificationOptions =
headerField(
"Disposition-Notification-Options");
1450 if ( notificationOptions.contains(
"required",
false ) ) {
1454 if ( !allowGUI )
return 0;
1455 mode = requestAdviceOnMDN(
"mdnUnknownOption" );
1456 s = MDN::SentManually;
1458 special = i18n(
"Header \"Disposition-Notification-Options\" contained "
1459 "required, but unknown parameter");
1467 kdDebug(5006) <<
"KPIM::splitEmailAddrList(receiptTo): "
1468 << KPIM::splitEmailAddrList(receiptTo).join(
"\n") << endl;
1469 if ( KPIM::splitEmailAddrList(receiptTo).count() > 1 ) {
1470 if ( !allowGUI )
return 0;
1471 mode = requestAdviceOnMDN(
"mdnMultipleAddressesInReceiptTo" );
1472 s = MDN::SentManually;
1480 AddrSpecList returnPathList = extractAddrSpecs(
"Return-Path");
1481 TQString returnPath = returnPathList.isEmpty() ? TQString()
1482 : returnPathList.front().localPart +
'@' + returnPathList.front().domain ;
1483 kdDebug(5006) <<
"clean return path: " << returnPath << endl;
1484 if ( returnPath.isEmpty() || !receiptTo.contains( returnPath,
false ) ) {
1485 if ( !allowGUI )
return 0;
1486 mode = requestAdviceOnMDN( returnPath.isEmpty() ?
1487 "mdnReturnPathEmpty" :
1488 "mdnReturnPathNotInReceiptTo" );
1489 s = MDN::SentManually;
1492 if ( a != KMime::MDN::AutomaticAction ) {
1495 if ( !allowGUI )
return 0;
1496 mode = requestAdviceOnMDN(
"mdnNormalAsk" );
1497 s = MDN::SentManually;
1502 setMDNSentState( KMMsgMDNIgnore );
1506 kdFatal(5006) <<
"KMMessage::createMDN(): The \"ask\" mode should "
1507 <<
"never appear here!" << endl;
1520 TQString finalRecipient = kmkernel->identityManager()
1521 ->identityForUoidOrDefault(
identityUoid() ).fullEmailAddr();
1532 DwHeaders & header = receipt->mMsg->Headers();
1533 header.MimeVersion().FromString(
"1.0");
1535 contentType.SetType( DwMime::kTypeMultipart );
1536 contentType.SetSubtype( DwMime::kSubtypeReport );
1537 contentType.CreateBoundary(0);
1538 receipt->mNeedsAssembly =
true;
1544 KMMessagePart firstMsgPart;
1545 firstMsgPart.setTypeStr(
"text" );
1546 firstMsgPart.setSubtypeStr(
"plain" );
1547 firstMsgPart.setBodyFromUnicode( description );
1551 KMMessagePart secondMsgPart;
1552 secondMsgPart.setType( DwMime::kTypeMessage );
1553 secondMsgPart.setSubtype( DwMime::kSubtypeDispositionNotification );
1556 secondMsgPart.setBodyEncoded( MDN::dispositionNotificationBodyContent(
1560 d, a, s, m, special ) );
1564 int num = mdnConfig.readNumEntry(
"quote-message", 0 );
1565 if ( num < 0 || num > 2 ) num = 0;
1566 MDN::ReturnContent returnContent =
static_cast<MDN::ReturnContent
>( num );
1568 KMMessagePart thirdMsgPart;
1569 switch ( returnContent ) {
1571 thirdMsgPart.setTypeStr(
"message" );
1572 thirdMsgPart.setSubtypeStr(
"rfc822" );
1576 case MDN::HeadersOnly:
1577 thirdMsgPart.setTypeStr(
"text" );
1578 thirdMsgPart.setSubtypeStr(
"rfc822-headers" );
1587 receipt->setTo( receiptTo );
1588 receipt->setSubject(
"Message Disposition Notification" );
1589 receipt->setReplyToId(
msgId() );
1594 kdDebug(5006) <<
"final message:\n" + receipt->
asString() << endl;
1599 KMMsgMDNSentState state = KMMsgMDNStateUnknown;
1601 case MDN::Displayed: state = KMMsgMDNDisplayed;
break;
1602 case MDN::Deleted: state = KMMsgMDNDeleted;
break;
1603 case MDN::Dispatched: state = KMMsgMDNDispatched;
break;
1604 case MDN::Processed: state = KMMsgMDNProcessed;
break;
1605 case MDN::Denied: state = KMMsgMDNDenied;
break;
1606 case MDN::Failed: state = KMMsgMDNFailed;
break;
1608 setMDNSentState( state );
1614 TQString result = s;
1615 TQRegExp rx(
"\\$\\{([a-z0-9-]+)\\}",
false );
1616 Q_ASSERT( rx.isValid() );
1618 TQRegExp rxDate(
"\\$\\{date\\}" );
1619 Q_ASSERT( rxDate.isValid() );
1621 TQString sDate = KMime::DateFormatter::formatDate(
1622 KMime::DateFormatter::Localized, date() );
1625 if( ( idx = rxDate.search( result, idx ) ) != -1 ) {
1626 result.replace( idx, rxDate.matchedLength(), sDate );
1630 while ( ( idx = rx.search( result, idx ) ) != -1 ) {
1631 TQString replacement =
headerField( TQString(rx.cap(1)).latin1() );
1632 result.replace( idx, rx.matchedLength(), replacement );
1633 idx += replacement.length();
1640 TQString str, receiptTo;
1643 receiptTo =
headerField(
"Disposition-Notification-To");
1644 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1645 receiptTo.remove(
'\n' );
1649 receipt->setTo(receiptTo);
1650 receipt->setSubject(i18n(
"Receipt: ") +
subject());
1652 str =
"Your message was successfully delivered.";
1653 str +=
"\n\n---------- Message header follows ----------\n";
1655 str +=
"--------------------------------------------\n";
1658 receipt->
setBody(str.latin1());
1667 const KPIM::Identity & ident =
1668 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1670 if(ident.fullEmailAddr().isEmpty())
1673 setFrom(ident.fullEmailAddr());
1675 if(ident.replyToAddr().isEmpty())
1678 setReplyTo(ident.replyToAddr());
1680 if(ident.bcc().isEmpty())
1683 setBcc(ident.bcc());
1685 if (ident.organization().isEmpty())
1690 if (ident.isDefault())
1693 setHeaderField(
"X-KMail-Identity", TQString::number( ident.uoid() ));
1695 if ( ident.transport().isEmpty() )
1700 if ( ident.fcc().isEmpty() )
1701 setFcc( TQString() );
1703 setFcc( ident.fcc() );
1705 if ( ident.drafts().isEmpty() )
1706 setDrafts( TQString() );
1708 setDrafts( ident.drafts() );
1710 if ( ident.templates().isEmpty() )
1711 setTemplates( TQString() );
1713 setTemplates( ident.templates() );
1731 TQString idString =
headerField(
"X-KMail-Identity").stripWhiteSpace();
1733 int id = idString.toUInt( &ok );
1735 if ( !ok ||
id == 0 )
1736 id = kmkernel->identityManager()->identityForAddress(
to() +
", " +
cc() ).uoid();
1737 if (
id == 0 && parent() )
1738 id = parent()->identity();
1751 if (!msg->
headerField(
"X-KMail-Transport").isEmpty())
1759 DwHeaders& header = mMsg->Headers();
1760 DwField* field = header.FirstField();
1763 if (mNeedsAssembly) mMsg->Assemble();
1764 mNeedsAssembly =
false;
1768 nextField = field->Next();
1769 if (field->FieldBody()->AsString().empty())
1771 header.RemoveField(field);
1772 mNeedsAssembly =
true;
1782 DwHeaders& header = mMsg->Headers();
1783 header.MimeVersion().FromString(
"1.0");
1789 contentType.SetType( DwMime::kTypeMultipart);
1790 contentType.SetSubtype(DwMime::kSubtypeMixed );
1793 contentType.CreateBoundary(0);
1795 mNeedsAssembly =
true;
1802 TDEConfigGroup general( KMKernel::config(),
"General" );
1803 DwHeaders& header = mMsg->Headers();
1806 if (!header.HasDate())
return "";
1807 unixTime = header.Date().AsUnixTime();
1811 return KMime::DateFormatter::formatDate(
1812 static_cast<KMime::DateFormatter::FormatType>(general.readNumEntry(
"dateFormat", KMime::DateFormatter::Fancy )),
1813 unixTime, general.readEntry(
"customDateFormat" ));
1820 DwHeaders& header = mMsg->Headers();
1823 if (!header.HasDate())
return "";
1824 unixTime = header.Date().AsUnixTime();
1826 TQCString result = ctime(&unixTime);
1827 int len = result.length();
1828 if (result[len-1]==
'\n')
1829 result.truncate(len-1);
1836 TQString KMMessage::dateIsoStr()
const
1838 DwHeaders& header = mMsg->Headers();
1841 if (!header.HasDate())
return "";
1842 unixTime = header.Date().AsUnixTime();
1845 strftime(cstr, 63,
"%Y-%m-%d %H:%M:%S", localtime(&unixTime));
1846 return TQString(cstr);
1851 time_t KMMessage::date()
const
1853 time_t res = ( time_t )-1;
1854 DwHeaders& header = mMsg->Headers();
1855 if (header.HasDate())
1856 res = header.Date().AsUnixTime();
1864 struct timeval tval;
1865 gettimeofday(&tval, 0);
1866 setDate((time_t)tval.tv_sec);
1871 void KMMessage::setDate(time_t aDate)
1874 mMsg->Headers().Date().FromCalendarTime(aDate);
1875 mMsg->Headers().Date().Assemble();
1876 mNeedsAssembly =
true;
1882 void KMMessage::setDate(
const TQCString& aStr)
1884 DwHeaders& header = mMsg->Headers();
1886 header.Date().FromString(aStr);
1887 header.Date().Parse();
1888 mNeedsAssembly =
true;
1891 if (header.HasDate())
1892 mDate = header.Date().AsUnixTime();
1902 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1905 return KPIM::normalizeAddressesAndDecodeIDNs( headers.join(
", " ) );
1910 void KMMessage::setTo(
const TQString& aStr)
1916 TQString KMMessage::toStrip()
const
1924 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Reply-To") );
1929 void KMMessage::setReplyTo(
const TQString& aStr)
1936 void KMMessage::setReplyTo(
KMMessage* aMsg)
1949 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1952 return KPIM::normalizeAddressesAndDecodeIDNs( headers.join(
", " ) );
1957 void KMMessage::setCc(
const TQString& aStr)
1964 TQString KMMessage::ccStrip()
const
1973 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Bcc") );
1978 void KMMessage::setBcc(
const TQString& aStr)
1991 void KMMessage::setFcc(
const TQString &aStr )
1997 void KMMessage::setDrafts(
const TQString &aStr )
2003 void KMMessage::setTemplates(
const TQString &aStr )
2012 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(mParent->whoField().utf8()) );
2020 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"From") );
2025 void KMMessage::setFrom(
const TQString& bStr)
2027 TQString aStr = bStr;
2036 TQString KMMessage::fromStrip()
const
2043 AddrSpecList asl = extractAddrSpecs(
"Sender" );
2045 asl = extractAddrSpecs(
"From" );
2048 return asl.front().asString();
2059 void KMMessage::setSubject(
const TQString& aStr)
2074 void KMMessage::setXMark(
const TQString& aStr)
2084 int leftAngle, rightAngle;
2089 rightAngle = replyTo.find(
'>' );
2090 if (rightAngle != -1)
2091 replyTo.truncate( rightAngle + 1 );
2093 leftAngle = replyTo.findRev(
'<' );
2094 if (leftAngle != -1)
2095 replyTo = replyTo.mid( leftAngle );
2101 if (!replyTo.isEmpty() && (replyTo[0] ==
'<') &&
2102 ( -1 == replyTo.find(
'"' ) ) )
2106 leftAngle = references.findRev(
'<' );
2107 if (leftAngle != -1)
2108 references = references.mid( leftAngle );
2109 rightAngle = references.find(
'>' );
2110 if (rightAngle != -1)
2111 references.truncate( rightAngle + 1 );
2114 if (!references.isEmpty() && references[0] ==
'<')
2123 TQString KMMessage::replyToIdMD5()
const {
2130 int leftAngle, rightAngle;
2134 leftAngle = references.findRev(
'<' );
2135 leftAngle = references.findRev(
'<', leftAngle - 1 );
2136 if( leftAngle != -1 )
2137 references = references.mid( leftAngle );
2138 rightAngle = references.findRev(
'>' );
2139 if( rightAngle != -1 )
2140 references.truncate( rightAngle + 1 );
2142 if( !references.isEmpty() && references[0] ==
'<' )
2154 const int rightAngle = result.find(
'>' );
2155 if( rightAngle != -1 )
2156 result.truncate( rightAngle + 1 );
2158 return base64EncodedMD5( result );
2163 return base64EncodedMD5( stripOffPrefixes(
subject() ),
true );
2168 return base64EncodedMD5(
subject(),
true );
2177 void KMMessage::setReplyToId(
const TQString& aStr)
2190 const int rightAngle = msgId.find(
'>' );
2191 if (rightAngle != -1)
2192 msgId.truncate( rightAngle + 1 );
2194 const int leftAngle = msgId.findRev(
'<' );
2195 if (leftAngle != -1)
2196 msgId = msgId.mid( leftAngle );
2202 TQString KMMessage::msgIdMD5()
const {
2203 return base64EncodedMD5(
msgId() );
2208 void KMMessage::setMsgId(
const TQString& aStr)
2221 void KMMessage::setMsgSizeServer(
size_t size)
2234 void KMMessage::setUID(ulong uid)
2244 const char * scursor = str.begin();
2246 return AddressList();
2247 const char *
const send = str.begin() + str.length();
2248 if ( !parseAddressList( scursor, send, result ) )
2249 kdDebug(5006) <<
"Error in address splitting: parseAddressList returned false!"
2258 AddrSpecList KMMessage::extractAddrSpecs(
const TQCString & header )
const {
2260 AddrSpecList result;
2261 for ( AddressList::const_iterator ait = al.begin() ; ait != al.end() ; ++ait )
2262 for ( MailboxList::const_iterator mit = (*ait).mailboxList.begin() ; mit != (*ait).mailboxList.end() ; ++mit )
2263 result.push_back( (*mit).addrSpec );
2268 if ( name.isEmpty() )
return TQCString();
2270 DwHeaders & header = mMsg->Headers();
2271 DwField * field = header.FindField( name );
2273 if ( !field )
return TQCString();
2275 return header.FieldBody( name.data() ).AsString().c_str();
2280 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2281 return TQValueList<TQCString>();
2283 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2285 for ( uint i = 0; i < v.size(); ++i ) {
2286 headerFields.append( v[i]->AsString().c_str() );
2294 if ( aName.isEmpty() )
2297 if ( !mMsg->Headers().FindField( aName ) )
2300 return decodeRFC2047String( mMsg->Headers().FieldBody( aName.data() ).AsString().c_str(),
2307 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2308 return TQStringList();
2310 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2312 for ( uint i = 0; i < v.size(); ++i ) {
2313 headerFields.append( decodeRFC2047String( v[i]->AsString().c_str(),
charset() ) );
2322 DwHeaders & header = mMsg->Headers();
2323 DwField * field = header.FindField(aName);
2326 header.RemoveField(field);
2327 mNeedsAssembly =
true;
2333 DwHeaders & header = mMsg->Headers();
2334 while ( DwField * field = header.FindField(aName) ) {
2335 header.RemoveField(field);
2336 mNeedsAssembly =
true;
2343 HeaderFieldType type,
bool prepend )
2346 if ( type != Unstructured )
2347 kdDebug(5006) <<
"KMMessage::setHeaderField( \"" << aName <<
"\", \""
2348 << bValue <<
"\", " << type <<
" )" << endl;
2350 if (aName.isEmpty())
return;
2352 DwHeaders& header = mMsg->Headers();
2357 if (!bValue.isEmpty())
2359 TQString value = bValue;
2360 if ( type == Address )
2361 value = KPIM::normalizeAddressesAndEncodeIDNs( value );
2363 if ( type != Unstructured )
2364 kdDebug(5006) <<
"value: \"" << value <<
"\"" << endl;
2366 TQCString encoding = autoDetectCharset(
charset(), sPrefCharsets, value );
2367 if (encoding.isEmpty())
2369 aValue = encodeRFC2047String( value, encoding );
2371 if ( type != Unstructured )
2372 kdDebug(5006) <<
"aValue: \"" << aValue <<
"\"" << endl;
2376 if (str[str.length()-1] !=
':') str +=
": ";
2378 if ( !aValue.isEmpty() )
2379 str += aValue.data();
2380 if (str[str.length()-1] !=
'\n') str +=
'\n';
2382 field =
new DwField(str, mMsg);
2386 header.AddFieldAt( 1, field );
2388 header.AddOrReplaceField( field );
2389 mNeedsAssembly =
true;
2396 DwHeaders& header = mMsg->Headers();
2397 if (header.HasContentType())
return header.ContentType().TypeStr().c_str();
2403 int KMMessage::type()
const
2405 DwHeaders& header = mMsg->Headers();
2406 if (header.HasContentType())
return header.ContentType().Type();
2407 else return DwMime::kTypeNull;
2412 void KMMessage::setTypeStr(
const TQCString& aStr)
2416 mNeedsAssembly =
true;
2421 void KMMessage::setType(
int aType)
2425 mNeedsAssembly =
true;
2433 DwHeaders& header = mMsg->Headers();
2434 if (header.HasContentType())
return header.ContentType().SubtypeStr().c_str();
2440 int KMMessage::subtype()
const
2442 DwHeaders& header = mMsg->Headers();
2443 if (header.HasContentType())
return header.ContentType().Subtype();
2444 else return DwMime::kSubtypeNull;
2449 void KMMessage::setSubtypeStr(
const TQCString& aStr)
2453 mNeedsAssembly =
true;
2458 void KMMessage::setSubtype(
int aSubtype)
2462 mNeedsAssembly =
true;
2468 const TQCString& attr,
2469 const TQCString& val )
2472 DwParameter *param = mType.FirstParameter();
2474 if (!kasciistricmp(param->Attribute().c_str(), attr))
2477 param = param->Next();
2480 param =
new DwParameter;
2481 param->SetAttribute(DwString( attr ));
2482 mType.AddParameter( param );
2485 mType.SetModified();
2486 param->SetValue(DwString( val ));
2494 if (mNeedsAssembly) mMsg->Assemble();
2495 mNeedsAssembly =
false;
2497 mNeedsAssembly =
true;
2504 DwHeaders& header = mMsg->Headers();
2505 if (header.HasContentTransferEncoding())
2506 return header.ContentTransferEncoding().AsString().c_str();
2512 int KMMessage::contentTransferEncoding( DwEntity *entity )
const
2517 DwHeaders& header = entity->Headers();
2518 if ( header.HasContentTransferEncoding() )
2519 return header.ContentTransferEncoding().AsEnum();
2520 else return DwMime::kCteNull;
2525 void KMMessage::setContentTransferEncodingStr(
const TQCString& cteString,
2531 entity->Headers().ContentTransferEncoding().FromString( cteString );
2532 entity->Headers().ContentTransferEncoding().Parse();
2533 mNeedsAssembly =
true;
2538 void KMMessage::setContentTransferEncoding(
int cte, DwEntity *entity )
2543 entity->Headers().ContentTransferEncoding().FromEnum( cte );
2544 mNeedsAssembly =
true;
2551 return mMsg->Headers();
2558 mNeedsAssembly =
true;
2566 if ( mNeedsAssembly ) {
2568 mNeedsAssembly =
false;
2575 const DwString&
body = mMsg->Body().AsString();
2585 TQByteArray KMMessage::bodyDecodedBinary()
const
2588 const DwString& dwsrc = mMsg->Body().AsString();
2592 case DwMime::kCteBase64:
2593 DwDecodeBase64(dwsrc, dwstr);
2595 case DwMime::kCteQuotedPrintable:
2596 DwDecodeQuotedPrintable(dwsrc, dwstr);
2603 int len = dwstr.size();
2604 TQByteArray ba(len);
2605 memcpy(ba.data(),dwstr.data(),len);
2614 DwString dwsrc = mMsg->Body().AsString();
2618 case DwMime::kCteBase64:
2619 DwDecodeBase64(dwsrc, dwstr);
2621 case DwMime::kCteQuotedPrintable:
2622 DwDecodeQuotedPrintable(dwsrc, dwstr);
2644 TQValueList<int> allowedCtes;
2646 switch ( cf.type() ) {
2647 case CharFreq::SevenBitText:
2648 allowedCtes << DwMime::kCte7bit;
2649 case CharFreq::EightBitText:
2651 allowedCtes << DwMime::kCte8bit;
2652 case CharFreq::SevenBitData:
2653 if ( cf.printableRatio() > 5.0/6.0 ) {
2657 allowedCtes << DwMime::kCteQp;
2658 allowedCtes << DwMime::kCteBase64;
2660 allowedCtes << DwMime::kCteBase64;
2661 allowedCtes << DwMime::kCteQp;
2664 case CharFreq::EightBitData:
2665 allowedCtes << DwMime::kCteBase64;
2667 case CharFreq::None:
2677 if ( ( willBeSigned && cf.hasTrailingWhitespace() ) ||
2678 cf.hasLeadingFrom() ) {
2679 allowedCtes.remove( DwMime::kCte8bit );
2680 allowedCtes.remove( DwMime::kCte7bit );
2689 TQValueList<int> & allowedCte,
2697 CharFreq cf( aBuf );
2699 setCte( allowedCte[0], entity );
2700 setBodyEncodedBinary( aBuf, entity );
2706 TQValueList<int> & allowedCte,
2714 CharFreq cf( aBuf.data(), aBuf.size()-1 );
2716 setCte( allowedCte[0], entity );
2727 DwString dwSrc(aStr.data(), aStr.size()-1 );
2730 switch (cte( entity ))
2732 case DwMime::kCteBase64:
2733 DwEncodeBase64(dwSrc, dwResult);
2735 case DwMime::kCteQuotedPrintable:
2736 DwEncodeQuotedPrintable(dwSrc, dwResult);
2743 entity->Body().FromString(dwResult);
2744 mNeedsAssembly =
true;
2748 void KMMessage::setBodyEncodedBinary(
const TQByteArray& aStr, DwEntity *entity )
2753 DwString dwSrc(aStr.data(), aStr.size());
2756 switch ( cte( entity ) )
2758 case DwMime::kCteBase64:
2759 DwEncodeBase64( dwSrc, dwResult );
2761 case DwMime::kCteQuotedPrintable:
2762 DwEncodeQuotedPrintable( dwSrc, dwResult );
2769 entity->Body().FromString( dwResult );
2770 entity->Body().Parse();
2772 mNeedsAssembly =
true;
2780 mNeedsAssembly =
true;
2784 mMsg->Body().FromString(aStr);
2785 mNeedsAssembly =
true;
2789 mMsg->Body().FromString(aStr);
2790 mNeedsAssembly =
true;
2796 mMsg->Body().Parse();
2797 mNeedsAssembly =
true;
2813 TQPtrList< DwBodyPart > parts;
2819 && part->hasHeaders()
2820 && part->Headers().HasContentType()
2821 && part->Body().FirstBodyPart()
2822 && (DwMime::kTypeMultipart == part->Headers().ContentType().Type()) )
2824 parts.append( part );
2825 part = part->Body().FirstBodyPart();
2831 while (part && !(part->Next()) && !(parts.isEmpty()))
2833 part = parts.getLast();
2837 if (part && part->Body().Message() &&
2838 part->Body().Message()->Body().FirstBodyPart())
2840 part = part->Body().Message()->Body().FirstBodyPart();
2842 part = part->Next();
2853 return mMsg->Body().FirstBodyPart();
2860 DwBodyPart *curpart;
2861 TQPtrList< DwBodyPart > parts;
2868 while (curpart && !idx) {
2871 && curpart->hasHeaders()
2872 && curpart->Headers().HasContentType()
2873 && curpart->Body().FirstBodyPart()
2874 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2876 parts.append( curpart );
2877 curpart = curpart->Body().FirstBodyPart();
2880 if (curpart == aDwBodyPart)
2885 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2887 curpart = parts.getLast();
2891 curpart = curpart->Next();
2900 DwBodyPart *part, *curpart;
2901 TQPtrList< DwBodyPart > parts;
2908 while (curpart && !part) {
2911 && curpart->hasHeaders()
2912 && curpart->Headers().HasContentType()
2913 && curpart->Body().FirstBodyPart()
2914 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2916 parts.append( curpart );
2917 curpart = curpart->Body().FirstBodyPart();
2925 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2927 curpart = parts.getLast();
2931 curpart = curpart->Next();
2940 DwBodyPart *part, *curpart;
2941 TQPtrList< DwBodyPart > parts;
2947 while (curpart && !part) {
2950 && curpart->hasHeaders()
2951 && curpart->Headers().HasContentType()
2952 && curpart->Body().FirstBodyPart()
2953 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
2954 parts.append( curpart );
2955 curpart = curpart->Body().FirstBodyPart();
2961 if ( curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
2962 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
2963 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
2967 curpart->hasHeaders() &&
2968 curpart->Headers().HasContentType() &&
2969 curpart->Headers().ContentType().Type() == type &&
2970 curpart->Headers().ContentType().Subtype() == subtype) {
2975 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
2976 curpart = parts.getLast();
2980 curpart = curpart->Next();
2989 DwBodyPart *part, *curpart;
2990 TQPtrList< DwBodyPart > parts;
2996 while (curpart && !part) {
2999 && curpart->hasHeaders()
3000 && curpart->Headers().HasContentType()
3001 && curpart->Body().FirstBodyPart()
3002 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
3003 parts.append( curpart );
3004 curpart = curpart->Body().FirstBodyPart();
3010 if (curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
3011 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
3012 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
3016 curpart->hasHeaders() &&
3017 curpart->Headers().HasContentType() &&
3018 curpart->Headers().ContentType().TypeStr().c_str() == type &&
3019 curpart->Headers().ContentType().SubtypeStr().c_str() == subtype) {
3024 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
3025 curpart = parts.getLast();
3029 curpart = curpart->Next();
3036 void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart )
3048 TQCString additionalCTypeParams;
3049 if (headers.HasContentType())
3051 DwMediaType& ct = headers.ContentType();
3052 aPart->setOriginalContentTypeStr( ct.AsString().c_str() );
3053 aPart->setTypeStr(ct.TypeStr().c_str());
3054 aPart->setSubtypeStr(ct.SubtypeStr().c_str());
3055 DwParameter *param = ct.FirstParameter();
3058 if (!tqstricmp(param->Attribute().c_str(),
"charset")) {
3059 if (aPart->type() == DwMime::kTypeText) {
3060 aPart->setCharset(TQCString(param->Value().c_str()).lower());
3063 else if (!tqstrnicmp(param->Attribute().c_str(),
"name*", 5))
3064 aPart->setName(KMMsgBase::decodeRFC2231String(KMMsgBase::extractRFC2231HeaderField( param->Value().c_str(),
"name" )));
3066 additionalCTypeParams +=
';';
3067 additionalCTypeParams += param->AsString().c_str();
3069 param=param->Next();
3074 aPart->setTypeStr(
"text");
3075 aPart->setSubtypeStr(
"plain");
3077 aPart->setAdditionalCTypeParamStr( additionalCTypeParams );
3079 if (aPart->name().isEmpty())
3081 if (headers.HasContentType() && !headers.ContentType().Name().empty()) {
3082 aPart->setName(KMMsgBase::decodeRFC2047String(headers.
3083 ContentType().Name().c_str()) );
3084 }
else if (headers.HasSubject() && !headers.Subject().AsString().empty()) {
3085 aPart->setName( KMMsgBase::decodeRFC2047String(headers.
3086 Subject().AsString().c_str()) );
3091 if (headers.HasContentTransferEncoding())
3092 aPart->setCteStr(headers.ContentTransferEncoding().AsString().c_str());
3094 aPart->setCteStr(
"7bit");
3097 if (headers.HasContentDescription())
3098 aPart->setContentDescription( KMMsgBase::decodeRFC2047String(
3099 headers.ContentDescription().AsString().c_str() ) );
3101 aPart->setContentDescription(
"");
3104 if (headers.HasContentDisposition())
3105 aPart->setContentDisposition(headers.ContentDisposition().AsString().c_str());
3107 aPart->setContentDisposition(
"");
3119 if( aDwBodyPart && aDwBodyPart->hasHeaders() ) {
3124 TQString partId( aDwBodyPart->partId() );
3125 aPart->setPartSpecifier( partId );
3127 DwHeaders& headers = aDwBodyPart->Headers();
3128 applyHeadersToMessagePart( headers, aPart );
3132 aPart->setBody( aDwBodyPart->Body().AsString() );
3134 aPart->setBody( TQCString(
"") );
3137 if ( headers.HasContentId() ) {
3138 const TQCString contentId = headers.ContentId().AsString().c_str();
3140 aPart->setContentId( contentId.mid( 1, contentId.length() - 2 ) );
3147 aPart->setTypeStr(
"");
3148 aPart->setSubtypeStr(
"");
3149 aPart->setCteStr(
"");
3153 aPart->setContentDescription(
"");
3154 aPart->setContentDisposition(
"");
3155 aPart->setBody(TQCString(
""));
3156 aPart->setContentId(
"");
3168 if ( DwBodyPart *part =
dwBodyPart( aIdx ) ) {
3170 if( aPart->name().isEmpty() )
3171 aPart->setName( i18n(
"Attachment: %1").arg( aIdx ) );
3179 mMsg->Body().DeleteBodyParts();
3187 DwBodyPart *dwpart = findPart( partIndex );
3191 if ( !part.isComplete() )
3194 DwBody *parentNode =
dynamic_cast<DwBody*
>( dwpart->Parent() );
3197 parentNode->RemoveBodyPart( dwpart );
3200 KMMessagePart dummyPart;
3201 dummyPart.duplicate( part );
3202 TQString comment = i18n(
"This attachment has been deleted.");
3203 if ( !part.fileName().isEmpty() )
3204 comment = i18n(
"The attachment '%1' has been deleted." ).arg( part.fileName() );
3205 dummyPart.setContentDescription( comment );
3206 dummyPart.setBodyEncodedBinary( TQByteArray() );
3207 TQCString cd = dummyPart.contentDisposition();
3208 if ( cd.find(
"inline", 0,
false ) == 0 ) {
3209 cd.replace( 0, 10,
"attachment" );
3210 dummyPart.setContentDisposition( cd );
3211 }
else if ( cd.isEmpty() ) {
3212 dummyPart.setContentDisposition(
"attachment" );
3215 parentNode->AddBodyPart( newDwPart );
3216 getTopLevelPart()->Assemble();
3223 DwBodyPart* part = DwBodyPart::NewBodyPart(emptyString, 0);
3228 TQCString
charset = aPart->charset();
3229 TQCString type = aPart->typeStr();
3230 TQCString subtype = aPart->subtypeStr();
3231 TQCString cte = aPart->cteStr();
3232 TQCString contDesc = aPart->contentDescriptionEncoded();
3233 TQCString contDisp = aPart->contentDisposition();
3234 TQCString name = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->name(),
charset );
3235 bool RFC2231encoded = aPart->name() != TQString(name);
3236 TQCString paramAttr = aPart->parameterAttribute();
3238 DwHeaders& headers = part->Headers();
3240 DwMediaType& ct = headers.ContentType();
3241 if (!type.isEmpty() && !subtype.isEmpty())
3243 ct.SetTypeStr(type.data());
3244 ct.SetSubtypeStr(subtype.data());
3245 if (!charset.isEmpty()){
3247 param=
new DwParameter;
3248 param->SetAttribute(
"charset");
3249 param->SetValue(charset.data());
3250 ct.AddParameter(param);
3254 TQCString additionalParam = aPart->additionalCTypeParamStr();
3255 if( !additionalParam.isEmpty() )
3258 DwString parA, parV;
3260 iL = additionalParam.length();
3262 i2 = additionalParam.find(
';', i1,
false);
3268 parAV = additionalParam.mid( i1, (i2-i1) );
3269 iM = parAV.find(
'=');
3272 parA = parAV.left( iM ).data();
3273 parV = parAV.right( parAV.length() - iM - 1 ).data();
3274 if( (
'"' == parV.at(0)) && (
'"' == parV.at(parV.length()-1)) )
3277 parV.erase( parV.length()-1 );
3282 parA = parAV.data();
3286 param =
new DwParameter;
3287 param->SetAttribute( parA );
3288 param->SetValue( parV );
3289 ct.AddParameter( param );
3292 i2 = additionalParam.find(
';', i1,
false);
3296 if ( !name.isEmpty() ) {
3299 DwParameter *nameParam;
3300 nameParam =
new DwParameter;
3301 nameParam->SetAttribute(
"name*");
3302 nameParam->SetValue(name.data(),
true);
3303 ct.AddParameter(nameParam);
3305 ct.SetName(name.data());
3309 if (!paramAttr.isEmpty())
3311 TQCString paramValue;
3312 paramValue = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->parameterValue(),
charset );
3313 DwParameter *param =
new DwParameter;
3314 if (aPart->parameterValue() != TQString(paramValue))
3316 param->SetAttribute((paramAttr +
'*').data());
3317 param->SetValue(paramValue.data(),
true);
3319 param->SetAttribute(paramAttr.data());
3320 param->SetValue(paramValue.data());
3322 ct.AddParameter(param);
3326 headers.Cte().FromString(cte);
3328 if (!contDesc.isEmpty())
3329 headers.ContentDescription().FromString(contDesc);
3331 if (!contDisp.isEmpty())
3332 headers.ContentDisposition().FromString(contDisp);
3334 const DwString bodyStr = aPart->dwBody();
3335 if (!bodyStr.empty())
3336 part->Body().FromString(bodyStr);
3338 part->Body().FromString(
"");
3340 if (!aPart->partSpecifier().isNull())
3341 part->SetPartId( aPart->partSpecifier().latin1() );
3343 if (aPart->decodedSize() > 0)
3344 part->SetBodySize( aPart->decodedSize() );
3353 mMsg->Body().AddBodyPart( aDwPart );
3354 mNeedsAssembly =
true;
3369 TQDateTime datetime = TQDateTime::currentDateTime();
3372 msgIdStr =
'<' + datetime.toString(
"yyyyMMddhhmm.sszzz" );
3374 TQString msgIdSuffix;
3375 TDEConfigGroup general( KMKernel::config(),
"General" );
3377 if( general.readBoolEntry(
"useCustomMessageIdSuffix",
false ) )
3378 msgIdSuffix = general.readEntry(
"myMessageIdSuffix" );
3380 if( !msgIdSuffix.isEmpty() )
3381 msgIdStr +=
'@' + msgIdSuffix;
3383 msgIdStr +=
'.' + KPIM::encodeIDN( addr );
3394 TQCString result( 1 + 6*(src.size()-1) );
3396 TQCString::ConstIterator s = src.begin();
3397 TQCString::Iterator d = result.begin();
3460 result.truncate( d - result.begin() );
3468 result = TQString::fromLatin1( KMMsgBase::encodeRFC2047String( str,
3470 result = KURL::encode_string( result );
3479 result = KURL::decode_string( url );
3480 result = KMMsgBase::decodeRFC2047String( result.latin1() );
3490 if ( aStr.isEmpty() )
3501 TQCString angleAddress;
3502 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3503 bool inQuotedString =
false;
3504 int commentLevel = 0;
3506 for (
const char* p = aStr.data(); *p; ++p ) {
3507 switch ( context ) {
3510 case '"' : inQuotedString = !inQuotedString;
3512 case '(' :
if ( !inQuotedString ) {
3513 context = InComment;
3519 case '<' :
if ( !inQuotedString ) {
3520 context = InAngleAddress;
3530 case ',' :
if ( !inQuotedString ) {
3532 if ( !result.isEmpty() )
3534 name = name.stripWhiteSpace();
3535 comment = comment.stripWhiteSpace();
3536 angleAddress = angleAddress.stripWhiteSpace();
3545 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3550 else if ( !name.isEmpty() ) {
3553 else if ( !comment.isEmpty() ) {
3556 else if ( !angleAddress.isEmpty() ) {
3557 result += angleAddress;
3560 comment = TQCString();
3561 angleAddress = TQCString();
3566 default : name += *p;
3572 case '(' : ++commentLevel;
3575 case ')' : --commentLevel;
3576 if ( commentLevel == 0 ) {
3588 default : comment += *p;
3592 case InAngleAddress : {
3594 case '"' : inQuotedString = !inQuotedString;
3597 case '>' :
if ( !inQuotedString ) {
3608 default : angleAddress += *p;
3614 if ( !result.isEmpty() )
3616 name = name.stripWhiteSpace();
3617 comment = comment.stripWhiteSpace();
3618 angleAddress = angleAddress.stripWhiteSpace();
3624 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3629 else if ( !name.isEmpty() ) {
3632 else if ( !comment.isEmpty() ) {
3635 else if ( !angleAddress.isEmpty() ) {
3636 result += angleAddress;
3649 if ( aStr.isEmpty() )
3660 TQString angleAddress;
3661 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3662 bool inQuotedString =
false;
3663 int commentLevel = 0;
3666 unsigned int strLength(aStr.length());
3667 for ( uint index = 0; index < strLength; ++index ) {
3669 switch ( context ) {
3671 switch ( ch.latin1() ) {
3672 case '"' : inQuotedString = !inQuotedString;
3674 case '(' :
if ( !inQuotedString ) {
3675 context = InComment;
3681 case '<' :
if ( !inQuotedString ) {
3682 context = InAngleAddress;
3689 if ( index < aStr.length() )
3690 name += aStr[index];
3692 case ',' :
if ( !inQuotedString ) {
3694 if ( !result.isEmpty() )
3696 name = name.stripWhiteSpace();
3697 comment = comment.stripWhiteSpace();
3698 angleAddress = angleAddress.stripWhiteSpace();
3707 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3712 else if ( !name.isEmpty() ) {
3715 else if ( !comment.isEmpty() ) {
3718 else if ( !angleAddress.isEmpty() ) {
3719 result += angleAddress;
3722 comment = TQString();
3723 angleAddress = TQString();
3728 default : name += ch;
3733 switch ( ch.latin1() ) {
3734 case '(' : ++commentLevel;
3737 case ')' : --commentLevel;
3738 if ( commentLevel == 0 ) {
3747 if ( index < aStr.length() )
3748 comment += aStr[index];
3750 default : comment += ch;
3754 case InAngleAddress : {
3755 switch ( ch.latin1() ) {
3756 case '"' : inQuotedString = !inQuotedString;
3759 case '>' :
if ( !inQuotedString ) {
3767 if ( index < aStr.length() )
3768 angleAddress += aStr[index];
3770 default : angleAddress += ch;
3776 if ( !result.isEmpty() )
3778 name = name.stripWhiteSpace();
3779 comment = comment.stripWhiteSpace();
3780 angleAddress = angleAddress.stripWhiteSpace();
3786 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3791 else if ( !name.isEmpty() ) {
3794 else if ( !comment.isEmpty() ) {
3797 else if ( !angleAddress.isEmpty() ) {
3798 result += angleAddress;
3811 unsigned int strLength(str.length());
3812 result.reserve( 6*strLength );
3813 for(
unsigned int i = 0; i < strLength; ++i )
3814 switch ( str[i].latin1() ) {
3828 if ( !removeLineBreaks )
3845 if( aEmail.isEmpty() )
3848 TQStringList addressList = KPIM::splitEmailAddrList( aEmail );
3851 for( TQStringList::ConstIterator it = addressList.begin();
3852 ( it != addressList.end() );
3854 if( !(*it).isEmpty() ) {
3857 TQString name, mail;
3858 KPIM::getNameAndMail( *it, name, mail );
3860 TQString prettyStripped;
3861 if ( name.stripWhiteSpace().isEmpty() ) {
3863 prettyStripped = mail;
3865 pretty = KPIM::quoteNameIfNecessary( name ) +
" <" + mail +
">";
3866 prettyStripped = name;
3870 result +=
"<a href=\"mailto:"
3872 +
"\" "+cssStyle+
">";
3888 result.truncate( result.length() - 2 );
3898 const TQStringList& list )
3900 TQStringList addresses( list );
3901 TQString addrSpec( KPIM::getEmailAddress( address ) );
3902 for ( TQStringList::Iterator it = addresses.begin();
3903 it != addresses.end(); ) {
3904 if ( kasciistricmp( addrSpec.utf8().data(),
3905 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 ) {
3906 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3908 it = addresses.remove( it );
3921 TQStringList addresses = list;
3922 for( TQStringList::Iterator it = addresses.begin();
3923 it != addresses.end(); ) {
3924 kdDebug(5006) <<
"Check whether " << *it <<
" is one of my addresses"
3926 if( kmkernel->identityManager()->thatIsMe( KPIM::getEmailAddress( *it ) ) ) {
3927 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3929 it = addresses.remove( it );
3941 const TQStringList& addresses )
3943 TQString addrSpec = KPIM::getEmailAddress( address );
3944 for( TQStringList::ConstIterator it = addresses.begin();
3945 it != addresses.end(); ++it ) {
3946 if ( kasciistricmp( addrSpec.utf8().data(),
3947 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 )
3958 if ( recipients.isEmpty() )
3961 TQStringList recipientList = KPIM::splitEmailAddrList( recipients );
3963 TQString expandedRecipients;
3964 for ( TQStringList::Iterator it = recipientList.begin();
3965 it != recipientList.end(); ++it ) {
3966 if ( !expandedRecipients.isEmpty() )
3967 expandedRecipients +=
", ";
3968 TQString receiver = (*it).stripWhiteSpace();
3971 TQString expandedList = KAddrBookExternal::expandDistributionList( receiver );
3972 if ( !expandedList.isEmpty() ) {
3973 expandedRecipients += expandedList;
3978 TQString expandedNickName = KabcBridge::expandNickName( receiver );
3979 if ( !expandedNickName.isEmpty() ) {
3980 expandedRecipients += expandedNickName;
3986 if ( receiver.find(
'@') == -1 ) {
3987 TDEConfigGroup general( KMKernel::config(),
"General" );
3988 TQString defaultdomain = general.readEntry(
"Default domain" );
3989 if( !defaultdomain.isEmpty() ) {
3990 expandedRecipients += receiver +
"@" + defaultdomain;
3997 expandedRecipients += receiver;
4000 return expandedRecipients;
4008 if ( loginName.isEmpty() )
4011 char hostnameC[256];
4013 hostnameC[255] =
'\0';
4015 if ( gethostname( hostnameC, 255 ) )
4016 hostnameC[0] =
'\0';
4017 TQString address = loginName;
4019 address += TQString::fromLocal8Bit( hostnameC );
4022 const KUser user( loginName );
4023 if ( user.isValid() ) {
4024 TQString fullName = user.fullName();
4025 if ( fullName.find( TQRegExp(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) ) != -1 )
4026 address =
'"' + fullName.replace(
'\\',
"\\" ).replace(
'"',
"\\" )
4027 +
"\" <" + address +
'>';
4029 address = fullName +
" <" + address +
'>';
4040 TDEConfig *config=KMKernel::config();
4041 TDEConfigGroupSaver saver(config,
"General");
4043 config->setGroup(
"General");
4045 int languageNr = config->readNumEntry(
"reply-current-language",0);
4048 TDEConfigGroupSaver saver(config, TQString(
"KMMessage #%1").arg(languageNr));
4049 sReplyLanguage = config->readEntry(
"language",TDEGlobal::locale()->language());
4050 sReplyStr = config->readEntry(
"phrase-reply",
4051 i18n(
"On %D, you wrote:"));
4052 sReplyAllStr = config->readEntry(
"phrase-reply-all",
4053 i18n(
"On %D, %F wrote:"));
4054 sForwardStr = config->readEntry(
"phrase-forward",
4055 i18n(
"Forwarded Message"));
4056 sIndentPrefixStr = config->readEntry(
"indent-prefix",
">%_");
4060 TDEConfigGroupSaver saver(config,
"Composer");
4061 sSmartQuote = GlobalSettings::self()->smartQuote();
4062 sWordWrap = GlobalSettings::self()->wordWrap();
4063 sWrapCol = GlobalSettings::self()->lineWrapWidth();
4064 if ((sWrapCol == 0) || (sWrapCol > 78))
4069 sPrefCharsets = config->readListEntry(
"pref-charsets");
4073 TDEConfigGroupSaver saver(config,
"Reader");
4074 sHeaderStrategy = HeaderStrategy::create( config->readEntry(
"header-set-displayed",
"rich" ) );
4082 if (!sPrefCharsets.isEmpty())
4083 retval = sPrefCharsets[0].latin1();
4085 if (retval.isEmpty() || (retval ==
"locale")) {
4086 retval = TQCString(kmkernel->networkCodec()->mimeName());
4087 KPIM::kAsciiToLower( retval.data() );
4090 if (retval ==
"jisx0208.1983-0") retval =
"iso-2022-jp";
4091 else if (retval ==
"ksc5601.1987-0") retval =
"euc-kr";
4097 return sPrefCharsets;
4103 if ( mMsg->Headers().HasContentType() ) {
4104 DwMediaType &mType=mMsg->Headers().ContentType();
4106 DwParameter *param=mType.FirstParameter();
4108 if (!kasciistricmp(param->Attribute().c_str(),
"charset"))
4109 return param->Value().c_str();
4110 else param=param->Next();
4119 kdWarning( type() != DwMime::kTypeText )
4120 <<
"KMMessage::setCharset(): trying to set a charset for a non-textual mimetype." << endl
4121 <<
"Fix this caller:" << endl
4122 <<
"====================================================================" << endl
4123 << kdBacktrace( 5 ) << endl
4124 <<
"====================================================================" << endl;
4129 DwMediaType &mType = entity->Headers().ContentType();
4131 DwParameter *param = mType.FirstParameter();
4135 if ( !kasciistricmp( param->Attribute().c_str(),
"charset" ) )
4138 param = param->Next();
4141 param =
new DwParameter;
4142 param->SetAttribute(
"charset" );
4143 mType.AddParameter( param );
4146 mType.SetModified();
4148 TQCString lowerCharset =
charset;
4149 KPIM::kAsciiToLower( lowerCharset.data() );
4150 param->SetValue( DwString( lowerCharset ) );
4158 if (mStatus == aStatus)
4165 if( mEncryptionState == s )
4167 mEncryptionState = s;
4174 if( mSignatureState == s )
4176 mSignatureState = s;
4181 void KMMessage::setMDNSentState( KMMsgMDNSentState status,
int idx )
4183 if ( mMDNSentState == status )
4186 status = KMMsgMDNStateUnknown;
4189 KMMsgBase::setMDNSentState( status, idx );
4195 Q_ASSERT( aStatus == KMMsgStatusReplied
4196 || aStatus == KMMsgStatusForwarded
4197 || aStatus == KMMsgStatusDeleted );
4199 TQString message =
headerField(
"X-KMail-Link-Message" );
4200 if ( !message.isEmpty() )
4202 TQString type =
headerField(
"X-KMail-Link-Type" );
4203 if ( !type.isEmpty() )
4206 message += TQString::number( aMsg->getMsgSerNum() );
4207 if ( aStatus == KMMsgStatusReplied )
4209 else if ( aStatus == KMMsgStatusForwarded )
4211 else if ( aStatus == KMMsgStatusDeleted )
4222 *reStatus = KMMsgStatusUnknown;
4224 TQString message =
headerField(
"X-KMail-Link-Message");
4226 message = message.section(
',', n, n);
4227 type = type.section(
',', n, n);
4229 if ( !message.isEmpty() && !type.isEmpty() ) {
4230 *retMsgSerNum = message.toULong();
4231 if ( type ==
"reply" )
4232 *reStatus = KMMsgStatusReplied;
4233 else if ( type ==
"forward" )
4234 *reStatus = KMMsgStatusForwarded;
4235 else if ( type ==
"deleted" )
4236 *reStatus = KMMsgStatusDeleted;
4243 if ( !part )
return 0;
4244 DwBodyPart* current;
4246 if ( part->partId() == partSpecifier )
4250 if ( part->hasHeaders() &&
4251 part->Headers().HasContentType() &&
4252 part->Body().FirstBodyPart() &&
4253 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) &&
4254 (current =
findDwBodyPart( part->Body().FirstBodyPart(), partSpecifier )) )
4260 if ( part->Body().Message() &&
4261 part->Body().Message()->Body().FirstBodyPart() &&
4262 (current =
findDwBodyPart( part->Body().Message()->Body().FirstBodyPart(),
4275 if ( !data.data() || !data.size() )
4278 DwString content( data.data(), data.size() );
4280 partSpecifier !=
"0" &&
4281 partSpecifier !=
"TEXT" )
4283 TQString specifier = partSpecifier;
4284 if ( partSpecifier.endsWith(
".HEADER") ||
4285 partSpecifier.endsWith(
".MIME") ) {
4287 specifier = partSpecifier.section(
'.', 0, -2 );
4292 kdDebug(5006) <<
"KMMessage::updateBodyPart " << specifier << endl;
4295 kdWarning(5006) <<
"KMMessage::updateBodyPart - can not find part "
4296 << specifier << endl;
4299 if ( partSpecifier.endsWith(
".MIME") )
4303 content.resize( TQMAX( content.length(), 2 ) - 2 );
4306 mLastUpdated->Headers().DeleteAllFields();
4307 mLastUpdated->Headers().FromString( content );
4308 mLastUpdated->Headers().Parse();
4309 }
else if ( partSpecifier.endsWith(
".HEADER") )
4312 mLastUpdated->Body().Message()->Headers().FromString( content );
4313 mLastUpdated->Body().Message()->Headers().Parse();
4316 mLastUpdated->Body().FromString( content );
4317 TQString parentSpec = partSpecifier.section(
'.', 0, -2 );
4318 if ( !parentSpec.isEmpty() )
4321 if ( parent && parent->hasHeaders() && parent->Headers().HasContentType() )
4323 const DwMediaType& contentType = parent->Headers().ContentType();
4324 if ( contentType.Type() == DwMime::kTypeMessage &&
4325 contentType.Subtype() == DwMime::kSubtypeRfc822 )
4329 parent->Body().Message()->Body().FromString( content );
4338 if ( partSpecifier ==
"TEXT" )
4340 mMsg->Body().FromString( content );
4341 mMsg->Body().Parse();
4343 mNeedsAssembly =
true;
4344 if (! partSpecifier.endsWith(
".HEADER") )
4351 void KMMessage::updateInvitationState()
4353 if ( mMsg && mMsg->hasHeaders() && mMsg->Headers().HasContentType() ) {
4354 TQString cntType = mMsg->Headers().ContentType().TypeStr().c_str();
4356 cntType += mMsg->Headers().ContentType().SubtypeStr().c_str();
4357 if ( cntType.lower() ==
"text/calendar" ) {
4362 setStatus( KMMsgStatusHasNoInvitation );
4367 void KMMessage::updateAttachmentState( DwBodyPart* part )
4379 bool filenameEmpty =
true;
4380 if ( part->hasHeaders() ) {
4381 if ( part->Headers().HasContentDisposition() ) {
4382 DwDispositionType cd = part->Headers().ContentDisposition();
4383 filenameEmpty = cd.Filename().empty();
4384 if ( filenameEmpty ) {
4386 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField( cd.AsString().c_str(),
"filename" ) ).isEmpty();
4392 if ( filenameEmpty && part->Headers().HasContentType() ) {
4393 DwMediaType contentType = part->Headers().ContentType();
4394 filenameEmpty = contentType.Name().empty();
4395 if ( filenameEmpty ) {
4397 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField(
4398 contentType.AsString().c_str(),
"name" ) ).isEmpty();
4403 if ( part->hasHeaders() &&
4404 ( ( part->Headers().HasContentDisposition() &&
4405 !part->Headers().ContentDisposition().Filename().empty() ) ||
4406 ( part->Headers().HasContentType() &&
4407 !filenameEmpty ) ) )
4410 if ( !part->Headers().HasContentType() ||
4411 ( part->Headers().HasContentType() &&
4412 part->Headers().ContentType().Subtype() != DwMime::kSubtypePgpSignature &&
4413 part->Headers().ContentType().Subtype() != DwMime::kSubtypePkcs7Signature ) )
4421 if ( part->hasHeaders() &&
4422 part->Headers().HasContentType() &&
4423 part->Body().FirstBodyPart() &&
4424 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) )
4426 updateAttachmentState( part->Body().FirstBodyPart() );
4430 if ( part->Body().Message() &&
4431 part->Body().Message()->Body().FirstBodyPart() )
4433 updateAttachmentState( part->Body().Message()->Body().FirstBodyPart() );
4438 updateAttachmentState( part->Next() );
4439 else if ( attachmentState() == KMMsgAttachmentUnknown )
4446 if ( encoding.isEmpty() )
4448 const TQTextCodec *
codec = KMMsgBase::codecForName( encoding );
4450 TQValueList<int> dummy;
4457 const TQTextCodec * c = mOverrideCodec;
4460 c = KMMsgBase::codecForName(
charset() );
4464 c = KMMsgBase::codecForName( GlobalSettings::self()->fallbackCharacterEncoding().latin1() );
4469 c = kmkernel->networkCodec();
4477 codec = this->
codec();
4486 TQCString str( KPIM::getFirstEmailAddress(
rawHeaderField(
"From") ) );
4487 if ( str.isEmpty() )
4488 str =
"unknown@unknown.invalid";
4490 if ( dateStr.isEmpty() ) {
4491 time_t t = ::time( 0 );
4492 dateStr = ctime( &t );
4493 const int len = dateStr.length();
4494 if ( dateStr[len-1] ==
'\n' )
4495 dateStr.truncate( len - 1 );
4497 return "From " + str +
" " + dateStr +
"\n";
4502 sPendingDeletes <<
this;
4505 DwBodyPart* KMMessage::findPart(
int index )
4508 return findPartInternal( getTopLevelPart(), index, accu );
4511 DwBodyPart* KMMessage::findPartInternal(DwEntity * root,
int index,
int & accu)
4516 DwBodyPart *current =
dynamic_cast<DwBodyPart*
>( root );
4517 if ( index == accu )
4520 if ( root->Body().FirstBodyPart() )
4521 rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
4522 if ( !rv && current && current->Next() )
4523 rv = findPartInternal( current->Next(), index, accu );
4524 if ( !rv && root->Body().Message() )
4525 rv = findPartInternal( root->Body().Message(), index, accu );