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;
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 );
241 return MessageProperty::transferInProgress( getMsgSerNum() );
248 MessageProperty::setTransferInProgress( getMsgSerNum(), value, force );
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;
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 +
'>';
4038 KMMsgBase::readConfig();
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)
4160 KMMsgBase::setStatus(aStatus, idx);
4165 if( mEncryptionState == s )
4167 mEncryptionState = s;
4169 KMMsgBase::setEncryptionState(s, idx);
4174 if( mSignatureState == s )
4176 mSignatureState = s;
4178 KMMsgBase::setSignatureState(s, idx);
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 );
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 TQCString defaultCharset()
Get the default message charset.
static TQStringList stripMyAddressesFromAddressList(const TQStringList &list)
Strips all the user's addresses from an address list.
void addDwBodyPart(DwBodyPart *aDwPart)
Append a DwBodyPart to the message.
void setSignatureState(const KMMsgSignatureState, int idx=-1)
Set signature status of the message.
TQString replaceHeadersInString(const TQString &s) const
Replaces every occurrence of "${foo}" in s with headerField("foo")
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...
TQString headerAsString() const
Return header as string.
DwString dwString(const TQCString &str)
Construct a DwString from a TQCString.
DwBodyPart * dwBodyPart(int aIdx) const
Get the DwBodyPart at position in aIdx.
uint identityUoid() const
static TQString smartQuote(const TQString &msg, int maxLineLength)
Given argument msg add quoting characters and relayout for max width maxLength.
int partNumber(DwBodyPart *aDwBodyPart) const
Get the number of the given DwBodyPart.
void setSelection(const TQString &selection)
Sets the selection.
bool hasUnencryptedMsg() const
Returns TRUE if the message contains an unencrypted copy of itself.
virtual ~KMMessage()
Destructor.
TQString bcc() const
Get or set the 'Bcc' header field.
DwMediaType & dwContentType()
Return reference to Content-Type header for direct manipulation.
TQCString typeStr() const
Get or set the 'Content-Type' header field The member functions that involve enumerated types (ints) ...
void cleanupHeader()
Removes empty fields from the header, e.g.
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
TQCString rawHeaderField(const TQCString &name) const
Returns the raw 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 initFromMessage(const KMMessage *msg, bool idHeaders=true)
Initialize headers fields according to the identity and the transport header of the given original me...
void initHeader(uint identity=0)
Initialize header fields.
static KMime::Types::AddressList splitAddrField(const TQCString &str)
Splits the given address list into separate addresses.
const DwString & asDwString() const
Return the entire message contents in the DwString.
void setBodyFromUnicode(const TQString &str, DwEntity *entity=0)
Sets this body's content to str.
KMime::Types::AddressList headerAddrField(const TQCString &name) const
Returns header address list as string list.
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...
void setBody(const TQCString &aStr)
Set the message body.
static void setDwMediaTypeParam(DwMediaType &mType, const TQCString &attr, const TQCString &val)
add or change a parameter of a DwMediaType field
TQCString subtypeStr() const
Subtype.
static TQString quoteHtmlChars(const TQString &str, bool removeLineBreaks=false)
Quotes the following characters which have a special meaning in HTML: '<' '>' '&' '"'...
void setNeedsAssembly()
tell the message that internal data were changed (must be called after directly modifying message str...
void setBodyEncoded(const TQCString &aStr, DwEntity *entity=0)
Set the message body, encoding it according to the current content transfer encoding.
TQString from() const
Get or set the 'From' header field.
TQCString contentTransferEncodingStr() const
Get or set the 'Content-Transfer-Encoding' header field The member functions that involve enumerated ...
void setCharset(const TQCString &charset, DwEntity *entity=0)
Sets the charset of the message or a subpart of the message.
static void bodyPart(DwBodyPart *aDwBodyPart, KMMessagePart *aPart, bool withBody=true)
Fill the KMMessagePart structure for a given DwBodyPart.
void setStatusFields()
Set "Status" and "X-Status" fields of the message from the internal message status.
static TQStringList stripAddressFromAddressList(const TQString &address, const TQStringList &addresses)
Strips an address from an address list.
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 removeHeaderFields(const TQCString &name)
Remove all header fields with given name.
static TQString generateMessageId(const TQString &addr)
Generates the Message-Id.
DwBodyPart * createDWBodyPart(const KMMessagePart *aPart)
Compose a DwBodyPart (needed for adding a part to the message).
static TQCString html2source(const TQCString &src)
Convert '<' into "<" resp.
TQString msgId() const
Get or set the 'Message-Id' header field.
TQString replyTo() const
Get or set the 'ReplyTo' header field.
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...
KMMsgInfo * msgInfo()
Get the KMMsgInfo object that was set with setMsgInfo().
void removePrivateHeaderFields()
Remove all private header fields: *Status: and X-KMail-*.
bool deleteBodyPart(int partIndex)
Delete a body part with the specified part index.
void setMsgSerNum(unsigned long newMsgSerNum=0)
Sets the message serial number.
The TemplateParser transforms a message with a given template.
TQString xmark() const
Get or set the 'X-Mark' header field.
size_t msgSizeServer() const
Get/set size on server.
void setAllowDecryption(const bool allowDecryption)
Sets whether the template parser is allowed to decrypt the original message when needing its message ...
ulong UID() const
Get/set UID.
TQValueList< TQCString > rawHeaderFields(const TQCString &field) const
Returns a list of the raw values of all header fields with the given name.
DwBodyPart * getFirstDwBodyPart() const
Get the 1st DwBodyPart.
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...
KMMessage * createDeliveryReceipt() const
Create a new message that is a delivery receipt of this message, filling required header fileds with ...
static TQString expandAliases(const TQString &recipients)
Expands aliases (distribution lists and nick names) and appends a domain part to all email addresses ...
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 ...
TQString replyToAuxIdMD5() const
Get the second to last id from the References header field.
TQString dateStr() const
Get or set the 'Date' header field.
TQString templates() const
Get or set the 'Templates' folder.
static bool addressIsInAddressList(const TQString &address, const TQStringList &addresses)
Returns true if the given address is contained in the given address list.
void setMultiPartBody(const TQCString &aStr)
Hack to enable structured body parts to be set as flat text...
TQString subjectMD5() const
Get a hash of the subject.
void updateBodyPart(const TQString partSpecifier, const TQByteArray &data)
Sets the body of the specified part.
void setDateToday()
Set the 'Date' header field to the current date.
KMMessage * createRedirect(const TQString &toStr)
Create a new message that is a redirect to this message, filling all required header fields with the ...
TQString replyToId() const
Get or set the 'In-Reply-To' header field.
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...
TQCString bodyDecoded() const
Returns a decoded version of the body from the current content transfer encoding. ...
void setContentTypeParam(const TQCString &attr, const TQCString &val)
add or change a parameter of the Content-Type field
static TQString encodeMailtoUrl(const TQString &str)
Encodes an email address as mailto URL.
TQCString asString() const
Return the entire message contents as a string.
TQCString dateShortStr() const
Returns the message date in asctime format or an empty string if the message lacks a Date header...
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
TQCString headerAsSendableString() const
Return the message header with the headers that should not be sent stripped off.
void getLink(int n, ulong *retMsgSerNum, KMMsgStatus *reStatus) const
Returns the information for the Nth link into retMsg and reStatus.
void deleteBodyParts()
Delete all body parts.
TQString subject() const
Get or set the 'Subject' header field.
bool subjectIsPrefixed() const
Is the subject prefixed by Re: or similar?
void setUnencryptedMsg(KMMessage *unencrypted)
Specifies an unencrypted copy of this message to be stored in a separate member variable to allow sav...
bool isMessage() const
Returns TRUE if object is a real message (not KMMsgInfo or KMMsgBase)
bool transferInProgress() const
Return, if the message should not be deleted.
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...
KMMessage * unencryptedMsg() const
Returns an unencrypted copy of this message or 0 if none exists.
void assembleIfNeeded()
Assemble the internal message.
TQCString charset() const
Get the message charset.
TQString formatString(const TQString &) const
Convert wildcards into normal string.
TQString drafts() const
Get or set the 'Drafts' folder.
TQCString body() const
Get the message body.
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().
KMMessage(KMFolder *parent=0)
Straight forward initialization.
TQCString getRefStr() const
Creates reference string for reply to messages.
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.
static TQString decodeMailtoUrl(const TQString &url)
Decodes a mailto URL.
const TQTextCodec * codec() const
Get a TQTextCodec suitable for this message part.
void addBodyPart(const KMMessagePart *aPart)
Append a body part to the message.
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
void sanitizeHeaders(const TQStringList &whiteList=TQStringList())
Remove all headers but the content description ones, and those in the white list. ...
TQStringList headerFields(const TQCString &name) const
Returns a list of the values of all header fields with the given name.
TQByteArray ByteArray(const DwString &str)
Construct a TQByteArray from a DwString.
static TQCString stripEmailAddr(const TQCString &emailAddr)
This function generates a displayable string from a list of email addresses.
KMMsgStatus status() const
Status of the message.
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).
static const TQStringList & preferredCharsets()
Get a list of preferred message charsets.
TQString fcc() const
Get or set the 'Fcc' header field.
TQString bodyToUnicode(const TQTextCodec *codec=0) const
Returns the body part decoded to unicode.
TQCString CString(const DwString &str)
Construct a TQCString from a DwString.
TQString cc() const
Get or set the 'Cc' header field.
TQString who() const
Get or set the 'Who' header field.
TQCString id() const
Returns the message ID, useful for followups.
TQString references() const
Get or set the references for this message.
static void readConfig()
Reads config settings from group "KMMessage" and sets all internal variables (e.g.
TQCString mboxMessageSeparator()
Returns an mbox message separator line for this message, i.e.
TQByteArray asSendableString() const
Return the message contents with the headers that should not be sent stripped off.
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
KMMsgSignatureState signatureState() const
Signature status of the message.
TQString strippedSubjectMD5() const
Get a hash of the subject with all prefixes such as Re: removed.
void removeHeaderField(const TQCString &name)
Remove header field with given name.
TQString asPlainText(bool stripSignature, bool allowDecryption) const
Return the textual content of the message as plain text, converting HTML to plain text if necessary...
TQString to() const
Get or set the 'To' header field.
DwHeaders & headers() const
get the DwHeaders (make sure to call setNeedsAssembly() function after directly modyfying internal da...
int numBodyParts() const
Number of body parts the message has.
KMMsgEncryptionState encryptionState() const
Encryption status of the message.
bool readyToShow() const
Return if the message is ready to be shown.
void link(const KMMessage *aMsg, KMMsgStatus aStatus)
Links this message to aMsg, setting link type to aStatus.
void setEncryptionState(const KMMsgEncryptionState, int idx=-1)
Set encryption status of the message.
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
void setAutomaticFields(bool isMultipart=false)
Set fields that are either automatically set (Message-id) or that do not change from one message to a...
DwBodyPart * findDwBodyPart(int type, int subtype) const
Return the first DwBodyPart matching a given Content-Type or zero, if no found.
void deleteWhenUnused()
Delete this message as soon as it no longer in use.
TQCString createForwardBody()
Create the forwarded body for the message.