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:
33 static 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 
56 using namespace KPIM;
57 
58 static 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 
69 IdentityManager::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 
99 IdentityManager::~IdentityManager()
100 {
101  kdWarning( hasPendingChanges(), 5006 )
102  << "IdentityManager: There were uncommitted changes!" << endl;
103  delete mConfig;
104 }
105 
106 void 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 << kapp->dcopClient()->appId();
160  arg << DCOPObject::objId(); // the real objId, for checking in slotIdentitiesChanged
161  kapp->dcopClient()->emitDCOPSignal( "KPIM::IdentityManager", "identitiesChanged(TQCString,TQCString)", data );
162 }
163 
164 void IdentityManager::rollback()
165 {
166  mShadowIdentities = mIdentities;
167 }
168 
169 bool IdentityManager::hasPendingChanges() const
170 {
171  return mIdentities != mShadowIdentities;
172 }
173 
174 TQStringList 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 
183 TQStringList 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 
192 void IdentityManager::sort() {
193  qHeapSort( mShadowIdentities );
194 }
195 
196 void 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 
223 void 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 
252 TQStringList IdentityManager::groupList(TDEConfigBase* config) const {
253  return config->groupList().grep( TQRegExp("^Identity #\\d+$") );
254 }
255 
256 IdentityManager::ConstIterator IdentityManager::begin() const {
257  return mIdentities.begin();
258 }
259 
260 IdentityManager::ConstIterator IdentityManager::end() const {
261  return mIdentities.end();
262 }
263 
264 IdentityManager::Iterator IdentityManager::modifyBegin() {
265  return mShadowIdentities.begin();
266 }
267 
268 IdentityManager::Iterator IdentityManager::modifyEnd() {
269  return mShadowIdentities.end();
270 }
271 
272 const 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 
281 const 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 
287 const 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 
296 const 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 
305 const 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 
321 bool IdentityManager::thatIsMe( const TQString & addressList ) const {
322  return !identityForAddress( addressList ).isNull();
323 }
324 
325 Identity & 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 
334 Identity & 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 
343 const 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 
351 bool 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 
363 bool 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 
382 bool 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 
394 Identity & IdentityManager::newFromScratch( const TQString & name ) {
395  return newFromExisting( Identity( name ) );
396 }
397 
398 Identity & 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 
410 Identity & 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 
421 void 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 
467 int 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 = kapp->random();
491  } while ( usedUOIDs.find( uoid ) != usedUOIDs.end() );
492 
493  return uoid;
494 }
495 
496 TQStringList 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 
505 void 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 ( kapp->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