TDE personal information management applications
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.

imapaccountbase.cpp 52KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454
  1. /** -*- c++ -*-
  2. * imapaccountbase.cpp
  3. *
  4. * Copyright (c) 2000-2002 Michael Haeckel <haeckel@kde.org>
  5. * Copyright (c) 2002 Marc Mutz <mutz@kde.org>
  6. *
  7. * This file is based on work on pop3 and imap account implementations
  8. * by Don Sanders <sanders@kde.org> and Michael Haeckel <haeckel@kde.org>
  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; version 2 of the License
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. */
  23. #ifdef HAVE_CONFIG_H
  24. #include <config.h>
  25. #endif
  26. #include "imapaccountbase.h"
  27. using KMail::SieveConfig;
  28. #include "accountmanager.h"
  29. using KMail::AccountManager;
  30. #include "kmfolder.h"
  31. #include "broadcaststatus.h"
  32. using KPIM::BroadcastStatus;
  33. #include "kmmainwin.h"
  34. #include "kmfolderimap.h"
  35. #include "kmmainwidget.h"
  36. #include "kmmainwin.h"
  37. #include "kmmsgpart.h"
  38. #include "acljobs.h"
  39. #include "kmfoldercachedimap.h"
  40. #include "bodyvisitor.h"
  41. using KMail::BodyVisitor;
  42. #include "imapjob.h"
  43. using KMail::ImapJob;
  44. #include "protocols.h"
  45. #include "progressmanager.h"
  46. using KPIM::ProgressManager;
  47. #include "kmfoldermgr.h"
  48. #include "listjob.h"
  49. #include <tdeapplication.h>
  50. #include <kdebug.h>
  51. #include <tdeconfig.h>
  52. #include <tdelocale.h>
  53. #include <tdemessagebox.h>
  54. using TDEIO::MetaData;
  55. #include <tdeio/passdlg.h>
  56. using TDEIO::PasswordDialog;
  57. #include <tdeio/scheduler.h>
  58. #include <tdeio/slave.h>
  59. #include <mimelib/bodypart.h>
  60. #include <mimelib/body.h>
  61. #include <mimelib/headers.h>
  62. #include <mimelib/message.h>
  63. //using TDEIO::Scheduler; // use FQN below
  64. #include <tqregexp.h>
  65. #include <tqstylesheet.h>
  66. namespace KMail {
  67. static const unsigned short int imapDefaultPort = 143;
  68. //
  69. //
  70. // Ctor and Dtor
  71. //
  72. //
  73. ImapAccountBase::ImapAccountBase( AccountManager * parent, const TQString & name, uint id )
  74. : NetworkAccount( parent, name, id ),
  75. mIdleTimer( 0, "mIdleTimer" ),
  76. mNoopTimer( 0, "mNoopTimer" ),
  77. mTotal( 0 ),
  78. mCountUnread( 0 ),
  79. mCountLastUnread( 0 ),
  80. mAutoExpunge( true ),
  81. mHiddenFolders( false ),
  82. mOnlySubscribedFolders( false ),
  83. mOnlyLocallySubscribedFolders( false ),
  84. mLoadOnDemand( true ),
  85. mListOnlyOpenFolders( false ),
  86. mProgressEnabled( false ),
  87. mErrorDialogIsActive( false ),
  88. mPasswordDialogIsActive( false ),
  89. mACLSupport( true ),
  90. mAnnotationSupport( true ),
  91. mQuotaSupport( true ),
  92. mSlaveConnected( false ),
  93. mSlaveConnectionError( false ),
  94. mCheckingSingleFolder( false ),
  95. mListDirProgressItem( 0 )
  96. {
  97. mPort = imapDefaultPort;
  98. mBodyPartList.setAutoDelete(true);
  99. TDEIO::Scheduler::connect(TQT_SIGNAL(slaveError(TDEIO::Slave *, int, const TQString &)),
  100. this, TQT_SLOT(slotSchedulerSlaveError(TDEIO::Slave *, int, const TQString &)));
  101. TDEIO::Scheduler::connect(TQT_SIGNAL(slaveConnected(TDEIO::Slave *)),
  102. this, TQT_SLOT(slotSchedulerSlaveConnected(TDEIO::Slave *)));
  103. connect(&mNoopTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotNoopTimeout()));
  104. connect(&mIdleTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotIdleTimeout()));
  105. }
  106. ImapAccountBase::~ImapAccountBase() {
  107. kdWarning( mSlave, 5006 )
  108. << "slave should have been destroyed by subclass!" << endl;
  109. }
  110. void ImapAccountBase::init() {
  111. mAutoExpunge = true;
  112. mHiddenFolders = false;
  113. mOnlySubscribedFolders = false;
  114. mOnlyLocallySubscribedFolders = false;
  115. mLoadOnDemand = true;
  116. mListOnlyOpenFolders = false;
  117. mProgressEnabled = false;
  118. }
  119. void ImapAccountBase::pseudoAssign( const KMAccount * a ) {
  120. NetworkAccount::pseudoAssign( a );
  121. const ImapAccountBase * i = dynamic_cast<const ImapAccountBase*>( a );
  122. if ( !i ) return;
  123. setAutoExpunge( i->autoExpunge() );
  124. setHiddenFolders( i->hiddenFolders() );
  125. setOnlySubscribedFolders( i->onlySubscribedFolders() );
  126. setOnlyLocallySubscribedFolders( i->onlyLocallySubscribedFolders() );
  127. setLoadOnDemand( i->loadOnDemand() );
  128. setListOnlyOpenFolders( i->listOnlyOpenFolders() );
  129. setNamespaces( i->namespaces() );
  130. setNamespaceToDelimiter( i->namespaceToDelimiter() );
  131. localBlacklistFromStringList( i->locallyBlacklistedFolders() );
  132. }
  133. unsigned short int ImapAccountBase::defaultPort() const {
  134. return imapDefaultPort;
  135. }
  136. TQString ImapAccountBase::protocol() const {
  137. return useSSL() ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL;
  138. }
  139. //
  140. //
  141. // Getters and Setters
  142. //
  143. //
  144. void ImapAccountBase::setAutoExpunge( bool expunge ) {
  145. mAutoExpunge = expunge;
  146. }
  147. void ImapAccountBase::setHiddenFolders( bool show ) {
  148. mHiddenFolders = show;
  149. }
  150. void ImapAccountBase::setOnlySubscribedFolders( bool show ) {
  151. mOnlySubscribedFolders = show;
  152. }
  153. void ImapAccountBase::setOnlyLocallySubscribedFolders( bool show ) {
  154. mOnlyLocallySubscribedFolders = show;
  155. }
  156. void ImapAccountBase::setLoadOnDemand( bool load ) {
  157. mLoadOnDemand = load;
  158. }
  159. void ImapAccountBase::setListOnlyOpenFolders( bool only ) {
  160. mListOnlyOpenFolders = only;
  161. }
  162. //
  163. //
  164. // read/write config
  165. //
  166. //
  167. void ImapAccountBase::readConfig( /*const*/ TDEConfig/*Base*/ & config ) {
  168. NetworkAccount::readConfig( config );
  169. setAutoExpunge( config.readBoolEntry( "auto-expunge", false ) );
  170. setHiddenFolders( config.readBoolEntry( "hidden-folders", false ) );
  171. setOnlySubscribedFolders( config.readBoolEntry( "subscribed-folders", false ) );
  172. setOnlyLocallySubscribedFolders( config.readBoolEntry( "locally-subscribed-folders", false ) );
  173. setLoadOnDemand( config.readBoolEntry( "loadondemand", false ) );
  174. setListOnlyOpenFolders( config.readBoolEntry( "listOnlyOpenFolders", false ) );
  175. mCapabilities = config.readListEntry( "capabilities", TQStringList() );
  176. // read namespaces
  177. nsMap map;
  178. TQStringList list = config.readListEntry( TQString::number( PersonalNS ) );
  179. if ( !list.isEmpty() )
  180. map[PersonalNS] = list.gres( "\"", "" );
  181. list = config.readListEntry( TQString::number( OtherUsersNS ) );
  182. if ( !list.isEmpty() )
  183. map[OtherUsersNS] = list.gres( "\"", "" );
  184. list = config.readListEntry( TQString::number( SharedNS ) );
  185. if ( !list.isEmpty() )
  186. map[SharedNS] = list.gres( "\"", "" );
  187. setNamespaces( map );
  188. // read namespace - delimiter
  189. namespaceDelim entries = config.entryMap( config.group() );
  190. namespaceDelim namespaceToDelimiter;
  191. for ( namespaceDelim::ConstIterator it = entries.begin();
  192. it != entries.end(); ++it ) {
  193. if ( it.key().startsWith( "Namespace:" ) ) {
  194. TQString key = it.key().right( it.key().length() - 10 );
  195. namespaceToDelimiter[key] = it.data();
  196. }
  197. }
  198. setNamespaceToDelimiter( namespaceToDelimiter );
  199. mOldPrefix = config.readEntry( "prefix" );
  200. if ( !mOldPrefix.isEmpty() ) {
  201. makeConnection();
  202. }
  203. localBlacklistFromStringList( config.readListEntry( "locallyUnsubscribedFolders" ) );
  204. }
  205. void ImapAccountBase::writeConfig( TDEConfig/*Base*/ & config ) /*const*/ {
  206. NetworkAccount::writeConfig( config );
  207. config.writeEntry( "auto-expunge", autoExpunge() );
  208. config.writeEntry( "hidden-folders", hiddenFolders() );
  209. config.writeEntry( "subscribed-folders", onlySubscribedFolders() );
  210. config.writeEntry( "locally-subscribed-folders", onlyLocallySubscribedFolders() );
  211. config.writeEntry( "loadondemand", loadOnDemand() );
  212. config.writeEntry( "listOnlyOpenFolders", listOnlyOpenFolders() );
  213. config.writeEntry( "capabilities", mCapabilities );
  214. TQString data;
  215. for ( nsMap::Iterator it = mNamespaces.begin(); it != mNamespaces.end(); ++it ) {
  216. if ( !it.data().isEmpty() ) {
  217. data = "\"" + it.data().join("\",\"") + "\"";
  218. config.writeEntry( TQString::number( it.key() ), data );
  219. }
  220. }
  221. TQString key;
  222. for ( namespaceDelim::ConstIterator it = mNamespaceToDelimiter.begin();
  223. it != mNamespaceToDelimiter.end(); ++it ) {
  224. key = "Namespace:" + it.key();
  225. config.writeEntry( key, it.data() );
  226. }
  227. config.writeEntry( "locallyUnsubscribedFolders", locallyBlacklistedFolders() );
  228. }
  229. //
  230. //
  231. // Network processing
  232. //
  233. //
  234. MetaData ImapAccountBase::slaveConfig() const {
  235. MetaData m = NetworkAccount::slaveConfig();
  236. m.insert( "auth", auth() );
  237. if ( autoExpunge() )
  238. m.insert( "expunge", "auto" );
  239. return m;
  240. }
  241. ImapAccountBase::ConnectionState ImapAccountBase::makeConnection()
  242. {
  243. if ( mSlave && mSlaveConnected ) {
  244. return Connected;
  245. }
  246. if ( mPasswordDialogIsActive ) return Connecting;
  247. if( mAskAgain || ( ( passwd().isEmpty() || login().isEmpty() ) &&
  248. auth() != "GSSAPI" ) ) {
  249. Q_ASSERT( !mSlave ); // disconnected on 'wrong login' error already, or first try
  250. TQString log = login();
  251. TQString pass = passwd();
  252. // We init "store" to true to indicate that we want to have the
  253. // "keep password" checkbox. Then, we set [Passwords]Keep to
  254. // storePasswd(), so that the checkbox in the dialog will be
  255. // init'ed correctly:
  256. TDEConfigGroup passwords( TDEGlobal::config(), "Passwords" );
  257. passwords.writeEntry( "Keep", storePasswd() );
  258. TQString msg = i18n("You need to supply a username and a password to "
  259. "access this mailbox.");
  260. mPasswordDialogIsActive = true;
  261. PasswordDialog dlg( msg, log, true /* store pw */, true, KMKernel::self()->mainWin() );
  262. dlg.setPlainCaption( i18n("Authorization Dialog") );
  263. dlg.addCommentLine( i18n("Account:"), name() );
  264. int ret = dlg.exec();
  265. if (ret != TQDialog::Accepted ) {
  266. mPasswordDialogIsActive = false;
  267. mAskAgain = false;
  268. emit connectionResult( TDEIO::ERR_USER_CANCELED, TQString() );
  269. return Error;
  270. }
  271. mPasswordDialogIsActive = false;
  272. // The user has been given the chance to change login and
  273. // password, so copy both from the dialog:
  274. setPasswd( dlg.password(), dlg.keepPassword() );
  275. setLogin( dlg.username() );
  276. mAskAgain = false;
  277. }
  278. // already waiting for a connection?
  279. if ( mSlave && !mSlaveConnected ) return Connecting;
  280. mSlaveConnected = false;
  281. mSlave = TDEIO::Scheduler::getConnectedSlave( getUrl(), slaveConfig() );
  282. if ( !mSlave ) {
  283. KMessageBox::error(0, i18n("Could not start process for %1.")
  284. .arg( getUrl().protocol() ) );
  285. return Error;
  286. }
  287. if ( mSlave->isConnected() ) {
  288. slotSchedulerSlaveConnected( mSlave );
  289. return Connected;
  290. }
  291. return Connecting;
  292. }
  293. bool ImapAccountBase::handleJobError( TDEIO::Job *job, const TQString& context, bool abortSync )
  294. {
  295. JobIterator it = findJob( job );
  296. if ( it != jobsEnd() && (*it).progressItem )
  297. {
  298. (*it).progressItem->setComplete();
  299. (*it).progressItem = 0;
  300. }
  301. return handleError( job->error(), job->errorText(), job, context, abortSync );
  302. }
  303. // Called when we're really all done.
  304. void ImapAccountBase::postProcessNewMail( bool showStatusMsg ) {
  305. setCheckingMail(false);
  306. int newMails = 0;
  307. if ( mCountUnread > 0 && mCountUnread > mCountLastUnread ) {
  308. newMails = mCountUnread - mCountLastUnread;
  309. mCountLastUnread = mCountUnread;
  310. mCountUnread = 0;
  311. checkDone( true, CheckOK );
  312. } else {
  313. mCountUnread = 0;
  314. checkDone( false, CheckOK );
  315. }
  316. if ( showStatusMsg )
  317. BroadcastStatus::instance()->setStatusMsgTransmissionCompleted(
  318. name(), newMails);
  319. }
  320. //-----------------------------------------------------------------------------
  321. void ImapAccountBase::changeSubscription( bool subscribe, const TQString& imapPath, bool quiet )
  322. {
  323. // change the subscription of the folder
  324. KURL url = getUrl();
  325. url.setPath(imapPath);
  326. TQByteArray packedArgs;
  327. TQDataStream stream( packedArgs, IO_WriteOnly);
  328. if (subscribe)
  329. stream << (int) 'u' << url;
  330. else
  331. stream << (int) 'U' << url;
  332. // create the TDEIO-job
  333. if ( makeConnection() != Connected )
  334. return;// ## doesn't handle Connecting
  335. TDEIO::SimpleJob *job = TDEIO::special(url, packedArgs, false);
  336. TDEIO::Scheduler::assignJobToSlave(mSlave, job);
  337. jobData jd( url.url(), NULL );
  338. // a bit of a hack to save one slot
  339. if (subscribe) jd.onlySubscribed = true;
  340. else jd.onlySubscribed = false;
  341. jd.quiet = quiet;
  342. insertJob(job, jd);
  343. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  344. TQT_SLOT(slotSubscriptionResult(TDEIO::Job *)));
  345. }
  346. //-----------------------------------------------------------------------------
  347. void ImapAccountBase::slotSubscriptionResult( TDEIO::Job * job )
  348. {
  349. // result of a subscription-job
  350. JobIterator it = findJob( job );
  351. if ( it == jobsEnd() ) return;
  352. bool onlySubscribed = (*it).onlySubscribed;
  353. TQString path = static_cast<TDEIO::SimpleJob*>(job)->url().path();
  354. if (job->error())
  355. {
  356. if ( !(*it).quiet )
  357. handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' );
  358. emit subscriptionChangeFailed( job->errorString() );
  359. // ## emit subscriptionChanged here in case anyone needs it to support continue/cancel
  360. }
  361. else
  362. {
  363. emit subscriptionChanged( path, onlySubscribed );
  364. if (mSlave) removeJob(job);
  365. }
  366. }
  367. //-----------------------------------------------------------------------------
  368. // TODO imapPath can be removed once parent can be a KMFolderImapBase or whatever
  369. void ImapAccountBase::getUserRights( KMFolder* parent, const TQString& imapPath )
  370. {
  371. // There isn't much point in asking the server about a user's rights on his own inbox,
  372. // it might not be the effective permissions (at least with Cyrus, one can admin his own inbox,
  373. // even after a SETACL that removes the admin permissions. Other imap servers apparently
  374. // don't even allow removing one's own admin permission, so this code won't hurt either).
  375. if ( imapPath == "/INBOX/" ) {
  376. if ( parent->folderType() == KMFolderTypeImap )
  377. static_cast<KMFolderImap*>( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
  378. else if ( parent->folderType() == KMFolderTypeCachedImap )
  379. static_cast<KMFolderCachedImap*>( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
  380. emit receivedUserRights( parent ); // warning, you need to connect first to get that one
  381. return;
  382. }
  383. KURL url = getUrl();
  384. url.setPath(imapPath);
  385. ACLJobs::GetUserRightsJob* job = ACLJobs::getUserRights( mSlave, url );
  386. jobData jd( url.url(), parent );
  387. jd.cancellable = true;
  388. insertJob(job, jd);
  389. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  390. TQT_SLOT(slotGetUserRightsResult(TDEIO::Job *)));
  391. }
  392. void ImapAccountBase::slotGetUserRightsResult( TDEIO::Job* _job )
  393. {
  394. ACLJobs::GetUserRightsJob* job = static_cast<ACLJobs::GetUserRightsJob *>( _job );
  395. JobIterator it = findJob( job );
  396. if ( it == jobsEnd() ) return;
  397. KMFolder* folder = (*it).parent;
  398. if ( job->error() ) {
  399. if ( job->error() == TDEIO::ERR_UNSUPPORTED_ACTION ) // that's when the imap server doesn't support ACLs
  400. mACLSupport = false;
  401. else
  402. kdWarning(5006) << "slotGetUserRightsResult: " << job->errorString() << endl;
  403. } else {
  404. #ifndef NDEBUG
  405. //kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl;
  406. #endif
  407. }
  408. // Store the permissions
  409. if ( folder->folderType() == KMFolderTypeImap )
  410. static_cast<KMFolderImap*>( folder->storage() )->setUserRights( job->permissions(),
  411. job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok );
  412. else if ( folder->folderType() == KMFolderTypeCachedImap )
  413. static_cast<KMFolderCachedImap*>( folder->storage() )->setUserRights( job->permissions(),
  414. job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok );
  415. if (mSlave) removeJob(job);
  416. emit receivedUserRights( folder );
  417. }
  418. //-----------------------------------------------------------------------------
  419. void ImapAccountBase::getACL( KMFolder* parent, const TQString& imapPath )
  420. {
  421. KURL url = getUrl();
  422. url.setPath(imapPath);
  423. ACLJobs::GetACLJob* job = ACLJobs::getACL( mSlave, url );
  424. jobData jd( url.url(), parent );
  425. jd.cancellable = true;
  426. insertJob(job, jd);
  427. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  428. TQT_SLOT(slotGetACLResult(TDEIO::Job *)));
  429. }
  430. void ImapAccountBase::slotGetACLResult( TDEIO::Job* _job )
  431. {
  432. ACLJobs::GetACLJob* job = static_cast<ACLJobs::GetACLJob *>( _job );
  433. JobIterator it = findJob( job );
  434. if ( it == jobsEnd() ) return;
  435. KMFolder* folder = (*it).parent;
  436. emit receivedACL( folder, job, job->entries() );
  437. if (mSlave) removeJob(job);
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Do not remove imapPath, FolderDiaQuotaTab needs to call this with parent==0.
  441. void ImapAccountBase::getStorageQuotaInfo( KMFolder* parent, const TQString& imapPath )
  442. {
  443. if ( !mSlave ) return;
  444. KURL url = getUrl();
  445. url.setPath(imapPath);
  446. QuotaJobs::GetStorageQuotaJob* job = QuotaJobs::getStorageQuota( mSlave, url );
  447. jobData jd( url.url(), parent );
  448. jd.cancellable = true;
  449. insertJob(job, jd);
  450. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  451. TQT_SLOT(slotGetStorageQuotaInfoResult(TDEIO::Job *)));
  452. }
  453. void ImapAccountBase::slotGetStorageQuotaInfoResult( TDEIO::Job* _job )
  454. {
  455. QuotaJobs::GetStorageQuotaJob* job = static_cast<QuotaJobs::GetStorageQuotaJob *>( _job );
  456. JobIterator it = findJob( job );
  457. if ( it == jobsEnd() ) return;
  458. if ( job->error() && job->error() == TDEIO::ERR_UNSUPPORTED_ACTION )
  459. setHasNoQuotaSupport();
  460. KMFolder* folder = (*it).parent; // can be 0
  461. emit receivedStorageQuotaInfo( folder, job, job->storageQuotaInfo() );
  462. if (mSlave) removeJob(job);
  463. }
  464. void ImapAccountBase::slotNoopTimeout()
  465. {
  466. if ( mSlave ) {
  467. TQByteArray packedArgs;
  468. TQDataStream stream( packedArgs, IO_WriteOnly );
  469. stream << ( int ) 'N';
  470. TDEIO::SimpleJob *job = TDEIO::special( getUrl(), packedArgs, false );
  471. TDEIO::Scheduler::assignJobToSlave(mSlave, job);
  472. connect( job, TQT_SIGNAL(result( TDEIO::Job * ) ),
  473. this, TQT_SLOT( slotSimpleResult( TDEIO::Job * ) ) );
  474. } else {
  475. /* Stop the timer, we have disconnected. We have to make sure it is
  476. started again when a new slave appears. */
  477. mNoopTimer.stop();
  478. }
  479. }
  480. void ImapAccountBase::slotIdleTimeout()
  481. {
  482. if ( mSlave ) {
  483. TDEIO::Scheduler::disconnectSlave(mSlave);
  484. mSlave = 0;
  485. mSlaveConnected = false;
  486. /* As for the noop timer, we need to make sure this one is started
  487. again when a new slave goes up. */
  488. mIdleTimer.stop();
  489. }
  490. }
  491. void ImapAccountBase::slotAbortRequested( KPIM::ProgressItem* item )
  492. {
  493. if ( item )
  494. item->setComplete();
  495. killAllJobs();
  496. }
  497. //-----------------------------------------------------------------------------
  498. void ImapAccountBase::slotSchedulerSlaveError(TDEIO::Slave *aSlave, int errorCode,
  499. const TQString &errorMsg)
  500. {
  501. if (aSlave != mSlave) return;
  502. handleError( errorCode, errorMsg, 0, TQString(), true );
  503. if ( mAskAgain )
  504. if ( makeConnection() != ImapAccountBase::Error )
  505. return;
  506. if ( !mSlaveConnected ) {
  507. mSlaveConnectionError = true;
  508. resetConnectionList( this );
  509. if ( mSlave )
  510. {
  511. TDEIO::Scheduler::disconnectSlave( slave() );
  512. mSlave = 0;
  513. }
  514. }
  515. emit connectionResult( errorCode, errorMsg );
  516. }
  517. //-----------------------------------------------------------------------------
  518. void ImapAccountBase::slotSchedulerSlaveConnected(TDEIO::Slave *aSlave)
  519. {
  520. if (aSlave != mSlave) return;
  521. mSlaveConnected = true;
  522. mNoopTimer.start( 60000 ); // make sure we start sending noops
  523. emit connectionResult( 0, TQString() ); // success
  524. if ( mNamespaces.isEmpty() || mNamespaceToDelimiter.isEmpty() ) {
  525. connect( this, TQT_SIGNAL( namespacesFetched( const ImapAccountBase::nsDelimMap& ) ),
  526. this, TQT_SLOT( slotSaveNamespaces( const ImapAccountBase::nsDelimMap& ) ) );
  527. getNamespaces();
  528. }
  529. // get capabilities
  530. TQByteArray packedArgs;
  531. TQDataStream stream( packedArgs, IO_WriteOnly);
  532. stream << (int) 'c';
  533. TDEIO::SimpleJob *job = TDEIO::special( getUrl(), packedArgs, false );
  534. TDEIO::Scheduler::assignJobToSlave( mSlave, job );
  535. connect( job, TQT_SIGNAL(infoMessage(TDEIO::Job*, const TQString&)),
  536. TQT_SLOT(slotCapabilitiesResult(TDEIO::Job*, const TQString&)) );
  537. }
  538. //-----------------------------------------------------------------------------
  539. void ImapAccountBase::slotCapabilitiesResult( TDEIO::Job*, const TQString& result )
  540. {
  541. mCapabilities = TQStringList::split(' ', result.lower() );
  542. kdDebug(5006) << "capabilities:" << mCapabilities << endl;
  543. }
  544. //-----------------------------------------------------------------------------
  545. void ImapAccountBase::getNamespaces()
  546. {
  547. disconnect( this, TQT_SIGNAL( connectionResult(int, const TQString&) ),
  548. this, TQT_SLOT( getNamespaces() ) );
  549. if ( makeConnection() != Connected || !mSlave ) {
  550. kdDebug(5006) << "getNamespaces - wait for connection" << endl;
  551. if ( mNamespaces.isEmpty() || mNamespaceToDelimiter.isEmpty() ) {
  552. // when the connection is established slotSchedulerSlaveConnected notifies us
  553. } else {
  554. // getNamespaces was called by someone else
  555. connect( this, TQT_SIGNAL( connectionResult(int, const TQString&) ),
  556. this, TQT_SLOT( getNamespaces() ) );
  557. }
  558. return;
  559. }
  560. TQByteArray packedArgs;
  561. TQDataStream stream( packedArgs, IO_WriteOnly);
  562. stream << (int) 'n';
  563. jobData jd;
  564. jd.total = 1; jd.done = 0; jd.cancellable = true;
  565. jd.progressItem = ProgressManager::createProgressItem(
  566. ProgressManager::getUniqueID(),
  567. i18n("Retrieving Namespaces"),
  568. TQString(), true, useSSL() || useTLS() );
  569. jd.progressItem->setTotalItems( 1 );
  570. connect ( jd.progressItem,
  571. TQT_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
  572. this,
  573. TQT_SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
  574. TDEIO::SimpleJob *job = TDEIO::special( getUrl(), packedArgs, false );
  575. TDEIO::Scheduler::assignJobToSlave( mSlave, job );
  576. insertJob( job, jd );
  577. connect( job, TQT_SIGNAL( infoMessage(TDEIO::Job*, const TQString&) ),
  578. TQT_SLOT( slotNamespaceResult(TDEIO::Job*, const TQString&) ) );
  579. }
  580. //-----------------------------------------------------------------------------
  581. void ImapAccountBase::slotNamespaceResult( TDEIO::Job* job, const TQString& str )
  582. {
  583. JobIterator it = findJob( job );
  584. if ( it == jobsEnd() ) return;
  585. nsDelimMap map;
  586. namespaceDelim nsDelim;
  587. TQStringList ns = TQStringList::split( ",", str );
  588. for ( TQStringList::Iterator it = ns.begin(); it != ns.end(); ++it ) {
  589. // split, allow empty parts as we can get empty namespaces
  590. TQStringList parts = TQStringList::split( "=", *it, true );
  591. imapNamespace section = imapNamespace( parts[0].toInt() );
  592. if ( map.contains( section ) ) {
  593. nsDelim = map[section];
  594. } else {
  595. nsDelim.clear();
  596. }
  597. // map namespace to delimiter
  598. nsDelim[parts[1]] = parts[2];
  599. map[section] = nsDelim;
  600. }
  601. removeJob(it);
  602. kdDebug(5006) << "namespaces fetched" << endl;
  603. emit namespacesFetched( map );
  604. }
  605. //-----------------------------------------------------------------------------
  606. void ImapAccountBase::slotSaveNamespaces( const ImapAccountBase::nsDelimMap& map )
  607. {
  608. kdDebug(5006) << "slotSaveNamespaces " << name() << endl;
  609. // extract the needed information
  610. mNamespaces.clear();
  611. mNamespaceToDelimiter.clear();
  612. for ( uint i = 0; i < 3; ++i ) {
  613. imapNamespace section = imapNamespace( i );
  614. namespaceDelim ns = map[ section ];
  615. namespaceDelim::ConstIterator it;
  616. TQStringList list;
  617. for ( it = ns.begin(); it != ns.end(); ++it ) {
  618. list += it.key();
  619. mNamespaceToDelimiter[ it.key() ] = it.data();
  620. }
  621. if ( !list.isEmpty() ) {
  622. mNamespaces[section] = list;
  623. }
  624. }
  625. // see if we need to migrate an old prefix
  626. if ( !mOldPrefix.isEmpty() ) {
  627. migratePrefix();
  628. }
  629. emit namespacesFetched();
  630. }
  631. //-----------------------------------------------------------------------------
  632. void ImapAccountBase::migratePrefix()
  633. {
  634. if ( !mOldPrefix.isEmpty() && mOldPrefix != "/" ) {
  635. // strip /
  636. if ( mOldPrefix.startsWith("/") ) {
  637. mOldPrefix = mOldPrefix.right( mOldPrefix.length()-1 );
  638. }
  639. if ( mOldPrefix.endsWith("/") ) {
  640. mOldPrefix = mOldPrefix.left( mOldPrefix.length()-1 );
  641. }
  642. TQStringList list = mNamespaces[PersonalNS];
  643. bool done = false;
  644. for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
  645. if ( (*it).startsWith( mOldPrefix ) ) {
  646. // should be ok
  647. done = true;
  648. kdDebug(5006) << "migratePrefix - no migration needed" << endl;
  649. break;
  650. }
  651. }
  652. if ( !done ) {
  653. TQString msg = i18n("KMail has detected a prefix entry in the "
  654. "configuration of the account \"%1\" which is obsolete with the "
  655. "support of IMAP namespaces.").arg( name() );
  656. if ( list.contains( "" ) ) {
  657. // replace empty entry with the old prefix
  658. list.remove( "" );
  659. list += mOldPrefix;
  660. mNamespaces[PersonalNS] = list;
  661. if ( mNamespaceToDelimiter.contains( "" ) ) {
  662. TQString delim = mNamespaceToDelimiter[""];
  663. mNamespaceToDelimiter.remove( "" );
  664. mNamespaceToDelimiter[mOldPrefix] = delim;
  665. }
  666. kdDebug(5006) << "migratePrefix - replaced empty with " << mOldPrefix << endl;
  667. msg += i18n("The configuration was automatically migrated but you should check "
  668. "your account configuration.");
  669. } else if ( list.count() == 1 ) {
  670. // only one entry in the personal namespace so replace it
  671. TQString old = list.first();
  672. list.clear();
  673. list += mOldPrefix;
  674. mNamespaces[PersonalNS] = list;
  675. if ( mNamespaceToDelimiter.contains( old ) ) {
  676. TQString delim = mNamespaceToDelimiter[old];
  677. mNamespaceToDelimiter.remove( old );
  678. mNamespaceToDelimiter[mOldPrefix] = delim;
  679. }
  680. kdDebug(5006) << "migratePrefix - replaced single with " << mOldPrefix << endl;
  681. msg += i18n("The configuration was automatically migrated but you should check "
  682. "your account configuration.");
  683. } else {
  684. kdDebug(5006) << "migratePrefix - migration failed" << endl;
  685. msg += i18n("It was not possible to migrate your configuration automatically "
  686. "so please check your account configuration.");
  687. }
  688. KMessageBox::information( kmkernel->getKMMainWidget(), msg );
  689. }
  690. } else
  691. {
  692. kdDebug(5006) << "migratePrefix - no migration needed" << endl;
  693. }
  694. mOldPrefix = "";
  695. }
  696. //-----------------------------------------------------------------------------
  697. TQString ImapAccountBase::namespaceForFolder( FolderStorage* storage )
  698. {
  699. TQString path;
  700. if ( storage->folderType() == KMFolderTypeImap ) {
  701. path = static_cast<KMFolderImap*>( storage )->imapPath();
  702. } else if ( storage->folderType() == KMFolderTypeCachedImap ) {
  703. path = static_cast<KMFolderCachedImap*>( storage )->imapPath();
  704. }
  705. nsMap::Iterator it;
  706. for ( it = mNamespaces.begin(); it != mNamespaces.end(); ++it )
  707. {
  708. TQStringList::Iterator strit;
  709. for ( strit = it.data().begin(); strit != it.data().end(); ++strit )
  710. {
  711. TQString ns = *strit;
  712. if ( ns.endsWith("/") || ns.endsWith(".") ) {
  713. // strip delimiter for the comparison
  714. ns = ns.left( ns.length()-1 );
  715. }
  716. // first ignore an empty prefix as it would match always
  717. if ( !ns.isEmpty() && path.find( ns ) != -1 ) {
  718. return (*strit);
  719. }
  720. }
  721. }
  722. return TQString();
  723. }
  724. //-----------------------------------------------------------------------------
  725. TQString ImapAccountBase::delimiterForNamespace( const TQString& prefix )
  726. {
  727. //kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
  728. // try to match exactly
  729. if ( mNamespaceToDelimiter.contains(prefix) ) {
  730. return mNamespaceToDelimiter[prefix];
  731. }
  732. // then try if the prefix is part of a namespace
  733. // exclude empty namespace
  734. for ( namespaceDelim::ConstIterator it = mNamespaceToDelimiter.begin();
  735. it != mNamespaceToDelimiter.end(); ++it ) {
  736. // the namespace definition sometimes contains the delimiter
  737. // make sure we also match this version
  738. TQString stripped = it.key().left( it.key().length() - 1 );
  739. if ( !it.key().isEmpty() &&
  740. ( prefix.contains( it.key() ) || prefix.contains( stripped ) ) ) {
  741. return it.data();
  742. }
  743. }
  744. // see if we have an empty namespace
  745. // this should always be the case
  746. if ( mNamespaceToDelimiter.contains( "" ) ) {
  747. return mNamespaceToDelimiter[""];
  748. }
  749. // well, we tried
  750. //kdDebug(5006) << "delimiterForNamespace - not found" << endl;
  751. return TQString();
  752. }
  753. //-----------------------------------------------------------------------------
  754. TQString ImapAccountBase::delimiterForFolder( FolderStorage* storage )
  755. {
  756. TQString prefix = namespaceForFolder( storage );
  757. TQString delim = delimiterForNamespace( prefix );
  758. return delim;
  759. }
  760. //-----------------------------------------------------------------------------
  761. void ImapAccountBase::slotSimpleResult(TDEIO::Job * job)
  762. {
  763. JobIterator it = findJob( job );
  764. bool quiet = false;
  765. if (it != mapJobData.end()) {
  766. quiet = (*it).quiet;
  767. if ( !(job->error() && !quiet) ) // the error handler removes in that case
  768. removeJob(it);
  769. }
  770. if (job->error()) {
  771. if (!quiet)
  772. handleJobError(job, TQString() );
  773. else {
  774. if ( job->error() == TDEIO::ERR_CONNECTION_BROKEN && slave() ) {
  775. // make sure ERR_CONNECTION_BROKEN is properly handled and the slave
  776. // disconnected even when quiet()
  777. TDEIO::Scheduler::disconnectSlave( slave() );
  778. mSlave = 0;
  779. }
  780. if (job->error() == TDEIO::ERR_SLAVE_DIED)
  781. slaveDied();
  782. }
  783. }
  784. }
  785. //-----------------------------------------------------------------------------
  786. bool ImapAccountBase::handlePutError( TDEIO::Job* job, jobData& jd, KMFolder* folder )
  787. {
  788. Q_ASSERT( !jd.msgList.isEmpty() );
  789. KMMessage* msg = jd.msgList.first();
  790. // Use double-quotes around the subject to keep the sentence readable,
  791. // but don't use double quotes around the sender since from() might return a double-quoted name already
  792. const TQString subject = msg->subject().isEmpty() ? i18n( "<unknown>" ) : TQString("\"%1\"").arg( msg->subject() );
  793. const TQString from = msg->from().isEmpty() ? i18n( "<unknown>" ) : msg->from();
  794. TQString myError = "<p><b>" + i18n("Error while uploading message")
  795. + "</b></p><p>"
  796. + i18n("Could not upload the message dated %1 from <i>%2</i> with subject <i>%3</i> to the server.").arg( msg->dateStr(), TQStyleSheet::escape( from ), TQStyleSheet::escape( subject ) )
  797. + "</p><p>"
  798. + i18n("The destination folder was: <b>%1</b>.").arg( TQStyleSheet::escape( folder->prettyURL() ) )
  799. + "</p><p>"
  800. + i18n("The server reported:") + "</p>";
  801. return handleJobError( job, myError );
  802. }
  803. TQString ImapAccountBase::prettifyQuotaError( const TQString& _error, TDEIO::Job * job )
  804. {
  805. TQString error = _error;
  806. if ( error.find( "quota", 0, false ) == -1 ) return error;
  807. // this is a quota error, prettify it a bit
  808. JobIterator it = findJob( job );
  809. TQString quotaAsString( i18n("No detailed quota information available.") );
  810. bool readOnly = false;
  811. if (it != mapJobData.end()) {
  812. const KMFolder * const folder = (*it).parent;
  813. if( !folder ) return _error;
  814. const KMFolderCachedImap * const imap = dynamic_cast<const KMFolderCachedImap*>( folder->storage() );
  815. if ( imap ) {
  816. quotaAsString = imap->quotaInfo().toString();
  817. }
  818. readOnly = folder->isReadOnly();
  819. }
  820. error = i18n("The folder is too close to its quota limit. (%1)").arg( quotaAsString );
  821. if ( readOnly ) {
  822. error += i18n("\nSince you do not have write privileges on this folder, "
  823. "please ask the owner of the folder to free up some space in it.");
  824. }
  825. return error;
  826. }
  827. //-----------------------------------------------------------------------------
  828. bool ImapAccountBase::handleError( int errorCode, const TQString &errorMsg, TDEIO::Job* job, const TQString& context, bool abortSync )
  829. {
  830. // Copy job's data before a possible killAllJobs
  831. TQStringList errors;
  832. if ( job && job->error() != TDEIO::ERR_SLAVE_DEFINED /*workaround for tdelibs-3.2*/)
  833. errors = job->detailedErrorStrings();
  834. bool jobsKilled = true;
  835. switch( errorCode ) {
  836. case TDEIO::ERR_SLAVE_DIED: slaveDied(); killAllJobs( true ); break;
  837. case TDEIO::ERR_COULD_NOT_AUTHENTICATE: // bad password
  838. mAskAgain = true;
  839. // fallthrough intended
  840. case TDEIO::ERR_CONNECTION_BROKEN:
  841. case TDEIO::ERR_COULD_NOT_CONNECT:
  842. case TDEIO::ERR_SERVER_TIMEOUT:
  843. // These mean that we'll have to reconnect on the next attempt, so disconnect and set mSlave to 0.
  844. killAllJobs( true );
  845. break;
  846. case TDEIO::ERR_COULD_NOT_LOGIN:
  847. case TDEIO::ERR_USER_CANCELED:
  848. killAllJobs( false );
  849. break;
  850. default:
  851. if ( abortSync )
  852. killAllJobs( false );
  853. else
  854. jobsKilled = false;
  855. break;
  856. }
  857. // check if we still display an error
  858. if ( !mErrorDialogIsActive && errorCode != TDEIO::ERR_USER_CANCELED ) {
  859. mErrorDialogIsActive = true;
  860. TQString msg = context + '\n' + prettifyQuotaError( TDEIO::buildErrorString( errorCode, errorMsg ), job );
  861. TQString caption = i18n("Error");
  862. if ( jobsKilled || errorCode == TDEIO::ERR_COULD_NOT_LOGIN ) {
  863. if ( errorCode == TDEIO::ERR_SERVER_TIMEOUT || errorCode == TDEIO::ERR_CONNECTION_BROKEN ) {
  864. msg = i18n("The connection to the server %1 was unexpectedly closed or timed out. It will be re-established automatically if possible.").
  865. arg( name() );
  866. KMessageBox::information( TQT_TQWIDGET(kapp->activeWindow()), msg, caption, "kmailConnectionBrokenErrorDialog" );
  867. // Show it in the status bar, in case the user has ticked "don't show again"
  868. if ( errorCode == TDEIO::ERR_CONNECTION_BROKEN )
  869. KPIM::BroadcastStatus::instance()->setStatusMsg(
  870. i18n( "The connection to account %1 was broken." ).arg( name() ) );
  871. else if ( errorCode == TDEIO::ERR_SERVER_TIMEOUT )
  872. KPIM::BroadcastStatus::instance()->setStatusMsg(
  873. i18n( "The connection to account %1 timed out." ).arg( name() ) );
  874. } else {
  875. if ( !errors.isEmpty() )
  876. KMessageBox::detailedError( TQT_TQWIDGET(kapp->activeWindow()), msg, errors.join("\n").prepend("<qt>"), caption );
  877. else
  878. KMessageBox::error( TQT_TQWIDGET(kapp->activeWindow()), msg, caption );
  879. }
  880. } else { // i.e. we have a chance to continue, ask the user about it
  881. if ( errors.count() >= 3 ) { // there is no detailedWarningContinueCancel... (#86517)
  882. TQString error = prettifyQuotaError( errors[1], job );
  883. msg = TQString( "<qt>") + context + error + '\n' + errors[2];
  884. caption = errors[0];
  885. }
  886. int ret = KMessageBox::warningContinueCancel( TQT_TQWIDGET(kapp->activeWindow()), msg, caption );
  887. if ( ret == KMessageBox::Cancel ) {
  888. jobsKilled = true;
  889. killAllJobs( false );
  890. }
  891. }
  892. mErrorDialogIsActive = false;
  893. } else {
  894. if ( mErrorDialogIsActive )
  895. kdDebug(5006) << "suppressing error:" << errorMsg << endl;
  896. }
  897. if ( job && !jobsKilled )
  898. removeJob( job );
  899. return !jobsKilled; // jobsKilled==false -> continue==true
  900. }
  901. //-----------------------------------------------------------------------------
  902. void ImapAccountBase::cancelMailCheck()
  903. {
  904. TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
  905. while ( it != mapJobData.end() ) {
  906. kdDebug(5006) << "cancelMailCheck: job is cancellable: " << (*it).cancellable << endl;
  907. if ( (*it).cancellable ) {
  908. it.key()->kill();
  909. TQMap<TDEIO::Job*, jobData>::Iterator rmit = it;
  910. ++it;
  911. mapJobData.remove( rmit );
  912. // We killed a job -> this kills the slave
  913. mSlave = 0;
  914. } else
  915. ++it;
  916. }
  917. for( TQPtrListIterator<FolderJob> it( mJobList ); it.current(); ++it ) {
  918. if ( it.current()->isCancellable() ) {
  919. FolderJob* job = it.current();
  920. job->setPassiveDestructor( true );
  921. mJobList.remove( job );
  922. delete job;
  923. } else
  924. ++it;
  925. }
  926. }
  927. //-----------------------------------------------------------------------------
  928. void ImapAccountBase::processNewMailInFolder( KMFolder* folder, FolderListType type /*= Single*/ )
  929. {
  930. if ( mFoldersQueuedForChecking.contains( folder ) )
  931. return;
  932. mFoldersQueuedForChecking.append( folder );
  933. mCheckingSingleFolder = ( type == Single );
  934. if ( checkingMail() )
  935. {
  936. disconnect( this, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
  937. this, TQT_SLOT( slotCheckQueuedFolders() ) );
  938. connect( this, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
  939. this, TQT_SLOT( slotCheckQueuedFolders() ) );
  940. } else {
  941. slotCheckQueuedFolders();
  942. }
  943. }
  944. //-----------------------------------------------------------------------------
  945. void ImapAccountBase::slotCheckQueuedFolders()
  946. {
  947. disconnect( this, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
  948. this, TQT_SLOT( slotCheckQueuedFolders() ) );
  949. TQValueList<TQGuardedPtr<KMFolder> > mSaveList = mMailCheckFolders;
  950. mMailCheckFolders = mFoldersQueuedForChecking;
  951. if ( kmkernel->acctMgr() )
  952. kmkernel->acctMgr()->singleCheckMail(this, true);
  953. mMailCheckFolders = mSaveList;
  954. mFoldersQueuedForChecking.clear();
  955. }
  956. //-----------------------------------------------------------------------------
  957. bool ImapAccountBase::checkingMail( KMFolder *folder )
  958. {
  959. if (checkingMail() && mFoldersQueuedForChecking.contains(folder))
  960. return true;
  961. return false;
  962. }
  963. //-----------------------------------------------------------------------------
  964. void ImapAccountBase::handleBodyStructure( TQDataStream & stream, KMMessage * msg,
  965. const AttachmentStrategy *as )
  966. {
  967. mBodyPartList.clear();
  968. mCurrentMsg = msg;
  969. // first delete old parts as we construct our own
  970. msg->deleteBodyParts();
  971. // make the parts and fill the mBodyPartList
  972. constructParts( stream, 1, 0, 0, msg->asDwMessage() );
  973. if ( mBodyPartList.count() == 1 ) // we directly set the body later, at partsToLoad below
  974. msg->deleteBodyParts();
  975. if ( !as )
  976. {
  977. kdWarning(5006) << k_funcinfo << " - found no attachment strategy!" << endl;
  978. return;
  979. }
  980. // see what parts have to loaded according to attachmentstrategy
  981. BodyVisitor *visitor = BodyVisitorFactory::getVisitor( as );
  982. visitor->visit( mBodyPartList );
  983. TQPtrList<KMMessagePart> parts = visitor->partsToLoad();
  984. delete visitor;
  985. TQPtrListIterator<KMMessagePart> it( parts );
  986. KMMessagePart *part;
  987. int partsToLoad = 0;
  988. // check how many parts we have to load
  989. while ( (part = it.current()) != 0 )
  990. {
  991. ++it;
  992. if ( part->loadPart() )
  993. {
  994. ++partsToLoad;
  995. }
  996. }
  997. // if the only body part is not text, part->loadPart() would return false
  998. // and that part is never loaded, so make sure it loads.
  999. // it seems that TEXT does load the single body part even if it is not text/*
  1000. if ( mBodyPartList.count() == 1 && partsToLoad == 0 )
  1001. partsToLoad = 1; // this causes the next test to succeed, and loads the whole message
  1002. if ( (mBodyPartList.count() * 0.5) < partsToLoad )
  1003. {
  1004. // more than 50% of the parts have to be loaded anyway so it is faster
  1005. // to load the message completely
  1006. kdDebug(5006) << "Falling back to normal mode" << endl;
  1007. FolderJob *job = msg->parent()->createJob(
  1008. msg, FolderJob::tGetMessage, 0, "TEXT" );
  1009. job->start();
  1010. return;
  1011. }
  1012. it.toFirst();
  1013. while ( (part = it.current()) != 0 )
  1014. {
  1015. ++it;
  1016. kdDebug(5006) << "ImapAccountBase::handleBodyStructure - load " << part->partSpecifier()
  1017. << " (" << part->originalContentTypeStr() << ")" << endl;
  1018. if ( part->loadHeaders() )
  1019. {
  1020. kdDebug(5006) << "load HEADER" << endl;
  1021. FolderJob *job = msg->parent()->createJob(
  1022. msg, FolderJob::tGetMessage, 0, part->partSpecifier()+".MIME" );
  1023. job->start();
  1024. }
  1025. if ( part->loadPart() )
  1026. {
  1027. kdDebug(5006) << "load Part" << endl;
  1028. FolderJob *job = msg->parent()->createJob(
  1029. msg, FolderJob::tGetMessage, 0, part->partSpecifier() );
  1030. job->start();
  1031. }
  1032. }
  1033. }
  1034. //-----------------------------------------------------------------------------
  1035. void ImapAccountBase::constructParts( TQDataStream & stream, int count, KMMessagePart* parentKMPart,
  1036. DwBodyPart * parent, const DwMessage * dwmsg )
  1037. {
  1038. int children;
  1039. for (int i = 0; i < count; i++)
  1040. {
  1041. stream >> children;
  1042. KMMessagePart* part = new KMMessagePart( stream );
  1043. part->setParent( parentKMPart );
  1044. mBodyPartList.append( part );
  1045. kdDebug(5006) << "ImapAccountBase::constructParts - created id " << part->partSpecifier()
  1046. << " of type " << part->originalContentTypeStr() << endl;
  1047. DwBodyPart *dwpart = mCurrentMsg->createDWBodyPart( part );
  1048. if ( parent )
  1049. {
  1050. // add to parent body
  1051. parent->Body().AddBodyPart( dwpart );
  1052. dwpart->Parse();
  1053. // kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
  1054. // << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
  1055. } else if ( part->partSpecifier() != "0" &&
  1056. !part->partSpecifier().endsWith(".HEADER") )
  1057. {
  1058. // add to message
  1059. dwmsg->Body().AddBodyPart( dwpart );
  1060. dwpart->Parse();
  1061. // kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
  1062. // << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
  1063. } else
  1064. dwpart = 0;
  1065. if ( !parentKMPart )
  1066. parentKMPart = part;
  1067. if (children > 0)
  1068. {
  1069. DwBodyPart* newparent = dwpart;
  1070. const DwMessage* newmsg = dwmsg;
  1071. if ( part->originalContentTypeStr() == "MESSAGE/RFC822" && dwpart &&
  1072. dwpart->Body().Message() )
  1073. {
  1074. // set the encapsulated message as the new message
  1075. newparent = 0;
  1076. newmsg = dwpart->Body().Message();
  1077. }
  1078. KMMessagePart* newParentKMPart = part;
  1079. if ( part->partSpecifier().endsWith(".HEADER") ) // we don't want headers as parent
  1080. newParentKMPart = parentKMPart;
  1081. constructParts( stream, children, newParentKMPart, newparent, newmsg );
  1082. }
  1083. }
  1084. }
  1085. //-----------------------------------------------------------------------------
  1086. void ImapAccountBase::setImapStatus( KMFolder* folder, const TQString& path, const TQCString& flags )
  1087. {
  1088. // set the status on the server, the uids are integrated in the path
  1089. kdDebug(5006) << "setImapStatus path=" << path << " to: " << flags << endl;
  1090. KURL url = getUrl();
  1091. url.setPath(path);
  1092. TQByteArray packedArgs;
  1093. TQDataStream stream( packedArgs, IO_WriteOnly);
  1094. stream << (int) 'S' << url << flags;
  1095. if ( makeConnection() != Connected )
  1096. return; // can't happen with dimap
  1097. TDEIO::SimpleJob *job = TDEIO::special(url, packedArgs, false);
  1098. TDEIO::Scheduler::assignJobToSlave(slave(), job);
  1099. ImapAccountBase::jobData jd( url.url(), folder );
  1100. jd.path = path;
  1101. insertJob(job, jd);
  1102. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  1103. TQT_SLOT(slotSetStatusResult(TDEIO::Job *)));
  1104. }
  1105. void ImapAccountBase::setImapSeenStatus(KMFolder * folder, const TQString & path, bool seen)
  1106. {
  1107. KURL url = getUrl();
  1108. url.setPath(path);
  1109. TQByteArray packedArgs;
  1110. TQDataStream stream( packedArgs, IO_WriteOnly);
  1111. stream << (int) 's' << url << seen;
  1112. if ( makeConnection() != Connected )
  1113. return; // can't happen with dimap
  1114. TDEIO::SimpleJob *job = TDEIO::special(url, packedArgs, false);
  1115. TDEIO::Scheduler::assignJobToSlave(slave(), job);
  1116. ImapAccountBase::jobData jd( url.url(), folder );
  1117. jd.path = path;
  1118. insertJob(job, jd);
  1119. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  1120. TQT_SLOT(slotSetStatusResult(TDEIO::Job *)));
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. void ImapAccountBase::slotSetStatusResult(TDEIO::Job * job)
  1124. {
  1125. ImapAccountBase::JobIterator it = findJob(job);
  1126. if ( it == jobsEnd() ) return;
  1127. int errorCode = job->error();
  1128. KMFolder * const parent = (*it).parent;
  1129. const TQString path = (*it).path;
  1130. if (errorCode && errorCode != TDEIO::ERR_CANNOT_OPEN_FOR_WRITING)
  1131. {
  1132. bool cont = handleJobError( job, i18n( "Error while uploading status of messages to server: " ) + '\n' );
  1133. emit imapStatusChanged( parent, path, cont );
  1134. }
  1135. else
  1136. {
  1137. emit imapStatusChanged( parent, path, true );
  1138. removeJob(it);
  1139. }
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. void ImapAccountBase::setFolder(KMFolder* folder, bool addAccount)
  1143. {
  1144. if (folder)
  1145. {
  1146. folder->setSystemLabel(name());
  1147. folder->setId(id());
  1148. }
  1149. NetworkAccount::setFolder(folder, addAccount);
  1150. }
  1151. //-----------------------------------------------------------------------------
  1152. void ImapAccountBase::removeJob( JobIterator& it )
  1153. {
  1154. if( (*it).progressItem ) {
  1155. (*it).progressItem->setComplete();
  1156. (*it).progressItem = 0;
  1157. }
  1158. mapJobData.remove( it );
  1159. }
  1160. //-----------------------------------------------------------------------------
  1161. void KMail::ImapAccountBase::removeJob( TDEIO::Job* job )
  1162. {
  1163. mapJobData.remove( job );
  1164. }
  1165. //-----------------------------------------------------------------------------
  1166. KPIM::ProgressItem* ImapAccountBase::listDirProgressItem()
  1167. {
  1168. if ( !mListDirProgressItem )
  1169. {
  1170. mListDirProgressItem = ProgressManager::createProgressItem(
  1171. "ListDir" + name(),
  1172. TQStyleSheet::escape( name() ),
  1173. i18n("retrieving folders"),
  1174. true,
  1175. useSSL() || useTLS() );
  1176. connect ( mListDirProgressItem,
  1177. TQT_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
  1178. this,
  1179. TQT_SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
  1180. // Start with a guessed value of the old folder count plus 5%. As long
  1181. // as the list of folders doesn't constantly change, that should be good
  1182. // enough.
  1183. unsigned int count = folderCount();
  1184. mListDirProgressItem->setTotalItems( count + (unsigned int)(count*0.05) );
  1185. }
  1186. return mListDirProgressItem;
  1187. }
  1188. //-----------------------------------------------------------------------------
  1189. unsigned int ImapAccountBase::folderCount() const
  1190. {
  1191. if ( !rootFolder() || !rootFolder()->folder() || !rootFolder()->folder()->child() )
  1192. return 0;
  1193. return kmkernel->imapFolderMgr()->folderCount( rootFolder()->folder()->child() );
  1194. }
  1195. //------------------------------------------------------------------------------
  1196. TQString ImapAccountBase::addPathToNamespace( const TQString& prefix )
  1197. {
  1198. TQString myPrefix = prefix;
  1199. if ( !myPrefix.startsWith( "/" ) ) {
  1200. myPrefix = "/" + myPrefix;
  1201. }
  1202. if ( !myPrefix.endsWith( "/" ) ) {
  1203. myPrefix += "/";
  1204. }
  1205. return myPrefix;
  1206. }
  1207. //------------------------------------------------------------------------------
  1208. bool ImapAccountBase::isNamespaceFolder( TQString& name )
  1209. {
  1210. TQStringList ns = mNamespaces[OtherUsersNS];
  1211. ns += mNamespaces[SharedNS];
  1212. ns += mNamespaces[PersonalNS];
  1213. TQString nameWithDelimiter;
  1214. for ( TQStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
  1215. {
  1216. nameWithDelimiter = name + delimiterForNamespace( *it );
  1217. if ( *it == name || *it == nameWithDelimiter )
  1218. return true;
  1219. }
  1220. return false;
  1221. }
  1222. //------------------------------------------------------------------------------
  1223. ImapAccountBase::nsDelimMap ImapAccountBase::namespacesWithDelimiter()
  1224. {
  1225. nsDelimMap map;
  1226. nsMap::ConstIterator it;
  1227. for ( uint i = 0; i < 3; ++i )
  1228. {
  1229. imapNamespace section = imapNamespace( i );
  1230. TQStringList namespaces = mNamespaces[section];
  1231. namespaceDelim nsDelim;
  1232. TQStringList::Iterator lit;
  1233. for ( lit = namespaces.begin(); lit != namespaces.end(); ++lit )
  1234. {
  1235. nsDelim[*lit] = delimiterForNamespace( *lit );
  1236. }
  1237. map[section] = nsDelim;
  1238. }
  1239. return map;
  1240. }
  1241. //------------------------------------------------------------------------------
  1242. TQString ImapAccountBase::createImapPath( const TQString& parent,
  1243. const TQString& folderName )
  1244. {
  1245. kdDebug(5006) << "createImapPath parent="<<parent<<", folderName="<<folderName<<endl;
  1246. TQString newName = parent;
  1247. // strip / at the end
  1248. if ( newName.endsWith("/") ) {
  1249. newName = newName.left( newName.length() - 1 );
  1250. }
  1251. // add correct delimiter
  1252. TQString delim = delimiterForNamespace( newName );
  1253. // should not happen...
  1254. if ( delim.isEmpty() ) {
  1255. delim = "/";
  1256. }
  1257. if ( !newName.isEmpty() &&
  1258. !newName.endsWith( delim ) && !folderName.startsWith( delim ) ) {
  1259. newName = newName + delim;
  1260. }
  1261. newName = newName + folderName;
  1262. // add / at the end
  1263. if ( !newName.endsWith("/") ) {
  1264. newName = newName + "/";
  1265. }
  1266. return newName;
  1267. }
  1268. //------------------------------------------------------------------------------
  1269. TQString ImapAccountBase::createImapPath( FolderStorage* parent,
  1270. const TQString& folderName )
  1271. {
  1272. TQString path;
  1273. if ( parent->folderType() == KMFolderTypeImap ) {
  1274. path = static_cast<KMFolderImap*>( parent )->imapPath();
  1275. } else if ( parent->folderType() == KMFolderTypeCachedImap ) {
  1276. path = static_cast<KMFolderCachedImap*>( parent )->imapPath();
  1277. } else {
  1278. // error
  1279. return path;
  1280. }
  1281. return createImapPath( path, folderName );
  1282. }
  1283. bool ImapAccountBase::locallySubscribedTo( const TQString& imapPath )
  1284. {
  1285. return mLocalSubscriptionBlackList.find( imapPath ) == mLocalSubscriptionBlackList.end();
  1286. }
  1287. void ImapAccountBase::changeLocalSubscription( const TQString& imapPath, bool subscribe )
  1288. {
  1289. if ( subscribe ) {
  1290. // find in blacklist and remove from it
  1291. mLocalSubscriptionBlackList.erase( imapPath );
  1292. } else {
  1293. // blacklist
  1294. mLocalSubscriptionBlackList.insert( imapPath );
  1295. }
  1296. }
  1297. TQStringList ImapAccountBase::locallyBlacklistedFolders() const
  1298. {
  1299. TQStringList list;
  1300. std::set<TQString>::const_iterator it = mLocalSubscriptionBlackList.begin();
  1301. std::set<TQString>::const_iterator end = mLocalSubscriptionBlackList.end();
  1302. for ( ; it != end ; ++it )
  1303. list.append( *it );
  1304. return list;
  1305. }
  1306. void ImapAccountBase::localBlacklistFromStringList( const TQStringList &list )
  1307. {
  1308. for( TQStringList::ConstIterator it = list.constBegin( ); it != list.constEnd( ); ++it )
  1309. mLocalSubscriptionBlackList.insert( *it );
  1310. }
  1311. } // namespace KMail
  1312. #include "imapaccountbase.moc"