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 <kapplication.h>
38 #include <kglobalsettings.h>
41 #include <khtml_part.h>
44 #include <kasciistricmp.h>
47 #include <tqtextcodec.h>
48 #include <tqmessagebox.h>
49 #include <kmime_util.h>
50 #include <kmime_charfreq.h>
52 #include <kmime_header_parsing.h>
53 using KMime::HeaderParsing::parseAddressList;
54 using namespace KMime::Types;
56 #include <mimelib/body.h>
57 #include <mimelib/field.h>
58 #include <mimelib/mimepp.h>
59 #include <mimelib/string.h>
69 #include <kmessagebox.h>
72 using namespace KMime;
74 static DwString emptyString(
"");
77 static TQString sReplyLanguage, sReplyStr, sReplyAllStr, sIndentPrefixStr;
78 static bool sSmartQuote,
81 static TQStringList sPrefCharsets;
83 TQString KMMessage::sForwardStr;
84 const HeaderStrategy * KMMessage::sHeaderStrategy = HeaderStrategy::rich();
86 static void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart );
88 TQValueList<KMMessage*> KMMessage::sPendingDeletes;
96 mNeedsAssembly =
true;
111 mMsgSize = msgInfo.msgSize();
112 mFolderOffset = msgInfo.folderOffset();
113 mStatus = msgInfo.status();
114 mEncryptionState = msgInfo.encryptionState();
115 mSignatureState = msgInfo.signatureState();
116 mMDNSentState = msgInfo.mdnSentState();
117 mDate = msgInfo.date();
118 mFileName = msgInfo.fileName();
119 KMMsgBase::assign(&msgInfo);
133 void KMMessage::init( DwMessage* aMsg )
135 mNeedsAssembly =
false;
139 mMsg =
new DwMessage;
148 mStatus = KMMsgStatusNew;
149 mEncryptionState = KMMsgEncryptionStateUnknown;
150 mSignatureState = KMMsgSignatureStateUnknown;
151 mMDNSentState = KMMsgMDNStateUnknown;
160 void KMMessage::assign(
const KMMessage& other )
162 MessageProperty::forget(
this );
164 delete mUnencryptedMsg;
166 mNeedsAssembly =
true;
168 mMsg =
new DwMessage( *(other.mMsg) );
171 mOverrideCodec = other.mOverrideCodec;
172 mDecodeHTML = other.mDecodeHTML;
173 mMsgSize = other.mMsgSize;
174 mMsgLength = other.mMsgLength;
175 mFolderOffset = other.mFolderOffset;
176 mStatus = other.mStatus;
177 mEncryptionState = other.mEncryptionState;
178 mSignatureState = other.mSignatureState;
179 mMDNSentState = other.mMDNSentState;
180 mIsParsed = other.mIsParsed;
186 setDrafts( other.
drafts() );
197 kmkernel->undoStack()->msgDestroyed(
this );
202 void KMMessage::setReferences(
const TQCString& aStr)
204 if (aStr.isNull())
return;
205 mMsg->Headers().References().FromString(aStr);
206 mNeedsAssembly =
true;
213 DwHeaders& header = mMsg->Headers();
214 if (header.HasMessageId())
228 MessageProperty::setSerialCache(
this, newMsgSerNum );
250 sPendingDeletes.remove(
this );
252 int idx = parent()->find(
this );
254 parent()->removeMsg( idx );
263 return headerField(
"Priority" ).contains(
"urgent",
false )
270 delete mUnencryptedMsg;
271 mUnencryptedMsg = unencrypted;
277 TQString& brokenAddress )
279 if ( aStr.isEmpty() ) {
280 return KPIM::AddressEmpty;
283 TQStringList list = KPIM::splitEmailAddrList( aStr );
284 for( TQStringList::const_iterator it = list.begin(); it != list.end(); ++it ) {
285 KPIM::EmailParseResult errorCode = KPIM::isValidEmailAddress( *it );
286 if ( errorCode != KPIM::AddressOk ) {
287 brokenAddress = ( *it );
291 return KPIM::AddressOk;
299 mNeedsAssembly =
false;
302 return mMsg->AsString();
306 const DwMessage* KMMessage::asDwMessage()
310 mNeedsAssembly =
false;
324 KMMessage msg(
new DwMessage( *this->mMsg ) );
332 KMMessage msg(
new DwMessage( *this->mMsg ) );
356 char str[2] = { 0, 0 };
368 str[0] =
static_cast<char>( mdnSentState() );
373 mNeedsAssembly =
false;
374 mMsg->Headers().Assemble();
375 mMsg->Assemble( mMsg->Headers(),
383 DwHeaders& header = mMsg->Headers();
385 if ( header.AsString().empty() )
387 return TQString::fromLatin1( header.AsString().c_str() );
394 return mMsg->Headers().ContentType();
397 void KMMessage::fromByteArray(
const TQByteArray & ba,
bool setStatus ) {
398 return fromDwString( DwString( ba.data(), ba.size() ), setStatus );
401 void KMMessage::fromString(
const TQCString & str,
bool aSeStatus ) {
408 mMsg =
new DwMessage;
409 mMsg->FromString( str );
414 setEncryptionStateChar(
headerField(
"X-KMail-EncryptionState").at(0) );
415 setSignatureStateChar(
headerField(
"X-KMail-SignatureState").at(0) );
416 setMDNSentState( static_cast<KMMsgMDNSentState>(
headerField(
"X-KMail-MDN-Sent").at(0).latin1() ) );
418 if ( invitationState() == KMMsgInvitationUnknown &&
readyToShow() )
419 updateInvitationState();
420 if ( attachmentState() == KMMsgAttachmentUnknown &&
readyToShow() )
421 updateAttachmentState();
423 mNeedsAssembly =
false;
431 TQString result, str;
438 unsigned int strLength(aStr.length());
439 for (uint i=0; i<strLength;) {
449 result += KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
450 date(), sReplyLanguage,
false );
456 result += fromStrip();
462 for (j=0; str[j]>
' '; j++)
464 unsigned int strLength(str.length());
465 for (; j < strLength && str[j] <=
' '; j++)
510 static void removeTrailingSpace( TQString &line )
512 int i = line.length()-1;
513 while( (i >= 0) && ((line[i] ==
' ') || (line[i] ==
'\t')))
518 static TQString splitLine( TQString &line)
520 removeTrailingSpace( line );
523 int l = line.length();
530 if ((c ==
'>') || (c ==
':') || (c ==
'|'))
532 else if ((c !=
' ') && (c !=
'\t'))
543 TQString result = line.left(j);
548 TQString result = line.left(j);
553 static TQString flowText(TQString &text,
const TQString& indent,
int maxLength)
558 return indent+
"<NULL>\n";
564 if ((
int) text.length() > maxLength)
567 while( (i >= 0) && (text[i] !=
' '))
582 TQString line = text.left(i);
583 if (i < (
int) text.length())
588 result += indent + line +
'\n';
595 static bool flushPart(TQString &msg, TQStringList &part,
596 const TQString &indent,
int maxLength)
598 maxLength -= indent.length();
599 if (maxLength < 20) maxLength = 20;
602 while ((part.begin() != part.end()) && part.last().isEmpty())
604 part.remove(part.fromLast());
608 for(TQStringList::Iterator it2 = part.begin();
612 TQString line = (*it2);
617 msg += flowText(text, indent, maxLength);
618 msg += indent +
'\n';
625 text +=
' '+line.stripWhiteSpace();
627 if (((
int) text.length() < maxLength) || ((
int) line.length() < (maxLength-10)))
628 msg += flowText(text, indent, maxLength);
632 msg += flowText(text, indent, maxLength);
634 bool appendEmptyLine =
true;
636 appendEmptyLine =
false;
639 return appendEmptyLine;
642 static TQString stripSignature(
const TQString & msg,
bool clearSigned ) {
644 return msg.left( msg.findRev( TQRegExp(
"\n--\\s?\n" ) ) );
646 return msg.left( msg.findRev(
"\n-- \n" ) );
653 bool firstPart =
true;
656 const TQStringList lines = TQStringList::split(
'\n', msg,
true);
659 for(TQStringList::const_iterator it = lines.begin();
665 const TQString indent = splitLine( line );
670 part.append(TQString());
680 if (oldIndent != indent)
684 if (part.count() && (oldIndent.length() < indent.length()))
686 TQStringList::Iterator it2 = part.fromLast();
687 while( (it2 != part.end()) && (*it2).isEmpty())
690 if ((it2 != part.end()) && ((*it2).endsWith(
":")))
692 fromLine = oldIndent + (*it2) +
'\n';
696 if (flushPart( result, part, oldIndent, maxLineLength))
698 if (oldIndent.length() > indent.length())
699 result += indent +
'\n';
701 result += oldIndent +
'\n';
703 if (!fromLine.isEmpty())
711 flushPart( result, part, oldIndent, maxLineLength);
718 TQCString& parsedString,
719 const TQTextCodec*& codec,
725 partNode * curNode = root->findType( DwMime::kTypeText,
726 DwMime::kSubtypeUnknown,
729 kdDebug(5006) <<
"\n\n======= KMMessage::parseTextStringFromDwPart() - "
730 << ( curNode ?
"text part found!\n" :
"sorry, no text node!\n" ) << endl;
732 isHTML = DwMime::kSubtypeHtml == curNode->subType();
734 ObjectTreeParser otp( 0, 0,
true,
false,
true );
735 otp.parseObjectTree( curNode );
736 parsedString = otp.rawReplyString();
737 codec = curNode->msgPart().codec();
744 bool allowDecryption )
const
747 Q_ASSERT( root->processed() );
749 TQCString parsedString;
751 const TQTextCodec *
codec = 0;
753 if ( !root )
return TQString();
756 if ( mOverrideCodec || !codec )
757 codec = this->
codec();
759 if ( parsedString.isEmpty() )
762 bool clearSigned =
false;
766 if ( allowDecryption ) {
767 TQPtrList<Kpgp::Block> pgpBlocks;
768 TQStrList nonPgpBlocks;
769 if ( Kpgp::Module::prepareMessageForDecryption( parsedString,
774 if ( pgpBlocks.count() == 1 ) {
775 Kpgp::Block * block = pgpBlocks.first();
776 if ( block->type() == Kpgp::PgpMessageBlock ||
777 block->type() == Kpgp::ClearsignedBlock ) {
778 if ( block->type() == Kpgp::PgpMessageBlock ) {
787 result = codec->toUnicode( nonPgpBlocks.first() )
788 + codec->toUnicode( block->text() )
789 + codec->toUnicode( nonPgpBlocks.last() );
795 if ( result.isEmpty() ) {
796 result = codec->toUnicode( parsedString );
797 if ( result.isEmpty() )
802 if ( isHTML && mDecodeHTML ) {
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 )
873 TQString mailingListStr, replyToStr, toStr;
874 TQStringList mailingListAddresses;
875 TQCString refStr, headerName;
876 bool replyAll =
true;
880 MailingList::name(
this, headerName, mailingListStr);
886 if ( parent() && parent()->isMailingListEnabled() &&
887 !parent()->mailingListPostAddress().isEmpty() ) {
888 mailingListAddresses << parent()->mailingListPostAddress();
890 if (
headerField(
"List-Post").find(
"mailto:", 0,
false ) != -1 ) {
892 TQRegExp rx(
"<mailto:([^@>]+)@([^>]+)>",
false );
893 if ( rx.search( listPost, 0 ) != -1 )
894 mailingListAddresses << rx.cap(1) +
'@' + rx.cap(2);
898 switch( replyStrategy ) {
899 case KMail::ReplySmart : {
900 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
903 else if ( !replyToStr.isEmpty() ) {
907 else if ( !mailingListAddresses.isEmpty() ) {
908 toStr = mailingListAddresses[0];
917 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
920 if ( toStr.isEmpty() && !recipients.isEmpty() )
921 toStr = recipients[0];
925 case KMail::ReplyList : {
926 if ( !
headerField(
"Mail-Followup-To" ).isEmpty() ) {
929 else if ( !mailingListAddresses.isEmpty() ) {
930 toStr = mailingListAddresses[0];
932 else if ( !replyToStr.isEmpty() ) {
937 TQStringList recipients = KPIM::splitEmailAddrList( toStr );
942 case KMail::ReplyAll : {
943 TQStringList recipients;
944 TQStringList ccRecipients;
947 if( !replyToStr.isEmpty() ) {
948 recipients += KPIM::splitEmailAddrList( replyToStr );
951 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
952 it != mailingListAddresses.end();
958 if ( !mailingListAddresses.isEmpty() ) {
960 if ( recipients.isEmpty() && !
from().isEmpty() ) {
963 ccRecipients +=
from();
964 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of CC recipients"
968 recipients.prepend( mailingListAddresses[0] );
972 if ( recipients.isEmpty() && !
from().isEmpty() ) {
975 recipients +=
from();
976 kdDebug(5006) <<
"Added " <<
from() <<
" to the list of recipients"
985 if( !
cc().isEmpty() || !
to().isEmpty() ) {
988 list += KPIM::splitEmailAddrList(
to());
990 list += KPIM::splitEmailAddrList(
cc());
991 for( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
995 kdDebug(5006) <<
"Added " << *it <<
" to the list of CC recipients"
1001 if ( !ccRecipients.isEmpty() ) {
1007 if ( toStr.isEmpty() && !ccRecipients.isEmpty() ) {
1008 toStr = ccRecipients[0];
1009 ccRecipients.pop_front();
1012 msg->setCc( ccRecipients.join(
", ") );
1015 if ( toStr.isEmpty() && !recipients.isEmpty() ) {
1017 toStr = recipients[0];
1021 case KMail::ReplyAuthor : {
1022 if ( !replyToStr.isEmpty() ) {
1023 TQStringList recipients = KPIM::splitEmailAddrList( replyToStr );
1026 for ( TQStringList::const_iterator it = mailingListAddresses.begin();
1027 it != mailingListAddresses.end();
1031 if ( !recipients.isEmpty() ) {
1032 toStr = recipients.join(
", ");
1040 else if ( !
from().isEmpty() ) {
1046 case KMail::ReplyNone : {
1054 if (!refStr.isEmpty())
1055 msg->setReferences(refStr);
1057 msg->setReplyToId(
msgId());
1069 msg->setSubject( replySubject() );
1071 formatString( GlobalSettings::self()->quoteString() ) );
1073 TemplateParser parser( msg, ( replyAll ? TemplateParser::ReplyAll : TemplateParser::Reply ) );
1075 if ( GlobalSettings::quoteSelectionOnly() ) {
1078 if ( !tmpl.isEmpty() ) {
1079 parser.process( tmpl,
this );
1081 parser.process(
this );
1085 msg->
link(
this, KMMsgStatusReplied);
1087 if ( parent() && parent()->putRepliesInSameFolder() )
1088 msg->setFcc( parent()->idString() );
1103 TQCString firstRef, lastRef, refStr, retRefStr;
1106 refStr =
headerField(
"References").stripWhiteSpace().latin1();
1108 if (refStr.isEmpty())
1111 i = refStr.find(
'<');
1112 j = refStr.find(
'>');
1113 firstRef = refStr.mid(i, j-i+1);
1114 if (!firstRef.isEmpty())
1115 retRefStr = firstRef +
' ';
1117 i = refStr.findRev(
'<');
1118 j = refStr.findRev(
'>');
1120 lastRef = refStr.mid(i, j-i+1);
1121 if (!lastRef.isEmpty() && lastRef != firstRef)
1122 retRefStr += lastRef +
' ';
1133 KMMessagePart msgPart;
1136 TQString strId = msg->
headerField(
"X-KMail-Identity" ).stripWhiteSpace();
1137 if ( !strId.isEmpty())
1138 id = strId.toUInt();
1139 const KPIM::Identity & ident =
1140 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1143 TQString strByWayOf = TQString(
"%1 (by way of %2 <%3>)")
1145 .arg( ident.fullName() )
1146 .arg( ident.primaryEmailAddress() );
1149 TQString strFrom = TQString(
"%1 <%2>")
1150 .arg( ident.fullName() )
1151 .arg( ident.primaryEmailAddress() );
1158 if ( origDate.isEmpty() )
1173 msg->
link(
this, KMMsgStatusForwarded);
1185 if (sHeaderStrategy == HeaderStrategy::all()) {
1186 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1189 str +=
"\n-------------------------------------------------------\n";
1191 s =
"\n\n---------- " + sForwardStr +
" ----------\n\n";
1192 s +=
"Subject: " +
subject() +
"\n";
1194 + KMime::DateFormatter::formatDate( KMime::DateFormatter::Localized,
1195 date(), sReplyLanguage,
false )
1197 s +=
"From: " +
from() +
"\n";
1198 s +=
"To: " +
to() +
"\n";
1199 if (!
cc().isEmpty()) s +=
"Cc: " +
cc() +
"\n";
1202 str +=
"\n-------------------------------------------------------\n";
1212 DwHeaders& header = mMsg->Headers();
1213 DwField* field = header.FirstField();
1217 nextField = field->Next();
1218 if ( field->FieldNameStr().find(
"ontent" ) == DwString::npos
1219 && !whiteList.contains( TQString::fromLatin1( field->FieldNameStr().c_str() ) ) )
1220 header.RemoveField(field);
1234 if ( type() == DwMime::kTypeMultipart ||
1235 ( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypePlain ) ) {
1240 DwMediaType oldContentType = msg->mMsg->Headers().ContentType();
1245 TQStringList blacklist = GlobalSettings::self()->mimetypesToStripWhenInlineForwarding();
1246 for ( TQStringList::Iterator it = blacklist.begin(); it != blacklist.end(); ++it ) {
1247 TQString entry = (*it);
1248 int sep = entry.find(
'/' );
1249 TQCString type = entry.left( sep ).latin1();
1250 TQCString subtype = entry.mid( sep+1 ).latin1();
1251 kdDebug( 5006 ) <<
"Looking for blacklisted type: " << type <<
"/" << subtype << endl;
1252 while ( DwBodyPart * part = msg->
findDwBodyPart( type, subtype ) ) {
1253 msg->mMsg->Body().RemoveBodyPart( part );
1256 msg->mMsg->Assemble();
1260 msg->mMsg->Headers().ContentType().FromString( oldContentType.AsString() );
1261 msg->mMsg->Headers().ContentType().Parse();
1262 msg->mMsg->Assemble();
1264 else if( type() == DwMime::kTypeText && subtype() == DwMime::kSubtypeHtml ) {
1268 msg->setType( DwMime::kTypeText );
1269 msg->setSubtype( DwMime::kSubtypeHtml );
1270 msg->mNeedsAssembly =
true;
1280 DwHeaders & header = msg->mMsg->Headers();
1281 header.MimeVersion().FromString(
"1.0");
1283 contentType.SetType( DwMime::kTypeMultipart );
1284 contentType.SetSubtype( DwMime::kSubtypeMixed );
1285 contentType.CreateBoundary(0);
1286 contentType.Assemble();
1289 KMMessagePart msgPart;
1293 KMMessagePart secondPart;
1294 secondPart.setType( type() );
1295 secondPart.setSubtype( subtype() );
1296 secondPart.setBody( mMsg->Body().AsString() );
1298 applyHeadersToMessagePart( mMsg->Headers(), &secondPart );
1300 msg->mNeedsAssembly =
true;
1305 msg->setSubject( forwardSubject() );
1308 if ( !tmpl.isEmpty() ) {
1309 parser.process( tmpl,
this );
1311 parser.process(
this );
1321 msg->
link(
this, KMMsgStatusForwarded);
1325 static const struct {
1326 const char * dontAskAgainID;
1329 } mdnMessageBoxes[] = {
1330 {
"mdnNormalAsk",
true,
1331 I18N_NOOP(
"This message contains a request to return a notification "
1332 "about your reception of the message.\n"
1333 "You can either ignore the request or let KMail send a "
1334 "\"denied\" or normal response.") },
1335 {
"mdnUnknownOption",
false,
1336 I18N_NOOP(
"This message contains a request to send a notification "
1337 "about your reception of the message.\n"
1338 "It contains a processing instruction that is marked as "
1339 "\"required\", but which is unknown to KMail.\n"
1340 "You can either ignore the request or let KMail send a "
1341 "\"failed\" response.") },
1342 {
"mdnMultipleAddressesInReceiptTo",
true,
1343 I18N_NOOP(
"This message contains a request to send a notification "
1344 "about your reception of the message,\n"
1345 "but it is requested to send the notification to more "
1346 "than one address.\n"
1347 "You can either ignore the request or let KMail send a "
1348 "\"denied\" or normal response.") },
1349 {
"mdnReturnPathEmpty",
true,
1350 I18N_NOOP(
"This message contains a request to send a notification "
1351 "about your reception of the message,\n"
1352 "but there is no return-path set.\n"
1353 "You can either ignore the request or let KMail send a "
1354 "\"denied\" or normal response.") },
1355 {
"mdnReturnPathNotInReceiptTo",
true,
1356 I18N_NOOP(
"This message contains a request to send a notification "
1357 "about your reception of the message,\n"
1358 "but the return-path address differs from the address "
1359 "the notification was requested to be sent to.\n"
1360 "You can either ignore the request or let KMail send a "
1361 "\"denied\" or normal response.") },
1364 static const int numMdnMessageBoxes
1365 =
sizeof mdnMessageBoxes /
sizeof *mdnMessageBoxes;
1368 static int requestAdviceOnMDN(
const char * what ) {
1369 for (
int i = 0 ; i < numMdnMessageBoxes ; ++i ) {
1370 if ( !qstrcmp( what, mdnMessageBoxes[i].dontAskAgainID ) ) {
1371 if ( mdnMessageBoxes[i].canDeny ) {
1373 int answer = TQMessageBox::information( 0,
1374 i18n(
"Message Disposition Notification Request"),
1375 i18n( mdnMessageBoxes[i].text ),
1376 i18n(
"&Ignore"), i18n(
"Send \"&denied\""), i18n(
"&Send") );
1377 return answer ? answer + 1 : 0 ;
1380 int answer = TQMessageBox::information( 0,
1381 i18n(
"Message Disposition Notification Request"),
1382 i18n( mdnMessageBoxes[i].text ),
1383 i18n(
"&Ignore"), i18n(
"&Send") );
1384 return answer ? answer + 2 : 0 ;
1388 kdWarning(5006) <<
"didn't find data for message box \""
1389 << what <<
"\"" << endl;
1394 MDN::DispositionType d,
1396 TQValueList<MDN::DispositionModifier> m )
1405 if ( mdnSentState() != KMMsgMDNStateUnknown &&
1406 mdnSentState() != KMMsgMDNNone )
1409 char st[2]; st[0] = (char)mdnSentState(); st[1] = 0;
1410 kdDebug(5006) <<
"mdnSentState() == '" << st <<
"'" << endl;
1415 DwMime::kSubtypeDispositionNotification ) ) {
1416 setMDNSentState( KMMsgMDNIgnore );
1421 TQString receiptTo =
headerField(
"Disposition-Notification-To");
1422 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1423 receiptTo.remove(
'\n' );
1426 MDN::SendingMode s = MDN::SentAutomatically;
1428 KConfigGroup mdnConfig( KMKernel::config(),
"MDN" );
1431 int mode = mdnConfig.readNumEntry(
"default-policy", 0 );
1432 if ( !mode || mode < 0 || mode > 3 ) {
1434 setMDNSentState( KMMsgMDNIgnore );
1444 TQString notificationOptions =
headerField(
"Disposition-Notification-Options");
1445 if ( notificationOptions.contains(
"required",
false ) ) {
1449 if ( !allowGUI )
return 0;
1450 mode = requestAdviceOnMDN(
"mdnUnknownOption" );
1451 s = MDN::SentManually;
1453 special = i18n(
"Header \"Disposition-Notification-Options\" contained "
1454 "required, but unknown parameter");
1462 kdDebug(5006) <<
"KPIM::splitEmailAddrList(receiptTo): "
1463 << KPIM::splitEmailAddrList(receiptTo).join(
"\n") << endl;
1464 if ( KPIM::splitEmailAddrList(receiptTo).count() > 1 ) {
1465 if ( !allowGUI )
return 0;
1466 mode = requestAdviceOnMDN(
"mdnMultipleAddressesInReceiptTo" );
1467 s = MDN::SentManually;
1475 AddrSpecList returnPathList = extractAddrSpecs(
"Return-Path");
1476 TQString returnPath = returnPathList.isEmpty() ? TQString()
1477 : returnPathList.front().localPart +
'@' + returnPathList.front().domain ;
1478 kdDebug(5006) <<
"clean return path: " << returnPath << endl;
1479 if ( returnPath.isEmpty() || !receiptTo.contains( returnPath,
false ) ) {
1480 if ( !allowGUI )
return 0;
1481 mode = requestAdviceOnMDN( returnPath.isEmpty() ?
1482 "mdnReturnPathEmpty" :
1483 "mdnReturnPathNotInReceiptTo" );
1484 s = MDN::SentManually;
1487 if ( a != KMime::MDN::AutomaticAction ) {
1490 if ( !allowGUI )
return 0;
1491 mode = requestAdviceOnMDN(
"mdnNormalAsk" );
1492 s = MDN::SentManually;
1497 setMDNSentState( KMMsgMDNIgnore );
1501 kdFatal(5006) <<
"KMMessage::createMDN(): The \"ask\" mode should "
1502 <<
"never appear here!" << endl;
1515 TQString finalRecipient = kmkernel->identityManager()
1516 ->identityForUoidOrDefault(
identityUoid() ).fullEmailAddr();
1527 DwHeaders & header = receipt->mMsg->Headers();
1528 header.MimeVersion().FromString(
"1.0");
1530 contentType.SetType( DwMime::kTypeMultipart );
1531 contentType.SetSubtype( DwMime::kSubtypeReport );
1532 contentType.CreateBoundary(0);
1533 receipt->mNeedsAssembly =
true;
1539 KMMessagePart firstMsgPart;
1540 firstMsgPart.setTypeStr(
"text" );
1541 firstMsgPart.setSubtypeStr(
"plain" );
1542 firstMsgPart.setBodyFromUnicode( description );
1546 KMMessagePart secondMsgPart;
1547 secondMsgPart.setType( DwMime::kTypeMessage );
1548 secondMsgPart.setSubtype( DwMime::kSubtypeDispositionNotification );
1551 secondMsgPart.setBodyEncoded( MDN::dispositionNotificationBodyContent(
1555 d, a, s, m, special ) );
1559 int num = mdnConfig.readNumEntry(
"quote-message", 0 );
1560 if ( num < 0 || num > 2 ) num = 0;
1561 MDN::ReturnContent returnContent =
static_cast<MDN::ReturnContent
>( num );
1563 KMMessagePart thirdMsgPart;
1564 switch ( returnContent ) {
1566 thirdMsgPart.setTypeStr(
"message" );
1567 thirdMsgPart.setSubtypeStr(
"rfc822" );
1571 case MDN::HeadersOnly:
1572 thirdMsgPart.setTypeStr(
"text" );
1573 thirdMsgPart.setSubtypeStr(
"rfc822-headers" );
1582 receipt->setTo( receiptTo );
1583 receipt->setSubject(
"Message Disposition Notification" );
1584 receipt->setReplyToId(
msgId() );
1589 kdDebug(5006) <<
"final message:\n" + receipt->
asString() << endl;
1594 KMMsgMDNSentState state = KMMsgMDNStateUnknown;
1596 case MDN::Displayed: state = KMMsgMDNDisplayed;
break;
1597 case MDN::Deleted: state = KMMsgMDNDeleted;
break;
1598 case MDN::Dispatched: state = KMMsgMDNDispatched;
break;
1599 case MDN::Processed: state = KMMsgMDNProcessed;
break;
1600 case MDN::Denied: state = KMMsgMDNDenied;
break;
1601 case MDN::Failed: state = KMMsgMDNFailed;
break;
1603 setMDNSentState( state );
1609 TQString result = s;
1610 TQRegExp rx(
"\\$\\{([a-z0-9-]+)\\}",
false );
1611 Q_ASSERT( rx.isValid() );
1613 TQRegExp rxDate(
"\\$\\{date\\}" );
1614 Q_ASSERT( rxDate.isValid() );
1616 TQString sDate = KMime::DateFormatter::formatDate(
1617 KMime::DateFormatter::Localized, date() );
1620 if( ( idx = rxDate.search( result, idx ) ) != -1 ) {
1621 result.replace( idx, rxDate.matchedLength(), sDate );
1625 while ( ( idx = rx.search( result, idx ) ) != -1 ) {
1626 TQString replacement =
headerField( TQString(rx.cap(1)).latin1() );
1627 result.replace( idx, rx.matchedLength(), replacement );
1628 idx += replacement.length();
1635 TQString str, receiptTo;
1638 receiptTo =
headerField(
"Disposition-Notification-To");
1639 if ( receiptTo.stripWhiteSpace().isEmpty() )
return 0;
1640 receiptTo.remove(
'\n' );
1644 receipt->setTo(receiptTo);
1645 receipt->setSubject(i18n(
"Receipt: ") +
subject());
1647 str =
"Your message was successfully delivered.";
1648 str +=
"\n\n---------- Message header follows ----------\n";
1650 str +=
"--------------------------------------------\n";
1653 receipt->
setBody(str.latin1());
1662 const KPIM::Identity & ident =
1663 kmkernel->identityManager()->identityForUoidOrDefault(
id );
1665 if(ident.fullEmailAddr().isEmpty())
1668 setFrom(ident.fullEmailAddr());
1670 if(ident.replyToAddr().isEmpty())
1673 setReplyTo(ident.replyToAddr());
1675 if(ident.bcc().isEmpty())
1678 setBcc(ident.bcc());
1680 if (ident.organization().isEmpty())
1685 if (ident.isDefault())
1688 setHeaderField(
"X-KMail-Identity", TQString::number( ident.uoid() ));
1690 if ( ident.transport().isEmpty() )
1695 if ( ident.fcc().isEmpty() )
1696 setFcc( TQString() );
1698 setFcc( ident.fcc() );
1700 if ( ident.drafts().isEmpty() )
1701 setDrafts( TQString() );
1703 setDrafts( ident.drafts() );
1705 if ( ident.templates().isEmpty() )
1706 setTemplates( TQString() );
1708 setTemplates( ident.templates() );
1726 TQString idString =
headerField(
"X-KMail-Identity").stripWhiteSpace();
1728 int id = idString.toUInt( &ok );
1730 if ( !ok ||
id == 0 )
1731 id = kmkernel->identityManager()->identityForAddress(
to() +
", " +
cc() ).uoid();
1732 if (
id == 0 && parent() )
1733 id = parent()->identity();
1746 if (!msg->
headerField(
"X-KMail-Transport").isEmpty())
1754 DwHeaders& header = mMsg->Headers();
1755 DwField* field = header.FirstField();
1758 if (mNeedsAssembly) mMsg->Assemble();
1759 mNeedsAssembly =
false;
1763 nextField = field->Next();
1764 if (field->FieldBody()->AsString().empty())
1766 header.RemoveField(field);
1767 mNeedsAssembly =
true;
1777 DwHeaders& header = mMsg->Headers();
1778 header.MimeVersion().FromString(
"1.0");
1784 contentType.SetType( DwMime::kTypeMultipart);
1785 contentType.SetSubtype(DwMime::kSubtypeMixed );
1788 contentType.CreateBoundary(0);
1790 mNeedsAssembly =
true;
1797 KConfigGroup general( KMKernel::config(),
"General" );
1798 DwHeaders& header = mMsg->Headers();
1801 if (!header.HasDate())
return "";
1802 unixTime = header.Date().AsUnixTime();
1806 return KMime::DateFormatter::formatDate(
1807 static_cast<KMime::DateFormatter::FormatType>(general.readNumEntry(
"dateFormat", KMime::DateFormatter::Fancy )),
1808 unixTime, general.readEntry(
"customDateFormat" ));
1815 DwHeaders& header = mMsg->Headers();
1818 if (!header.HasDate())
return "";
1819 unixTime = header.Date().AsUnixTime();
1821 TQCString result = ctime(&unixTime);
1822 int len = result.length();
1823 if (result[len-1]==
'\n')
1824 result.truncate(len-1);
1831 TQString KMMessage::dateIsoStr()
const
1833 DwHeaders& header = mMsg->Headers();
1836 if (!header.HasDate())
return "";
1837 unixTime = header.Date().AsUnixTime();
1840 strftime(cstr, 63,
"%Y-%m-%d %H:%M:%S", localtime(&unixTime));
1841 return TQString(cstr);
1846 time_t KMMessage::date()
const
1848 time_t res = ( time_t )-1;
1849 DwHeaders& header = mMsg->Headers();
1850 if (header.HasDate())
1851 res = header.Date().AsUnixTime();
1859 struct timeval tval;
1860 gettimeofday(&tval, 0);
1861 setDate((time_t)tval.tv_sec);
1866 void KMMessage::setDate(time_t aDate)
1869 mMsg->Headers().Date().FromCalendarTime(aDate);
1870 mMsg->Headers().Date().Assemble();
1871 mNeedsAssembly =
true;
1877 void KMMessage::setDate(
const TQCString& aStr)
1879 DwHeaders& header = mMsg->Headers();
1881 header.Date().FromString(aStr);
1882 header.Date().Parse();
1883 mNeedsAssembly =
true;
1886 if (header.HasDate())
1887 mDate = header.Date().AsUnixTime();
1897 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1900 return KPIM::normalizeAddressesAndDecodeIDNs( headers.join(
", " ) );
1905 void KMMessage::setTo(
const TQString& aStr)
1911 TQString KMMessage::toStrip()
const
1919 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Reply-To") );
1924 void KMMessage::setReplyTo(
const TQString& aStr)
1931 void KMMessage::setReplyTo(
KMMessage* aMsg)
1944 for ( TQValueList<TQCString>::Iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
1947 return KPIM::normalizeAddressesAndDecodeIDNs( headers.join(
", " ) );
1952 void KMMessage::setCc(
const TQString& aStr)
1959 TQString KMMessage::ccStrip()
const
1968 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"Bcc") );
1973 void KMMessage::setBcc(
const TQString& aStr)
1986 void KMMessage::setFcc(
const TQString &aStr )
1992 void KMMessage::setDrafts(
const TQString &aStr )
1998 void KMMessage::setTemplates(
const TQString &aStr )
2007 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(mParent->whoField().utf8()) );
2015 return KPIM::normalizeAddressesAndDecodeIDNs(
rawHeaderField(
"From") );
2020 void KMMessage::setFrom(
const TQString& bStr)
2022 TQString aStr = bStr;
2031 TQString KMMessage::fromStrip()
const
2038 AddrSpecList asl = extractAddrSpecs(
"Sender" );
2040 asl = extractAddrSpecs(
"From" );
2043 return asl.front().asString();
2054 void KMMessage::setSubject(
const TQString& aStr)
2069 void KMMessage::setXMark(
const TQString& aStr)
2079 int leftAngle, rightAngle;
2084 rightAngle = replyTo.find(
'>' );
2085 if (rightAngle != -1)
2086 replyTo.truncate( rightAngle + 1 );
2088 leftAngle = replyTo.findRev(
'<' );
2089 if (leftAngle != -1)
2090 replyTo = replyTo.mid( leftAngle );
2096 if (!replyTo.isEmpty() && (replyTo[0] ==
'<') &&
2097 ( -1 == replyTo.find(
'"' ) ) )
2101 leftAngle = references.findRev(
'<' );
2102 if (leftAngle != -1)
2103 references = references.mid( leftAngle );
2104 rightAngle = references.find(
'>' );
2105 if (rightAngle != -1)
2106 references.truncate( rightAngle + 1 );
2109 if (!references.isEmpty() && references[0] ==
'<')
2118 TQString KMMessage::replyToIdMD5()
const {
2125 int leftAngle, rightAngle;
2129 leftAngle = references.findRev(
'<' );
2130 leftAngle = references.findRev(
'<', leftAngle - 1 );
2131 if( leftAngle != -1 )
2132 references = references.mid( leftAngle );
2133 rightAngle = references.findRev(
'>' );
2134 if( rightAngle != -1 )
2135 references.truncate( rightAngle + 1 );
2137 if( !references.isEmpty() && references[0] ==
'<' )
2149 const int rightAngle = result.find(
'>' );
2150 if( rightAngle != -1 )
2151 result.truncate( rightAngle + 1 );
2153 return base64EncodedMD5( result );
2158 return base64EncodedMD5( stripOffPrefixes(
subject() ),
true );
2163 return base64EncodedMD5(
subject(),
true );
2172 void KMMessage::setReplyToId(
const TQString& aStr)
2185 const int rightAngle = msgId.find(
'>' );
2186 if (rightAngle != -1)
2187 msgId.truncate( rightAngle + 1 );
2189 const int leftAngle = msgId.findRev(
'<' );
2190 if (leftAngle != -1)
2191 msgId = msgId.mid( leftAngle );
2197 TQString KMMessage::msgIdMD5()
const {
2198 return base64EncodedMD5(
msgId() );
2203 void KMMessage::setMsgId(
const TQString& aStr)
2216 void KMMessage::setMsgSizeServer(
size_t size)
2229 void KMMessage::setUID(ulong uid)
2239 const char * scursor = str.begin();
2241 return AddressList();
2242 const char *
const send = str.begin() + str.length();
2243 if ( !parseAddressList( scursor, send, result ) )
2244 kdDebug(5006) <<
"Error in address splitting: parseAddressList returned false!"
2253 AddrSpecList KMMessage::extractAddrSpecs(
const TQCString & header )
const {
2255 AddrSpecList result;
2256 for ( AddressList::const_iterator ait = al.begin() ; ait != al.end() ; ++ait )
2257 for ( MailboxList::const_iterator mit = (*ait).mailboxList.begin() ; mit != (*ait).mailboxList.end() ; ++mit )
2258 result.push_back( (*mit).addrSpec );
2263 if ( name.isEmpty() )
return TQCString();
2265 DwHeaders & header = mMsg->Headers();
2266 DwField * field = header.FindField( name );
2268 if ( !field )
return TQCString();
2270 return header.FieldBody( name.data() ).AsString().c_str();
2275 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2276 return TQValueList<TQCString>();
2278 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2280 for ( uint i = 0; i < v.size(); ++i ) {
2281 headerFields.append( v[i]->AsString().c_str() );
2289 if ( aName.isEmpty() )
2292 if ( !mMsg->Headers().FindField( aName ) )
2295 return decodeRFC2047String( mMsg->Headers().FieldBody( aName.data() ).AsString().c_str(),
2302 if ( field.isEmpty() || !mMsg->Headers().FindField( field ) )
2303 return TQStringList();
2305 std::vector<DwFieldBody*> v = mMsg->Headers().AllFieldBodies( field.data() );
2307 for ( uint i = 0; i < v.size(); ++i ) {
2308 headerFields.append( decodeRFC2047String( v[i]->AsString().c_str(),
charset() ) );
2317 DwHeaders & header = mMsg->Headers();
2318 DwField * field = header.FindField(aName);
2321 header.RemoveField(field);
2322 mNeedsAssembly =
true;
2328 DwHeaders & header = mMsg->Headers();
2329 while ( DwField * field = header.FindField(aName) ) {
2330 header.RemoveField(field);
2331 mNeedsAssembly =
true;
2338 HeaderFieldType type,
bool prepend )
2341 if ( type != Unstructured )
2342 kdDebug(5006) <<
"KMMessage::setHeaderField( \"" << aName <<
"\", \""
2343 << bValue <<
"\", " << type <<
" )" << endl;
2345 if (aName.isEmpty())
return;
2347 DwHeaders& header = mMsg->Headers();
2352 if (!bValue.isEmpty())
2354 TQString value = bValue;
2355 if ( type == Address )
2356 value = KPIM::normalizeAddressesAndEncodeIDNs( value );
2358 if ( type != Unstructured )
2359 kdDebug(5006) <<
"value: \"" << value <<
"\"" << endl;
2361 TQCString encoding = autoDetectCharset(
charset(), sPrefCharsets, value );
2362 if (encoding.isEmpty())
2364 aValue = encodeRFC2047String( value, encoding );
2366 if ( type != Unstructured )
2367 kdDebug(5006) <<
"aValue: \"" << aValue <<
"\"" << endl;
2371 if (str[str.length()-1] !=
':') str +=
": ";
2373 if ( !aValue.isEmpty() )
2374 str += aValue.data();
2375 if (str[str.length()-1] !=
'\n') str +=
'\n';
2377 field =
new DwField(str, mMsg);
2381 header.AddFieldAt( 1, field );
2383 header.AddOrReplaceField( field );
2384 mNeedsAssembly =
true;
2391 DwHeaders& header = mMsg->Headers();
2392 if (header.HasContentType())
return header.ContentType().TypeStr().c_str();
2398 int KMMessage::type()
const
2400 DwHeaders& header = mMsg->Headers();
2401 if (header.HasContentType())
return header.ContentType().Type();
2402 else return DwMime::kTypeNull;
2407 void KMMessage::setTypeStr(
const TQCString& aStr)
2411 mNeedsAssembly =
true;
2416 void KMMessage::setType(
int aType)
2420 mNeedsAssembly =
true;
2428 DwHeaders& header = mMsg->Headers();
2429 if (header.HasContentType())
return header.ContentType().SubtypeStr().c_str();
2435 int KMMessage::subtype()
const
2437 DwHeaders& header = mMsg->Headers();
2438 if (header.HasContentType())
return header.ContentType().Subtype();
2439 else return DwMime::kSubtypeNull;
2444 void KMMessage::setSubtypeStr(
const TQCString& aStr)
2448 mNeedsAssembly =
true;
2453 void KMMessage::setSubtype(
int aSubtype)
2457 mNeedsAssembly =
true;
2463 const TQCString& attr,
2464 const TQCString& val )
2467 DwParameter *param = mType.FirstParameter();
2469 if (!kasciistricmp(param->Attribute().c_str(), attr))
2472 param = param->Next();
2475 param =
new DwParameter;
2476 param->SetAttribute(DwString( attr ));
2477 mType.AddParameter( param );
2480 mType.SetModified();
2481 param->SetValue(DwString( val ));
2489 if (mNeedsAssembly) mMsg->Assemble();
2490 mNeedsAssembly =
false;
2492 mNeedsAssembly =
true;
2499 DwHeaders& header = mMsg->Headers();
2500 if (header.HasContentTransferEncoding())
2501 return header.ContentTransferEncoding().AsString().c_str();
2507 int KMMessage::contentTransferEncoding( DwEntity *entity )
const
2512 DwHeaders& header = entity->Headers();
2513 if ( header.HasContentTransferEncoding() )
2514 return header.ContentTransferEncoding().AsEnum();
2515 else return DwMime::kCteNull;
2520 void KMMessage::setContentTransferEncodingStr(
const TQCString& cteString,
2526 entity->Headers().ContentTransferEncoding().FromString( cteString );
2527 entity->Headers().ContentTransferEncoding().Parse();
2528 mNeedsAssembly =
true;
2533 void KMMessage::setContentTransferEncoding(
int cte, DwEntity *entity )
2538 entity->Headers().ContentTransferEncoding().FromEnum( cte );
2539 mNeedsAssembly =
true;
2546 return mMsg->Headers();
2553 mNeedsAssembly =
true;
2561 if ( mNeedsAssembly ) {
2563 mNeedsAssembly =
false;
2570 const DwString&
body = mMsg->Body().AsString();
2580 TQByteArray KMMessage::bodyDecodedBinary()
const
2583 const DwString& dwsrc = mMsg->Body().AsString();
2587 case DwMime::kCteBase64:
2588 DwDecodeBase64(dwsrc, dwstr);
2590 case DwMime::kCteQuotedPrintable:
2591 DwDecodeQuotedPrintable(dwsrc, dwstr);
2598 int len = dwstr.size();
2599 TQByteArray ba(len);
2600 memcpy(ba.data(),dwstr.data(),len);
2609 DwString dwsrc = mMsg->Body().AsString();
2613 case DwMime::kCteBase64:
2614 DwDecodeBase64(dwsrc, dwstr);
2616 case DwMime::kCteQuotedPrintable:
2617 DwDecodeQuotedPrintable(dwsrc, dwstr);
2639 TQValueList<int> allowedCtes;
2641 switch ( cf.type() ) {
2642 case CharFreq::SevenBitText:
2643 allowedCtes << DwMime::kCte7bit;
2644 case CharFreq::EightBitText:
2646 allowedCtes << DwMime::kCte8bit;
2647 case CharFreq::SevenBitData:
2648 if ( cf.printableRatio() > 5.0/6.0 ) {
2652 allowedCtes << DwMime::kCteQp;
2653 allowedCtes << DwMime::kCteBase64;
2655 allowedCtes << DwMime::kCteBase64;
2656 allowedCtes << DwMime::kCteQp;
2659 case CharFreq::EightBitData:
2660 allowedCtes << DwMime::kCteBase64;
2662 case CharFreq::None:
2672 if ( ( willBeSigned && cf.hasTrailingWhitespace() ) ||
2673 cf.hasLeadingFrom() ) {
2674 allowedCtes.remove( DwMime::kCte8bit );
2675 allowedCtes.remove( DwMime::kCte7bit );
2684 TQValueList<int> & allowedCte,
2692 CharFreq cf( aBuf );
2694 setCte( allowedCte[0], entity );
2695 setBodyEncodedBinary( aBuf, entity );
2701 TQValueList<int> & allowedCte,
2709 CharFreq cf( aBuf.data(), aBuf.size()-1 );
2711 setCte( allowedCte[0], entity );
2722 DwString dwSrc(aStr.data(), aStr.size()-1 );
2725 switch (cte( entity ))
2727 case DwMime::kCteBase64:
2728 DwEncodeBase64(dwSrc, dwResult);
2730 case DwMime::kCteQuotedPrintable:
2731 DwEncodeQuotedPrintable(dwSrc, dwResult);
2738 entity->Body().FromString(dwResult);
2739 mNeedsAssembly =
true;
2743 void KMMessage::setBodyEncodedBinary(
const TQByteArray& aStr, DwEntity *entity )
2748 DwString dwSrc(aStr.data(), aStr.size());
2751 switch ( cte( entity ) )
2753 case DwMime::kCteBase64:
2754 DwEncodeBase64( dwSrc, dwResult );
2756 case DwMime::kCteQuotedPrintable:
2757 DwEncodeQuotedPrintable( dwSrc, dwResult );
2764 entity->Body().FromString( dwResult );
2765 entity->Body().Parse();
2767 mNeedsAssembly =
true;
2775 mNeedsAssembly =
true;
2779 mMsg->Body().FromString(aStr);
2780 mNeedsAssembly =
true;
2784 mMsg->Body().FromString(aStr);
2785 mNeedsAssembly =
true;
2791 mMsg->Body().Parse();
2792 mNeedsAssembly =
true;
2808 TQPtrList< DwBodyPart > parts;
2814 && part->hasHeaders()
2815 && part->Headers().HasContentType()
2816 && part->Body().FirstBodyPart()
2817 && (DwMime::kTypeMultipart == part->Headers().ContentType().Type()) )
2819 parts.append( part );
2820 part = part->Body().FirstBodyPart();
2826 while (part && !(part->Next()) && !(parts.isEmpty()))
2828 part = parts.getLast();
2832 if (part && part->Body().Message() &&
2833 part->Body().Message()->Body().FirstBodyPart())
2835 part = part->Body().Message()->Body().FirstBodyPart();
2837 part = part->Next();
2848 return mMsg->Body().FirstBodyPart();
2855 DwBodyPart *curpart;
2856 TQPtrList< DwBodyPart > parts;
2863 while (curpart && !idx) {
2866 && curpart->hasHeaders()
2867 && curpart->Headers().HasContentType()
2868 && curpart->Body().FirstBodyPart()
2869 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2871 parts.append( curpart );
2872 curpart = curpart->Body().FirstBodyPart();
2875 if (curpart == aDwBodyPart)
2880 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2882 curpart = parts.getLast();
2886 curpart = curpart->Next();
2895 DwBodyPart *part, *curpart;
2896 TQPtrList< DwBodyPart > parts;
2903 while (curpart && !part) {
2906 && curpart->hasHeaders()
2907 && curpart->Headers().HasContentType()
2908 && curpart->Body().FirstBodyPart()
2909 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) )
2911 parts.append( curpart );
2912 curpart = curpart->Body().FirstBodyPart();
2920 while (curpart && !(curpart->Next()) && !(parts.isEmpty()))
2922 curpart = parts.getLast();
2926 curpart = curpart->Next();
2935 DwBodyPart *part, *curpart;
2936 TQPtrList< DwBodyPart > parts;
2942 while (curpart && !part) {
2945 && curpart->hasHeaders()
2946 && curpart->Headers().HasContentType()
2947 && curpart->Body().FirstBodyPart()
2948 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
2949 parts.append( curpart );
2950 curpart = curpart->Body().FirstBodyPart();
2956 if ( curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
2957 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
2958 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
2962 curpart->hasHeaders() &&
2963 curpart->Headers().HasContentType() &&
2964 curpart->Headers().ContentType().Type() == type &&
2965 curpart->Headers().ContentType().Subtype() == subtype) {
2970 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
2971 curpart = parts.getLast();
2975 curpart = curpart->Next();
2984 DwBodyPart *part, *curpart;
2985 TQPtrList< DwBodyPart > parts;
2991 while (curpart && !part) {
2994 && curpart->hasHeaders()
2995 && curpart->Headers().HasContentType()
2996 && curpart->Body().FirstBodyPart()
2997 && (DwMime::kTypeMultipart == curpart->Headers().ContentType().Type()) ) {
2998 parts.append( curpart );
2999 curpart = curpart->Body().FirstBodyPart();
3005 if (curpart && curpart->hasHeaders() && curpart->Headers().HasContentType() ) {
3006 kdDebug(5006) << curpart->Headers().ContentType().TypeStr().c_str()
3007 <<
" " << curpart->Headers().ContentType().SubtypeStr().c_str() << endl;
3011 curpart->hasHeaders() &&
3012 curpart->Headers().HasContentType() &&
3013 curpart->Headers().ContentType().TypeStr().c_str() == type &&
3014 curpart->Headers().ContentType().SubtypeStr().c_str() == subtype) {
3019 while (curpart && !(curpart->Next()) && !(parts.isEmpty())) {
3020 curpart = parts.getLast();
3024 curpart = curpart->Next();
3031 void applyHeadersToMessagePart( DwHeaders& headers, KMMessagePart* aPart )
3043 TQCString additionalCTypeParams;
3044 if (headers.HasContentType())
3046 DwMediaType& ct = headers.ContentType();
3047 aPart->setOriginalContentTypeStr( ct.AsString().c_str() );
3048 aPart->setTypeStr(ct.TypeStr().c_str());
3049 aPart->setSubtypeStr(ct.SubtypeStr().c_str());
3050 DwParameter *param = ct.FirstParameter();
3053 if (!qstricmp(param->Attribute().c_str(),
"charset"))
3054 aPart->setCharset(TQCString(param->Value().c_str()).lower());
3055 else if (!qstrnicmp(param->Attribute().c_str(),
"name*", 5))
3056 aPart->setName(KMMsgBase::decodeRFC2231String(KMMsgBase::extractRFC2231HeaderField( param->Value().c_str(),
"name" )));
3058 additionalCTypeParams +=
';';
3059 additionalCTypeParams += param->AsString().c_str();
3061 param=param->Next();
3066 aPart->setTypeStr(
"text");
3067 aPart->setSubtypeStr(
"plain");
3069 aPart->setAdditionalCTypeParamStr( additionalCTypeParams );
3071 if (aPart->name().isEmpty())
3073 if (headers.HasContentType() && !headers.ContentType().Name().empty()) {
3074 aPart->setName(KMMsgBase::decodeRFC2047String(headers.
3075 ContentType().Name().c_str()) );
3076 }
else if (headers.HasSubject() && !headers.Subject().AsString().empty()) {
3077 aPart->setName( KMMsgBase::decodeRFC2047String(headers.
3078 Subject().AsString().c_str()) );
3083 if (headers.HasContentTransferEncoding())
3084 aPart->setCteStr(headers.ContentTransferEncoding().AsString().c_str());
3086 aPart->setCteStr(
"7bit");
3089 if (headers.HasContentDescription())
3090 aPart->setContentDescription( KMMsgBase::decodeRFC2047String(
3091 headers.ContentDescription().AsString().c_str() ) );
3093 aPart->setContentDescription(
"");
3096 if (headers.HasContentDisposition())
3097 aPart->setContentDisposition(headers.ContentDisposition().AsString().c_str());
3099 aPart->setContentDisposition(
"");
3111 if( aDwBodyPart && aDwBodyPart->hasHeaders() ) {
3116 TQString partId( aDwBodyPart->partId() );
3117 aPart->setPartSpecifier( partId );
3119 DwHeaders& headers = aDwBodyPart->Headers();
3120 applyHeadersToMessagePart( headers, aPart );
3124 aPart->setBody( aDwBodyPart->Body().AsString() );
3126 aPart->setBody( TQCString(
"") );
3129 if ( headers.HasContentId() ) {
3130 const TQCString contentId = headers.ContentId().AsString().c_str();
3132 aPart->setContentId( contentId.mid( 1, contentId.length() - 2 ) );
3139 aPart->setTypeStr(
"");
3140 aPart->setSubtypeStr(
"");
3141 aPart->setCteStr(
"");
3145 aPart->setContentDescription(
"");
3146 aPart->setContentDisposition(
"");
3147 aPart->setBody(TQCString(
""));
3148 aPart->setContentId(
"");
3160 if ( DwBodyPart *part =
dwBodyPart( aIdx ) ) {
3162 if( aPart->name().isEmpty() )
3163 aPart->setName( i18n(
"Attachment: %1").arg( aIdx ) );
3171 mMsg->Body().DeleteBodyParts();
3179 DwBodyPart *dwpart = findPart( partIndex );
3183 if ( !part.isComplete() )
3186 DwBody *parentNode =
dynamic_cast<DwBody*
>( dwpart->Parent() );
3189 parentNode->RemoveBodyPart( dwpart );
3192 KMMessagePart dummyPart;
3193 dummyPart.duplicate( part );
3194 TQString comment = i18n(
"This attachment has been deleted.");
3195 if ( !part.fileName().isEmpty() )
3196 comment = i18n(
"The attachment '%1' has been deleted." ).arg( part.fileName() );
3197 dummyPart.setContentDescription( comment );
3198 dummyPart.setBodyEncodedBinary( TQByteArray() );
3199 TQCString cd = dummyPart.contentDisposition();
3200 if ( cd.find(
"inline", 0,
false ) == 0 ) {
3201 cd.replace( 0, 10,
"attachment" );
3202 dummyPart.setContentDisposition( cd );
3203 }
else if ( cd.isEmpty() ) {
3204 dummyPart.setContentDisposition(
"attachment" );
3207 parentNode->AddBodyPart( newDwPart );
3208 getTopLevelPart()->Assemble();
3215 DwBodyPart* part = DwBodyPart::NewBodyPart(emptyString, 0);
3220 TQCString
charset = aPart->charset();
3221 TQCString type = aPart->typeStr();
3222 TQCString subtype = aPart->subtypeStr();
3223 TQCString cte = aPart->cteStr();
3224 TQCString contDesc = aPart->contentDescriptionEncoded();
3225 TQCString contDisp = aPart->contentDisposition();
3226 TQCString name = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->name(),
charset );
3227 bool RFC2231encoded = aPart->name() != TQString(name);
3228 TQCString paramAttr = aPart->parameterAttribute();
3230 DwHeaders& headers = part->Headers();
3232 DwMediaType& ct = headers.ContentType();
3233 if (!type.isEmpty() && !subtype.isEmpty())
3235 ct.SetTypeStr(type.data());
3236 ct.SetSubtypeStr(subtype.data());
3237 if (!charset.isEmpty()){
3239 param=
new DwParameter;
3240 param->SetAttribute(
"charset");
3241 param->SetValue(charset.data());
3242 ct.AddParameter(param);
3246 TQCString additionalParam = aPart->additionalCTypeParamStr();
3247 if( !additionalParam.isEmpty() )
3250 DwString parA, parV;
3252 iL = additionalParam.length();
3254 i2 = additionalParam.find(
';', i1,
false);
3260 parAV = additionalParam.mid( i1, (i2-i1) );
3261 iM = parAV.find(
'=');
3264 parA = parAV.left( iM ).data();
3265 parV = parAV.right( parAV.length() - iM - 1 ).data();
3266 if( (
'"' == parV.at(0)) && (
'"' == parV.at(parV.length()-1)) )
3269 parV.erase( parV.length()-1 );
3274 parA = parAV.data();
3278 param =
new DwParameter;
3279 param->SetAttribute( parA );
3280 param->SetValue( parV );
3281 ct.AddParameter( param );
3284 i2 = additionalParam.find(
';', i1,
false);
3288 if ( !name.isEmpty() ) {
3291 DwParameter *nameParam;
3292 nameParam =
new DwParameter;
3293 nameParam->SetAttribute(
"name*");
3294 nameParam->SetValue(name.data(),
true);
3295 ct.AddParameter(nameParam);
3297 ct.SetName(name.data());
3301 if (!paramAttr.isEmpty())
3303 TQCString paramValue;
3304 paramValue = KMMsgBase::encodeRFC2231StringAutoDetectCharset( aPart->parameterValue(),
charset );
3305 DwParameter *param =
new DwParameter;
3306 if (aPart->parameterValue() != TQString(paramValue))
3308 param->SetAttribute((paramAttr +
'*').data());
3309 param->SetValue(paramValue.data(),
true);
3311 param->SetAttribute(paramAttr.data());
3312 param->SetValue(paramValue.data());
3314 ct.AddParameter(param);
3318 headers.Cte().FromString(cte);
3320 if (!contDesc.isEmpty())
3321 headers.ContentDescription().FromString(contDesc);
3323 if (!contDisp.isEmpty())
3324 headers.ContentDisposition().FromString(contDisp);
3326 const DwString bodyStr = aPart->dwBody();
3327 if (!bodyStr.empty())
3328 part->Body().FromString(bodyStr);
3330 part->Body().FromString(
"");
3332 if (!aPart->partSpecifier().isNull())
3333 part->SetPartId( aPart->partSpecifier().latin1() );
3335 if (aPart->decodedSize() > 0)
3336 part->SetBodySize( aPart->decodedSize() );
3345 mMsg->Body().AddBodyPart( aDwPart );
3346 mNeedsAssembly =
true;
3361 TQDateTime datetime = TQDateTime::currentDateTime();
3364 msgIdStr =
'<' + datetime.toString(
"yyyyMMddhhmm.sszzz" );
3366 TQString msgIdSuffix;
3367 KConfigGroup general( KMKernel::config(),
"General" );
3369 if( general.readBoolEntry(
"useCustomMessageIdSuffix",
false ) )
3370 msgIdSuffix = general.readEntry(
"myMessageIdSuffix" );
3372 if( !msgIdSuffix.isEmpty() )
3373 msgIdStr +=
'@' + msgIdSuffix;
3375 msgIdStr +=
'.' + KPIM::encodeIDN( addr );
3386 TQCString result( 1 + 6*(src.size()-1) );
3388 TQCString::ConstIterator s = src.begin();
3389 TQCString::Iterator d = result.begin();
3452 result.truncate( d - result.begin() );
3460 result = TQString::fromLatin1( KMMsgBase::encodeRFC2047String( str,
3462 result = KURL::encode_string( result );
3471 result = KURL::decode_string( url );
3472 result = KMMsgBase::decodeRFC2047String( result.latin1() );
3482 if ( aStr.isEmpty() )
3493 TQCString angleAddress;
3494 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3495 bool inQuotedString =
false;
3496 int commentLevel = 0;
3498 for (
const char* p = aStr.data(); *p; ++p ) {
3499 switch ( context ) {
3502 case '"' : inQuotedString = !inQuotedString;
3504 case '(' :
if ( !inQuotedString ) {
3505 context = InComment;
3511 case '<' :
if ( !inQuotedString ) {
3512 context = InAngleAddress;
3522 case ',' :
if ( !inQuotedString ) {
3524 if ( !result.isEmpty() )
3526 name = name.stripWhiteSpace();
3527 comment = comment.stripWhiteSpace();
3528 angleAddress = angleAddress.stripWhiteSpace();
3537 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3542 else if ( !name.isEmpty() ) {
3545 else if ( !comment.isEmpty() ) {
3548 else if ( !angleAddress.isEmpty() ) {
3549 result += angleAddress;
3552 comment = TQCString();
3553 angleAddress = TQCString();
3558 default : name += *p;
3564 case '(' : ++commentLevel;
3567 case ')' : --commentLevel;
3568 if ( commentLevel == 0 ) {
3580 default : comment += *p;
3584 case InAngleAddress : {
3586 case '"' : inQuotedString = !inQuotedString;
3589 case '>' :
if ( !inQuotedString ) {
3600 default : angleAddress += *p;
3606 if ( !result.isEmpty() )
3608 name = name.stripWhiteSpace();
3609 comment = comment.stripWhiteSpace();
3610 angleAddress = angleAddress.stripWhiteSpace();
3616 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3621 else if ( !name.isEmpty() ) {
3624 else if ( !comment.isEmpty() ) {
3627 else if ( !angleAddress.isEmpty() ) {
3628 result += angleAddress;
3641 if ( aStr.isEmpty() )
3652 TQString angleAddress;
3653 enum { TopLevel, InComment, InAngleAddress } context = TopLevel;
3654 bool inQuotedString =
false;
3655 int commentLevel = 0;
3658 unsigned int strLength(aStr.length());
3659 for ( uint index = 0; index < strLength; ++index ) {
3661 switch ( context ) {
3663 switch ( ch.latin1() ) {
3664 case '"' : inQuotedString = !inQuotedString;
3666 case '(' :
if ( !inQuotedString ) {
3667 context = InComment;
3673 case '<' :
if ( !inQuotedString ) {
3674 context = InAngleAddress;
3681 if ( index < aStr.length() )
3682 name += aStr[index];
3684 case ',' :
if ( !inQuotedString ) {
3686 if ( !result.isEmpty() )
3688 name = name.stripWhiteSpace();
3689 comment = comment.stripWhiteSpace();
3690 angleAddress = angleAddress.stripWhiteSpace();
3699 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3704 else if ( !name.isEmpty() ) {
3707 else if ( !comment.isEmpty() ) {
3710 else if ( !angleAddress.isEmpty() ) {
3711 result += angleAddress;
3714 comment = TQString();
3715 angleAddress = TQString();
3720 default : name += ch;
3725 switch ( ch.latin1() ) {
3726 case '(' : ++commentLevel;
3729 case ')' : --commentLevel;
3730 if ( commentLevel == 0 ) {
3739 if ( index < aStr.length() )
3740 comment += aStr[index];
3742 default : comment += ch;
3746 case InAngleAddress : {
3747 switch ( ch.latin1() ) {
3748 case '"' : inQuotedString = !inQuotedString;
3751 case '>' :
if ( !inQuotedString ) {
3759 if ( index < aStr.length() )
3760 angleAddress += aStr[index];
3762 default : angleAddress += ch;
3768 if ( !result.isEmpty() )
3770 name = name.stripWhiteSpace();
3771 comment = comment.stripWhiteSpace();
3772 angleAddress = angleAddress.stripWhiteSpace();
3778 if ( angleAddress.isEmpty() && !comment.isEmpty() ) {
3783 else if ( !name.isEmpty() ) {
3786 else if ( !comment.isEmpty() ) {
3789 else if ( !angleAddress.isEmpty() ) {
3790 result += angleAddress;
3803 unsigned int strLength(str.length());
3804 result.reserve( 6*strLength );
3805 for(
unsigned int i = 0; i < strLength; ++i )
3806 switch ( str[i].latin1() ) {
3820 if ( !removeLineBreaks )
3837 if( aEmail.isEmpty() )
3840 TQStringList addressList = KPIM::splitEmailAddrList( aEmail );
3843 for( TQStringList::ConstIterator it = addressList.begin();
3844 ( it != addressList.end() );
3846 if( !(*it).isEmpty() ) {
3849 TQString name, mail;
3850 KPIM::getNameAndMail( *it, name, mail );
3852 TQString prettyStripped;
3853 if ( name.stripWhiteSpace().isEmpty() ) {
3855 prettyStripped = mail;
3857 pretty = KPIM::quoteNameIfNecessary( name ) +
" <" + mail +
">";
3858 prettyStripped = name;
3862 result +=
"<a href=\"mailto:"
3864 +
"\" "+cssStyle+
">";
3880 result.truncate( result.length() - 2 );
3890 const TQStringList& list )
3892 TQStringList addresses( list );
3893 TQString addrSpec( KPIM::getEmailAddress( address ) );
3894 for ( TQStringList::Iterator it = addresses.begin();
3895 it != addresses.end(); ) {
3896 if ( kasciistricmp( addrSpec.utf8().data(),
3897 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 ) {
3898 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3900 it = addresses.remove( it );
3913 TQStringList addresses = list;
3914 for( TQStringList::Iterator it = addresses.begin();
3915 it != addresses.end(); ) {
3916 kdDebug(5006) <<
"Check whether " << *it <<
" is one of my addresses"
3918 if( kmkernel->identityManager()->thatIsMe( KPIM::getEmailAddress( *it ) ) ) {
3919 kdDebug(5006) <<
"Removing " << *it <<
" from the address list"
3921 it = addresses.remove( it );
3933 const TQStringList& addresses )
3935 TQString addrSpec = KPIM::getEmailAddress( address );
3936 for( TQStringList::ConstIterator it = addresses.begin();
3937 it != addresses.end(); ++it ) {
3938 if ( kasciistricmp( addrSpec.utf8().data(),
3939 KPIM::getEmailAddress( *it ).utf8().data() ) == 0 )
3950 if ( recipients.isEmpty() )
3953 TQStringList recipientList = KPIM::splitEmailAddrList( recipients );
3955 TQString expandedRecipients;
3956 for ( TQStringList::Iterator it = recipientList.begin();
3957 it != recipientList.end(); ++it ) {
3958 if ( !expandedRecipients.isEmpty() )
3959 expandedRecipients +=
", ";
3960 TQString receiver = (*it).stripWhiteSpace();
3963 TQString expandedList = KAddrBookExternal::expandDistributionList( receiver );
3964 if ( !expandedList.isEmpty() ) {
3965 expandedRecipients += expandedList;
3970 TQString expandedNickName = KabcBridge::expandNickName( receiver );
3971 if ( !expandedNickName.isEmpty() ) {
3972 expandedRecipients += expandedNickName;
3978 if ( receiver.find(
'@') == -1 ) {
3979 KConfigGroup general( KMKernel::config(),
"General" );
3980 TQString defaultdomain = general.readEntry(
"Default domain" );
3981 if( !defaultdomain.isEmpty() ) {
3982 expandedRecipients += receiver +
"@" + defaultdomain;
3989 expandedRecipients += receiver;
3992 return expandedRecipients;
4000 if ( loginName.isEmpty() )
4003 char hostnameC[256];
4005 hostnameC[255] =
'\0';
4007 if ( gethostname( hostnameC, 255 ) )
4008 hostnameC[0] =
'\0';
4009 TQString address = loginName;
4011 address += TQString::fromLocal8Bit( hostnameC );
4014 const KUser user( loginName );
4015 if ( user.isValid() ) {
4016 TQString fullName = user.fullName();
4017 if ( fullName.find( TQRegExp(
"[^ 0-9A-Za-z\\x0080-\\xFFFF]" ) ) != -1 )
4018 address =
'"' + fullName.replace(
'\\',
"\\" ).replace(
'"',
"\\" )
4019 +
"\" <" + address +
'>';
4021 address = fullName +
" <" + address +
'>';
4032 KConfig *config=KMKernel::config();
4033 KConfigGroupSaver saver(config,
"General");
4035 config->setGroup(
"General");
4037 int languageNr = config->readNumEntry(
"reply-current-language",0);
4040 KConfigGroupSaver saver(config, TQString(
"KMMessage #%1").arg(languageNr));
4041 sReplyLanguage = config->readEntry(
"language",KGlobal::locale()->language());
4042 sReplyStr = config->readEntry(
"phrase-reply",
4043 i18n(
"On %D, you wrote:"));
4044 sReplyAllStr = config->readEntry(
"phrase-reply-all",
4045 i18n(
"On %D, %F wrote:"));
4046 sForwardStr = config->readEntry(
"phrase-forward",
4047 i18n(
"Forwarded Message"));
4048 sIndentPrefixStr = config->readEntry(
"indent-prefix",
">%_");
4052 KConfigGroupSaver saver(config,
"Composer");
4053 sSmartQuote = GlobalSettings::self()->smartQuote();
4054 sWordWrap = GlobalSettings::self()->wordWrap();
4055 sWrapCol = GlobalSettings::self()->lineWrapWidth();
4056 if ((sWrapCol == 0) || (sWrapCol > 78))
4061 sPrefCharsets = config->readListEntry(
"pref-charsets");
4065 KConfigGroupSaver saver(config,
"Reader");
4066 sHeaderStrategy = HeaderStrategy::create( config->readEntry(
"header-set-displayed",
"rich" ) );
4074 if (!sPrefCharsets.isEmpty())
4075 retval = sPrefCharsets[0].latin1();
4077 if (retval.isEmpty() || (retval ==
"locale")) {
4078 retval = TQCString(kmkernel->networkCodec()->mimeName());
4079 KPIM::kAsciiToLower( retval.data() );
4082 if (retval ==
"jisx0208.1983-0") retval =
"iso-2022-jp";
4083 else if (retval ==
"ksc5601.1987-0") retval =
"euc-kr";
4089 return sPrefCharsets;
4095 if ( mMsg->Headers().HasContentType() ) {
4096 DwMediaType &mType=mMsg->Headers().ContentType();
4098 DwParameter *param=mType.FirstParameter();
4100 if (!kasciistricmp(param->Attribute().c_str(),
"charset"))
4101 return param->Value().c_str();
4102 else param=param->Next();
4111 kdWarning( type() != DwMime::kTypeText )
4112 <<
"KMMessage::setCharset(): trying to set a charset for a non-textual mimetype." << endl
4113 <<
"Fix this caller:" << endl
4114 <<
"====================================================================" << endl
4115 << kdBacktrace( 5 ) << endl
4116 <<
"====================================================================" << endl;
4121 DwMediaType &mType = entity->Headers().ContentType();
4123 DwParameter *param = mType.FirstParameter();
4127 if ( !kasciistricmp( param->Attribute().c_str(),
"charset" ) )
4130 param = param->Next();
4133 param =
new DwParameter;
4134 param->SetAttribute(
"charset" );
4135 mType.AddParameter( param );
4138 mType.SetModified();
4140 TQCString lowerCharset =
charset;
4141 KPIM::kAsciiToLower( lowerCharset.data() );
4142 param->SetValue( DwString( lowerCharset ) );
4150 if (mStatus == aStatus)
4157 if( mEncryptionState == s )
4159 mEncryptionState = s;
4166 if( mSignatureState == s )
4168 mSignatureState = s;
4173 void KMMessage::setMDNSentState( KMMsgMDNSentState status,
int idx )
4175 if ( mMDNSentState == status )
4178 status = KMMsgMDNStateUnknown;
4181 KMMsgBase::setMDNSentState( status, idx );
4187 Q_ASSERT( aStatus == KMMsgStatusReplied
4188 || aStatus == KMMsgStatusForwarded
4189 || aStatus == KMMsgStatusDeleted );
4191 TQString message =
headerField(
"X-KMail-Link-Message" );
4192 if ( !message.isEmpty() )
4194 TQString type =
headerField(
"X-KMail-Link-Type" );
4195 if ( !type.isEmpty() )
4198 message += TQString::number( aMsg->getMsgSerNum() );
4199 if ( aStatus == KMMsgStatusReplied )
4201 else if ( aStatus == KMMsgStatusForwarded )
4203 else if ( aStatus == KMMsgStatusDeleted )
4214 *reStatus = KMMsgStatusUnknown;
4216 TQString message =
headerField(
"X-KMail-Link-Message");
4218 message = message.section(
',', n, n);
4219 type = type.section(
',', n, n);
4221 if ( !message.isEmpty() && !type.isEmpty() ) {
4222 *retMsgSerNum = message.toULong();
4223 if ( type ==
"reply" )
4224 *reStatus = KMMsgStatusReplied;
4225 else if ( type ==
"forward" )
4226 *reStatus = KMMsgStatusForwarded;
4227 else if ( type ==
"deleted" )
4228 *reStatus = KMMsgStatusDeleted;
4235 if ( !part )
return 0;
4236 DwBodyPart* current;
4238 if ( part->partId() == partSpecifier )
4242 if ( part->hasHeaders() &&
4243 part->Headers().HasContentType() &&
4244 part->Body().FirstBodyPart() &&
4245 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) &&
4246 (current =
findDwBodyPart( part->Body().FirstBodyPart(), partSpecifier )) )
4252 if ( part->Body().Message() &&
4253 part->Body().Message()->Body().FirstBodyPart() &&
4254 (current =
findDwBodyPart( part->Body().Message()->Body().FirstBodyPart(),
4267 if ( !data.data() || !data.size() )
4270 DwString content( data.data(), data.size() );
4272 partSpecifier !=
"0" &&
4273 partSpecifier !=
"TEXT" )
4275 TQString specifier = partSpecifier;
4276 if ( partSpecifier.endsWith(
".HEADER") ||
4277 partSpecifier.endsWith(
".MIME") ) {
4279 specifier = partSpecifier.section(
'.', 0, -2 );
4284 kdDebug(5006) <<
"KMMessage::updateBodyPart " << specifier << endl;
4287 kdWarning(5006) <<
"KMMessage::updateBodyPart - can not find part "
4288 << specifier << endl;
4291 if ( partSpecifier.endsWith(
".MIME") )
4295 content.resize( TQMAX( content.length(), 2 ) - 2 );
4298 mLastUpdated->Headers().DeleteAllFields();
4299 mLastUpdated->Headers().FromString( content );
4300 mLastUpdated->Headers().Parse();
4301 }
else if ( partSpecifier.endsWith(
".HEADER") )
4304 mLastUpdated->Body().Message()->Headers().FromString( content );
4305 mLastUpdated->Body().Message()->Headers().Parse();
4308 mLastUpdated->Body().FromString( content );
4309 TQString parentSpec = partSpecifier.section(
'.', 0, -2 );
4310 if ( !parentSpec.isEmpty() )
4313 if ( parent && parent->hasHeaders() && parent->Headers().HasContentType() )
4315 const DwMediaType& contentType = parent->Headers().ContentType();
4316 if ( contentType.Type() == DwMime::kTypeMessage &&
4317 contentType.Subtype() == DwMime::kSubtypeRfc822 )
4321 parent->Body().Message()->Body().FromString( content );
4330 if ( partSpecifier ==
"TEXT" )
4332 mMsg->Body().FromString( content );
4333 mMsg->Body().Parse();
4335 mNeedsAssembly =
true;
4336 if (! partSpecifier.endsWith(
".HEADER") )
4343 void KMMessage::updateInvitationState()
4345 if ( mMsg && mMsg->hasHeaders() && mMsg->Headers().HasContentType() ) {
4346 TQString cntType = mMsg->Headers().ContentType().TypeStr().c_str();
4348 cntType += mMsg->Headers().ContentType().SubtypeStr().c_str();
4349 if ( cntType.lower() ==
"text/calendar" ) {
4354 setStatus( KMMsgStatusHasNoInvitation );
4359 void KMMessage::updateAttachmentState( DwBodyPart* part )
4371 bool filenameEmpty =
true;
4372 if ( part->hasHeaders() ) {
4373 if ( part->Headers().HasContentDisposition() ) {
4374 DwDispositionType cd = part->Headers().ContentDisposition();
4375 filenameEmpty = cd.Filename().empty();
4376 if ( filenameEmpty ) {
4378 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField( cd.AsString().c_str(),
"filename" ) ).isEmpty();
4384 if ( filenameEmpty && part->Headers().HasContentType() ) {
4385 DwMediaType contentType = part->Headers().ContentType();
4386 filenameEmpty = contentType.Name().empty();
4387 if ( filenameEmpty ) {
4389 filenameEmpty = KMMsgBase::decodeRFC2231String( KMMsgBase::extractRFC2231HeaderField(
4390 contentType.AsString().c_str(),
"name" ) ).isEmpty();
4395 if ( part->hasHeaders() &&
4396 ( ( part->Headers().HasContentDisposition() &&
4397 !part->Headers().ContentDisposition().Filename().empty() ) ||
4398 ( part->Headers().HasContentType() &&
4399 !filenameEmpty ) ) )
4402 if ( !part->Headers().HasContentType() ||
4403 ( part->Headers().HasContentType() &&
4404 part->Headers().ContentType().Subtype() != DwMime::kSubtypePgpSignature &&
4405 part->Headers().ContentType().Subtype() != DwMime::kSubtypePkcs7Signature ) )
4413 if ( part->hasHeaders() &&
4414 part->Headers().HasContentType() &&
4415 part->Body().FirstBodyPart() &&
4416 (DwMime::kTypeMultipart == part->Headers().ContentType().Type() ) )
4418 updateAttachmentState( part->Body().FirstBodyPart() );
4422 if ( part->Body().Message() &&
4423 part->Body().Message()->Body().FirstBodyPart() )
4425 updateAttachmentState( part->Body().Message()->Body().FirstBodyPart() );
4430 updateAttachmentState( part->Next() );
4431 else if ( attachmentState() == KMMsgAttachmentUnknown )
4438 if ( encoding.isEmpty() )
4440 const TQTextCodec *
codec = KMMsgBase::codecForName( encoding );
4442 TQValueList<int> dummy;
4449 const TQTextCodec * c = mOverrideCodec;
4452 c = KMMsgBase::codecForName(
charset() );
4456 c = KMMsgBase::codecForName( GlobalSettings::self()->fallbackCharacterEncoding().latin1() );
4461 c = kmkernel->networkCodec();
4469 codec = this->
codec();
4478 TQCString str( KPIM::getFirstEmailAddress(
rawHeaderField(
"From") ) );
4479 if ( str.isEmpty() )
4480 str =
"unknown@unknown.invalid";
4482 if ( dateStr.isEmpty() ) {
4483 time_t t = ::time( 0 );
4484 dateStr = ctime( &t );
4485 const int len = dateStr.length();
4486 if ( dateStr[len-1] ==
'\n' )
4487 dateStr.truncate( len - 1 );
4489 return "From " + str +
" " + dateStr +
"\n";
4494 sPendingDeletes <<
this;
4497 DwBodyPart* KMMessage::findPart(
int index )
4500 return findPartInternal( getTopLevelPart(), index, accu );
4503 DwBodyPart* KMMessage::findPartInternal(DwEntity * root,
int index,
int & accu)
4508 DwBodyPart *current =
dynamic_cast<DwBodyPart*
>( root );
4509 if ( index == accu )
4512 if ( root->Body().FirstBodyPart() )
4513 rv = findPartInternal( root->Body().FirstBodyPart(), index, accu );
4514 if ( !rv && current && current->Next() )
4515 rv = findPartInternal( current->Next(), index, accu );
4516 if ( !rv && root->Body().Message() )
4517 rv = findPartInternal( root->Body().Message(), index, accu );