1 /* -*- mode: C++; c-file-style: "gnu" -*-
2 Copyright (C) 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
3 Copyright (c) 2009 Andras Mantia <andras@kdab.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "messagehelper.h"
21 #include "kdepim-version.h"
23 #include "messagecomposersettings.h"
25 #include "messagecore/mailinglist.h"
26 #include "messagecore/stringutil.h"
29 #include <KProtocolManager>
30 #include <KMime/Message>
31 #include <kmime/kmime_mdn.h>
32 #include <kmime/kmime_dateformatter.h>
33 #include <kmime/kmime_headers.h>
34 #include <kpimidentities/identitymanager.h>
35 #include <kpimidentities/identity.h>
36 #include <KPIMUtils/Email>
38 using namespace MessageCore
;
40 namespace MessageHelper
{
42 void initHeader( const KMime::Message::Ptr
&message
, const KPIMIdentities::IdentityManager
* identMan
, uint id
)
44 applyIdentity( message
, identMan
, id
);
45 message
->to()->clear();
46 message
->subject()->clear();
47 message
->date()->setDateTime( KDateTime::currentLocalDateTime() );
49 // user agent, e.g. KMail/1.9.50 (Windows/5.0; KDE/3.97.1; i686; svn-762186; 2008-01-15)
50 QStringList extraInfo
;
51 #if defined KDEPIM_GIT_REVISION_STRING && defined KDEPIM_GIT_LAST_CHANGE
52 extraInfo
<< QString::fromLocal8Bit(KDEPIM_GIT_REVISION_STRING
) << QString::fromLocal8Bit(KDEPIM_GIT_LAST_CHANGE
);
54 #error forgot to include kdepim-version.h
57 message
->userAgent()->fromUnicodeString( KProtocolManager::userAgentForApplication( QString::fromLocal8Bit("KMail"), QString::fromLocal8Bit(KDEPIM_GIT_REVISION_STRING
), extraInfo
), QLatin1String("utf-8").latin1() );
58 // This will allow to change Content-Type:
59 message
->contentType()->setMimeType( "text/plain" );
64 void initFromMessage( const KMime::Message::Ptr
&msg
, const KMime::Message::Ptr
&origMsg
,
65 KPIMIdentities::IdentityManager
* identMan
, uint id
, bool idHeaders
)
68 MessageHelper::initHeader( msg
, identMan
, id
);
70 KMime::Headers::Generic
*header
= new KMime::Headers::Generic( "X-KMail-Identity", msg
.get(),
71 QString::number( id
), "utf-8" );
72 msg
->setHeader( header
);
75 if ( origMsg
->headerByType("X-KMail-Transport") ) {
76 const QString transport
= origMsg
->headerByType("X-KMail-Transport")->asUnicodeString();
77 KMime::Headers::Generic
*header
= new KMime::Headers::Generic( "X-KMail-Transport", msg
.get(),
79 msg
->setHeader( header
);
84 void applyIdentity( const KMime::Message::Ptr
&message
, const KPIMIdentities::IdentityManager
* identMan
, uint id
)
86 const KPIMIdentities::Identity
& ident
=
87 identMan
->identityForUoidOrDefault( id
);
89 if ( ident
.fullEmailAddr().isEmpty() )
90 message
->from()->clear();
92 message
->from()->addAddress(ident
.primaryEmailAddress().toUtf8(), ident
.fullName());
94 if ( ident
.replyToAddr().isEmpty() )
95 message
->replyTo()->clear();
97 message
->replyTo()->addAddress(ident
.primaryEmailAddress().toUtf8(), ident
.fullName());
99 if ( ident
.bcc().isEmpty() )
100 message
->bcc()->clear();
102 const KMime::Types::Mailbox::List mailboxes
= MessageCore::StringUtil::mailboxListFromUnicodeString( ident
.bcc() );
103 foreach ( const KMime::Types::Mailbox
&mailbox
, mailboxes
)
104 message
->bcc()->addAddress( mailbox
);
107 if ( ident
.organization().isEmpty() )
108 message
->removeHeader("Organization");
110 KMime::Headers::Organization
* const organization
111 = new KMime::Headers::Organization( message
.get(), ident
.organization(), "utf-8" );
112 message
->setHeader( organization
);
115 if (ident
.isDefault())
116 message
->removeHeader("X-KMail-Identity");
118 KMime::Headers::Generic
*header
= new KMime::Headers::Generic( "X-KMail-Identity", message
.get(), QString::number( ident
.uoid() ), "utf-8" );
119 message
->setHeader( header
);
122 if (ident
.transport().isEmpty())
123 message
->removeHeader("X-KMail-Transport");
125 KMime::Headers::Generic
*header
= new KMime::Headers::Generic( "X-KMail-Transport", message
.get(), ident
.transport(), "utf-8" );
126 message
->setHeader( header
);
129 if (ident
.fcc().isEmpty())
130 message
->removeHeader("X-KMail-Fcc");
132 KMime::Headers::Generic
*header
= new KMime::Headers::Generic( "X-KMail-Fcc", message
.get(), ident
.fcc(), "utf-8" );
133 message
->setHeader( header
);
136 if (ident
.drafts().isEmpty())
137 message
->removeHeader("X-KMail-Drafts");
139 KMime::Headers::Generic
*header
= new KMime::Headers::Generic( "X-KMail-Drafts", message
.get(), ident
.drafts(), "utf-8" );
140 message
->setHeader( header
);
143 if (ident
.templates().isEmpty())
144 message
->removeHeader("X-KMail-Templates");
146 KMime::Headers::Generic
*header
= new KMime::Headers::Generic( "X-KMail-Templates", message
.get(), ident
.templates(), "utf-8" );
147 message
->setHeader( header
);
151 KMime::Types::AddrSpecList
extractAddrSpecs( const KMime::Message::Ptr
&msg
, const QByteArray
& header
)
153 KMime::Types::AddrSpecList result
;
154 if ( !msg
->headerByType( header
) )
157 KMime::Types::AddressList al
=
158 MessageCore::StringUtil::splitAddressField( msg
->headerByType( header
)->asUnicodeString().toUtf8() );
159 KMime::Types::AddressList::const_iterator
alend( al
.constEnd() );
160 for ( KMime::Types::AddressList::const_iterator ait
= al
.constBegin() ; ait
!= alend
; ++ait
) {
161 KMime::Types::MailboxList::const_iterator
mitEnd( (*ait
).mailboxList
.constEnd() );
162 for ( KMime::Types::MailboxList::const_iterator mit
= (*ait
).mailboxList
.constBegin() ; mit
!= mitEnd
; ++mit
) {
163 result
.push_back( (*mit
).addrSpec() );
169 QString
cleanSubject( const KMime::Message::Ptr
&msg
)
171 return cleanSubject( msg
, MessageComposer::MessageComposerSettings::self()->replyPrefixes() + MessageComposer::MessageComposerSettings::self()->forwardPrefixes(),
172 true, QString() ).trimmed();
175 QString
cleanSubject( const KMime::Message::Ptr
&msg
, const QStringList
& prefixRegExps
,
176 bool replace
, const QString
& newPrefix
)
178 return replacePrefixes( msg
->subject()->asUnicodeString(), prefixRegExps
, replace
,
182 QString
forwardSubject( const KMime::Message::Ptr
&msg
)
184 return cleanSubject( msg
, MessageComposer::MessageComposerSettings::self()->forwardPrefixes(),
185 MessageComposer::MessageComposerSettings::self()->replaceForwardPrefix(), QString::fromLatin1("Fwd:") );
188 QString
replySubject( const KMime::Message::Ptr
&msg
)
190 return cleanSubject( msg
, MessageComposer::MessageComposerSettings::self()->replyPrefixes(),
191 MessageComposer::MessageComposerSettings::self()->replaceReplyPrefix(), QString::fromLatin1("Re:") );
194 QString
replacePrefixes( const QString
& str
, const QStringList
&prefixRegExps
,
195 bool replace
, const QString
&newPrefix
)
197 bool recognized
= false;
198 // construct a big regexp that
199 // 1. is anchored to the beginning of str (sans whitespace)
200 // 2. matches at least one of the part regexps in prefixRegExps
201 QString bigRegExp
= QString::fromLatin1("^(?:\\s+|(?:%1))+\\s*")
202 .arg( prefixRegExps
.join(QString::fromLatin1(")|(?:")) );
203 QRegExp
rx( bigRegExp
, Qt::CaseInsensitive
);
204 if ( rx
.isValid() ) {
206 if ( rx
.indexIn( tmp
) == 0 ) {
209 return tmp
.replace( 0, rx
.matchedLength(), newPrefix
+ QString::fromLatin1( " " ) );
212 kWarning() << "bigRegExp = \""
213 << bigRegExp
<< "\"\n"
214 << "prefix regexp is invalid!";
215 // try good ole Re/Fwd:
216 recognized
= str
.startsWith( newPrefix
);
220 return newPrefix
+ QString::fromLatin1(" ") + str
;
226 void setAutomaticFields(const KMime::Message::Ptr
&msg
, bool aIsMulti
)
228 msg
->setHeader( new KMime::Headers::Generic( "MIME-Version", msg
.get(), QLatin1String("1.0"), QLatin1String("utf-8").latin1() ) );
230 if (aIsMulti
|| msg
->contents().size() > 1)
232 // Set the type to 'Multipart' and the subtype to 'Mixed'
233 msg
->contentType()->setMimeType( "multipart/mixed" );
234 // Create a random printable string and set it as the boundary parameter
235 msg
->contentType()->setBoundary( KMime::multiPartBoundary() );
239 QString
ccStrip( const KMime::Message::Ptr
&msg
)
241 return MessageCore::StringUtil::stripEmailAddr( msg
->cc()->asUnicodeString() );
244 QString
toStrip( const KMime::Message::Ptr
&msg
)
246 return MessageCore::StringUtil::stripEmailAddr( msg
->to()->asUnicodeString() );
249 QString
fromStrip( const KMime::Message::Ptr
&msg
)
251 return MessageCore::StringUtil::stripEmailAddr( msg
->from()->asUnicodeString() );
255 QString
stripOffPrefixes( const QString
& str
)
257 return replacePrefixes( str
, MessageComposer::MessageComposerSettings::self()->replyPrefixes() + MessageComposer::MessageComposerSettings::self()->forwardPrefixes(),
258 true, QString() ).trimmed();
261 QString
skipKeyword( const QString
& aStr
, QChar sepChar
,
266 while (str
[0] == QChar::fromLatin1(' ')) str
.remove(0,1);
267 if (hasKeyword
) *hasKeyword
=false;
269 unsigned int i
= 0, maxChars
= 3;
270 unsigned int strLength(str
.length());
271 for (i
=0; i
< strLength
&& i
< maxChars
; i
++)
273 if (str
[i
] < QChar::fromLatin1('A') || str
[i
] == sepChar
) break;
276 if (str
[i
] == sepChar
) // skip following spaces too
280 } while (str
[i
] == QChar::fromLatin1(' '));
281 if (hasKeyword
) *hasKeyword
=true;