00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "blokkalaccount.h"
00021 #include "blokkalaccount.moc"
00022
00023 #include "blokkalaccountconfig.h"
00024 #include "blokkalprotocol.h"
00025 #include "blokkalblog.h"
00026 #include "blokkalblogconfig.h"
00027 #include "blokkalwalletmanager.h"
00028
00029 #include "blokkalio/categorymanager.h"
00030
00031 #include "blokkalui/globalsettings.h"
00032
00033 #include <kstandarddirs.h>
00034 #include <kaction.h>
00035 #include <kactioncollection.h>
00036 #include <klocale.h>
00037 #include <kdebug.h>
00038 #include <kwallet.h>
00039 #include <kpassworddialog.h>
00040 #include <knotification.h>
00041
00042 #include <QDir>
00043 #include <QTimer>
00044 #include <QDomElement>
00045
00046 class Blokkal::Account::Private {
00047 public:
00048 Private( void ):
00049 removeAccount( FALSE ),
00050 blogMap( QMap< QString, Blokkal::Blog * >() ),
00051 unregisteredBlogs( QMap< QString, QDomElement >() ),
00052 categoryManager( 0 ),
00053 autoReconnectCounter( 0 ){}
00054
00055 Protocol * protocol;
00056
00057 AccountConfig * accountConfig;
00058
00059 Blokkal::Account::ConnectionStatus connectionStatus;
00060
00061 bool removeAccount;
00062 QMap< QString, Blokkal::Blog * > blogMap;
00063 QMap< QString, QDomElement > unregisteredBlogs;
00064
00065 Io::CategoryManager * categoryManager;
00066 unsigned int autoReconnectCounter;
00067 };
00068
00069 Blokkal::Account::Account( Blokkal::Protocol * protocol, const QString & id ) :
00070 QObject( protocol ),
00071 d( new Private() )
00072 {
00073 d->protocol = protocol;
00074 d->accountConfig = new AccountConfig( id, protocol );
00075 d->connectionStatus = Disconnected;
00076
00077 d->categoryManager = new Io::CategoryManager( this );
00078 }
00079
00080 Blokkal::Account::~Account( void )
00081 {
00082 emit accountDestroyed( this );
00083
00084 delete d->accountConfig;
00085 d->accountConfig = 0;
00086 delete d;
00087 }
00088
00089 Blokkal::AccountConfig * Blokkal::Account::config( void ) const
00090 {
00091 return d->accountConfig;
00092 }
00093
00094 Blokkal::Protocol * Blokkal::Account::protocol( void ) const
00095 {
00096 return d->protocol;
00097 }
00098
00099 QString Blokkal::Account::serverName( void ) const
00100 {
00101 return config()->readEntry( "servername" );
00102 }
00103
00104 KUrl Blokkal::Account::connectAddress( void ) const
00105 {
00106 return config()->readEntry( "connectaddress" );
00107 }
00108
00109 QString Blokkal::Account::id( void ) const
00110 {
00111 return config()->id();
00112 }
00113
00114 QString Blokkal::Account::userName( void ) const
00115 {
00116 return config()->readEntry( "username" );
00117 }
00118
00119 KIcon Blokkal::Account::icon( void ) const
00120 {
00121 return protocol()->icon();
00122 }
00123
00124 void Blokkal::Account::removeAccount( void )
00125 {
00126 d->removeAccount = TRUE;
00127 disconnectAccount( UserDisconnect );
00128 }
00129
00130 bool Blokkal::Account::usesDefaultConnectAddress( void ) const
00131 {
00132 return config()->readBoolEntry( "defaultconnectaddress" );
00133 }
00134
00135 Blokkal::Account::ConnectionStatus Blokkal::Account::connectionStatus( void ) const
00136 {
00137 return d->connectionStatus;
00138 }
00139
00140 void Blokkal::Account::setConnectionStatus( Blokkal::Account::ConnectionStatus status )
00141 {
00142 d->connectionStatus = status;
00143 if( status == Connected ) {
00144 d->autoReconnectCounter = 0;
00145 }
00146 emit connectionStatusChanged( this );
00147 }
00148
00149 void Blokkal::Account::disconnectAccount( Blokkal::Account::DisconnectReason reason, const QString & reasonString )
00150 {
00151 if( reason != UserDisconnect ) {
00152 QString message;
00153 if( !reasonString.isEmpty() || reason == AuthenticationDisconnect ) {
00154 message = i18n( "<b>%1</b> disconnected : %2" ,
00155 id(),
00156 reasonString.isEmpty() ? i18n( "authentication failed" ) : reasonString );
00157 }
00158 else {
00159 message = i18n( "<b>%1</b> disconnected" , id() );
00160 }
00161 KNotification * notification = new KNotification( "account_disconnected", Ui::GlobalSettings::self()->mainWidget() );
00162 notification->setText( message );
00163 notification->sendEvent();
00164 }
00165
00166 QList<Blog*> bloglist = blogs();
00167 for( QList<Blog*>::ConstIterator it = bloglist.begin();
00168 it != bloglist.end();
00169 ++it )
00170 {
00171 (*it)->saveProperties();
00172 }
00173
00174 setConnectionStatus( Disconnected );
00175
00176 if( d->removeAccount ) {
00177 config()->remove();
00178 deleteLater();
00179 }
00180 else if( reason == AuthenticationDisconnect ) {
00181 QTimer::singleShot( 0, this, SLOT( connectAccount() ) );
00182 }
00183 else if( reason != UserDisconnect && d->autoReconnectCounter < 3 ){
00184 d->autoReconnectCounter++;
00185 kDebug() << "auto reconnect: " << d->autoReconnectCounter << endl;
00186 QTimer::singleShot( 30 * 1000, this, SLOT( connectAccount() ) );
00187 }
00188 }
00189
00190 QList< Blokkal::Blog * > Blokkal::Account::blogs( void ) const
00191 {
00192 return d->blogMap.values();
00193 }
00194
00195 Blokkal::Blog * Blokkal::Account::registerBlog( Blokkal::Blog * blog )
00196 {
00197 if( d->blogMap.contains( blog->id() ) ) {
00198 if( d->blogMap[blog->id()] == blog ) {
00199 return blog;
00200 }
00201 else {
00202 blog->deleteLater();
00203 return 0;
00204 }
00205 }
00206
00207
00208 d->blogMap.insert( blog->id(), blog );
00209 if( d->unregisteredBlogs.contains( blog->id() ) ) {
00210 config()->node().appendChild( d->unregisteredBlogs[blog->id()] );
00211 d->unregisteredBlogs.remove( blog->id() );
00212 }
00213 connect( blog, SIGNAL( blogDestroyed( Blokkal::Blog * ) ),
00214 this, SLOT( unregisterBlog( Blokkal::Blog * ) ) );
00215 emit blogRegistered( blog );
00216 return blog;
00217 }
00218
00219 void Blokkal::Account::unregisterBlog( Blokkal::Blog * blog )
00220 {
00221 if( !d->blogMap.contains( blog->id() ) ) {
00222 d->blogMap.remove( blog->id() );
00223 emit blogUnregistered( blog );
00224 }
00225 }
00226
00227 Blokkal::Blog * Blokkal::Account::blog( const QString & id ) const
00228 {
00229 if( d->blogMap.contains( id ) ) {
00230 return d->blogMap[ id ];
00231 }
00232
00233 return 0;
00234 }
00235
00236 QString Blokkal::Account::dataDirectory( void ) const
00237 {
00238 QString dataDirName = KStandardDirs::locateLocal( "appdata",
00239 QString::fromLatin1( "accounts/%1/" ).arg( id() ),
00240 TRUE );
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 return dataDirName;
00255 }
00256
00257 void Blokkal::Account::setServerName( const QString & serverName )
00258 {
00259 config()->writeEntry( "servername", serverName );
00260 }
00261
00262 void Blokkal::Account::setConnectAddress( const QString & address )
00263 {
00264 config()->writeEntry( "connectaddress", address );
00265 }
00266
00267 void Blokkal::Account::setUsesDefaultConnectAddress( bool useDefault )
00268 {
00269 config()->writeEntry( "defaultconnectaddress", useDefault );
00270 }
00271
00272 void Blokkal::Account::setUserName( const QString & user )
00273 {
00274 config()->writeEntry( "username", user );
00275 }
00276
00277 bool Blokkal::Account::isConnected( void ) const
00278 {
00279 return connectionStatus() == Connected;
00280 }
00281
00282 bool Blokkal::Account::isDisconnected( void ) const
00283 {
00284 return connectionStatus() == Disconnected;
00285 }
00286
00287 QDomElement Blokkal::Account::blogNode( const QString & id )
00288 {
00289
00290 QDomElement currentElement;
00291 for( QDomNode currentNode = config()->node().namedItem( "blog" );
00292 !currentNode.isNull();
00293 currentNode = currentNode.nextSibling() )
00294 {
00295 if( currentNode.nodeName() == "blog" && currentNode.isElement() ) {
00296 currentElement = currentNode.toElement();
00297 if( currentElement.attribute( "id" ) == id
00298 || currentElement.attribute( "name" ) == id )
00299 {
00300 return currentElement;
00301 }
00302 }
00303 }
00304
00305
00306 if( d->unregisteredBlogs.contains( id ) ) {
00307 return d->unregisteredBlogs[id];
00308 }
00309
00310
00311 currentElement = config()->node().ownerDocument().createElement( "blog" );
00312 currentElement.setAttribute( "id", id );
00313 d->unregisteredBlogs.insert( id, currentElement );
00314 return currentElement;
00315 }
00316
00317 void Blokkal::Account::restoreBlogs( void )
00318 {
00319 QDomElement currentElement;
00320 Blog * currentBlog;
00321 BlogConfig * config;
00322
00323 for( QDomNode currentNode = this->config()->node().namedItem( "blog" );
00324 !currentNode.isNull();
00325 currentNode = currentNode.nextSibling() )
00326 {
00327 if( currentNode.nodeName() == "blog" && currentNode.isElement() ) {
00328 currentElement = currentNode.toElement();
00329 const QString id = currentElement.attribute( "name" ).isEmpty()
00330 ? currentElement.attribute( "id")
00331 : currentElement.attribute( "name" );
00332 if( id.isEmpty() ) {
00333 this->config()->node().removeChild( currentElement );
00334 continue;
00335 }
00336
00337 config = new BlogConfig( id, this );
00338 currentBlog = restoreBlog( config );
00339 if( currentBlog ) {
00340 registerBlog( currentBlog );
00341 }
00342
00343 delete config;
00344 }
00345 }
00346 }
00347
00348 bool Blokkal::Account::autoConnect( void ) const
00349 {
00350 return config()->readBoolEntry( "autoconnect", TRUE );
00351 }
00352
00353 void Blokkal::Account::setAutoConnect( bool enable ) const
00354 {
00355 config()->writeEntry( "autoconnect", enable );
00356 }
00357
00358 Blokkal::Io::CategoryManager * Blokkal::Account::categoryManager( void ) const
00359 {
00360 return d->categoryManager;
00361 }
00362
00363
00364
00365
00366 class Blokkal::PasswordedAccount::Private {
00367 public:
00368 Private( void ) :
00369 passwordWrong( FALSE ) {}
00370
00371 bool passwordWrong;
00372 QString password;
00373 };
00374 Blokkal::PasswordedAccount::PasswordedAccount( Blokkal::Protocol * protocol, const QString & id ):
00375 Account( protocol, id ),
00376 d( new Private() )
00377 {
00378 }
00379
00380 Blokkal::PasswordedAccount::~PasswordedAccount( void )
00381 {
00382 delete d;
00383 }
00384
00385 void Blokkal::PasswordedAccount::removeAccount( void )
00386 {
00387 new Blokkal::PasswordDeleter( id() );
00388 Account::removeAccount( );
00389 }
00390
00391 void Blokkal::PasswordedAccount::connectAccount( void )
00392 {
00393 setConnectionStatus( Connecting );
00394 if( d->password.isNull() || d->passwordWrong ) {
00395 WalletManager::self()->openWallet( this, SLOT( slotWalletOpened( KWallet::Wallet * ) ) );
00396 }
00397 else {
00398 connectInner();
00399 }
00400 }
00401
00402 void Blokkal::PasswordedAccount::disconnectAccount( Blokkal::Account::DisconnectReason reason, const QString & reasonString )
00403 {
00404 if( reason == AuthenticationDisconnect ) {
00405 d->password == QString::null;
00406 d->passwordWrong = TRUE;
00407 }
00408
00409 Account::disconnectAccount( reason, reasonString );
00410 }
00411
00412 const QString & Blokkal::PasswordedAccount::password( void ) const
00413 {
00414 return d->password;
00415 }
00416
00417 void Blokkal::PasswordedAccount::slotWalletOpened( KWallet::Wallet * wallet )
00418 {
00419 bool isValid = TRUE;
00420 if( wallet ) {
00421 if( d->passwordWrong ) {
00422 d->password = promptUser( isValid, wallet );
00423 }
00424 else if( wallet->hasEntry( id() ) ) {
00425 wallet->readPassword( id(), d->password );
00426 }
00427 else {
00428 d->password = promptUser( isValid, wallet );
00429 }
00430 }
00431 else {
00432 d->password = promptUser( isValid, wallet );
00433 }
00434
00435 if( isValid ) {
00436 d->passwordWrong = FALSE;
00437 connectInner();
00438 }
00439 else {
00440 disconnectAccount( UserDisconnect );
00441 }
00442 }
00443
00444 QString Blokkal::PasswordedAccount::promptUser( bool & success, KWallet::Wallet * wallet )
00445 {
00446 const QString passwordPrompt = i18n( "Password required for account: \"%1\"", id() );
00447 QString password;
00448
00449 KPasswordDialog * passwordDialog = new KPasswordDialog( Blokkal::Ui::GlobalSettings::self()->mainWidget(),
00450 wallet ? KPasswordDialog::ShowKeepPassword : KPasswordDialog::NoFlags );
00451
00452 passwordDialog->setPrompt( passwordPrompt );
00453
00454
00455 if( passwordDialog->exec() ) {
00456 password = passwordDialog->password();
00457 if( passwordDialog->keepPassword() && wallet ) {
00458 wallet->writePassword( id(), password );
00459 }
00460 success = TRUE;
00461 }
00462 else {
00463 success = FALSE;
00464 password = QString::null;
00465 }
00466
00467 delete passwordDialog;
00468 passwordDialog = 0;
00469 return password;
00470 }
00471
00472 QList< QAction * > Blokkal::Account::actionList( void )
00473 {
00474 return QList<QAction*>();
00475 }