00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "account.h"
00019 #include "maillist.h"
00020
00021 Account::Account( QString name, AccountList* accountList, QObject* parent )
00022 : QObject( parent )
00023 {
00024 this->name = name;
00025 this->accountList = accountList;
00026
00027
00028 mails = new MailList( this, this );
00029
00030
00031
00032 timeoutTimer = new QTimer( this );
00033 connect( timeoutTimer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) );
00034
00035 init();
00036
00037 }
00038
00039 Account::~Account()
00040 {
00041 delete mails;
00042 if( !socket.isNull() ) delete socket;
00043 }
00044
00045 QString Account::getName() const
00046 {
00047 return name;
00048 }
00049
00050 void Account::print() const
00051 {
00052
00053 cout << getName().toStdString() << endl;
00054 cout << "====================" << endl;
00055 cout << "Active: " << isActive() << endl;
00056 cout << "Host: " << url.host().toStdString() << endl;
00057 cout << "Port: " << url.port() << endl;
00058 cout << "User: " << url.user().toStdString() << endl;
00059 cout << "Password: " << url.password().toStdString() << endl;
00060
00061
00062
00063 mails->print();
00064 }
00065
00066 void Account::init()
00067 {
00068
00069 active = true;
00070
00071
00072 state = AccountIdle;
00073
00074
00075 nmbDeletedMailsLastRefresh = 0;
00076 nmbMovedMailsLastRefresh = 0;
00077 nmbIgnoredMails = 0;
00078 moveCounter = 0;
00079 nmbDeletedMailsLastStart = 0;
00080 nmbMovedMailsLastStart = 0;
00081 nmbIgnoredMails = 0;
00082
00083 downloadActionsInvoked = false;
00084 deletionPerformedByFilters = false;
00085 filterApplied = false;
00086
00087
00088 dontHandleError = false;
00089
00090 }
00091
00092 bool Account::isActive( ) const
00093 {
00094 return active;
00095 }
00096
00097 void Account::setActive(bool active) {
00098 this->active = active;
00099 }
00100
00101 void Account::load()
00102 {
00103 KConfigGroup* accountConfig = new KConfigGroup( KGlobal::config(), getName() );
00104
00105 setHost( accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_SERVER, DEFAULT_ACCOUNT_SERVER ) );
00106 setProtocol( accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_PROTOCOL, DEFAULT_ACCOUNT_PROTOCOL ) );
00107 setPort( accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_PORT, DEFAULT_ACCOUNT_PORT_POP3 ) );
00108 setUser( accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_USER, DEFAULT_ACCOUNT_USER ) );
00109 passwordStorage = accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_PASSWORD_STORAGE, DEFAULT_ACCOUNT_PASSWORD_STORAGE );
00110
00111 if( passwordStorage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_FILE )
00112 setPassword( decrypt( accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_PASSWORD, DEFAULT_ACCOUNT_PASSWORD ) ) );
00113 else if( passwordStorage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_KWALLET )
00114 setPassword( KWalletAccess::getPassword( getName() ) );
00115 else
00116 setPassword( QString() );
00117
00118 active = accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_ACTIVE, DEFAULT_ACCOUNT_ACTIVE );
00119
00120 int intTransferSecurity = accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_SECTRANSFER, DEFAULT_ACCOUNT_SECTRANSFER );
00121 if( intTransferSecurity == CONFIG_VALUE_ACCOUNT_SECTRANSFER_NONE )
00122 transferSecurity = TransSecNone;
00123 else if( intTransferSecurity == CONFIG_VALUE_ACCOUNT_SECTRANSFER_SSL )
00124 transferSecurity = TransSecSSL;
00125 else if( intTransferSecurity == CONFIG_VALUE_ACCOUNT_SECTRANSFER_TLS )
00126 transferSecurity = TransSecTLS;
00127 else
00128 transferSecurity = TransSecNone;
00129
00130 allowUnsecureLogin = accountConfig->readEntry( CONFIG_ENTRY_ACCOUNT_ALLOW_UNSECURE_LOGIN, DEFAULT_ACCOUNT_ALLOW_UNSECURE_LOGIN );
00131
00132
00133 KConfigGroup* spamConfig = new KConfigGroup( KGlobal::config(), CONFIG_GROUP_SPAMCHECK );
00134 int intSpamAction = spamConfig->readEntry( CONFIG_ENTRY_SPAMCHECK_ACTION, DEFAULT_SPAMCHECK_ACTION );
00135
00136 switch( intSpamAction )
00137 {
00138 case CONFIG_VALUE_SPAMCHECK_ACTION_DELETE : spamAction = FActDelete; break;
00139 case CONFIG_VALUE_SPAMCHECK_ACTION_MARK : spamAction = FActMark; break;
00140 case CONFIG_VALUE_SPAMCHECK_ACTION_MOVE : spamAction = FActMove; break;
00141 default :
00142 kdError() << "Invalid value in " << CONFIG_ENTRY_SPAMCHECK_ACTION << ". Set default value." << endl;
00143 switch( DEFAULT_SPAMCHECK_ACTION )
00144 {
00145 case CONFIG_VALUE_SPAMCHECK_ACTION_DELETE : spamAction = FActDelete; break;
00146 case CONFIG_VALUE_SPAMCHECK_ACTION_MARK : spamAction = FActMark; break;
00147 case CONFIG_VALUE_SPAMCHECK_ACTION_MOVE : spamAction = FActMove; break;
00148 default : spamAction = FActMark; break;
00149 }
00150
00151 }
00152
00153 if( spamAction == FActMove )
00154 spamMailbox = spamConfig->readEntry( CONFIG_ENTRY_SPAMCHECK_MOVE_MAILBOX, DEFAULT_SPAMCHECK_ACTION_MOVE_MAILBOX );
00155
00156
00157 KConfigGroup* generalConfig = new KConfigGroup( KGlobal::config(), CONFIG_GROUP_GENERAL );
00158 informAboutErrors = generalConfig->readEntry( CONFIG_ENTRY_SHOW_CONNECTION_ERRORS, DEFAULT_SHOW_CONNECTION_ERRORS );
00159 timeOutTime = generalConfig->readEntry( CONFIG_ENTRY_TIMEOUT_TIME, DEFAULT_TIMEOUT_TIME );
00160
00161 delete accountConfig;
00162 delete spamConfig;
00163 delete generalConfig;
00164 }
00165
00166 void Account::refreshMailList( FilterLog* log )
00167 {
00168
00169 if( log != NULL )
00170 fLog = log;
00171
00172
00173 if( !isActive() )
00174 {
00175 emit sigRefreshReady( getName() );
00176 return;
00177 }
00178
00179
00180
00181
00182 if( !assertPassword() )
00183 {
00184 emit sigRefreshReady( name );
00185 kdDebug() << "No Password" << endl;
00186 return;
00187 }
00188
00189 kdDebug() << "refresh " << getName() << endl;
00190
00191
00192 state = AccountRefreshing;
00193
00194
00195
00196
00197 tempMailList = new MailList( this, this );
00198
00199
00200 if( !refreshPerformedByFilters )
00201 {
00202 nmbDeletedMailsLastRefresh = 0;
00203 nmbMovedMailsLastRefresh = 0;
00204 nmbIgnoredMails = 0;
00205 }
00206
00207
00208
00209 doConnect();
00210
00211 }
00212
00213 bool Account::hasPassword( ) const
00214 {
00215 return url.hasPass();
00216 }
00217
00218 QString Account::getPassword( ) const
00219 {
00220 return url.pass();
00221 }
00222
00223 void Account::setPassword( const QString& password )
00224 {
00225 url.setPass( password );
00226 }
00227
00228 void Account::setHost( const QString& host )
00229 {
00230 url.setHost( host );
00231 }
00232
00233 void Account::setProtocol( const QString& protocol )
00234 {
00235 url.setProtocol( protocol );
00236 }
00237
00238 void Account::setPort( unsigned short int port )
00239 {
00240 url.setPort( port );
00241 }
00242
00243 void Account::setUser( const QString & user )
00244 {
00245 url.setUser( user );
00246 }
00247
00248 QString Account::getUser( ) const
00249 {
00250 return url.user();
00251 }
00252
00253 QString Account::getHost( ) const
00254 {
00255 return url.host();
00256 }
00257
00258 QString Account::getProtocol( bool upperCase ) const
00259 {
00260 if( upperCase )
00261 return url.protocol().toUpper();
00262 else
00263 return url.protocol();
00264 }
00265
00266 unsigned short int Account::getPort( ) const
00267 {
00268 return url.port();
00269 }
00270
00271 bool Account::assertPassword( bool force )
00272 {
00273
00274 if ( !hasPassword() || force )
00275 {
00276
00277
00278 while( QApplication::overrideCursor() )
00279 QApplication::restoreOverrideCursor();
00280
00281
00282 QPointer<KPasswordDialog> pwdialog = new KPasswordDialog( NULL );
00283 pwdialog->setPrompt( i18nc( "@info we need the password", "Please type in the password for <resource>%1</resource>", getName() ) );
00284 int result = pwdialog->exec();
00285
00286
00287
00288 QApplication::setOverrideCursor( Qt::WaitCursor );
00289
00290
00291 if( result == KPasswordDialog::Accepted )
00292 {
00293
00294
00295 setPassword( pwdialog->password() );
00296
00297
00298 KConfigGroup* accountConfig = new KConfigGroup( KGlobal::config(), getName() );
00299
00300 if( passwordStorage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_FILE )
00301 accountConfig->writeEntry( CONFIG_ENTRY_ACCOUNT_PASSWORD, crypt( url ) );
00302 else
00303 accountConfig->writeEntry( CONFIG_ENTRY_ACCOUNT_PASSWORD, "" );
00304
00305 if( passwordStorage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_KWALLET )
00306 {
00307 KWalletAccess::savePassword( getName(), url.pass() );
00308 }
00309
00310 accountConfig->sync();
00311
00312 delete accountConfig;
00313 delete pwdialog;
00314
00315
00316 emit ( sigConfigChanged() );
00317
00318
00319 return true;
00320 }
00321 else {
00322
00323 delete pwdialog;
00324 return false;
00325 }
00326 }
00327 else
00328
00329 return true;
00330
00331 }
00332
00333 void Account::setPasswordStorage( int storage )
00334 {
00335 if( storage == CONFIG_VALUE_ACCOUNT_PASSWORD_DONT_SAVE ||
00336 storage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_FILE ||
00337 storage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_KWALLET )
00338
00339 passwordStorage = storage;
00340
00341 else
00342
00343 passwordStorage = DEFAULT_ACCOUNT_PASSWORD_STORAGE;
00344 }
00345
00346 int Account::getPasswordStorage( ) const
00347 {
00348 return passwordStorage;
00349 }
00350
00351 void Account::doConnect()
00352 {
00353
00354 if( !socket.isNull() ) {
00355
00356 if( socket->state() != KTcpSocket::UnconnectedState )
00357 {
00358 closeConnection();
00359 }
00360
00361 }
00362
00363
00364 initBeforeConnect();
00365
00366
00367 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
00368 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotReadFirstServerMessage() ) );
00369
00370
00371 if( transferSecurity == TransSecNone || transferSecurity == TransSecTLS ) {
00372
00373 socket->connectToHost( getHost(), getPort() );
00374
00375 } else if( transferSecurity == TransSecSSL ) {
00376
00377 socket->connectToHostEncrypted( getHost(), getPort() );
00378
00379
00380 } else {
00381
00382 handleError( "Unsupported Transfer Security" );
00383 return;
00384 }
00385 }
00386
00387 void Account::closeConnection()
00388 {
00389 if( socket->state() != KTcpSocket::UnconnectedState && socket->state() != KTcpSocket::ClosingState )
00390 {
00391 kdDebug() << "Close Connection: " << getName() << endl;
00392
00393 socket->flush();
00394 socket->disconnectFromHost();
00395 if( socket->state() != KTcpSocket::UnconnectedState )
00396 socket->waitForDisconnected();
00397 socket->reset();
00398
00399
00400 int nrTry = 0;
00401 while( nrTry < 5 && socket->state() != KTcpSocket::UnconnectedState ) {
00402 socket->close();
00403 nrTry++;
00404 }
00405 }
00406 }
00407
00408 void Account::initBeforeConnect()
00409 {
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 if( socket.isNull() )
00426 socket = new KTcpSocket( this );
00427
00428
00429 connect( socket, SIGNAL( error( KTcpSocket::Error ) ), this, SLOT( slotSocketError( KTcpSocket::Error ) ) );
00430 connect( socket, SIGNAL( connected() ), this, SLOT( slotConnected() ) );
00431 connect( socket, SIGNAL( hostFound() ), this, SLOT( slotHostFound() ) );
00432 connect( socket, SIGNAL( sslErrors(QList<KSslError>) ), this, SLOT( slotSSLError(QList<KSslError>) ) );
00433
00434
00435 quitSent = false;
00436 apopAvail = false;
00437 dontUseAPOP = false;
00438
00439 downloadActionsInvoked = false;
00440 deletionPerformedByFilters = false;
00441 filterApplied = false;
00442
00443 dontHandleError = false;
00444
00445
00446 supportsStartTLS = false;
00447
00448
00449 timeoutTimer->start( timeOutTime * 1000 );
00450
00451 }
00452
00453 void Account::slotConnected()
00454 {
00455 }
00456
00457 void Account::slotHostFound()
00458 {
00459 }
00460
00461 void Account::slotSocketError( KTcpSocket::Error errorCode)
00462 {
00463
00464 if( dontHandleError ) return;
00465
00466
00467 QString message;
00468 switch( errorCode )
00469 {
00470 case KTcpSocket::UnknownError : message = i18nc( "@info error message", "Unknown error" ); break;
00471 case KTcpSocket::ConnectionRefusedError : message = i18nc( "@info error message", "Connection refused" ); break;
00472 case KTcpSocket::HostNotFoundError : message = QString( i18nc( "@info error message", "Host not found: <resource>%1</resource>", getHost() ) ); break;
00473 case KTcpSocket::RemoteHostClosedError : message = QString( i18nc( "@info error message", "Host <resource>%1</resource> closed", getHost() ) ); break;
00474 case KTcpSocket::SocketAccessError : message = i18nc( "@info error message", "Socket access error" ); break;
00475 case KTcpSocket::SocketResourceError : message = i18nc( "@info error message", "Socket resource error" ); break;
00476 case KTcpSocket::SocketTimeoutError : message = i18nc( "@info error message", "Socket timeout error" ); break;
00477 case KTcpSocket::NetworkError : message = i18nc( "@info error message", "Network error" ); break;
00478 case KTcpSocket::UnsupportedSocketOperationError : message = i18nc( "@info error message", "Unsupported Socket Operation Error" ); break;
00479 default : message = i18nc( "@info error message", "Unknown connection error" ); break;
00480 }
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 handleError( message );
00511
00512 }
00513
00514 void Account::handleError( QString error )
00515 {
00516
00517
00518 closeConnection();
00519
00520
00521 timeoutTimer->stop();
00522
00523
00524 if( informAboutErrors ) {
00525
00526 emit sigMessageWindowOpened();
00527 KMessageBox::error( NULL, i18nc( "@info general error message", "Account <resource>%1</resource>: %2", getName(), error ) );
00528 emit sigMessageWindowClosed();
00529 }
00530
00531
00532 AccountState_Type oldState = state;
00533 state = AccountIdle;
00534
00535
00536 mailsToDelete.clear();
00537 mailsToDownload.clear();
00538 mailsToShow.clear();
00539
00540
00541 switch( oldState )
00542 {
00543 case AccountDeleting : emit sigDeleteReady( getName() ); break;
00544 case AccountDownloading : emit sigShowBodiesReady( getName() ); break;
00545 case AccountRefreshing : emit sigRefreshReady( getName() ); break;
00546 default : break;
00547 }
00548
00549
00550
00551 }
00552
00553 QStringList Account::readfromSocket( bool singleLine )
00554 {
00555 QString readed;
00556 bool responseEndFound = false;
00557
00558
00559 QString lineTerm( 13 );
00560 lineTerm.append( 10 );
00561
00562
00563
00564 QString endOfMultiLine( lineTerm );
00565 endOfMultiLine.append( END_MULTILINE_RESPONSE );
00566 endOfMultiLine.append( lineTerm );
00567
00568
00569
00570
00571 while( !responseEndFound ) {
00572
00573
00574 if( socket->bytesAvailable() == 0 ) {
00575
00576
00577
00578
00579
00580
00581
00582
00583 if( transferSecurity == TransSecSSL || transferSecurity == TransSecTLS ) {
00584
00585 dontHandleError = true;
00586 if( !socket->waitForReadyRead( 500 ) ) {
00587
00588 QByteArray toWrite( "NOOP\n" );
00589 socket->write( toWrite );
00590
00591 dontHandleError = false;
00592 if( !socket->waitForReadyRead() ) {
00593
00594 return QStringList();
00595 }
00596
00597 }
00598 dontHandleError = false;
00599
00600 } else {
00601
00602 if( !socket->waitForReadyRead() )
00603 {
00604 return QStringList();
00605 }
00606 }
00607
00608
00609
00610 }
00611
00612
00613 QByteArray data = socket->readAll();
00614
00615
00616 if( data.size() > 0 ) {
00617 readed.append( data );
00618 }
00619
00620
00621
00622
00623 if( isNegativeResponse( readed ) )
00624 {
00625 responseEndFound = true;
00626 }
00627
00628 else if( readed.endsWith( endOfMultiLine ) )
00629 {
00630 responseEndFound = true;
00631 }
00632
00633 else
00634 {
00635
00636 if( singleLine && readed.endsWith( lineTerm ) ) responseEndFound = true;
00637 }
00638
00639
00640 }
00641
00642
00643
00644 QStringList response = readed.split( lineTerm );
00645
00646
00647
00648
00649
00650 if( response.last().isEmpty() ) {
00651
00652 response.removeLast();
00653 }
00654
00655
00656 return response;
00657
00658
00659 }
00660
00661 void Account::slotReadFirstServerMessage()
00662 {
00663 QStringList text = readfromSocket( true );
00664
00665
00666
00667 if( text.isEmpty() )
00668 {
00669 finishTask();
00670 return;
00671 }
00672
00673
00674 if( !isPositiveServerMessage( text ) )
00675 {
00676
00677
00678 handleError( i18nc( "@info error message: this is not a POP3 server", "<resource>%1</resource> is not a POP3 mail server", getHost() ) );
00679 return;
00680 }
00681
00682
00683 QString response = text.first();
00684
00685
00686 QRegExp regEx( "<.*>" );
00687 if( regEx.indexIn( response ) != -1 )
00688 {
00689
00690 apopAvail = true;
00691
00692 apopTimestamp = regEx.cap();
00693 }
00694
00695
00696 getCapabilities();
00697 }
00698
00699 void Account::sendCommand( const QString& command )
00700 {
00701 kdDebug() << "Send " << command << " to " << getName() << endl;
00702
00703
00704 if( socket->state() != KTcpSocket::ConnectedState )
00705 {
00706 handleError( i18nc( "@info error message: connection lost", "No connect to <resource>%1</resource>", getHost() ) );
00707 return;
00708 }
00709
00710
00711 QByteArray data;
00712 data.append( command );
00713 data.append( "\r\n" );
00714
00715
00716
00717 qint64 writtenBytes = socket->write( data.data() );
00718
00719
00720 if( writtenBytes == -1 )
00721 {
00722 handleError( i18nc( "@info error message: could not send a command to the server", "Could not send the command <icode>%1</icode> to <resource>%2</resource>", command, getName() ) );
00723 return;
00724 }
00725
00726 }
00727
00728 void Account::getCapabilities()
00729 {
00730
00731 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
00732 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotCapabilitiesResponse() ) );
00733
00734
00735 sendCommand( CAPA_REQUEST );
00736 }
00737
00738 void Account::slotCapabilitiesResponse()
00739 {
00740
00741
00742 QStringList text = readfromSocket( false );
00743
00744
00745
00746
00747 if( text.isEmpty() )
00748 {
00749 finishTask();
00750 return;
00751 }
00752
00753
00754
00755 bool haveCapa = isPositiveServerMessage( text );
00756
00757
00758 if( haveCapa )
00759 {
00760
00761 removeStatusIndicator( &text );
00762 removeEndOfResponseMarker( &text );
00763
00764
00765 supportsStartTLS = text.contains( CAPA_RESPONSE_STLS, Qt::CaseInsensitive );
00766
00767
00768
00769 if( transferSecurity == TransSecTLS && !supportsStartTLS ) {
00770
00771 handleError( i18nc( "@info error message", "No support for START-TLS" ) );
00772 return;
00773 }
00774
00775 }
00776
00777
00778
00779 getAuthMech();
00780
00781 }
00782
00783 void Account::printServerMessage( QStringList& text ) const
00784 {
00785 if( text.isEmpty() )
00786 {
00787 kdDebug() << "empty server message" << endl;
00788 }
00789 else
00790 {
00791 for( int i = 0; i < text.size(); ++i )
00792 {
00793 kdDebug() << text.at( i ) << endl;
00794 }
00795 }
00796 }
00797
00798 bool Account::isPositiveServerMessage( QStringList& message ) const
00799 {
00800
00801 if( message.isEmpty() ) return false;
00802
00803
00804 if( message.first().startsWith( RESPONSE_POSITIVE ) ) return true;
00805
00806
00807 return false;
00808 }
00809
00810 void Account::getAuthMech()
00811 {
00812
00813 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
00814 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotAuthMechResponse() ) );
00815
00816
00817 sendCommand( AUTH_REQUEST );
00818 }
00819
00820 void Account::slotAuthMechResponse()
00821 {
00822
00823 QStringList text = readfromSocket( false );
00824
00825
00826
00827 if( text.isEmpty() )
00828 {
00829 finishTask();
00830 return;
00831 }
00832
00833
00834 bool haveAuth = isPositiveServerMessage( text );
00835
00836
00837 if( haveAuth )
00838 {
00839
00840 removeStatusIndicator( &text );
00841 removeEndOfResponseMarker( &text );
00842 }
00843
00844
00845
00846
00847
00848
00849 if( supportsStartTLS && transferSecurity == TransSecTLS ) {
00850
00851 startTLS();
00852 return;
00853
00854 } else if( transferSecurity == TransSecSSL ) {
00855
00856 loginUser();
00857 return;
00858
00859 } else if( apopAvail && !dontUseAPOP )
00860 loginApop();
00861 else
00862 {
00863 if( allowUnsecureLogin == true )
00864 loginUser();
00865 else
00866 {
00867 emit sigMessageWindowOpened();
00868 KMessageBox::sorry( NULL, i18nc( "@info Warning: the server does'nt support secure login", "Account <resource>%1</resource>: This server doesn't provide a safety login and you have disallowed the using of an unsafe login. If you want to use this Account you must allow unsafe login at the account setup.<nl/><warning>Bear in mind, in this case criminals could read your password!</warning>", getName() ), i18nc( "@title:window", "Unsafe login is not allowed") );
00869 emit sigMessageWindowClosed();
00870
00871
00872 finishTask();
00873
00874 }
00875 }
00876
00877 }
00878
00879 void Account::commit()
00880 {
00881 if( socket->state() == KTcpSocket::ConnectedState )
00882 {
00883
00884 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
00885 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotCommitResponse() ) );
00886
00887
00888
00889 quitSent = true;
00890
00891
00892 sendCommand( COMMIT );
00893 }
00894 else
00895 {
00896 finishTask();
00897 }
00898 }
00899
00900 void Account::finishTask()
00901 {
00902
00903 timeoutTimer->stop();
00904
00905
00906 closeConnection();
00907
00908
00909 Types::AccountState_Type oldState = state;
00910 state = AccountIdle;
00911
00912
00913 switch( oldState )
00914 {
00915 case AccountDeleting : emit sigDeleteReady( getName() ); break;
00916 case AccountDownloading : emit sigShowBodiesReady( getName() ); break;
00917 case AccountRefreshing : emit sigRefreshReady( getName() ); break;
00918 default : break;
00919 }
00920
00921
00922 mailsToDelete.clear();
00923 mailsToDownload.clear();
00924 mailsToShow.clear();
00925
00926 }
00927
00928 void Account::slotCommitResponse()
00929 {
00930
00931 QStringList response = readfromSocket( true );
00932
00933
00934
00935 if( response.isEmpty() )
00936 {
00937 finishTask();
00938 return;
00939 }
00940
00941 if( !isPositiveServerMessage( response ) )
00942 {
00943
00944 handleError( i18nc( "@info error message: we could not quit the POP3 session", "<resource>%1</resource> has not accepted the <icode>%2</icode> command. Error message is: <message>%3</message>", getHost(), COMMIT, response.first() ) );
00945 return;
00946 }
00947
00948 finishTask();
00949 }
00950
00951 void Account::loginUser()
00952 {
00953
00954 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
00955 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotLoginUserResponse() ) );
00956
00957
00958 sendCommand( LOGIN_USER + ' ' + getUser() );
00959 }
00960
00961 void Account::slotLoginUserResponse()
00962 {
00963
00964 QStringList response = readfromSocket( true );
00965
00966
00967
00968 if( response.isEmpty() )
00969 {
00970 finishTask();
00971 return;
00972 }
00973
00974 if( !isPositiveServerMessage( response ) )
00975 {
00976
00977 handleError( i18nc( "@info error message", "Login has failed. Maybe your user name is invalid. Error message is: <message>%1</message>", removeStatusIndicator( response.first() ) ) );
00978
00979 load();
00980
00981 return;
00982 }
00983
00984
00985 loginPasswd();
00986 }
00987
00988 void Account::loginPasswd()
00989 {
00990
00991 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
00992 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotLoginPasswdResponse() ) );
00993
00994
00995 sendCommand( LOGIN_PASSWD + ' ' + getPassword() );
00996 }
00997
00998 void Account::slotLoginPasswdResponse()
00999 {
01000
01001 QStringList response = readfromSocket( true );
01002
01003
01004
01005 if( response.isEmpty() )
01006 {
01007 finishTask();
01008 return;
01009 }
01010
01011 if( !isPositiveServerMessage( response ) )
01012 {
01013
01014 handleError( i18nc( "@info error message", "Login has failed. Maybe your user name or password is invalid. Error message is: <message>%1</message>", removeStatusIndicator( response.first() ) ) );
01015
01016 load();
01017 return;
01018 }
01019
01020
01021 switch( getState() )
01022 {
01023 case AccountRefreshing : getUIDList(); break;
01024 case AccountDeleting : deleteNextMail(); break;
01025 case AccountDownloading : showNextMail(); break;
01026 default : commit(); break;
01027 }
01028 }
01029
01030 QString Account::removeStatusIndicator(const QString & message)
01031 {
01032 QString ret( message );
01033
01034 if( ret.startsWith( RESPONSE_POSITIVE ) )
01035 {
01036 return ret.remove( 0, RESPONSE_POSITIVE.length() );
01037 }
01038 else if( ret.startsWith( RESPONSE_NEGATIVE ) )
01039 {
01040 return ret.remove( 0, RESPONSE_NEGATIVE.length() );
01041 }
01042
01043 return ret;
01044 }
01045
01046
01047
01048
01049 void Account::loginApop()
01050 {
01051
01052 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
01053 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotLoginApopResponse() ) );
01054
01055
01056 QString secret( apopTimestamp + getPassword() );
01057 KMD5 md5( secret.toAscii() );
01058 QString md5Digest( md5.hexDigest() );
01059
01060
01061 sendCommand( LOGIN_APOP + ' ' + getUser() + ' ' + md5Digest );
01062 }
01063
01064 void Account::slotLoginApopResponse()
01065 {
01066
01067 QStringList response = readfromSocket( true );
01068
01069
01070
01071 if( response.isEmpty() )
01072 {
01073 finishTask();
01074 return;
01075 }
01076
01077 if( !isPositiveServerMessage( response ) )
01078 {
01079
01080 if( allowUnsecureLogin )
01081 {
01082
01083 closeConnection();
01084 dontUseAPOP = true;
01085 doConnect();
01086 return;
01087 }
01088 else
01089 {
01090 handleError( i18nc( "@info error message", "Login has failed. Maybe your user name or password is invalid. Error message is: <message>%1</message><nl/>Maybe the secure login of this server is faulty. You can try to allow the unsafe login for this account at the account setup.<nl/><warning>Bear in mind, in this case criminals could read your password!</warning>", removeStatusIndicator( response.first() ) ) );
01091
01092 load();
01093 return;
01094 }
01095 }
01096
01097
01098 switch( getState() )
01099 {
01100 case AccountRefreshing : getUIDList(); return;
01101 case AccountDeleting : deleteNextMail(); return;
01102 case AccountDownloading : showNextMail(); return;
01103 default : commit(); return;
01104 }
01105
01106 }
01107
01108 void Account::removeStatusIndicator( QStringList* response )
01109 {
01110
01111 if( response->isEmpty() ) return;
01112
01113
01114 QString firstLine = response->first();
01115
01116
01117
01118 while( firstLine.startsWith( RESPONSE_POSITIVE ) || firstLine.startsWith( RESPONSE_NEGATIVE ) )
01119 {
01120
01121 response->pop_front();
01122
01123 firstLine = response->first();
01124 }
01125 }
01126
01127 Types::AccountState_Type Account::getState()
01128 {
01129 return state;
01130 }
01131
01132 bool Account::isUnsecureLoginAllowed() const
01133 {
01134 return allowUnsecureLogin;
01135 }
01136
01137 void Account::getUIDList()
01138 {
01139
01140 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
01141 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotUIDListResponse() ) );
01142
01143
01144 sendCommand( UID_LIST );
01145 }
01146
01147 void Account::slotUIDListResponse()
01148 {
01149 kdDebug() << "slotUIDListRespones" << endl;
01150
01151
01152 QStringList receivedUIDs = readfromSocket( false );
01153
01154
01155
01156 if( receivedUIDs.isEmpty() )
01157 {
01158 finishTask();
01159 return;
01160 }
01161
01162
01163 if( !isPositiveServerMessage( receivedUIDs ) )
01164 {
01165 handleError( i18nc( "@info error message: a server doesn't support mail UIDs", "<resource>%1</resource> doesn't support mail UID's. KShowmail can't work without this. Error message is: <message>%2</message>", getName(), receivedUIDs.first() ) );
01166 return;
01167 }
01168
01169
01170
01171
01172 removeStatusIndicator( &receivedUIDs );
01173 removeEndOfResponseMarker( &receivedUIDs );
01174
01175
01176 if( receivedUIDs.isEmpty() )
01177 {
01178
01179
01180 swapMailLists();
01181 return;
01182 }
01183
01184
01185 long number;
01186 QString uid;
01187 bool isNew = false;
01188
01189
01190
01191 for ( QStringList::Iterator it = receivedUIDs.begin(); it != receivedUIDs.end(); ++it )
01192 {
01193 QString line = *it;
01194
01195
01196
01197 int positionOfSpace = line.indexOf( " " );
01198
01199
01200 if( positionOfSpace == -1 )
01201 {
01202 handleError( i18nc( "@info error message", "Get corrupt UID list. No spaces" ) );
01203 return;
01204 }
01205 else
01206 {
01207
01208 bool isNumber;
01209 number = line.left( positionOfSpace ).toLong( &isNumber );
01210
01211
01212 if( !isNumber )
01213 {
01214
01215 handleError( i18nc( "@info error message", "Get corrupt UID list. No number found at begin." ) );
01216 return;
01217 }
01218 else
01219 {
01220
01221 uid = line.mid( positionOfSpace + 1 );
01222
01223
01224 if( !mails->hasMail( uid ) )
01225 {
01226
01227
01228 isNew = true;
01229 }
01230 else if( ( accountList->keepNew() || refreshPerformedByFilters ) && mails->isNew( uid ) )
01231 {
01232
01233
01234 isNew = true;
01235 }
01236 else
01237 isNew = false;
01238
01239
01240 tempMailList->addMail( number, uid, isNew );
01241
01242 }
01243 }
01244 }
01245
01246
01247 getMailSizes();
01248 }
01249
01250 void Account::removeEndOfResponseMarker( QStringList * response )
01251 {
01252
01253 if( response->isEmpty() ) return;
01254
01255
01256 QString lastLine = response->last();
01257
01258
01259 if( lastLine == END_MULTILINE_RESPONSE )
01260 {
01261
01262 response->pop_back();
01263 }
01264
01265 }
01266
01267 void Account::swapMailLists( )
01268 {
01269
01270 delete mails;
01271
01272
01273 if( tempMailList != NULL )
01274 mails = tempMailList;
01275 else
01276 mails = new MailList( this, this );
01277
01278 refreshPerformedByFilters = false;
01279
01280
01281
01282
01283
01284 if( filterApplied | !headerFilter.isActive() )
01285 {
01286
01287 filterApplied = false;
01288
01289
01290 commit();
01291 return;
01292 }
01293 else
01294 {
01295
01296 applyFilters();
01297 return;
01298 }
01299
01300 commit();
01301 }
01302
01303 void Account::applyFilters()
01304 {
01305
01306 if( !downloadActionsInvoked )
01307 {
01308
01309
01310
01311
01312 filterApplied = true;
01313
01314
01315
01316
01317
01318 mailsToDelete.clear();
01319 mails->applyHeaderFilter( &headerFilter, getName(), mailsToDelete, mailsToDownload, nmbIgnoredMails, fLog );
01320 nmbDeletedMailsLastRefresh += mailsToDelete.count();
01321 nmbDeletedMailsLastStart += mailsToDelete.count();
01322
01323
01324 if( !mailsToDownload.empty() )
01325 {
01326 downloadActionsInvoked = true;
01327 doDownloadActions();
01328
01329
01330
01331 return;
01332 }
01333
01334 }
01335 else
01336 {
01337
01338
01339
01340
01341 downloadActionsInvoked = false;
01342
01343
01344 mailsToDownload.clear();
01345 }
01346
01347
01348
01349
01350
01351
01352 if( !mailsToDelete.empty() )
01353 {
01354
01355
01356
01357 deletionPerformedByFilters = true;
01358
01359 deleteNextMail();
01360 }
01361 else
01362 {
01363
01364
01365 commit();
01366 filterApplied = false;
01367 }
01368 }
01369
01370 void Account::getMailSizes()
01371 {
01372
01373 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
01374 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotMailSizesResponse() ) );
01375
01376
01377 sendCommand( MAIL_LIST );
01378 }
01379
01380 void Account::slotMailSizesResponse()
01381 {
01382
01383
01384 QStringList receivedSizes = readfromSocket( false );
01385
01386
01387
01388 if( receivedSizes.isEmpty() )
01389 {
01390 finishTask();
01391 return;
01392 }
01393
01394
01395 if( receivedSizes.isEmpty() )
01396 {
01397 handleError( i18nc( "@info error message: a server has not send a response", "<resource>%1</resource> has not sent a response after <icode>%2</icode> command.", getHost(), MAIL_LIST ) );
01398 return;
01399 }
01400
01401
01402 if( !isPositiveServerMessage( receivedSizes ) )
01403 {
01404 handleError( i18nc( "@info error message: a server has not send the mail sizes", "Error while trying to get the mail sizes. Message is: <message>%1</message>", receivedSizes.first() ) );
01405 return;
01406 }
01407
01408
01409
01410
01411 removeStatusIndicator( &receivedSizes );
01412 removeEndOfResponseMarker( &receivedSizes );
01413
01414
01415 int number;
01416 long size;
01417
01418
01419 if( receivedSizes.isEmpty() )
01420 {
01421 handleError( i18nc( "@info error message", "Error while trying to get the mail sizes. All mails are disappeard." ) );
01422 return;
01423 }
01424
01425
01426 for ( QStringList::Iterator it = receivedSizes.begin(); it != receivedSizes.end(); ++it )
01427 {
01428 QString line = *it;
01429
01430
01431
01432 int positionOfSpace = line.indexOf( " " );
01433
01434
01435 if( positionOfSpace == -1 )
01436 {
01437 handleError( i18nc( "@info error message", "Get corrupt size list. No spaces" ) );
01438 return;
01439 }
01440 else
01441 {
01442
01443 bool isNumber;
01444 number = line.left( positionOfSpace ).toInt( &isNumber );
01445
01446 if( !isNumber )
01447 {
01448
01449 handleError( i18nc( "@info error message", "Get corrupt size list. No numbers at begin." ) );
01450 return;
01451 }
01452 else
01453 {
01454
01455 size = line.mid( positionOfSpace + 1 ).toLong( &isNumber );
01456
01457
01458 if( !isNumber )
01459 {
01460
01461 handleError( i18nc( "@info error message", "Get corrupt size list. No sizes found at end." ) );
01462 return;
01463 }
01464 else
01465 {
01466
01467
01468 tempMailList->setSize( number, size );
01469 }
01470 }
01471 }
01472 }
01473
01474
01475 getHeaders();
01476 }
01477
01478 void Account::getHeaders( )
01479 {
01480
01481 newMails = tempMailList->getNewMails();
01482 if( newMails.empty() )
01483 {
01484
01485 copyHeaders();
01486 return;
01487 }
01488
01489
01490 getNextHeader();
01491 }
01492
01493 void Account::getNextHeader( )
01494 {
01495
01496 if( newMails.empty() )
01497 {
01498 copyHeaders();
01499 return;
01500 }
01501
01502
01503 QString mailNumber;
01504 mailNumber = mailNumber.setNum( *newMails.begin() );
01505
01506
01507 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
01508 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotGetHeaderResponse() ) );
01509
01510
01511 sendCommand( GET_HEADER + ' ' + mailNumber + " 0" );
01512 }
01513
01514 void Account::slotGetHeaderResponse( )
01515 {
01516
01517 int mailNumber = *newMails.begin();
01518
01519
01520 QStringList header = readfromSocket( false );
01521
01522
01523 if( header.isEmpty() )
01524 {
01525 handleError( i18nc( "@info error message: could not get a mail header", "<resource>%1</resource> has not sent the header of mail <numid>%2</numid>.", getHost(), mailNumber ) );
01526 finishTask();
01527 return;
01528 }
01529
01530
01531 if( !isPositiveServerMessage( header ) )
01532 {
01533 handleError( i18nc( "@info error message: a server doesn't know the command TOP", "<resource>%1</resource> doesn't support the TOP command. KShowmail can't work without this. Error message is: <message>%2</message>", getName(), header.first() ) );
01534 return;
01535 }
01536
01537
01538
01539
01540 removeStatusIndicator( &header );
01541 removeEndOfResponseMarker( &header );
01542
01543
01544 tempMailList->setHeader( *newMails.begin(), header );
01545
01546
01547 newMails.removeFirst();
01548
01549
01550 if( newMails.empty() )
01551 {
01552 copyHeaders();
01553 return;
01554 }
01555
01556
01557 getNextHeader();
01558 }
01559
01560 bool Account::isNegativeResponse(const QString & response)
01561 {
01562 return response.startsWith( RESPONSE_NEGATIVE );
01563
01564 }
01565
01566 void Account::copyHeaders( )
01567 {
01568
01569 QStringList UIDs = tempMailList->getUIDsOfOldMails();
01570
01571 try
01572 {
01573
01574
01575 QStringList::iterator it;
01576 for ( it = UIDs.begin(); it != UIDs.end(); ++it )
01577 {
01578 QStringList header = mails->getHeaderOf( *it );
01579 tempMailList->setHeader( *it, header );
01580 }
01581 }
01582 catch( CorruptDataException& e )
01583 {
01584 kdDebug() << "Fehler: " << e.what() << endl;
01585 }
01586
01587
01588 swapMailLists();
01589 }
01590
01591 int Account::getNumberMails() const
01592 {
01593 if( isActive() ) return mails->getNumberMails();
01594
01595 return 0;
01596 }
01597
01598 void Account::addMailToDelete( int number )
01599 {
01600 mailsToDelete.append( number );
01601 }
01602
01603 void Account::addMailToShow( int number )
01604 {
01605 mailsToShow.append( number );
01606 }
01607
01608 void Account::deleteMails()
01609 {
01610
01611 if( mailsToDelete.empty() )
01612 {
01613 emit sigDeleteReady( name );
01614 return;
01615 }
01616
01617
01618
01619
01620 if( !assertPassword() )
01621 {
01622 emit sigDeleteReady( name );
01623 return;
01624 }
01625
01626
01627 state = AccountDeleting;
01628
01629
01630 doConnect();
01631
01632 }
01633
01634 void Account::deleteNextMail( )
01635 {
01636
01637 if( mailsToDelete.empty() )
01638 {
01639 if( deletionPerformedByFilters )
01640 {
01641 applyFiltersDeleted();
01642 }
01643 else
01644 {
01645 commit();
01646 }
01647 return;
01648 }
01649
01650
01651 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
01652 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotMailDeleted() ) );
01653
01654
01655 sendCommand( DELETE + ' ' + QString( "%1" ).arg( mailsToDelete.first() ) );
01656 }
01657
01658 void Account::showNextMail()
01659 {
01660
01661 if( mailsToShow.isEmpty() )
01662 {
01663 commit();
01664 return;
01665 }
01666
01667
01668 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
01669 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotBodyDownloaded() ) );
01670
01671
01672 sendCommand( GET_MAIL + ' ' + QString( "%1" ).arg( mailsToShow.first() ) );
01673
01674 }
01675
01676 void Account::slotMailDeleted()
01677 {
01678
01679 QStringList answer = readfromSocket( true );
01680
01681
01682 if( answer.isEmpty() )
01683 {
01684 handleError( i18nc( "@info error message: no server responce after we have deleted a mail", "<resource>%1</resource> has not sent an answer after removing of mail <numid>%2</numid>.", getHost(), mailsToDelete.first() ) );
01685 finishTask();
01686 return;
01687 }
01688
01689
01690 if( !isPositiveServerMessage( answer ) )
01691 {
01692 handleError( i18nc( "@info error message: error while removing a mail", "Error while removing mail <numid>%1</numid> of <resource>%2</resource>: <message>%3</message>", mailsToDelete.first(), getName(), answer.first() ) );
01693 return;
01694 }
01695
01696
01697
01698 if( !deletionPerformedByFilters ) {
01699
01700 fLog->addDeletedMail( mails->getDateTimeOf( mailsToDelete.first() ),
01701 mails->getSenderOf( mailsToDelete.first() ),
01702 getName(),
01703 mails->getSubjectOf( mailsToDelete.first() ),
01704 DelManual
01705 );
01706 }
01707
01708
01709 mailsToDelete.removeFirst();
01710
01711
01712 if( mailsToDelete.empty() )
01713 {
01714 if( deletionPerformedByFilters )
01715 {
01716 applyFiltersDeleted();
01717 }
01718 else
01719 {
01720 commit();
01721 }
01722 return;
01723 }
01724
01725
01726 deleteNextMail();
01727
01728 }
01729
01730 void Account::slotBodyDownloaded()
01731 {
01732
01733 QStringList answer = readfromSocket( false );
01734
01735
01736 if( answer.isEmpty() )
01737 {
01738 handleError( i18nc( "@info error message: we could not download a mail", "<resource>%1</resource> has not sent an answer after retrieve of mail <numid>%2</numid>.", getHost(), mailsToShow.first() ) );
01739 finishTask();
01740 return;
01741 }
01742
01743
01744 if( !isPositiveServerMessage( answer ) )
01745 {
01746 handleError( i18nc( "@info error message: we could not download a mail", "Error while downloading mail <numid>%1</numid> of <resource>%2</resource>: <message>%3</message>", mailsToShow.first(), getName(), answer.first() ) );
01747 return;
01748 }
01749
01750
01751
01752
01753 removeStatusIndicator( &answer );
01754 removeEndOfResponseMarker( &answer );
01755
01756
01757
01758
01759
01760 KConfigGroup* configView = new KConfigGroup( KGlobal::config(), CONFIG_GROUP_VIEW );
01761 bool allowHTML = configView->readEntry( CONFIG_ENTRY_VIEW_USE_HTML, DEFAULT_VIEW_USE_HTML );
01762
01763
01764 int currentMail = mailsToShow.first();
01765
01766
01767 QString tsender = mails->getSenderOf( currentMail );
01768 QString tdate = mails->getDateOf( currentMail );
01769 QString tsize = mails->getSizeOf( currentMail );
01770 QString tsubject = mails->getSubjectOf( currentMail );
01771 bool isHTML;
01772 QStringList body = mails->decodeMailBody( answer, currentMail, allowHTML , isHTML );
01773
01774
01775
01776 emit sigMessageWindowOpened();
01777
01778
01779 timeoutTimer->stop();
01780
01781
01782 QPointer<ShowMailDialog> dlg = new ShowMailDialog( kapp->activeWindow(), getName(), allowHTML, isHTML, tsender, tdate, tsize, tsubject, body );
01783 int ret = dlg->exec();
01784
01785 delete dlg;
01786
01787
01788 emit sigMessageWindowClosed();
01789
01790
01791 timeoutTimer->start( timeOutTime * 1000 );
01792
01793
01794
01795 if( ret == KDialog::Rejected )
01796 {
01797 mailsToShow.clear();
01798 commit();
01799 return;
01800 }
01801
01802
01803 mailsToShow.removeFirst();
01804
01805
01806 if( mailsToShow.empty() )
01807 {
01808 commit();
01809 return;
01810 }
01811
01812
01813
01814 showNextMail();
01815 }
01816
01817 int Account::numberDeletedMailsLastRefresh( )
01818 {
01819 return nmbDeletedMailsLastRefresh;
01820 }
01821
01822 int Account::numberDeletedMailsStart( )
01823 {
01824 return nmbDeletedMailsLastStart;
01825 }
01826
01827 int Account::numberMovedMailsLastRefresh( )
01828 {
01829 return nmbMovedMailsLastRefresh;
01830 }
01831
01832 int Account::numberMovedMailsStart( )
01833 {
01834 return nmbMovedMailsLastStart;
01835 }
01836
01837 int Account::numberIgnoredMails( )
01838 {
01839 return nmbIgnoredMails;
01840 }
01841
01842 void Account::reloadFilterSettings( )
01843 {
01844 headerFilter.load();
01845 }
01846
01847 void Account::doDownloadActions()
01848 {
01849
01850 getNextMailForDownloadActions();
01851 }
01852
01853 void Account::getNextMailForDownloadActions()
01854 {
01855
01856 if( mailsToDownload.empty() )
01857 {
01858 applyFilters();
01859 return;
01860 }
01861
01862
01863
01864 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
01865 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotMailDownloadedForAction() ) );
01866
01867
01868 sendCommand( GET_MAIL + ' ' + QString( "%1" ).arg( mailsToDownload.begin().key() ) );
01869
01870 }
01871
01872 void Account::slotMailDownloadedForAction()
01873 {
01874
01875
01876 QStringList mail = readfromSocket( false );
01877
01878
01879 if( mail.isEmpty() )
01880 {
01881 handleError( i18nc( "@info error message: we could not download a mail", "<resource>%1</resource> has not sent an answer after retrieve of mail <numid>%2</numid>.", getHost(), mailsToShow.first() ) );
01882 finishTask();
01883 return;
01884 }
01885
01886
01887 if( !isPositiveServerMessage( mail ) )
01888 {
01889 handleError( i18nc( "@info error message: we could not download a mail", "Error while downloading mail <numid>%1</numid> of <resource>%2</resource>: <message>%3</message>", mailsToShow.first(), getName(), mail.first() ) );
01890 return;
01891 }
01892
01893
01894
01895
01896 removeStatusIndicator( &mail );
01897 removeEndOfResponseMarker( &mail );
01898
01899
01900
01901
01902 MailToDownloadMap_Type::Iterator firstMail = mailsToDownload.begin();
01903 int currentMailNumber = firstMail.key();
01904 QString currentMailBox( firstMail.value().mailbox );
01905
01906 FilterAction_Type action = firstMail.value().action;
01907
01908 bool resultMove = false;
01909 bool resultSpam = false;
01910 bool deleteIt = false;
01911 bool resultAction = false;
01912
01913 switch( action )
01914 {
01915 case FActMove : resultMove = writeToMailBox( mail, currentMailBox );
01916
01917 if( resultMove == true )
01918 {
01919 nmbMovedMailsLastRefresh++;
01920 nmbMovedMailsLastStart++;
01921
01922 resultAction = true;
01923 deleteIt = true;
01924 }
01925 else
01926 {
01927 resultAction = false;
01928 deleteIt = false;
01929 }
01930 break;
01931
01932 case FActSpamcheck : resultSpam = isSpam( mail );
01933 if( resultSpam == true )
01934 {
01935 switch( spamAction )
01936 {
01937 case FActMove : resultMove = writeToMailBox( mail, spamMailbox );
01938 if( resultMove == true )
01939 {
01940 nmbMovedMailsLastRefresh++;
01941 nmbMovedMailsLastStart++;
01942
01943 if( fLog != NULL )
01944 mails->writeToMoveLog( fLog, currentMailNumber, getName(), spamMailbox );
01945 resultAction = true;
01946 deleteIt = true;
01947 }
01948 else
01949 {
01950 resultAction = false;
01951 deleteIt = false;
01952 }
01953 break;
01954
01955 case FActMark : mails->setMarkAtNextViewRefresh( currentMailNumber );
01956 resultAction = true;
01957 deleteIt = false;
01958 break;
01959
01960 case FActDelete : if( fLog != NULL )
01961 mails->writeToDeleteLog( fLog, currentMailNumber, getName(), DelFilter );
01962
01963 nmbDeletedMailsLastRefresh++;
01964 nmbDeletedMailsLastStart++;
01965 resultAction = true;
01966 deleteIt = true;
01967 break;
01968
01969 default : kdError() << "invalid action for spam mail" << endl;
01970 resultAction = false;
01971 deleteIt = false;
01972 break;
01973
01974 }
01975 }
01976 else
01977 {
01978 resultAction = true;
01979 deleteIt = false;
01980 }
01981 break;
01982
01983 default : deleteIt = false;
01984 resultAction = false;
01985
01986 }
01987
01988 if( resultAction == true )
01989 {
01990
01991
01992 mailsToDownload.remove( firstMail.key() );
01993
01994
01995 if( deleteIt )
01996 mailsToDelete.append( currentMailNumber );
01997 }
01998 else
01999 {
02000
02001
02002 applyFilters();
02003 return;
02004 }
02005
02006
02007
02008 if( mailsToDownload.empty() )
02009 {
02010 applyFilters();
02011 return;
02012 }
02013
02014
02015 getNextMailForDownloadActions();
02016 }
02017
02018 void Account::applyFiltersDeleted( )
02019 {
02020
02021 deletionPerformedByFilters = false;
02022
02023
02024 refreshPerformedByFilters = true;
02025
02026
02027 commitBeforeRefresh();
02028 }
02029
02030 void Account::commitBeforeRefresh()
02031 {
02032 if( socket->state() == KTcpSocket::ConnectedState )
02033 {
02034
02035 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
02036 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotCommitBeforeRefreshDone() ) );
02037
02038
02039
02040 quitSent = true;
02041
02042
02043 sendCommand( COMMIT );
02044 }
02045 else
02046 {
02047 finishTask();
02048 }
02049
02050 }
02051
02052 void Account::slotCommitBeforeRefreshDone( )
02053 {
02054
02055 refreshMailList();
02056 }
02057
02058 void Account::saveOptions( QDomDocument& doc, QDomElement& parent )
02059 {
02060
02061 KConfigGroup* config = new KConfigGroup( KGlobal::config(), getName() );
02062
02063
02064 config->writeEntry( CONFIG_ENTRY_ACCOUNT_ACTIVE, isActive() );
02065 config->sync();
02066
02067
02068 parent.setAttribute( ATTRIBUTE_ACCOUNT_NAME, getName() );
02069 mails->saveMails( doc, parent );
02070 }
02071
02072 void Account::showMails()
02073 {
02074
02075 if( mailsToShow.empty() )
02076 {
02077 emit sigShowBodiesReady( name );
02078 return;
02079 }
02080
02081
02082
02083
02084 if( !assertPassword() )
02085 {
02086 emit sigShowBodiesReady( name );
02087 return;
02088 }
02089
02090
02091 state = AccountDownloading;
02092
02093
02094 doConnect();
02095
02096 }
02097
02098 bool Account::writeToMailBox( const QStringList& mail, const QString& box )
02099 {
02100 QDir mailDir( box );
02101
02102
02103 if( !isMailDir( mailDir ) )
02104 {
02105
02106 KMessageBox::error( NULL, i18nc( "@info error message: writing a mail into a mailbox: this is not a mail box", "<filename>%1</filename> is not a mailbox.", box ) );
02107 return false;
02108 }
02109
02110
02111 QString partTime = QString::number( time( NULL ) );
02112
02113 char hname[256];
02114 QString partHostname;
02115 if( gethostname( hname, 255 ) == 0 )
02116 partHostname = QString( hname );
02117 else
02118 {
02119
02120
02121 KMessageBox::error( NULL, i18nc( "@info error message", "Can't read the hostname of your computer. But KShowmail need it to write a mail into the mailbox." ) );
02122 return false;
02123 }
02124
02125 QString partPID = QString::number( getpid() );
02126
02127 QString partCounter = QString::number( moveCounter++ );
02128
02129 QString uniqueName( partTime + '.' + partPID + partCounter + '.' + partHostname );
02130
02131
02132 mailDir.cd( "tmp" );
02133 QString absFile = mailDir.filePath( uniqueName );
02134
02135
02136 QFile file( absFile );
02137 if( file.open( QFile::WriteOnly ) )
02138 {
02139 QTextStream stream( &file );
02140 stream << mail.join( "\n" ) << endl;
02141 file.close();
02142 }
02143 else
02144 {
02145 KMessageBox::detailedError( NULL, i18nc( "@info error message: we could not write a mail into a mailbox", "Could not file a mail to <filename>%1</filename>.", box ), file.errorString() );
02146 return false;
02147 }
02148
02149
02150 mailDir.cdUp();
02151 mailDir.cd( "new" );
02152 QString absNewFile = mailDir.filePath( uniqueName );
02153
02154 if( KDE::rename( absFile.toAscii(), absNewFile.toAscii() ) == -1 )
02155 {
02156 KMessageBox::error( NULL, i18nc( "@info error message: error during writing a mail into a mailbox", "Could not move a mail from <filename>%1</filename> to <filename>%2</filename>.", absFile, absNewFile ) );
02157 return false;
02158 }
02159
02160
02161 return true;
02162 }
02163
02164 bool Account::isMailDir( const QDir& path )
02165 {
02166
02167 const QStringList entries = path.entryList( QDir::Dirs | QDir::Readable | QDir::Writable | QDir::Hidden, QDir::Name | QDir::IgnoreCase | QDir::LocaleAware );
02168
02169
02170 bool curFound = false;
02171 bool newFound = false;
02172 bool tmpFound = false;
02173
02174
02175 QStringList::const_iterator it = entries.begin();
02176 while( it != entries.end() && !( curFound && newFound && tmpFound ) )
02177 {
02178 if( *it == "tmp" )
02179 tmpFound = true;
02180 else if( *it == "cur" )
02181 curFound = true;
02182 else if( *it == "new" )
02183 newFound = true;
02184
02185 ++it;
02186 }
02187
02188 return curFound && newFound && tmpFound;
02189 }
02190
02191 bool Account::isSpam( QStringList mail ) const
02192 {
02193
02194
02195 if( !isSpamAssassinRunning() )
02196 {
02197 KMessageBox::information( NULL, i18nc( "@info", "You want to check your mails for spam, but SpamAssassin is not running.<nl/>KShowmail skips the spam check." ), i18nc( "@title:window", "SpamAssassin is not running" ), "AccountNoSpamAssassinRunning" );
02198 return false;
02199 }
02200
02201
02202 FILE *write_fp;
02203 write_fp = popen( "spamc -E", "w" );
02204
02205
02206 if( write_fp != NULL )
02207 {
02208
02209 QString joinedMail = mail.join( "\n" );
02210 fwrite( joinedMail.toAscii(), sizeof( char), joinedMail.size(), write_fp );
02211
02212
02213 int excode = pclose( write_fp );
02214 if( excode == 0 )
02215 return false;
02216 else
02217 return true;
02218 }
02219 else
02220 {
02221 kdError() << "Could not call the command spamc of SpamAssassin." << endl;
02222 return false;
02223 }
02224
02225 return false;
02226 }
02227
02228 bool Account::isSpamAssassinRunning( ) const
02229 {
02230 FILE *read_fp;
02231 char buffer[ BUFSIZ + 1 ];
02232 int chars_read;
02233 bool found = false;
02234
02235 memset( buffer, '\0', sizeof( buffer ) );
02236 read_fp = popen( "sa-check_spamd"
02237 , "r" );
02238 if( read_fp != NULL )
02239 {
02240 chars_read = fread( buffer, sizeof( char ), BUFSIZ, read_fp );
02241 while( chars_read > 0 )
02242 {
02243 buffer[ chars_read - 1 ] = '\0';
02244 QString output( buffer );
02245 found = output.contains( "SPAMD OK" ) > 0;
02246 if( found ) return found;
02247 chars_read = fread( buffer, sizeof( char ), BUFSIZ, read_fp );
02248 }
02249 pclose( read_fp );
02250 }
02251
02252 return found;
02253 }
02254
02255 int Account::getNumberNewMails( )
02256 {
02257 return mails->getNumberNewMails();
02258 }
02259
02260 long Account::getTotalSize() const {
02261 return mails->getTotalSize();
02262 }
02263
02264 QString Account::getTotalSizeUnit() const {
02265
02266 int size = getTotalSize();
02267 QString strSize;
02268
02269 if( size >= 1024 * 1024 )
02270 {
02271
02272 strSize = QString( "%L1M" ).arg( ( (double)size / ( 1024 * 1024 ) ), 0, 'f', 1 );
02273 }
02274 else if( size >= 1024 )
02275 {
02276
02277 strSize = QString( "%L1K" ).arg( ( (double)size / 1024 ), 0, 'f', 1 );
02278 }
02279 else
02280
02281 strSize = QString( "%L1" ).arg( size );
02282
02283 return strSize;
02284
02285 }
02286
02287 void Account::slotSSLError( const QList<KSslError>& errors ) {
02288
02289
02290 QString message;
02291 QListIterator<KSslError> it( errors );
02292 while( it.hasNext() ) {
02293
02294 KSslError error = it.next();
02295
02296 message.append( error.errorString() );
02297 }
02298
02299
02300 emit sigMessageWindowOpened();
02301 int answer = KMessageBox::warningContinueCancel( NULL,
02302 i18nc( "@info error message: general SSL error", "SSL error: <message>%1</message><nl/>Do you want to continue?", message ),
02303 i18nc( "@title:window", "SSL-Error - %1", getName() ),
02304 KStandardGuiItem::cont(),
02305 KStandardGuiItem::cancel(),
02306 QString( "askSSLErrorContinue_%1").arg( getName() ) );
02307 emit sigMessageWindowClosed();
02308
02309 if( answer == KMessageBox::Continue ) {
02310
02311
02312 socket->ignoreSslErrors();
02313
02314 } else {
02315
02316
02317 dontHandleError = true;
02318
02319
02320 finishTask();
02321
02322 }
02323
02324 return;
02325
02326 }
02327
02328 void Account::readStoredMails( QDomElement& parent )
02329 {
02330
02331 mails->readStoredMails( parent );
02332 }
02333
02334 int Account::compare( Account* other, AccountSort_Type property ) {
02335
02336 switch( property ) {
02337
02338
02339 case AccSortActive : {
02340
02341 if( other->isActive() == isActive() ) return 0;
02342 else if( isActive() == false ) return -1;
02343 else return 1;
02344 break;
02345
02346 }
02347
02348
02349 case AccSortName : {
02350
02351 return QString::localeAwareCompare( getName(), other->getName() );
02352 }
02353
02354
02355 case AccSortServer : {
02356
02357 return QString::localeAwareCompare( getHost(), other->getHost() );
02358 }
02359
02360
02361 case AccSortUser : {
02362
02363 return QString::localeAwareCompare( getUser(), other->getUser() );
02364 }
02365
02366
02367 case AccSortNrMess : {
02368
02369 if( getNumberMails() == other->getNumberMails() ) return 0;
02370 else if( getNumberMails() < other->getNumberMails() ) return -1;
02371 else return 1;
02372 }
02373
02374
02375 case AccSortSize : {
02376
02377 if( getTotalSize() == other->getTotalSize() ) return 0;
02378 else if( getTotalSize() < other->getTotalSize() ) return -1;
02379 else return 1;
02380 }
02381
02382 default: {
02383 return QString::localeAwareCompare( getName(), other->getName() );
02384 }
02385 }
02386 }
02387
02388 QList<Mail> Account::getAllMails() const
02389 {
02390 if( isActive() )
02391 return mails->getAllMails();
02392 else
02393 return QList<Mail>();
02394 }
02395
02396 void Account::slotTimeout()
02397 {
02398 handleError( i18nc( "@info error message", "Timeout" ) );
02399 }
02400
02401 void Account::cancelTask()
02402 {
02403 if( state != AccountIdle ) {
02404
02405 socket->close();
02406 handleError( i18nc( "@info the task was canceled by user", "Task canceled" ) );
02407 }
02408 }
02409
02410 void Account::startTLS()
02411 {
02412
02413 disconnect( socket, SIGNAL( readyRead() ), 0, 0 );
02414 connect( socket, SIGNAL( readyRead() ), this, SLOT( slotStartTLSResponse() ) );
02415
02416
02417 sendCommand( START_TLS );
02418
02419 }
02420
02421 void Account::slotStartTLSResponse()
02422 {
02423
02424 QStringList text = readfromSocket( true );
02425
02426
02427
02428 if( text.isEmpty() )
02429 {
02430 finishTask();
02431 return;
02432 }
02433
02434
02435 bool ack = isPositiveServerMessage( text );
02436
02437
02438 if( !ack ) {
02439
02440 kdError() << "The Server " << getHost() << " says it supports STLS but it doesn't accept the STLS command: " << text.first() << endl;
02441
02442 if( apopAvail && !dontUseAPOP ) {
02443
02444 loginApop();
02445 return;
02446
02447 } else {
02448
02449 if( allowUnsecureLogin == true ) {
02450
02451 loginUser();
02452
02453 } else {
02454
02455 emit sigMessageWindowOpened();
02456 KMessageBox::sorry( NULL, i18nc( "@info error message: this server doesn't support secure login", "Account <resource>%1</resource>: This server doesn't provide a safety login and you have disallowed the using of an unsafe login. If you want to use this Account you must allow unsafe login at the account setup.<nl/><warning>Bear in mind in this case criminals could read your password!</warning>", getName() ), i18nc( "@title:window", "Unsafe login is not allowed") );
02457 emit sigMessageWindowClosed();
02458
02459
02460 finishTask();
02461
02462 }
02463 }
02464
02465 } else {
02466
02467
02468
02469 socket->startClientEncryption();
02470
02471
02472 loginUser();
02473 }
02474
02475 }
02476
02477 AccountViewItem Account::getViewItem()
02478 {
02479 return AccountViewItem( isActive(), getName(), getHost(), getUser(), getNumberMails(), getTotalSize(), QPointer<Account>( this ) );
02480 }
02481