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