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 aPart->setCharset(TQCString(param->Value().c_str()).lower());
3060 else if (!tqstrnicmp(param->Attribute().c_str(),
"name*", 5))
3061 aPart->setName(KMMsgBase::decodeRFC2231String(KMMsgBase::extractRFC2231HeaderField( param->Value().c_str(),
"name" )));
3063 additionalCTypeParams +=
';';
3064 additionalCTypeParams += param->AsString().c_str();
3066 param=param->Next();
3071 aPart->setTypeStr(
"text");
3072 aPart->setSubtypeStr(
"plain");
3074 aPart->setAdditionalCTypeParamStr( additionalCTypeParams );
3076 if (aPart->name().isEmpty())
3078 if (
headers.HasContentType() && !
headers.ContentType().Name().empty()) {
3079 aPart->setName(KMMsgBase::decodeRFC2047String(
headers.
3080 ContentType().Name().c_str()) );
3081 }
else if (
headers.HasSubject() && !
headers.Subject().AsString().empty()) {
3082 aPart->setName( KMMsgBase::decodeRFC2047String(
headers.
3083 Subject().AsString().c_str()) );
3088 if (
headers.HasContentTransferEncoding())
3089 aPart->setCteStr(
headers.ContentTransferEncoding().AsString().c_str());
3091 aPart->setCteStr(
"7bit");
3094 if (
headers.HasContentDescription())
3095 aPart->setContentDescription( KMMsgBase::decodeRFC2047String(
3096 headers.ContentDescription().AsString().c_str() ) );
3098 aPart->setContentDescription(
"");
3101 if (
headers.HasContentDisposition())
3102 aPart->setContentDisposition(
headers.ContentDisposition().AsString().c_str());
3104 aPart->setContentDisposition(
"");
3116 if( aDwBodyPart && aDwBodyPart->hasHeaders() ) {
3121 TQString partId( aDwBodyPart->partId() );
3122 aPart->setPartSpecifier( partId );
3124 DwHeaders&
headers = aDwBodyPart->Headers();
3125 applyHeadersToMessagePart( headers, aPart );
3129 aPart->setBody( aDwBodyPart->Body().AsString() );
3131 aPart->setBody( TQCString(
"") );
3134 if ( headers.HasContentId() ) {
3135 const TQCString contentId = headers.ContentId().AsString().c_str();
3137 aPart->setContentId( contentId.mid( 1, contentId.length() - 2 ) );
3144 aPart->setTypeStr(
"");
3145 aPart->setSubtypeStr(
"");
3146 aPart->setCteStr(
"");
3150 aPart->setContentDescription(
"");
3151 aPart->setContentDisposition(
"");
3152 aPart->setBody(TQCString(
""));
3153 aPart->setContentId(
"");
3165 if ( DwBodyPart *part =
dwBodyPart( aIdx ) ) {
3167 if( aPart->name().isEmpty() )
3168 aPart->setName( i18n(
"Attachment: %1").arg( aIdx ) );
3176 mMsg->Body().DeleteBodyParts();
3184 DwBodyPart *dwpart = findPart( partIndex );
3188 if ( !part.isComplete() )
3191 DwBody *parentNode =
dynamic_cast<DwBody*
>( dwpart->Parent() );
3194 parentNode->RemoveBodyPart( dwpart );
3197 KMMessagePart dummyPart;
3198 dummyPart.duplicate( part );
3199 TQString comment = i18n(
"This attachment has been deleted.");
3200 if ( !part.fileName().isEmpty() )
3201 comment = i18n(
"The attachment '%1' has been deleted." ).arg( part.fileName() );
3202 dummyPart.setContentDescription( comment );
3203 dummyPart.setBodyEncodedBinary( TQByteArray() );
3204 TQCString cd = dummyPart.contentDisposition();
3205 if ( cd.find(
"inline", 0,
false ) == 0 ) {
3206 cd.replace( 0, 10,
"attachment" );
3207 dummyPart.setContentDisposition( cd );
3208 }
else if ( cd.isEmpty() ) {
3209 dummyPart.setContentDisposition(
"attachment" );
3212 parentNode->AddBodyPart( newDwPart );
3213 getTopLevelPart()->Assemble();
3220 DwBodyPart* part = DwBodyPart::NewBodyPart(emptyString, 0);
3225 TQCString
charset = aPart->charset();
3226 TQCString type = aPart->typeStr();
3227 TQCString subtype = aPart->subtypeStr();
3228 TQCString cte = aPart->cteStr();
3229 TQCString contDesc = aPart->contentDescriptionEncoded();
3230 TQCString contDisp = aPart->contentDisposition();
3231 TQCString name = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->name(),
charset );
3232 bool RFC2231encoded = aPart->name() != TQString(name);
3233 TQCString paramAttr = aPart->parameterAttribute();
3235 DwHeaders&
headers = part->Headers();
3237 DwMediaType& ct = headers.ContentType();
3238 if (!type.isEmpty() && !subtype.isEmpty())
3240 ct.SetTypeStr(type.data());
3241 ct.SetSubtypeStr(subtype.data());
3242 if (!charset.isEmpty()){
3244 param=
new DwParameter;
3245 param->SetAttribute(
"charset");
3246 param->SetValue(charset.data());
3247 ct.AddParameter(param);
3251 TQCString additionalParam = aPart->additionalCTypeParamStr();
3252 if( !additionalParam.isEmpty() )
3255 DwString parA, parV;
3257 iL = additionalParam.length();
3259 i2 = additionalParam.find(
';', i1,
false);
3265 parAV = additionalParam.mid( i1, (i2-i1) );
3266 iM = parAV.find(
'=');
3269 parA = parAV.left( iM ).data();
3270 parV = parAV.right( parAV.length() - iM - 1 ).data();
3271 if( (
'"' == parV.at(0)) && (
'"' == parV.at(parV.length()-1)) )
3274 parV.erase( parV.length()-1 );
3279 parA = parAV.data();
3283 param =
new DwParameter;
3284 param->SetAttribute( parA );
3285 param->SetValue( parV );
3286 ct.AddParameter( param );
3289 i2 = additionalParam.find(
';', i1,
false);
3293 if ( !name.isEmpty() ) {
3296 DwParameter *nameParam;
3297 nameParam =
new DwParameter;
3298 nameParam->SetAttribute(
"name*");
3299 nameParam->SetValue(name.data(),
true);
3300 ct.AddParameter(nameParam);
3302 ct.SetName(name.data());
3306 if (!paramAttr.isEmpty())
3308 TQCString paramValue;
3309 paramValue = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->parameterValue(),
charset );
3310 DwParameter *param =
new DwParameter;
3311 if (aPart->parameterValue() != TQString(paramValue))
3313 param->SetAttribute((paramAttr +
'*').data());
3314 param->SetValue(paramValue.data(),
true);
3316 param->SetAttribute(paramAttr.data());
3317 param->SetValue(paramValue.data());
3319 ct.AddParameter(param);
3323 headers.Cte().FromString(cte);
3325 if (!contDesc.isEmpty())
3326 headers.ContentDescription().FromString(contDesc);
3328 if (!contDisp.isEmpty())
3329 headers.ContentDisposition().FromString(contDisp);
3331 const DwString bodyStr = aPart->dwBody();
3332 if (!bodyStr.empty())
3333 part->Body().FromString(bodyStr);
3335 part->Body().FromString(
"");
3337 if (!aPart->partSpecifier().isNull())
3338 part->SetPartId( aPart->partSpecifier().latin1() );
3340 if (aPart->decodedSize() > 0)
3341 part->SetBodySize( aPart->decodedSize() );
3350 mMsg->Body().AddBodyPart( aDwPart );
3351 mNeedsAssembly =
true;
3366 TQDateTime datetime = TQDateTime::currentDateTime();
3369 msgIdStr =
'<' + datetime.toString(
"yyyyMMddhhmm.sszzz" );
3371 TQString msgIdSuffix;
3372 TDEConfigGroup general( KMKernel::config(),
"General" );
3374 if( general.readBoolEntry(
"useCustomMessageIdSuffix",
false ) )
3375 msgIdSuffix = general.readEntry(
"myMessageIdSuffix" );
3377 if( !msgIdSuffix.isEmpty() )
3378 msgIdStr +=
'@' + msgIdSuffix;
3380 msgIdStr +=
'.' + KPIM::encodeIDN( addr );
3391 TQCString result( 1 + 6*(src.size()-1) );
3393 TQCString::ConstIterator s = src.begin();
3394 TQCString::Iterator d = result.begin();
3457 result.truncate( d - result.begin() );
3465 result = TQString::fromLatin1( KMMsgBase::encodeRFC2047String( str,
3467 result = KURL::encode_string( result );
3476 result = KURL::decode_string( url );
3477 result = KMMsgBase::decodeRFC2047String( result.latin1() );
3487 if ( aStr.isEmpty() )
3498 TQCString angleAddress;
3499 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3500 bool inQuotedString =
false;
3501 int commentLevel = 0;
3503 for (
const char* p = aStr.data(); *p; ++p ) {
3504 switch ( context ) {
3507 case '"' : inQuotedString = !inQuotedString;
3509 case '(' :
if ( !inQuotedString ) {
3510 context = InComment;
3516 case '<' :
if ( !inQuotedString ) {
3517 context = InAngleAddress;
3527 case ',' :
if ( !inQuotedString ) {
3529 if ( !result.isEmpty() )
3531 name = name.stripWhiteSpace();
3532 comment = comment.stripWhiteSpace();
3533 angleAddress = angleAddress.stripWhiteSpace();
3542 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3547 else if ( !name.isEmpty() ) {
3550 else if ( !comment.isEmpty() ) {
3553 else if ( !angleAddress.isEmpty() ) {
3554 result += angleAddress;
3557 comment = TQCString();
3558 angleAddress = TQCString();
3563 default : name += *p;
3569 case '(' : ++commentLevel;
3572 case ')' : --commentLevel;
3573 if ( commentLevel == 0 ) {
3585 default : comment += *p;
3589 case InAngleAddress : {
3591 case '"' : inQuotedString = !inQuotedString;
3594 case '>' :
if ( !inQuotedString ) {
3605 default : angleAddress += *p;
3611 if ( !result.isEmpty() )
3613 name = name.stripWhiteSpace();
3614 comment = comment.stripWhiteSpace();
3615 angleAddress = angleAddress.stripWhiteSpace();
3621 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3626 else if ( !name.isEmpty() ) {
3629 else if ( !comment.isEmpty() ) {
3632 else if ( !angleAddress.isEmpty() ) {
3633 result += angleAddress;
3646 if ( aStr.isEmpty() )
3657 TQString angleAddress;
3658 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3659 bool inQuotedString =
false;
3660 int commentLevel = 0;
3663 unsigned int strLength(aStr.length());
3664 for ( uint index = 0; index < strLength; ++index ) {
3666 switch ( context ) {
3668 switch ( ch.latin1() ) {
3669 case '"' : inQuotedString = !inQuotedString;
3671 case '(' :
if ( !inQuotedString ) {
3672 context = InComment;
3678 case '<' :
if ( !inQuotedString ) {
3679 context = InAngleAddress;
3686 if ( index < aStr.length() )
3687 name += aStr[index];
3689 case ',' :
if ( !inQuotedString ) {
3691 if ( !result.isEmpty() )
3693 name = name.stripWhiteSpace();
3694 comment = comment.stripWhiteSpace();
3695 angleAddress = angleAddress.stripWhiteSpace();
3704 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3709 else if ( !name.isEmpty() ) {
3712 else if ( !comment.isEmpty() ) {
3715 else if ( !angleAddress.isEmpty() ) {
3716 result += angleAddress;
3719 comment = TQString();
3720 angleAddress = TQString();
3725 default : name += ch;
3730 switch ( ch.latin1() ) {
3731 case '(' : ++commentLevel;
3734 case ')' : --commentLevel;
3735 if ( commentLevel == 0 ) {
3744 if ( index < aStr.length() )
3745 comment += aStr[index];
3747 default : comment += ch;
3751 case InAngleAddress : {
3752 switch ( ch.latin1() ) {
3753 case '"' : inQuotedString = !inQuotedString;
3756 case '>' :
if ( !inQuotedString ) {
3764 if ( index < aStr.length() )
3765 angleAddress += aStr[index];
3767 default : angleAddress += ch;
3773 if ( !result.isEmpty() )
3775 name = name.stripWhiteSpace();
3776 comment = comment.stripWhiteSpace();
3777 angleAddress = angleAddress.stripWhiteSpace();
3783 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3788 else if ( !name.isEmpty() ) {
3791 else if ( !comment.isEmpty() ) {
3794 else if ( !angleAddress.isEmpty() ) {
3795 result += angleAddress;
3808 unsigned int strLength(str.length());
3809 result.reserve( 6*strLength );
3810 for(
unsigned int i = 0; i < strLength; ++i )
3811 switch ( str[i].latin1() ) {
3825 if ( !removeLineBreaks )
3842 if( aEmail.isEmpty() )
3845 TQStringList addressList = KPIM::splitEmailAddrList( aEmail );
3848 for( TQStringList::ConstIterator it = addressList.begin();
3849 ( it != addressList.end() );
3851 if( !(*it).isEmpty() ) {
3854 TQString name, mail;
3855 KPIM::getNameAndMail( *it, name, mail );
3857 TQString prettyStripped;
3858 if ( name.stripWhiteSpace().isEmpty() ) {
3860 prettyStripped = mail;
3862 pretty = KPIM::quoteNameIfNecessary( name ) +
" <" + mail +
">";
3863 prettyStripped = name;
3867 result +=
"<a href=\"mailto:" 3869 +
"\" "+cssStyle+
">";
3885 result.truncate( result.length() - 2 );
3895 const TQStringList& list )
3897 TQStringList addresses( list );
3898 TQString addrSpec( KPIM::getEmailAddress( address ) );
3899 for ( TQStringList::Iterator it = addresses.begin();
3900 it != addresses.end(); ) {
3901 if ( kasciistricmp( addrSpec.utf8().data(),
3902 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 ) {
3903 kdDebug(5006) <<
"Removing " << *it <<
" from the address list" 3905 it = addresses.remove( it );
3918 TQStringList addresses = list;
3919 for( TQStringList::Iterator it = addresses.begin();
3920 it != addresses.end(); ) {
3921 kdDebug(5006) <<
"Check whether " << *it <<
" is one of my addresses" 3923 if( kmkernel->identityManager()->thatIsMe( KPIM::getEmailAddress( *it ) ) ) {
3924 kdDebug(5006) <<
"Removing " << *it <<
" from the address list" 3926 it = addresses.remove( it );
3938 const TQStringList& addresses )
3940 TQString addrSpec = KPIM::getEmailAddress( address );
3941 for( TQStringList::ConstIterator it = addresses.begin();
3942 it != addresses.end(); ++it ) {
3943 if ( kasciistricmp( addrSpec.utf8().data(),
3944 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 )
3955 if ( recipients.isEmpty() )
3958 TQStringList recipientList = KPIM::splitEmailAddrList( recipients );
3960 TQString expandedRecipients;
3961 for ( TQStringList::Iterator it = recipientList.begin();
3962 it != recipientList.end(); ++it ) {
3963 if ( !expandedRecipients.isEmpty() )
3964 expandedRecipients +=
", ";
3965 TQString receiver = (*it).stripWhiteSpace();
3968 TQString expandedList = KAddrBookExternal::expandDistributionList( receiver );
3969 if ( !expandedList.isEmpty() ) {
3970 expandedRecipients += expandedList;
3975 TQString expandedNickName = KabcBridge::expandNickName( receiver );
3976 if ( !expandedNickName.isEmpty() ) {
3977 expandedRecipients += expandedNickName;
3983 if ( receiver.find(
'@') == -1 ) {
3984 TDEConfigGroup general( KMKernel::config(),
"General" );
3985 TQString defaultdomain = general.readEntry(
"Default domain" );
3986 if( !defaultdomain.isEmpty() ) {
3987 expandedRecipients += receiver +
"@" + defaultdomain;
3994 expandedRecipients += receiver;
3997 return expandedRecipients;
4005 if ( loginName.isEmpty() )
4008 char hostnameC[256];
4010 hostnameC[255] =
'\0';
4012 if ( gethostname( hostnameC, 255 ) )
4013 hostnameC[0] =
'\0';
4014 TQString address = loginName;
4016 address += TQString::fromLocal8Bit( hostnameC );
4019 const KUser user( loginName );
4020 if ( user.isValid() ) {
4021 TQString fullName = user.fullName();
4022 if ( fullName.find( TQRegExp(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) ) != -1 )
4023 address =
'"' + fullName.replace(
'\\',
"\\" ).replace(
'"',
"\\" )
4024 +
"\" <" + address +
'>';
4026 address = fullName +
" <" + address +
'>';
4035 KMMsgBase::readConfig();
4037 TDEConfig *config=KMKernel::config();
4038 TDEConfigGroupSaver saver(config,
"General");
4040 config->setGroup(
"General");
4042 int languageNr = config->readNumEntry(
"reply-current-language",0);
4045 TDEConfigGroupSaver saver(config, TQString(
"KMMessage #%1").arg(languageNr));
4046 sReplyLanguage = config->readEntry(
"language",TDEGlobal::locale()->language());
4047 sReplyStr = config->readEntry(
"phrase-reply",
4048 i18n(
"On %D, you wrote:"));
4049 sReplyAllStr = config->readEntry(
"phrase-reply-all",
4050 i18n(
"On %D, %F wrote:"));
4051 sForwardStr = config->readEntry(
"phrase-forward",
4052 i18n(
"Forwarded Message"));
4053 sIndentPrefixStr = config->readEntry(
"indent-prefix",
">%_");
4057 TDEConfigGroupSaver saver(config,
"Composer");
4058 sSmartQuote = GlobalSettings::self()->smartQuote();
4059 sWordWrap = GlobalSettings::self()->wordWrap();
4060 sWrapCol = GlobalSettings::self()->lineWrapWidth();
4061 if ((sWrapCol == 0) || (sWrapCol > 78))
4066 sPrefCharsets = config->readListEntry(
"pref-charsets");
4070 TDEConfigGroupSaver saver(config,
"Reader");
4071 sHeaderStrategy = HeaderStrategy::create( config->readEntry(
"header-set-displayed",
"rich" ) );
4079 if (!sPrefCharsets.isEmpty())
4080 retval = sPrefCharsets[0].latin1();
4082 if (retval.isEmpty() || (retval ==
"locale")) {
4083 retval = TQCString(kmkernel->networkCodec()->mimeName());
4084 KPIM::kAsciiToLower( retval.data() );
4087 if (retval ==
"jisx0208.1983-0") retval =
"iso-2022-jp";
4088 else if (retval ==
"ksc5601.1987-0") retval =
"euc-kr";
4094 return sPrefCharsets;
4100 if ( mMsg->Headers().HasContentType() ) {
4101 DwMediaType &mType=mMsg->Headers().ContentType();
4103 DwParameter *param=mType.FirstParameter();
4105 if (!kasciistricmp(param->Attribute().c_str(),
"charset"))
4106 return param->Value().c_str();
4107 else param=param->Next();
4116 kdWarning( type() != DwMime::kTypeText )
4117 <<
"KMMessage::setCharset(): trying to set a charset for a non-textual mimetype." << endl
4118 <<
"Fix this caller:" << endl
4119 <<
"====================================================================" << endl
4120 << kdBacktrace( 5 ) << endl
4121 <<
"====================================================================" << endl;
4126 DwMediaType &mType = entity->Headers().ContentType();
4128 DwParameter *param = mType.FirstParameter();
4132 if ( !kasciistricmp( param->Attribute().c_str(),
"charset" ) )
4135 param = param->Next();
4138 param =
new DwParameter;
4139 param->SetAttribute(
"charset" );
4140 mType.AddParameter( param );
4143 mType.SetModified();
4145 TQCString lowerCharset =
charset;
4146 KPIM::kAsciiToLower( lowerCharset.data() );
4147 param->SetValue( DwString( lowerCharset ) );
4155 if (mStatus == aStatus)
4157 KMMsgBase::setStatus(aStatus, idx);
4162 if( mEncryptionState == s )
4164 mEncryptionState = s;
4166 KMMsgBase::setEncryptionState(s, idx);
4171 if( mSignatureState == s )
4173 mSignatureState = s;
4175 KMMsgBase::setSignatureState(s, idx);
4178 void KMMessage::setMDNSentState( KMMsgMDNSentState
status,
int idx )
4180 if ( mMDNSentState ==
status )
4183 status = KMMsgMDNStateUnknown;
4186 KMMsgBase::setMDNSentState(
status, idx );
4192 Q_ASSERT( aStatus == KMMsgStatusReplied
4193 || aStatus == KMMsgStatusForwarded
4194 || aStatus == KMMsgStatusDeleted );
4196 TQString message =
headerField(
"X-KMail-Link-Message" );
4197 if ( !message.isEmpty() )
4199 TQString type =
headerField(
"X-KMail-Link-Type" );
4200 if ( !type.isEmpty() )
4203 message += TQString::number( aMsg->getMsgSerNum() );
4204 if ( aStatus == KMMsgStatusReplied )
4206 else if ( aStatus == KMMsgStatusForwarded )
4208 else if ( aStatus == KMMsgStatusDeleted )
4219 *reStatus = KMMsgStatusUnknown;
4221 TQString message =
headerField(
"X-KMail-Link-Message");
4223 message = message.section(
',', n, n);
4224 type = type.section(
',', n, n);
4226 if ( !message.isEmpty() && !type.isEmpty() ) {
4227 *retMsgSerNum = message.toULong();
4228 if ( type ==
"reply" )
4229 *reStatus = KMMsgStatusReplied;
4230 else if ( type ==
"forward" )
4231 *reStatus = KMMsgStatusForwarded;
4232 else if ( type ==
"deleted" )
4233 *reStatus = KMMsgStatusDeleted;
4240 if ( !part )
return 0;
4241 DwBodyPart* current;
4243 if ( part->partId() == partSpecifier )
4247 if ( part->hasHeaders() &&
4248 part->Headers().HasContentType() &&
4249 part->Body().FirstBodyPart() &&
4250 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) &&
4251 (current =
findDwBodyPart( part->Body().FirstBodyPart(), partSpecifier )) )
4257 if ( part->Body().Message() &&
4258 part->Body().Message()->Body().FirstBodyPart() &&
4259 (current =
findDwBodyPart( part->Body().Message()->Body().FirstBodyPart(),
4272 if ( !data.data() || !data.size() )
4275 DwString content( data.data(), data.size() );
4277 partSpecifier !=
"0" &&
4278 partSpecifier !=
"TEXT" )
4280 TQString specifier = partSpecifier;
4281 if ( partSpecifier.endsWith(
".HEADER") ||
4282 partSpecifier.endsWith(
".MIME") ) {
4284 specifier = partSpecifier.section(
'.', 0, -2 );
4289 kdDebug(5006) <<
"KMMessage::updateBodyPart " << specifier << endl;
4292 kdWarning(5006) <<
"KMMessage::updateBodyPart - can not find part " 4293 << specifier << endl;
4296 if ( partSpecifier.endsWith(
".MIME") )
4300 content.resize( TQMAX( content.length(), 2 ) - 2 );
4303 mLastUpdated->Headers().DeleteAllFields();
4304 mLastUpdated->Headers().FromString( content );
4305 mLastUpdated->Headers().Parse();
4306 }
else if ( partSpecifier.endsWith(
".HEADER") )
4309 mLastUpdated->Body().Message()->Headers().FromString( content );
4310 mLastUpdated->Body().Message()->Headers().Parse();
4313 mLastUpdated->Body().FromString( content );
4314 TQString parentSpec = partSpecifier.section(
'.', 0, -2 );
4315 if ( !parentSpec.isEmpty() )
4318 if ( parent && parent->hasHeaders() && parent->Headers().HasContentType() )
4320 const DwMediaType& contentType = parent->Headers().ContentType();
4321 if ( contentType.Type() == DwMime::kTypeMessage &&
4322 contentType.Subtype() == DwMime::kSubtypeRfc822 )
4326 parent->Body().Message()->Body().FromString( content );
4335 if ( partSpecifier ==
"TEXT" )
4337 mMsg->Body().FromString( content );
4338 mMsg->Body().Parse();
4340 mNeedsAssembly =
true;
4341 if (! partSpecifier.endsWith(
".HEADER") )
4348 void KMMessage::updateInvitationState()
4350 if ( mMsg && mMsg->hasHeaders() && mMsg->Headers().HasContentType() ) {
4351 TQString cntType = mMsg->Headers().ContentType().TypeStr().c_str();
4353 cntType += mMsg->Headers().ContentType().SubtypeStr().c_str();
4354 if ( cntType.lower() ==
"text/calendar" ) {
4359 setStatus( KMMsgStatusHasNoInvitation );
4364 void KMMessage::updateAttachmentState( DwBodyPart* part )
4376 bool filenameEmpty =
true;
4377 if ( part->hasHeaders() ) {
4378 if ( part->Headers().HasContentDisposition() ) {
4379 DwDispositionType cd = part->Headers().ContentDisposition();
4380 filenameEmpty = cd.Filename().empty();
4381 if ( filenameEmpty ) {
4383 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField( cd.AsString().c_str(),
"filename" ) ).isEmpty();
4389 if ( filenameEmpty && part->Headers().HasContentType() ) {
4390 DwMediaType contentType = part->Headers().ContentType();
4391 filenameEmpty = contentType.Name().empty();
4392 if ( filenameEmpty ) {
4394 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField(
4395 contentType.AsString().c_str(),
"name" ) ).isEmpty();
4400 if ( part->hasHeaders() &&
4401 ( ( part->Headers().HasContentDisposition() &&
4402 !part->Headers().ContentDisposition().Filename().empty() ) ||
4403 ( part->Headers().HasContentType() &&
4404 !filenameEmpty ) ) )
4407 if ( !part->Headers().HasContentType() ||
4408 ( part->Headers().HasContentType() &&
4409 part->Headers().ContentType().Subtype() != DwMime::kSubtypePgpSignature &&
4410 part->Headers().ContentType().Subtype() != DwMime::kSubtypePkcs7Signature ) )
4418 if ( part->hasHeaders() &&
4419 part->Headers().HasContentType() &&
4420 part->Body().FirstBodyPart() &&
4421 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) )
4423 updateAttachmentState( part->Body().FirstBodyPart() );
4427 if ( part->Body().Message() &&
4428 part->Body().Message()->Body().FirstBodyPart() )
4430 updateAttachmentState( part->Body().Message()->Body().FirstBodyPart() );
4435 updateAttachmentState( part->Next() );
4436 else if ( attachmentState() == KMMsgAttachmentUnknown )
4443 if ( encoding.isEmpty() )
4445 const TQTextCodec *
codec = KMMsgBase::codecForName( encoding );
4447 TQValueList<int> dummy;
4454 const TQTextCodec * c = mOverrideCodec;
4457 c = KMMsgBase::codecForName(
charset() );
4461 c = KMMsgBase::codecForName( GlobalSettings::self()->fallbackCharacterEncoding().latin1() );
4466 c = kmkernel->networkCodec();
4474 codec = this->
codec();
4483 TQCString str( KPIM::getFirstEmailAddress(
rawHeaderField(
"From") ) );
4484 if ( str.isEmpty() )
4485 str =
"unknown@unknown.invalid";
4487 if ( dateStr.isEmpty() ) {
4488 time_t t = ::time( 0 );
4489 dateStr = ctime( &t );
4490 const int len = dateStr.length();
4491 if ( dateStr[len-1] ==
'\n' )
4492 dateStr.truncate( len - 1 );
4494 return "From " + str +
" " + dateStr +
"\n";
4499 sPendingDeletes <<
this;
4502 DwBodyPart* KMMessage::findPart(
int index )
4505 return findPartInternal( getTopLevelPart(), index, accu );
4508 DwBodyPart* KMMessage::findPartInternal(DwEntity * root,
int index,
int & accu)
4513 DwBodyPart *current =
dynamic_cast<DwBodyPart*
>( root );
4514 if ( index == accu )
4517 if ( root->Body().FirstBodyPart() )
4518 rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
4519 if ( !rv && current && current->Next() )
4520 rv = findPartInternal( current->Next(), index, accu );
4521 if ( !rv && root->Body().Message() )
4522 rv = findPartInternal( root->Body().Message(), index, accu );
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.
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...
TQCString typeStr() const
Get or set the 'Content-Type' header field The member functions that involve enumerated types (ints) ...
TQValueList< TQCString > rawHeaderFields(const TQCString &field) const
Returns a list of the raw values of all header fields with the given name.
KMMessage * unencryptedMsg() const
Returns an unencrypted copy of this message or 0 if none exists.
TQString replyToAuxIdMD5() const
Get the second to last id from the References header field.
DwString dwString(const TQCString &str)
Construct a DwString from a TQCString.
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 smartQuote(const TQString &msg, int maxLineLength)
Given argument msg add quoting characters and relayout for max width maxLength.
void setSelection(const TQString &selection)
Sets the selection.
TQString subject() const
Get or set the 'Subject' header field.
virtual ~KMMessage()
Destructor.
TQString from() const
Get or set the 'From' header field.
DwMediaType & dwContentType()
Return reference to Content-Type header for direct manipulation.
void cleanupHeader()
Removes empty fields from the header, e.g.
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
TQString replaceHeadersInString(const TQString &s) const
Replaces every occurrence of "${foo}" in s with headerField("foo")
const TQTextCodec * codec() const
Get a TQTextCodec suitable for this message part.
void applyIdentity(uint id)
Set the from, to, cc, bcc, encrytion etc headers as specified in the given identity.
TQString msgId() const
Get or set the 'Message-Id' header field.
TQCString id() const
Returns the message ID, useful for followups.
void initFromMessage(const KMMessage *msg, bool idHeaders=true)
Initialize headers fields according to the identity and the transport header of the given original me...
void initHeader(uint identity=0)
Initialize header fields.
static KMime::Types::AddressList splitAddrField(const TQCString &str)
Splits the given address list into separate addresses.
void setBodyFromUnicode(const TQString &str, DwEntity *entity=0)
Sets this body's content to str.
TQCString bodyDecoded() const
Returns a decoded version of the body from the current content transfer encoding. ...
void getLink(int n, ulong *retMsgSerNum, KMMsgStatus *reStatus) const
Returns the information for the Nth link into retMsg and reStatus.
bool subjectIsPrefixed() const
Is the subject prefixed by Re: or similar?
uint identityUoid() const
bool readyToShow() const
Return if the message is ready to be shown.
TQString templates() const
Get or set the 'Templates' folder.
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
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...
TQString drafts() const
Get or set the 'Drafts' folder.
KMime::Types::AddressList headerAddrField(const TQCString &name) const
Returns header address list as string list.
void setBodyEncoded(const TQCString &aStr, DwEntity *entity=0)
Set the message body, encoding it according to the current content transfer encoding.
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.
DwBodyPart * getFirstDwBodyPart() const
Get the 1st DwBodyPart.
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.
KMMsgStatus status() const
Status of the message.
void removeHeaderFields(const TQCString &name)
Remove all header fields with given name.
static TQString generateMessageId(const TQString &addr)
Generates the Message-Id.
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
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.
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...
TQCString dateShortStr() const
Returns the message date in asctime format or an empty string if the message lacks a Date header...
KMMsgInfo * msgInfo()
Get the KMMsgInfo object that was set with setMsgInfo().
TQString references() const
Get or set the references for this message.
void removePrivateHeaderFields()
Remove all private header fields: *Status: and X-KMail-*.
bool deleteBodyPart(int partIndex)
Delete a body part with the specified part index.
DwHeaders & headers() const
get the DwHeaders (make sure to call setNeedsAssembly() function after directly modyfying internal da...
TQString xmark() const
Get or set the 'X-Mark' header field.
void setMsgSerNum(unsigned long newMsgSerNum=0)
Sets the message serial number.
The TemplateParser transforms a message with a given template.
TQStringList headerFields(const TQCString &name) const
Returns a list of the values of all header fields with the given name.
int partNumber(DwBodyPart *aDwBodyPart) const
Get the number of the given DwBodyPart.
TQCString rawHeaderField(const TQCString &name) const
Returns the raw value of a header field with the given name.
bool transferInProgress() const
Return, if the message should not be deleted.
void setAllowDecryption(const bool allowDecryption)
Sets whether the template parser is allowed to decrypt the original message when needing its message ...
TQCString subtypeStr() const
Subtype.
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...
TQString asPlainText(bool stripSignature, bool allowDecryption) const
Return the textual content of the message as plain text, converting HTML to plain text if necessary...
static TQString expandAliases(const TQString &recipients)
Expands aliases (distribution lists and nick names) and appends a domain part to all email addresses ...
KMMessage * createDeliveryReceipt() const
Create a new message that is a delivery receipt of this message, filling required header fileds with ...
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 headerAsString() const
Return header as string.
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 asPlainTextFromObjectTree(partNode *root, bool stripSignature, bool allowDecryption) const
Same as asPlainText(), only that this method expects an already parsed object tree as paramter...
TQCString body() const
Get the message body.
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.
TQString cc() const
Get or set the 'Cc' header field.
TQByteArray asSendableString() const
Return the message contents with the headers that should not be sent stripped off.
DwBodyPart * dwBodyPart(int aIdx) const
Get the DwBodyPart at position in aIdx.
KMMessage * createRedirect(const TQString &toStr)
Create a new message that is a redirect to this message, filling all required header fields with the ...
TQString formatString(const TQString &) const
Convert wildcards into normal string.
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...
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.
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().
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
void deleteBodyParts()
Delete all body parts.
void setUnencryptedMsg(KMMessage *unencrypted)
Specifies an unencrypted copy of this message to be stored in a separate member variable to allow sav...
TQString fcc() const
Get or set the 'Fcc' header field.
TQCString contentTransferEncodingStr() const
Get or set the 'Content-Transfer-Encoding' header field The member functions that involve enumerated ...
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...
TQCString headerAsSendableString() const
Return the message header with the headers that should not be sent stripped off.
TQString to() const
Get or set the 'To' header field.
void assembleIfNeeded()
Assemble the internal message.
TQString subjectMD5() const
Get a hash of the subject.
TQCString asString() const
Return the entire message contents as a string.
TQString replyTo() const
Get or set the 'ReplyTo' header field.
KMMsgEncryptionState encryptionState() const
Encryption status of the message.
KMMessage(KMFolder *parent=0)
Straight forward initialization.
static TQString decodeMailtoUrl(const TQString &url)
Decodes a mailto URL.
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. ...
DwBodyPart * findDwBodyPart(int type, int subtype) const
Return the first DwBodyPart matching a given Content-Type or zero, if no found.
TQString bcc() const
Get or set the 'Bcc' header field.
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.
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.
TQCString CString(const DwString &str)
Construct a TQCString from a DwString.
KMMsgSignatureState signatureState() const
Signature status of the message.
TQCString charset() const
Get the message charset.
TQString strippedSubjectMD5() const
Get a hash of the subject with all prefixes such as Re: removed.
static void readConfig()
Reads config settings from group "KMMessage" and sets all internal variables (e.g.
ulong UID() const
Get/set UID.
TQCString mboxMessageSeparator()
Returns an mbox message separator line for this message, i.e.
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
bool hasUnencryptedMsg() const
Returns TRUE if the message contains an unencrypted copy of itself.
void removeHeaderField(const TQCString &name)
Remove header field with given name.
TQString bodyToUnicode(const TQTextCodec *codec=0) const
Returns the body part decoded to unicode.
TQString dateStr() const
Get or set the 'Date' header field.
bool isMessage() const
Returns TRUE if object is a real message (not KMMsgInfo or KMMsgBase)
void link(const KMMessage *aMsg, KMMsgStatus aStatus)
Links this message to aMsg, setting link type to aStatus.
int numBodyParts() const
Number of body parts the message has.
void setEncryptionState(const KMMsgEncryptionState, int idx=-1)
Set encryption status of the message.
void setAutomaticFields(bool isMultipart=false)
Set fields that are either automatically set (Message-id) or that do not change from one message to a...
void deleteWhenUnused()
Delete this message as soon as it no longer in use.
const DwString & asDwString() const
Return the entire message contents in the DwString.
TQCString createForwardBody()
Create the forwarded body for the message.
size_t msgSizeServer() const
Get/set size on server.
TQString replyToId() const
Get or set the 'In-Reply-To' header field.
TQCString getRefStr() const
Creates reference string for reply to messages.
TQString who() const
Get or set the 'Who' header field.