/** -*- c++ -*-
* imapaccountbase . cpp
*
* Copyright ( c ) 2000 - 2002 Michael Haeckel < haeckel @ kde . org >
* Copyright ( c ) 2002 Marc Mutz < mutz @ kde . org >
*
* This file is based on work on pop3 and imap account implementations
* by Don Sanders < sanders @ kde . org > and Michael Haeckel < haeckel @ kde . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 of the License
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include "imapaccountbase.h"
using KMail : : SieveConfig ;
# include "accountmanager.h"
using KMail : : AccountManager ;
# include "kmfolder.h"
# include "broadcaststatus.h"
using KPIM : : BroadcastStatus ;
# include "kmmainwin.h"
# include "kmfolderimap.h"
# include "kmmainwidget.h"
# include "kmmainwin.h"
# include "kmmsgpart.h"
# include "acljobs.h"
# include "kmfoldercachedimap.h"
# include "bodyvisitor.h"
using KMail : : BodyVisitor ;
# include "imapjob.h"
using KMail : : ImapJob ;
# include "protocols.h"
# include "progressmanager.h"
using KPIM : : ProgressManager ;
# include "kmfoldermgr.h"
# include "listjob.h"
# include <kapplication.h>
# include <kdebug.h>
# include <kconfig.h>
# include <klocale.h>
# include <kmessagebox.h>
using KIO : : MetaData ;
# include <kio/passdlg.h>
using KIO : : PasswordDialog ;
# include <kio/scheduler.h>
# include <kio/slave.h>
# include <mimelib/bodypart.h>
# include <mimelib/body.h>
# include <mimelib/headers.h>
# include <mimelib/message.h>
//using KIO::Scheduler; // use FQN below
# include <tqregexp.h>
# include <tqstylesheet.h>
namespace KMail {
static const unsigned short int imapDefaultPort = 143 ;
//
//
// Ctor and Dtor
//
//
ImapAccountBase : : ImapAccountBase ( AccountManager * parent , const TQString & name , uint id )
: NetworkAccount ( parent , name , id ) ,
mIdleTimer ( 0 , " mIdleTimer " ) ,
mNoopTimer ( 0 , " mNoopTimer " ) ,
mTotal ( 0 ) ,
mCountUnread ( 0 ) ,
mCountLastUnread ( 0 ) ,
mAutoExpunge ( true ) ,
mHiddenFolders ( false ) ,
mOnlySubscribedFolders ( false ) ,
mOnlyLocallySubscribedFolders ( false ) ,
mLoadOnDemand ( true ) ,
mListOnlyOpenFolders ( false ) ,
mProgressEnabled ( false ) ,
mErrorDialogIsActive ( false ) ,
mPasswordDialogIsActive ( false ) ,
mACLSupport ( true ) ,
mAnnotationSupport ( true ) ,
mQuotaSupport ( true ) ,
mSlaveConnected ( false ) ,
mSlaveConnectionError ( false ) ,
mCheckingSingleFolder ( false ) ,
mListDirProgressItem ( 0 )
{
mPort = imapDefaultPort ;
mBodyPartList . setAutoDelete ( true ) ;
KIO : : Scheduler : : connect ( TQT_SIGNAL ( slaveError ( KIO : : Slave * , int , const TQString & ) ) ,
this , TQT_SLOT ( slotSchedulerSlaveError ( KIO : : Slave * , int , const TQString & ) ) ) ;
KIO : : Scheduler : : connect ( TQT_SIGNAL ( slaveConnected ( KIO : : Slave * ) ) ,
this , TQT_SLOT ( slotSchedulerSlaveConnected ( KIO : : Slave * ) ) ) ;
connect ( & mNoopTimer , TQT_SIGNAL ( timeout ( ) ) , TQT_SLOT ( slotNoopTimeout ( ) ) ) ;
connect ( & mIdleTimer , TQT_SIGNAL ( timeout ( ) ) , TQT_SLOT ( slotIdleTimeout ( ) ) ) ;
}
ImapAccountBase : : ~ ImapAccountBase ( ) {
kdWarning ( mSlave , 5006 )
< < " slave should have been destroyed by subclass! " < < endl ;
}
void ImapAccountBase : : init ( ) {
mAutoExpunge = true ;
mHiddenFolders = false ;
mOnlySubscribedFolders = false ;
mOnlyLocallySubscribedFolders = false ;
mLoadOnDemand = true ;
mListOnlyOpenFolders = false ;
mProgressEnabled = false ;
}
void ImapAccountBase : : pseudoAssign ( const KMAccount * a ) {
NetworkAccount : : pseudoAssign ( a ) ;
const ImapAccountBase * i = dynamic_cast < const ImapAccountBase * > ( a ) ;
if ( ! i ) return ;
setAutoExpunge ( i - > autoExpunge ( ) ) ;
setHiddenFolders ( i - > hiddenFolders ( ) ) ;
setOnlySubscribedFolders ( i - > onlySubscribedFolders ( ) ) ;
setOnlyLocallySubscribedFolders ( i - > onlyLocallySubscribedFolders ( ) ) ;
setLoadOnDemand ( i - > loadOnDemand ( ) ) ;
setListOnlyOpenFolders ( i - > listOnlyOpenFolders ( ) ) ;
setNamespaces ( i - > namespaces ( ) ) ;
setNamespaceToDelimiter ( i - > namespaceToDelimiter ( ) ) ;
localBlacklistFromStringList ( i - > locallyBlacklistedFolders ( ) ) ;
}
unsigned short int ImapAccountBase : : defaultPort ( ) const {
return imapDefaultPort ;
}
TQString ImapAccountBase : : protocol ( ) const {
return useSSL ( ) ? IMAP_SSL_PROTOCOL : IMAP_PROTOCOL ;
}
//
//
// Getters and Setters
//
//
void ImapAccountBase : : setAutoExpunge ( bool expunge ) {
mAutoExpunge = expunge ;
}
void ImapAccountBase : : setHiddenFolders ( bool show ) {
mHiddenFolders = show ;
}
void ImapAccountBase : : setOnlySubscribedFolders ( bool show ) {
mOnlySubscribedFolders = show ;
}
void ImapAccountBase : : setOnlyLocallySubscribedFolders ( bool show ) {
mOnlyLocallySubscribedFolders = show ;
}
void ImapAccountBase : : setLoadOnDemand ( bool load ) {
mLoadOnDemand = load ;
}
void ImapAccountBase : : setListOnlyOpenFolders ( bool only ) {
mListOnlyOpenFolders = only ;
}
//
//
// read/write config
//
//
void ImapAccountBase : : readConfig ( /*const*/ KConfig /*Base*/ & config ) {
NetworkAccount : : readConfig ( config ) ;
setAutoExpunge ( config . readBoolEntry ( " auto-expunge " , false ) ) ;
setHiddenFolders ( config . readBoolEntry ( " hidden-folders " , false ) ) ;
setOnlySubscribedFolders ( config . readBoolEntry ( " subscribed-folders " , false ) ) ;
setOnlyLocallySubscribedFolders ( config . readBoolEntry ( " locally-subscribed-folders " , false ) ) ;
setLoadOnDemand ( config . readBoolEntry ( " loadondemand " , false ) ) ;
setListOnlyOpenFolders ( config . readBoolEntry ( " listOnlyOpenFolders " , false ) ) ;
mCapabilities = config . readListEntry ( " capabilities " , TQStringList ( ) ) ;
// read namespaces
nsMap map ;
TQStringList list = config . readListEntry ( TQString : : number ( PersonalNS ) ) ;
if ( ! list . isEmpty ( ) )
map [ PersonalNS ] = list . gres ( " \" " , " " ) ;
list = config . readListEntry ( TQString : : number ( OtherUsersNS ) ) ;
if ( ! list . isEmpty ( ) )
map [ OtherUsersNS ] = list . gres ( " \" " , " " ) ;
list = config . readListEntry ( TQString : : number ( SharedNS ) ) ;
if ( ! list . isEmpty ( ) )
map [ SharedNS ] = list . gres ( " \" " , " " ) ;
setNamespaces ( map ) ;
// read namespace - delimiter
namespaceDelim entries = config . entryMap ( config . group ( ) ) ;
namespaceDelim namespaceToDelimiter ;
for ( namespaceDelim : : ConstIterator it = entries . begin ( ) ;
it ! = entries . end ( ) ; + + it ) {
if ( it . key ( ) . startsWith ( " Namespace: " ) ) {
TQString key = it . key ( ) . right ( it . key ( ) . length ( ) - 10 ) ;
namespaceToDelimiter [ key ] = it . data ( ) ;
}
}
setNamespaceToDelimiter ( namespaceToDelimiter ) ;
mOldPrefix = config . readEntry ( " prefix " ) ;
if ( ! mOldPrefix . isEmpty ( ) ) {
makeConnection ( ) ;
}
localBlacklistFromStringList ( config . readListEntry ( " locallyUnsubscribedFolders " ) ) ;
}
void ImapAccountBase : : writeConfig ( KConfig /*Base*/ & config ) /*const*/ {
NetworkAccount : : writeConfig ( config ) ;
config . writeEntry ( " auto-expunge " , autoExpunge ( ) ) ;
config . writeEntry ( " hidden-folders " , hiddenFolders ( ) ) ;
config . writeEntry ( " subscribed-folders " , onlySubscribedFolders ( ) ) ;
config . writeEntry ( " locally-subscribed-folders " , onlyLocallySubscribedFolders ( ) ) ;
config . writeEntry ( " loadondemand " , loadOnDemand ( ) ) ;
config . writeEntry ( " listOnlyOpenFolders " , listOnlyOpenFolders ( ) ) ;
config . writeEntry ( " capabilities " , mCapabilities ) ;
TQString data ;
for ( nsMap : : Iterator it = mNamespaces . begin ( ) ; it ! = mNamespaces . end ( ) ; + + it ) {
if ( ! it . data ( ) . isEmpty ( ) ) {
data = " \" " + it . data ( ) . join ( " \" , \" " ) + " \" " ;
config . writeEntry ( TQString : : number ( it . key ( ) ) , data ) ;
}
}
TQString key ;
for ( namespaceDelim : : ConstIterator it = mNamespaceToDelimiter . begin ( ) ;
it ! = mNamespaceToDelimiter . end ( ) ; + + it ) {
key = " Namespace: " + it . key ( ) ;
config . writeEntry ( key , it . data ( ) ) ;
}
config . writeEntry ( " locallyUnsubscribedFolders " , locallyBlacklistedFolders ( ) ) ;
}
//
//
// Network processing
//
//
MetaData ImapAccountBase : : slaveConfig ( ) const {
MetaData m = NetworkAccount : : slaveConfig ( ) ;
m . insert ( " auth " , auth ( ) ) ;
if ( autoExpunge ( ) )
m . insert ( " expunge " , " auto " ) ;
return m ;
}
ImapAccountBase : : ConnectionState ImapAccountBase : : makeConnection ( )
{
if ( mSlave & & mSlaveConnected ) {
return Connected ;
}
if ( mPasswordDialogIsActive ) return Connecting ;
if ( mAskAgain | | ( ( passwd ( ) . isEmpty ( ) | | login ( ) . isEmpty ( ) ) & &
auth ( ) ! = " GSSAPI " ) ) {
Q_ASSERT ( ! mSlave ) ; // disconnected on 'wrong login' error already, or first try
TQString log = login ( ) ;
TQString pass = passwd ( ) ;
// We init "store" to true to indicate that we want to have the
// "keep password" checkbox. Then, we set [Passwords]Keep to
// storePasswd(), so that the checkbox in the dialog will be
// init'ed correctly:
KConfigGroup passwords ( KGlobal : : config ( ) , " Passwords " ) ;
passwords . writeEntry ( " Keep " , storePasswd ( ) ) ;
TQString msg = i18n ( " You need to supply a username and a password to "
" access this mailbox. " ) ;
mPasswordDialogIsActive = true ;
PasswordDialog dlg ( msg , log , true /* store pw */ , true , KMKernel : : self ( ) - > mainWin ( ) ) ;
dlg . setPlainCaption ( i18n ( " Authorization Dialog " ) ) ;
dlg . addCommentLine ( i18n ( " Account: " ) , name ( ) ) ;
int ret = dlg . exec ( ) ;
if ( ret ! = TQDialog : : Accepted ) {
mPasswordDialogIsActive = false ;
mAskAgain = false ;
emit connectionResult ( KIO : : ERR_USER_CANCELED , TQString ( ) ) ;
return Error ;
}
mPasswordDialogIsActive = false ;
// The user has been given the chance to change login and
// password, so copy both from the dialog:
setPasswd ( dlg . password ( ) , dlg . keepPassword ( ) ) ;
setLogin ( dlg . username ( ) ) ;
mAskAgain = false ;
}
// already waiting for a connection?
if ( mSlave & & ! mSlaveConnected ) return Connecting ;
mSlaveConnected = false ;
mSlave = KIO : : Scheduler : : getConnectedSlave ( getUrl ( ) , slaveConfig ( ) ) ;
if ( ! mSlave ) {
KMessageBox : : error ( 0 , i18n ( " Could not start process for %1. " )
. tqarg ( getUrl ( ) . protocol ( ) ) ) ;
return Error ;
}
if ( mSlave - > isConnected ( ) ) {
slotSchedulerSlaveConnected ( mSlave ) ;
return Connected ;
}
return Connecting ;
}
bool ImapAccountBase : : handleJobError ( KIO : : Job * job , const TQString & context , bool abortSync )
{
JobIterator it = findJob ( job ) ;
if ( it ! = jobsEnd ( ) & & ( * it ) . progressItem )
{
( * it ) . progressItem - > setComplete ( ) ;
( * it ) . progressItem = 0 ;
}
return handleError ( job - > error ( ) , job - > errorText ( ) , job , context , abortSync ) ;
}
// Called when we're really all done.
void ImapAccountBase : : postProcessNewMail ( bool showStatusMsg ) {
setCheckingMail ( false ) ;
int newMails = 0 ;
if ( mCountUnread > 0 & & mCountUnread > mCountLastUnread ) {
newMails = mCountUnread - mCountLastUnread ;
mCountLastUnread = mCountUnread ;
mCountUnread = 0 ;
checkDone ( true , CheckOK ) ;
} else {
mCountUnread = 0 ;
checkDone ( false , CheckOK ) ;
}
if ( showStatusMsg )
BroadcastStatus : : instance ( ) - > seStatusMsgTransmissionCompleted (
name ( ) , newMails ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : changeSubscription ( bool subscribe , const TQString & imapPath , bool quiet )
{
// change the subscription of the folder
KURL url = getUrl ( ) ;
url . setPath ( imapPath ) ;
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
if ( subscribe )
stream < < ( int ) ' u ' < < url ;
else
stream < < ( int ) ' U ' < < url ;
// create the KIO-job
if ( makeConnection ( ) ! = Connected )
return ; // ## doesn't handle Connecting
KIO : : SimpleJob * job = KIO : : special ( url , packedArgs , false ) ;
KIO : : Scheduler : : assignJobToSlave ( mSlave , job ) ;
jobData jd ( url . url ( ) , NULL ) ;
// a bit of a hack to save one slot
if ( subscribe ) jd . onlySubscribed = true ;
else jd . onlySubscribed = false ;
jd . quiet = quiet ;
insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
TQT_SLOT ( slotSubscriptionResult ( KIO : : Job * ) ) ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotSubscriptionResult ( KIO : : Job * job )
{
// result of a subscription-job
JobIterator it = findJob ( job ) ;
if ( it = = jobsEnd ( ) ) return ;
bool onlySubscribed = ( * it ) . onlySubscribed ;
TQString path = static_cast < KIO : : SimpleJob * > ( job ) - > url ( ) . path ( ) ;
if ( job - > error ( ) )
{
if ( ! ( * it ) . quiet )
handleJobError ( job , i18n ( " Error while trying to subscribe to %1: " ) . tqarg ( path ) + ' \n ' ) ;
emit subscriptionChangeFailed ( job - > errorString ( ) ) ;
// ## emit subscriptionChanged here in case anyone needs it to support continue/cancel
}
else
{
emit subscriptionChanged ( path , onlySubscribed ) ;
if ( mSlave ) removeJob ( job ) ;
}
}
//-----------------------------------------------------------------------------
// TODO imapPath can be removed once parent can be a KMFolderImapBase or whatever
void ImapAccountBase : : getUserRights ( KMFolder * parent , const TQString & imapPath )
{
// There isn't much point in asking the server about a user's rights on his own inbox,
// it might not be the effective permissions (at least with Cyrus, one can admin his own inbox,
// even after a SETACL that removes the admin permissions. Other imap servers apparently
// don't even allow removing one's own admin permission, so this code won't hurt either).
if ( imapPath = = " /INBOX/ " ) {
if ( parent - > folderType ( ) = = KMFolderTypeImap )
static_cast < KMFolderImap * > ( parent - > storage ( ) ) - > setUserRights ( ACLJobs : : All , ACLJobs : : Ok ) ;
else if ( parent - > folderType ( ) = = KMFolderTypeCachedImap )
static_cast < KMFolderCachedImap * > ( parent - > storage ( ) ) - > setUserRights ( ACLJobs : : All , ACLJobs : : Ok ) ;
emit receivedUserRights ( parent ) ; // warning, you need to connect first to get that one
return ;
}
KURL url = getUrl ( ) ;
url . setPath ( imapPath ) ;
ACLJobs : : GetUserRightsJob * job = ACLJobs : : getUserRights ( mSlave , url ) ;
jobData jd ( url . url ( ) , parent ) ;
jd . cancellable = true ;
insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
TQT_SLOT ( slotGetUserRightsResult ( KIO : : Job * ) ) ) ;
}
void ImapAccountBase : : slotGetUserRightsResult ( KIO : : Job * _job )
{
ACLJobs : : GetUserRightsJob * job = static_cast < ACLJobs : : GetUserRightsJob * > ( _job ) ;
JobIterator it = findJob ( job ) ;
if ( it = = jobsEnd ( ) ) return ;
KMFolder * folder = ( * it ) . parent ;
if ( job - > error ( ) ) {
if ( job - > error ( ) = = KIO : : ERR_UNSUPPORTED_ACTION ) // that's when the imap server doesn't support ACLs
mACLSupport = false ;
else
kdWarning ( 5006 ) < < " slotGetUserRightsResult: " < < job - > errorString ( ) < < endl ;
} else {
# ifndef NDEBUG
//kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl;
# endif
}
// Store the permissions
if ( folder - > folderType ( ) = = KMFolderTypeImap )
static_cast < KMFolderImap * > ( folder - > storage ( ) ) - > setUserRights ( job - > permissions ( ) ,
job - > error ( ) ? KMail : : ACLJobs : : FetchFailed : KMail : : ACLJobs : : Ok ) ;
else if ( folder - > folderType ( ) = = KMFolderTypeCachedImap )
static_cast < KMFolderCachedImap * > ( folder - > storage ( ) ) - > setUserRights ( job - > permissions ( ) ,
job - > error ( ) ? KMail : : ACLJobs : : FetchFailed : KMail : : ACLJobs : : Ok ) ;
if ( mSlave ) removeJob ( job ) ;
emit receivedUserRights ( folder ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : getACL ( KMFolder * parent , const TQString & imapPath )
{
KURL url = getUrl ( ) ;
url . setPath ( imapPath ) ;
ACLJobs : : GetACLJob * job = ACLJobs : : getACL ( mSlave , url ) ;
jobData jd ( url . url ( ) , parent ) ;
jd . cancellable = true ;
insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
TQT_SLOT ( slotGetACLResult ( KIO : : Job * ) ) ) ;
}
void ImapAccountBase : : slotGetACLResult ( KIO : : Job * _job )
{
ACLJobs : : GetACLJob * job = static_cast < ACLJobs : : GetACLJob * > ( _job ) ;
JobIterator it = findJob ( job ) ;
if ( it = = jobsEnd ( ) ) return ;
KMFolder * folder = ( * it ) . parent ;
emit receivedACL ( folder , job , job - > entries ( ) ) ;
if ( mSlave ) removeJob ( job ) ;
}
//-----------------------------------------------------------------------------
// Do not remove imapPath, FolderDiaQuotaTab needs to call this with parent==0.
void ImapAccountBase : : getStorageQuotaInfo ( KMFolder * parent , const TQString & imapPath )
{
if ( ! mSlave ) return ;
KURL url = getUrl ( ) ;
url . setPath ( imapPath ) ;
QuotaJobs : : GetStorageQuotaJob * job = QuotaJobs : : getStorageQuota ( mSlave , url ) ;
jobData jd ( url . url ( ) , parent ) ;
jd . cancellable = true ;
insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
TQT_SLOT ( slotGetStorageQuotaInfoResult ( KIO : : Job * ) ) ) ;
}
void ImapAccountBase : : slotGetStorageQuotaInfoResult ( KIO : : Job * _job )
{
QuotaJobs : : GetStorageQuotaJob * job = static_cast < QuotaJobs : : GetStorageQuotaJob * > ( _job ) ;
JobIterator it = findJob ( job ) ;
if ( it = = jobsEnd ( ) ) return ;
if ( job - > error ( ) & & job - > error ( ) = = KIO : : ERR_UNSUPPORTED_ACTION )
setHasNoQuotaSupport ( ) ;
KMFolder * folder = ( * it ) . parent ; // can be 0
emit receivedStorageQuotaInfo ( folder , job , job - > storageQuotaInfo ( ) ) ;
if ( mSlave ) removeJob ( job ) ;
}
void ImapAccountBase : : slotNoopTimeout ( )
{
if ( mSlave ) {
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
stream < < ( int ) ' N ' ;
KIO : : SimpleJob * job = KIO : : special ( getUrl ( ) , packedArgs , false ) ;
KIO : : Scheduler : : assignJobToSlave ( mSlave , job ) ;
connect ( job , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
this , TQT_SLOT ( slotSimpleResult ( KIO : : Job * ) ) ) ;
} else {
/* Stop the timer, we have disconnected. We have to make sure it is
started again when a new slave appears . */
mNoopTimer . stop ( ) ;
}
}
void ImapAccountBase : : slotIdleTimeout ( )
{
if ( mSlave ) {
KIO : : Scheduler : : disconnectSlave ( mSlave ) ;
mSlave = 0 ;
mSlaveConnected = false ;
/* As for the noop timer, we need to make sure this one is started
again when a new slave goes up . */
mIdleTimer . stop ( ) ;
}
}
void ImapAccountBase : : slotAbortRequested ( KPIM : : ProgressItem * item )
{
if ( item )
item - > setComplete ( ) ;
killAllJobs ( ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotSchedulerSlaveError ( KIO : : Slave * aSlave , int errorCode ,
const TQString & errorMsg )
{
if ( aSlave ! = mSlave ) return ;
handleError ( errorCode , errorMsg , 0 , TQString ( ) , true ) ;
if ( mAskAgain )
if ( makeConnection ( ) ! = ImapAccountBase : : Error )
return ;
if ( ! mSlaveConnected ) {
mSlaveConnectionError = true ;
resetConnectionList ( this ) ;
if ( mSlave )
{
KIO : : Scheduler : : disconnectSlave ( slave ( ) ) ;
mSlave = 0 ;
}
}
emit connectionResult ( errorCode , errorMsg ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotSchedulerSlaveConnected ( KIO : : Slave * aSlave )
{
if ( aSlave ! = mSlave ) return ;
mSlaveConnected = true ;
mNoopTimer . start ( 60000 ) ; // make sure we start sending noops
emit connectionResult ( 0 , TQString ( ) ) ; // success
if ( mNamespaces . isEmpty ( ) | | mNamespaceToDelimiter . isEmpty ( ) ) {
connect ( this , TQT_SIGNAL ( namespacesFetched ( const ImapAccountBase : : nsDelimMap & ) ) ,
this , TQT_SLOT ( slotSaveNamespaces ( const ImapAccountBase : : nsDelimMap & ) ) ) ;
getNamespaces ( ) ;
}
// get capabilities
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
stream < < ( int ) ' c ' ;
KIO : : SimpleJob * job = KIO : : special ( getUrl ( ) , packedArgs , false ) ;
KIO : : Scheduler : : assignJobToSlave ( mSlave , job ) ;
connect ( job , TQT_SIGNAL ( infoMessage ( KIO : : Job * , const TQString & ) ) ,
TQT_SLOT ( slotCapabilitiesResult ( KIO : : Job * , const TQString & ) ) ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotCapabilitiesResult ( KIO : : Job * , const TQString & result )
{
mCapabilities = TQStringList : : split ( ' ' , result . lower ( ) ) ;
kdDebug ( 5006 ) < < " capabilities: " < < mCapabilities < < endl ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : getNamespaces ( )
{
disconnect ( this , TQT_SIGNAL ( connectionResult ( int , const TQString & ) ) ,
this , TQT_SLOT ( getNamespaces ( ) ) ) ;
if ( makeConnection ( ) ! = Connected | | ! mSlave ) {
kdDebug ( 5006 ) < < " getNamespaces - wait for connection " < < endl ;
if ( mNamespaces . isEmpty ( ) | | mNamespaceToDelimiter . isEmpty ( ) ) {
// when the connection is established slotSchedulerSlaveConnected notifies us
} else {
// getNamespaces was called by someone else
connect ( this , TQT_SIGNAL ( connectionResult ( int , const TQString & ) ) ,
this , TQT_SLOT ( getNamespaces ( ) ) ) ;
}
return ;
}
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
stream < < ( int ) ' n ' ;
jobData jd ;
jd . total = 1 ; jd . done = 0 ; jd . cancellable = true ;
jd . progressItem = ProgressManager : : createProgressItem (
ProgressManager : : getUniqueID ( ) ,
i18n ( " Retrieving Namespaces " ) ,
TQString ( ) , true , useSSL ( ) | | useTLS ( ) ) ;
jd . progressItem - > setTotalItems ( 1 ) ;
connect ( jd . progressItem ,
TQT_SIGNAL ( progressItemCanceled ( KPIM : : ProgressItem * ) ) ,
this ,
TQT_SLOT ( slotAbortRequested ( KPIM : : ProgressItem * ) ) ) ;
KIO : : SimpleJob * job = KIO : : special ( getUrl ( ) , packedArgs , false ) ;
KIO : : Scheduler : : assignJobToSlave ( mSlave , job ) ;
insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( infoMessage ( KIO : : Job * , const TQString & ) ) ,
TQT_SLOT ( slotNamespaceResult ( KIO : : Job * , const TQString & ) ) ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotNamespaceResult ( KIO : : Job * job , const TQString & str )
{
JobIterator it = findJob ( job ) ;
if ( it = = jobsEnd ( ) ) return ;
nsDelimMap map ;
namespaceDelim nsDelim ;
TQStringList ns = TQStringList : : split ( " , " , str ) ;
for ( TQStringList : : Iterator it = ns . begin ( ) ; it ! = ns . end ( ) ; + + it ) {
// split, allow empty parts as we can get empty namespaces
TQStringList parts = TQStringList : : split ( " = " , * it , true ) ;
imapNamespace section = imapNamespace ( parts [ 0 ] . toInt ( ) ) ;
if ( map . contains ( section ) ) {
nsDelim = map [ section ] ;
} else {
nsDelim . clear ( ) ;
}
// map namespace to delimiter
nsDelim [ parts [ 1 ] ] = parts [ 2 ] ;
map [ section ] = nsDelim ;
}
removeJob ( it ) ;
kdDebug ( 5006 ) < < " namespaces fetched " < < endl ;
emit namespacesFetched ( map ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotSaveNamespaces ( const ImapAccountBase : : nsDelimMap & map )
{
kdDebug ( 5006 ) < < " slotSaveNamespaces " < < name ( ) < < endl ;
// extract the needed information
mNamespaces . clear ( ) ;
mNamespaceToDelimiter . clear ( ) ;
for ( uint i = 0 ; i < 3 ; + + i ) {
imapNamespace section = imapNamespace ( i ) ;
namespaceDelim ns = map [ section ] ;
namespaceDelim : : ConstIterator it ;
TQStringList list ;
for ( it = ns . begin ( ) ; it ! = ns . end ( ) ; + + it ) {
list + = it . key ( ) ;
mNamespaceToDelimiter [ it . key ( ) ] = it . data ( ) ;
}
if ( ! list . isEmpty ( ) ) {
mNamespaces [ section ] = list ;
}
}
// see if we need to migrate an old prefix
if ( ! mOldPrefix . isEmpty ( ) ) {
migratePrefix ( ) ;
}
emit namespacesFetched ( ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : migratePrefix ( )
{
if ( ! mOldPrefix . isEmpty ( ) & & mOldPrefix ! = " / " ) {
// strip /
if ( mOldPrefix . startsWith ( " / " ) ) {
mOldPrefix = mOldPrefix . right ( mOldPrefix . length ( ) - 1 ) ;
}
if ( mOldPrefix . endsWith ( " / " ) ) {
mOldPrefix = mOldPrefix . left ( mOldPrefix . length ( ) - 1 ) ;
}
TQStringList list = mNamespaces [ PersonalNS ] ;
bool done = false ;
for ( TQStringList : : Iterator it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
if ( ( * it ) . startsWith ( mOldPrefix ) ) {
// should be ok
done = true ;
kdDebug ( 5006 ) < < " migratePrefix - no migration needed " < < endl ;
break ;
}
}
if ( ! done ) {
TQString msg = i18n ( " KMail has detected a prefix entry in the "
" configuration of the account \" %1 \" which is obsolete with the "
" support of IMAP namespaces. " ) . tqarg ( name ( ) ) ;
if ( list . contains ( " " ) ) {
// replace empty entry with the old prefix
list . remove ( " " ) ;
list + = mOldPrefix ;
mNamespaces [ PersonalNS ] = list ;
if ( mNamespaceToDelimiter . contains ( " " ) ) {
TQString delim = mNamespaceToDelimiter [ " " ] ;
mNamespaceToDelimiter . remove ( " " ) ;
mNamespaceToDelimiter [ mOldPrefix ] = delim ;
}
kdDebug ( 5006 ) < < " migratePrefix - replaced empty with " < < mOldPrefix < < endl ;
msg + = i18n ( " The configuration was automatically migrated but you should check "
" your account configuration. " ) ;
} else if ( list . count ( ) = = 1 ) {
// only one entry in the personal namespace so replace it
TQString old = list . first ( ) ;
list . clear ( ) ;
list + = mOldPrefix ;
mNamespaces [ PersonalNS ] = list ;
if ( mNamespaceToDelimiter . contains ( old ) ) {
TQString delim = mNamespaceToDelimiter [ old ] ;
mNamespaceToDelimiter . remove ( old ) ;
mNamespaceToDelimiter [ mOldPrefix ] = delim ;
}
kdDebug ( 5006 ) < < " migratePrefix - replaced single with " < < mOldPrefix < < endl ;
msg + = i18n ( " The configuration was automatically migrated but you should check "
" your account configuration. " ) ;
} else {
kdDebug ( 5006 ) < < " migratePrefix - migration failed " < < endl ;
msg + = i18n ( " It was not possible to migrate your configuration automatically "
" so please check your account configuration. " ) ;
}
KMessageBox : : information ( kmkernel - > getKMMainWidget ( ) , msg ) ;
}
} else
{
kdDebug ( 5006 ) < < " migratePrefix - no migration needed " < < endl ;
}
mOldPrefix = " " ;
}
//-----------------------------------------------------------------------------
TQString ImapAccountBase : : namespaceForFolder ( FolderStorage * storage )
{
TQString path ;
if ( storage - > folderType ( ) = = KMFolderTypeImap ) {
path = static_cast < KMFolderImap * > ( storage ) - > imapPath ( ) ;
} else if ( storage - > folderType ( ) = = KMFolderTypeCachedImap ) {
path = static_cast < KMFolderCachedImap * > ( storage ) - > imapPath ( ) ;
}
nsMap : : Iterator it ;
for ( it = mNamespaces . begin ( ) ; it ! = mNamespaces . end ( ) ; + + it )
{
TQStringList : : Iterator strit ;
for ( strit = it . data ( ) . begin ( ) ; strit ! = it . data ( ) . end ( ) ; + + strit )
{
TQString ns = * strit ;
if ( ns . endsWith ( " / " ) | | ns . endsWith ( " . " ) ) {
// strip delimiter for the comparison
ns = ns . left ( ns . length ( ) - 1 ) ;
}
// first ignore an empty prefix as it would match always
if ( ! ns . isEmpty ( ) & & path . find ( ns ) ! = - 1 ) {
return ( * strit ) ;
}
}
}
return TQString ( ) ;
}
//-----------------------------------------------------------------------------
TQString ImapAccountBase : : delimiterForNamespace ( const TQString & prefix )
{
//kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
// try to match exactly
if ( mNamespaceToDelimiter . contains ( prefix ) ) {
return mNamespaceToDelimiter [ prefix ] ;
}
// then try if the prefix is part of a namespace
// exclude empty namespace
for ( namespaceDelim : : ConstIterator it = mNamespaceToDelimiter . begin ( ) ;
it ! = mNamespaceToDelimiter . end ( ) ; + + it ) {
// the namespace definition sometimes contains the delimiter
// make sure we also match this version
TQString stripped = it . key ( ) . left ( it . key ( ) . length ( ) - 1 ) ;
if ( ! it . key ( ) . isEmpty ( ) & &
( prefix . contains ( it . key ( ) ) | | prefix . contains ( stripped ) ) ) {
return it . data ( ) ;
}
}
// see if we have an empty namespace
// this should always be the case
if ( mNamespaceToDelimiter . contains ( " " ) ) {
return mNamespaceToDelimiter [ " " ] ;
}
// well, we tried
//kdDebug(5006) << "delimiterForNamespace - not found" << endl;
return TQString ( ) ;
}
//-----------------------------------------------------------------------------
TQString ImapAccountBase : : delimiterForFolder ( FolderStorage * storage )
{
TQString prefix = namespaceForFolder ( storage ) ;
TQString delim = delimiterForNamespace ( prefix ) ;
return delim ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotSimpleResult ( KIO : : Job * job )
{
JobIterator it = findJob ( job ) ;
bool quiet = false ;
if ( it ! = mapJobData . end ( ) ) {
quiet = ( * it ) . quiet ;
if ( ! ( job - > error ( ) & & ! quiet ) ) // the error handler removes in that case
removeJob ( it ) ;
}
if ( job - > error ( ) ) {
if ( ! quiet )
handleJobError ( job , TQString ( ) ) ;
else {
if ( job - > error ( ) = = KIO : : ERR_CONNECTION_BROKEN & & slave ( ) ) {
// make sure ERR_CONNECTION_BROKEN is properly handled and the slave
// disconnected even when quiet()
KIO : : Scheduler : : disconnectSlave ( slave ( ) ) ;
mSlave = 0 ;
}
if ( job - > error ( ) = = KIO : : ERR_SLAVE_DIED )
slaveDied ( ) ;
}
}
}
//-----------------------------------------------------------------------------
bool ImapAccountBase : : handlePutError ( KIO : : Job * job , jobData & jd , KMFolder * folder )
{
Q_ASSERT ( ! jd . msgList . isEmpty ( ) ) ;
KMMessage * msg = jd . msgList . first ( ) ;
// Use double-quotes around the subject to keep the sentence readable,
// but don't use double quotes around the sender since from() might return a double-quoted name already
const TQString subject = msg - > subject ( ) . isEmpty ( ) ? i18n ( " <unknown> " ) : TQString ( " \" %1 \" " ) . tqarg ( msg - > subject ( ) ) ;
const TQString from = msg - > from ( ) . isEmpty ( ) ? i18n ( " <unknown> " ) : msg - > from ( ) ;
TQString myError = " <p><b> " + i18n ( " Error while uploading message " )
+ " </b></p><p> "
+ i18n ( " Could not upload the message dated %1 from <i>%2</i> with subject <i>%3</i> to the server. " ) . tqarg ( msg - > dateStr ( ) , TQStyleSheet : : escape ( from ) , TQStyleSheet : : escape ( subject ) )
+ " </p><p> "
+ i18n ( " The destination folder was: <b>%1</b>. " ) . tqarg ( TQStyleSheet : : escape ( folder - > prettyURL ( ) ) )
+ " </p><p> "
+ i18n ( " The server reported: " ) + " </p> " ;
return handleJobError ( job , myError ) ;
}
TQString ImapAccountBase : : prettifyQuotaError ( const TQString & _error , KIO : : Job * job )
{
TQString error = _error ;
if ( error . find ( " quota " , 0 , false ) = = - 1 ) return error ;
// this is a quota error, prettify it a bit
JobIterator it = findJob ( job ) ;
TQString quotaAsString ( i18n ( " No detailed quota information available. " ) ) ;
bool readOnly = false ;
if ( it ! = mapJobData . end ( ) ) {
const KMFolder * const folder = ( * it ) . parent ;
if ( ! folder ) return _error ;
const KMFolderCachedImap * const imap = dynamic_cast < const KMFolderCachedImap * > ( folder - > storage ( ) ) ;
if ( imap ) {
quotaAsString = imap - > quotaInfo ( ) . toString ( ) ;
}
readOnly = folder - > isReadOnly ( ) ;
}
error = i18n ( " The folder is too close to its quota limit. (%1) " ) . tqarg ( quotaAsString ) ;
if ( readOnly ) {
error + = i18n ( " \n Since you do not have write privileges on this folder, "
" please ask the owner of the folder to free up some space in it. " ) ;
}
return error ;
}
//-----------------------------------------------------------------------------
bool ImapAccountBase : : handleError ( int errorCode , const TQString & errorMsg , KIO : : Job * job , const TQString & context , bool abortSync )
{
// Copy job's data before a possible killAllJobs
TQStringList errors ;
if ( job & & job - > error ( ) ! = KIO : : ERR_SLAVE_DEFINED /*workaround for tdelibs-3.2*/ )
errors = job - > detailedErrorStrings ( ) ;
bool jobsKilled = true ;
switch ( errorCode ) {
case KIO : : ERR_SLAVE_DIED : slaveDied ( ) ; killAllJobs ( true ) ; break ;
case KIO : : ERR_COULD_NOT_AUTHENTICATE : // bad password
mAskAgain = true ;
// fallthrough intended
case KIO : : ERR_CONNECTION_BROKEN :
case KIO : : ERR_COULD_NOT_CONNECT :
case KIO : : ERR_SERVER_TIMEOUT :
// These mean that we'll have to reconnect on the next attempt, so disconnect and set mSlave to 0.
killAllJobs ( true ) ;
break ;
case KIO : : ERR_COULD_NOT_LOGIN :
case KIO : : ERR_USER_CANCELED :
killAllJobs ( false ) ;
break ;
default :
if ( abortSync )
killAllJobs ( false ) ;
else
jobsKilled = false ;
break ;
}
// check if we still display an error
if ( ! mErrorDialogIsActive & & errorCode ! = KIO : : ERR_USER_CANCELED ) {
mErrorDialogIsActive = true ;
TQString msg = context + ' \n ' + prettifyQuotaError ( KIO : : buildErrorString ( errorCode , errorMsg ) , job ) ;
TQString caption = i18n ( " Error " ) ;
if ( jobsKilled | | errorCode = = KIO : : ERR_COULD_NOT_LOGIN ) {
if ( errorCode = = KIO : : ERR_SERVER_TIMEOUT | | errorCode = = KIO : : ERR_CONNECTION_BROKEN ) {
msg = i18n ( " The connection to the server %1 was unexpectedly closed or timed out. It will be re-established automatically if possible. " ) .
arg ( name ( ) ) ;
KMessageBox : : information ( TQT_TQWIDGET ( kapp - > activeWindow ( ) ) , msg , caption , " kmailConnectionBrokenErrorDialog " ) ;
// Show it in the status bar, in case the user has ticked "don't show again"
if ( errorCode = = KIO : : ERR_CONNECTION_BROKEN )
KPIM : : BroadcastStatus : : instance ( ) - > seStatusMsg (
i18n ( " The connection to account %1 was broken. " ) . tqarg ( name ( ) ) ) ;
else if ( errorCode = = KIO : : ERR_SERVER_TIMEOUT )
KPIM : : BroadcastStatus : : instance ( ) - > seStatusMsg (
i18n ( " The connection to account %1 timed out. " ) . tqarg ( name ( ) ) ) ;
} else {
if ( ! errors . isEmpty ( ) )
KMessageBox : : detailedError ( TQT_TQWIDGET ( kapp - > activeWindow ( ) ) , msg , errors . join ( " \n " ) . prepend ( " <qt> " ) , caption ) ;
else
KMessageBox : : error ( TQT_TQWIDGET ( kapp - > activeWindow ( ) ) , msg , caption ) ;
}
} else { // i.e. we have a chance to continue, ask the user about it
if ( errors . count ( ) > = 3 ) { // there is no detailedWarningContinueCancel... (#86517)
TQString error = prettifyQuotaError ( errors [ 1 ] , job ) ;
msg = TQString ( " <qt> " ) + context + error + ' \n ' + errors [ 2 ] ;
caption = errors [ 0 ] ;
}
int ret = KMessageBox : : warningContinueCancel ( TQT_TQWIDGET ( kapp - > activeWindow ( ) ) , msg , caption ) ;
if ( ret = = KMessageBox : : Cancel ) {
jobsKilled = true ;
killAllJobs ( false ) ;
}
}
mErrorDialogIsActive = false ;
} else {
if ( mErrorDialogIsActive )
kdDebug ( 5006 ) < < " suppressing error: " < < errorMsg < < endl ;
}
if ( job & & ! jobsKilled )
removeJob ( job ) ;
return ! jobsKilled ; // jobsKilled==false -> continue==true
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : cancelMailCheck ( )
{
TQMap < KIO : : Job * , jobData > : : Iterator it = mapJobData . begin ( ) ;
while ( it ! = mapJobData . end ( ) ) {
kdDebug ( 5006 ) < < " cancelMailCheck: job is cancellable: " < < ( * it ) . cancellable < < endl ;
if ( ( * it ) . cancellable ) {
it . key ( ) - > kill ( ) ;
TQMap < KIO : : Job * , jobData > : : Iterator rmit = it ;
+ + it ;
mapJobData . remove ( rmit ) ;
// We killed a job -> this kills the slave
mSlave = 0 ;
} else
+ + it ;
}
for ( TQPtrListIterator < FolderJob > it ( mJobList ) ; it . current ( ) ; + + it ) {
if ( it . current ( ) - > isCancellable ( ) ) {
FolderJob * job = it . current ( ) ;
job - > setPassiveDestructor ( true ) ;
mJobList . remove ( job ) ;
delete job ;
} else
+ + it ;
}
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : processNewMailInFolder ( KMFolder * folder , FolderListType type /*= Single*/ )
{
if ( mFoldersQueuedForChecking . contains ( folder ) )
return ;
mFoldersQueuedForChecking . append ( folder ) ;
mCheckingSingleFolder = ( type = = Single ) ;
if ( checkingMail ( ) )
{
disconnect ( this , TQT_SIGNAL ( finishedCheck ( bool , ChecktqStatus ) ) ,
this , TQT_SLOT ( slotCheckQueuedFolders ( ) ) ) ;
connect ( this , TQT_SIGNAL ( finishedCheck ( bool , ChecktqStatus ) ) ,
this , TQT_SLOT ( slotCheckQueuedFolders ( ) ) ) ;
} else {
slotCheckQueuedFolders ( ) ;
}
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotCheckQueuedFolders ( )
{
disconnect ( this , TQT_SIGNAL ( finishedCheck ( bool , ChecktqStatus ) ) ,
this , TQT_SLOT ( slotCheckQueuedFolders ( ) ) ) ;
TQValueList < TQGuardedPtr < KMFolder > > mSaveList = mMailCheckFolders ;
mMailCheckFolders = mFoldersQueuedForChecking ;
if ( kmkernel - > acctMgr ( ) )
kmkernel - > acctMgr ( ) - > singleCheckMail ( this , true ) ;
mMailCheckFolders = mSaveList ;
mFoldersQueuedForChecking . clear ( ) ;
}
//-----------------------------------------------------------------------------
bool ImapAccountBase : : checkingMail ( KMFolder * folder )
{
if ( checkingMail ( ) & & mFoldersQueuedForChecking . contains ( folder ) )
return true ;
return false ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : handleBodyStructure ( TQDataStream & stream , KMMessage * msg ,
const AttachmentStrategy * as )
{
mBodyPartList . clear ( ) ;
mCurrentMsg = msg ;
// first delete old parts as we construct our own
msg - > deleteBodyParts ( ) ;
// make the parts and fill the mBodyPartList
constructParts ( stream , 1 , 0 , 0 , msg - > asDwMessage ( ) ) ;
if ( mBodyPartList . count ( ) = = 1 ) // we directly set the body later, at partsToLoad below
msg - > deleteBodyParts ( ) ;
if ( ! as )
{
kdWarning ( 5006 ) < < k_funcinfo < < " - found no attachment strategy! " < < endl ;
return ;
}
// see what parts have to loaded according to attachmentstrategy
BodyVisitor * visitor = BodyVisitorFactory : : getVisitor ( as ) ;
visitor - > visit ( mBodyPartList ) ;
TQPtrList < KMMessagePart > parts = visitor - > partsToLoad ( ) ;
delete visitor ;
TQPtrListIterator < KMMessagePart > it ( parts ) ;
KMMessagePart * part ;
int partsToLoad = 0 ;
// check how many parts we have to load
while ( ( part = it . current ( ) ) ! = 0 )
{
+ + it ;
if ( part - > loadPart ( ) )
{
+ + partsToLoad ;
}
}
// if the only body part is not text, part->loadPart() would return false
// and that part is never loaded, so make sure it loads.
// it seems that TEXT does load the single body part even if it is not text/*
if ( mBodyPartList . count ( ) = = 1 & & partsToLoad = = 0 )
partsToLoad = 1 ; // this causes the next test to succeed, and loads the whole message
if ( ( mBodyPartList . count ( ) * 0.5 ) < partsToLoad )
{
// more than 50% of the parts have to be loaded anyway so it is faster
// to load the message completely
kdDebug ( 5006 ) < < " Falling back to normal mode " < < endl ;
FolderJob * job = msg - > parent ( ) - > createJob (
msg , FolderJob : : tGetMessage , 0 , " TEXT " ) ;
job - > start ( ) ;
return ;
}
it . toFirst ( ) ;
while ( ( part = it . current ( ) ) ! = 0 )
{
+ + it ;
kdDebug ( 5006 ) < < " ImapAccountBase::handleBodyStructure - load " < < part - > partSpecifier ( )
< < " ( " < < part - > originalContentTypeStr ( ) < < " ) " < < endl ;
if ( part - > loadHeaders ( ) )
{
kdDebug ( 5006 ) < < " load HEADER " < < endl ;
FolderJob * job = msg - > parent ( ) - > createJob (
msg , FolderJob : : tGetMessage , 0 , part - > partSpecifier ( ) + " .MIME " ) ;
job - > start ( ) ;
}
if ( part - > loadPart ( ) )
{
kdDebug ( 5006 ) < < " load Part " < < endl ;
FolderJob * job = msg - > parent ( ) - > createJob (
msg , FolderJob : : tGetMessage , 0 , part - > partSpecifier ( ) ) ;
job - > start ( ) ;
}
}
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : constructParts ( TQDataStream & stream , int count , KMMessagePart * parentKMPart ,
DwBodyPart * parent , const DwMessage * dwmsg )
{
int tqchildren ;
for ( int i = 0 ; i < count ; i + + )
{
stream > > tqchildren ;
KMMessagePart * part = new KMMessagePart ( stream ) ;
part - > setParent ( parentKMPart ) ;
mBodyPartList . append ( part ) ;
kdDebug ( 5006 ) < < " ImapAccountBase::constructParts - created id " < < part - > partSpecifier ( )
< < " of type " < < part - > originalContentTypeStr ( ) < < endl ;
DwBodyPart * dwpart = mCurrentMsg - > createDWBodyPart ( part ) ;
if ( parent )
{
// add to parent body
parent - > Body ( ) . AddBodyPart ( dwpart ) ;
dwpart - > Parse ( ) ;
// kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
// << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
} else if ( part - > partSpecifier ( ) ! = " 0 " & &
! part - > partSpecifier ( ) . endsWith ( " .HEADER " ) )
{
// add to message
dwmsg - > Body ( ) . AddBodyPart ( dwpart ) ;
dwpart - > Parse ( ) ;
// kdDebug(5006) << "constructed dwpart " << dwpart << ",dwmsg " << dwmsg << ",parent " << parent
// << ",dwparts msg " << dwpart->Body().Message() <<",id "<<dwpart->ObjectId() << endl;
} else
dwpart = 0 ;
if ( ! parentKMPart )
parentKMPart = part ;
if ( tqchildren > 0 )
{
DwBodyPart * newparent = dwpart ;
const DwMessage * newmsg = dwmsg ;
if ( part - > originalContentTypeStr ( ) = = " MESSAGE/RFC822 " & & dwpart & &
dwpart - > Body ( ) . Message ( ) )
{
// set the encapsulated message as the new message
newparent = 0 ;
newmsg = dwpart - > Body ( ) . Message ( ) ;
}
KMMessagePart * newParentKMPart = part ;
if ( part - > partSpecifier ( ) . endsWith ( " .HEADER " ) ) // we don't want headers as parent
newParentKMPart = parentKMPart ;
constructParts ( stream , tqchildren , newParentKMPart , newparent , newmsg ) ;
}
}
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : setImaptqStatus ( KMFolder * folder , const TQString & path , const TQCString & flags )
{
// set the status on the server, the uids are integrated in the path
kdDebug ( 5006 ) < < " setImapStatus path= " < < path < < " to: " < < flags < < endl ;
KURL url = getUrl ( ) ;
url . setPath ( path ) ;
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
stream < < ( int ) ' S ' < < url < < flags ;
if ( makeConnection ( ) ! = Connected )
return ; // can't happen with dimap
KIO : : SimpleJob * job = KIO : : special ( url , packedArgs , false ) ;
KIO : : Scheduler : : assignJobToSlave ( slave ( ) , job ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , folder ) ;
jd . path = path ;
insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
TQT_SLOT ( slotSeStatusResult ( KIO : : Job * ) ) ) ;
}
void ImapAccountBase : : setImapSeentqStatus ( KMFolder * folder , const TQString & path , bool seen )
{
KURL url = getUrl ( ) ;
url . setPath ( path ) ;
TQByteArray packedArgs ;
TQDataStream stream ( packedArgs , IO_WriteOnly ) ;
stream < < ( int ) ' s ' < < url < < seen ;
if ( makeConnection ( ) ! = Connected )
return ; // can't happen with dimap
KIO : : SimpleJob * job = KIO : : special ( url , packedArgs , false ) ;
KIO : : Scheduler : : assignJobToSlave ( slave ( ) , job ) ;
ImapAccountBase : : jobData jd ( url . url ( ) , folder ) ;
jd . path = path ;
insertJob ( job , jd ) ;
connect ( job , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
TQT_SLOT ( slotSeStatusResult ( KIO : : Job * ) ) ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : slotSeStatusResult ( KIO : : Job * job )
{
ImapAccountBase : : JobIterator it = findJob ( job ) ;
if ( it = = jobsEnd ( ) ) return ;
int errorCode = job - > error ( ) ;
KMFolder * const parent = ( * it ) . parent ;
const TQString path = ( * it ) . path ;
if ( errorCode & & errorCode ! = KIO : : ERR_CANNOT_OPEN_FOR_WRITING )
{
bool cont = handleJobError ( job , i18n ( " Error while uploading status of messages to server: " ) + ' \n ' ) ;
emit imapStatusChanged ( parent , path , cont ) ;
}
else
{
emit imapStatusChanged ( parent , path , true ) ;
removeJob ( it ) ;
}
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : setFolder ( KMFolder * folder , bool addAccount )
{
if ( folder )
{
folder - > setSystemLabel ( name ( ) ) ;
folder - > setId ( id ( ) ) ;
}
NetworkAccount : : setFolder ( folder , addAccount ) ;
}
//-----------------------------------------------------------------------------
void ImapAccountBase : : removeJob ( JobIterator & it )
{
if ( ( * it ) . progressItem ) {
( * it ) . progressItem - > setComplete ( ) ;
( * it ) . progressItem = 0 ;
}
mapJobData . remove ( it ) ;
}
//-----------------------------------------------------------------------------
void KMail : : ImapAccountBase : : removeJob ( KIO : : Job * job )
{
mapJobData . remove ( job ) ;
}
//-----------------------------------------------------------------------------
KPIM : : ProgressItem * ImapAccountBase : : listDirProgressItem ( )
{
if ( ! mListDirProgressItem )
{
mListDirProgressItem = ProgressManager : : createProgressItem (
" ListDir " + name ( ) ,
TQStyleSheet : : escape ( name ( ) ) ,
i18n ( " retrieving folders " ) ,
true ,
useSSL ( ) | | useTLS ( ) ) ;
connect ( mListDirProgressItem ,
TQT_SIGNAL ( progressItemCanceled ( KPIM : : ProgressItem * ) ) ,
this ,
TQT_SLOT ( slotAbortRequested ( KPIM : : ProgressItem * ) ) ) ;
// Start with a guessed value of the old folder count plus 5%. As long
// as the list of folders doesn't constantly change, that should be good
// enough.
unsigned int count = folderCount ( ) ;
mListDirProgressItem - > setTotalItems ( count + ( unsigned int ) ( count * 0.05 ) ) ;
}
return mListDirProgressItem ;
}
//-----------------------------------------------------------------------------
unsigned int ImapAccountBase : : folderCount ( ) const
{
if ( ! rootFolder ( ) | | ! rootFolder ( ) - > folder ( ) | | ! rootFolder ( ) - > folder ( ) - > child ( ) )
return 0 ;
return kmkernel - > imapFolderMgr ( ) - > folderCount ( rootFolder ( ) - > folder ( ) - > child ( ) ) ;
}
//------------------------------------------------------------------------------
TQString ImapAccountBase : : addPathToNamespace ( const TQString & prefix )
{
TQString myPrefix = prefix ;
if ( ! myPrefix . startsWith ( " / " ) ) {
myPrefix = " / " + myPrefix ;
}
if ( ! myPrefix . endsWith ( " / " ) ) {
myPrefix + = " / " ;
}
return myPrefix ;
}
//------------------------------------------------------------------------------
bool ImapAccountBase : : isNamespaceFolder ( TQString & name )
{
TQStringList ns = mNamespaces [ OtherUsersNS ] ;
ns + = mNamespaces [ SharedNS ] ;
ns + = mNamespaces [ PersonalNS ] ;
TQString nameWithDelimiter ;
for ( TQStringList : : Iterator it = ns . begin ( ) ; it ! = ns . end ( ) ; + + it )
{
nameWithDelimiter = name + delimiterForNamespace ( * it ) ;
if ( * it = = name | | * it = = nameWithDelimiter )
return true ;
}
return false ;
}
//------------------------------------------------------------------------------
ImapAccountBase : : nsDelimMap ImapAccountBase : : namespacesWithDelimiter ( )
{
nsDelimMap map ;
nsMap : : ConstIterator it ;
for ( uint i = 0 ; i < 3 ; + + i )
{
imapNamespace section = imapNamespace ( i ) ;
TQStringList namespaces = mNamespaces [ section ] ;
namespaceDelim nsDelim ;
TQStringList : : Iterator lit ;
for ( lit = namespaces . begin ( ) ; lit ! = namespaces . end ( ) ; + + lit )
{
nsDelim [ * lit ] = delimiterForNamespace ( * lit ) ;
}
map [ section ] = nsDelim ;
}
return map ;
}
//------------------------------------------------------------------------------
TQString ImapAccountBase : : createImapPath ( const TQString & parent ,
const TQString & folderName )
{
kdDebug ( 5006 ) < < " createImapPath parent= " < < parent < < " , folderName= " < < folderName < < endl ;
TQString newName = parent ;
// strip / at the end
if ( newName . endsWith ( " / " ) ) {
newName = newName . left ( newName . length ( ) - 1 ) ;
}
// add correct delimiter
TQString delim = delimiterForNamespace ( newName ) ;
// should not happen...
if ( delim . isEmpty ( ) ) {
delim = " / " ;
}
if ( ! newName . isEmpty ( ) & &
! newName . endsWith ( delim ) & & ! folderName . startsWith ( delim ) ) {
newName = newName + delim ;
}
newName = newName + folderName ;
// add / at the end
if ( ! newName . endsWith ( " / " ) ) {
newName = newName + " / " ;
}
return newName ;
}
//------------------------------------------------------------------------------
TQString ImapAccountBase : : createImapPath ( FolderStorage * parent ,
const TQString & folderName )
{
TQString path ;
if ( parent - > folderType ( ) = = KMFolderTypeImap ) {
path = static_cast < KMFolderImap * > ( parent ) - > imapPath ( ) ;
} else if ( parent - > folderType ( ) = = KMFolderTypeCachedImap ) {
path = static_cast < KMFolderCachedImap * > ( parent ) - > imapPath ( ) ;
} else {
// error
return path ;
}
return createImapPath ( path , folderName ) ;
}
bool ImapAccountBase : : locallySubscribedTo ( const TQString & imapPath )
{
return mLocalSubscriptionBlackList . find ( imapPath ) = = mLocalSubscriptionBlackList . end ( ) ;
}
void ImapAccountBase : : changeLocalSubscription ( const TQString & imapPath , bool subscribe )
{
if ( subscribe ) {
// find in blacklist and remove from it
mLocalSubscriptionBlackList . erase ( imapPath ) ;
} else {
// blacklist
mLocalSubscriptionBlackList . insert ( imapPath ) ;
}
}
TQStringList ImapAccountBase : : locallyBlacklistedFolders ( ) const
{
TQStringList list ;
std : : set < TQString > : : const_iterator it = mLocalSubscriptionBlackList . begin ( ) ;
std : : set < TQString > : : const_iterator end = mLocalSubscriptionBlackList . end ( ) ;
for ( ; it ! = end ; + + it )
list . append ( * it ) ;
return list ;
}
void ImapAccountBase : : localBlacklistFromStringList ( const TQStringList & list )
{
for ( TQStringList : : ConstIterator it = list . constBegin ( ) ; it ! = list . constEnd ( ) ; + + it )
mLocalSubscriptionBlackList . insert ( * it ) ;
}
} // namespace KMail
# include "imapaccountbase.moc"