• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.3 API Reference
  • KDE Home
  • Contact Us
 

kpimidentities

  • kpimidentities
identitymanager.cpp
1 /*
2  Copyright (c) 2002 Marc Mutz <mutz@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 // config keys:
21 static const char configKeyDefaultIdentity[] = "Default Identity";
22 
23 #include "identitymanager.h"
24 #include "identity.h" // for IdentityList::{export,import}Data
25 
26 #include <kpimutils/email.h> // for static helper functions
27 
28 #include <kemailsettings.h> // for IdentityEntry::fromControlCenter()
29 #include <klocale.h>
30 #include <kglobal.h>
31 #include <kdebug.h>
32 #include <kconfig.h>
33 #include <kuser.h>
34 #include <kconfiggroup.h>
35 
36 #include <QList>
37 #include <QRegExp>
38 #include <QtDBus/QtDBus>
39 
40 #include <assert.h>
41 #include <krandom.h>
42 
43 #include "identitymanageradaptor.h"
44 
45 using namespace KPIMIdentities;
46 
47 static QString newDBusObjectName()
48 {
49  static int s_count = 0;
50  QString name( "/KPIMIDENTITIES_IdentityManager" );
51  if ( s_count++ ) {
52  name += '_';
53  name += QString::number( s_count );
54  }
55  return name;
56 }
57 
58 IdentityManager::IdentityManager( bool readonly, QObject *parent,
59  const char *name )
60  : QObject( parent )
61 {
62  setObjectName( name );
63  KGlobal::locale()->insertCatalog( "libkpimidentities" );
64  new IdentityManagerAdaptor( this );
65  QDBusConnection dbus = QDBusConnection::sessionBus();
66  const QString dbusPath = newDBusObjectName();
67  setProperty( "uniqueDBusPath", dbusPath );
68  const QString dbusInterface = "org.kde.pim.IdentityManager";
69  dbus.registerObject( dbusPath, this );
70  dbus.connect( QString(), QString(), dbusInterface, "identitiesChanged", this,
71  SLOT(slotIdentitiesChanged(QString)) );
72 
73  mReadOnly = readonly;
74  mConfig = new KConfig( "emailidentities" );
75  readConfig( mConfig );
76  if ( mIdentities.isEmpty() ) {
77  kDebug( 5325 ) << "emailidentities is empty -> convert from kmailrc";
78  // No emailidentities file, or an empty one due to broken conversion
79  // (kconf_update bug in kdelibs <= 3.2.2)
80  // => convert it, i.e. read settings from kmailrc
81  KConfig kmailConf( "kmailrc" );
82  readConfig( &kmailConf );
83  }
84  // we need at least a default identity:
85  if ( mIdentities.isEmpty() ) {
86  kDebug( 5325 ) << "IdentityManager: No identity found. Creating default.";
87  createDefaultIdentity();
88  commit();
89  }
90  // Migration: people without settings in kemailsettings should get some
91  if ( KEMailSettings().getSetting( KEMailSettings::EmailAddress ).isEmpty() ) {
92  writeConfig();
93  }
94 }
95 
96 IdentityManager::~IdentityManager()
97 {
98  kWarning( hasPendingChanges(), 5325 )
99  << "IdentityManager: There were uncommitted changes!";
100  delete mConfig;
101 }
102 
103 QString IdentityManager::makeUnique( const QString &name ) const
104 {
105  int suffix = 1;
106  QString result = name;
107  while ( identities().contains( result ) ) {
108  result = i18nc( "%1: name; %2: number appended to it to make it unique "
109  "among a list of names", "%1 #%2",
110  name, suffix );
111  suffix++;
112  }
113  return result;
114 }
115 
116 bool IdentityManager::isUnique( const QString &name ) const
117 {
118  return !identities().contains( name );
119 }
120 
121 void IdentityManager::commit()
122 {
123  // early out:
124  if ( !hasPendingChanges() || mReadOnly ) {
125  return;
126  }
127 
128  QList<uint> seenUOIDs;
129  QList<Identity>::ConstIterator end = mIdentities.constEnd();
130  for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
131  it != end; ++it ) {
132  seenUOIDs << (*it).uoid();
133  }
134 
135  QList<uint> changedUOIDs;
136  // find added and changed identities:
137  for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
138  it != mShadowIdentities.constEnd(); ++it ) {
139  int index = seenUOIDs.indexOf( (*it).uoid() );
140  if ( index != -1 ) {
141  uint uoid = seenUOIDs.at( index );
142  const Identity &orig = identityForUoid( uoid ); // look up in mIdentities
143  if ( *it != orig ) {
144  // changed identity
145  kDebug( 5325 ) << "emitting changed() for identity" << uoid;
146  emit changed(*it);
147  changedUOIDs << uoid;
148  }
149  seenUOIDs.removeAll( uoid );
150  } else {
151  // new identity
152  kDebug( 5325 ) << "emitting added() for identity" << (*it).uoid();
153  emit added(*it);
154  }
155  }
156 
157  // what's left are deleted identities:
158  for ( QList<uint>::ConstIterator it = seenUOIDs.constBegin();
159  it != seenUOIDs.constEnd(); ++it ) {
160  kDebug( 5325 ) << "emitting deleted() for identity" << (*it);
161  emit deleted(*it);
162  }
163 
164  mIdentities = mShadowIdentities;
165  writeConfig();
166 
167  // now that mIdentities has all the new info, we can emit the added/changed
168  // signals that ship a uoid. This is because the slots might use
169  // identityForUoid(uoid)...
170  QList<uint>::ConstIterator changedEnd( changedUOIDs.constEnd() );
171  for ( QList<uint>::ConstIterator it = changedUOIDs.constBegin();
172  it != changedEnd; ++it )
173  emit changed(*it);
174 
175  emit changed(); // normal signal
176 
177  // DBus signal for other IdentityManager instances
178  const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).
179  arg( QDBusConnection::sessionBus().baseService() ).
180  arg( property( "uniqueDBusPath" ).toString() );
181  emit identitiesChanged( ourIdentifier );
182 }
183 
184 void IdentityManager::rollback()
185 {
186  mShadowIdentities = mIdentities;
187 }
188 
189 bool IdentityManager::hasPendingChanges() const
190 {
191  return mIdentities != mShadowIdentities;
192 }
193 
194 QStringList IdentityManager::identities() const
195 {
196  QStringList result;
197  ConstIterator end = mIdentities.constEnd();
198  for ( ConstIterator it = mIdentities.constBegin();
199  it != end; ++it )
200  result << (*it).identityName();
201  return result;
202 }
203 
204 QStringList IdentityManager::shadowIdentities() const
205 {
206  QStringList result;
207  ConstIterator end = mShadowIdentities.constEnd();
208  for ( ConstIterator it = mShadowIdentities.constBegin();
209  it != end; ++it )
210  result << (*it).identityName();
211  return result;
212 }
213 
214 void IdentityManager::sort()
215 {
216  qSort( mShadowIdentities );
217 }
218 
219 void IdentityManager::writeConfig() const
220 {
221  const QStringList identities = groupList( mConfig );
222  QStringList::const_iterator groupEnd = identities.constEnd();
223  for ( QStringList::const_iterator group = identities.constBegin();
224  group != groupEnd; ++group )
225  mConfig->deleteGroup( *group );
226  int i = 0;
227  ConstIterator end = mIdentities.constEnd();
228  for ( ConstIterator it = mIdentities.constBegin();
229  it != end; ++it, ++i ) {
230  KConfigGroup cg( mConfig, QString::fromLatin1( "Identity #%1" ).arg( i ) );
231  (*it).writeConfig( cg );
232  if ( (*it).isDefault() ) {
233  // remember which one is default:
234  KConfigGroup general( mConfig, "General" );
235  general.writeEntry( configKeyDefaultIdentity, (*it).uoid() );
236 
237  // Also write the default identity to emailsettings
238  KEMailSettings es;
239  es.setSetting( KEMailSettings::RealName, (*it).fullName() );
240  es.setSetting( KEMailSettings::EmailAddress, (*it).primaryEmailAddress() );
241  es.setSetting( KEMailSettings::Organization, (*it).organization() );
242  es.setSetting( KEMailSettings::ReplyToAddress, (*it).replyToAddr() );
243  }
244  }
245  mConfig->sync();
246 
247 }
248 
249 void IdentityManager::readConfig( KConfig *config )
250 {
251  mIdentities.clear();
252 
253  const QStringList identities = groupList( config );
254  if ( identities.isEmpty() ) {
255  return; // nothing to be done...
256  }
257 
258  KConfigGroup general( config, "General" );
259  uint defaultIdentity = general.readEntry( configKeyDefaultIdentity, 0 );
260  bool haveDefault = false;
261  QStringList::const_iterator groupEnd = identities.constEnd();
262  for ( QStringList::const_iterator group = identities.constBegin();
263  group != groupEnd; ++group ) {
264  KConfigGroup configGroup( config, *group );
265  mIdentities << Identity();
266  mIdentities.last().readConfig( configGroup );
267  if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
268  haveDefault = true;
269  mIdentities.last().setIsDefault( true );
270  }
271  }
272 
273  if ( !haveDefault ) {
274  kWarning( 5325 ) << "IdentityManager: There was no default identity."
275  << "Marking first one as default.";
276  mIdentities.first().setIsDefault( true );
277  }
278  qSort( mIdentities );
279 
280  mShadowIdentities = mIdentities;
281 }
282 
283 QStringList IdentityManager::groupList( KConfig *config ) const
284 {
285  return config->groupList().filter( QRegExp( "^Identity #\\d+$" ) );
286 }
287 
288 IdentityManager::ConstIterator IdentityManager::begin() const
289 {
290  return mIdentities.begin();
291 }
292 
293 IdentityManager::ConstIterator IdentityManager::end() const
294 {
295  return mIdentities.end();
296 }
297 
298 IdentityManager::Iterator IdentityManager::modifyBegin()
299 {
300  return mShadowIdentities.begin();
301 }
302 
303 IdentityManager::Iterator IdentityManager::modifyEnd()
304 {
305  return mShadowIdentities.end();
306 }
307 
308 const Identity &IdentityManager::identityForUoid( uint uoid ) const
309 {
310  for ( ConstIterator it = begin(); it != end(); ++it ) {
311  if ( (*it).uoid() == uoid ) {
312  return (*it);
313  }
314  }
315  return Identity::null();
316 }
317 
318 const Identity &IdentityManager::identityForUoidOrDefault( uint uoid ) const
319 {
320  const Identity &ident = identityForUoid( uoid );
321  if ( ident.isNull() ) {
322  return defaultIdentity();
323  } else {
324  return ident;
325  }
326 }
327 
328 const Identity &IdentityManager::identityForAddress(
329  const QString &addresses ) const
330 {
331  const QStringList addressList = KPIMUtils::splitAddressList( addresses );
332  foreach ( const QString &fullAddress, addressList ) {
333  const QString addrSpec = KPIMUtils::extractEmailAddress( fullAddress ).toLower();
334  for ( ConstIterator it = begin(); it != end(); ++it ) {
335  const Identity &identity = *it;
336  if ( identity.matchesEmailAddress( addrSpec ) ) {
337  return identity;
338  }
339  }
340  }
341  return Identity::null();
342 }
343 
344 bool IdentityManager::thatIsMe( const QString &addressList ) const
345 {
346  return !identityForAddress( addressList ).isNull();
347 }
348 
349 Identity &IdentityManager::modifyIdentityForName( const QString &name )
350 {
351  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
352  if ( (*it).identityName() == name ) {
353  return (*it);
354  }
355  }
356 
357  kWarning( 5325 ) << "IdentityManager::modifyIdentityForName() used as"
358  << "newFromScratch() replacement!"
359  << endl << " name == \"" << name << "\"";
360  return newFromScratch( name );
361 }
362 
363 Identity &IdentityManager::modifyIdentityForUoid( uint uoid )
364 {
365  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
366  if ( (*it).uoid() == uoid ) {
367  return (*it);
368  }
369  }
370 
371  kWarning( 5325 ) << "IdentityManager::identityForUoid() used as"
372  << "newFromScratch() replacement!"
373  << endl << " uoid == \"" << uoid << "\"";
374  return newFromScratch( i18n( "Unnamed" ) );
375 }
376 
377 const Identity &IdentityManager::defaultIdentity() const
378 {
379  for ( ConstIterator it = begin(); it != end(); ++it ) {
380  if ( (*it).isDefault() ) {
381  return (*it);
382  }
383  }
384 
385  if ( mIdentities.isEmpty() ) {
386  kFatal( 5325 ) << "IdentityManager: No default identity found!";
387  } else {
388  kWarning( 5325 ) << "IdentityManager: No default identity found!";
389  }
390  return *begin();
391 }
392 
393 bool IdentityManager::setAsDefault( uint uoid )
394 {
395  // First, check if the identity actually exists:
396  bool found = false;
397  for ( ConstIterator it = mShadowIdentities.constBegin();
398  it != mShadowIdentities.constEnd(); ++it )
399  if ( (*it).uoid() == uoid ) {
400  found = true;
401  break;
402  }
403 
404  if ( !found ) {
405  return false;
406  }
407 
408  // Then, change the default as requested:
409  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
410  (*it).setIsDefault( (*it).uoid() == uoid );
411  }
412 
413  // and re-sort:
414  sort();
415  return true;
416 }
417 
418 bool IdentityManager::removeIdentity( const QString &name )
419 {
420  if ( mShadowIdentities.size() <= 1 ) {
421  return false;
422  }
423 
424  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
425  if ( (*it).identityName() == name ) {
426  bool removedWasDefault = (*it).isDefault();
427  mShadowIdentities.erase( it );
428  if ( removedWasDefault && !mShadowIdentities.isEmpty() ) {
429  mShadowIdentities.first().setIsDefault( true );
430  }
431  return true;
432  }
433  }
434  return false;
435 }
436 
437 bool IdentityManager::removeIdentityForced( const QString &name )
438 {
439  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
440  if ( (*it).identityName() == name ) {
441  bool removedWasDefault = (*it).isDefault();
442  mShadowIdentities.erase( it );
443  if ( removedWasDefault && !mShadowIdentities.isEmpty() ) {
444  mShadowIdentities.first().setIsDefault( true );
445  }
446  return true;
447  }
448  }
449  return false;
450 }
451 
452 Identity &IdentityManager::newFromScratch( const QString &name )
453 {
454  return newFromExisting( Identity( name ) );
455 }
456 
457 Identity &IdentityManager::newFromControlCenter( const QString &name )
458 {
459  KEMailSettings es;
460  es.setProfile( es.defaultProfileName() );
461 
462  return
463  newFromExisting( Identity( name,
464  es.getSetting( KEMailSettings::RealName ),
465  es.getSetting( KEMailSettings::EmailAddress ),
466  es.getSetting( KEMailSettings::Organization ),
467  es.getSetting( KEMailSettings::ReplyToAddress ) ) );
468 }
469 
470 Identity &IdentityManager::newFromExisting( const Identity &other, const QString &name )
471 {
472  mShadowIdentities << other;
473  Identity &result = mShadowIdentities.last();
474  result.setIsDefault( false ); // we don't want two default identities!
475  result.setUoid( newUoid() ); // we don't want two identies w/ same UOID
476  if ( !name.isNull() ) {
477  result.setIdentityName( name );
478  }
479  return result;
480 }
481 
482 void IdentityManager::createDefaultIdentity()
483 {
484  QString fullName, emailAddress;
485  bool done = false;
486 
487  // Check if the application has any settings
488  createDefaultIdentity( fullName, emailAddress );
489 
490  // If not, then use the kcontrol settings
491  if ( fullName.isEmpty() && emailAddress.isEmpty() ) {
492  KEMailSettings emailSettings;
493  fullName = emailSettings.getSetting( KEMailSettings::RealName );
494  emailAddress = emailSettings.getSetting( KEMailSettings::EmailAddress );
495 
496  if ( !fullName.isEmpty() && !emailAddress.isEmpty() ) {
497  newFromControlCenter( i18nc( "use default address from control center",
498  "Default" ) );
499  done = true;
500  } else {
501  // If KEmailSettings doesn't have name and address, generate something from KUser
502  KUser user;
503  if ( fullName.isEmpty() ) {
504  fullName = user.property( KUser::FullName ).toString();
505  }
506  if ( emailAddress.isEmpty() ) {
507  emailAddress = user.loginName();
508  if ( !emailAddress.isEmpty() ) {
509  KConfigGroup general( mConfig, "General" );
510  QString defaultdomain = general.readEntry( "Default domain" );
511  if ( !defaultdomain.isEmpty() ) {
512  emailAddress += '@' + defaultdomain;
513  } else {
514  emailAddress.clear();
515  }
516  }
517  }
518  }
519  }
520 
521  if ( !done ) {
522  // Default identity name
523  QString name( i18nc( "Default name for new email accounts/identities.", "Unnamed" ) );
524 
525  if ( !emailAddress.isEmpty() ) {
526  // If we have an email address, create a default identity name from it
527  QString idName = emailAddress;
528  int pos = idName.indexOf( '@' );
529  if ( pos != -1 ) {
530  name = idName.mid( pos + 1, -1 );
531  }
532 
533  // Make the name a bit more human friendly
534  name.replace( '.', ' ' );
535  pos = name.indexOf( ' ' );
536  if ( pos != 0 ) {
537  name[pos + 1] = name[pos + 1].toUpper();
538  }
539  name[0] = name[0].toUpper();
540  } else if ( !fullName.isEmpty() ) {
541  // If we have a full name, create a default identity name from it
542  name = fullName;
543  }
544  mShadowIdentities << Identity( name, fullName, emailAddress );
545  }
546 
547  mShadowIdentities.last().setIsDefault( true );
548  mShadowIdentities.last().setUoid( newUoid() );
549  if ( mReadOnly ) { // commit won't do it in readonly mode
550  mIdentities = mShadowIdentities;
551  }
552 }
553 
554 int IdentityManager::newUoid()
555 {
556  int uoid;
557 
558  // determine the UOIDs of all saved identities
559  QList<uint> usedUOIDs;
560  QList<Identity>::ConstIterator end(mIdentities.constEnd());
561  for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
562  it != end; ++it )
563  usedUOIDs << (*it).uoid();
564 
565  if ( hasPendingChanges() ) {
566  // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
567  // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
568  QList<Identity>::ConstIterator endShadow(mShadowIdentities.constEnd());
569  for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
570  it != endShadow; ++it ) {
571  usedUOIDs << (*it).uoid();
572  }
573  }
574 
575  usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
576  // default identity
577 
578  do {
579  uoid = KRandom::random();
580  } while ( usedUOIDs.indexOf( uoid ) != -1 );
581 
582  return uoid;
583 }
584 
585 QStringList KPIMIdentities::IdentityManager::allEmails() const
586 {
587  QStringList lst;
588  for ( ConstIterator it = begin(); it != end(); ++it ) {
589  lst << (*it).primaryEmailAddress();
590  if ( !(*it).emailAliases().isEmpty() ) {
591  lst << (*it).emailAliases();
592  }
593  }
594  return lst;
595 }
596 
597 void KPIMIdentities::IdentityManager::slotRollback()
598 {
599  rollback();
600 }
601 
602 void KPIMIdentities::IdentityManager::slotIdentitiesChanged( const QString &id )
603 {
604  kDebug( 5325 ) <<" KPIMIdentities::IdentityManager::slotIdentitiesChanged :" << id;
605  const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).
606  arg( QDBusConnection::sessionBus().baseService() ).
607  arg( property( "uniqueDBusPath" ).toString() );
608  if ( id != ourIdentifier ) {
609  mConfig->reparseConfiguration();
610  Q_ASSERT( !hasPendingChanges() );
611  readConfig( mConfig );
612  emit changed();
613  }
614 }
615 
616 #include "identitymanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Nov 26 2012 16:50:02 by doxygen 1.8.1.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kpimidentities

Skip menu "kpimidentities"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.9.3 API Reference

Skip menu "kdepimlibs-4.9.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal