kmail

kmacctimap.cpp
1
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include "kmacctimap.h"
27using KMail::SieveConfig;
28
29#include "kmmessage.h"
30#include "broadcaststatus.h"
31using KPIM::BroadcastStatus;
32#include "kmfoldertree.h"
33#include "kmfoldermgr.h"
34#include "kmfolderimap.h"
35#include "kmmainwin.h"
36#include "kmmsgdict.h"
37#include "kmfilter.h"
38#include "kmfiltermgr.h"
39#include "folderstorage.h"
40#include "imapjob.h"
41#include "actionscheduler.h"
42using KMail::ActionScheduler;
43using KMail::ImapJob;
44using KMail::ImapAccountBase;
45#include "progressmanager.h"
46using KPIM::ProgressItem;
47using KPIM::ProgressManager;
48#include <tdeio/scheduler.h>
49#include <tdeio/slave.h>
50#include <tdemessagebox.h>
51#include <kdebug.h>
52
53#include <tqstylesheet.h>
54
55#include <errno.h>
56
57//-----------------------------------------------------------------------------
58KMAcctImap::KMAcctImap(AccountManager* aOwner, const TQString& aAccountName, uint id):
59 KMail::ImapAccountBase(aOwner, aAccountName, id),
60 mCountRemainChecks( 0 ),
61 mErrorTimer( 0, "mErrorTimer" )
62{
63 mFolder = 0;
64 mScheduler = 0;
65 mNoopTimer.start( 60000 ); // // send a noop every minute
66 mOpenFolders.setAutoDelete(true);
67 connect(kmkernel->imapFolderMgr(), TQ_SIGNAL(changed()),
68 this, TQ_SLOT(slotUpdateFolderList()));
69 connect(&mErrorTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotResetConnectionError()));
70
71 TQString serNumUri = locateLocal( "data", "kmail/unfiltered." +
72 TQString("%1").arg(KAccount::id()) );
73 TDEConfig config( serNumUri );
74 TQStringList serNums = config.readListEntry( "unfiltered" );
75 mFilterSerNumsToSave.setAutoDelete( false );
76
77 for ( TQStringList::ConstIterator it = serNums.begin();
78 it != serNums.end(); ++it ) {
79 mFilterSerNums.append( (*it).toUInt() );
80 mFilterSerNumsToSave.insert( *it, (const int *)1 );
81 }
82}
83
84
85//-----------------------------------------------------------------------------
86KMAcctImap::~KMAcctImap()
87{
88 killAllJobs( true );
89
90 TQString serNumUri = locateLocal( "data", "kmail/unfiltered." +
91 TQString("%1").arg(KAccount::id()) );
92 TDEConfig config( serNumUri );
93 TQStringList serNums;
94 TQDictIterator<int> it( mFilterSerNumsToSave );
95 for( ; it.current(); ++it )
96 serNums.append( it.currentKey() );
97 config.writeEntry( "unfiltered", serNums );
98}
99
100
101//-----------------------------------------------------------------------------
102TQString KMAcctImap::type() const
103{
104 return "imap";
105}
106
107//-----------------------------------------------------------------------------
108void KMAcctImap::pseudoAssign( const KMAccount * a ) {
109 killAllJobs( true );
110 if (mFolder)
111 {
112 mFolder->setContentState(KMFolderImap::imapNoInformation);
113 mFolder->setSubfolderState(KMFolderImap::imapNoInformation);
114 }
115 ImapAccountBase::pseudoAssign( a );
116}
117
118//-----------------------------------------------------------------------------
119void KMAcctImap::setImapFolder(KMFolderImap *aFolder)
120{
121 mFolder = aFolder;
122 mFolder->setImapPath( "/" );
123}
124
125
126//-----------------------------------------------------------------------------
127
128bool KMAcctImap::handleError( int errorCode, const TQString &errorMsg, TDEIO::Job* job, const TQString& context, bool abortSync )
129{
130 /* TODO check where to handle this one better. */
131 if ( errorCode == TDEIO::ERR_DOES_NOT_EXIST ) {
132 // folder is gone, so reload the folderlist
133 if ( mFolder )
134 mFolder->listDirectory();
135 return true;
136 }
137 return ImapAccountBase::handleError( errorCode, errorMsg, job, context, abortSync );
138}
139
140
141//-----------------------------------------------------------------------------
142void KMAcctImap::killAllJobs( bool disconnectSlave )
143{
144 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
145 for ( ; it != mapJobData.end(); ++it)
146 {
147 TQPtrList<KMMessage> msgList = (*it).msgList;
148 TQPtrList<KMMessage>::Iterator it2 = msgList.begin();
149 for ( ; it2 != msgList.end(); ++it2 ) {
150 KMMessage *msg = *it2;
151 if ( msg->transferInProgress() ) {
152 kdDebug(5006) << "KMAcctImap::killAllJobs - resetting mail" << endl;
153 msg->setTransferInProgress( false );
154 }
155 }
156 if ((*it).parent)
157 {
158 // clear folder state
159 KMFolderImap *fld = static_cast<KMFolderImap*>((*it).parent->storage());
160 fld->setCheckingValidity(false);
161 fld->quiet(false);
162 fld->setContentState(KMFolderImap::imapNoInformation);
163 fld->setSubfolderState(KMFolderImap::imapNoInformation);
164 fld->sendFolderComplete(FALSE);
165 fld->removeJobs();
166 }
167 if ( (*it).progressItem )
168 {
169 (*it).progressItem->setComplete();
170 }
171 }
172 if (mSlave && mapJobData.begin() != mapJobData.end())
173 {
174 mSlave->kill();
175 mSlave = 0;
176 }
177 // remove the jobs
178 mapJobData.clear();
179 // KMAccount::deleteFolderJobs(); doesn't work here always, it deletes jobs from
180 // its own mJobList instead of our mJobList...
181 KMAccount::deleteFolderJobs();
182 TQPtrListIterator<ImapJob> it2( mJobList );
183 while ( it2.current() ) {
184 ImapJob *job = it2.current();
185 ++it2;
186 job->kill();
187 }
188 mJobList.clear();
189 // make sure that no new-mail-check is blocked
190 if (mCountRemainChecks > 0)
191 {
192 checkDone( false, CheckOK ); // returned 0 new messages
193 mCountRemainChecks = 0;
194 }
195 if ( disconnectSlave && slave() ) {
196 TDEIO::Scheduler::disconnectSlave( slave() );
197 mSlave = 0;
198 }
199}
200
201//-----------------------------------------------------------------------------
202void KMAcctImap::ignoreJobsForMessage( KMMessage* msg )
203{
204 if (!msg) return;
205 TQPtrListIterator<ImapJob> it( mJobList );
206 while ( it.current() )
207 {
208 ImapJob *job = it.current();
209 ++it;
210 if ( job->msgList().first() == msg )
211 {
212 job->kill();
213 }
214 }
215}
216
217//-----------------------------------------------------------------------------
218void KMAcctImap::ignoreJobsForFolder( KMFolder* folder )
219{
220 TQPtrListIterator<ImapJob> it( mJobList );
221 while ( it.current() )
222 {
223 ImapJob *job = it.current();
224 ++it;
225 if ( !job->msgList().isEmpty() && job->msgList().first()->parent() == folder )
226 {
227 job->kill();
228 }
229 }
230}
231
232//-----------------------------------------------------------------------------
233void KMAcctImap::removeSlaveJobsForFolder( KMFolder* folder )
234{
235 // Make sure the folder is not referenced in any tdeio slave jobs
236 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
237 while ( it != mapJobData.end() ) {
238 TQMap<TDEIO::Job*, jobData>::Iterator i = it;
239 it++;
240 if ( (*i).parent ) {
241 if ( (*i).parent == folder ) {
242 mapJobData.remove(i);
243 }
244 }
245 }
246}
247
248//-----------------------------------------------------------------------------
249void KMAcctImap::cancelMailCheck()
250{
251 // Make list of folders to reset, like in killAllJobs
252 TQValueList<KMFolderImap*> folderList;
253 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
254 for (; it != mapJobData.end(); ++it) {
255 if ( (*it).cancellable && (*it).parent ) {
256 folderList << static_cast<KMFolderImap*>((*it).parent->storage());
257 }
258 }
259 // Kill jobs
260 // FIXME
261 // ImapAccountBase::cancelMailCheck();
262 killAllJobs( true );
263 // emit folderComplete, this is important for
264 // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
265 for( TQValueList<KMFolderImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
266 KMFolderImap *fld = *it;
267 fld->sendFolderComplete(FALSE);
268 }
269}
270
271//-----------------------------------------------------------------------------
272void KMAcctImap::processNewMail(bool interactive)
273{
274 kdDebug() << "processNewMail " << mCheckingSingleFolder << ",status="<<makeConnection()<<endl;
275 if (!mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
276 makeConnection() == ImapAccountBase::Error)
277 {
278 mCountRemainChecks = 0;
279 mCheckingSingleFolder = false;
280 checkDone( false, CheckError );
281 return;
282 }
283 // if necessary then initialize the list of folders which should be checked
284 if( mMailCheckFolders.isEmpty() )
285 {
286 slotUpdateFolderList();
287 // if no folders should be checked then the check is finished
288 if( mMailCheckFolders.isEmpty() )
289 {
290 checkDone( false, CheckOK );
291 mCheckingSingleFolder = false;
292 return;
293 }
294 }
295 // Ok, we're really checking, get a progress item;
296 Q_ASSERT( !mMailCheckProgressItem );
297 mMailCheckProgressItem =
298 ProgressManager::createProgressItem(
299 "MailCheckAccount" + name(),
300 i18n("Checking account: %1" ).arg( TQStyleSheet::escape( name() ) ),
301 TQString(), // status
302 true, // can be canceled
303 useSSL() || useTLS() );
304
305 mMailCheckProgressItem->setTotalItems( mMailCheckFolders.count() );
306 connect ( mMailCheckProgressItem,
307 TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem*) ),
308 this,
309 TQ_SLOT( slotMailCheckCanceled() ) );
310
311 TQValueList<TQGuardedPtr<KMFolder> >::Iterator it;
312 // first get the current count of unread-messages
313 mCountRemainChecks = 0;
314 mCountUnread = 0;
315 mUnreadBeforeCheck.clear();
316 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
317 {
318 KMFolder *folder = *it;
319 if (folder && !folder->noContent())
320 {
321 mUnreadBeforeCheck[folder->idString()] = folder->countUnread();
322 }
323 }
324 bool gotError = false;
325 // then check for new mails
326 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
327 {
328 KMFolder *folder = *it;
329 if (folder && !folder->noContent())
330 {
331 KMFolderImap *imapFolder = static_cast<KMFolderImap*>(folder->storage());
332 if ( imapFolder->getContentState() != KMFolderImap::imapListingInProgress
333 && imapFolder->getContentState() != KMFolderImap::imapDownloadInProgress )
334 {
335 // connect the result-signals for new-mail-notification
336 mCountRemainChecks++;
337
338 if (imapFolder->isSelected()) {
339 connect(imapFolder, TQ_SIGNAL(folderComplete(KMFolderImap*, bool)),
340 this, TQ_SLOT(postProcessNewMail(KMFolderImap*, bool)));
341 imapFolder->getFolder();
342 } else if ( kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( id() ) &&
343 imapFolder->folder()->isSystemFolder() &&
344 imapFolder->imapPath() == "/INBOX/" ) {
345 imapFolder->open("acctimap"); // will be closed in the folderSelected slot
346 // first get new headers before we select the folder
347 imapFolder->setSelected( true );
348 connect( imapFolder, TQ_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
349 this, TQ_SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
350 imapFolder->getFolder();
351 }
352 else {
353 connect(imapFolder, TQ_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
354 this, TQ_SLOT(postProcessNewMail(KMFolder*)));
355 bool ok = imapFolder->processNewMail(interactive);
356 if (!ok)
357 {
358 // there was an error so cancel
359 mCountRemainChecks--;
360 gotError = true;
361 if ( mMailCheckProgressItem ) {
362 mMailCheckProgressItem->incCompletedItems();
363 mMailCheckProgressItem->updateProgress();
364 }
365 }
366 }
367 }
368 }
369 } // end for
370 if ( gotError )
371 slotUpdateFolderList();
372 // for the case the account is down and all folders report errors
373 if ( mCountRemainChecks == 0 )
374 {
375 mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
376 ImapAccountBase::postProcessNewMail();
377 mUnreadBeforeCheck.clear();
378 mCheckingSingleFolder = false;
379 }
380}
381
382//-----------------------------------------------------------------------------
383void KMAcctImap::postProcessNewMail(KMFolderImap* folder, bool)
384{
385 disconnect(folder, TQ_SIGNAL(folderComplete(KMFolderImap*, bool)),
386 this, TQ_SLOT(postProcessNewMail(KMFolderImap*, bool)));
387 postProcessNewMail(static_cast<KMFolder*>(folder->folder()));
388}
389
390void KMAcctImap::postProcessNewMail( KMFolder * folder )
391{
392 disconnect( folder->storage(), TQ_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
393 this, TQ_SLOT(postProcessNewMail(KMFolder*)) );
394
395 if ( mMailCheckProgressItem ) {
396 mMailCheckProgressItem->incCompletedItems();
397 mMailCheckProgressItem->updateProgress();
398 mMailCheckProgressItem->setStatus( folder->prettyURL() + i18n(" completed") );
399 }
400 mCountRemainChecks--;
401
402 // count the unread messages
403 const TQString folderId = folder->idString();
404 int newInFolder = folder->countUnread();
405 if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
406 newInFolder -= mUnreadBeforeCheck[folderId];
407 if ( newInFolder > 0 ) {
408 addToNewInFolder( folderId, newInFolder );
409 mCountUnread += newInFolder;
410 }
411
412 // Filter messages
413 TQValueListIterator<TQ_UINT32> filterIt = mFilterSerNums.begin();
414 TQValueList<TQ_UINT32> inTransit;
415
416 if (ActionScheduler::isEnabled() ||
417 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
418 KMFilterMgr::FilterSet set = KMFilterMgr::Inbound;
419 TQValueList<KMFilter*> filters = kmkernel->filterMgr()->filters();
420 if (!mScheduler) {
421 mScheduler = new KMail::ActionScheduler( set, filters );
422 mScheduler->setAccountId( id() );
423 connect( mScheduler, TQ_SIGNAL(filtered(TQ_UINT32)), this, TQ_SLOT(slotFiltered(TQ_UINT32)) );
424 } else {
425 mScheduler->setFilterList( filters );
426 }
427 }
428
429 while (filterIt != mFilterSerNums.end()) {
430 int idx = -1;
431 KMFolder *folder = 0;
432 KMMessage *msg = 0;
433 KMMsgDict::instance()->getLocation( *filterIt, &folder, &idx );
434 // It's possible that the message has been deleted or moved into a
435 // different folder, or that the serNum is stale
436 if ( !folder ) {
437 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
438 ++filterIt;
439 continue;
440 }
441
442 KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder->storage());
443 if (!imapFolder ||
444 !imapFolder->folder()->isSystemFolder() ||
445 !(imapFolder->imapPath() == "/INBOX/") ) { // sanity checking
446 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
447 ++filterIt;
448 continue;
449 }
450
451 if (idx != -1) {
452
453 msg = folder->getMsg( idx );
454 if (!msg) { // sanity checking
455 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
456 ++filterIt;
457 continue;
458 }
459
460 if (ActionScheduler::isEnabled() ||
461 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
462 mScheduler->execFilters( msg );
463 } else {
464 if (msg->transferInProgress()) {
465 inTransit.append( *filterIt );
466 ++filterIt;
467 continue;
468 }
469 msg->setTransferInProgress(true);
470 if ( !msg->isComplete() ) {
471 FolderJob *job = folder->createJob(msg);
472 connect(job, TQ_SIGNAL(messageRetrieved(KMMessage*)),
473 TQ_SLOT(slotFilterMsg(KMMessage*)));
474 job->start();
475 } else {
476 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
477 if (slotFilterMsg(msg) == 2) break;
478 }
479 }
480 }
481 ++filterIt;
482 }
483 mFilterSerNums = inTransit;
484
485 if (mCountRemainChecks == 0)
486 {
487 // all checks are done
488 mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
489 // when we check only one folder (=selected) and we have new mails
490 // then do not display a summary as the normal status message is better
491 bool showStatus = ( mCheckingSingleFolder && mCountUnread > 0 ) ? false : true;
492 ImapAccountBase::postProcessNewMail( showStatus );
493 mUnreadBeforeCheck.clear();
494 mCheckingSingleFolder = false;
495 }
496}
497
498//-----------------------------------------------------------------------------
499void KMAcctImap::slotFiltered(TQ_UINT32 serNum)
500{
501 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( serNum ) );
502}
503
504//-----------------------------------------------------------------------------
505void KMAcctImap::slotUpdateFolderList()
506{
507 if ( !mFolder || !mFolder->folder() || !mFolder->folder()->child() )
508 {
509 kdWarning(5006) << "KMAcctImap::slotUpdateFolderList return" << endl;
510 return;
511 }
512 TQStringList strList;
513 mMailCheckFolders.clear();
514 kmkernel->imapFolderMgr()->createFolderList(&strList, &mMailCheckFolders,
515 mFolder->folder()->child(), TQString(), false);
516 // the new list
517 TQValueList<TQGuardedPtr<KMFolder> > includedFolders;
518 // check for excluded folders
519 TQValueList<TQGuardedPtr<KMFolder> >::Iterator it;
520 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
521 {
522 KMFolderImap* folder = static_cast<KMFolderImap*>(((KMFolder*)(*it))->storage());
523 if (folder->includeInMailCheck())
524 includedFolders.append(*it);
525 }
526 mMailCheckFolders = includedFolders;
527}
528
529//-----------------------------------------------------------------------------
530void KMAcctImap::listDirectory()
531{
532 mFolder->listDirectory();
533}
534
535//-----------------------------------------------------------------------------
536void KMAcctImap::readConfig(TDEConfig& config)
537{
538 ImapAccountBase::readConfig( config );
539}
540
541//-----------------------------------------------------------------------------
542void KMAcctImap::slotMailCheckCanceled()
543{
544 if( mMailCheckProgressItem )
545 mMailCheckProgressItem->setComplete();
546 cancelMailCheck();
547}
548
549//-----------------------------------------------------------------------------
550FolderStorage* KMAcctImap::rootFolder() const
551{
552 return mFolder;
553}
554
555ImapAccountBase::ConnectionState KMAcctImap::makeConnection()
556{
557 if ( mSlaveConnectionError )
558 {
559 mErrorTimer.start(100, true); // Clear error flag
560 return Error;
561 }
562 return ImapAccountBase::makeConnection();
563}
564
565void KMAcctImap::slotResetConnectionError()
566{
567 mSlaveConnectionError = false;
568 kdDebug(5006) << k_funcinfo << endl;
569}
570
571void KMAcctImap::slotFolderSelected( KMFolderImap* folder, bool )
572{
573 folder->setSelected( false );
574 disconnect( folder, TQ_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
575 this, TQ_SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
576 postProcessNewMail( static_cast<KMFolder*>(folder->folder()) );
577 folder->close( "acctimap" );
578}
579
580void KMAcctImap::execFilters(TQ_UINT32 serNum)
581{
582 if ( !kmkernel->filterMgr()->atLeastOneFilterAppliesTo( id() ) ) return;
583 TQValueListIterator<TQ_UINT32> findIt = mFilterSerNums.find( serNum );
584 if ( findIt != mFilterSerNums.end() )
585 return;
586 mFilterSerNums.append( serNum );
587 mFilterSerNumsToSave.insert( TQString( "%1" ).arg( serNum ), (const int *)1 );
588}
589
590int KMAcctImap::slotFilterMsg( KMMessage *msg )
591{
592 if ( !msg ) {
593 // messageRetrieved(0) is always possible
594 return -1;
595 }
596 msg->setTransferInProgress(false);
597 TQ_UINT32 serNum = msg->getMsgSerNum();
598 if ( serNum )
599 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( serNum ) );
600
601 int filterResult = kmkernel->filterMgr()->process(msg,
602 KMFilterMgr::Inbound,
603 true,
604 id() );
605 if (filterResult == 2) {
606 // something went horribly wrong (out of space?)
607 kmkernel->emergencyExit( i18n("Unable to process messages: " ) + TQString::fromLocal8Bit(strerror(errno)));
608 return 2;
609 }
610 if (msg->parent()) { // unGet this msg
611 int idx = -1;
612 KMFolder * p = 0;
613 KMMsgDict::instance()->getLocation( msg, &p, &idx );
614 assert( p == msg->parent() ); assert( idx >= 0 );
615 p->unGetMsg( idx );
616 }
617
618 return filterResult;
619}
620
621#include "kmacctimap.moc"
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
Definition: folderstorage.h:80
Mail folder.
Definition: kmfolder.h:69
int countUnread()
Number of new or unread messages in this folder.
Definition: kmfolder.cpp:450
TQString idString() const
Returns a string that can be used to identify this folder.
Definition: kmfolder.cpp:705
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Definition: kmfolder.cpp:593
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition: kmfolder.cpp:326
FolderJob * createJob(KMMessage *msg, FolderJob::JobType jt=FolderJob::tGetMessage, KMFolder *folder=0, TQString partSpecifier=TQString(), const AttachmentStrategy *as=0) const
These methods create respective FolderJob (You should derive FolderJob for each derived KMFolder).
Definition: kmfolder.cpp:346
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
bool noContent() const
Returns, if the folder can't contain mails, but only subfolder.
Definition: kmfolder.cpp:301
This is a Mime Message.
Definition: kmmessage.h:68
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
Definition: kmmessage.cpp:243
bool transferInProgress() const
Return, if the message should not be deleted.
Definition: kmmessage.cpp:236
bool isComplete() const
Return true if the complete message is available without referring to the backing store.
Definition: kmmessage.h:867
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
Definition: kmmsgdict.cpp:319
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
The account manager is responsible for creating accounts of various types via the factory method crea...
folderdiaquotatab.h
Definition: aboutdata.cpp:40