";
+ if ( printing ) {
+ //provide a bit more left padding when printing
+ //kolab/issue3254 (printed mail cut at the left side)
+ headerStr += "
";
+ } else {
+ headerStr += "
";
+ }
- // TODO
- // spam status
- // ### iterate over the rest of strategy->headerToDisplay() (or
- // ### all headers if DefaultPolicy == Display) (elsewhere, too)
- return headerStr;
+ // TODO
+ // spam status
+ // ### iterate over the rest of strategy->headerToDisplay() (or
+ // ### all headers if DefaultPolicy == Display) (elsewhere, too)
+ return headerStr;
}
// #####################
diff --git a/kmail/identitydialog.cpp b/kmail/identitydialog.cpp
index c0a1952d7..22b5a4c81 100644
--- a/kmail/identitydialog.cpp
+++ b/kmail/identitydialog.cpp
@@ -48,6 +48,7 @@ using KMail::FolderRequester;
#include "kmfolder.h"
#include "templatesconfiguration.h"
#include "templatesconfiguration_kfg.h"
+#include "simplestringlisteditor.h"
// other kdepim headers:
// libkdepim
@@ -76,6 +77,8 @@ using KMail::FolderRequester;
#include
#include
#include
+#include
+#include
// other headers:
#include
@@ -107,7 +110,7 @@ namespace KMail {
tab = new TQWidget( tabWidget );
tabWidget->addTab( tab, i18n("&General") );
- glay = new TQGridLayout( tab, 4, 2, marginHint(), spacingHint() );
+ glay = new TQGridLayout( tab, 5, 2, marginHint(), spacingHint() );
glay->setRowStretch( 3, 1 );
glay->setColStretch( 1, 1 );
@@ -140,19 +143,40 @@ namespace KMail {
TQWhatsThis::add( mOrganizationEdit, msg );
// "Email Address" line edit and label:
- // (row 3: spacer)
++row;
mEmailEdit = new KLineEdit( tab );
glay->addWidget( mEmailEdit, row, 1 );
label = new TQLabel( mEmailEdit, i18n("&Email address:"), tab );
glay->addWidget( label, row, 0 );
msg = i18n("
Email address
"
- "
This field should have your full email address.
"
+ "
This field should have your full email address
"
+ "
This address is the primary one, used for all outgoing mail. "
+ "If you have more than one address, either create a new identity, "
+ "or add additional alias addresses in the field below.
"
"
If you leave this blank, or get it wrong, people "
"will have trouble replying to you.
This field contains alias addresses that should also "
+ "be considered as belonging to this identity (as opposed "
+ "to representing a different identity).
"
+ "
Example:
"
+ "
"
+ "
Primary address:
first.last@example.org
"
+ "
Aliases:
first@example.org last@example.org
"
+ "
"
+ "
Type one alias address per line.
");
+ TQWhatsThis::add( label, msg );
+ TQWhatsThis::add( mAliasEdit, msg );
+
//
// Tab Widget: Cryptography
//
@@ -499,6 +523,15 @@ void IdentityDialog::slotOk() {
return;
}
+ const TQStringList aliases = mAliasEdit->stringList();
+ for ( TQStringList::const_iterator it = aliases.begin(), end = aliases.end() ; it != end ; ++it ) {
+ if ( !isValidSimpleEmailAddress( *it ) ) {
+ TQString errorMsg( simpleEmailAddressErrorMsg());
+ KMessageBox::sorry( this, errorMsg, i18n("Invalid Email Alias \"%1\"").arg( *it ) );
+ return;
+ }
+ }
+
if ( !validateAddresses( mReplyToEdit->text().stripWhiteSpace() ) ) {
return;
}
@@ -584,7 +617,8 @@ void IdentityDialog::slotOk() {
// "General" tab:
mNameEdit->setText( ident.fullName() );
mOrganizationEdit->setText( ident.organization() );
- mEmailEdit->setText( ident.emailAddr() );
+ mEmailEdit->setText( ident.primaryEmailAddress() );
+ mAliasEdit->setStringList( ident.emailAliases() );
// "Cryptography" tab:
mPGPSigningKeyRequester->setFingerprint( ident.pgpSigningKey() );
@@ -652,7 +686,9 @@ void IdentityDialog::slotOk() {
ident.setFullName( mNameEdit->text() );
ident.setOrganization( mOrganizationEdit->text() );
TQString email = mEmailEdit->text();
- ident.setEmailAddr( email );
+ ident.setPrimaryEmailAddress( email );
+ const TQStringList aliases = mAliasEdit->stringList();
+ ident.setEmailAliases( aliases );
// "Cryptography" tab:
ident.setPGPSigningKey( mPGPSigningKeyRequester->fingerprint().latin1() );
ident.setPGPEncryptionKey( mPGPEncryptionKeyRequester->fingerprint().latin1() );
diff --git a/kmail/identitydialog.h b/kmail/identitydialog.h
index 20bb55a70..f8e71073c 100644
--- a/kmail/identitydialog.h
+++ b/kmail/identitydialog.h
@@ -40,6 +40,7 @@ class TQCheckBox;
class TQComboBox;
class TQString;
class TQStringList;
+class SimpleStringListEditor;
class TemplatesConfiguration;
class KPushButton;
namespace Kleo {
@@ -87,6 +88,7 @@ namespace KMail {
TQLineEdit *mNameEdit;
TQLineEdit *mOrganizationEdit;
TQLineEdit *mEmailEdit;
+ SimpleStringListEditor *mAliasEdit;
// "cryptography" tab:
TQWidget *mCryptographyTab;
Kleo::SigningKeyRequester *mPGPSigningKeyRequester;
diff --git a/kmail/imapaccountbase.cpp b/kmail/imapaccountbase.cpp
index 778403988..b0f78c5aa 100644
--- a/kmail/imapaccountbase.cpp
+++ b/kmail/imapaccountbase.cpp
@@ -198,6 +198,7 @@ namespace KMail {
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 ) );
@@ -237,6 +238,7 @@ namespace KMail {
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() ) {
@@ -357,7 +359,7 @@ namespace KMail {
}
//-----------------------------------------------------------------------------
- void ImapAccountBase::changeSubscription( bool subscribe, const TQString& imapPath )
+ void ImapAccountBase::changeSubscription( bool subscribe, const TQString& imapPath, bool quiet )
{
// change the subscription of the folder
KURL url = getUrl();
@@ -380,6 +382,7 @@ namespace KMail {
// 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 *)),
@@ -396,7 +399,9 @@ namespace KMail {
TQString path = static_cast(job)->url().path();
if (job->error())
{
- handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' );
+ if ( !(*it).quiet )
+ handleJobError( job, i18n( "Error while trying to subscribe to %1:" ).arg( path ) + '\n' );
+ emit subscriptionChangeFailed( job->errorString() );
// ## emit subscriptionChanged here in case anyone needs it to support continue/cancel
}
else
@@ -416,9 +421,9 @@ namespace KMail {
// 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( parent->storage() )->setUserRights( ACLJobs::All );
+ static_cast( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
else if ( parent->folderType() == KMFolderTypeCachedImap )
- static_cast( parent->storage() )->setUserRights( ACLJobs::All );
+ static_cast( parent->storage() )->setUserRights( ACLJobs::All, ACLJobs::Ok );
emit receivedUserRights( parent ); // warning, you need to connect first to get that one
return;
}
@@ -452,12 +457,15 @@ namespace KMail {
#ifndef NDEBUG
//kdDebug(5006) << "User Rights: " << ACLJobs::permissionsToString( job->permissions() ) << endl;
#endif
- // Store the permissions
- if ( folder->folderType() == KMFolderTypeImap )
- static_cast( folder->storage() )->setUserRights( job->permissions() );
- else if ( folder->folderType() == KMFolderTypeCachedImap )
- static_cast( folder->storage() )->setUserRights( job->permissions() );
}
+ // Store the permissions
+ if ( folder->folderType() == KMFolderTypeImap )
+ static_cast( folder->storage() )->setUserRights( job->permissions(),
+ job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok );
+ else if ( folder->folderType() == KMFolderTypeCachedImap )
+ static_cast( folder->storage() )->setUserRights( job->permissions(),
+ job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok );
+
if (mSlave) removeJob(job);
emit receivedUserRights( folder );
}
@@ -802,7 +810,7 @@ namespace KMail {
//-----------------------------------------------------------------------------
TQString ImapAccountBase::delimiterForNamespace( const TQString& prefix )
{
- kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
+ //kdDebug(5006) << "delimiterForNamespace " << prefix << endl;
// try to match exactly
if ( mNamespaceToDelimiter.contains(prefix) ) {
return mNamespaceToDelimiter[prefix];
@@ -826,7 +834,7 @@ namespace KMail {
return mNamespaceToDelimiter[""];
}
// well, we tried
- kdDebug(5006) << "delimiterForNamespace - not found" << endl;
+ //kdDebug(5006) << "delimiterForNamespace - not found" << endl;
return TQString::null;
}
@@ -893,17 +901,17 @@ namespace KMail {
bool readOnly = false;
if (it != mapJobData.end()) {
const KMFolder * const folder = (*it).parent;
- assert(folder);
+ if( !folder ) return _error;
const KMFolderCachedImap * const imap = dynamic_cast( folder->storage() );
if ( imap ) {
- quotaAsString = imap->quotaInfo().toString();
+ quotaAsString = imap->quotaInfo().toString();
}
readOnly = folder->isReadOnly();
}
error = i18n("The folder is too close to its quota limit. (%1)").arg( quotaAsString );
if ( readOnly ) {
error += i18n("\nSince you do not have write privileges on this folder, "
- "please ask the owner of the folder to free up some space in it.");
+ "please ask the owner of the folder to free up some space in it.");
}
return error;
}
@@ -1015,12 +1023,12 @@ namespace KMail {
}
//-----------------------------------------------------------------------------
- void ImapAccountBase::processNewMailSingleFolder(KMFolder* folder)
+ void ImapAccountBase::processNewMailInFolder( KMFolder* folder, FolderListType type /*= Single*/ )
{
if ( mFoldersQueuedForChecking.contains( folder ) )
return;
- mFoldersQueuedForChecking.append(folder);
- mCheckingSingleFolder = true;
+ mFoldersQueuedForChecking.append( folder );
+ mCheckingSingleFolder = ( type == Single );
if ( checkingMail() )
{
disconnect( this, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
diff --git a/kmail/imapaccountbase.h b/kmail/imapaccountbase.h
index 26d7a4b01..39fb33b69 100644
--- a/kmail/imapaccountbase.h
+++ b/kmail/imapaccountbase.h
@@ -187,8 +187,10 @@ namespace KMail {
* Subscribe (@p subscribe = TRUE) / Unsubscribe the folder
* identified by @p imapPath.
* Emits subscriptionChanged signal on success.
+ * Emits subscriptionChangeFailed signal when it fails.
+ * @param quiet if false, an error message will be displayed if the job fails.
*/
- void changeSubscription(bool subscribe, const TQString& imapPath);
+ void changeSubscription(bool subscribe, const TQString& imapPath, bool quiet = false );
/**
* Returns whether the account is locally subscribed to the
@@ -252,9 +254,10 @@ namespace KMail {
virtual void cancelMailCheck();
/**
- * Init a new-mail-check for a single folder
+ * Init a new-mail-check for a single folder, and optionally its subfolders.
*/
- void processNewMailSingleFolder(KMFolder* folder);
+ enum FolderListType { Single, Recursive };
+ void processNewMailInFolder( KMFolder* folder, FolderListType type = Single );
/**
* Return true if we are processing a mailcheck for a single folder
@@ -323,7 +326,7 @@ namespace KMail {
/**
* Returns the root folder of this account
*/
- virtual FolderStorage* const rootFolder() const = 0;
+ virtual FolderStorage* rootFolder() const = 0;
/**
* Progress item for listDir
@@ -585,6 +588,12 @@ namespace KMail {
*/
void subscriptionChanged(const TQString& imapPath, bool subscribed);
+ /**
+ * Emitted when changeSubscription() failed.
+ * @param errorMessage the error message that contains the reason for the failure
+ */
+ void subscriptionChangeFailed( const TQString &errorMessage );
+
/**
* Emitted upon completion of the job for setting the status for a group of UIDs,
* as a result of a setImapStatus call.
@@ -595,7 +604,8 @@ namespace KMail {
/**
* Emitted when the get-user-rights job is done,
* as a result of a getUserRights call.
- * Use userRights() to retrieve them, they will still be on 0 if the job failed.
+ * Use userRights() to retrieve them after using userRightsState() to see if the results are
+ * valid.
*/
void receivedUserRights( KMFolder* folder );
diff --git a/kmail/imapjob.cpp b/kmail/imapjob.cpp
index 50db423cb..560343689 100644
--- a/kmail/imapjob.cpp
+++ b/kmail/imapjob.cpp
@@ -420,6 +420,8 @@ void ImapJob::slotGetMessageResult( KIO::Job * job )
// do not know if the message has no attachment or we simply did not load the header
if (msg->attachmentState() != KMMsgHasAttachment)
msg->updateAttachmentState();
+ if (msg->invitationState() != KMMsgHasInvitation)
+ msg->updateInvitationState();
}
} else {
kdDebug(5006) << "ImapJob::slotGetMessageResult - got no data for " << mPartSpecifier << endl;
diff --git a/kmail/importarchivedialog.cpp b/kmail/importarchivedialog.cpp
new file mode 100644
index 000000000..bdae8054d
--- /dev/null
+++ b/kmail/importarchivedialog.cpp
@@ -0,0 +1,107 @@
+/* Copyright 2009 Klarälvdalens Datakonsult AB
+
+ 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; either version 2 of
+ the License or (at your option) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 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, see .
+*/
+#include "importarchivedialog.h"
+
+#include "kmfolder.h"
+#include "folderrequester.h"
+#include "kmmainwidget.h"
+#include "importjob.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace KMail;
+
+ImportArchiveDialog::ImportArchiveDialog( TQWidget *parent, TQt::WidgetFlags flags )
+ : KDialogBase( parent, "import_archive_dialog", false, i18n( "Import Archive" ),
+ KDialogBase::Ok | KDialogBase::Cancel,
+ KDialogBase::Ok, true ),
+ mParentWidget( parent )
+{
+ setWFlags( flags );
+ TQWidget *mainWidget = new TQWidget( this );
+ TQGridLayout *mainLayout = new TQGridLayout( mainWidget );
+ mainLayout->setSpacing( KDialog::spacingHint() );
+ mainLayout->setMargin( KDialog::marginHint() );
+ setMainWidget( mainWidget );
+
+ int row = 0;
+
+ // TODO: Explaination label
+ // TODO: Use QFormLayout in KDE4
+ // TODO: better label for "Ok" button
+
+ TQLabel *folderLabel = new TQLabel( i18n( "&Folder:" ), mainWidget );
+ mainLayout->addWidget( folderLabel, row, 0 );
+ mFolderRequester = new FolderRequester( mainWidget, kmkernel->getKMMainWidget()->folderTree() );
+ folderLabel->setBuddy( mFolderRequester );
+ mainLayout->addWidget( mFolderRequester, row, 1 );
+ row++;
+
+ TQLabel *fileNameLabel = new TQLabel( i18n( "&Archive File:" ), mainWidget );
+ mainLayout->addWidget( fileNameLabel, row, 0 );
+ mUrlRequester = new KURLRequester( mainWidget );
+ mUrlRequester->setMode( KFile::LocalOnly );
+ mUrlRequester->setFilter( "*.tar *.zip *.tar.gz *.tar.bz2" );
+ fileNameLabel->setBuddy( mUrlRequester );
+ mainLayout->addWidget( mUrlRequester, row, 1 );
+ row++;
+
+ // TODO: what's this, tooltips
+
+ mainLayout->setColStretch( 1, 1 );
+ mainLayout->addItem( new TQSpacerItem( 1, 1, TQSizePolicy::Expanding, TQSizePolicy::Expanding ), row, 0 );
+
+ // Make it a bit bigger, else the folder requester cuts off the text too early
+ resize( 500, minimumSize().height() );
+}
+
+void ImportArchiveDialog::setFolder( KMFolder *defaultFolder )
+{
+ mFolderRequester->setFolder( defaultFolder );
+}
+
+void ImportArchiveDialog::slotOk()
+{
+ if ( !TQFile::exists( mUrlRequester->url() ) ) {
+ KMessageBox::information( this, i18n( "Please select an archive file that should be imported." ),
+ i18n( "No archive file selected" ) );
+ return;
+ }
+
+ if ( !mFolderRequester->folder() ) {
+ KMessageBox::information( this, i18n( "Please select the folder where the archive should be imported to." ),
+ i18n( "No target folder selected" ) );
+ return;
+ }
+
+ // TODO: check if url is empty. or better yet, disable ok button until file is chosen
+
+ ImportJob *importJob = new KMail::ImportJob( mParentWidget );
+ importJob->setFile( mUrlRequester->url() );
+ importJob->setRootFolder( mFolderRequester->folder() );
+ importJob->start();
+ accept();
+}
+
+#include "importarchivedialog.moc"
diff --git a/kmail/importarchivedialog.h b/kmail/importarchivedialog.h
new file mode 100644
index 000000000..0b04d9b84
--- /dev/null
+++ b/kmail/importarchivedialog.h
@@ -0,0 +1,55 @@
+/* Copyright 2009 Klarälvdalens Datakonsult AB
+
+ 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; either version 2 of
+ the License or (at your option) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 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, see .
+*/
+#ifndef IMPORTARCHIVEDIALOG_H
+#define IMPORTARCHIVEDIALOG_H
+
+#include
+
+class KMFolder;
+class KURLRequester;
+
+namespace KMail
+{
+class FolderRequester;
+
+// TODO: Common base class for ArchiveFolderDialog and ImportArchiveDialog?
+class ImportArchiveDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+
+ ImportArchiveDialog( TQWidget *parent, TQt::WidgetFlags flags );
+ void setFolder( KMFolder *defaultFolder );
+
+ protected slots:
+
+ /** reimp */
+ virtual void slotOk();
+
+ private:
+
+ TQWidget *mParentWidget;
+ FolderRequester *mFolderRequester;
+ KURLRequester *mUrlRequester;
+};
+
+}
+
+#endif
diff --git a/kmail/importjob.cpp b/kmail/importjob.cpp
new file mode 100644
index 000000000..3a7de1981
--- /dev/null
+++ b/kmail/importjob.cpp
@@ -0,0 +1,396 @@
+/* Copyright 2009 Klarälvdalens Datakonsult AB
+
+ 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; either version 2 of
+ the License or (at your option) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 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, see .
+*/
+#include "importjob.h"
+
+#include "kmfolder.h"
+#include "folderutil.h"
+#include "kmfolderdir.h"
+#include "kmfolderimap.h"
+#include "imapjob.h"
+
+#include "progressmanager.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace KMail;
+
+KMail::ImportJob::ImportJob( TQWidget *parentWidget )
+ : TQObject( parentWidget ),
+ mArchive( 0 ),
+ mRootFolder( 0 ),
+ mParentWidget( parentWidget ),
+ mNumberOfImportedMessages( 0 ),
+ mCurrentFolder( 0 ),
+ mCurrentMessage( 0 ),
+ mCurrentMessageFile( 0 ),
+ mProgressItem( 0 ),
+ mAborted( false )
+{
+}
+
+KMail::ImportJob::~ImportJob()
+{
+ if ( mArchive && mArchive->isOpened() ) {
+ mArchive->close();
+ }
+ delete mArchive;
+ mArchive = 0;
+}
+
+void KMail::ImportJob::setFile( const KURL &archiveFile )
+{
+ mArchiveFile = archiveFile;
+}
+
+void KMail::ImportJob::setRootFolder( KMFolder *rootFolder )
+{
+ mRootFolder = rootFolder;
+}
+
+void KMail::ImportJob::finish()
+{
+ kdDebug(5006) << "Finished import job." << endl;
+ mProgressItem->setComplete();
+ mProgressItem = 0;
+ TQString text = i18n( "Importing the archive file '%1' into the folder '%2' succeeded." )
+ .arg( mArchiveFile.path() ).arg( mRootFolder->name() );
+ text += "\n" + i18n( "1 message was imported.", "%n messages were imported.", mNumberOfImportedMessages );
+ KMessageBox::information( mParentWidget, text, i18n( "Import finished." ) );
+ deleteLater();
+}
+
+void KMail::ImportJob::cancelJob()
+{
+ abort( i18n( "The operation was canceled by the user." ) );
+}
+
+void KMail::ImportJob::abort( const TQString &errorMessage )
+{
+ if ( mAborted )
+ return;
+
+ mAborted = true;
+ TQString text = i18n( "Failed to import the archive into folder '%1'." ).arg( mRootFolder->name() );
+ text += "\n" + errorMessage;
+ if ( mProgressItem ) {
+ mProgressItem->setComplete();
+ mProgressItem = 0;
+ // The progressmanager will delete it
+ }
+ KMessageBox::sorry( mParentWidget, text, i18n( "Importing archive failed." ) );
+ deleteLater();
+}
+
+KMFolder * KMail::ImportJob::createSubFolder( KMFolder *parent, const TQString &folderName, mode_t permissions )
+{
+ KMFolder *newFolder = FolderUtil::createSubFolder( parent, parent->child(), folderName, TQString(),
+ KMFolderTypeMaildir );
+ if ( !newFolder ) {
+ abort( i18n( "Unable to create subfolder for folder '%1'." ).arg( parent->name() ) );
+ return 0;
+ }
+ else {
+ newFolder->createChildFolder(); // TODO: Just creating a child folder here is wasteful, only do
+ // that if really needed. We do it here so we can set the
+ // permissions
+ chmod( newFolder->location().latin1(), permissions | S_IXUSR );
+ chmod( newFolder->subdirLocation().latin1(), permissions | S_IXUSR );
+ // TODO: chown?
+ // TODO: what about subdirectories like "cur"?
+ return newFolder;
+ }
+}
+
+void KMail::ImportJob::enqueueMessages( const KArchiveDirectory *dir, KMFolder *folder )
+{
+ const KArchiveDirectory *messageDir = dynamic_cast( dir->entry( "cur" ) );
+ if ( messageDir ) {
+ Messages messagesToQueue;
+ messagesToQueue.parent = folder;
+ const TQStringList entries = messageDir->entries();
+ for ( uint i = 0; i < entries.size(); i++ ) {
+ const KArchiveEntry *entry = messageDir->entry( entries[i] );
+ Q_ASSERT( entry );
+ if ( entry->isDirectory() ) {
+ kdWarning(5006) << "Unexpected subdirectory in archive folder " << dir->name() << endl;
+ }
+ else {
+ kdDebug(5006) << "Queueing message " << entry->name() << endl;
+ const KArchiveFile *file = static_cast( entry );
+ messagesToQueue.files.append( file );
+ }
+ }
+ mQueuedMessages.append( messagesToQueue );
+ }
+ else {
+ kdWarning(5006) << "No 'cur' subdirectory for archive directory " << dir->name() << endl;
+ }
+}
+
+void KMail::ImportJob::messageAdded()
+{
+ mNumberOfImportedMessages++;
+ if ( mCurrentFolder->folderType() == KMFolderTypeMaildir ||
+ mCurrentFolder->folderType() == KMFolderTypeCachedImap ) {
+ const TQString messageFile = mCurrentFolder->location() + "/cur/" + mCurrentMessage->fileName();
+ // TODO: what if the file is not in the "cur" subdirectory?
+ if ( TQFile::exists( messageFile ) ) {
+ chmod( messageFile.latin1(), mCurrentMessageFile->permissions() );
+ // TODO: changing user/group he requires a bit more work, requires converting the strings
+ // to uid_t and gid_t
+ //getpwnam()
+ //chown( messageFile,
+ }
+ else {
+ kdWarning(5006) << "Unable to change permissions for newly created file: " << messageFile << endl;
+ }
+ }
+ // TODO: Else?
+
+ mCurrentMessage = 0;
+ mCurrentMessageFile = 0;
+ TQTimer::singleShot( 0, this, TQT_SLOT( importNextMessage() ) );
+}
+
+void KMail::ImportJob::importNextMessage()
+{
+ if ( mAborted )
+ return;
+
+ if ( mQueuedMessages.isEmpty() ) {
+ kdDebug(5006) << "importNextMessage(): Processed all messages in the queue." << endl;
+ if ( mCurrentFolder ) {
+ mCurrentFolder->close( "ImportJob" );
+ }
+ mCurrentFolder = 0;
+ importNextDirectory();
+ return;
+ }
+
+ Messages &messages = mQueuedMessages.front();
+ if ( messages.files.isEmpty() ) {
+ mQueuedMessages.pop_front();
+ importNextMessage();
+ return;
+ }
+
+ KMFolder *folder = messages.parent;
+ if ( folder != mCurrentFolder ) {
+ kdDebug(5006) << "importNextMessage(): Processed all messages in the current folder of the queue." << endl;
+ if ( mCurrentFolder ) {
+ mCurrentFolder->close( "ImportJob" );
+ }
+ mCurrentFolder = folder;
+ if ( mCurrentFolder->open( "ImportJob" ) != 0 ) {
+ abort( i18n( "Unable to open folder '%1'." ).arg( mCurrentFolder->name() ) );
+ return;
+ }
+ kdDebug(5006) << "importNextMessage(): Current folder of queue is now: " << mCurrentFolder->name() << endl;
+ mProgressItem->setStatus( i18n( "Importing folder %1" ).arg( mCurrentFolder->name() ) );
+ }
+
+ mProgressItem->setProgress( ( mProgressItem->progress() + 5 ) );
+
+ mCurrentMessageFile = messages.files.first();
+ Q_ASSERT( mCurrentMessageFile );
+ messages.files.removeFirst();
+
+ mCurrentMessage = new KMMessage();
+ mCurrentMessage->fromByteArray( mCurrentMessageFile->data(), true /* setStatus */ );
+ int retIndex;
+
+ // If this is not an IMAP folder, we can add the message directly. Otherwise, the whole thing is
+ // async, for online IMAP. While addMsg() fakes a sync call, we rather do it the async way here
+ // ourselves, as otherwise the whole thing gets pretty much messed up with regards to folder
+ // refcounting. Furthermore, the completion dialog would be shown before the messages are actually
+ // uploaded.
+ if ( mCurrentFolder->folderType() != KMFolderTypeImap ) {
+ if ( mCurrentFolder->addMsg( mCurrentMessage, &retIndex ) != 0 ) {
+ abort( i18n( "Failed to add a message to the folder '%1'." ).arg( mCurrentFolder->name() ) );
+ return;
+ }
+ messageAdded();
+ }
+ else {
+ ImapJob *imapJob = new ImapJob( mCurrentMessage, ImapJob::tPutMessage,
+ dynamic_cast( mCurrentFolder->storage() ) );
+ connect( imapJob, TQT_SIGNAL(result(KMail::FolderJob*)),
+ TQT_SLOT(messagePutResult(KMail::FolderJob*)) );
+ imapJob->start();
+ }
+}
+
+void KMail::ImportJob::messagePutResult( KMail::FolderJob *job )
+{
+ if ( mAborted )
+ return;
+
+ if ( job->error() ) {
+ abort( i18n( "Failed to upload a message to the IMAP server." ) );
+ return;
+ } else {
+
+ KMFolderImap *imap = dynamic_cast( mCurrentFolder->storage() );
+ Q_ASSERT( imap );
+
+ // Ok, we uploaded the message, but we still need to add it to the folder. Use addMsgQuiet(),
+ // otherwise it will be uploaded again.
+ imap->addMsgQuiet( mCurrentMessage );
+ messageAdded();
+ }
+}
+
+// Input: .inbox.directory
+// Output: inbox
+// Can also return an empty string if this is no valid dir name
+static TQString folderNameForDirectoryName( const TQString &dirName )
+{
+ Q_ASSERT( dirName.startsWith( "." ) );
+ const TQString end = ".directory";
+ const int expectedIndex = dirName.length() - end.length();
+ if ( dirName.lower().find( end ) != expectedIndex )
+ return TQString();
+ TQString returnName = dirName.left( dirName.length() - end.length() );
+ returnName = returnName.right( returnName.length() - 1 );
+ return returnName;
+}
+
+KMFolder* KMail::ImportJob::getOrCreateSubFolder( KMFolder *parentFolder, const TQString &subFolderName,
+ mode_t subFolderPermissions )
+{
+ if ( !parentFolder->createChildFolder() ) {
+ abort( i18n( "Unable to create subfolder for folder '%1'." ).arg( parentFolder->name() ) );
+ return 0;
+ }
+
+ KMFolder *subFolder = 0;
+ subFolder = dynamic_cast( parentFolder->child()->hasNamedFolder( subFolderName ) );
+
+ if ( !subFolder ) {
+ subFolder = createSubFolder( parentFolder, subFolderName, subFolderPermissions );
+ }
+ return subFolder;
+}
+
+void KMail::ImportJob::importNextDirectory()
+{
+ if ( mAborted )
+ return;
+
+ if ( mQueuedDirectories.isEmpty() ) {
+ finish();
+ return;
+ }
+
+ Folder folder = mQueuedDirectories.first();
+ KMFolder *currentFolder = folder.parent;
+ mQueuedDirectories.pop_front();
+ kdDebug(5006) << "importNextDirectory(): Working on directory " << folder.archiveDir->name() << endl;
+
+ TQStringList entries = folder.archiveDir->entries();
+ for ( uint i = 0; i < entries.size(); i++ ) {
+ const KArchiveEntry *entry = folder.archiveDir->entry( entries[i] );
+ Q_ASSERT( entry );
+ kdDebug(5006) << "Queueing entry " << entry->name() << endl;
+ if ( entry->isDirectory() ) {
+ const KArchiveDirectory *dir = static_cast( entry );
+ if ( !dir->name().startsWith( "." ) ) {
+
+ kdDebug(5006) << "Queueing messages in folder " << entry->name() << endl;
+ KMFolder *subFolder = getOrCreateSubFolder( currentFolder, entry->name(), entry->permissions() );
+ if ( !subFolder )
+ return;
+
+ enqueueMessages( dir, subFolder );
+ }
+
+ // Entry starts with a dot, so we assume it is a subdirectory
+ else {
+
+ const TQString folderName = folderNameForDirectoryName( entry->name() );
+ if ( folderName.isEmpty() ) {
+ abort( i18n( "Unexpected subdirectory named '%1'." ).arg( entry->name() ) );
+ return;
+ }
+ KMFolder *subFolder = getOrCreateSubFolder( currentFolder, folderName, entry->permissions() );
+ if ( !subFolder )
+ return;
+
+ Folder newFolder;
+ newFolder.archiveDir = dir;
+ newFolder.parent = subFolder;
+ kdDebug(5006) << "Enqueueing directory " << entry->name() << endl;
+ mQueuedDirectories.push_back( newFolder );
+ }
+ }
+ }
+
+ importNextMessage();
+}
+
+// TODO:
+// BUGS:
+// Online IMAP can fail spectacular, for example when cancelling upload
+// Online IMAP: Inform that messages are still being uploaded on finish()!
+void KMail::ImportJob::start()
+{
+ Q_ASSERT( mRootFolder );
+ Q_ASSERT( mArchiveFile.isValid() );
+
+ KMimeType::Ptr mimeType = KMimeType::findByURL( mArchiveFile, 0, true /* local file */ );
+ if ( !mimeType->patterns().grep( "tar", false /* no case-sensitive */ ).isEmpty() )
+ mArchive = new KTar( mArchiveFile.path() );
+ else if ( !mimeType->patterns().grep( "zip", false ).isEmpty() )
+ mArchive = new KZip( mArchiveFile.path() );
+ else {
+ abort( i18n( "The file '%1' does not appear to be a valid archive." ).arg( mArchiveFile.path() ) );
+ return;
+ }
+
+ if ( !mArchive->open( IO_ReadOnly ) ) {
+ abort( i18n( "Unable to open archive file '%1'" ).arg( mArchiveFile.path() ) );
+ return;
+ }
+
+ mProgressItem = KPIM::ProgressManager::createProgressItem(
+ "ImportJob",
+ i18n( "Importing Archive" ),
+ TQString(),
+ true );
+ mProgressItem->setUsesBusyIndicator( true );
+ connect( mProgressItem, TQT_SIGNAL(progressItemCanceled(KPIM::ProgressItem*)),
+ this, TQT_SLOT(cancelJob()) );
+
+ Folder nextFolder;
+ nextFolder.archiveDir = mArchive->directory();
+ nextFolder.parent = mRootFolder;
+ mQueuedDirectories.push_back( nextFolder );
+ importNextDirectory();
+}
+
+#include "importjob.moc"
diff --git a/kmail/importjob.h b/kmail/importjob.h
new file mode 100644
index 000000000..ee7a0ac8b
--- /dev/null
+++ b/kmail/importjob.h
@@ -0,0 +1,126 @@
+/* Copyright 2009 Klarälvdalens Datakonsult AB
+
+ 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; either version 2 of
+ the License or (at your option) version 3 or any later version
+ accepted by the membership of KDE e.V. (or its successor approved
+ by the membership of KDE e.V.), which shall act as a proxy
+ defined in Section 14 of version 3 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, see .
+*/
+#ifndef IMPORTJOB_H
+#define IMPORTJOB_H
+
+#include
+
+#include
+#include
+#include
+
+#include
+
+class TQWidget;
+class KArchive;
+class KArchiveDirectory;
+class KArchiveFile;
+class KMFolder;
+class KMMessage;
+
+namespace KPIM
+{
+ class ProgressItem;
+}
+
+namespace KMail
+{
+ class FolderJob;
+
+/**
+ * Imports an archive that was previously backed up with an BackupJob.
+ * This job will re-create the folder structure, under the root folder given in setRootFolder().
+ *
+ * The job deletes itself after it finished.
+ */
+class ImportJob : public TQObject
+{
+ Q_OBJECT
+
+ public:
+
+ explicit ImportJob( TQWidget *parentWidget = 0 );
+ ~ImportJob();
+ void start();
+ void setFile( const KURL &archiveFile );
+ void setRootFolder( KMFolder *rootFolder );
+
+ private slots:
+
+ void importNextMessage();
+ void cancelJob();
+ void messagePutResult( KMail::FolderJob *job );
+
+ private:
+
+ struct Folder
+ {
+ KMFolder *parent;
+ const KArchiveDirectory *archiveDir;
+ };
+
+ struct Messages
+ {
+ KMFolder *parent;
+ TQPtrList files;
+ };
+
+ void finish();
+ void abort( const TQString &errorMessage );
+ void queueFolders();
+ void importNextDirectory();
+ KMFolder* createSubFolder( KMFolder *parent, const TQString &folderName, mode_t permissions );
+ KMFolder* getOrCreateSubFolder( KMFolder *parentFolder, const TQString &subFolderName,
+ mode_t subFolderPermissions );
+ void enqueueMessages( const KArchiveDirectory *dir, KMFolder *folder );
+ void messageAdded();
+
+ KArchive *mArchive;
+
+ // The root folder which the user has selected as the folder to which everything should be
+ // imported
+ KMFolder *mRootFolder;
+
+ TQWidget *mParentWidget;
+ KURL mArchiveFile;
+ int mNumberOfImportedMessages;
+
+ // List of archive folders with their corresponding KMail parent folder that are awaiting
+ // processing
+ TQValueList mQueuedDirectories;
+
+ // List of list of messages and their parent folders which are awaiting processing
+ TQValueList mQueuedMessages;
+
+ // The folder to which we are currently importing messages
+ KMFolder *mCurrentFolder;
+
+ // The message which is currently being added
+ KMMessage *mCurrentMessage;
+
+ // The archive file of the current message that is being added
+ KArchiveFile *mCurrentMessageFile;
+
+ KPIM::ProgressItem *mProgressItem;
+ bool mAborted;
+};
+
+}
+
+#endif
diff --git a/kmail/interfaces/bodypartformatter.h b/kmail/interfaces/bodypartformatter.h
index b31cb26b7..9bc947f53 100644
--- a/kmail/interfaces/bodypartformatter.h
+++ b/kmail/interfaces/bodypartformatter.h
@@ -35,7 +35,7 @@
#define __KMAIL_INTERFACE_BODYPARTFORMATTER_H__
namespace KMail {
-
+ class Callback;
class HtmlWriter;
namespace Interface {
@@ -47,7 +47,7 @@ namespace KMail {
public:
virtual ~BodyPartFormatter() {}
- /**
+ /**
@li Ok returned when format() generated some HTML
@li NeedContent returned when format() needs the body of the part
@li AsIcon returned when the part should be shown iconified
@@ -61,7 +61,7 @@ namespace KMail {
@return the result code (see above)
*/
- virtual Result format( BodyPart * part, KMail::HtmlWriter * writer ) const = 0;
+ virtual Result format( BodyPart * part, KMail::HtmlWriter * writer, Callback &c ) const = 0;
};
/**
diff --git a/kmail/interfaces/urlhandler.h b/kmail/interfaces/urlhandler.h
index fba673d65..38ada083f 100644
--- a/kmail/interfaces/urlhandler.h
+++ b/kmail/interfaces/urlhandler.h
@@ -57,6 +57,41 @@ namespace KMail {
false otherwise.
*/
virtual bool handleClick( const KURL & url, KMReaderWin * w ) const = 0;
+
+ /**
+ * Called when shift-clicking the link in the reader.
+ * @return true if the click was handled by this URLHandler, false otherwise
+ */
+ virtual bool handleShiftClick( const KURL &url, KMReaderWin *window ) const {
+ Q_UNUSED( url );
+ Q_UNUSED( window );
+ return false;
+ }
+
+ /**
+ * @return should return true if this URLHandler will handle the drag
+ */
+ virtual bool willHandleDrag( const KURL &url, const TQString &imagePath,
+ KMReaderWin *window ) const {
+ Q_UNUSED( url );
+ Q_UNUSED( window );
+ Q_UNUSED( imagePath );
+ return false;
+ }
+
+ /**
+ * Called when starting a drag with the given URL.
+ * If the drag is handled, you should create a drag object.
+ * @return true if the click was handled by this URLHandler, false otherwise
+ */
+ virtual bool handleDrag( const KURL &url, const TQString &imagePath,
+ KMReaderWin *window ) const {
+ Q_UNUSED( url );
+ Q_UNUSED( window );
+ Q_UNUSED( imagePath );
+ return false;
+ }
+
/** Called when RMB-clicking on a link in the reader. Should show
a context menu at the specified point with the specified
widget as parent.
diff --git a/kmail/isubject.cpp b/kmail/isubject.cpp
index 7219dc0e9..d231d365c 100644
--- a/kmail/isubject.cpp
+++ b/kmail/isubject.cpp
@@ -31,8 +31,15 @@ namespace KMail {
void ISubject::notify()
{
kdDebug(5006) << "ISubject::notify " << mObserverList.size() << endl;
- for ( TQValueVector::iterator it = mObserverList.begin() ; it != mObserverList.end() ; ++it )
- (*it)->update( this );
+
+ // iterate over a copy (to prevent crashes when
+ // {attach(),detach()} is called from an Observer::update()
+ const TQValueVector copy = mObserverList;
+ for ( TQValueVector::const_iterator it = copy.begin() ; it != copy.end() ; ++it ) {
+ if ( (*it) ) {
+ (*it)->update( this );
+ }
+ }
}
}
diff --git a/kmail/keyresolver.cpp b/kmail/keyresolver.cpp
index e35a7f5f9..3c1a952ca 100644
--- a/kmail/keyresolver.cpp
+++ b/kmail/keyresolver.cpp
@@ -42,6 +42,7 @@
#include "kcursorsaver.h"
#include "kleo_util.h"
+#include "stl_util.h"
#include
#include
@@ -103,7 +104,7 @@ static inline bool WithRespectToKeyID( const GpgME::Key & left, const GpgME::Key
return qstrcmp( left.keyID(), right.keyID() ) == 0 ;
}
-static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
+static bool ValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
if ( key.protocol() != GpgME::Context::OpenPGP ) {
return false;
}
@@ -119,9 +120,15 @@ static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
#endif
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
return false;
+ return true;
+}
+
+static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
+ if ( !ValidOpenPGPEncryptionKey( key ) )
+ return false;
const std::vector uids = key.userIDs();
for ( std::vector::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
- if ( !it->isRevoked() && it->validity() != GpgME::UserID::Marginal )
+ if ( !it->isRevoked() && it->validity() >= GpgME::UserID::Marginal )
return true;
#if 0
else
@@ -134,7 +141,7 @@ static bool ValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key ) {
return false;
}
-static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
+static bool ValidSMIMEEncryptionKey( const GpgME::Key & key ) {
if ( key.protocol() != GpgME::Context::CMS )
return false;
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canEncrypt() )
@@ -142,6 +149,12 @@ static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
return true;
}
+static bool ValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
+ if ( !ValidSMIMEEncryptionKey( key ) )
+ return false;
+ return true;
+}
+
static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
switch ( key.protocol() ) {
case GpgME::Context::OpenPGP:
@@ -153,6 +166,17 @@ static inline bool ValidTrustedEncryptionKey( const GpgME::Key & key ) {
}
}
+static inline bool ValidEncryptionKey( const GpgME::Key & key ) {
+ switch ( key.protocol() ) {
+ case GpgME::Context::OpenPGP:
+ return ValidOpenPGPEncryptionKey( key );
+ case GpgME::Context::CMS:
+ return ValidSMIMEEncryptionKey( key );
+ default:
+ return false;
+ }
+}
+
static inline bool ValidSigningKey( const GpgME::Key & key ) {
if ( key.isRevoked() || key.isExpired() || key.isDisabled() || !key.canSign() )
return false;
@@ -171,14 +195,26 @@ static inline bool NotValidTrustedOpenPGPEncryptionKey( const GpgME::Key & key )
return !ValidTrustedOpenPGPEncryptionKey( key );
}
+static inline bool NotValidOpenPGPEncryptionKey( const GpgME::Key & key ) {
+ return !ValidOpenPGPEncryptionKey( key );
+}
+
static inline bool NotValidTrustedSMIMEEncryptionKey( const GpgME::Key & key ) {
return !ValidTrustedSMIMEEncryptionKey( key );
}
+static inline bool NotValidSMIMEEncryptionKey( const GpgME::Key & key ) {
+ return !ValidSMIMEEncryptionKey( key );
+}
+
static inline bool NotValidTrustedEncryptionKey( const GpgME::Key & key ) {
return !ValidTrustedEncryptionKey( key );
}
+static inline bool NotValidEncryptionKey( const GpgME::Key & key ) {
+ return !ValidEncryptionKey( key );
+}
+
static inline bool NotValidSigningKey( const GpgME::Key & key ) {
return !ValidSigningKey( key );
}
@@ -191,6 +227,40 @@ static inline bool NotValidSMIMESigningKey( const GpgME::Key & key ) {
return !ValidSMIMESigningKey( key );
}
+namespace {
+ struct ByTrustScore {
+ static int score( const GpgME::UserID & uid ) {
+ return uid.isRevoked() || uid.isInvalid() ? -1 : uid.validity() ;
+ }
+ bool operator()( const GpgME::UserID & lhs, const GpgME::UserID & rhs ) const {
+ return score( lhs ) < score( rhs ) ;
+ }
+ };
+}
+
+static std::vector matchingUIDs( const std::vector & uids, const TQString & address ) {
+ if ( address.isEmpty() )
+ return std::vector();
+
+ std::vector result;
+ result.reserve( uids.size() );
+ for ( std::vector::const_iterator it = uids.begin(), end = uids.end() ; it != end ; ++it )
+ // PENDING(marc) check DN for an EMAIL, too, in case of X.509 certs... :/
+ if ( const char * email = it->email() )
+ if ( *email && TQString::fromUtf8( email ).stripWhiteSpace().lower() == address )
+ result.push_back( *it );
+ return result;
+}
+
+static GpgME::UserID findBestMatchUID( const GpgME::Key & key, const TQString & address ) {
+ const std::vector all = key.userIDs();
+ if ( all.empty() )
+ return GpgME::UserID();
+ const std::vector matching = matchingUIDs( all, address.lower() );
+ const std::vector & v = matching.empty() ? all : matching ;
+ return *std::max_element( v.begin(), v.end(), ByTrustScore() );
+}
+
static TQStringList keysAsStrings( const std::vector& keys ) {
TQStringList strings;
for ( std::vector::const_iterator it = keys.begin() ; it != keys.end() ; ++it ) {
@@ -205,35 +275,40 @@ static TQStringList keysAsStrings( const std::vector& keys ) {
return strings;
}
-static inline std::vector TrustedOrConfirmed( const std::vector & keys ) {
+static std::vector trustedOrConfirmed( const std::vector & keys, const TQString & address, bool & canceled ) {
+ // PENDING(marc) work on UserIDs here?
std::vector fishies;
std::vector ickies;
+ std::vector rewookies;
std::vector::const_iterator it = keys.begin();
const std::vector::const_iterator end = keys.end();
for ( ; it != end ; it++ ) {
- const GpgME::Key key = *it;
- assert( ValidTrustedEncryptionKey( key ) );
- const std::vector uids = key.userIDs();
- for ( std::vector::const_iterator it = uids.begin() ; it != uids.end() ; ++it ) {
- if ( !it->isRevoked() && it->validity() == GpgME::UserID::Marginal ) {
+ const GpgME::Key & key = *it;
+ assert( ValidEncryptionKey( key ) );
+ const GpgME::UserID uid = findBestMatchUID( key, address );
+ if ( uid.isRevoked() ) {
+ rewookies.push_back( key );
+ }
+ if ( !uid.isRevoked() && uid.validity() == GpgME::UserID::Marginal ) {
fishies.push_back( key );
- break;
- }
- if ( !it->isRevoked() && it->validity() < GpgME::UserID::Never ) {
+ }
+ if ( !uid.isRevoked() && uid.validity() < GpgME::UserID::Never ) {
ickies.push_back( key );
- break;
- }
}
}
- if ( fishies.empty() && ickies.empty() )
+ if ( fishies.empty() && ickies.empty() && rewookies.empty() )
return keys;
// if some keys are not fully trusted, let the user confirm their use
- TQString msg = i18n("One or more of your configured OpenPGP encryption "
- "keys or S/MIME certificates is not fully trusted "
- "for encryption.");
+ TQString msg = address.isEmpty()
+ ? i18n("One or more of your configured OpenPGP encryption "
+ "keys or S/MIME certificates is not fully trusted "
+ "for encryption.")
+ : i18n("One or more of the OpenPGP encryption keys or S/MIME "
+ "certificates for recipient \"%1\" is not fully trusted "
+ "for encryption.").arg(address) ;
if ( !fishies.empty() ) {
// certificates can't have marginal trust
@@ -244,6 +319,10 @@ static inline std::vector TrustedOrConfirmed( const std::vectorrevoked: \n");
+ msg += keysAsStrings( rewookies ).join(",");
+ }
if( KMessageBox::warningContinueCancel( 0, msg, i18n("Not Fully Trusted Encryption Keys"),
KStdGuiItem::cont(),
@@ -251,7 +330,8 @@ static inline std::vector TrustedOrConfirmed( const std::vector();
+ canceled = true;
+ return std::vector();
}
namespace {
@@ -266,6 +346,20 @@ namespace {
const Kleo::CryptoMessageFormat format;
};
+
+ struct IsForFormat : std::unary_function {
+ explicit IsForFormat( Kleo::CryptoMessageFormat f )
+ : protocol( isOpenPGP( f ) ? GpgME::Context::OpenPGP :
+ isSMIME( f ) ? GpgME::Context::CMS :
+ /* else */ GpgME::Context::Unknown ) {}
+
+ bool operator()( const GpgME::Key & key ) const {
+ return key.protocol() == protocol ;
+ }
+
+ const GpgME::Context::Protocol protocol;
+ };
+
}
@@ -334,6 +428,11 @@ public:
}
void operator()( Item & item );
+ template
+ void process( Container & c ) {
+ *this = std::for_each( c.begin(), c.end(), *this );
+ }
+
#define make_int_accessor(x) unsigned int num##x() const { return m##x; }
make_int_accessor(NoKey)
make_int_accessor(NeverEncrypt)
@@ -346,6 +445,7 @@ public:
#undef make_int_accessor
private:
EncryptionPreference mDefaultPreference;
+ bool mNoOps;
unsigned int mTotal;
unsigned int mNoKey;
unsigned int mNeverEncrypt, mUnknownPreference, mAlwaysEncrypt,
@@ -353,12 +453,14 @@ private:
};
void Kleo::KeyResolver::EncryptionPreferenceCounter::operator()( Item & item ) {
+ if ( _this ) {
if ( item.needKeys )
item.keys = _this->getEncryptionKeys( item.address, true );
if ( item.keys.empty() ) {
++mNoKey;
return;
}
+ }
switch ( !item.pref ? mDefaultPreference : item.pref ) {
#define CASE(x) case Kleo::x: ++m##x; break
CASE(NeverEncrypt);
@@ -427,13 +529,13 @@ namespace {
void EncryptionFormatPreferenceCounter::operator()( const Kleo::KeyResolver::Item & item ) {
if ( item.format & (Kleo::InlineOpenPGPFormat|Kleo::OpenPGPMIMEFormat) &&
std::find_if( item.keys.begin(), item.keys.end(),
- ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) {
+ ValidTrustedOpenPGPEncryptionKey ) != item.keys.end() ) { // -= trusted?
CASE(OpenPGPMIME);
CASE(InlineOpenPGP);
}
if ( item.format & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) &&
std::find_if( item.keys.begin(), item.keys.end(),
- ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) {
+ ValidTrustedSMIMEEncryptionKey ) != item.keys.end() ) { // -= trusted?
CASE(SMIME);
CASE(SMIMEOpaque);
}
@@ -523,13 +625,108 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
const GpgME::Subkey subkey = key.subkey(0);
if ( d->alreadyWarnedFingerprints.count( subkey.fingerprint() ) )
return Kpgp::Ok; // already warned about this one (and so about it's issuers)
- d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
if ( subkey.neverExpires() )
return Kpgp::Ok;
static const double secsPerDay = 24 * 60 * 60;
- const int daysTillExpiry =
- 1 + int( ::difftime( subkey.expirationTime(), time(0) ) / secsPerDay );
+ const double secsTillExpiry = ::difftime( subkey.expirationTime(), time(0) );
+ if ( secsTillExpiry <= 0 ) {
+ const int daysSinceExpiry = 1 + int( -secsTillExpiry / secsPerDay );
+ kdDebug() << "Key 0x" << key.shortKeyID() << " expired less than "
+ << daysSinceExpiry << " days ago" << endl;
+ const TQString msg =
+ key.protocol() == GpgME::Context::OpenPGP
+ ? ( mine ? sign
+ ? i18n("
",
daysTillExpiry ) ).arg( Kleo::DN( key.userID(0).id() ).prettyDN(),
key.issuerSerial() ) );
+ d->alreadyWarnedFingerprints.insert( subkey.fingerprint() );
if ( KMessageBox::warningContinueCancel( 0, msg,
key.protocol() == GpgME::Context::OpenPGP
? i18n("OpenPGP Key Expires Soon" )
@@ -637,6 +835,7 @@ Kpgp::Result Kleo::KeyResolver::checkKeyNearExpiry( const GpgME::Key & key, cons
== KMessageBox::Cancel )
return Kpgp::Canceled;
}
+ }
if ( key.isRoot() )
return Kpgp::Ok;
else if ( const char * chain_id = key.chainID() ) {
@@ -657,10 +856,10 @@ Kpgp::Result Kleo::KeyResolver::setEncryptToSelfKeys( const TQStringList & finge
std::vector keys = lookup( fingerprints );
std::remove_copy_if( keys.begin(), keys.end(),
std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
- NotValidTrustedOpenPGPEncryptionKey );
+ NotValidTrustedOpenPGPEncryptionKey ); // -= trusted?
std::remove_copy_if( keys.begin(), keys.end(),
std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
- NotValidTrustedSMIMEEncryptionKey );
+ NotValidTrustedSMIMEEncryptionKey ); // -= trusted?
if ( d->mOpenPGPEncryptToSelfKeys.size() + d->mSMIMEEncryptToSelfKeys.size()
< keys.size() ) {
@@ -814,6 +1013,20 @@ Kleo::Action Kleo::KeyResolver::checkEncryptionPreferences( bool encryptionReque
d->mOpenPGPEncryptToSelfKeys.empty() && d->mSMIMEEncryptToSelfKeys.empty() )
return Impossible;
+ if ( !encryptionRequested && !mOpportunisticEncyption ) {
+ // try to minimize crypto ops (including key lookups) by only
+ // looking up keys when at least one the the encryption
+ // preferences needs it:
+ EncryptionPreferenceCounter count( 0, UnknownPreference );
+ count.process( d->mPrimaryEncryptionKeys );
+ count.process( d->mSecondaryEncryptionKeys );
+ if ( !count.numAlwaysEncrypt() &&
+ !count.numAlwaysAskForEncryption() && // this guy might not need a lookup, when declined, but it's too complex to implement that here
+ !count.numAlwaysEncryptIfPossible() &&
+ !count.numAskWheneverPossible() )
+ return DontDoIt;
+ }
+
EncryptionPreferenceCounter count( this, mOpportunisticEncyption ? AskWheneverPossible : UnknownPreference );
count = std::for_each( d->mPrimaryEncryptionKeys.begin(), d->mPrimaryEncryptionKeys.end(),
count );
@@ -859,9 +1072,10 @@ Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& en
result = resolveEncryptionKeys( signingRequested );
if ( result != Kpgp::Ok )
return result;
- if ( signingRequested )
- if ( encryptionRequested )
+ if ( signingRequested ) {
+ if ( encryptionRequested ) {
result = resolveSigningKeysForEncryption();
+ }
else {
result = resolveSigningKeysForSigningOnly();
if ( result == Kpgp::Failure ) {
@@ -869,6 +1083,7 @@ Kpgp::Result Kleo::KeyResolver::resolveAllKeys( bool& signingRequested, bool& en
return Kpgp::Ok;
}
}
+ }
return result;
}
@@ -1334,10 +1549,10 @@ Kpgp::Result Kleo::KeyResolver::showKeyApprovalDialog() {
std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
std::back_inserter( d->mOpenPGPEncryptToSelfKeys ),
- NotValidTrustedOpenPGPEncryptionKey );
+ NotValidTrustedOpenPGPEncryptionKey ); // -= trusted (see above, too)?
std::remove_copy_if( senderKeys.begin(), senderKeys.end(),
std::back_inserter( d->mSMIMEEncryptToSelfKeys ),
- NotValidTrustedSMIMEEncryptionKey );
+ NotValidTrustedSMIMEEncryptionKey ); // -= trusted (see above, too)?
return Kpgp::Ok;
}
@@ -1364,16 +1579,21 @@ std::vector Kleo::KeyResolver::signingKeys( CryptoMessageFormat f )
std::vector Kleo::KeyResolver::selectKeys( const TQString & person, const TQString & msg, const std::vector & selectedKeys ) const {
+ const bool opgp = containsOpenPGP( mCryptoMessageFormats );
+ const bool x509 = containsSMIME( mCryptoMessageFormats );
+
Kleo::KeySelectionDialog dlg( i18n("Encryption Key Selection"),
- msg, selectedKeys,
- Kleo::KeySelectionDialog::ValidEncryptionKeys,
+ msg, KPIM::getEmailAddress(person), selectedKeys,
+ Kleo::KeySelectionDialog::ValidEncryptionKeys
+ & ~(opgp ? 0 : Kleo::KeySelectionDialog::OpenPGPKeys)
+ & ~(x509 ? 0 : Kleo::KeySelectionDialog::SMIMEKeys),
true, true ); // multi-selection and "remember choice" box
if ( dlg.exec() != TQDialog::Accepted )
return std::vector();
std::vector keys = dlg.selectedKeys();
keys.erase( std::remove_if( keys.begin(), keys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidTrustedEncryptionKey ), // -= trusted?
keys.end() );
if ( !keys.empty() && dlg.rememberSelection() )
setKeysForAddress( person, dlg.pgpKeyFingerprints(), dlg.smimeFingerprints() );
@@ -1396,70 +1616,80 @@ std::vector Kleo::KeyResolver::getEncryptionKeys( const TQString & p
if ( !keys.empty() ) {
// Check if all of the keys are trusted and valid encryption keys
if ( std::find_if( keys.begin(), keys.end(),
- NotValidTrustedEncryptionKey ) != keys.end() ) {
+ NotValidTrustedEncryptionKey ) != keys.end() ) { // -= trusted?
// not ok, let the user select: this is not conditional on !quiet,
// since it's a bug in the configuration and the user should be
// notified about it as early as possible:
keys = selectKeys( person,
i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
"There is a problem with the "
- "encryption key(s) for \"%1\".\n\n"
- "Please re-select the key(s) which should "
+ "encryption certificate(s) for \"%1\".\n\n"
+ "Please re-select the certificate(s) which should "
"be used for this recipient.").arg(person),
keys );
}
- keys = TrustedOrConfirmed( keys );
+ bool canceled = false;
+ keys = trustedOrConfirmed( keys, address, canceled );
+ if ( canceled )
+ return std::vector();
if ( !keys.empty() )
return keys;
- // hmmm, should we not return the keys in any case here?
+ // keys.empty() is considered cancel by callers, so go on
}
}
// Now search all public keys for matching keys
std::vector matchingKeys = lookup( person );
matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidEncryptionKey ),
matchingKeys.end() );
// if no keys match the complete address look for keys which match
// the canonical mail address
if ( matchingKeys.empty() ) {
matchingKeys = lookup( address );
matchingKeys.erase( std::remove_if( matchingKeys.begin(), matchingKeys.end(),
- NotValidTrustedEncryptionKey ),
+ NotValidEncryptionKey ),
matchingKeys.end() );
}
// if called with quite == true (from EncryptionPreferenceCounter), we only want to
// check if there are keys for this recipients, not (yet) their validity, so
// don't show the untrusted encryption key warning in that case
+ bool canceled = false;
if ( !quiet )
- matchingKeys = TrustedOrConfirmed( matchingKeys );
+ matchingKeys = trustedOrConfirmed( matchingKeys, address, canceled );
+ if ( canceled )
+ return std::vector();
if ( quiet || matchingKeys.size() == 1 )
return matchingKeys;
// no match until now, or more than one key matches; let the user
// choose the key(s)
// FIXME: let user get the key from keyserver
- return TrustedOrConfirmed( selectKeys( person,
+ return trustedOrConfirmed( selectKeys( person,
matchingKeys.empty()
? i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
- "No valid and trusted encryption key was "
- "found for \"%1\".\n\n"
- "Select the key(s) which should "
- "be used for this recipient.").arg(person)
+ "No valid and trusted encryption certificate was "
+ "found for \"%1\".
"
+ "Select the certificate(s) which should "
+ "be used for this recipient. If there is no suitable certificate in the list "
+ "you can also search for external certificates by clicking the button: search for external certificates.")
+ .arg( TQStyleSheet::escape(person) )
: i18n("if in your language something like "
- "'key(s)' isn't possible please "
+ "'certificate(s)' isn't possible please "
"use the plural in the translation",
- "More than one key matches \"%1\".\n\n"
- "Select the key(s) which should "
- "be used for this recipient.").arg(person),
- matchingKeys ) );
+ "More than one certificate matches \"%1\".\n\n"
+ "Select the certificate(s) which should "
+ "be used for this recipient.").arg( TQStyleSheet::escape(person) ),
+ matchingKeys ), address, canceled );
+ // we can ignore 'canceled' here, since trustedOrConfirmed() returns
+ // an empty vector when canceled == true, and we'd just do the same
}
@@ -1513,8 +1743,11 @@ void Kleo::KeyResolver::addKeys( const std::vector & items ) {
SplitInfo si( it->address );
CryptoMessageFormat f = AutoFormat;
for ( unsigned int i = 0 ; i < numConcreteCryptoMessageFormats ; ++i ) {
- if ( concreteCryptoMessageFormats[i] & it->format ) {
- f = concreteCryptoMessageFormats[i];
+ const CryptoMessageFormat fmt = concreteCryptoMessageFormats[i];
+ if ( ( fmt & it->format ) &&
+ kdtools::any( it->keys.begin(), it->keys.end(), IsForFormat( fmt ) ) )
+ {
+ f = fmt;
break;
}
}
diff --git a/kmail/khtmlparthtmlwriter.cpp b/kmail/khtmlparthtmlwriter.cpp
index dfc9fd358..2d29d3c9e 100644
--- a/kmail/khtmlparthtmlwriter.cpp
+++ b/kmail/khtmlparthtmlwriter.cpp
@@ -49,7 +49,7 @@ namespace KMail {
KHtmlPartHtmlWriter::KHtmlPartHtmlWriter( KHTMLPart * part,
TQObject * parent, const char * name )
: TQObject( parent, name ), HtmlWriter(),
- mHtmlPart( part ), mState( Ended ), mHtmlTimer( 0, "mHtmlTimer" )
+ mHtmlPart( part ), mHtmlTimer( 0, "mHtmlTimer" ), mState( Ended )
{
assert( part );
connect( &mHtmlTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotWriteNextHtmlChunk()) );
diff --git a/kmail/kleo_util.h b/kmail/kleo_util.h
index b2378e9fa..dc0eb6d2c 100644
--- a/kmail/kleo_util.h
+++ b/kmail/kleo_util.h
@@ -77,5 +77,12 @@ static inline bool isOpenPGP( Kleo::CryptoMessageFormat f ) {
return f == Kleo::InlineOpenPGPFormat || f == Kleo::OpenPGPMIMEFormat ;
}
+static inline bool containsSMIME( unsigned int f ) {
+ return f & (Kleo::SMIMEFormat|Kleo::SMIMEOpaqueFormat) ;
+}
+
+static inline bool containsOpenPGP( unsigned int f ) {
+ return f & (Kleo::OpenPGPMIMEFormat|Kleo::InlineOpenPGPFormat) ;
+}
#endif // __KDEPIM_KMAIL_KLEO_UTIL_H__
diff --git a/kmail/kmacctcachedimap.cpp b/kmail/kmacctcachedimap.cpp
index 2305b0809..b673b5e14 100644
--- a/kmail/kmacctcachedimap.cpp
+++ b/kmail/kmacctcachedimap.cpp
@@ -179,21 +179,6 @@ void KMAcctCachedImap::cancelMailCheck()
}
}
-//-----------------------------------------------------------------------------
-void KMAcctCachedImap::killJobsForItem(KMFolderTreeItem * fti)
-{
- TQMap::Iterator it = mapJobData.begin();
- while (it != mapJobData.end())
- {
- if (it.data().parent == fti->folder())
- {
- killAllJobs();
- break;
- }
- else ++it;
- }
-}
-
// Reimplemented from ImapAccountBase because we only check one folder at a time
void KMAcctCachedImap::slotCheckQueuedFolders()
{
@@ -217,7 +202,12 @@ void KMAcctCachedImap::processNewMail( bool /*interactive*/ )
else {
KMFolder* f = mMailCheckFolders.front();
mMailCheckFolders.pop_front();
- processNewMail( static_cast( f->storage() ), false );
+
+ // Only check mail if the folder really exists, it might have been removed by the sync in
+ // the meantime.
+ if ( f ) {
+ processNewMail( static_cast( f->storage() ), !checkingSingleFolder() );
+ }
}
}
@@ -234,7 +224,7 @@ void KMAcctCachedImap::processNewMail( KMFolderCachedImap* folder,
mNoopTimer.stop();
// reset namespace todo
- if ( folder == mFolder ) {
+ if ( folder == mFolder && !namespaces().isEmpty() ) {
TQStringList nsToList = namespaces()[PersonalNS];
TQStringList otherNSToCheck = namespaces()[OtherUsersNS];
otherNSToCheck += namespaces()[SharedNS];
@@ -361,8 +351,8 @@ void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
TQStringList strList;
TQValueList > folderList;
kmkernel->dimapFolderMgr()->createFolderList( &strList, &folderList,
- folder->folder()->child(), TQString::null,
- false );
+ folder->folder()->child(), TQString::null,
+ false );
TQValueList >::Iterator it;
mCountLastUnread = 0;
mUnreadBeforeCheck.clear();
@@ -374,13 +364,12 @@ void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
// This invalidates the folder completely
cfolder->setUidValidity("INVALID");
cfolder->writeUidCache();
- processNewMailSingleFolder( f );
}
}
folder->setUidValidity("INVALID");
folder->writeUidCache();
- processNewMailSingleFolder( folder->folder() );
+ processNewMailInFolder( folder->folder(), Recursive );
}
//-----------------------------------------------------------------------------
@@ -462,7 +451,7 @@ void KMAcctCachedImap::slotProgressItemCanceled( ProgressItem* )
}
}
-FolderStorage* const KMAcctCachedImap::rootFolder() const
+FolderStorage* KMAcctCachedImap::rootFolder() const
{
return mFolder;
}
diff --git a/kmail/kmacctcachedimap.h b/kmail/kmacctcachedimap.h
index e8e428204..72ed5c7db 100644
--- a/kmail/kmacctcachedimap.h
+++ b/kmail/kmacctcachedimap.h
@@ -75,11 +75,6 @@ public:
virtual TQString type() const;
virtual void processNewMail( bool interactive );
- /**
- * Kill all jobs related the the specified folder
- */
- void killJobsForItem(KMFolderTreeItem * fti);
-
/**
* Kill the slave if any jobs are active
*/
@@ -179,7 +174,7 @@ public:
/**
* Returns the root folder of this account
*/
- virtual FolderStorage* const rootFolder() const;
+ virtual FolderStorage* rootFolder() const;
/** return if the account passed the annotation test */
bool annotationCheckPassed(){ return mAnnotationCheckPassed;};
diff --git a/kmail/kmacctimap.cpp b/kmail/kmacctimap.cpp
index bf96c79a1..4ead745c7 100644
--- a/kmail/kmacctimap.cpp
+++ b/kmail/kmacctimap.cpp
@@ -547,7 +547,7 @@ void KMAcctImap::slotMailCheckCanceled()
}
//-----------------------------------------------------------------------------
-FolderStorage* const KMAcctImap::rootFolder() const
+FolderStorage* KMAcctImap::rootFolder() const
{
return mFolder;
}
diff --git a/kmail/kmacctimap.h b/kmail/kmacctimap.h
index c69bca899..fac17eebe 100644
--- a/kmail/kmacctimap.h
+++ b/kmail/kmacctimap.h
@@ -87,7 +87,7 @@ public:
/**
* Returns the root folder of this account
*/
- virtual FolderStorage* const rootFolder() const;
+ virtual FolderStorage* rootFolder() const;
/**
* Queues a message for automatic filtering
diff --git a/kmail/kmacctlocal.cpp b/kmail/kmacctlocal.cpp
index b486b5378..d1e15f83a 100644
--- a/kmail/kmacctlocal.cpp
+++ b/kmail/kmacctlocal.cpp
@@ -220,6 +220,7 @@ bool KMAcctLocal::fetchMsg()
msg->setSignatureStateChar( msg->headerField( "X-KMail-SignatureState" ).at(0));
msg->setComplete(true);
msg->updateAttachmentState();
+ msg->updateInvitationState();
mAddedOk = processNewMsg(msg);
diff --git a/kmail/kmaddrbook.cpp b/kmail/kmaddrbook.cpp
index b115f54e2..055b29fcc 100644
--- a/kmail/kmaddrbook.cpp
+++ b/kmail/kmaddrbook.cpp
@@ -29,7 +29,6 @@
#include
#include
#include
-#include
#include
#include
diff --git a/kmail/kmail.kcfg b/kmail/kmail.kcfg
index afb228cfe..4192d234f 100644
--- a/kmail/kmail.kcfg
+++ b/kmail/kmail.kcfg
@@ -24,6 +24,8 @@
+
+ SelectLastSelected
@@ -153,7 +155,7 @@
- 85
+ 80
@@ -184,6 +186,12 @@
false
+
+
+ When replying to invitations, send the reply comment in way that Microsoft Outlook understands.
+ false
+
+
When this is checked, you will not see the mail composer window. Instead, all invitation mails are sent automatically. If you want to see the mail before sending it, you can uncheck this option. However, be aware that the text in the composer window is in iCalendar syntax, and you should not try modifying it by hand.
@@ -200,15 +208,25 @@
AskForAllButAcceptance
-
+
When this is checked, received invitation emails that have been replied to will be moved to the Trash folder, once the reply has been successfully sent.true
-
-
+
+
+ true
+
+
+
+
+ KMail::ObjectTreeParser::defaultToltecReplacementText()
+
+
+
+
@@ -253,14 +271,12 @@
0
-
- true
-
- false
+
+ true
@@ -293,10 +309,6 @@
This option enables or disables the search line edit above the message list which can be used to quickly search the information shown in the message list.true
-
-
- false
- true
@@ -333,6 +345,11 @@
Remember this mail transport, so that it will be used in future composer windows as well.false
+
+ Remember this dictionary, so that it will be used in future composer windows as well.
+
+ false
+ true
@@ -347,8 +364,21 @@
30255
+
+
+ true
+ If the number of recipients is larger than this value, KMail will warn and ask for a confirmation before sending the mail. The warning can be turned off.
+
+
+
+ 5
+ 1
+ 100
+ If the number of recipients is larger than this value, KMail will warn and ask for a confirmation before sending the mail. The warning can be turned off.
+
+
@@ -436,6 +466,14 @@
true
+
+
+ true
+
+
+
+ true
+
@@ -515,6 +553,10 @@
+
+
+ false
+ true
diff --git a/kmail/kmailIface.h b/kmail/kmailIface.h
index fd47f0485..2338a4c40 100644
--- a/kmail/kmailIface.h
+++ b/kmail/kmailIface.h
@@ -60,6 +60,19 @@ k_dcop:
const TQString &attachParamValue,
const TQCString &attachContDisp,
const TQCString &attachCharset) = 0;
+ virtual int openComposer (const TQString &to, const TQString &cc,
+ const TQString &bcc, const TQString &subject,
+ const TQString &body, int hidden,
+ const TQString &attachName,
+ const TQCString &attachCte,
+ const TQCString &attachData,
+ const TQCString &attachType,
+ const TQCString &attachSubType,
+ const TQCString &attachParamAttr,
+ const TQString &attachParamValue,
+ const TQCString &attachContDisp,
+ const TQCString &attachCharset,
+ uint identity) = 0;
/** Open composer and return reference to DCOP interface of composer window.
If hidden is true, the window will not be shown. If you use that option,
it's your responsibility to call the send() function of the composer in
@@ -102,6 +115,7 @@ k_dcop:
virtual int dcopAddMessage(const TQString & foldername,
const KURL & messagefile,
const TQString & MsgStatusFlags = TQString()) = 0;
+ virtual void showImportArchiveDialog() = 0;
virtual TQStringList folderList() const =0;
virtual DCOPRef getFolder( const TQString& vpath ) =0;
@@ -211,7 +225,7 @@ k_dcop_hidden:
/** Clears the list of added message ids which is used to filter out
duplicates. */
virtual void dcopResetAddMessage() = 0;
-
+
virtual void loadProfile( const TQString& path ) = 0;
virtual void saveToProfile( const TQString& path ) const = 0;
};
diff --git a/kmail/kmail_config_accounts.desktop b/kmail/kmail_config_accounts.desktop
index 4c2c9f92c..c2e58a03e 100644
--- a/kmail/kmail_config_accounts.desktop
+++ b/kmail/kmail_config_accounts.desktop
@@ -39,7 +39,6 @@ Name[hu]=Fiókok
Name[is]=Tengingar
Name[it]=Account
Name[ja]=アカウント
-Name[ka]=ანგარიშები
Name[kk]=Тіркелгілері
Name[km]=គណនី
Name[lt]=Paskyros
@@ -64,8 +63,7 @@ Name[ta]=கணக்குகள்
Name[tg]=Қайдҳои баҳисобгирӣ
Name[tr]=Hesaplar
Name[uk]=Рахунки
-Name[uz]=Hisoblar
-Name[uz@cyrillic]=Ҳисоблар
+Name[uz]=Ҳисоблар
Name[zh_CN]=账户
Name[zh_TW]=帳號
Comment=Setup for Sending and Receiving Messages
@@ -91,7 +89,6 @@ Comment[hu]=Küldési és fogadási beállítások
Comment[is]=Uppsetning fyrir sendingu og móttöku af tölvupósti
Comment[it]=Impostazioni per spedire e ricevere messaggi
Comment[ja]=メッセージを送受信するための設定
-Comment[ka]=შეტყობინებების გაგზავნისა და მიღების კონფიგურაცია
Comment[kk]=Хаттарды жіберу мен қабылдауды баптау
Comment[km]=រៀបចំដើម្បីផ្ញើ និងទទួលសារ
Comment[lt]=Laiškų siuntimo ir gavimo sąranka
@@ -139,7 +136,6 @@ Keywords[he]=kmail,accounts,דוא"ל, חשבון, חשבונות
Keywords[hu]=kmail,azonosítók
Keywords[is]=kmail,accounts,tengingar
Keywords[it]=kmail,account
-Keywords[ka]=kmail,ანგარიშები
Keywords[km]=kmail,គណនី
Keywords[lt]=kmail,accounts,paskyros
Keywords[mk]=kmail,accounts,кпошта,сметка,сметки
diff --git a/kmail/kmail_config_appearance.desktop b/kmail/kmail_config_appearance.desktop
index 09df7ea4a..3008ea543 100644
--- a/kmail/kmail_config_appearance.desktop
+++ b/kmail/kmail_config_appearance.desktop
@@ -39,7 +39,6 @@ Name[hu]=Megjelenés
Name[is]=Útlit
Name[it]=Aspetto
Name[ja]=外観
-Name[ka]=იერსახე
Name[kk]=Сыртқы көрінісі
Name[km]=រូបរាង
Name[ko]=모양
@@ -66,8 +65,7 @@ Name[ta]=தோற்றம்
Name[tg]=Намуди зоҳирӣ
Name[tr]=Görünüm
Name[uk]=Вигляд
-Name[uz]=Koʻrinishi
-Name[uz@cyrillic]=Кўриниши
+Name[uz]=Кўриниши
Name[zh_CN]=外观
Comment=Customize Visual Appearance
Comment[af]=Pasmaak die visuele voorkoms
@@ -93,7 +91,6 @@ Comment[hu]=A grafikai megjelenés testreszabása
Comment[is]=Stilla útlit
Comment[it]=Personalizza l'aspetto
Comment[ja]=外観をカスタマイズ
-Comment[ka]=ვიზუალური იერსახის დაყენება
Comment[kk]=Сыртқы көрінісін ыңғайлау
Comment[km]=ប្ដូររូបរាងមើលឃើញតាមបំណង
Comment[lt]=Derinti vizualinę išvaizdą
@@ -143,7 +140,6 @@ Keywords[hu]=kmail,megjelenés
Keywords[is]=kmail,útlit
Keywords[it]=kmail,aspetto
Keywords[ja]=kmail,外観
-Keywords[ka]=kmail,იერსახე
Keywords[km]=kmail,រូបរាង
Keywords[lt]=kmail,appearance,išvaizda
Keywords[mk]=kmail,appearance,кпошта,појава,изглед,визуелно
diff --git a/kmail/kmail_config_composer.desktop b/kmail/kmail_config_composer.desktop
index 5c75a1c4c..4cc868bbc 100644
--- a/kmail/kmail_config_composer.desktop
+++ b/kmail/kmail_config_composer.desktop
@@ -35,7 +35,6 @@ Name[he]=עורך
Name[hu]=Szerkesztő
Name[it]=Compositore
Name[ja]=メール作成
-Name[ka]=წერილების რედაქტორი
Name[kk]=Құрастарғыш
Name[km]=កម្មវិធីតែង
Name[lt]=Redaktorius
@@ -80,7 +79,6 @@ Comment[fr]=Modèles et comportement général
Comment[fy]=Sjabloanen en algemien gedrach
Comment[gl]=Planteis e Comportamento Xeral
Comment[hu]=Sablonok, általános működési jellemzők
-Comment[is]=Forsnið & almenn hegðun
Comment[it]=Modelli e comportamento generale
Comment[ja]=テンプレートと全般的な動作
Comment[kk]=Үлгілер мен Жалпы тәртібі
@@ -124,7 +122,6 @@ Keywords[he]=kmail,composer,כתבן
Keywords[hu]=kmail,szerkesztő
Keywords[is]=kmail,ritill
Keywords[it]=kmail,compositore
-Keywords[ka]=kmail,წერილების რედაქტორი
Keywords[km]=kmail កម្មវិធីតែង
Keywords[lt]=kmail,composer,redaktorius
Keywords[mk]=kmail,composer,кпошта,составувач
diff --git a/kmail/kmail_config_identity.desktop b/kmail/kmail_config_identity.desktop
index 8cf28eb02..fe985db67 100644
--- a/kmail/kmail_config_identity.desktop
+++ b/kmail/kmail_config_identity.desktop
@@ -37,7 +37,6 @@ Name[hu]=Azonosítók
Name[is]=Auðkenni
Name[it]=Identità
Name[ja]=個人情報
-Name[ka]=პროფილები
Name[kk]=Іс-әлпеттері
Name[km]=អត្តសញ្ញាណ
Name[lt]=Tapatybės
@@ -62,8 +61,7 @@ Name[ta]=அடையாளங்கள்
Name[tg]=Профилҳо
Name[tr]=Kimlikler
Name[uk]=Профілі
-Name[uz]=Shaxsiyatlar
-Name[uz@cyrillic]=Шахсиятлар
+Name[uz]=Шахсиятлар
Name[zh_CN]=身份
Name[zh_TW]=身份
Comment=Manage Identities
@@ -92,7 +90,6 @@ Comment[hu]=Az azonosítók kezelése
Comment[is]=Stjórna auðkennum
Comment[it]=Gestisce le identità
Comment[ja]=個人情報の管理
-Comment[ka]=პროფილების მართვა
Comment[kk]=Іс-әлпеттерді басқару
Comment[km]=គ្រប់គ្រងអត្តសញ្ញាណ
Comment[lt]=Tvarkyti tapatybes
@@ -143,7 +140,6 @@ Keywords[hu]=kmail,azonosító
Keywords[is]=kmail,auðkenni
Keywords[it]=kmail,identità
Keywords[ja]=kmail,個人情報
-Keywords[ka]=kmail,პროფილი
Keywords[km]=kmail,អត្តសញ្ញាណ
Keywords[lt]=kmail,identity,tapatybė
Keywords[mk]=kmail,identity,кпошта,идентитет,идентитети
@@ -165,6 +161,5 @@ Keywords[ta]=கேஅஞ்சல்,அடையாளம்
Keywords[tg]=kmail,identity,профил
Keywords[tr]=kmail,kimlikler
Keywords[uk]=kmail,профіль
-Keywords[uz]=kmail,shaxsiyat
-Keywords[uz@cyrillic]=kmail,шахсият
+Keywords[uz]=kmail,шахсият
Keywords[zh_CN]=kmail,identity, 身份
diff --git a/kmail/kmail_config_misc.desktop b/kmail/kmail_config_misc.desktop
index 6a33c6432..7c1d946fd 100644
--- a/kmail/kmail_config_misc.desktop
+++ b/kmail/kmail_config_misc.desktop
@@ -36,7 +36,6 @@ Name[hu]=Egyéb
Name[is]=Ýmislegt
Name[it]=Varie
Name[ja]=その他
-Name[ka]=სხვადასხვა
Name[kk]=Басқалары
Name[km]=ផ្សេងៗ
Name[lt]=Įvairūs
@@ -62,8 +61,7 @@ Name[ta]=இதர
Name[tg]=Ғайра
Name[tr]=Çeşitli
Name[uk]=Різне
-Name[uz]=Har xil
-Name[uz@cyrillic]=Ҳар хил
+Name[uz]=Ҳар хил
Name[zh_CN]=杂项
Name[zh_TW]=其他
Comment=Settings that don't fit elsewhere
@@ -89,7 +87,6 @@ Comment[hu]=A máshová nem besorolható beállítások
Comment[is]=Stillingar sem passa ekki annars staðar
Comment[it]=Impostazioni che non rientrano in altre categorie
Comment[ja]=その他の設定
-Comment[ka]=პარამეტრები,რომლებიც სხვას არ ერგება
Comment[kk]=Басқа параметрлері
Comment[km]=ការកំណត់ដែលមិនត្រូវនឹងកន្លែងផ្សេង
Comment[lt]=Kiti nustatymai
@@ -138,7 +135,6 @@ Keywords[hu]=kmail,egyéb
Keywords[is]=kmail,ýmislegt
Keywords[it]=kmail,varie
Keywords[ja]=kmail,その他
-Keywords[ka]=kmail,სხვადასხვა
Keywords[km]=kmail,ផ្សេងៗ
Keywords[lt]=kmail,misc,įvairūs
Keywords[mk]=kmail,misc,кпошта,разно
@@ -161,6 +157,5 @@ Keywords[ta]=கேஅஞ்சல், இதர
Keywords[tg]=kmail,misc,ғайра,дигар
Keywords[tr]=kmail,çeşitli
Keywords[uk]=kmail,різне
-Keywords[uz]=kmail,har xil
-Keywords[uz@cyrillic]=kmail,ҳар хил
+Keywords[uz]=kmail,ҳар хил
Keywords[zh_CN]=kmail,misc,杂项
diff --git a/kmail/kmail_config_security.desktop b/kmail/kmail_config_security.desktop
index 1b61544e4..4d1a2a402 100644
--- a/kmail/kmail_config_security.desktop
+++ b/kmail/kmail_config_security.desktop
@@ -38,7 +38,6 @@ Name[hu]=Biztonság
Name[is]=Öryggi
Name[it]=Sicurezza
Name[ja]=セキュリティ
-Name[ka]=უსაფრთხოება
Name[kk]=Қауіпсіздік
Name[km]=សុវត្ថិភាព
Name[lt]=Saugumas
@@ -64,8 +63,7 @@ Name[ta]=பாதுகாப்பு
Name[tg]=Амният
Name[tr]=Güvenlik
Name[uk]=Безпека
-Name[uz]=Xavfsizlik
-Name[uz@cyrillic]=Хавфсизлик
+Name[uz]=Хавфсизлик
Name[zh_CN]=安全
Name[zh_TW]=安全性
Comment=Security & Privacy Settings
@@ -93,7 +91,6 @@ Comment[hu]=Biztonsági és adatvédelmi beállítások
Comment[is]=Öryggis & einkalífsstillingar
Comment[it]=Impostazioni sicurezza e privacy
Comment[ja]=セキュリティ & プライバシーの設定
-Comment[ka]=უსაფრთხოებისა და პირადულობის პარამეტრები
Comment[kk]=Қауіпсіздігі пен Дербестік параметрлері
Comment[km]=ការកំណត់សុវត្ថិភាព & ភាពឯកជន
Comment[lt]=Saugumo ir privatumo nustatymai
@@ -144,7 +141,6 @@ Keywords[hu]=kmail,biztonság
Keywords[is]=kmail,öryggi
Keywords[it]=kmail,sicurezza
Keywords[ja]=kmail,セキュリティ
-Keywords[ka]=kmail,უსაფრთხოება
Keywords[km]=kmail,សុវត្ថិភាព
Keywords[lt]=kmail,security,saugumas
Keywords[mk]=kmail,security,кпошта,безбедност
@@ -167,6 +163,5 @@ Keywords[ta]=கேஅஞ்சல்,பாதுகாப்பு
Keywords[tg]=kmail,security,амният
Keywords[tr]=kmail,güvenlik
Keywords[uk]=kmail,безпека
-Keywords[uz]=kmail,xavfsizlik
-Keywords[uz@cyrillic]=kmail,хавфсизлик
+Keywords[uz]=kmail,хавфсизлик
Keywords[zh_CN]=kmail,security,安全
diff --git a/kmail/kmail_part.rc b/kmail/kmail_part.rc
index 72cf6ec35..fb4794dfd 100644
--- a/kmail/kmail_part.rc
+++ b/kmail/kmail_part.rc
@@ -2,7 +2,7 @@
the same menu entries at the same place in KMail and Kontact -->
-
+