KShowMail – show mails on a POP3 server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1759 lines
47KB

  1. /***************************************************************************
  2. ConfigElem.cpp - description
  3. -------------------
  4. begin : Tue May 9 2000
  5. copyright : (C) 2000-2001 by Eggert Ehmke
  6. email : eggert.ehmke@berlin.de
  7. ***************************************************************************/
  8. /***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************/
  16. #include "configelem.h"
  17. int const ConfigElem::continueShowHeaders( 0 );
  18. int const ConfigElem::cancelShowHeaders( 1 );
  19. ConfigElem::ConfigElem( ) : TQObject()
  20. {
  21. //initialize account
  22. init();
  23. //set default values
  24. m_url.setProtocol( "pop3" );
  25. m_url.setPort( 110 );
  26. m_bActive = false;
  27. appConfig = NULL;
  28. m_strAccount = "";
  29. }
  30. ConfigElem::ConfigElem( ConfigList* config ) : TQObject()
  31. {
  32. //initialize account
  33. init();
  34. m_url.setProtocol( "pop3" );
  35. m_url.setPort (110);
  36. m_bActive = false;
  37. appConfig = config;
  38. }
  39. ConfigElem::ConfigElem( ConfigElem* pElem ) : TQObject()
  40. {
  41. //initialize account
  42. init();
  43. //set active by default
  44. m_bActive = pElem->isActive();
  45. //copy some interesting stuff from the sample
  46. //the url object contains all necessary information about the server
  47. m_strAccount = pElem->getAccountName();
  48. m_url = pElem->getURL();
  49. appConfig = pElem->appConfig;
  50. }
  51. ConfigElem::ConfigElem( ConfigList* config, const TQString& account ) : TQObject()
  52. {
  53. //initialize account
  54. init();
  55. //set account name
  56. m_strAccount = account;
  57. //deactivate it by default
  58. m_bActive = false;
  59. //set the pointer to the general app configuration
  60. appConfig = config;
  61. }
  62. void ConfigElem::init( )
  63. {
  64. //initialize timeout timer
  65. pop3Timer = new TQTimer( this );
  66. connect( pop3Timer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) );
  67. //state is idle
  68. state = AccountIdle;
  69. //create new empty mail list
  70. m_pshowrecord = new ShowRecord();
  71. //the account has no appropriate account list view item yet
  72. m_pViewItem = NULL;
  73. //set default values
  74. PasswordStorage = DEFAULT_ACCOUNT_PASSWORD_STORAGE;
  75. filterApplied = false;
  76. deletionPerformedByFilters = false;
  77. refreshPerformedByFilters = false;
  78. downloadActionsInvoked = false;
  79. //initialize counters
  80. moveCounter = 0;
  81. nmbDeletedMailsLastRefresh = 0;
  82. nmbDeletedMailsLastStart = 0;
  83. nmbMovedMailsLastRefresh = 0;
  84. nmbMovedMailsLastStart = 0;
  85. nmbIgnoredMails = 0;
  86. }
  87. ConfigElem::~ConfigElem()
  88. {
  89. // do not delete m_pshowrecord here
  90. }
  91. void ConfigElem::saveOptions( TQDomDocument& doc, TQDomElement& parent )
  92. {
  93. //get application config
  94. TDEConfig* config = TDEApplication::kApplication()->config();
  95. //save the active state
  96. config->setGroup( getAccountName() );
  97. config->writeEntry( CONFIG_ENTRY_ACCOUNT_ACTIVE, m_bActive );
  98. config->sync();
  99. //save the stored mails inside this account
  100. parent.setAttribute( ATTRIBUTE_ACCOUNT_NAME, m_strAccount );
  101. m_pshowrecord->saveOptions( doc, parent );
  102. }
  103. void ConfigElem::readStoredMails( TQDomElement& parent )
  104. {
  105. //get mails
  106. m_pshowrecord->readStoredMails( parent );
  107. }
  108. int ConfigElem::count()
  109. {
  110. return m_pshowrecord->count();
  111. }
  112. bool ConfigElem::isActive( ) const
  113. {
  114. return m_bActive;
  115. }
  116. void ConfigElem::setActive( bool active )
  117. {
  118. m_bActive = active;
  119. }
  120. TQString ConfigElem::getAccountName( ) const
  121. {
  122. return m_strAccount;
  123. }
  124. void ConfigElem::setAccountName( TQString name )
  125. {
  126. if( name != NULL )
  127. m_strAccount = name;
  128. }
  129. TQString ConfigElem::getPassword( ) const
  130. {
  131. return m_url.pass();
  132. }
  133. void ConfigElem::setPassword( const TQString& password )
  134. {
  135. m_url.setPass( password );
  136. }
  137. KURL ConfigElem::getURL( ) const
  138. {
  139. return m_url;
  140. }
  141. bool ConfigElem::hasPassword( ) const
  142. {
  143. return m_url.hasPass();
  144. }
  145. void ConfigElem::setListViewItem( TQListViewItem* item )
  146. {
  147. m_pViewItem = item;
  148. }
  149. TQListViewItem * ConfigElem::getListViewItem( )
  150. {
  151. return m_pViewItem;
  152. }
  153. bool ConfigElem::isSelected( ) const
  154. {
  155. if( m_pViewItem == NULL )
  156. return false;
  157. else
  158. return m_pViewItem->isSelected();
  159. }
  160. void ConfigElem::clearMailList( )
  161. {
  162. if( m_pshowrecord == NULL )
  163. //there is no mail list yet, create a one
  164. m_pshowrecord = new ShowRecord;
  165. else
  166. //clear the existing mail list
  167. m_pshowrecord->clear();
  168. }
  169. void ConfigElem::setHost( const TQString& host )
  170. {
  171. m_url.setHost( host );
  172. }
  173. void ConfigElem::setProtocol( const TQString& protocol )
  174. {
  175. m_url.setProtocol( protocol );
  176. }
  177. void ConfigElem::setPort( unsigned short int port )
  178. {
  179. m_url.setPort( port );
  180. }
  181. void ConfigElem::setUser( const TQString & user )
  182. {
  183. m_url.setUser( user );
  184. }
  185. TQString ConfigElem::getUser( ) const
  186. {
  187. return m_url.user();
  188. }
  189. TQString ConfigElem::getHost( ) const
  190. {
  191. return m_url.host();
  192. }
  193. void ConfigElem::deleteSelectedMails( )
  194. {
  195. //return if this account has no selected mails or
  196. //the account is not idle or the account is not active
  197. if( !m_pshowrecord->hasSelectedMails() || state != AccountIdle || !isActive() )
  198. {
  199. emit sigDeleteReady( m_strAccount );
  200. return;
  201. }
  202. //check whether we have a password for this account
  203. //if not, ask for it
  204. //return when no password is available
  205. if( !assertPassword() )
  206. {
  207. emit sigDeleteReady( m_strAccount );
  208. return;
  209. }
  210. //get the numbers of all selected mails
  211. MailsToDelete = m_pshowrecord->getSelectedMails();
  212. if( MailsToDelete.empty() )
  213. {
  214. kdError() << "ConfigElem::deleteSelectedMails (Account " << m_strAccount << "): The account has selected mails to delete but ShowRecord::getSelectedMails has returned an empty list." << endl;
  215. emit sigDeleteReady( m_strAccount );
  216. return;
  217. }
  218. //set account state
  219. state = AccountDeleting;
  220. //start the deleting of all mails in MailsToDelete
  221. deleteNextMail();
  222. }
  223. bool ConfigElem::assertPassword( bool force )
  224. {
  225. //is a password stored?
  226. if ( !hasPassword() || force )
  227. {
  228. //no password found, we will ask the user!
  229. //set normal cursor
  230. while( TQApplication::overrideCursor() )
  231. TQApplication::restoreOverrideCursor();
  232. TQCString password; //for the password dialog to store the password
  233. int result = KPasswordDialog::getPassword( password, i18n( "Please type in the password for %1" ).arg( getAccountName() ) );
  234. //set waiting cursor
  235. TQApplication::setOverrideCursor( TQt::waitCursor );
  236. //let's look, what the user has done :o)
  237. if( result == KPasswordDialog::Accepted )
  238. {
  239. //the user has clicked OK in the password dialog
  240. //store the password
  241. setPassword( password );
  242. //save password in file or TDEWallet
  243. TDEConfig* config = TDEApplication::kApplication()->config();
  244. config->setGroup( getAccountName() );
  245. if( PasswordStorage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_FILE )
  246. config->writeEntry( CONFIG_ENTRY_ACCOUNT_PASSWORD, crypt( m_url ) );
  247. else
  248. config->writeEntry( CONFIG_ENTRY_ACCOUNT_PASSWORD, TQString::null );
  249. if( PasswordStorage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_KWALLET )
  250. TDEWalletAccess::savePassword( getAccountName(), m_url.pass() );
  251. config->sync();
  252. //emit configuration changed signal
  253. emit ( sigConfigChanged() );
  254. //tell we have a password
  255. return true;
  256. }
  257. else
  258. //the user has clicked Cancel in the password dialog; we don't have a password
  259. return false;
  260. }
  261. else
  262. //we have already a password for this account
  263. return true;
  264. }
  265. void ConfigElem::deleteNextMail( )
  266. {
  267. //if the list of mails to delete is empty, finalize the deletion and return
  268. if( MailsToDelete.empty() )
  269. {
  270. if( deletionPerformedByFilters )
  271. {
  272. applyFiltersDeleted();
  273. }
  274. else
  275. {
  276. commitDeletion();
  277. }
  278. return;
  279. }
  280. //start job
  281. startKIOJob( TQString( "/remove/%1" ).arg( *MailsToDelete.begin() ) );
  282. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotMailDeleted( TDEIO::Job* ) ) );
  283. }
  284. void ConfigElem::slotMailDeleted( TDEIO::Job* job )
  285. {
  286. //stop timeout timer
  287. pop3Timer->stop();
  288. //check for errors
  289. //if an error is occured, the deletion will be canceled
  290. //or will ask for a new password
  291. if( job->error() == TDEIO::ERR_COULD_NOT_LOGIN )
  292. {
  293. //login failed, ask for a new password
  294. job->showErrorDialog();
  295. bool res = assertPassword( true );
  296. if( res == false )
  297. {
  298. //we have not got a new password; cancel delete
  299. if( deletionPerformedByFilters )
  300. {
  301. applyFiltersDeleted();
  302. }
  303. else
  304. {
  305. slotFinalizeDeletion( NULL );
  306. }
  307. return;
  308. }
  309. //if we have got a new password, it jumps to the end of the if-statement
  310. }
  311. else if( job->error() != 0 )
  312. {
  313. //unknown error, show message and cancel delete
  314. job->showErrorDialog();
  315. if( deletionPerformedByFilters )
  316. {
  317. applyFiltersDeleted();
  318. }
  319. else
  320. {
  321. slotFinalizeDeletion( NULL );
  322. }
  323. return;
  324. }
  325. else
  326. {
  327. //operation was successful
  328. //remove the deleted mail from the internal mail list
  329. m_pshowrecord->removeMail( *MailsToDelete.begin() );
  330. //remove the first item of the list of mails to delete
  331. MailsToDelete.remove( MailsToDelete.begin() );
  332. //if the list of mails to delete is empty, finalize the deletion and return
  333. if( MailsToDelete.empty() )
  334. {
  335. if( deletionPerformedByFilters )
  336. {
  337. applyFiltersDeleted();
  338. }
  339. else
  340. {
  341. commitDeletion();
  342. }
  343. return;
  344. }
  345. }
  346. //delete next mail in list
  347. deleteNextMail();
  348. }
  349. void ConfigElem::slotFinalizeDeletion( TDEIO::Job* )
  350. {
  351. //stop timeout time
  352. pop3Timer->stop();
  353. //set account state to idle
  354. state = AccountIdle;
  355. //emit signal to report the deletion is ready
  356. emit sigDeleteReady( m_strAccount );
  357. }
  358. void ConfigElem::startKIOJob( const TQString & path )
  359. {
  360. TDEIO::MetaData options; //options for the pop3 job
  361. //set options
  362. options.insert( "progress", "off" );
  363. options.insert( "pipelining", "off" );
  364. if( useTLS )
  365. options.insert( "tls", "on" );
  366. else
  367. options.insert( "tls", "off" );
  368. //Where is secure login?
  369. //I have decided against a configurable secure login because the used POP3 tdeioslave
  370. //always tries to login with APOP, if the server has sent a timestap (inside of the greeting string) for this authentification type.
  371. //It just follows the auth-metadata, if the server doesn't support APOP (no timestamp inside of the greeting string).
  372. //But I think, there is no server, which support a SASL authentification without also provide APOP.
  373. //Ulrich Weigelt
  374. //set the given command and parameters
  375. m_url.setPath( path );
  376. //print debug message
  377. kdDebug() << "ConfigElem::startKIOJob: start KIO job on URL " << m_url.url() << endl;
  378. //start the job and get handle to it
  379. pop3Job = TDEIO::get( m_url, false, false );
  380. //put options to the job
  381. pop3Job->addMetaData( options );
  382. //start timeout timer
  383. pop3Timer->start( getTimeoutTime() * 1000, true );
  384. }
  385. Types::AccountState_Type ConfigElem::getState( )
  386. {
  387. return state;
  388. }
  389. void ConfigElem::commitDeletion( )
  390. {
  391. //start job to commit
  392. startKIOJob( TQString( "/commit" ) );
  393. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotFinalizeDeletion( TDEIO::Job* ) ) );
  394. }
  395. unsigned int ConfigElem::getTimeoutTime( )
  396. {
  397. //return default time, if the configuration is not accessable
  398. if( appConfig == NULL )
  399. return DEFAULT_TIMEOUT_TIME;
  400. //get time from configuration
  401. unsigned int time = appConfig->getTimeoutTime();
  402. //take minimum time, if get time is less
  403. if( time < MINIMUM_TIMEOUT_TIME )
  404. time = MINIMUM_TIMEOUT_TIME;
  405. return time;
  406. }
  407. void ConfigElem::slotTimeout( )
  408. {
  409. //kill a running job
  410. if( pop3Job != NULL )
  411. pop3Job->kill( true );
  412. //show error message (during refresh if desired only)
  413. kdError() << "Timeout error!" << endl;
  414. if( state != AccountRefreshing || appConfig->showConnectionErrors() )
  415. KMessageBox::error( NULL, TQString( i18n( "Time out on %1. The operation could not be finished on time" ) ).arg( m_strAccount ), i18n( "Time Out" ) );
  416. //call the appropriate finalize methode
  417. switch( state )
  418. {
  419. case AccountIdle : break;
  420. case AccountDeleting : slotFinalizeDeletion( NULL ); break;
  421. case AccountDownloading : slotFinalizeShowMail( NULL ); break;
  422. case AccountRefreshing : cancelRefresh(); break;
  423. default : break;
  424. }
  425. }
  426. TQStringList ConfigElem::getSelectedSubjects( ) const
  427. {
  428. return m_pshowrecord->getSelectedSubjects();
  429. }
  430. bool ConfigElem::hasSelectedMails( )
  431. {
  432. return m_pshowrecord->hasSelectedMails();
  433. }
  434. void ConfigElem::showSelectedMails( )
  435. {
  436. //return if this account has no selected mails or
  437. //the account is not idle or the account is not active
  438. if( !m_pshowrecord->hasSelectedMails() || state != AccountIdle || !isActive() )
  439. {
  440. emit sigShowBodiesReady( m_strAccount );
  441. return;
  442. }
  443. //check whether we have a password for this account
  444. //if not, ask for it
  445. //return when no password is available
  446. if( !assertPassword() )
  447. {
  448. emit sigShowBodiesReady( m_strAccount );
  449. return;
  450. }
  451. //get the numbers of all selected mails
  452. MailsToShow = m_pshowrecord->getSelectedMails();
  453. if( MailsToShow.empty() )
  454. {
  455. kdError() << "ConfigElem::showSelectedMails (Account " << m_strAccount << "): The account has selected mails to show but ShowRecord::getSelectedMails has returned an empty list." << endl;
  456. emit sigShowBodiesReady( m_strAccount );
  457. return;
  458. }
  459. //set account state
  460. state = AccountDownloading;
  461. //start the deleting of all mails in MailsToDelete
  462. showNextMail();
  463. }
  464. void ConfigElem::showNextMail( )
  465. {
  466. //if the list of mails to show is empty, finalize it and return
  467. if( MailsToShow.empty() )
  468. {
  469. slotFinalizeShowMail( NULL );
  470. return;
  471. }
  472. //clear the class variable mailbody, which contains the downloaded mail body
  473. mailbody.resize( 0 );
  474. //start job
  475. startKIOJob( TQString( "/download/%1" ).arg( *MailsToShow.begin() ) );
  476. connect( pop3Job, SIGNAL( data( TDEIO::Job*, const TQByteArray & ) ), SLOT( slotDataMailBody( TDEIO::Job*, const TQByteArray & ) ) );
  477. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotBodyDownloaded( TDEIO::Job* ) ) );
  478. }
  479. void ConfigElem::slotBodyDownloaded( TDEIO::Job * job )
  480. {
  481. //stop timeout timer
  482. pop3Timer->stop();
  483. //check for errors
  484. //if an error has occured, the download will be canceled
  485. //or will ask for a new password
  486. if( job->error() == TDEIO::ERR_COULD_NOT_LOGIN )
  487. {
  488. //login failed, ask for a new password
  489. job->showErrorDialog();
  490. bool res = assertPassword( true );
  491. if( res == false )
  492. {
  493. //we have not got a new password; cancel delete
  494. slotFinalizeShowMail( NULL );
  495. return;
  496. }
  497. //if we have got a new password, jump to the end of the if-statement
  498. }
  499. else if( job->error() != 0 )
  500. {
  501. job->showErrorDialog();
  502. slotFinalizeShowMail( NULL );
  503. return;
  504. }
  505. else
  506. {
  507. //succesful download
  508. //show mail
  509. int currentMail = *MailsToShow.begin();
  510. TQString tsender = m_pshowrecord->getSenderOf( currentMail );
  511. TQString tdate = m_pshowrecord->getDateOf( currentMail );
  512. TQString tsize = m_pshowrecord->getSizeOf( currentMail );
  513. TQString tsubject = m_pshowrecord->getSubjectOf( currentMail );
  514. TQString tmailbody( m_pshowrecord->decodeMailBody( mailbody, currentMail, appConfig->allowHTML() ) );
  515. //emit signal to notify the opening of a window
  516. emit sigMessageWindowOpened();
  517. //create and open the window
  518. ShowMailDialog dlg( kapp->mainWidget(), m_strAccount, appConfig->allowHTML(), tsender, tdate, tsize, tsubject, tmailbody );
  519. int ret = dlg.exec();
  520. //emit signal to notify the closing of a window
  521. emit sigMessageWindowClosed();
  522. //cancel the download if desired
  523. if( ret == KDialogBase::Rejected )
  524. {
  525. MailsToShow.clear();
  526. commitDownloading();
  527. return;
  528. }
  529. //remove the first item of the list of mails to show
  530. MailsToShow.remove( MailsToShow.begin() );
  531. //if the list of mails is empty, finalize the showing and return
  532. if( MailsToShow.empty() )
  533. {
  534. commitDownloading();
  535. return;
  536. }
  537. }
  538. //show next mail in list
  539. showNextMail();
  540. }
  541. void ConfigElem::slotFinalizeShowMail( TDEIO::Job* )
  542. {
  543. //stop timeout time
  544. pop3Timer->stop();
  545. //set account state to idle
  546. state = AccountIdle;
  547. //emit signal to report the download is ready
  548. emit sigShowBodiesReady( m_strAccount );
  549. }
  550. void ConfigElem::slotDataMailBody( TDEIO::Job *, const TQByteArray & datas )
  551. {
  552. if( !datas.isEmpty() )
  553. {
  554. //we get the next part of the mail
  555. //append it
  556. uint lastSize = mailbody.size();
  557. mailbody.resize( lastSize + datas.size() );
  558. for( uint i = 0; i < datas.size(); i++ )
  559. mailbody[ lastSize + i ] = datas[ i ];
  560. }
  561. }
  562. void ConfigElem::commitDownloading( )
  563. {
  564. //start job to commit
  565. startKIOJob( TQString( "/commit" ) );
  566. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotFinalizeShowMail( TDEIO::Job* ) ) );
  567. }
  568. void ConfigElem::refreshMailList( FilterLog* log )
  569. {
  570. //store pointer to log
  571. if( log != NULL )
  572. FLog = log;
  573. //return, if account is not active
  574. if( !isActive() )
  575. {
  576. emit sigRefreshReady( m_strAccount );
  577. return;
  578. }
  579. //check whether we have a password for this account
  580. //if not, ask for it
  581. //return when no password is available
  582. if( !assertPassword() )
  583. {
  584. emit sigRefreshReady( m_strAccount );
  585. return;
  586. }
  587. //create a new ShowRecord instance
  588. //When the refresh has finished successfully, this will
  589. //replace the old mail list
  590. tempMailList = new ShowRecord();
  591. //set account state
  592. state = AccountRefreshing;
  593. //init counter
  594. if( !refreshPerformedByFilters )
  595. {
  596. nmbDeletedMailsLastRefresh = 0;
  597. nmbMovedMailsLastRefresh = 0;
  598. nmbIgnoredMails = 0;
  599. }
  600. //the first step is to get the UIDs
  601. getUIDs();
  602. }
  603. void ConfigElem::getUIDs( )
  604. {
  605. //clears the TQString list, which contains all received UIDs
  606. receivedUIDs.clear();
  607. //start job
  608. startKIOJob( TQString( "/uidl" ) );
  609. connect( pop3Job, SIGNAL( data( TDEIO::Job*, const TQByteArray & ) ), SLOT( slotReceiveUID( TDEIO::Job*, const TQByteArray & ) ) );
  610. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotUIDsReceived( TDEIO::Job* ) ) );
  611. }
  612. void ConfigElem::slotReceiveUID( TDEIO::Job*, const TQByteArray& data )
  613. {
  614. //return, when data is empty
  615. if( data.isEmpty() ) return;
  616. //cast the data to TQString
  617. TQString uid( data );
  618. //insert the uid at the end of the UID list
  619. receivedUIDs.append( uid );
  620. }
  621. void ConfigElem::slotUIDsReceived( TDEIO::Job * job )
  622. {
  623. int number; //an extracted mail number
  624. TQString uid; //an extracted uid
  625. bool corruptData = false; //set to TRUE, if a data is corrupt
  626. bool isNew = false; //state of the received mail
  627. //stop timeout timer
  628. pop3Timer->stop();
  629. //check for errors
  630. //if an error has occured, the refresh will be canceled
  631. //or will ask for a new password
  632. if( job->error() == TDEIO::ERR_COULD_NOT_LOGIN )
  633. {
  634. //login failed, ask for a new password
  635. job->showErrorDialog();
  636. bool res = assertPassword( true );
  637. if( res == true )
  638. {
  639. //we have got a new password, try again
  640. delete tempMailList;
  641. refreshMailList();
  642. }
  643. else
  644. //we have not got a new password; cancel refresh
  645. cancelRefresh();
  646. return;
  647. }
  648. else if( job->error() != 0 )
  649. {
  650. //show error message if desired
  651. if( appConfig->showConnectionErrors() )
  652. job->showErrorDialog();
  653. cancelRefresh();
  654. return;
  655. }
  656. //analyze UIDs
  657. if( !receivedUIDs.isEmpty() )
  658. {
  659. //iterate over all UIDs in the list
  660. for ( TQStringList::Iterator it = receivedUIDs.begin(); it != receivedUIDs.end(); ++it )
  661. {
  662. TQString line = *it;
  663. //every line has the format "number UID", e.g.: 1 bf10d38018de7c1d628d65288d722f6a
  664. //get the position of the separating space
  665. int positionOfSpace = line.find( " " );
  666. //if no space was found, the line is corrupt
  667. if( positionOfSpace == -1 )
  668. {
  669. kdError() << "ConfigElem::slotUIDsReceived: get a corrupt UID from " << dynamic_cast<TDEIO::SimpleJob*>(job)->url().host() << ". No space. : " << line << endl;
  670. corruptData = true;
  671. }
  672. else
  673. {
  674. //extract mail number and uid
  675. bool isNumber;
  676. number = line.left( positionOfSpace ).toInt( &isNumber );
  677. //check number
  678. if( !isNumber )
  679. {
  680. //the first part is not a number
  681. kdError() << "ConfigElem::slotUIDsReceived: get a corrupt UID from " << dynamic_cast<TDEIO::SimpleJob*>(job)->url().host() << ". No number found at begin. : " << line << endl;
  682. corruptData = true;
  683. }
  684. else
  685. {
  686. //number is ok; extract uid
  687. uid = line.mid( positionOfSpace + 1 );
  688. //determine about new mail or not
  689. if( !m_pshowrecord->hasMail( uid ) )
  690. {
  691. //the old list doesn't contain a mail with this uid
  692. //the mail is new
  693. isNew = true;
  694. }
  695. else if( ( appConfig->keepNew() || refreshPerformedByFilters ) && m_pshowrecord->isNew( uid ) )
  696. {
  697. //the mail is already in the old list
  698. //but we will leave the state of formerly new mails, because the user wants it or this refresh is performed by filters
  699. isNew = true;
  700. }
  701. else
  702. isNew = false;
  703. //append mail to the list
  704. tempMailList->appendNewMail( number, uid, isNew );
  705. }
  706. }
  707. }
  708. //if the data are ok, start the second step: get sizes
  709. //otherwise cancel the refresh
  710. if( !corruptData )
  711. getSizes();
  712. else
  713. cancelRefresh();
  714. }
  715. else
  716. {
  717. //we haven't received any UIDs. The account has no mails.
  718. //finalize the refresh
  719. swapMailLists();
  720. }
  721. }
  722. void ConfigElem::cancelRefresh()
  723. {
  724. //print error message
  725. kdError() << m_strAccount << ": " << "Refresh canceled" << endl;
  726. //delete the new mail list
  727. delete tempMailList;
  728. //delete old mail list and create a new empty one
  729. delete m_pshowrecord;
  730. m_pshowrecord = new ShowRecord();
  731. //emit signal
  732. emit sigRefreshReady( m_strAccount );
  733. //set account state to idle
  734. state = AccountIdle;
  735. //we don't need an error message, because the KIO job has shown one
  736. }
  737. void ConfigElem::slotFinalizeRefresh( TDEIO::Job* )
  738. {
  739. //stop timeout time
  740. pop3Timer->stop();
  741. //unset the flag
  742. refreshPerformedByFilters = false;
  743. //emit signal
  744. emit sigRefreshReady( m_strAccount );
  745. //set account state to idle
  746. state = AccountIdle;
  747. }
  748. void ConfigElem::commitRefresh( )
  749. {
  750. //start job to commit
  751. startKIOJob( TQString( "/commit" ) );
  752. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotFinalizeRefresh( TDEIO::Job* ) ) );
  753. }
  754. void ConfigElem::getSizes( )
  755. {
  756. //clears the TQString list, which contains all received UIDs
  757. receivedSizes.clear();
  758. //start job
  759. startKIOJob( TQString( "/index" ) );
  760. connect( pop3Job, SIGNAL( data( TDEIO::Job*, const TQByteArray & ) ), SLOT( slotReceiveSize( TDEIO::Job*, const TQByteArray & ) ) );
  761. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotSizesReceived( TDEIO::Job* ) ) );
  762. }
  763. void ConfigElem::slotSizesReceived( TDEIO::Job * job )
  764. {
  765. int number; //an extracted mail number
  766. long size; //an extracted size
  767. bool corruptData = false; //set to TRUE, if a data is corrupt
  768. //stop timeout timer
  769. pop3Timer->stop();
  770. //check for errors
  771. //if an error has occured, the refresh will be canceled
  772. if( job->error() != 0 )
  773. {
  774. //show error message if desired
  775. if( appConfig->showConnectionErrors() )
  776. job->showErrorDialog();
  777. cancelRefresh();
  778. return;
  779. }
  780. //analyze UIDs
  781. if( !receivedSizes.isEmpty() )
  782. {
  783. //iterate over all sizes in the list
  784. for ( TQStringList::Iterator it = receivedSizes.begin(); it != receivedSizes.end(); ++it )
  785. {
  786. TQString line = *it;
  787. //every line has the format "number size", e.g.: 1 1234
  788. //get the position of the separating space
  789. int positionOfSpace = line.find( " " );
  790. //if no space was found, the line is corrupt
  791. if( positionOfSpace == -1 )
  792. {
  793. kdError() << "ConfigElem::slotSizesReceived: get a corrupt size from " << dynamic_cast<TDEIO::SimpleJob*>(job)->url().host() << ". No space. : " << line << endl;
  794. corruptData = true;
  795. }
  796. else
  797. {
  798. //extract mail number and size
  799. bool isNumber;
  800. number = line.left( positionOfSpace ).toInt( &isNumber );
  801. //check number
  802. if( !isNumber )
  803. {
  804. //the first part is not a number
  805. kdError() << "ConfigElem::slotSizesReceived: get a corrupt size from " << dynamic_cast<TDEIO::SimpleJob*>(job)->url().host() << ". No number found at begin. : " << line << endl;
  806. corruptData = true;
  807. }
  808. else
  809. {
  810. //number is ok; extract size
  811. size = line.mid( positionOfSpace + 1 ).toLong( &isNumber );
  812. //check size
  813. if( !isNumber )
  814. {
  815. //the second part of the string is not a number
  816. kdError() << "ConfigElem::slotSizesReceived: get a corrupt size from " << dynamic_cast<TDEIO::SimpleJob*>(job)->url().host() << ". No size found at end. : " << line << endl;
  817. corruptData = true;
  818. }
  819. else
  820. {
  821. //size is ok
  822. //set it
  823. tempMailList->setSize( number, size );
  824. }
  825. }
  826. }
  827. }
  828. //if the data are ok, start the third step: get headers
  829. //otherwise cancel the refresh
  830. if( !corruptData )
  831. getHeaders();
  832. else
  833. cancelRefresh();
  834. }
  835. }
  836. void ConfigElem::slotReceiveSize( TDEIO::Job *, const TQByteArray & data )
  837. {
  838. //return, when data is empty
  839. if( data.isEmpty() ) return;
  840. //cast the data to TQString
  841. TQString size( data );
  842. //insert the uid at the end of the sizes list
  843. receivedSizes.append( size );
  844. }
  845. void ConfigElem::getHeaders( )
  846. {
  847. //get the numbers of all new mails
  848. newMails = tempMailList->getNewMails();
  849. if( newMails.empty() )
  850. {
  851. //no new mails available; copy the known headers from the old mail list
  852. copyHeaders();
  853. return;
  854. }
  855. //get the headers
  856. getNextHeader();
  857. }
  858. void ConfigElem::getNextHeader( )
  859. {
  860. //if the list of mails empty, copy the known headers from the old mail list
  861. if( newMails.empty() )
  862. {
  863. copyHeaders();
  864. return;
  865. }
  866. //clear temporary header store
  867. receivedHeader.resize( 0 );
  868. //start job
  869. startKIOJob( TQString( "/headers/%1" ).arg( *newMails.begin() ) );
  870. connect( pop3Job, SIGNAL( data( TDEIO::Job*, const TQByteArray & ) ), this, SLOT( slotReceiveHeader( TDEIO::Job*, const TQByteArray & ) ) );
  871. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotHeaderDownloaded( TDEIO::Job* ) ) );
  872. }
  873. void ConfigElem::slotHeaderDownloaded( TDEIO::Job * job )
  874. {
  875. //stop timeout timer
  876. pop3Timer->stop();
  877. //check for errors
  878. //if an error is occured, the download will be canceled
  879. if( job->error() != 0 )
  880. {
  881. //show error message if desired
  882. if( appConfig->showConnectionErrors() )
  883. job->showErrorDialog();
  884. cancelRefresh();
  885. return;
  886. }
  887. //store header
  888. tempMailList->setHeader( *newMails.begin(), TQString( receivedHeader ) );
  889. //remove the first item of the list of new mails
  890. newMails.remove( newMails.begin() );
  891. //if the list of new mails is empty, copy the headers of old mails to the new list
  892. if( newMails.empty() )
  893. {
  894. copyHeaders();
  895. return;
  896. }
  897. //get next header
  898. getNextHeader();
  899. }
  900. void ConfigElem::copyHeaders( )
  901. {
  902. //get the UIDs of the old mails in the temporary mail list
  903. TQStringList UIDs = tempMailList->getUIDsOfOldMails();
  904. //iterate over all members of the list,
  905. //get the header from the old list and store it in the new one
  906. TQStringList::iterator it;
  907. for ( it = UIDs.begin(); it != UIDs.end(); ++it )
  908. {
  909. TQString header = m_pshowrecord->getHeaderOf( *it );
  910. tempMailList->setHeader( *it, header );
  911. }
  912. //now we have the a complete new mail list
  913. swapMailLists();
  914. }
  915. void ConfigElem::slotReceiveHeader( TDEIO::Job *, const TQByteArray & data )
  916. {
  917. if( !data.isEmpty() )
  918. {
  919. //we get the next part of the mail
  920. //append it
  921. uint lastSize = receivedHeader.size();
  922. receivedHeader.resize( lastSize + data.size() );
  923. for( uint i = 0; i < data.size(); i++ )
  924. receivedHeader[ lastSize + i ] = data[ i ];
  925. }
  926. }
  927. int ConfigElem::getNumberNewMails( )
  928. {
  929. return m_pshowrecord->getNumberNewMails();
  930. }
  931. int ConfigElem::getNumberMails( )
  932. {
  933. return m_pshowrecord->getNumberMails();
  934. }
  935. long ConfigElem::getTotalSize( )
  936. {
  937. return m_pshowrecord->getTotalSize();
  938. }
  939. void ConfigElem::fillMailListView( KshowmailView* view )
  940. {
  941. m_pshowrecord->fillMailListView( view, m_strAccount );
  942. }
  943. void ConfigElem::refreshAccountListItem( )
  944. {
  945. if( m_pViewItem != NULL )
  946. {
  947. if( isActive() )
  948. {
  949. m_pViewItem->setText( 4, TQString( "%1" ).arg( getNumberMails(), 3 ) );
  950. m_pViewItem->setText( 5, TQString( "%1" ).arg( getTotalSize(), 8 ) );
  951. }
  952. else
  953. {
  954. m_pViewItem->setText( 4, TQString( "???" ) );
  955. m_pViewItem->setText( 5, TQString( "???" ) );
  956. }
  957. }
  958. }
  959. void ConfigElem::killPOP3Job( )
  960. {
  961. //just try to kill, if it is not idle
  962. if( state != AccountIdle )
  963. {
  964. //kill a running job
  965. if( pop3Job != NULL )
  966. pop3Job->kill( true );
  967. //stop timeout timer
  968. pop3Timer->stop();
  969. //call the appropriate finalize method
  970. switch( state )
  971. {
  972. case AccountDeleting : slotFinalizeDeletion( NULL ); break;
  973. case AccountDownloading : slotFinalizeShowMail( NULL ); break;
  974. case AccountRefreshing : cancelRefresh(); break;
  975. default : break;
  976. }
  977. }
  978. }
  979. int ConfigElem::showSelectedHeaders( )
  980. {
  981. //return, if no mails are selected
  982. if( !hasSelectedMails() )
  983. return ConfigElem::continueShowHeaders;
  984. //order the mail list to show the headers of the selected mails
  985. int ret = m_pshowrecord->showSelectedHeaders( m_strAccount );
  986. return ret == ShowRecord::continueShowHeaders ? ConfigElem::continueShowHeaders : ConfigElem::cancelShowHeaders;
  987. }
  988. void ConfigElem::printSetup( ) const
  989. {
  990. kdDebug() << "Setup of " << m_strAccount << ":" << endl;
  991. kdDebug() << "Host: " << m_url.host() << endl;
  992. kdDebug() << "Protocol: " << m_url.protocol() << endl;
  993. kdDebug() << "Port: " << m_url.port() << endl;
  994. kdDebug() << "User: " << m_url.user() << endl;
  995. kdDebug() << "Password: " << m_url.pass() << endl;
  996. switch( PasswordStorage )
  997. {
  998. case CONFIG_VALUE_ACCOUNT_PASSWORD_DONT_SAVE : kdDebug() << "Password Storage: don't save" << endl; break;
  999. case CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_FILE : kdDebug() << "Password Storage: save in file" << endl; break;
  1000. case CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_KWALLET : kdDebug() << "Password Storage: use TDEWallet" << endl; break;
  1001. default : kdDebug() << "Password Storage: invalid value" << endl;
  1002. }
  1003. kdDebug() << "active: " << m_bActive << endl << endl;
  1004. }
  1005. void ConfigElem::setPasswordStorage( int storage )
  1006. {
  1007. if( storage == CONFIG_VALUE_ACCOUNT_PASSWORD_DONT_SAVE ||
  1008. storage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_FILE ||
  1009. storage == CONFIG_VALUE_ACCOUNT_PASSWORD_SAVE_KWALLET )
  1010. PasswordStorage = storage;
  1011. else
  1012. PasswordStorage = DEFAULT_ACCOUNT_PASSWORD_STORAGE;
  1013. }
  1014. int ConfigElem::getPasswordStorage( ) const
  1015. {
  1016. return PasswordStorage;
  1017. }
  1018. TQString ConfigElem::getProtocol( bool upperCase ) const
  1019. {
  1020. if( upperCase )
  1021. return m_url.protocol().upper();
  1022. else
  1023. return m_url.protocol();
  1024. }
  1025. unsigned short int ConfigElem::getPort( ) const
  1026. {
  1027. return m_url.port();
  1028. }
  1029. void ConfigElem::setTLS( bool tls )
  1030. {
  1031. useTLS = tls;
  1032. }
  1033. bool ConfigElem::getTLS( ) const
  1034. {
  1035. return useTLS;
  1036. }
  1037. void ConfigElem::reloadFilterSettings( )
  1038. {
  1039. headerFilter.load();
  1040. }
  1041. void ConfigElem::applyFilters( )
  1042. {
  1043. //are we executed by the MOVE routines?
  1044. if( !downloadActionsInvoked )
  1045. {
  1046. //this is the first call (at the current refresh cycle) of this methode
  1047. //we get the lists of mails to delete an move and call the MOVE routines if necessary
  1048. //OK, the filters were applied
  1049. filterApplied = true;
  1050. //order the mail list to apply the header filters
  1051. //it returns lists of mail numbers which shall be deleted or moved
  1052. //the marking will be done by the mail list itself
  1053. //the mail list removes all mails which shall be ignored itself
  1054. MailsToDelete.clear();
  1055. m_pshowrecord->applyHeaderFilter( &headerFilter, getAccountName(), MailsToDelete, MailsToDownload, nmbIgnoredMails, FLog );
  1056. nmbDeletedMailsLastRefresh += MailsToDelete.count();
  1057. nmbDeletedMailsLastStart += MailsToDelete.count();
  1058. //This part will be executed, if mails shall be downloaded
  1059. if( !MailsToDownload.empty() )
  1060. {
  1061. downloadActionsInvoked = true;
  1062. doDownloadActions();
  1063. //we quit this methode at this point, because after the bodies are downloaded and written this methode will recalled.
  1064. //At this time the else branch of this IF-statement will be executed and the methode continues
  1065. return;
  1066. }
  1067. }
  1068. else
  1069. {
  1070. //this is the second call (at the current refresh cycle) of this methode.
  1071. //it is called by the Move routines.
  1072. //the downloading of the mailbodies and writing it to the mailboxes has ended.
  1073. //A second call was just exceuted, if there was mails to move
  1074. downloadActionsInvoked = false;
  1075. //after an move error there are maybe some mails leftover in MailsToMove
  1076. MailsToDownload.clear();
  1077. }
  1078. //we have get the list of mails to delete and the all mails to move are written to its mailboxes
  1079. //now we delete this mails (the moved mails too)
  1080. if( !MailsToDelete.empty() )
  1081. {
  1082. //there are mails to delete
  1083. //we delete they
  1084. //after the delete cycle has done its job, it will call applyFiltersDeleted()
  1085. deletionPerformedByFilters = true; //this is set to indicate the deletion is performed by filters and not by user
  1086. //the deletion methodes need it to decide on branch targets
  1087. deleteNextMail();
  1088. }
  1089. else
  1090. {
  1091. //if we need not to start a second refresh cycle (no mails was deleted or moved)
  1092. //we just commit the refresh and let the filter applied flag to false for the next regular refresh
  1093. commitRefresh();
  1094. filterApplied = false;
  1095. }
  1096. }
  1097. void ConfigElem::swapMailLists( )
  1098. {
  1099. //delete old mail list
  1100. delete m_pshowrecord;
  1101. //assign the new list
  1102. if( tempMailList != NULL )
  1103. m_pshowrecord = tempMailList;
  1104. else
  1105. m_pshowrecord = new ShowRecord();
  1106. //if the filters were not applied yet, we do it now
  1107. //applyFilters() will either start a second refresh cycle if it did some deletions
  1108. //or call commitRefresh() to commit the refresh cycle.
  1109. //if the filters were already applied we commit the refresh.
  1110. if( filterApplied | !headerFilter.isActive() )
  1111. {
  1112. commitRefresh();
  1113. filterApplied = false;
  1114. return;
  1115. }
  1116. else
  1117. {
  1118. applyFilters();
  1119. return;
  1120. }
  1121. }
  1122. void ConfigElem::applyFiltersDeleted( )
  1123. {
  1124. //unset the flag
  1125. deletionPerformedByFilters = false;
  1126. //start the second refresh cycle
  1127. refreshPerformedByFilters = true;
  1128. //this sends a commit and restart the refresh
  1129. commitBeforeRefresh();
  1130. return;
  1131. //refreshMailList();
  1132. }
  1133. bool ConfigElem::writeToMailBox( const TQString & mail, const TQString & box )
  1134. {
  1135. TQDir mailDir( box );
  1136. //check whether the given path is a maildir
  1137. if( !isMailDir( mailDir ) )
  1138. {
  1139. //show an error message
  1140. KMessageBox::error( NULL, i18n( TQString( "%1 is not a mailbox." ).arg( box ) ) );
  1141. return false;
  1142. }
  1143. //create unique file name according http://cr.yp.to/proto/maildir.html
  1144. TQString partTime = TQString::number( time( NULL ) ); //left part, output of time()
  1145. char hname[256]; //right part, the hostname
  1146. TQString partHostname;
  1147. if( gethostname( hname, 255 ) == 0 )
  1148. partHostname = TQString( hname );
  1149. else
  1150. {
  1151. //the hostname is not readable
  1152. //show an error message and exit
  1153. KMessageBox::error( NULL, i18n( TQString( "Can't read the hostname of your computer. But KShowmail need it to write a mail into the mailbox." ) ) );
  1154. return false;
  1155. }
  1156. TQString partPID = TQString::number( getpid() ); //middle part, the PID
  1157. TQString partCounter = TQString::number( moveCounter++ );
  1158. TQString uniqueName( partTime + "." + partPID + partCounter + "." + partHostname );
  1159. //build absolute path
  1160. mailDir.cd( "tmp" );
  1161. TQString absFile = mailDir.filePath( uniqueName );
  1162. //and writing!
  1163. TQFile file( absFile );
  1164. if( file.open( IO_WriteOnly ) )
  1165. {
  1166. TQTextStream stream( &file );
  1167. stream << mail << endl;
  1168. file.close();
  1169. }
  1170. else
  1171. {
  1172. KMessageBox::detailedError( NULL, i18n( TQString( "Could not file a mail to %1." ) ).arg( box ), i18n( file.errorString() ) );
  1173. return false;
  1174. }
  1175. //now we move it to the "new" subdirectory
  1176. mailDir.cdUp();
  1177. mailDir.cd( "new" );
  1178. TQString absNewFile = mailDir.filePath( uniqueName );
  1179. if( rename( absFile.ascii(), absNewFile.ascii() ) == -1 )
  1180. {
  1181. KMessageBox::error( NULL, i18n( TQString( "Could not move a mail from %1 to %2." ) ).arg( absFile ).arg( absNewFile ) );
  1182. return false;
  1183. }
  1184. //the writing was successful
  1185. return true;
  1186. }
  1187. void ConfigElem::doDownloadActions()
  1188. {
  1189. //get first mail
  1190. getNextMailForDownloadActions();
  1191. }
  1192. bool ConfigElem::isMailDir( const TQDir & path )
  1193. {
  1194. //get a list of all subdirectories in this directory
  1195. const TQStringList entries = path.entryList( TQDir::Dirs | TQDir::Readable | TQDir::Writable | TQDir::Hidden, TQDir::Name | TQDir::IgnoreCase | TQDir::LocaleAware );
  1196. //a maildir folder must contains the folders "cur", "new" and "tmp"
  1197. bool curFound = false;
  1198. bool newFound = false;
  1199. bool tmpFound = false;
  1200. //iterate over all directories and look for the three necessary dirs
  1201. TQStringList::const_iterator it = entries.begin();
  1202. while( it != entries.end() && !( curFound && newFound && tmpFound ) )
  1203. {
  1204. if( *it == "tmp" )
  1205. tmpFound = true;
  1206. else if( *it == "cur" )
  1207. curFound = true;
  1208. else if( *it == "new" )
  1209. newFound = true;
  1210. ++it;
  1211. }
  1212. return curFound && newFound && tmpFound;
  1213. }
  1214. void ConfigElem::getNextMailForDownloadActions()
  1215. {
  1216. //if the list of mails to move is empty return to applyFilters
  1217. if( MailsToDownload.empty() )
  1218. {
  1219. applyFilters();
  1220. return;
  1221. }
  1222. //clear the class variable mailbody, which contains the downloaded mail body
  1223. mailbody.resize( 0 );
  1224. //start job
  1225. startKIOJob( TQString( "/download/%1" ).arg( MailsToDownload.begin().key() ) );
  1226. connect( pop3Job, SIGNAL( data( TDEIO::Job*, const TQByteArray & ) ), SLOT( slotDataMailBody( TDEIO::Job*, const TQByteArray & ) ) );
  1227. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotMailDownloadedForAction( TDEIO::Job* ) ) );
  1228. }
  1229. void ConfigElem::slotMailDownloadedForAction(TDEIO::Job * job)
  1230. {
  1231. //stop timeout timer
  1232. pop3Timer->stop();
  1233. //check for errors
  1234. //if an error has occured, the download will be canceled
  1235. //or will ask for a new password
  1236. if( job->error() == TDEIO::ERR_COULD_NOT_LOGIN )
  1237. {
  1238. //login failed, ask for a new password
  1239. job->showErrorDialog();
  1240. bool res = assertPassword( true );
  1241. if( res == false )
  1242. {
  1243. //we have not got a new password; cancel delete
  1244. applyFilters();
  1245. return;
  1246. }
  1247. //if we have got a new password, jump to the end of the if-statement
  1248. }
  1249. else if( job->error() != 0 )
  1250. {
  1251. job->showErrorDialog();
  1252. applyFilters();
  1253. return;
  1254. }
  1255. else
  1256. {
  1257. //succesful download
  1258. //do action
  1259. MailToDownloadMap_Type::Iterator firstMail = MailsToDownload.begin();
  1260. int currentMailNumber = firstMail.key(); //get mail number
  1261. TQString currentMailBox( firstMail.data().mailbox ); //get mailbox
  1262. TQString mail( mailbody ); //convert mailtext
  1263. FilterAction_Type action = firstMail.data().action; //get action
  1264. bool resultMove = false; //TRUE - mail is written into the mailbox
  1265. bool resultSpam = false; //TRUE - mail is Spam
  1266. bool deleteIt = false; //TRUE - mail shall be deleted
  1267. bool resultAction = false; //True - the action was succesful performed
  1268. switch( action )
  1269. {
  1270. case FActMove : resultMove = writeToMailBox( mail, currentMailBox );
  1271. //log entry is made by ShowRecordElem::applyHeaderFilter
  1272. if( resultMove == true )
  1273. {
  1274. nmbMovedMailsLastRefresh++;
  1275. nmbMovedMailsLastStart++;
  1276. resultAction = true;
  1277. deleteIt = true;
  1278. }
  1279. else
  1280. {
  1281. resultAction = false;
  1282. deleteIt = false;
  1283. }
  1284. break;
  1285. case FActSpamcheck : resultSpam = isSpam( mailbody ); //it is spam?
  1286. if( resultSpam == true ) //yes, it is spam! Arrgghh! Torture it!!!
  1287. {
  1288. switch( appConfig->getSpamAction() )
  1289. {
  1290. case FActMove : resultMove = writeToMailBox( mail, appConfig->getSpamMailbox() );
  1291. if( resultMove == true )
  1292. {
  1293. nmbMovedMailsLastRefresh++;
  1294. nmbMovedMailsLastStart++;
  1295. if( FLog != NULL )
  1296. m_pshowrecord->writeToMoveLog( FLog, currentMailNumber, getAccountName(), appConfig->getSpamMailbox() );
  1297. resultAction = true;
  1298. deleteIt = true;
  1299. }
  1300. else
  1301. {
  1302. resultAction = false;
  1303. deleteIt = false;
  1304. }
  1305. break;
  1306. case FActMark : m_pshowrecord->setMarkAtNextViewRefresh( currentMailNumber );
  1307. resultAction = true;
  1308. deleteIt = false;
  1309. break;
  1310. case FActDelete : if( FLog != NULL )
  1311. m_pshowrecord->writeToDeleteLog( FLog, currentMailNumber, getAccountName() );
  1312. nmbDeletedMailsLastRefresh++;
  1313. nmbDeletedMailsLastStart++;
  1314. resultAction = true;
  1315. deleteIt = true;
  1316. break;
  1317. default : kdError() << "invalid action for spam mail" << endl;
  1318. resultAction = false;
  1319. deleteIt = false;
  1320. break;
  1321. }
  1322. }
  1323. else //mail is not spam
  1324. {
  1325. resultAction = true;
  1326. deleteIt = false;
  1327. }
  1328. break;
  1329. default : deleteIt = false;
  1330. resultAction = false;
  1331. }
  1332. if( resultAction == true )
  1333. {
  1334. //Action was successful
  1335. //remove this mail from the list
  1336. MailsToDownload.remove( firstMail );
  1337. //maybe add this mail to list of mails to delete
  1338. if( deleteIt )
  1339. MailsToDelete.append( currentMailNumber );
  1340. }
  1341. else
  1342. {
  1343. //Action was not successful
  1344. //returns to applyFilters() to continue the filtering
  1345. applyFilters();
  1346. return;
  1347. }
  1348. //if the list of mails is empty, return to applyFilters() to continue the filtering
  1349. if( MailsToDownload.empty() )
  1350. {
  1351. applyFilters();
  1352. return;
  1353. }
  1354. }
  1355. //show next mail in list
  1356. getNextMailForDownloadActions();
  1357. }
  1358. bool ConfigElem::isSpam( TQByteArray mail ) const
  1359. {
  1360. //check for a running spamassassin
  1361. if( !isSpamAssassinRunning() )
  1362. {
  1363. KMessageBox::information( NULL, i18n( "You want to check your mails for spam, but SpamAssassin is not running.\nKShowmail skips the spam check." ), i18n( "SpamAssassin is not running" ), "ConfigElemNoSpamAssassinRunning" );
  1364. return false;
  1365. }
  1366. //append an \0 at the end of the string
  1367. int size = mail.size();
  1368. if( mail[ size - 1 ] != '\0' )
  1369. {
  1370. mail.resize( size + 1 );
  1371. mail[ size ] = '\0';
  1372. }
  1373. //calls spmac and get an file pointer to stdin of it
  1374. FILE *write_fp;
  1375. write_fp = popen( "spamc -E", "w" );
  1376. //forward the mail to SpamAssassin
  1377. if( write_fp != NULL )
  1378. {
  1379. fwrite( mail.data(), sizeof( char), mail.size(), write_fp );
  1380. //check exit code of spamc and return result
  1381. int excode = pclose( write_fp );
  1382. if( excode == 0 )
  1383. return false;
  1384. else
  1385. return true;
  1386. }
  1387. else
  1388. {
  1389. kdError() << "Could not call the command spamc of SpamAssassin." << endl;
  1390. return false;
  1391. }
  1392. return false;
  1393. }
  1394. bool ConfigElem::isSpamAssassinRunning( ) const
  1395. {
  1396. FILE *read_fp;
  1397. char buffer[ BUFSIZ + 1 ];
  1398. int chars_read;
  1399. bool found = false;
  1400. memset( buffer, '\0', sizeof( buffer ) );
  1401. read_fp = popen( "ps -eo comm", "r" );
  1402. if( read_fp != NULL )
  1403. {
  1404. chars_read = fread( buffer, sizeof( char ), BUFSIZ, read_fp );
  1405. while( chars_read > 0 )
  1406. {
  1407. buffer[ chars_read - 1 ] = '\0';
  1408. TQString output( buffer );
  1409. found = output.contains( NAME_SPAMASSASSIN_DAEMON ) > 0;
  1410. chars_read = fread( buffer, sizeof( char ), BUFSIZ, read_fp );
  1411. }
  1412. pclose( read_fp );
  1413. }
  1414. return found;
  1415. }
  1416. int ConfigElem::numberDeletedMailsLastRefresh( )
  1417. {
  1418. return nmbDeletedMailsLastRefresh;
  1419. }
  1420. int ConfigElem::numberDeletedMailsStart( )
  1421. {
  1422. return nmbDeletedMailsLastStart;
  1423. }
  1424. int ConfigElem::numberMovedMailsLastRefresh( )
  1425. {
  1426. return nmbMovedMailsLastRefresh;
  1427. }
  1428. int ConfigElem::numberMovedMailsStart( )
  1429. {
  1430. return nmbMovedMailsLastStart;
  1431. }
  1432. int ConfigElem::numberIgnoredMails( )
  1433. {
  1434. return nmbIgnoredMails;
  1435. }
  1436. TQStringList ConfigElem::getSelectedSenders( ) const
  1437. {
  1438. return m_pshowrecord->getSelectedSenders();
  1439. }
  1440. void ConfigElem::commitBeforeRefresh()
  1441. {
  1442. //start job to commit
  1443. startKIOJob( TQString( "/commit" ) );
  1444. connect( pop3Job, SIGNAL( result( TDEIO::Job* ) ), this, SLOT( slotCommitBeforeRefreshDone( TDEIO::Job* ) ) );
  1445. }
  1446. void ConfigElem::slotCommitBeforeRefreshDone(TDEIO::Job *)
  1447. {
  1448. //after a commit was send, we start a new refresh cyle
  1449. refreshMailList();
  1450. }