• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 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 
176  emit changed(); // normal signal
177 
178  // DBus signal for other IdentityManager instances
179  const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).
180  arg( QDBusConnection::sessionBus().baseService() ).
181  arg( property( "uniqueDBusPath" ).toString() );
182  emit identitiesChanged( ourIdentifier );
183 }
184 
185 void IdentityManager::rollback()
186 {
187  mShadowIdentities = mIdentities;
188 }
189 
190 bool IdentityManager::hasPendingChanges() const
191 {
192  return mIdentities != mShadowIdentities;
193 }
194 
195 QStringList IdentityManager::identities() const
196 {
197  QStringList result;
198  ConstIterator end = mIdentities.constEnd();
199  for ( ConstIterator it = mIdentities.constBegin();
200  it != end; ++it ) {
201  result << ( *it ).identityName();
202  }
203  return result;
204 }
205 
206 QStringList IdentityManager::shadowIdentities() const
207 {
208  QStringList result;
209  ConstIterator end = mShadowIdentities.constEnd();
210  for ( ConstIterator it = mShadowIdentities.constBegin();
211  it != end; ++it ) {
212  result << ( *it ).identityName();
213  }
214  return result;
215 }
216 
217 void IdentityManager::sort()
218 {
219  qSort( mShadowIdentities );
220 }
221 
222 void IdentityManager::writeConfig() const
223 {
224  const QStringList identities = groupList( mConfig );
225  QStringList::const_iterator groupEnd = identities.constEnd();
226  for ( QStringList::const_iterator group = identities.constBegin();
227  group != groupEnd; ++group ) {
228  mConfig->deleteGroup( *group );
229  }
230  int i = 0;
231  ConstIterator end = mIdentities.constEnd();
232  for ( ConstIterator it = mIdentities.constBegin();
233  it != end; ++it, ++i ) {
234  KConfigGroup cg( mConfig, QString::fromLatin1( "Identity #%1" ).arg( i ) );
235  ( *it ).writeConfig( cg );
236  if ( ( *it ).isDefault() ) {
237  // remember which one is default:
238  KConfigGroup general( mConfig, "General" );
239  general.writeEntry( configKeyDefaultIdentity, ( *it ).uoid() );
240 
241  // Also write the default identity to emailsettings
242  KEMailSettings es;
243  es.setSetting( KEMailSettings::RealName, ( *it ).fullName() );
244  es.setSetting( KEMailSettings::EmailAddress, ( *it ).primaryEmailAddress() );
245  es.setSetting( KEMailSettings::Organization, ( *it ).organization() );
246  es.setSetting( KEMailSettings::ReplyToAddress, ( *it ).replyToAddr() );
247  }
248  }
249  mConfig->sync();
250 
251 }
252 
253 void IdentityManager::readConfig( KConfig *config )
254 {
255  mIdentities.clear();
256 
257  const QStringList identities = groupList( config );
258  if ( identities.isEmpty() ) {
259  return; // nothing to be done...
260  }
261 
262  KConfigGroup general( config, "General" );
263  uint defaultIdentity = general.readEntry( configKeyDefaultIdentity, 0 );
264  bool haveDefault = false;
265  QStringList::const_iterator groupEnd = identities.constEnd();
266  for ( QStringList::const_iterator group = identities.constBegin();
267  group != groupEnd; ++group ) {
268  KConfigGroup configGroup( config, *group );
269  mIdentities << Identity();
270  mIdentities.last().readConfig( configGroup );
271  if ( !haveDefault && mIdentities.last().uoid() == defaultIdentity ) {
272  haveDefault = true;
273  mIdentities.last().setIsDefault( true );
274  }
275  }
276 
277  if ( !haveDefault ) {
278  kWarning( 5325 ) << "IdentityManager: There was no default identity."
279  << "Marking first one as default.";
280  mIdentities.first().setIsDefault( true );
281  }
282  qSort( mIdentities );
283 
284  mShadowIdentities = mIdentities;
285 }
286 
287 QStringList IdentityManager::groupList( KConfig *config ) const
288 {
289  return config->groupList().filter( QRegExp( "^Identity #\\d+$" ) );
290 }
291 
292 IdentityManager::ConstIterator IdentityManager::begin() const
293 {
294  return mIdentities.begin();
295 }
296 
297 IdentityManager::ConstIterator IdentityManager::end() const
298 {
299  return mIdentities.end();
300 }
301 
302 IdentityManager::Iterator IdentityManager::modifyBegin()
303 {
304  return mShadowIdentities.begin();
305 }
306 
307 IdentityManager::Iterator IdentityManager::modifyEnd()
308 {
309  return mShadowIdentities.end();
310 }
311 
312 const Identity &IdentityManager::identityForUoid( uint uoid ) const
313 {
314  for ( ConstIterator it = begin(); it != end(); ++it ) {
315  if ( ( *it ).uoid() == uoid ) {
316  return ( *it );
317  }
318  }
319  return Identity::null();
320 }
321 
322 const Identity &IdentityManager::identityForUoidOrDefault( uint uoid ) const
323 {
324  const Identity &ident = identityForUoid( uoid );
325  if ( ident.isNull() ) {
326  return defaultIdentity();
327  } else {
328  return ident;
329  }
330 }
331 
332 const Identity &IdentityManager::identityForAddress(
333  const QString &addresses ) const
334 {
335  const QStringList addressList = KPIMUtils::splitAddressList( addresses );
336  foreach ( const QString &fullAddress, addressList ) {
337  const QString addrSpec = KPIMUtils::extractEmailAddress( fullAddress ).toLower();
338  for ( ConstIterator it = begin(); it != end(); ++it ) {
339  const Identity &identity = *it;
340  if ( identity.matchesEmailAddress( addrSpec ) ) {
341  return identity;
342  }
343  }
344  }
345  return Identity::null();
346 }
347 
348 bool IdentityManager::thatIsMe( const QString &addressList ) const
349 {
350  return !identityForAddress( addressList ).isNull();
351 }
352 
353 Identity &IdentityManager::modifyIdentityForName( const QString &name )
354 {
355  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
356  if ( ( *it ).identityName() == name ) {
357  return ( *it );
358  }
359  }
360 
361  kWarning( 5325 ) << "IdentityManager::modifyIdentityForName() used as"
362  << "newFromScratch() replacement!"
363  << endl << " name == \"" << name << "\"";
364  return newFromScratch( name );
365 }
366 
367 Identity &IdentityManager::modifyIdentityForUoid( uint uoid )
368 {
369  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
370  if ( ( *it ).uoid() == uoid ) {
371  return ( *it );
372  }
373  }
374 
375  kWarning( 5325 ) << "IdentityManager::identityForUoid() used as"
376  << "newFromScratch() replacement!"
377  << endl << " uoid == \"" << uoid << "\"";
378  return newFromScratch( i18n( "Unnamed" ) );
379 }
380 
381 const Identity &IdentityManager::defaultIdentity() const
382 {
383  for ( ConstIterator it = begin(); it != end(); ++it ) {
384  if ( ( *it ).isDefault() ) {
385  return ( *it );
386  }
387  }
388 
389  if ( mIdentities.isEmpty() ) {
390  kFatal( 5325 ) << "IdentityManager: No default identity found!";
391  } else {
392  kWarning( 5325 ) << "IdentityManager: No default identity found!";
393  }
394  return *begin();
395 }
396 
397 bool IdentityManager::setAsDefault( uint uoid )
398 {
399  // First, check if the identity actually exists:
400  bool found = false;
401  for ( ConstIterator it = mShadowIdentities.constBegin();
402  it != mShadowIdentities.constEnd(); ++it ) {
403  if ( ( *it ).uoid() == uoid ) {
404  found = true;
405  break;
406  }
407  }
408 
409  if ( !found ) {
410  return false;
411  }
412 
413  // Then, change the default as requested:
414  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
415  ( *it ).setIsDefault( ( *it ).uoid() == uoid );
416  }
417 
418  // and re-sort:
419  sort();
420  return true;
421 }
422 
423 bool IdentityManager::removeIdentity( const QString &name )
424 {
425  if ( mShadowIdentities.size() <= 1 ) {
426  return false;
427  }
428 
429  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
430  if ( ( *it ).identityName() == name ) {
431  bool removedWasDefault = ( *it ).isDefault();
432  mShadowIdentities.erase( it );
433  if ( removedWasDefault && !mShadowIdentities.isEmpty() ) {
434  mShadowIdentities.first().setIsDefault( true );
435  }
436  return true;
437  }
438  }
439  return false;
440 }
441 
442 bool IdentityManager::removeIdentityForced( const QString &name )
443 {
444  for ( Iterator it = modifyBegin(); it != modifyEnd(); ++it ) {
445  if ( ( *it ).identityName() == name ) {
446  bool removedWasDefault = ( *it ).isDefault();
447  mShadowIdentities.erase( it );
448  if ( removedWasDefault && !mShadowIdentities.isEmpty() ) {
449  mShadowIdentities.first().setIsDefault( true );
450  }
451  return true;
452  }
453  }
454  return false;
455 }
456 
457 Identity &IdentityManager::newFromScratch( const QString &name )
458 {
459  return newFromExisting( Identity( name ) );
460 }
461 
462 Identity &IdentityManager::newFromControlCenter( const QString &name )
463 {
464  KEMailSettings es;
465  es.setProfile( es.defaultProfileName() );
466 
467  return
468  newFromExisting( Identity( name,
469  es.getSetting( KEMailSettings::RealName ),
470  es.getSetting( KEMailSettings::EmailAddress ),
471  es.getSetting( KEMailSettings::Organization ),
472  es.getSetting( KEMailSettings::ReplyToAddress ) ) );
473 }
474 
475 Identity &IdentityManager::newFromExisting( const Identity &other, const QString &name )
476 {
477  mShadowIdentities << other;
478  Identity &result = mShadowIdentities.last();
479  result.setIsDefault( false ); // we don't want two default identities!
480  result.setUoid( newUoid() ); // we don't want two identies w/ same UOID
481  if ( !name.isNull() ) {
482  result.setIdentityName( name );
483  }
484  return result;
485 }
486 
487 void IdentityManager::createDefaultIdentity()
488 {
489  QString fullName, emailAddress;
490  bool done = false;
491 
492  // Check if the application has any settings
493  createDefaultIdentity( fullName, emailAddress );
494 
495  // If not, then use the kcontrol settings
496  if ( fullName.isEmpty() && emailAddress.isEmpty() ) {
497  KEMailSettings emailSettings;
498  fullName = emailSettings.getSetting( KEMailSettings::RealName );
499  emailAddress = emailSettings.getSetting( KEMailSettings::EmailAddress );
500 
501  if ( !fullName.isEmpty() && !emailAddress.isEmpty() ) {
502  newFromControlCenter( i18nc( "use default address from control center",
503  "Default" ) );
504  done = true;
505  } else {
506  // If KEmailSettings doesn't have name and address, generate something from KUser
507  KUser user;
508  if ( fullName.isEmpty() ) {
509  fullName = user.property( KUser::FullName ).toString();
510  }
511  if ( emailAddress.isEmpty() ) {
512  emailAddress = user.loginName();
513  if ( !emailAddress.isEmpty() ) {
514  KConfigGroup general( mConfig, "General" );
515  QString defaultdomain = general.readEntry( "Default domain" );
516  if ( !defaultdomain.isEmpty() ) {
517  emailAddress += '@' + defaultdomain;
518  } else {
519  emailAddress.clear();
520  }
521  }
522  }
523  }
524  }
525 
526  if ( !done ) {
527  // Default identity name
528  QString name( i18nc( "Default name for new email accounts/identities.", "Unnamed" ) );
529 
530  if ( !emailAddress.isEmpty() ) {
531  // If we have an email address, create a default identity name from it
532  QString idName = emailAddress;
533  int pos = idName.indexOf( '@' );
534  if ( pos != -1 ) {
535  name = idName.mid( pos + 1, -1 );
536  }
537 
538  // Make the name a bit more human friendly
539  name.replace( '.', ' ' );
540  pos = name.indexOf( ' ' );
541  if ( pos != 0 ) {
542  name[pos + 1] = name[pos + 1].toUpper();
543  }
544  name[0] = name[0].toUpper();
545  } else if ( !fullName.isEmpty() ) {
546  // If we have a full name, create a default identity name from it
547  name = fullName;
548  }
549  mShadowIdentities << Identity( name, fullName, emailAddress );
550  }
551 
552  mShadowIdentities.last().setIsDefault( true );
553  mShadowIdentities.last().setUoid( newUoid() );
554  if ( mReadOnly ) { // commit won't do it in readonly mode
555  mIdentities = mShadowIdentities;
556  }
557 }
558 
559 int IdentityManager::newUoid()
560 {
561  int uoid;
562 
563  // determine the UOIDs of all saved identities
564  QList<uint> usedUOIDs;
565  QList<Identity>::ConstIterator end( mIdentities.constEnd() );
566  for ( QList<Identity>::ConstIterator it = mIdentities.constBegin();
567  it != end; ++it ) {
568  usedUOIDs << ( *it ).uoid();
569  }
570 
571  if ( hasPendingChanges() ) {
572  // add UOIDs of all shadow identities. Yes, we will add a lot of duplicate
573  // UOIDs, but avoiding duplicate UOIDs isn't worth the effort.
574  QList<Identity>::ConstIterator endShadow( mShadowIdentities.constEnd() );
575  for ( QList<Identity>::ConstIterator it = mShadowIdentities.constBegin();
576  it != endShadow; ++it ) {
577  usedUOIDs << ( *it ).uoid();
578  }
579  }
580 
581  usedUOIDs << 0; // no UOID must be 0 because this value always refers to the
582  // default identity
583 
584  do {
585  uoid = KRandom::random();
586  } while ( usedUOIDs.indexOf( uoid ) != -1 );
587 
588  return uoid;
589 }
590 
591 QStringList KPIMIdentities::IdentityManager::allEmails() const
592 {
593  QStringList lst;
594  for ( ConstIterator it = begin(); it != end(); ++it ) {
595  lst << ( *it ).primaryEmailAddress();
596  if ( !( *it ).emailAliases().isEmpty() ) {
597  lst << ( *it ).emailAliases();
598  }
599  }
600  return lst;
601 }
602 
603 void KPIMIdentities::IdentityManager::slotRollback()
604 {
605  rollback();
606 }
607 
608 void KPIMIdentities::IdentityManager::slotIdentitiesChanged( const QString &id )
609 {
610  kDebug( 5325 ) << " KPIMIdentities::IdentityManager::slotIdentitiesChanged :" << id;
611  const QString ourIdentifier = QString::fromLatin1( "%1/%2" ).
612  arg( QDBusConnection::sessionBus().baseService() ).
613  arg( property( "uniqueDBusPath" ).toString() );
614  if ( id != ourIdentifier ) {
615  mConfig->reparseConfiguration();
616  Q_ASSERT( !hasPendingChanges() );
617  readConfig( mConfig );
618  emit changed();
619  }
620 }
621 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:30:05 by doxygen 1.8.3.1 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.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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