kmail

kmaccount.cpp
1 // KMail Account
2 #include <config.h>
3 
4 #include "kmaccount.h"
5 
6 #include "accountmanager.h"
8 #include "globalsettings.h"
9 #include "kmacctfolder.h"
10 #include "kmfoldermgr.h"
11 #include "kmfiltermgr.h"
12 #include "messagesender.h"
13 #include "kmmessage.h"
14 #include "broadcaststatus.h"
15 using KPIM::BroadcastStatus;
16 #include "kmfoldercachedimap.h"
17 
18 #include "progressmanager.h"
19 using KPIM::ProgressItem;
20 using KPIM::ProgressManager;
21 
22 #include <libkpimidentities/identitymanager.h>
23 #include <libkpimidentities/identity.h>
24 
25 using KMail::FolderJob;
26 
27 #include <tdeapplication.h>
28 #include <tdelocale.h>
29 #include <tdemessagebox.h>
30 #include <kdebug.h>
31 #include <tdeconfig.h>
32 
33 #include <tqeventloop.h>
34 
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <errno.h>
38 
39 #include <assert.h>
40 
41 //----------------------
42 #include "kmaccount.moc"
43 
44 //-----------------------------------------------------------------------------
45 KMPrecommand::KMPrecommand(const TQString &precommand, TQObject *parent)
46  : TQObject(parent), mPrecommand(precommand)
47 {
48  BroadcastStatus::instance()->setStatusMsg(
49  i18n("Executing precommand %1").arg(precommand ));
50 
51  mPrecommandProcess.setUseShell(true);
52  mPrecommandProcess << precommand;
53 
54  connect(&mPrecommandProcess, TQ_SIGNAL(processExited(TDEProcess *)),
55  TQ_SLOT(precommandExited(TDEProcess *)));
56 }
57 
58 //-----------------------------------------------------------------------------
59 KMPrecommand::~KMPrecommand()
60 {
61 }
62 
63 
64 //-----------------------------------------------------------------------------
65 bool KMPrecommand::start()
66 {
67  bool ok = mPrecommandProcess.start( TDEProcess::NotifyOnExit );
68  if (!ok) KMessageBox::error(0, i18n("Could not execute precommand '%1'.")
69  .arg(mPrecommand));
70  return ok;
71 }
72 
73 
74 //-----------------------------------------------------------------------------
75 void KMPrecommand::precommandExited(TDEProcess *p)
76 {
77  int exitCode = p->normalExit() ? p->exitStatus() : -1;
78  if (exitCode)
79  KMessageBox::error(0, i18n("The precommand exited with code %1:\n%2")
80  .arg(exitCode).arg(strerror(exitCode)));
81  emit finished(!exitCode);
82 }
83 
84 
85 //-----------------------------------------------------------------------------
86 KMAccount::KMAccount(AccountManager* aOwner, const TQString& aName, uint id)
87  : KAccount( id, aName ),
88  mTrash(KMKernel::self()->trashFolder()->idString()),
89  mOwner(aOwner),
90  mFolder(0),
91  mTimer(0),
92  mInterval(0),
93  mExclude(false),
94  mCheckingMail(false),
95  mPrecommandSuccess(true),
96  mHasInbox(false),
97  mMailCheckProgressItem(0),
98  mIdentityId(0)
99 {
100  assert(aOwner != 0);
101 }
102 
103 void KMAccount::init() {
104  mTrash = kmkernel->trashFolder()->idString();
105  mExclude = false;
106  mInterval = 0;
107  mNewInFolder.clear();
108 }
109 
110 //-----------------------------------------------------------------------------
111 KMAccount::~KMAccount()
112 {
113  if ( (kmkernel && !kmkernel->shuttingDown()) && mFolder ) mFolder->removeAccount(this);
114  if (mTimer) deinstallTimer();
115 }
116 
117 
118 //-----------------------------------------------------------------------------
119 void KMAccount::setName(const TQString& aName)
120 {
121  mName = aName;
122 }
123 
124 
125 //-----------------------------------------------------------------------------
126 void KMAccount::clearPasswd()
127 {
128 }
129 
130 
131 //-----------------------------------------------------------------------------
132 void KMAccount::setFolder(KMFolder* aFolder, bool addAccount)
133 {
134  if(!aFolder) {
135  //kdDebug(5006) << "KMAccount::setFolder() : aFolder == 0" << endl;
136  mFolder = 0;
137  return;
138  }
139  mFolder = (KMAcctFolder*)aFolder;
140  if (addAccount) mFolder->addAccount(this);
141 }
142 
143 
144 //-----------------------------------------------------------------------------
145 void KMAccount::readConfig(TDEConfig& config)
146 {
147  TQString folderName;
148  mFolder = 0;
149  folderName = config.readEntry("Folder");
150  setCheckInterval(config.readNumEntry("check-interval", 0));
151  setTrash(config.readEntry("trash", kmkernel->trashFolder()->idString()));
152  setCheckExclude(config.readBoolEntry("check-exclude", false));
153  setPrecommand(config.readPathEntry("precommand"));
154  setIdentityId(config.readNumEntry("identity-id", 0));
155  if (!folderName.isEmpty())
156  {
157  setFolder(kmkernel->folderMgr()->findIdString(folderName), true);
158  }
159 
160  if (mInterval == 0)
161  deinstallTimer();
162  else
163  installTimer();
164 }
165 
166 void KMAccount::readTimerConfig()
167 {
168  // Re-reads and checks check-interval value and deinstalls timer incase check-interval
169  // for mail check is disabled.
170  // Or else, the mail sync goes into a infinite loop (kolab/issue2607)
171  if (mInterval == 0)
172  deinstallTimer();
173  else
174  installTimer();
175 }
176 
177 //-----------------------------------------------------------------------------
178 void KMAccount::writeConfig(TDEConfig& config)
179 {
180  // ID, Name
181  KAccount::writeConfig(config);
182 
183  config.writeEntry("Type", type());
184  config.writeEntry("Folder", mFolder ? mFolder->idString() : TQString());
185  config.writeEntry("check-interval", mInterval);
186  config.writeEntry("check-exclude", mExclude);
187  config.writePathEntry("precommand", mPrecommand);
188  config.writeEntry("trash", mTrash);
189  if ( mIdentityId && mIdentityId != kmkernel->identityManager()->defaultIdentity().uoid() )
190  config.writeEntry("identity-id", mIdentityId);
191  else
192  config.deleteEntry("identity-id");
193 }
194 
195 
196 //-----------------------------------------------------------------------------
197 void KMAccount::sendReceipt(KMMessage* aMsg)
198 {
199  TDEConfig* cfg = KMKernel::config();
200  bool sendReceipts;
201 
202  TDEConfigGroupSaver saver(cfg, "General");
203 
204  sendReceipts = cfg->readBoolEntry("send-receipts", false);
205  if (!sendReceipts) return;
206 
207  KMMessage *newMsg = aMsg->createDeliveryReceipt();
208  if (newMsg) {
209  mReceipts.append(newMsg);
210  TQTimer::singleShot( 0, this, TQ_SLOT( sendReceipts() ) );
211  }
212 }
213 
214 
215 //-----------------------------------------------------------------------------
216 bool KMAccount::processNewMsg(KMMessage* aMsg)
217 {
218  int rc, processResult;
219 
220  assert(aMsg != 0);
221 
222  // Save this one for readding
223  KMFolderCachedImap* parent = 0;
224  if( type() == "cachedimap" )
225  parent = static_cast<KMFolderCachedImap*>( aMsg->storage() );
226 
227  // checks whether we should send delivery receipts
228  // and sends them.
229  sendReceipt(aMsg);
230 
231  // Set status of new messages that are marked as old to read, otherwise
232  // the user won't see which messages newly arrived.
233  // This is only valid for pop accounts and produces wrong stati for imap.
234  if ( type() != "cachedimap" && type() != "imap" ) {
235  if ( aMsg->isOld() )
236  aMsg->setStatus(KMMsgStatusUnread); // -sanders
237  // aMsg->setStatus(KMMsgStatusRead);
238  else
239  aMsg->setStatus(KMMsgStatusNew);
240  }
241 /*
242 TQFile fileD0( "testdat_xx-kmaccount-0" );
243 if( fileD0.open( IO_WriteOnly ) ) {
244  TQDataStream ds( &fileD0 );
245  ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
246  fileD0.close(); // If data is 0 we just create a zero length file.
247 }
248 */
249  // 0==message moved; 1==processing ok, no move; 2==critical error, abort!
250 
251  processResult = kmkernel->filterMgr()->process(aMsg,KMFilterMgr::Inbound,true,id());
252  if (processResult == 2) {
253  perror("Critical error: Unable to collect mail (out of space?)");
254  KMessageBox::information(0,(i18n("Critical error: "
255  "Unable to collect mail: ")) + TQString::fromLocal8Bit(strerror(errno)));
256  return false;
257  }
258  else if (processResult == 1)
259  {
260  if( type() == "cachedimap" )
261  ; // already done by caller: parent->addMsgInternal( aMsg, false );
262  else {
263  // TODO: Perhaps it would be best, if this if was handled by a virtual
264  // method, so the if( !dimap ) above could die?
265  kmkernel->filterMgr()->tempOpenFolder(mFolder);
266  rc = mFolder->addMsg(aMsg);
267 /*
268 TQFile fileD0( "testdat_xx-kmaccount-1" );
269 if( fileD0.open( IO_WriteOnly ) ) {
270  TQDataStream ds( &fileD0 );
271  ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
272  fileD0.close(); // If data is 0 we just create a zero length file.
273 }
274 */
275  if (rc) {
276  perror("failed to add message");
277  KMessageBox::information(0, i18n("Failed to add message:\n") +
278  TQString(strerror(rc)));
279  return false;
280  }
281  int count = mFolder->count();
282  // If count == 1, the message is immediately displayed
283  if (count != 1) mFolder->unGetMsg(count - 1);
284  }
285  }
286 
287  // Count number of new messages for each folder
288  TQString folderId;
289  if ( processResult == 1 ) {
290  folderId = ( type() == "cachedimap" ) ? parent->folder()->idString()
291  : mFolder->idString();
292  }
293  else {
294  folderId = aMsg->parent()->idString();
295  }
296  addToNewInFolder( folderId, 1 );
297 
298  return true; //Everything's fine - message has been added by filter }
299 }
300 
301 //-----------------------------------------------------------------------------
302 void KMAccount::setCheckInterval(int aInterval)
303 {
304  if (aInterval <= 0)
305  mInterval = 0;
306  else
307  mInterval = aInterval;
308  // Don't call installTimer from here! See #117935.
309 }
310 
311 int KMAccount::checkInterval() const
312 {
313  if ( mInterval <= 0 )
314  return mInterval;
315  return TQMAX( mInterval, GlobalSettings::self()->minimumCheckInterval() );
316 }
317 
318 //----------------------------------------------------------------------------
319 void KMAccount::deleteFolderJobs()
320 {
321  mJobList.setAutoDelete(true);
322  mJobList.clear();
323  mJobList.setAutoDelete(false);
324 }
325 
326 //----------------------------------------------------------------------------
327 void KMAccount::ignoreJobsForMessage( KMMessage* msg )
328 {
329  //FIXME: remove, make folders handle those
330  for( TQPtrListIterator<FolderJob> it(mJobList); it.current(); ++it ) {
331  if ( it.current()->msgList().first() == msg) {
332  FolderJob *job = it.current();
333  mJobList.remove( job );
334  delete job;
335  break;
336  }
337  }
338 }
339 
340 //-----------------------------------------------------------------------------
341 void KMAccount::setCheckExclude(bool aExclude)
342 {
343  mExclude = aExclude;
344 }
345 
346 
347 //-----------------------------------------------------------------------------
348 void KMAccount::installTimer()
349 {
350  if (mInterval <= 0) return;
351  if(!mTimer)
352  {
353  mTimer = new TQTimer(0, "mTimer");
354  connect(mTimer,TQ_SIGNAL(timeout()),TQ_SLOT(mailCheck()));
355  }
356  else
357  {
358  mTimer->stop();
359  }
360  mTimer->start( checkInterval() * 60000 );
361 }
362 
363 
364 //-----------------------------------------------------------------------------
365 void KMAccount::deinstallTimer()
366 {
367  delete mTimer;
368  mTimer = 0;
369 }
370 
371 //-----------------------------------------------------------------------------
372 bool KMAccount::runPrecommand(const TQString &precommand)
373 {
374  // Run the pre command if there is one
375  if ( precommand.isEmpty() )
376  return true;
377 
378  KMPrecommand precommandProcess(precommand, this);
379 
380  BroadcastStatus::instance()->setStatusMsg(
381  i18n("Executing precommand %1").arg(precommand ));
382 
383  connect(&precommandProcess, TQ_SIGNAL(finished(bool)),
384  TQ_SLOT(precommandExited(bool)));
385 
386  kdDebug(5006) << "Running precommand " << precommand << endl;
387  if (!precommandProcess.start()) return false;
388 
389  kapp->eventLoop()->enterLoop();
390 
391  return mPrecommandSuccess;
392 }
393 
394 //-----------------------------------------------------------------------------
395 void KMAccount::precommandExited(bool success)
396 {
397  mPrecommandSuccess = success;
398  kapp->eventLoop()->exitLoop();
399 }
400 
401 //-----------------------------------------------------------------------------
402 void KMAccount::mailCheck()
403 {
404  if (mTimer)
405  mTimer->stop();
406 
407  if ( kmkernel ) {
408  AccountManager *acctmgr = kmkernel->acctMgr();
409  if ( acctmgr )
410  acctmgr->singleCheckMail(this, false);
411  }
412 }
413 
414 //-----------------------------------------------------------------------------
415 void KMAccount::sendReceipts()
416 {
417  TQValueList<KMMessage*>::Iterator it;
418  for(it = mReceipts.begin(); it != mReceipts.end(); ++it)
419  kmkernel->msgSender()->send(*it); //might process events
420  mReceipts.clear();
421 }
422 
423 //-----------------------------------------------------------------------------
424 TQString KMAccount::encryptStr(const TQString &aStr)
425 {
426  TQString result;
427  for (uint i = 0; i < aStr.length(); i++)
428  /* yes, no typo. can't encode ' ' or '!' because
429  they're the unicode BOM. stupid scrambling. stupid. */
430  result += (aStr[i].unicode() <= 0x21 ) ? aStr[i] :
431  TQChar(0x1001F - aStr[i].unicode());
432  return result;
433 }
434 
435 //-----------------------------------------------------------------------------
436 TQString KMAccount::importPassword(const TQString &aStr)
437 {
438  unsigned int i, val;
439  unsigned int len = aStr.length();
440  TQCString result;
441  result.resize(len+1);
442 
443  for (i=0; i<len; i++)
444  {
445  val = aStr[i] - ' ';
446  val = (255-' ') - val;
447  result[i] = (char)(val + ' ');
448  }
449  result[i] = '\0';
450 
451  return encryptStr(result);
452 }
453 
454 void KMAccount::invalidateIMAPFolders()
455 {
456  // Default: Don't do anything. The IMAP account will handle it
457 }
458 
459 void KMAccount::pseudoAssign( const KMAccount * a ) {
460  if ( !a ) return;
461 
462  setName( a->name() );
463  setId( a->id() );
464  setCheckInterval( a->checkInterval() );
465  setCheckExclude( a->checkExclude() );
466  setFolder( a->folder() );
467  setPrecommand( a->precommand() );
468  setTrash( a->trash() );
469  setIdentityId( a->identityId() );
470 }
471 
472 //-----------------------------------------------------------------------------
473 void KMAccount::checkDone( bool newmail, CheckStatus status )
474 {
475  setCheckingMail( false );
476  // Reset the timeout for automatic mailchecking. The user might have
477  // triggered the check manually.
478  if (mTimer)
479  mTimer->start( checkInterval() * 60000 );
480  if ( mMailCheckProgressItem ) {
481  // set mMailCheckProgressItem = 0 before calling setComplete() to prevent
482  // a race condition
483  ProgressItem *savedMailCheckProgressItem = mMailCheckProgressItem;
484  mMailCheckProgressItem = 0;
485  savedMailCheckProgressItem->setComplete(); // that will delete it
486  }
487 
488  emit newMailsProcessed( mNewInFolder );
489  emit finishedCheck( newmail, status );
490  mNewInFolder.clear();
491 }
492 
493 //-----------------------------------------------------------------------------
494 void KMAccount::addToNewInFolder( TQString folderId, int num )
495 {
496  if ( mNewInFolder.find( folderId ) == mNewInFolder.end() )
497  mNewInFolder[folderId] = num;
498  else
499  mNewInFolder[folderId] += num;
500 }
Simple wrapper class that contains the kmail account handling stuff that is usually not required outs...
Definition: kmacctfolder.h:35
Mail folder.
Definition: kmfolder.h:69
Central point of coordination in KMail.
Definition: kmkernel.h:92
This is a Mime Message.
Definition: kmmessage.h:68
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
Definition: kmmessage.cpp:4153
KMMessage * createDeliveryReceipt() const
Create a new message that is a delivery receipt of this message, filling required header fileds with ...
Definition: kmmessage.cpp:1635
The account manager is responsible for creating accounts of various types via the factory method crea...