libkpimidentities

identitymanager.cpp
1/*
2 identitymanager.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2002 Marc Mutz <mutz@kde.org>
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License, version 2, as
9 published by the Free Software Foundation.
10
11 KMail is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 In addition, as a special exception, the copyright holders give
21 permission to link the code of this program with any edition of
22 the TQt library by Trolltech AS, Norway (or with modified versions
23 of TQt that use the same license as TQt), and distribute linked
24 combinations including the two. You must obey the GNU General
25 Public License in all respects for all of the code used other than
26 TQt. If you modify this file, you may extend this exception to
27 your version of the file, but you are not obligated to do so. If
28 you do not wish to do so, delete this exception statement from
29 your version.
30*/
31
32// config keys:
33static const char configKeyDefaultIdentity[] = "Default Identity";
34
35#ifdef HAVE_CONFIG_H
36#include <config.h>
37#endif
38
39#include "identitymanager.h"
40
41#include "identity.h" // for IdentityList::{export,import}Data
42#include <libemailfunctions/email.h> // for static helper functions
43
44#include <tdeemailsettings.h> // for IdentityEntry::fromControlCenter()
45#include <tdeapplication.h>
46#include <tdelocale.h>
47#include <kdebug.h>
48#include <tdeconfig.h>
49#include <kuser.h>
50#include <dcopclient.h>
51
52#include <tqregexp.h>
53
54#include <assert.h>
55
56using namespace KPIM;
57
58static TQCString newDCOPObjectName()
59{
60 static int s_count = 0;
61 TQCString name( "KPIM::IdentityManager" );
62 if ( s_count++ ) {
63 name += '-';
64 name += TQCString().setNum( s_count );
65 }
66 return name;
67}
68
69IdentityManager::IdentityManager( bool readonly, TQObject * parent, const char * name )
70 : ConfigManager( parent, name ), DCOPObject( newDCOPObjectName() )
71{
72 mReadOnly = readonly;
73 mConfig = new TDEConfig( "emailidentities", readonly );
74 readConfig(mConfig);
75 if ( mIdentities.isEmpty() ) {
76 kdDebug(5006) << "emailidentities is empty -> convert from kmailrc" << endl;
77 // No emailidentities file, or an empty one due to broken conversion (tdeconf_update bug in tdelibs <= 3.2.2)
78 // => convert it, i.e. read settings from kmailrc
79 TDEConfig kmailConf( "kmailrc", true );
80 readConfig( &kmailConf );
81 }
82 // we need at least a default identity:
83 if ( mIdentities.isEmpty() ) {
84 kdDebug( 5006 ) << "IdentityManager: No identity found. Creating default." << endl;
85 createDefaultIdentity();
86 commit();
87 }
88 // Migration: people without settings in kemailsettings should get some
89 if ( KEMailSettings().getSetting( KEMailSettings::EmailAddress ).isEmpty() ) {
90 writeConfig();
91 }
92
93 // The emitter is always called KPIM::IdentityManager even if we are not
94 if ( !connectDCOPSignal( 0, "KPIM::IdentityManager", "identitiesChanged(TQCString,TQCString)",
95 "slotIdentitiesChanged(TQCString,TQCString)", false ) )
96 kdError(5650) << "IdentityManager: connection to identitiesChanged failed" << endl;
97}
98
99IdentityManager::~IdentityManager()
100{
101 kdWarning( hasPendingChanges(), 5006 )
102 << "IdentityManager: There were uncommitted changes!" << endl;
103 delete mConfig;
104}
105
106void IdentityManager::commit()
107{
108 // early out:
109 if ( !hasPendingChanges() || mReadOnly ) return;
110
111 TQValueList<uint> seenUOIDs;
112 for ( TQValueList<Identity>::ConstIterator it = mIdentities.begin() ;
113 it != mIdentities.end() ; ++it )
114 seenUOIDs << (*it).uoid();
115
116 TQValueList<uint> changedUOIDs;
117 // find added and changed identities:
118 for ( TQValueList<Identity>::ConstIterator it = mShadowIdentities.begin() ;
119 it != mShadowIdentities.end() ; ++it ) {
120 TQValueList<uint>::Iterator uoid = seenUOIDs.find( (*it).uoid() );
121 if ( uoid != seenUOIDs.end() ) {
122 const Identity & orig = identityForUoid( *uoid ); // look it up in mIdentities
123 if ( *it != orig ) {
124 // changed identity
125 kdDebug( 5006 ) << "emitting changed() for identity " << *uoid << endl;
126 emit changed( *it );
127 changedUOIDs << *uoid;
128 }
129 seenUOIDs.remove( uoid );
130 } else {
131 // new identity
132 kdDebug( 5006 ) << "emitting added() for identity " << (*it).uoid() << endl;
133 emit added( *it );
134 }
135 }
136
137 // what's left are deleted identities:
138 for ( TQValueList<uint>::ConstIterator it = seenUOIDs.begin() ;
139 it != seenUOIDs.end() ; ++it ) {
140 kdDebug( 5006 ) << "emitting deleted() for identity " << (*it) << endl;
141 emit deleted( *it );
142 }
143
144 mIdentities = mShadowIdentities;
145 writeConfig();
146
147 // now that mIdentities has all the new info, we can emit the added/changed
148 // signals that ship a uoid. This is because the slots might use identityForUoid(uoid)...
149 for ( TQValueList<uint>::ConstIterator it = changedUOIDs.begin() ;
150 it != changedUOIDs.end() ; ++it )
151 emit changed( *it );
152
153 emit ConfigManager::changed(); // normal signal
154
155 // DCOP signal for other IdentityManager instances
156 // The emitter is always set to KPIM::IdentityManager, so that the connect works
157 // This is why we can't use k_dcop_signals here, but need to use emitDCOPSignal
158 TQByteArray data; TQDataStream arg( data, IO_WriteOnly );
159 arg << tdeApp->dcopClient()->appId();
160 arg << DCOPObject::objId(); // the real objId, for checking in slotIdentitiesChanged
161 tdeApp->dcopClient()->emitDCOPSignal( "KPIM::IdentityManager", "identitiesChanged(TQCString,TQCString)", data );
162}
163
164void IdentityManager::rollback()
165{
166 mShadowIdentities = mIdentities;
167}
168
169bool IdentityManager::hasPendingChanges() const
170{
171 return mIdentities != mShadowIdentities;
172}
173
174TQStringList IdentityManager::identities() const
175{
176 TQStringList result;
177 for ( ConstIterator it = mIdentities.begin() ;
178 it != mIdentities.end() ; ++it )
179 result << (*it).identityName();
180 return result;
181}
182
183TQStringList IdentityManager::shadowIdentities() const
184{
185 TQStringList result;
186 for ( ConstIterator it = mShadowIdentities.begin() ;
187 it != mShadowIdentities.end() ; ++it )
188 result << (*it).identityName();
189 return result;
190}
191
192void IdentityManager::sort() {
193 qHeapSort( mShadowIdentities );
194}
195
196void IdentityManager::writeConfig() const {
197 TQStringList identities = groupList(mConfig);
198 for ( TQStringList::Iterator group = identities.begin() ;
199 group != identities.end() ; ++group )
200 mConfig->deleteGroup( *group );
201 int i = 0;
202 for ( ConstIterator it = mIdentities.begin() ;
203 it != mIdentities.end() ; ++it, ++i ) {
204 TDEConfigGroup cg( mConfig, TQString::fromLatin1("Identity #%1").arg(i) );
205 (*it).writeConfig( &cg );
206 if ( (*it).isDefault() ) {
207 // remember which one is default:
208 TDEConfigGroup general( mConfig, "General" );
209 general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
210
211 // Also write the default identity to emailsettings
212 KEMailSettings es;
213 es.setSetting( KEMailSettings::RealName, (*it).fullName() );
214 es.setSetting( KEMailSettings::EmailAddress, (*it).primaryEmailAddress() );
215 es.setSetting( KEMailSettings::Organization, (*it).organization() );
216 es.setSetting( KEMailSettings::ReplyToAddress, (*it).replyToAddr() );
217 }
218 }
219 mConfig->sync();
220
221}
222
223void IdentityManager::readConfig(TDEConfigBase* config) {
224 mIdentities.clear();
225
226 TQStringList identities = groupList(config);
227 if ( identities.isEmpty() ) return; // nothing to be done...
228
229 TDEConfigGroup general( config, "General" );
230 uint defaultIdentity = general.readUnsignedNumEntry( configKeyDefaultIdentity );
231 bool haveDefault = false;
232
233 for ( TQStringList::Iterator group = identities.begin() ;
234 group != identities.end() ; ++group ) {
235 TDEConfigGroup configGroup( config, *group );
236 mIdentities << Identity();
237 mIdentities.last().readConfig( &configGroup );
238 if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
239 haveDefault = true;
240 mIdentities.last().setIsDefault( true );
241 }
242 }
243 if ( !haveDefault ) {
244 kdWarning( 5006 ) << "IdentityManager: There was no default identity. Marking first one as default." << endl;
245 mIdentities.first().setIsDefault( true );
246 }
247 qHeapSort( mIdentities );
248
249 mShadowIdentities = mIdentities;
250}
251
252TQStringList IdentityManager::groupList(TDEConfigBase* config) const {
253 return config->groupList().grep( TQRegExp("^Identity #\\d+$") );
254}
255
256IdentityManager::ConstIterator IdentityManager::begin() const {
257 return mIdentities.begin();
258}
259
260IdentityManager::ConstIterator IdentityManager::end() const {
261 return mIdentities.end();
262}
263
264IdentityManager::Iterator IdentityManager::modifyBegin() {
265 return mShadowIdentities.begin();
266}
267
268IdentityManager::Iterator IdentityManager::modifyEnd() {
269 return mShadowIdentities.end();
270}
271
272const Identity & IdentityManager::identityForName( const TQString & name ) const
273{
274 kdWarning( 5006 )
275 << "deprecated method IdentityManager::identityForName() called!" << endl;
276 for ( ConstIterator it = begin() ; it != end() ; ++it )
277 if ( (*it).identityName() == name ) return (*it);
278 return Identity::null();
279}
280
281const Identity & IdentityManager::identityForUoid( uint uoid ) const {
282 for ( ConstIterator it = begin() ; it != end() ; ++it )
283 if ( (*it).uoid() == uoid ) return (*it);
284 return Identity::null();
285}
286
287const Identity & IdentityManager::identityForNameOrDefault( const TQString & name ) const
288{
289 const Identity & ident = identityForName( name );
290 if ( ident.isNull() )
291 return defaultIdentity();
292 else
293 return ident;
294}
295
296const Identity & IdentityManager::identityForUoidOrDefault( uint uoid ) const
297{
298 const Identity & ident = identityForUoid( uoid );
299 if ( ident.isNull() )
300 return defaultIdentity();
301 else
302 return ident;
303}
304
305const Identity & IdentityManager::identityForAddress( const TQString & addresses ) const
306{
307 const TQStringList addressList = KPIM::splitEmailAddrList( addresses );
308 for( TQStringList::ConstIterator addrIt = addressList.begin();
309 addrIt != addressList.end(); ++addrIt ) {
310 const TQString addr = KPIM::getEmailAddress( *addrIt ).lower();
311 for ( ConstIterator it = begin() ; it != end() ; ++it ) {
312 const Identity & id = *it;
313 if ( id.matchesEmailAddress( addr ) ) {
314 return id;
315 }
316 }
317 }
318 return Identity::null();
319}
320
321bool IdentityManager::thatIsMe( const TQString & addressList ) const {
322 return !identityForAddress( addressList ).isNull();
323}
324
325Identity & IdentityManager::modifyIdentityForName( const TQString & name )
326{
327 for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
328 if ( (*it).identityName() == name ) return (*it);
329 kdWarning( 5006 ) << "IdentityManager::identityForName() used as newFromScratch() replacement!"
330 << "\n name == \"" << name << "\"" << endl;
331 return newFromScratch( name );
332}
333
334Identity & IdentityManager::modifyIdentityForUoid( uint uoid )
335{
336 for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
337 if ( (*it).uoid() == uoid ) return (*it);
338 kdWarning( 5006 ) << "IdentityManager::identityForUoid() used as newFromScratch() replacement!"
339 << "\n uoid == \"" << uoid << "\"" << endl;
340 return newFromScratch( i18n("Unnamed") );
341}
342
343const Identity & IdentityManager::defaultIdentity() const {
344 for ( ConstIterator it = begin() ; it != end() ; ++it )
345 if ( (*it).isDefault() ) return (*it);
346 (mIdentities.isEmpty() ? kdFatal( 5006 ) : kdWarning( 5006 ) )
347 << "IdentityManager: No default identity found!" << endl;
348 return *begin();
349}
350
351bool IdentityManager::setAsDefault( const TQString & name ) {
352 // First, check if the identity actually exists:
353 TQStringList names = shadowIdentities();
354 if ( names.find( name ) == names.end() ) return false;
355 // Then, change the default as requested:
356 for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
357 (*it).setIsDefault( (*it).identityName() == name );
358 // and re-sort:
359 sort();
360 return true;
361}
362
363bool IdentityManager::setAsDefault( uint uoid ) {
364 // First, check if the identity actually exists:
365 bool found = false;
366 for ( ConstIterator it = mShadowIdentities.begin() ;
367 it != mShadowIdentities.end() ; ++it )
368 if ( (*it).uoid() == uoid ) {
369 found = true;
370 break;
371 }
372 if ( !found ) return false;
373
374 // Then, change the default as requested:
375 for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
376 (*it).setIsDefault( (*it).uoid() == uoid );
377 // and re-sort:
378 sort();
379 return true;
380}
381
382bool IdentityManager::removeIdentity( const TQString & name ) {
383 for ( Iterator it = modifyBegin() ; it != modifyEnd() ; ++it )
384 if ( (*it).identityName() == name ) {
385 bool removedWasDefault = (*it).isDefault();
386 mShadowIdentities.remove( it );
387 if ( removedWasDefault )
388 mShadowIdentities.first().setIsDefault( true );
389 return true;
390 }
391 return false;
392}
393
394Identity & IdentityManager::newFromScratch( const TQString & name ) {
395 return newFromExisting( Identity( name ) );
396}
397
398Identity & IdentityManager::newFromControlCenter( const TQString & name ) {
399 KEMailSettings es;
400 es.setProfile( es.defaultProfileName() );
401
402 return newFromExisting( Identity( name,
403 es.getSetting( KEMailSettings::RealName ),
404 es.getSetting( KEMailSettings::EmailAddress ),
405 es.getSetting( KEMailSettings::Organization ),
406 es.getSetting( KEMailSettings::ReplyToAddress )
407 ) );
408}
409
410Identity & IdentityManager::newFromExisting( const Identity & other,
411 const TQString & name ) {
412 mShadowIdentities << other;
413 Identity & result = mShadowIdentities.last();
414 result.setIsDefault( false ); // we don't want two default identities!
415 result.setUoid( newUoid() ); // we don't want two identies w/ same UOID
416 if ( !name.isNull() )
417 result.setIdentityName( name );
418 return result;
419}
420
421void IdentityManager::createDefaultIdentity() {
422 TQString fullName, emailAddress;
423 bool done = false;
424
425 // Check if the application has any settings
426 createDefaultIdentity( fullName, emailAddress );
427
428 // If not, then use the kcontrol settings
429 if ( fullName.isEmpty() && emailAddress.isEmpty() ) {
430 KEMailSettings emailSettings;
431 fullName = emailSettings.getSetting( KEMailSettings::RealName );
432 emailAddress = emailSettings.getSetting( KEMailSettings::EmailAddress );
433
434 if ( !fullName.isEmpty() && !emailAddress.isEmpty() ) {
435 newFromControlCenter( i18n("Default") );
436 done = true;
437 } else {
438 // If KEmailSettings doesn't have name and address, generate something from KUser
439 KUser user;
440 if ( fullName.isEmpty() )
441 fullName = user.fullName();
442 if ( emailAddress.isEmpty() ) {
443 emailAddress = user.loginName();
444 if ( !emailAddress.isEmpty() ) {
445 TDEConfigGroup general( mConfig, "General" );
446 TQString defaultdomain = general.readEntry( "Default domain" );
447 if( !defaultdomain.isEmpty() ) {
448 emailAddress += '@' + defaultdomain;
449 }
450 else {
451 emailAddress = TQString();
452 }
453 }
454 }
455 }
456 }
457
458 if ( !done )
459 mShadowIdentities << Identity( i18n("Default"), fullName, emailAddress );
460
461 mShadowIdentities.last().setIsDefault( true );
462 mShadowIdentities.last().setUoid( newUoid() );
463 if ( mReadOnly ) // commit won't do it in readonly mode
464 mIdentities = mShadowIdentities;
465}
466
467int IdentityManager::newUoid()
468{
469 int uoid;
470
471 // determine the UOIDs of all saved identities
472 TQValueList<uint> usedUOIDs;
473 for ( TQValueList<Identity>::ConstIterator it = mIdentities.begin() ;
474 it != mIdentities.end() ; ++it )
475 usedUOIDs << (*it).uoid();
476
477 if ( hasPendingChanges() ) {
478 // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
479 // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
480 for ( TQValueList<Identity>::ConstIterator it = mShadowIdentities.begin() ;
481 it != mShadowIdentities.end() ; ++it ) {
482 usedUOIDs << (*it).uoid();
483 }
484 }
485
486 usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
487 // default identity
488
489 do {
490 uoid = tdeApp->random();
491 } while ( usedUOIDs.find( uoid ) != usedUOIDs.end() );
492
493 return uoid;
494}
495
496TQStringList KPIM::IdentityManager::allEmails() const
497{
498 TQStringList lst;
499 for ( ConstIterator it = begin() ; it != end() ; ++it ) {
500 lst << (*it).primaryEmailAddress();
501 }
502 return lst;
503}
504
505void KPIM::IdentityManager::slotIdentitiesChanged( TQCString appId, TQCString objId )
506{
507 // From standalone kmail to standalone korganizer, the appId will differ
508 // From kontact the appId will match, so we need to test the objId
509 if ( tdeApp->dcopClient()->appId() != appId || DCOPObject::objId() != objId ) {
510 mConfig->reparseConfiguration();
511 Q_ASSERT( !hasPendingChanges() );
512 readConfig( mConfig );
513 }
514}
515
516#include "identitymanager.moc"
User identity information.
Definition: identity.h:96
void setIsDefault(bool flag)
Set whether this identity is the default identity.
Definition: identity.cpp:444