1/*
2 Copyright (c) 2002-2004 Marc Mutz <mutz@kde.org>
3 Copyright (c) 2007 Tom Albers <tomalbers@kde.nl>
4
5 This library is free software; you can redistribute it and/or modify it
6 under the terms of the GNU Library General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or (at your
8 option) any later version.
9
10 This library is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301, USA.
19*/
20
21#include "identity.h"
22#include "signature.h"
23
24#include <sonnet/globals.h>
25#include <kdebug.h>
26#include <kconfiggroup.h>
27#include <kpimutils/email.h>
28
29#include <QMimeData>
30#include <QByteArray>
31#include <QHostInfo>
32
33using namespace KPIMIdentities;
34
35// TODO: should use a kstaticdeleter?
36static Identity *identityNull = 0;
37
38Identity::Identity( const QString &id, const QString &fullName,
39 const QString &emailAddr, const QString &organization,
40 const QString &replyToAddr )
41 : mIsDefault( false )
42{
43 setProperty( QLatin1String(s_uoid), 0 );
44 setProperty( QLatin1String(s_identity), id );
45 setProperty( QLatin1String(s_name), fullName );
46 setProperty( QLatin1String(s_email), emailAddr );
47 setProperty( QLatin1String(s_organization), organization );
48 setProperty( QLatin1String(s_replyto), replyToAddr );
49 setDictionary( Sonnet::defaultLanguageName() );
50 setProperty( QLatin1String(s_disabledFcc), false );
51 setProperty( QLatin1String(s_defaultDomainName), QHostInfo::localHostName());
52}
53
54Identity::~Identity()
55{}
56
57const Identity &Identity::null()
58{
59 if ( !identityNull ) {
60 identityNull = new Identity;
61 }
62 return *identityNull;
63}
64
65bool Identity::isNull() const
66{
67 bool empty = true;
68 QHash<QString, QVariant>::const_iterator i = mPropertiesMap.constBegin();
69 while ( i != mPropertiesMap.constEnd() ) {
70 // Take into account that the defaultDomainName for a null identity is not empty
71 if ( i.key() == QLatin1String(s_defaultDomainName) ) {
72 ++i;
73 continue;
74 }
75 // Take into account that the dictionary for a null identity is not empty
76 if ( i.key() == QLatin1String(s_dict) ) {
77 ++i;
78 continue;
79 }
80 // Take into account that disableFcc == false for a null identity
81 if( i.key() == QLatin1String(s_disabledFcc) && i.value().toBool() == false ) {
82 ++i;
83 continue;
84 }
85 // The uoid is 0 by default, so ignore this
86 if ( !( i.key() == QLatin1String(s_uoid) && i.value().toUInt() == 0 ) ) {
87 if ( !i.value().isNull() ||
88 ( i.value().type() == QVariant::String && !i.value().toString().isEmpty() ) ) {
89 empty = false;
90 }
91 }
92 ++i;
93 }
94 return empty;
95}
96
97void Identity::readConfig( const KConfigGroup &config )
98{
99 // get all keys and convert them to our QHash.
100 QMap<QString, QString> entries = config.entryMap();
101 QMap<QString, QString>::const_iterator i = entries.constBegin();
102 QMap<QString, QString>::const_iterator end = entries.constEnd();
103 while ( i != end ) {
104 if ( i.key() == QLatin1String(s_emailAliases) ) {
105 // HACK: Read s_emailAliases as a stringlist
106 mPropertiesMap.insert( i.key(), config.readEntry( i.key(), QStringList() ) );
107 } else {
108 mPropertiesMap.insert( i.key(), config.readEntry( i.key() ) );
109 }
110 ++i;
111 }
112 mSignature.readConfig( config );
113}
114
115void Identity::writeConfig( KConfigGroup &config ) const
116{
117 QHash<QString, QVariant>::const_iterator i = mPropertiesMap.constBegin();
118 QHash<QString, QVariant>::const_iterator end = mPropertiesMap.constEnd();
119 while ( i != end ) {
120 config.writeEntry( i.key(), i.value() );
121 kDebug( 5325 ) << "Store:" << i.key() << ":" << i.value();
122 ++i;
123 }
124 mSignature.writeConfig( config );
125}
126
127bool Identity::mailingAllowed() const
128{
129 return !property( QLatin1String(s_email) ).toString().isEmpty();
130}
131
132QString Identity::mimeDataType()
133{
134 return QLatin1String("application/x-kmail-identity-drag");
135}
136
137bool Identity::canDecode( const QMimeData*md )
138{
139 return md->hasFormat( mimeDataType() );
140}
141
142void Identity::populateMimeData( QMimeData*md )
143{
144 QByteArray a;
145 {
146 QDataStream s( &a, QIODevice::WriteOnly );
147 s << this;
148 }
149 md->setData( mimeDataType(), a );
150}
151
152Identity Identity::fromMimeData( const QMimeData*md )
153{
154 Identity i;
155 if ( canDecode( md ) ) {
156 QByteArray ba = md->data( mimeDataType() );
157 QDataStream s( &ba, QIODevice::ReadOnly );
158 s >> i;
159 }
160 return i;
161}
162
163// ------------------ Operators --------------------------//
164
165QDataStream &KPIMIdentities::operator<<
166( QDataStream &stream, const KPIMIdentities::Identity &i )
167{
168 return stream << static_cast<quint32>( i.uoid() )
169 << i.identityName()
170 << i.fullName()
171 << i.organization()
172 << i.pgpSigningKey()
173 << i.pgpEncryptionKey()
174 << i.smimeSigningKey()
175 << i.smimeEncryptionKey()
176 << i.primaryEmailAddress()
177 << i.emailAliases()
178 << i.replyToAddr()
179 << i.bcc()
180 << i.vCardFile()
181 << i.transport()
182 << i.fcc()
183 << i.drafts()
184 << i.templates()
185 << i.mPropertiesMap[QLatin1String(s_signature)]
186 << i.dictionary()
187 << i.xface()
188 << i.preferredCryptoMessageFormat()
189 << i.cc()
190 << i.attachVcard()
191 << i.autocorrectionLanguage()
192 << i.disabledFcc()
193 << i.pgpAutoSign()
194 << i.defaultDomainName();
195}
196
197QDataStream &KPIMIdentities::operator>>
198( QDataStream &stream, KPIMIdentities::Identity &i )
199{
200 quint32 uoid;
201 stream
202 >> uoid
203 >> i.mPropertiesMap[QLatin1String(s_identity)]
204 >> i.mPropertiesMap[QLatin1String(s_name)]
205 >> i.mPropertiesMap[QLatin1String(s_organization)]
206 >> i.mPropertiesMap[QLatin1String(s_pgps)]
207 >> i.mPropertiesMap[QLatin1String(s_pgpe)]
208 >> i.mPropertiesMap[QLatin1String(s_smimes)]
209 >> i.mPropertiesMap[QLatin1String(s_smimee)]
210 >> i.mPropertiesMap[QLatin1String(s_email)]
211 >> i.mPropertiesMap[QLatin1String(s_emailAliases)]
212 >> i.mPropertiesMap[QLatin1String(s_replyto)]
213 >> i.mPropertiesMap[QLatin1String(s_bcc)]
214 >> i.mPropertiesMap[QLatin1String(s_vcard)]
215 >> i.mPropertiesMap[QLatin1String(s_transport)]
216 >> i.mPropertiesMap[QLatin1String(s_fcc)]
217 >> i.mPropertiesMap[QLatin1String(s_drafts)]
218 >> i.mPropertiesMap[QLatin1String(s_templates)]
219 >> i.mPropertiesMap[QLatin1String(s_signature)]
220 >> i.mPropertiesMap[QLatin1String(s_dict)]
221 >> i.mPropertiesMap[QLatin1String(s_xface)]
222 >> i.mPropertiesMap[QLatin1String(s_prefcrypt)]
223 >> i.mPropertiesMap[QLatin1String(s_cc)]
224 >> i.mPropertiesMap[QLatin1String(s_attachVcard)]
225 >> i.mPropertiesMap[QLatin1String(s_autocorrectionLanguage)]
226 >> i.mPropertiesMap[QLatin1String(s_disabledFcc)]
227 >> i.mPropertiesMap[QLatin1String(s_pgpautosign)]
228 >> i.mPropertiesMap[QLatin1String(s_defaultDomainName)];
229
230 i.setProperty( QLatin1String(s_uoid), uoid );
231 return stream;
232}
233
234bool Identity::operator< ( const Identity &other ) const
235{
236 if ( isDefault() ) {
237 return true;
238 }
239 if ( other.isDefault() ) {
240 return false;
241 }
242 return identityName() < other.identityName();
243}
244
245bool Identity::operator> ( const Identity &other ) const
246{
247 if ( isDefault() ) {
248 return false;
249 }
250 if ( other.isDefault() ) {
251 return true;
252 }
253 return identityName() > other.identityName();
254}
255
256bool Identity::operator<= ( const Identity &other ) const
257{
258 return !operator> ( other );
259}
260
261bool Identity::operator>= ( const Identity &other ) const
262{
263 return !operator< ( other );
264}
265
266bool Identity::operator== ( const Identity &other ) const
267{
268 return mPropertiesMap == other.mPropertiesMap &&
269 mSignature == other.mSignature;
270}
271
272bool Identity::operator!= ( const Identity &other ) const
273{
274 return !operator== ( other );
275}
276
277// --------------------- Getters -----------------------------//
278
279QVariant Identity::property( const QString &key ) const
280{
281 return mPropertiesMap.value( key );
282}
283
284QString Identity::fullEmailAddr( void ) const
285{
286 const QString name = mPropertiesMap.value( QLatin1String(s_name) ).toString();
287 const QString mail = mPropertiesMap.value( QLatin1String(s_email) ).toString();
288
289 if ( name.isEmpty() ) {
290 return mail;
291 }
292
293 const QString specials( QLatin1String("()<>@,.;:[]") );
294
295 QString result;
296
297 // add DQUOTE's if necessary:
298 bool needsQuotes=false;
299 const int nameLength( name.length() );
300 for ( int i=0; i < nameLength; i++ ) {
301 if ( specials.contains( name[i] ) ) {
302 needsQuotes = true;
303 } else if ( name[i] == QLatin1Char('\\') || name[i] == QLatin1Char('"') ) {
304 needsQuotes = true;
305 result += QLatin1Char('\\');
306 }
307 result += name[i];
308 }
309
310 if ( needsQuotes ) {
311 result.insert( 0, QLatin1Char('"') );
312 result += QLatin1Char('"');
313 }
314
315 result += QLatin1String(" <") + mail + QLatin1Char('>');
316
317 return result;
318}
319
320QString Identity::identityName() const
321{
322 return property( QLatin1String( s_identity ) ).toString();
323}
324
325QString Identity::signatureText( bool *ok ) const
326{
327 return mSignature.withSeparator( ok );
328}
329
330bool Identity::signatureIsInlinedHtml() const
331{
332 return mSignature.isInlinedHtml();
333}
334
335bool Identity::isDefault() const
336{
337 return mIsDefault;
338}
339
340uint Identity::uoid() const
341{
342 return property( QLatin1String( s_uoid ) ).toInt();
343}
344
345QString Identity::fullName() const
346{
347 return property( QLatin1String( s_name ) ).toString();
348}
349
350QString Identity::organization() const
351{
352 return property( QLatin1String( s_organization ) ).toString();
353}
354
355QByteArray Identity::pgpEncryptionKey() const
356{
357 return property( QLatin1String( s_pgpe ) ).toByteArray();
358}
359
360QByteArray Identity::pgpSigningKey() const
361{
362 return property( QLatin1String( s_pgps ) ).toByteArray();
363}
364
365QByteArray Identity::smimeEncryptionKey() const
366{
367 return property( QLatin1String( s_smimee ) ).toByteArray();
368}
369
370QByteArray Identity::smimeSigningKey() const
371{
372 return property( QLatin1String( s_smimes ) ).toByteArray();
373}
374
375QString Identity::preferredCryptoMessageFormat() const
376{
377 return property( QLatin1String( s_prefcrypt ) ).toString();
378}
379
380QString Identity::emailAddr() const
381{
382 return primaryEmailAddress();
383}
384
385QString Identity::primaryEmailAddress() const
386{
387 return property( QLatin1String( s_email ) ).toString();
388}
389
390const QStringList Identity::emailAliases() const
391{
392 return property( QLatin1String( s_emailAliases ) ).toStringList();
393}
394
395QString Identity::vCardFile() const
396{
397 return property( QLatin1String( s_vcard ) ).toString();
398}
399
400bool Identity::attachVcard() const
401{
402 return property( QLatin1String( s_attachVcard ) ).toBool();
403}
404
405QString Identity::replyToAddr() const
406{
407 return property( QLatin1String( s_replyto ) ).toString();
408}
409
410QString Identity::bcc() const
411{
412 return property( QLatin1String( s_bcc ) ).toString();
413}
414
415QString Identity::cc() const
416{
417 return property( QLatin1String( s_cc ) ).toString();
418}
419
420Signature &Identity::signature()
421{
422 return mSignature;
423}
424
425bool Identity::isXFaceEnabled() const
426{
427 return property( QLatin1String( s_xfaceenabled ) ).toBool();
428}
429
430QString Identity::xface() const
431{
432 return property( QLatin1String( s_xface ) ).toString();
433}
434
435QString Identity::dictionary() const
436{
437 return property( QLatin1String( s_dict ) ).toString();
438}
439
440QString Identity::templates() const
441{
442 const QString str = property( QLatin1String( s_templates ) ).toString();
443 return verifyAkonadiId(str);
444}
445
446QString Identity::drafts() const
447{
448 const QString str = property( QLatin1String( s_drafts ) ).toString();
449 return verifyAkonadiId(str);
450}
451
452QString Identity::fcc() const
453{
454 const QString str = property( QLatin1String( s_fcc ) ).toString();
455 return verifyAkonadiId(str);
456}
457
458QString Identity::transport() const
459{
460 return property( QLatin1String( s_transport ) ).toString();
461}
462
463bool Identity::signatureIsCommand() const
464{
465 return mSignature.type() == Signature::FromCommand;
466}
467
468bool Identity::signatureIsPlainFile() const
469{
470 return mSignature.type() == Signature::FromFile;
471}
472
473bool Identity::signatureIsInline() const
474{
475 return mSignature.type() == Signature::Inlined;
476}
477
478bool Identity::useSignatureFile() const
479{
480 return signatureIsPlainFile() || signatureIsCommand();
481}
482
483QString Identity::signatureInlineText() const
484{
485 return mSignature.text();
486}
487
488QString Identity::signatureFile() const
489{
490 return mSignature.url();
491}
492
493QString Identity::autocorrectionLanguage() const
494{
495 return property( QLatin1String( s_autocorrectionLanguage ) ).toString();
496}
497
498// --------------------- Setters -----------------------------//
499
500void Identity::setProperty( const QString &key, const QVariant &value )
501{
502 if ( value.isNull() ||
503 ( value.type() == QVariant::String && value.toString().isEmpty() ) ) {
504 mPropertiesMap.remove( key );
505 } else {
506 mPropertiesMap.insert( key, value );
507 }
508}
509
510void Identity::setUoid( uint aUoid )
511{
512 setProperty( QLatin1String(s_uoid), aUoid );
513}
514
515void Identity::setIdentityName( const QString &name )
516{
517 setProperty( QLatin1String(s_identity), name );
518}
519
520void Identity::setFullName( const QString &str )
521{
522 setProperty( QLatin1String(s_name), str );
523}
524
525void Identity::setOrganization( const QString &str )
526{
527 setProperty( QLatin1String(s_organization), str );
528}
529
530void Identity::setPGPSigningKey( const QByteArray &str )
531{
532 setProperty( QLatin1String(s_pgps), QLatin1String( str ) );
533}
534
535void Identity::setPGPEncryptionKey( const QByteArray &str )
536{
537 setProperty( QLatin1String(s_pgpe), QLatin1String( str ) );
538}
539
540void Identity::setSMIMESigningKey( const QByteArray &str )
541{
542 setProperty( QLatin1String(s_smimes), QLatin1String( str ) );
543}
544
545void Identity::setSMIMEEncryptionKey( const QByteArray &str )
546{
547 setProperty( QLatin1String(s_smimee), QLatin1String( str ) );
548}
549
550void Identity::setEmailAddr( const QString &str )
551{
552 setPrimaryEmailAddress( str );
553}
554
555void Identity::setPrimaryEmailAddress( const QString & email )
556{
557 setProperty( QLatin1String(s_email), email );
558}
559
560void Identity::setEmailAliases( const QStringList & aliases )
561{
562 setProperty( QLatin1String(s_emailAliases), aliases );
563}
564
565void Identity::setVCardFile( const QString &str )
566{
567 setProperty( QLatin1String(s_vcard), str );
568}
569
570void Identity::setAttachVcard(bool attachment)
571{
572 setProperty( QLatin1String(s_attachVcard), attachment );
573}
574
575void Identity::setReplyToAddr( const QString&str )
576{
577 setProperty( QLatin1String(s_replyto), str );
578}
579
580void Identity::setSignatureFile( const QString &str )
581{
582 mSignature.setUrl( str, signatureIsCommand() );
583}
584
585void Identity::setSignatureInlineText( const QString &str )
586{
587 mSignature.setText( str );
588}
589
590void Identity::setTransport( const QString &str )
591{
592 setProperty( QLatin1String(s_transport), str );
593}
594
595void Identity::setFcc( const QString &str )
596{
597 setProperty( QLatin1String(s_fcc), str );
598}
599
600void Identity::setDrafts( const QString &str )
601{
602 setProperty( QLatin1String(s_drafts), str );
603}
604
605void Identity::setTemplates( const QString &str )
606{
607 setProperty( QLatin1String(s_templates), str );
608}
609
610void Identity::setDictionary( const QString &str )
611{
612 setProperty( QLatin1String(s_dict), str );
613}
614
615void Identity::setBcc( const QString &str )
616{
617 setProperty( QLatin1String(s_bcc), str );
618}
619
620void Identity::setCc( const QString &str )
621{
622 setProperty( QLatin1String(s_cc), str );
623}
624
625void Identity::setIsDefault( bool flag )
626{
627 mIsDefault = flag;
628}
629
630void Identity::setPreferredCryptoMessageFormat( const QString &str )
631{
632 setProperty( QLatin1String(s_prefcrypt), str );
633}
634
635void Identity::setXFace( const QString &str )
636{
637 QString strNew = str;
638 strNew.remove( QLatin1Char(' ') );
639 strNew.remove( QLatin1Char('\n') );
640 strNew.remove( QLatin1Char('\r') );
641 setProperty( QLatin1String(s_xface), strNew );
642}
643
644void Identity::setXFaceEnabled( const bool on )
645{
646 setProperty( QLatin1String(s_xfaceenabled), on );
647}
648
649void Identity::setSignature( const Signature &sig )
650{
651 mSignature = sig;
652}
653
654bool Identity::matchesEmailAddress( const QString & addr ) const
655{
656 const QString addrSpec = KPIMUtils::extractEmailAddress( addr ).toLower();
657 if ( addrSpec == primaryEmailAddress().toLower() ) {
658 return true;
659 }
660
661 foreach ( const QString &alias, emailAliases() ) {
662 if ( alias.toLower() == addrSpec ) {
663 return true;
664 }
665 }
666
667 return false;
668}
669
670QString Identity::verifyAkonadiId(const QString& str) const
671{
672 if(str.isEmpty())
673 return str;
674 bool ok = false;
675 const qlonglong val = str.toLongLong(&ok);
676 Q_UNUSED(val);
677 if(ok) {
678 return str;
679 } else {
680 return QString();
681 }
682}
683
684void Identity::setAutocorrectionLanguage(const QString& language)
685{
686 setProperty( QLatin1String(s_autocorrectionLanguage), language );
687}
688
689
690bool Identity::disabledFcc() const
691{
692 const QVariant var = property(QLatin1String( s_disabledFcc ));
693 if(var.isNull()) {
694 return false;
695 } else {
696 return var.toBool();
697 }
698}
699
700void Identity::setDisabledFcc(bool disable)
701{
702 setProperty( QLatin1String(s_disabledFcc), disable );
703}
704
705bool Identity::pgpAutoSign() const
706{
707 const QVariant var = property(QLatin1String( s_pgpautosign ));
708 if(var.isNull()) {
709 return false;
710 } else {
711 return var.toBool();
712 }
713}
714
715void Identity::setPgpAutoSign(bool autoSign)
716{
717 setProperty( QLatin1String(s_pgpautosign), autoSign );
718}
719
720QString Identity::defaultDomainName() const
721{
722 return property( QLatin1String( s_defaultDomainName ) ).toString();
723}
724
725void Identity::setDefaultDomainName(const QString &domainName)
726{
727 setProperty( QLatin1String(s_defaultDomainName), domainName );
728}
729
730
731